Library: change DSL scheme to handle optional and repeated better
It seemed that using postfix-decorating operators would be a good fit for the DSL. Exploring this idea further showed however, that such a scheme is indeed a good fit from the implementation side, but leads to rather confusing and hard to grasp DSL statements for many non-trivial syntax definition. The reason is: such a postfix-decorator will by default work on ''everything defined'' up to that point; this is too much in many cases. The other alternative would be a function-style definition, which has the benefit to take the sub-clause directly as argument (so the scope is always explicit). The downside is that argument arrangement is a bit more tricky for the repetition combinator (there can be mis-matches, since we take the »SPEC« as free-template argument) And, moreover, with function-style, having more top-level entrance points would be helpful. Overall, no fundamental roadblock, just more technicalities in the setup of the DSL functions. With that re-arrangd structure, an optional combinator could be easily integrated, and a solution was provided to pick up the parser function from a sub-expression defined as Syntax object.
This commit is contained in:
parent
5fed95b929
commit
089fafc1bd
3 changed files with 507 additions and 119 deletions
|
|
@ -59,6 +59,10 @@ namespace util {
|
|||
|
||||
using StrView = std::string_view;
|
||||
|
||||
template<class PAR>
|
||||
class Syntax;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Parse evaluation result
|
||||
|
|
@ -72,6 +76,10 @@ namespace util {
|
|||
size_t consumed{0};
|
||||
};
|
||||
|
||||
/**
|
||||
* Building block: parser function
|
||||
* definition and connection element.
|
||||
*/
|
||||
template<class FUN>
|
||||
struct Connex
|
||||
: util::NonAssign
|
||||
|
|
@ -86,6 +94,8 @@ namespace util {
|
|||
{ }
|
||||
};
|
||||
|
||||
|
||||
/** »Null-Connex« which always successfully accepts the empty sequence */
|
||||
auto
|
||||
buildConnex(NullType)
|
||||
{
|
||||
|
|
@ -96,6 +106,15 @@ namespace util {
|
|||
}
|
||||
using NulP = decltype(buildConnex (NullType()));
|
||||
|
||||
|
||||
/**
|
||||
* Foundation: build a \ref Connex to accept a _terminal symbol._
|
||||
* the actual parsing is delegated to a Regular Expression,
|
||||
* which must match against the _beginning_ of the input sequence,
|
||||
* possibly after skipping some whitespace. The defined parser
|
||||
* returns an \ref Eval context, to hold a _Result Model_ and
|
||||
* the number of characters matched by this terminal symbol.
|
||||
*/
|
||||
auto
|
||||
buildConnex (regex rex)
|
||||
{
|
||||
|
|
@ -111,12 +130,14 @@ namespace util {
|
|||
}
|
||||
using Term = decltype(buildConnex (std::declval<regex>()));
|
||||
|
||||
/** build from a string with Regular-Epression spec */
|
||||
Term
|
||||
buildConnex (string const& rexDef)
|
||||
{
|
||||
return buildConnex (regex{rexDef});
|
||||
}
|
||||
|
||||
/** copy-builder from an existing parser function */
|
||||
template<class FUN>
|
||||
auto
|
||||
buildConnex (Connex<FUN> const& anchor)
|
||||
|
|
@ -130,7 +151,21 @@ namespace util {
|
|||
return Connex{move(anchor)};
|
||||
}
|
||||
|
||||
template<class PAR>
|
||||
auto
|
||||
buildConnex (Syntax<PAR> const& anchor)
|
||||
{
|
||||
using Con = typename Syntax<PAR>::Connex;
|
||||
return Con{anchor};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adapt by applying a result-transforming function after a successful parse.
|
||||
* @remark the purpose is to extract a custom data model immediately from the
|
||||
* result; binding functors can be applied at any level of a Syntax,
|
||||
* and thus the parse can be configured to produce custom result data.
|
||||
*/
|
||||
template<class CON, class BIND>
|
||||
auto
|
||||
adaptConnex (CON&& connex, BIND&& modelBinding)
|
||||
|
|
@ -258,6 +293,7 @@ namespace util {
|
|||
RES model;
|
||||
};
|
||||
|
||||
|
||||
/** Standard case : combinator of two model branches */
|
||||
template<template<class...> class TAG, class R1, class R2 =void>
|
||||
struct _Join
|
||||
|
|
@ -325,7 +361,7 @@ namespace util {
|
|||
}
|
||||
|
||||
|
||||
/** accept sequence of two parse functions */
|
||||
/** accept either one of two alternative parse functions */
|
||||
template<class C1, class C2>
|
||||
auto
|
||||
branchedConnex (C1&& connex1, C2&& connex2)
|
||||
|
|
@ -364,13 +400,14 @@ namespace util {
|
|||
template<class C1, class C2>
|
||||
auto
|
||||
repeatedConnex (uint min, uint max
|
||||
,C1&& bodyConnex, C2&& delimConnex)
|
||||
,C1&& delimConnex
|
||||
,C2&& bodyConnex)
|
||||
{
|
||||
using Res = typename decay_t<C1>::Result;
|
||||
using Res = typename decay_t<C2>::Result;
|
||||
using IterResult = IterModel<Res>;
|
||||
using IterEval = Eval<IterResult>;
|
||||
return Connex{[sep = forward<C2>(delimConnex)
|
||||
,body = forward<C1>(bodyConnex)
|
||||
return Connex{[sep = forward<C1>(delimConnex)
|
||||
,body = forward<C2>(bodyConnex)
|
||||
,min,max
|
||||
]
|
||||
(StrView toParse) -> IterEval
|
||||
|
|
@ -402,11 +439,33 @@ namespace util {
|
|||
}
|
||||
|
||||
|
||||
|
||||
template<class PAR>
|
||||
class Syntax;
|
||||
/** try to accept parse-function, backtracking if not successful. */
|
||||
template<class CNX>
|
||||
auto
|
||||
optionalConnex (CNX&& connex)
|
||||
{
|
||||
using Res = typename decay_t<CNX>::Result;
|
||||
using OptResult = optional<Res>;
|
||||
using OptEval = Eval<OptResult>;
|
||||
return Connex{[body = forward<CNX>(connex)
|
||||
]
|
||||
(StrView toParse) -> OptEval
|
||||
{
|
||||
auto eval = body.parse (toParse);
|
||||
size_t consumed{eval.result? eval.consumed : 0};
|
||||
return OptEval{OptResult{eval.result? move(eval.result) : std::nullopt}
|
||||
,consumed
|
||||
};
|
||||
}};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A Parser function to match and accept some syntax.
|
||||
* This is a typing- and interface-adapter, wrapping a Connex.
|
||||
*/
|
||||
template<class CON>
|
||||
class Parser
|
||||
: public CON
|
||||
|
|
@ -418,13 +477,12 @@ namespace util {
|
|||
using Connex = CON;
|
||||
using Result = typename CON::Result;
|
||||
|
||||
using Sigi = typename _Fun<PFun>::Sig;
|
||||
//lib::test::TypeDebugger<Sigi> buggi;
|
||||
//lib::test::TypeDebugger<Result> guggi;
|
||||
|
||||
static_assert (has_Sig<PFun, Eval<Result>(StrView)>()
|
||||
,"Signature of the parse-function not suitable");
|
||||
|
||||
/**
|
||||
* Parse-Function operator: test input and yield Eval record
|
||||
*/
|
||||
Eval<Result>
|
||||
operator() (StrView toParse)
|
||||
{
|
||||
|
|
@ -435,17 +493,9 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
Parser (SPEC&& spec)
|
||||
: CON{buildConnex (forward<SPEC> (spec))}
|
||||
{ }
|
||||
|
||||
// template<class PAR>
|
||||
// Parser (Syntax<PAR> const& anchor)
|
||||
// : CON{anchor}
|
||||
// { }
|
||||
// template<class PAR>
|
||||
// Parser (CON const& anchor)
|
||||
// : CON{anchor}
|
||||
// { }
|
||||
};
|
||||
|
||||
/* === Deduction guide : how to construct a Parser === */
|
||||
Parser(NullType) -> Parser<NulP>;
|
||||
Parser(regex &&) -> Parser<Term>;
|
||||
Parser(regex const&) -> Parser<Term>;
|
||||
|
|
@ -453,11 +503,42 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
|
||||
template<class FUN>
|
||||
Parser(Connex<FUN> const&) -> Parser<Connex<FUN>>;
|
||||
//
|
||||
// template<class PAR>
|
||||
// Parser(Syntax<PAR> const&) -> Parser<typename PAR::Connex>;
|
||||
|
||||
template<class PAR>
|
||||
Parser(Syntax<PAR> const&) -> Parser<typename PAR::Connex>;
|
||||
|
||||
|
||||
/** @internal meta-helper : detect if parser can be built from a given type */
|
||||
template<typename SPEC, typename SEL =void>
|
||||
struct is_usableSpec : std::false_type{ };
|
||||
|
||||
template<typename SPEC>
|
||||
struct is_usableSpec<SPEC, std::void_t<decltype(Parser{std::declval<SPEC>()})>>
|
||||
: std::true_type
|
||||
{ };
|
||||
|
||||
template<typename SPEC>
|
||||
using if_acceptableSpec = lib::meta::enable_if<is_usableSpec<SPEC>>;
|
||||
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
using if_acceptableSpecs = lib::meta::enable_if<is_usableSpec<SPEC1>
|
||||
,lib::meta::enable_if<is_usableSpec<SPEC2>>>;
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************//**
|
||||
* A Syntax clause with a parser and result state.
|
||||
* An instance of this class embodies a (possibly complex)
|
||||
* _expected syntactical structure;_ the [parse function](\ref parse)
|
||||
* analyses a given input text for compliance with this expected structure.
|
||||
* After the parse, result state has been set
|
||||
* - indicating if the parse was successful
|
||||
* - possibly with an failure message (TODO 1/25)
|
||||
* - the number of characters covered by this match
|
||||
* - a _Result Model,_ as a structured term holding
|
||||
* result components from each part / sub-clause
|
||||
*/
|
||||
template<class PAR>
|
||||
class Syntax
|
||||
: public Eval<typename PAR::Result>
|
||||
|
|
@ -468,12 +549,6 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
using Connex = typename PAR::Connex;
|
||||
using Result = typename PAR::Result;
|
||||
|
||||
bool success() const { return bool(Syntax::result); }
|
||||
bool hasResult() const { return bool(Syntax::result); }
|
||||
size_t consumed() const { return Eval<Result>::consumed;}
|
||||
Result& getResult() { return * Syntax::result; }
|
||||
Result&& extractResult(){ return move(getResult()); }
|
||||
|
||||
Syntax()
|
||||
: parse_{NullType()}
|
||||
{ }
|
||||
|
|
@ -484,11 +559,21 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
{ }
|
||||
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return success();
|
||||
}
|
||||
operator bool() const { return success();}
|
||||
|
||||
operator Connex&() { return parse_; }
|
||||
operator Connex const&() const { return parse_; }
|
||||
|
||||
bool success() const { return bool(Syntax::result); }
|
||||
bool hasResult() const { return bool(Syntax::result); }
|
||||
size_t consumed() const { return Eval<Result>::consumed;}
|
||||
Result& getResult() { return * Syntax::result; }
|
||||
Result&& extractResult() { return move(getResult()); }
|
||||
|
||||
|
||||
/********************************************//**
|
||||
* Core API : parse against this syntax clause
|
||||
*/
|
||||
Syntax&&
|
||||
parse (StrView toParse)
|
||||
{
|
||||
|
|
@ -496,74 +581,41 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
return move(*this);
|
||||
}
|
||||
|
||||
Connex const&
|
||||
getConny() const
|
||||
{
|
||||
return parse_;
|
||||
}
|
||||
|
||||
|
||||
/** ===== Syntax clause builder DSL ===== */
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
seq (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
sequenceConnex (move(parse_)
|
||||
,Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
auto seq (SPEC&& clauseDef);
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
alt (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
branchedConnex (move(parse_)
|
||||
,Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
|
||||
auto
|
||||
repeat(uint cnt =uint(-1))
|
||||
{
|
||||
return repeat (1,cnt, NullType{});
|
||||
}
|
||||
auto alt (SPEC&& clauseDef);
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
repeat (SPEC&& delimDef)
|
||||
{
|
||||
return repeat (1,uint(-1), forward<SPEC> (delimDef));
|
||||
}
|
||||
auto opt (SPEC&& clauseDef);
|
||||
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto repeat (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef);
|
||||
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto repeat (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef);
|
||||
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto repeat (SPEC1&& delimDef, SPEC2&& clauseDef);
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
repeat (uint cnt, SPEC&& delimDef)
|
||||
{
|
||||
return repeat (cnt,cnt, forward<SPEC> (delimDef));
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
repeat (uint min, uint max, SPEC&& delimDef)
|
||||
{
|
||||
if (max<min)
|
||||
throw err::Invalid{_Fmt{"Invalid repeated syntax-spec: min:%d > max:%d"}
|
||||
% min % max };
|
||||
if (max == 0)
|
||||
throw err::Invalid{"Invalid repeat with max ≡ 0 repetitions"};
|
||||
|
||||
return accept(
|
||||
repeatedConnex (min,max
|
||||
,move(parse_)
|
||||
,Parser{forward<SPEC> (delimDef)}));
|
||||
}
|
||||
auto repeat (SPEC&& clauseDef);
|
||||
|
||||
private:
|
||||
Eval<Result>& eval() { return *this;}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** ===== Syntax clause builder DSL ===== */
|
||||
|
||||
/** build a Syntax clause from anything usable as parser-spec. */
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept (SPEC&& clauseDef)
|
||||
|
|
@ -571,16 +623,183 @@ using Sigi = typename _Fun<PFun>::Sig;
|
|||
return Syntax{Parser{forward<SPEC> (clauseDef)}};
|
||||
}
|
||||
|
||||
/** empty syntax clause to start further definition */
|
||||
/** empty Syntax clause to start further definition */
|
||||
auto accept() { return Syntax<Parser<NulP>>{}; }
|
||||
|
||||
|
||||
/** start Syntax clause with an optional syntax part */
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept_opt (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
optionalConnex (Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Start Syntax clause with a repeated sub-clause,
|
||||
* with separator and repetition limit; repetitions ∊ [min..max]
|
||||
* The separator will be expected _between_ instances of the repeated sub-clause
|
||||
* and will by itself produce no model. The result model is an instance of \ref IterModel,
|
||||
* which implies it is a vector (uses heap storage); if min ≡ 0, the model can be empty.
|
||||
*/
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto
|
||||
accept_repeated (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
if (max<min)
|
||||
throw err::Invalid{_Fmt{"Invalid repeated syntax-spec: min:%d > max:%d"}
|
||||
% min % max };
|
||||
if (max == 0)
|
||||
throw err::Invalid{"Invalid repeat with max ≡ 0 repetitions"};
|
||||
|
||||
return accept(
|
||||
repeatedConnex (min,max
|
||||
,Parser{forward<SPEC1> (delimDef)}
|
||||
,Parser{forward<SPEC2> (clauseDef)}));
|
||||
}
|
||||
|
||||
/** \param cnt exact number of repetitions expected */
|
||||
template<typename SPEC1, typename SPEC2, typename =if_acceptableSpecs<SPEC1,SPEC2>>
|
||||
auto
|
||||
accept_repeated (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
return accept_repeated (cnt,cnt, forward<SPEC1>(delimDef), forward<SPEC2>(clauseDef));
|
||||
}
|
||||
|
||||
/** start Syntax with an arbitrarily repeated sub-clause, with separator */
|
||||
template<typename SPEC1, typename SPEC2, typename =if_acceptableSpecs<SPEC1,SPEC2>>
|
||||
auto
|
||||
accept_repeated (SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
return accept_repeated (1,uint(-1), forward<SPEC1>(delimDef), forward<SPEC2>(clauseDef));
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept_repeated (uint min, uint max, SPEC&& clauseDef)
|
||||
{
|
||||
return accept_repeated (min, max, NullType{}, forward<SPEC>(clauseDef));
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept_repeated (uint cnt, SPEC&& clauseDef)
|
||||
{
|
||||
return accept_repeated (cnt, NullType{}, forward<SPEC>(clauseDef));
|
||||
}
|
||||
|
||||
template<typename SPEC>
|
||||
auto
|
||||
accept_repeated (SPEC&& clauseDef)
|
||||
{
|
||||
return accept_repeated (NullType{}, forward<SPEC>(clauseDef));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Combinator: extend this Syntax clause by expecting a further sub-clause
|
||||
* behind the part of the input matched by the already defined part of this Syntax.
|
||||
* The result model will be a \SeqModel, which essentially is a tuple of the
|
||||
* result models of all sequenced parts.
|
||||
* @return Syntax clause instance accepting the extended structure.
|
||||
* @warning the old syntax is invalidated by moving the parse-function out.
|
||||
*/
|
||||
template<class PAR>
|
||||
template<typename SPEC>
|
||||
auto
|
||||
Syntax<PAR>::seq (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
sequenceConnex (move(parse_)
|
||||
,Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combinator: extend this Syntax by adding an _alternative branch_.
|
||||
* So either the already defined part of this Syntax matches the input,
|
||||
* or the alternative clause is probed from the start of the input. At least
|
||||
* one branch must match for the parse to be successful; however, further
|
||||
* branches are not tested after finding a matching branch (short-circuit).
|
||||
* The result model is a _Sum Type,_ implemented as a custom variant record
|
||||
* of type \ref SubModel. It provides a branch selector field to detect which
|
||||
* branch of the syntax did match. And it allows to retrieve the result model
|
||||
* of this successful branch — which however requires that the invoking code
|
||||
* precisely knows the model type to expect.
|
||||
*/
|
||||
template<class PAR>
|
||||
template<typename SPEC>
|
||||
auto
|
||||
Syntax<PAR>::alt (SPEC&& clauseDef)
|
||||
{
|
||||
return accept(
|
||||
branchedConnex (move(parse_)
|
||||
,Parser{forward<SPEC> (clauseDef)}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combinator: extend this Syntax with a further sequenced sub-clause,
|
||||
* which however is _only optional_ and the match succeed without it.
|
||||
* The result model is (as always for \ref seq ) a tuple; the result
|
||||
* from the optional part is packaged into a std::optional.
|
||||
*/
|
||||
template<class PAR>
|
||||
template<typename SPEC>
|
||||
auto
|
||||
Syntax<PAR>::opt (SPEC&& clauseDef)
|
||||
{
|
||||
return seq (accept_opt (forward<SPEC> (clauseDef)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Combinator: extend this Syntax with a further sequenced sub-clause,
|
||||
* which in this case accepts a repeated sequence, with delimiter.
|
||||
* @see accept_sequenced()
|
||||
*/
|
||||
template<class PAR>
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto
|
||||
Syntax<PAR>::repeat (uint min, uint max, SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
return seq (accept_repeated (min,max
|
||||
,forward<SPEC1>(clauseDef)
|
||||
,forward<SPEC2>(clauseDef)));
|
||||
}
|
||||
|
||||
template<class PAR>
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto
|
||||
Syntax<PAR>::repeat (uint cnt, SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
return seq (accept_repeated (cnt
|
||||
,forward<SPEC1>(clauseDef)
|
||||
,forward<SPEC2>(clauseDef)));
|
||||
}
|
||||
|
||||
template<class PAR>
|
||||
template<typename SPEC1, typename SPEC2>
|
||||
auto
|
||||
Syntax<PAR>::repeat (SPEC1&& delimDef, SPEC2&& clauseDef)
|
||||
{
|
||||
return seq (accept_repeated (forward<SPEC1>(clauseDef)
|
||||
,forward<SPEC2>(clauseDef)));
|
||||
}
|
||||
|
||||
template<class PAR>
|
||||
template<typename SPEC>
|
||||
auto
|
||||
Syntax<PAR>::repeat (SPEC&& clauseDef)
|
||||
{
|
||||
return seq (accept_repeated (forward<SPEC>(clauseDef)));
|
||||
}
|
||||
|
||||
}// namespace parse
|
||||
|
||||
|
||||
using parse::accept;
|
||||
using parse::accept_opt;
|
||||
using parse::accept_repeated;
|
||||
|
||||
}// namespace util
|
||||
|
||||
namespace lib {
|
||||
}// namespace lib
|
||||
#endif/*LIB_PARSE_H*/
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ namespace parse{
|
|||
namespace test {
|
||||
|
||||
using lib::test::showType;
|
||||
using lib::meta::typeSymbol;
|
||||
using lib::meta::is_Tuple;
|
||||
using std::decay_t;
|
||||
using std::get;
|
||||
// using util::join;
|
||||
// using util::isnil;
|
||||
|
|
@ -79,6 +81,8 @@ namespace test {
|
|||
acceptSequential();
|
||||
acceptAlternatives();
|
||||
acceptIterWithDelim();
|
||||
acceptOptionally();
|
||||
acceptBracketed();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -117,16 +121,14 @@ namespace test {
|
|||
CHECK (not syntax2.hasResult());
|
||||
syntax2.parse (toParse);
|
||||
CHECK (not syntax2.success());
|
||||
|
||||
string bye{"cruel world"};
|
||||
syntax2.parse (bye);
|
||||
CHECK (syntax2.success());
|
||||
CHECK (syntax2.getResult()[1] == "cruel"_expect);
|
||||
|
||||
// going full circle: extract parser def from syntax
|
||||
// using Conn = decltype(syntax2)::Connex;
|
||||
// Conn conny{syntax2};
|
||||
// auto parse2 = Parser{conny};
|
||||
auto parse2 = Parser{syntax2.getConny()};
|
||||
// Going full circle: extract Parser definition from syntax
|
||||
auto parse2 = Parser{syntax2};
|
||||
CHECK (eval.result->str(1) == "vile");
|
||||
eval = parse2 (toParse);
|
||||
CHECK (not eval.result);
|
||||
|
|
@ -343,8 +345,10 @@ namespace test {
|
|||
|
||||
|
||||
|
||||
/** @test TODO define repetitive sequence with delimiter
|
||||
/** @test define repetitive sequence with delimiter
|
||||
* - demonstrate how actually to accept such a flexible sequence
|
||||
* - cover integration into the syntax clause DSL
|
||||
* - repetition count and delimiter
|
||||
*/
|
||||
void
|
||||
acceptIterWithDelim()
|
||||
|
|
@ -405,7 +409,7 @@ namespace test {
|
|||
|
||||
//______________________________________________
|
||||
// DSL parse clause builder: iterative sequence...
|
||||
auto syntax1 = accept(term).repeat(",");
|
||||
auto syntax1 = accept_repeated(",", term);
|
||||
|
||||
// Perform the same parse as demonstrated above....
|
||||
CHECK (not syntax1.hasResult());
|
||||
|
|
@ -423,8 +427,8 @@ namespace test {
|
|||
CHECK (res1[1].str() == "extort" );
|
||||
CHECK (res1[2].str() == "profit" );
|
||||
|
||||
auto syntax2 = accept(term).repeat(1,2,",");
|
||||
auto syntax3 = accept(term).repeat(4,",");
|
||||
auto syntax2 = accept_repeated(1,2,",", term);
|
||||
auto syntax3 = accept_repeated( 4,",", term);
|
||||
syntax2.parse(s2);
|
||||
syntax3.parse(s2);
|
||||
CHECK ( syntax2);
|
||||
|
|
@ -441,7 +445,7 @@ namespace test {
|
|||
CHECK (syntax3.getResult()[2].str() == "profit" );
|
||||
CHECK (syntax3.getResult()[3].str() == "dump" );
|
||||
|
||||
auto syntax4 = accept(term).repeat();
|
||||
auto syntax4 = accept_repeated(term);
|
||||
syntax4.parse(s1);
|
||||
CHECK (syntax4.success());
|
||||
CHECK (syntax4.getResult().size() == 2);
|
||||
|
|
@ -449,6 +453,94 @@ namespace test {
|
|||
CHECK (syntax4.getResult()[1].str() == "umschlungen" );
|
||||
CHECK (s1.substr(syntax4.consumed()) == ", Millionen");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test define compound syntax with optional sub-clause
|
||||
* - use the DSL to construct a complex syntax
|
||||
* - by default, several parts are implicitly sequenced
|
||||
* - here we combine repeated parts with an optional clause
|
||||
* - which in turn is again a compound syntax clause
|
||||
* - the produced model reflects the structure of this syntax
|
||||
* - result model of the optional clause is wrapped into `std::optional`
|
||||
* - terminal elements produce a `std::smatch` (RegExp matcher object)
|
||||
*/
|
||||
void
|
||||
acceptOptionally()
|
||||
{
|
||||
auto syntax = accept_repeated(",", "\\w+") // first we look for comma separated words
|
||||
.opt(accept("and") // then (implicitly sequenced) an optional clause
|
||||
.repeat("\\w+")); // ... comprising "and" followed by several words
|
||||
using Model = decay_t<decltype(syntax.getResult())>;
|
||||
|
||||
string s1{"fearmongering, scapegoating, intimidation"};
|
||||
string s2{"charisma and divine blessing"};
|
||||
|
||||
CHECK (not syntax.hasResult());
|
||||
syntax.parse(s1);
|
||||
CHECK (syntax.success());
|
||||
|
||||
Model res1 = syntax.getResult();
|
||||
CHECK (typeSymbol(res1) == "SeqModel");
|
||||
CHECK (typeSymbol(res1.get<0>()) == "IterModel");
|
||||
CHECK (typeSymbol(res1.get<1>()) == "optional");
|
||||
|
||||
CHECK (res1.N == 2); // 2-component tuple at top
|
||||
CHECK (res1.get<0>().size() == 3); // sequence in 1st component matched 3 elements
|
||||
CHECK (res1.get<0>()[0].str() == "fearmongering"); // elements in the sequence...
|
||||
CHECK (res1.get<0>()[1].str() == "scapegoating");
|
||||
CHECK (res1.get<0>()[2].str() == "intimidation");
|
||||
CHECK (res1.get<1>() == std::nullopt); // the optional clause did not match
|
||||
|
||||
syntax.parse(s2);
|
||||
CHECK (syntax.success());
|
||||
|
||||
Model res2 = syntax.getResult();
|
||||
CHECK (typeSymbol(res2) == "SeqModel"); // Syntax SeqModel
|
||||
CHECK (typeSymbol(res2.get<0>()) == "IterModel"); // repeat(word) opt IterModel optional
|
||||
CHECK (typeSymbol(res2.get<1>()) == "optional"); // | |
|
||||
CHECK (typeSymbol(*res2.get<1>()) == "SeqModel"); // Syntax SeqModel
|
||||
CHECK (typeSymbol(res2.get<1>()->get<0>()) == "match_results"); // "and" repeat(word) Terminal IterModel
|
||||
CHECK (typeSymbol(res2.get<1>()->get<1>()) == "IterModel"); //
|
||||
|
||||
CHECK (res2.get<0>().size() == 1);
|
||||
CHECK (res2.get<0>()[0].str() == "charisma");
|
||||
CHECK (res2.get<1>() != std::nullopt);
|
||||
CHECK (res2.get<1>()->N == 2);
|
||||
CHECK (res2.get<1>()->get<0>().str() == "and");
|
||||
CHECK (res2.get<1>()->get<1>().size() == 2 );
|
||||
CHECK (res2.get<1>()->get<1>()[0].str() == "divine" );
|
||||
CHECK (res2.get<1>()->get<1>()[1].str() == "blessing" );
|
||||
|
||||
string s3{s1+" , "+s2};
|
||||
syntax.parse(s3);
|
||||
CHECK (syntax.success());
|
||||
|
||||
Model res3 = syntax.getResult();
|
||||
CHECK (typeSymbol(res3) == "SeqModel");
|
||||
CHECK (res3.get<0>().size() == 4);
|
||||
CHECK (res3.get<0>()[0].str() == "fearmongering");
|
||||
CHECK (res3.get<0>()[1].str() == "scapegoating");
|
||||
CHECK (res3.get<0>()[2].str() == "intimidation");
|
||||
CHECK (res3.get<0>()[3].str() == "charisma");
|
||||
CHECK (res3.get<1>() != std::nullopt);
|
||||
CHECK (res3.get<1>()->N == 2);
|
||||
CHECK (res3.get<1>()->get<0>().str() == "and");
|
||||
CHECK (res3.get<1>()->get<1>().size() == 2);
|
||||
CHECK (res3.get<1>()->get<1>()[0].str() == "divine");
|
||||
CHECK (res3.get<1>()->get<1>()[1].str() == "blessing");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test
|
||||
*
|
||||
*/
|
||||
void
|
||||
acceptBracketed()
|
||||
{
|
||||
UNIMPLEMENTED ("bracketed");
|
||||
}
|
||||
};
|
||||
|
||||
LAUNCHER (Parse_test, "unit common");
|
||||
|
|
|
|||
|
|
@ -55198,10 +55198,9 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#dcd8bb" CREATED="1737571008910" ID="ID_1051885182" MODIFIED="1737571674702" TEXT="umgekehrte Postfix-Notation">
|
||||
<linktarget COLOR="#fef8c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="483;279;" ID="Arrow_ID_1143426887" SOURCE="ID_1134276650" STARTARROW="None" STARTINCLINATION="460;21;"/>
|
||||
<linktarget COLOR="#fef8c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="483;279;" ID="Arrow_ID_1290165292" SOURCE="ID_543391021" STARTARROW="None" STARTINCLINATION="554;61;"/>
|
||||
<icon BUILTIN="ksmiletris"/>
|
||||
<node BACKGROUND_COLOR="#c8b99a" COLOR="#690f14" CREATED="1737571008910" HGAP="54" ID="ID_1051885182" MODIFIED="1737603574855" TEXT="umgekehrte Postfix-Notation" VSHIFT="-2">
|
||||
<linktarget COLOR="#fed3c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="751;246;" ID="Arrow_ID_1143426887" SOURCE="ID_1134276650" STARTARROW="None" STARTINCLINATION="515;24;"/>
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1737571129595" ID="ID_1227830528" MODIFIED="1737571145596" TEXT="Posfix-Operator nimmt stets die ganze Syntax-Klausel"/>
|
||||
<node CREATED="1737571146527" ID="ID_1480801160" MODIFIED="1737571157199" TEXT="man definiert also von innen nach außen"/>
|
||||
<node CREATED="1737571212401" ID="ID_1700130675" MODIFIED="1737571228018" TEXT="wichtige Modifier">
|
||||
|
|
@ -55209,6 +55208,37 @@
|
|||
<node CREATED="1737571233558" ID="ID_1190994671" MODIFIED="1737571238865" TEXT="optional()"/>
|
||||
<node CREATED="1737571257818" ID="ID_779919773" MODIFIED="1737571292552" TEXT="bracket(spec)"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737602996904" ID="ID_231296474" MODIFIED="1737603535989" TEXT="bewährt sich nicht in der Praxis">
|
||||
<arrowlink COLOR="#8c4b4d" DESTINATION="ID_1220798311" ENDARROW="Default" ENDINCLINATION="14;-34;" ID="Arrow_ID_300013837" STARTARROW="None" STARTINCLINATION="-167;-19;"/>
|
||||
<icon BUILTIN="closed"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1737603396873" HGAP="19" ID="ID_1220798311" MODIFIED="1737603570376" TEXT="stattdessen..." VSHIFT="11">
|
||||
<linktarget COLOR="#8c4b4d" DESTINATION="ID_1220798311" ENDARROW="Default" ENDINCLINATION="14;-34;" ID="Arrow_ID_300013837" SOURCE="ID_231296474" STARTARROW="None" STARTINCLINATION="-167;-19;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<node BACKGROUND_COLOR="#ecdcb4" COLOR="#491354" CREATED="1737603423470" ID="ID_1829725832" LINK="#ID_172468776" MODIFIED="1737643392381" STYLE="fork">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
top-Level-Einstiege bieten ⟹ Präfix <font face="Monospaced" color="#681d21">accept_</font>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ecdcb4" COLOR="#491354" CREATED="1737603413919" ID="ID_1979527720" MODIFIED="1737603564463" STYLE="fork" TEXT="implizite Sequenz als default-Junktor">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
</node>
|
||||
<node CREATED="1737603449227" ID="ID_1769998683" MODIFIED="1737603460317" TEXT="für">
|
||||
<node CREATED="1736719956201" ID="ID_1631746484" MODIFIED="1737603479603" TEXT="repeat(N, delim, body)"/>
|
||||
<node CREATED="1737571233558" ID="ID_463545162" MODIFIED="1737646748974" TEXT="opt(syntax)"/>
|
||||
<node CREATED="1737571257818" ID="ID_1977661543" MODIFIED="1737603488865" TEXT="bracket(spec, syntax)"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1736724867345" ID="ID_1842306489" MODIFIED="1736724871350" TEXT="Model">
|
||||
|
|
@ -55430,7 +55460,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1736896942694" ID="ID_50956958" MODIFIED="1736896957680" TEXT="Kreis schließen: Parser wieder aus Syntax bauen">
|
||||
<node CREATED="1736896942694" ID="ID_50956958" MODIFIED="1737649641200" TEXT="Kreis schließen: Parser wieder aus Syntax bauen">
|
||||
<linktarget COLOR="#de5868" DESTINATION="ID_50956958" ENDARROW="Default" ENDINCLINATION="-792;1631;" ID="Arrow_ID_1971370194" SOURCE="ID_950065344" STARTARROW="None" STARTINCLINATION="-1469;98;"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1736896960412" ID="ID_281482378" MODIFIED="1736896967137" TEXT="will nicht recht funktionieren">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1736896977066" ID="ID_773020678" MODIFIED="1736897010857" TEXT="das läuft auf ein clone-construct des Connex hinaus">
|
||||
|
|
@ -55451,6 +55482,16 @@
|
|||
<node CREATED="1736897078444" ID="ID_1084979494" MODIFIED="1736897089814" TEXT="hängt wohl mit der Overload-Resolution zusammen"/>
|
||||
<node CREATED="1736897090523" ID="ID_142574777" MODIFIED="1736897102445" TEXT="wenn man direkt ein Objekt konstruiert, wird er verwendet"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#1b6b58" CREATED="1737656539272" ID="ID_613317824" MODIFIED="1737656638137" TEXT="muß den ganzen Pfad lenken">
|
||||
<icon BUILTIN="forward"/>
|
||||
<node CREATED="1737656557199" ID="ID_1766627630" MODIFIED="1737656570026" TEXT="Deduction-Guide für Parser{Syntax}">
|
||||
<node CREATED="1737656579333" ID="ID_1683176379" MODIFIED="1737656595775" TEXT="hier Typedef Syntax::Connex zu Hilfe nehmen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737656598432" ID="ID_1946066798" MODIFIED="1737656609012" TEXT="brauche buildConnex (Syntax)"/>
|
||||
<node CREATED="1737656610177" ID="ID_1186453687" MODIFIED="1737656620354" TEXT="Syntax muß conversion-Operator bieten"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1736897170512" ID="ID_28739070" MODIFIED="1736897191019" TEXT="Fazit: muß sinnvollerweise direkt aus Syntax heraus angestoßen werden">
|
||||
<node CREATED="1736897207538" ID="ID_953670876" MODIFIED="1736897215717" TEXT="das ist wohl akzeptabel"/>
|
||||
|
|
@ -55471,7 +55512,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1736897354542" ID="ID_1609713458" MODIFIED="1736897365189" TEXT="Sequenz-Kombinator anlegen">
|
||||
<node COLOR="#338800" CREATED="1736897354542" ID="ID_1609713458" MODIFIED="1737649511943" TEXT="Sequenz-Kombinator anlegen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1736897787716" ID="ID_663293705" MODIFIED="1737234458887" TEXT="Basis-Mechanik">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1736897797339" ID="ID_1097974753" MODIFIED="1736897811257" TEXT="brauche Zugang zu den Parse-Funktoren"/>
|
||||
|
|
@ -56853,9 +56895,8 @@
|
|||
<node CREATED="1737560320472" ID="ID_89163254" MODIFIED="1737560334666" TEXT="viel lesbarer, da Syntax immer durch das Stichwort "accept" eingeleitet wird"/>
|
||||
<node CREATED="1737560341821" ID="ID_713190827" MODIFIED="1737560350519" TEXT="spart eine Menge repetitive definitionen"/>
|
||||
</node>
|
||||
<node CREATED="1737569770813" ID="ID_858035606" MODIFIED="1737569832356" TEXT="noch besser: postfix repeat()">
|
||||
<icon BUILTIN="yes"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#5b280f" CREATED="1737569770813" ID="ID_858035606" MODIFIED="1737602936297" TEXT="noch besser: postfix repeat()">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1737569852750" ID="ID_1574259355" MODIFIED="1737571535674" TEXT="Begründung: sonst bekommen wir stets eine implizite Sequenz mit Tupel auf Model-Ebene">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -56880,9 +56921,39 @@
|
|||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
<arrowlink COLOR="#fef8c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="483;279;" ID="Arrow_ID_1143426887" STARTARROW="None" STARTINCLINATION="460;21;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
|
||||
<icon BUILTIN="forward"/>
|
||||
<arrowlink COLOR="#fed3c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="751;246;" ID="Arrow_ID_1143426887" STARTARROW="None" STARTINCLINATION="515;24;"/>
|
||||
<linktarget COLOR="#b60c19" DESTINATION="ID_1134276650" ENDARROW="Default" ENDINCLINATION="205;10;" ID="Arrow_ID_497998726" SOURCE="ID_543391021" STARTARROW="None" STARTINCLINATION="79;-13;"/>
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="13"/>
|
||||
<icon BUILTIN="stop-sign"/>
|
||||
</node>
|
||||
<node COLOR="#a3020d" CREATED="1737603165552" ID="ID_477286805" MODIFIED="1737603199554" TEXT="diese erzwingt in der Praxis unnötig viele Klammerungen">
|
||||
<font NAME="SansSerif" SIZE="11"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#ecdcb4" COLOR="#491354" CREATED="1737603246542" ID="ID_1239316504" MODIFIED="1737603354469" TEXT="implizite Sequenz als Default ist doch gar nicht so schlecht">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737603322428" ID="ID_172468776" MODIFIED="1737603344117" TEXT="also doch top-Level">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1737643237418" ID="ID_1852967082" MODIFIED="1737643310172">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
stets mit Präfix <font face="Monospaced" size="3" color="#542c2c">accept_</font>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1737649521902" ID="ID_950065344" MODIFIED="1737649641200" TEXT="muß Parser aus Syntax erzeugen können">
|
||||
<arrowlink COLOR="#de5868" DESTINATION="ID_50956958" ENDARROW="Default" ENDINCLINATION="-792;1631;" ID="Arrow_ID_1971370194" STARTARROW="None" STARTINCLINATION="-1469;98;"/>
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737603327947" ID="ID_366774797" MODIFIED="1737603344113" TEXT="und lokal als implizite Sequenz">
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -56895,7 +56966,8 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737515386507" ID="ID_1671829221" MODIFIED="1737515396597" TEXT="optionaler Kombinator">
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737515386507" ID="ID_1671829221" MODIFIED="1737591861198" TEXT="optionaler Kombinator">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1737515398692" ID="ID_1478704437" MODIFIED="1737515413091" TEXT="der ist einfach zu realisieren und sehr nützlich"/>
|
||||
<node CREATED="1737515413799" ID="ID_1235063232" MODIFIED="1737515424929" TEXT="das Model wird in einen std::optional gewickelt"/>
|
||||
<node BACKGROUND_COLOR="#e5d4c6" COLOR="#435e98" CREATED="1737515765304" ID="ID_692646776" MODIFIED="1737571714725" TEXT="per postfix-Operator darstellbar?">
|
||||
|
|
@ -56914,16 +56986,20 @@
|
|||
<node CREATED="1737552779748" ID="ID_1979253709" MODIFIED="1737552797867" TEXT="das Model wird in einen Optional gepackt"/>
|
||||
<node CREATED="1737552798647" ID="ID_845579574" MODIFIED="1737552821888" TEXT="Scheitern des Parsers führt nur zu Backtracking"/>
|
||||
</node>
|
||||
<node CREATED="1737552824569" ID="ID_1896891774" MODIFIED="1737552864018" TEXT="zur Lesbarkeit beide DSL-Varianten bieten">
|
||||
<node CREATED="1737552866525" ID="ID_849718453" MODIFIED="1737552892406" TEXT="Postfix geht immer wirkt aber auf die ganze Klausel">
|
||||
<node CREATED="1737570726608" ID="ID_543391021" MODIFIED="1737571674702" TEXT="Postfix-takes-all-Logik">
|
||||
<arrowlink COLOR="#fef8c9" DESTINATION="ID_1051885182" ENDARROW="Default" ENDINCLINATION="483;279;" ID="Arrow_ID_1290165292" STARTARROW="None" STARTINCLINATION="554;61;"/>
|
||||
<node CREATED="1737552824569" ID="ID_1896891774" MODIFIED="1737603097508" TEXT="Lesbarkeit der DSL-Varianten....">
|
||||
<node CREATED="1737552866525" ID="ID_849718453" MODIFIED="1737603117259" TEXT="Postfix geht immer — wirkt aber auf die ganze Klausel">
|
||||
<node CREATED="1737570726608" ID="ID_543391021" MODIFIED="1737603076848" TEXT="Postfix-takes-all-Logik">
|
||||
<arrowlink COLOR="#b60c19" DESTINATION="ID_1134276650" ENDARROW="Default" ENDINCLINATION="205;10;" ID="Arrow_ID_497998726" STARTARROW="None" STARTINCLINATION="79;-13;"/>
|
||||
<font NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737603121280" ID="ID_1882624112" MODIFIED="1737603160042" TEXT="Scope meist viel zu groß">
|
||||
<icon BUILTIN="broken-line"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737552896306" ID="ID_978425545" MODIFIED="1737552964929" TEXT="optional(parse) - Funktionsschreibweise bisweilsen klarer">
|
||||
<node CREATED="1737552896306" ID="ID_978425545" MODIFIED="1737603209963" TEXT="optional(parse) - Funktionsschreibweise klarer">
|
||||
<node CREATED="1737571480380" ID="ID_330911197" MODIFIED="1737571485431" TEXT="muß dann aber top-level sein"/>
|
||||
<node CREATED="1737571488227" ID="ID_479972357" MODIFIED="1737571542441" TEXT="denn sonst widerspricht es der Syntax-Klausel-Logik">
|
||||
<node CREATED="1737571488227" ID="ID_479972357" MODIFIED="1737603236739" TEXT="oder eine Sequenz implizieren">
|
||||
<arrowlink COLOR="#9091a5" DESTINATION="ID_1574259355" ENDARROW="Default" ENDINCLINATION="185;6;" ID="Arrow_ID_1603942836" STARTARROW="None" STARTINCLINATION="128;-10;"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -56990,8 +57066,9 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1737557515000" ID="ID_717799418" MODIFIED="1737557531293" TEXT="Parse-Mechanismus skizzieren"/>
|
||||
<node COLOR="#435e98" CREATED="1737557534805" ID="ID_1997532643" MODIFIED="1737557551147" TEXT="Akzeptieren und Backtracking"/>
|
||||
<node COLOR="#435e98" CREATED="1737509774878" ID="ID_1818283954" MODIFIED="1737557632090" TEXT="Kombinator per DSL">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737509774878" ID="ID_1818283954" MODIFIED="1737603375589" TEXT="Kombinator per DSL">
|
||||
<linktarget COLOR="#69a19e" DESTINATION="ID_1818283954" ENDARROW="Default" ENDINCLINATION="341;-27;" ID="Arrow_ID_1906636741" SOURCE="ID_909696958" STARTARROW="None" STARTINCLINATION="-269;35;"/>
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1737581111703" ID="ID_1277454723" MODIFIED="1737581129805" TEXT="mit vorgegebener Anzahl"/>
|
||||
<node COLOR="#435e98" CREATED="1737581124685" ID="ID_196113271" MODIFIED="1737581129806" TEXT="ohne Delimiter"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue