Library: complete test and documentaton of parsing support

This finishes an ''exercise'' in tool design,
which was set off by the requirement to parse the spec-ID of a render node.
While generally within the confines of a helper utility for simple use cases,
the solution became quite succinct and generic, as it allows to handle arbitrary
LL(n) grammars, possibly with recursion.
This commit is contained in:
Fischlurch 2025-01-29 23:51:13 +01:00
parent cdbdf620ca
commit 0a0369a4a5
3 changed files with 385 additions and 98 deletions

View file

@ -27,6 +27,111 @@
** and automatically consuming any leading whitespace. And notably the focus was
** _not placed_ on the challenging aspects of parsing while still allowing a
** pathway towards definition of arbitrarily recursive grammars, if so desired.
**
** ## Functionality
** This framework supports the construction of a recursive-descent parser without
** underlying lexer. Rather, _terminal expressions_ are delegated to a regular
** expression matcher, which allows for some additional leeway, like a negative
** match, or using lookahead-assertions. The implementation relies on parser
** _functions_ and the _combinator technique_ to combine building blocks yet
** those functions and combinators are wrapped into a syntax-clause builder DSL.
** Each parse yields a result, depending on the structure of the parse-function.
** The base building block, a parser to accept a regular expression, will yield
** the C++ matcher object as result and thus essentially some pointers into
** the original sequence, which has to be passed in as C++ string_view.
**
** An essential concept of this parsing support framework is that each parser
** can be decorated by a _model transformation functor,_ which gets the result
** of the wrapped parser and can return _any arbitrary value object._ In essence,
** this framework does not provide the notion of an _abstract syntax tree_ yet
** the user is free to build a custom syntax tree, relying on these model-bindings.
**
** \par Syntax building blocks
** - `accept(SPEC)` builds a clause to accept anything the given SPEC for
** a parser function would accept and to yield its return model.
** The `SPEC` argument might be...
** + a string describing regular expression syntax
** + a C++ regexp object
** + any hand-written functor `string_view model`
** + an existing syntax clause (either by RValue or LValue)
** - `accept_opt` builds a clause to optionally accept in accordance
** to the given definition; if no match is found, parsing backtracks.
** - `accept_repeated` builds a clause to accept a repetition of the
** structure accepted by its argument, optionally with an explicit delimiter
** and possibly with a limited number of instances. The result values are
** obviously all from the same type and will be collected into a IterModel,
** which essentially is a std::vector<RES> (note: heap storage!).
** - `accept_bracket` builds a clause to accept the structure of the
** given argument, but enclosed in parentheses, or an explicitly defined
** pair of delimiters. Variants are provided to accept optional bracketing.
** - `<syntax>.seq(SPEC)` extends a given syntax clause to accept the structure
** described by the SPEC _after_ the structure already described by the syntax.
** Both parts must succeed for the parse to be successful. The result value
** is packaged into a parse::SeqModel, which essentially is a tuple; when
** attaching several .seq() specifications, it can become a N-ary tuple.
** - `<syntax>.alt(SPEC)` adds an _alternative branch_ to the existing syntax.
** Either part alone is sufficient for a successful parse. First the existing
** branch(es) are tried, and only if those do not succeed, backtracking is
** performed and then the alternative branch is tried. Once some match is
** found, further branches will _not be attempted._ (short-circuit).
** Thus there is _always one_ result model, is placed into an AltModel,
** which is a _variant data type_ with a common inline result buffer.
** The _selector field_ must be checked to find out which branch of the
** syntax succeeded, and then the result must be handled with its appropriate
** type, because the various branches can possibly yield entirely different
** result value types.
** - `<syntax>.repeat()` _sequentially adds_ a repeated clause be accepted
** _after_ what the existing syntax accepts. The result is thus a SeqModel.
** - `<syntax>.bracket()` _sequentially adds_ a bracketing clause to be
** accepted _after_ parsing with the existing syntax. Again, the result
** is a SeqModel, with the result-model from the repetition in the last
** tuple element. The repetition itself yields an IterModel.
** - `<syntax>.bind(FUN)` is a postfix-operator and decorates the existing
** syntax with a result-binding functor `FUN`: The syntax's result value
** is passed into this functor and whatever this functor returns will
** become the result value of the compound.
** - `<syntax>.bindMatch(n)`: a convenience shortcut to bind to the complete
** input substring accepted by the underlying parser, or (when directly
** applied to a reg-exp terminal) it can also extract a match-sub-group.
** The result value of the resulting syntax clause will thus be a string.
**
** ### Recursion
** A _recursive syntax definition_ is what unleashes the parsing technique's
** full strength; but recursive grammars can be challenging to master at times
** and may in fact lead to deadlock due to unlimited recursion. Since this
** framework is focused on ease of use in simple situations, recursion is
** considered an advanced usage and thus supported in a way that requires
** some preparation and help by the user. In essence...
** - a syntax clause to be referred recursively _must be pre-declared_
** - this pre-declaration gives it a known, fixed result type and will
** internally use a `std::function` as parse function, initially empty.
** - later the full syntax must be defined, and supplemented with a binding
** to yield precisely the result-model type as pre-declared
** - finally this definition is _assigned_ to the pre-declared syntax object.
** One point to note is that internally a _reference_ to the pre-declared
** `std::function` is stored implying that the pre-declared syntax object
** must **remain in scope and can not be moved**. Other than requiring
** such a special setup, recursive syntax can be used without limits.
**
** ## Structure
** The util::parse::Syntax object is what the user handles and interacts with.
** It both holds a result record of type util::parse::Eval, and a parser object
** of type util::parse::Parser, while also acting as a move-style DSL builder.
** Here, _move-style_ implies that invoking a DSL extension operator will
** _move the embedded parser function_ into a new Syntax object with different
** result type. However, when starting with some of the top-level function-style
** builders, a given syntax object will be copied. This is important to keep
** in mind when building complex expressions. Another point worth mentioning
** is that the basic parse relies on std::string_view, which implies that the
** original input sequence must remain valid until the parse result is built.
**
** At the heart of the combinator mechanics is the class util::part::Connex,
** which is essentially a parser function with additional configuration, and
** can be passed to one of the _combinator functions_ `buildXXXConnex(...)`.
** The construction of compound model results relies on a set of overloaded
** `_Join` templates, which specify the way how models can be combined and
** sequences can be extended.
**@see parse-test.cpp
*/
@ -41,7 +146,6 @@
#include "lib/meta/function.hpp"
#include "lib/meta/trait.hpp"
#include "lib/regex.hpp"
#include "lib/test/diagnostic-output.hpp"/////////TODO
#include <optional>
#include <utility>
@ -266,7 +370,7 @@ namespace util {
else
{ // defensive fall-back: ignore model, return accepted input part
size_t pre = leadingWhitespace (toParse);
return {string{toParse.substr (pre, eval.consumed)}
return {string{toParse.substr (pre, eval.consumed - pre)}
,eval.consumed
};
}
@ -377,9 +481,7 @@ namespace util {
/** Marker-Tag for the result from a sub-expression, not to be joined */
template<typename RES>
struct SubModel
{
RES model;
};
{ /* for metaprogramming only */ };
/** Standard case : combinator of two model branches */

View file

@ -19,15 +19,10 @@
#include "lib/test/run.hpp"
#include "lib/test/test-helper.hpp"
#include "lib/parse.hpp"
//#include "lib/format-util.hpp"
#include "lib/meta/tuple-helper.hpp"
#include "lib/test/diagnostic-output.hpp"//////////////////TODO
//#include "lib/util.hpp"
//#include <vector>
//#include <memory>
#include "lib/parse.hpp"
#include <vector>
namespace util {
@ -38,35 +33,15 @@ namespace test {
using lib::meta::typeSymbol;
using lib::meta::is_Tuple;
using std::decay_t;
using std::vector;
using std::get;
// using util::join;
// using util::isnil;
// using std::vector;
// using std::shared_ptr;
// using std::make_shared;
// using LERR_(ITER_EXHAUST);
// using LERR_(INDEX_BOUNDS);
namespace { // test fixture
// const uint NUM_ELMS = 10;
// using Numz = vector<uint>;
} // (END)fixture
/************************************************************************//**
* @test verify helpers and shortcuts for simple recursive descent parsing
/****************************************************//**
* @test verify support for recursive descent parsing
* of structured data and specifications.
*
* @see parse.hpp
* @see proc-node.cpp "usage example"
*/
@ -77,6 +52,7 @@ namespace test {
run (Arg)
{
simpleUsage();
acceptTerminal();
acceptSequential();
acceptAlternatives();
@ -90,13 +66,32 @@ namespace test {
}
/** @test TODO just blah. */
/** @test demonstrate parsing a function-with-arguments structure. */
void
simpleUsage ()
{
using Model = std::pair<string, vector<string>>;
auto word = accept("\\w+").bindMatch();
auto term = accept(word)
.bracket (accept_repeated(",", word))
.bind([](auto res){ return Model{get<0>(res),get<1>(res)}; });
CHECK (not term.hasResult());
term.parse("great (hypertrophy, confusion, deception, profit)");
CHECK (term.success());
Model model = term.getResult();
CHECK (model.first == "great");
CHECK (model.second[0] == "hypertrophy");
CHECK (model.second[1] == "confusion" );
CHECK (model.second[2] == "deception" );
CHECK (model.second[3] == "profit" );
}
/** @test define a terminal symbol to match by parse. */
void
acceptTerminal()
@ -106,7 +101,7 @@ namespace test {
string toParse{"hello vile world of power"};
auto eval = parse (toParse);
CHECK (eval.result);
smatch res = *eval.result; // ◁——————————— the »result model« of a terminal parse is the RegExp-Matcher
smatch res = *eval.result; // ◁——————————————————————— »result model« of a terminal parse is the RegExp-Matcher
CHECK (res.ready() and not res.empty());
CHECK (res.size() == "2"_expect );
CHECK (res.position() == "0"_expect );
@ -133,7 +128,7 @@ namespace test {
// Going full circle: extract Parser definition from syntax
auto parse2 = Parser{syntax2};
CHECK (eval.result->str(1) == "vile");
CHECK (eval.result->str(1) == "vile"); // leftover value
eval = parse2 (toParse);
CHECK (not eval.result);
eval = parse2 (bye);
@ -145,7 +140,7 @@ namespace test {
* - first demonstrate explicitly how the consecutive parsing works
* and how both models are combined into a product model (tuple)
* - demonstrate how leading whitespace is skipped automatically
* - then perform the same parse with a Syntax clause build with
* - then perform the same parse with a Syntax clause, built by
* the `seq()` builder-DSL
* - extend this Syntax by adding a further sequential clause.
*/
@ -198,8 +193,8 @@ namespace test {
CHECK (not term2.parse(" old ").result);
//___________________________________________________
// DSL parse clause builder: a sequence of terminals...
//____________________________________________________
// DSL syntax clause builder: a sequence of terminals...
auto syntax = accept("hello").seq("world");
// Perform the same parse as demonstrated above....
@ -214,8 +209,9 @@ namespace test {
// can build extended clause from existing one
auto syntax2 = syntax.seq("trade");
auto syntax2 = accept(syntax).seq("trade"); // Warning: seq() moves the parse function (but accept() has created a copy)
CHECK (not syntax2.hasResult());
CHECK ( syntax.hasResult()); // ...so the syntax2 is indeed an independent instance now
syntax2.parse(s2);
CHECK (not syntax2.success());
syntax2.parse(s3);
@ -228,11 +224,12 @@ namespace test {
/** @test define alternative syntax structures to match by parse.
/** @test define alternative syntax clauses to match by parse.
* - first demonstrate how a model with alternative branches can be
* populated and gradually extended while searching for a match.
* - then show explicitly the logic to check and select branches
* and construct the corresponding sum-model (variant)
* - finally demonstrate equivalent behaviour using the DSL
*/
void
acceptAlternatives()
@ -340,7 +337,7 @@ namespace test {
CHECK (altModel.get<0>().str() == "brazen");
// can build extended clause from existing one
auto syntax2 = syntax.alt("smarmy (\\w+)");
auto syntax2 = accept(syntax).alt("smarmy (\\w+)");
CHECK (not syntax2.hasResult());
syntax2.parse(s1);
CHECK (not syntax2.success());
@ -370,10 +367,10 @@ namespace test {
{ //_______________________________________________
// Demonstration: how repetitive sequence works....
auto sep = buildConnex (",");
auto term = buildConnex ("\\w+");
auto word = buildConnex ("\\w+");
auto parseSeq = [&](StrView toParse)
{
using Res = decltype(term)::Result;
using Res = decltype(word)::Result;
using IterResult = std::vector<Res>;
using IterEval = Eval<IterResult>;
uint consumed{0};
@ -389,7 +386,7 @@ namespace test {
break;
offset += delim.consumed;
}
auto eval = term.parse (toParse.substr(offset));
auto eval = word.parse (toParse.substr(offset));
if (not eval.result)
break;
offset += eval.consumed;
@ -424,7 +421,7 @@ namespace test {
//______________________________________________
// DSL parse clause builder: iterative sequence...
auto syntax1 = accept_repeated(",", term);
auto syntax1 = accept_repeated(",", word);
// Perform the same parse as demonstrated above....
CHECK (not syntax1.hasResult());
@ -442,8 +439,8 @@ namespace test {
CHECK (res1[1].str() == "extort" );
CHECK (res1[2].str() == "profit" );
auto syntax2 = accept_repeated(1,2,",", term);
auto syntax3 = accept_repeated( 4,",", term);
auto syntax2 = accept_repeated(1,2,",", word);
auto syntax3 = accept_repeated( 4,",", word);
syntax2.parse(s2);
syntax3.parse(s2);
CHECK ( syntax2);
@ -460,7 +457,7 @@ namespace test {
CHECK (syntax3.getResult()[2].str() == "profit" );
CHECK (syntax3.getResult()[3].str() == "dump" );
auto syntax4 = accept_repeated(term);
auto syntax4 = accept_repeated(word);
syntax4.parse(s1);
CHECK (syntax4.success());
CHECK (syntax4.getResult().size() == 2);
@ -743,6 +740,7 @@ namespace test {
.alt(quote)
.alt(paren));
// abbreviation for the test...
auto apply = [](auto& syntax)
{ return [&](auto const& str)
{ return accept(syntax).bindMatch()
@ -751,25 +749,25 @@ namespace test {
};
};
SHOW_EXPR(apply(content)("prey .. haul .. loot"))
SHOW_EXPR(apply(content)("prey .. haul ,. loot"))
SHOW_EXPR(apply(content)("prey .( haul ,. loot"))
CHECK (apply(content)("prey .. haul .. loot") == "prey .. haul .. loot"_expect );
CHECK (apply(content)("prey .. haul ,. loot") == "prey .. haul "_expect );
CHECK (apply(content)("prey .( haul ,. loot") == "prey ."_expect );
SHOW_EXPR(apply(quote)("\"prey .( haul ,\"loot"))
SHOW_EXPR(apply(quote)("\"prey \\ haul ,\"loot"))
SHOW_EXPR(apply(quote)("\"prey\\\"haul ,\"loot"))
CHECK (apply(quote)("\"prey .( haul ,\"loot") == "\"prey .( haul ,\""_expect );
CHECK (apply(quote)("\"prey \\ haul ,\"loot") == "\"prey \\ haul ,\""_expect );
CHECK (apply(quote)("\"prey\\\"haul ,\"loot") == "\"prey\\\"haul ,\""_expect );
SHOW_EXPR(apply(paren)("(prey) .. haul .. loot"))
SHOW_EXPR(apply(paren)("(prey .. haul .. loot)"))
SHOW_EXPR(apply(paren)("(prey(..(haul)..)loot)"))
SHOW_EXPR(apply(paren)("(prey \" haul)\" loot)"))
SHOW_EXPR(apply(paren)("(prey\\( haul)\" loot)"))
CHECK (apply(paren)("(prey) .. haul .. loot") == "(prey)"_expect );
CHECK (apply(paren)("(prey .. haul .. loot)") == "(prey .. haul .. loot)"_expect );
CHECK (apply(paren)("(prey(..(haul)..)loot)") == "(prey(..(haul)..)loot)"_expect );
CHECK (apply(paren)("(prey \" haul)\" loot)") == "(prey \" haul)\" loot)"_expect );
CHECK (apply(paren)("(prey\\( haul)\" loot)") == "(prey\\( haul)"_expect );
SHOW_EXPR(apply(spec)("\"prey .( haul ,\"loot!"))
SHOW_EXPR(apply(spec)("\"prey .( haul \",loot!"))
SHOW_EXPR(apply(spec)(" prey .( haul \",loot!"))
SHOW_EXPR(apply(spec)(" prey .( haul )\"loot!"))
SHOW_EXPR(apply(spec)(" (prey\\( haul }, loot)"))
CHECK (apply(spec)("\"prey .( haul ,\"loot!") == "\"prey .( haul ,\"loot!"_expect);
CHECK (apply(spec)("\"prey .( haul \",loot!") == "\"prey .( haul \""_expect );
CHECK (apply(spec)(" prey .( haul \",loot!") == "prey ."_expect );
CHECK (apply(spec)(" prey .( haul,)\"loot!") == "prey .( haul,)"_expect );
CHECK (apply(spec)(" (prey\\( haul }, loot)") == "(prey\\( haul }, loot)"_expect );
}
};

View file

@ -55169,7 +55169,8 @@
</node>
<node CREATED="1736882670002" ID="ID_1282038470" MODIFIED="1736883801040" TEXT="schlankes Parser-Combinator-Framework">
<linktarget COLOR="#586e82" DESTINATION="ID_1282038470" ENDARROW="Default" ENDINCLINATION="-1550;3855;" ID="Arrow_ID_950785657" SOURCE="ID_1113355653" STARTARROW="None" STARTINCLINATION="1131;56;"/>
<node CREATED="1736718095868" ID="ID_149635951" MODIFIED="1736718100054" TEXT="Skizze">
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#306476" CREATED="1736718095868" ID="ID_149635951" MODIFIED="1737603564463" TEXT="Skizze">
<icon BUILTIN="idea"/>
<node CREATED="1736718101981" ID="ID_749637806" MODIFIED="1736718178019" TEXT="Parser">
<node CREATED="1736718185911" ID="ID_869386255" MODIFIED="1736718261272" TEXT="StrView &#x27fc; Eval&lt;RES&gt;"/>
<node CREATED="1736718295056" ID="ID_1924298162" MODIFIED="1736718391443" TEXT="construct">
@ -55277,9 +55278,11 @@
<node CREATED="1736728565818" ID="ID_787144515" MODIFIED="1736728580729" TEXT="PAR : Parser-Typ konfiguriert die Syntax"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1736811553465" ID="ID_758725308" MODIFIED="1736897374205" TEXT="Ausarbeitung einer Implementierung">
<icon BUILTIN="pencil"/>
<node CREATED="1736811562712" ID="ID_501249017" MODIFIED="1736811566252" TEXT="Entscheidungen">
<node COLOR="#338800" CREATED="1736811553465" ID="ID_758725308" MODIFIED="1738186737822" TEXT="Ausarbeitung einer Implementierung">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1736811562712" ID="ID_501249017" MODIFIED="1738186387349" TEXT="Entscheidungen">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="list"/>
<node CREATED="1736817250352" ID="ID_401051695" MODIFIED="1736817482304" TEXT="vom pragmatischen Nutzen her aufbauen">
<richcontent TYPE="NOTE"><html>
<head/>
@ -55333,7 +55336,8 @@
</body>
</html></richcontent>
</node>
<node CREATED="1736885232130" ID="ID_611424900" MODIFIED="1736885246544" TEXT="Stateful aber nicht zuweisbar">
<node CREATED="1736885232130" ID="ID_611424900" MODIFIED="1738186097643" TEXT="Stateful und zuweisbar">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1736885268189" ID="ID_836482464" MODIFIED="1736885685286" TEXT="stateful erscheint sinnvoll wegen der Builder-Notation">
<richcontent TYPE="NOTE"><html>
<head/>
@ -55344,12 +55348,22 @@
</body>
</html></richcontent>
</node>
<node CREATED="1736885690901" ID="ID_728944641" MODIFIED="1736885913639" TEXT="Kann nicht zuweisbar sein, aufgrund der &#x3bb;-inline-Storage">
<node CREATED="1736885690901" ID="ID_728944641" MODIFIED="1738186084054" TEXT="Kann nicht immer zuweisbar sein, aufgrund der &#x3bb;-inline-Storage">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Wenn man schon ein zustandsbehaftetes Objekt akzeptiert, k&#246;nnte auch Zuweisbarkeit bequem sein (man mu&#223; dann ja ohnehin aufpassen). Allerdings steht das im Konflikt mit dem Ansatz einer fein-granularen Typisierung, welche die Modell-Struktur abbildet. Und die Entscheidung, die recursive-descent-Struktur als parse-&#955; einzubetten, verbietet explizit die Zuweisbarkeit, denn man kann (und darf) nicht wissen, was in der Closure steckt
Wenn man schon ein zustandsbehaftetes Objekt akzeptiert, k&#246;nnte auch Zuweisbarkeit bequem sein (man mu&#223; dann ja ohnehin aufpassen). Allerdings steht das im Konflikt mit dem Ansatz einer fein-granularen Typisierung, welche die Modell-Struktur abbildet. Und die Entscheidung, die recursive-descent-Struktur als parse-&#955; einzubetten, verhindert in den meisten F&#228;llen die Zuweisbarkeit, denn man kann (und darf) nicht wissen, was in der Closure steckt
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1738186099863" ID="ID_1323355794" MODIFIED="1738186211338" TEXT="zur Unterst&#xfc;tzung rekursiver Syntax wird Zuweisung aber ben&#xf6;tigt">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
....in der weiteren Entwicklung zeigte sich, da&#223; der Ansatz mit den direkt aufgegriffenen &#955;-Typen seine Grenzen findet, sobald die Syntax-Klauseln rekursiv werden; in diesem Fall m&#252;&#223;en wir explizit die Typisierung <i>abschneiden.</i>&#160;Das ist ein Kompromi&#223;, den ich f&#252;r angemessen halte
</p>
</body>
</html></richcontent>
@ -55404,10 +55418,71 @@
</body>
</html></richcontent>
</node>
<node CREATED="1738185613258" ID="ID_1951563893" MODIFIED="1738185902080" TEXT="Model-Komposition folgt automatisch der Syntax-Struktur (Metaprogramming)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Das ist eine grunds&#228;tzliche Entscheidung, die direkt aus den explizit aufgegriffenen und eingebundenen &#955;-Typen folgt:
</p>
<ul>
<li>
dieses Framework baut selber <b>keinen Syntaxbaum auf</b>
</li>
<li>
daf&#252;r aber verwenden wir Metaprogrammierung, um aus den Builder-DSL-Aufrufen einen strukturierten Model-Term aufzubauen, der dem Aufbau der Syntax folgt
</li>
</ul>
</body>
</html></richcontent>
<arrowlink COLOR="#387ba0" DESTINATION="ID_364383845" ENDARROW="Default" ENDINCLINATION="188;-1058;" ID="Arrow_ID_1232592082" STARTARROW="None" STARTINCLINATION="1081;40;"/>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1736811967713" ID="ID_1645773137" MODIFIED="1736897400600" TEXT="Aufbau">
<node CREATED="1738185903843" ID="ID_780195440" MODIFIED="1738186010535" TEXT="per explizitem binding-&#x3bb; l&#xe4;&#xdf;t sich jedoch das Model jederzeit reduzieren">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...man ist also nicht in die komplexen, verschachtelten Strukturen hineingezwungen, sondern kann an strategisch g&#252;nstiger Stelle in einen eigenen Model-Typ &#252;bersetzen; f&#252;r die unterst&#252;tzung rekursiver Syntax-Klauseln erweist sich das sogar als essentiell
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1738186239565" ID="ID_1545863351" MODIFIED="1738186377434" TEXT="Einstiegspunkte in Funktions-Notation bieten (vorsicht mit Postfix-Operatoren)">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Aus Sicht der technischen Konstruktion erschien es mir erst sehr naheliegend, die DSL-Syntax weitgehend auf Postfix-Operatoren aufzubauen. Das erwies sich als Trugschlu&#223;, denn solche Konstrukte sind in der praktischen Anwendung schwer zu durchschauen. Daher habe ich die Pr&#228;ferenzen unterwegs ge&#228;ndert und die DSL so umstrukturiert, da&#223; sie eine Reihe freier Funktionen als Einstiegspunkt bietet, und diese freien Funktionen auch dazu dienen sollen, verschachtelte Sub-Syntax-Klauseln einzuleiten
</p>
</body>
</html></richcontent>
</node>
<node CREATED="1738186420476" ID="ID_1410288950" MODIFIED="1738186727976" TEXT="Rekursion erm&#xf6;glichen durch pre-deklarierte Klauseln und Bindings">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
Rekursion ist ein essentielles Element jeden echten Parsers; sie ist aber auch komplex (und potentiell nicht-terminierend). Daher sollen die meisten Anwendungsf&#228;lle durch vorgefertigte Syntax-Elemente (Repetition und Klammerung) abgefangen werden. F&#252;r die sonstigen F&#228;lle verlangen wir vom Benutzer etwas Vorarbeit: der Model-Result-Type mu&#223; in diesem Fall durch ein Binding <i>reduziert werden</i>, so da&#223; das Ergebnis einer rekursiven Referenz bereits feststeht. Damit konnte an der Stelle (mithilfe von std::function) eine elegante L&#246;sung gefunden werden, die nach au&#223;en nahezu unsichtbar bleibt:
</p>
<ul>
<li>
der Benutzer mu&#223; rekursiv zu referenzierende Klauseln vordefinieren, mit angegebenem Ergebnistyp
</li>
<li>
sp&#228;ter mu&#223; in der Definition der Klausel am Ende ein Model-Binding stehen, das <i>genau diesen Result-Typ liefert</i>
</li>
<li>
schlie&#223;lich wird diese Definition dem pre-deklarierten Syntax-Objekt <b>zugewiesen</b>
</li>
</ul>
</body>
</html></richcontent>
</node>
</node>
<node BACKGROUND_COLOR="#dbf0b6" COLOR="#006399" CREATED="1736811967713" ID="ID_1645773137" MODIFIED="1738185134450" TEXT="Aufbau">
<icon BUILTIN="edit"/>
<node CREATED="1736811972979" ID="ID_1413698396" MODIFIED="1736812166866" TEXT="Policy-Base als Struktur-Konfiguration">
<node COLOR="#435e98" CREATED="1736811972979" ID="ID_1413698396" MODIFIED="1738185498885" TEXT="Policy-Base als Struktur-Konfiguration">
<icon BUILTIN="yes"/>
<node CREATED="1736812168622" ID="ID_596543939" MODIFIED="1736812184719" TEXT="Parser erbt die Funktor-Eigenschaft von der Policy-Base"/>
<node CREATED="1736815274234" ID="ID_1286749463" MODIFIED="1736815303733">
<richcontent TYPE="NODE"><html>
@ -55420,7 +55495,8 @@
</html></richcontent>
</node>
</node>
<node CREATED="1736875251595" ID="ID_193269102" MODIFIED="1736875261198" TEXT="Regexp-search">
<node COLOR="#338800" CREATED="1736875251595" ID="ID_193269102" MODIFIED="1738185491685" TEXT="Regexp-search">
<icon BUILTIN="button_ok"/>
<node CREATED="1736875265103" ID="ID_205680289" MODIFIED="1736875271589" TEXT="oops ... gar nicht so einfach"/>
<node CREATED="1736875272991" ID="ID_460559047" MODIFIED="1736875300935" TEXT="deshalb verwende ich fast &#xfc;berall meinen RegexSearchIterator"/>
<node CREATED="1736875303467" ID="ID_376628405" MODIFIED="1736875334408" TEXT="Problem: Match-Verankerung am Anfang">
@ -55457,7 +55533,7 @@
</node>
</node>
</node>
<node CREATED="1736896942694" ID="ID_50956958" MODIFIED="1737649641200" TEXT="Kreis schlie&#xdf;en: Parser wieder aus Syntax bauen">
<node COLOR="#435e98" CREATED="1736896942694" ID="ID_50956958" MODIFIED="1738185461447" TEXT="Kreis schlie&#xdf;en: Parser wieder aus Syntax bauen">
<linktarget COLOR="#587bde" 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"/>
@ -55490,7 +55566,8 @@
<node CREATED="1737656610177" ID="ID_1186453687" MODIFIED="1737656620354" TEXT="Syntax mu&#xdf; conversion-Operator bieten"/>
</node>
</node>
<node CREATED="1736897170512" ID="ID_28739070" MODIFIED="1736897191019" TEXT="Fazit: mu&#xdf; sinnvollerweise direkt aus Syntax heraus angesto&#xdf;en werden">
<node COLOR="#435e98" CREATED="1736897170512" ID="ID_28739070" MODIFIED="1738185475861" TEXT="Fazit: mu&#xdf; sinnvollerweise direkt aus Syntax heraus angesto&#xdf;en werden">
<icon BUILTIN="forward"/>
<node CREATED="1736897207538" ID="ID_953670876" MODIFIED="1736897215717" TEXT="das ist wohl akzeptabel"/>
<node CREATED="1736897216258" ID="ID_1489413453" MODIFIED="1736897231402" TEXT="wirklich gebraucht wird es nur als Basis f&#xfc;r die Combinator-Implementierung"/>
<node CREATED="1736897235991" ID="ID_444935473" MODIFIED="1736897247114" TEXT="diese k&#xf6;nnte man aber auch in buildConnex verlagern">
@ -55606,7 +55683,7 @@
</body>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#f8f1cb" COLOR="#a50125" CREATED="1736948672141" ID="ID_134095537" MODIFIED="1736948681272" TEXT="k&#xf6;nnte potentiell unerw&#xfc;nscht sein">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1736948672141" ID="ID_134095537" MODIFIED="1738185414315" TEXT="k&#xf6;nnte potentiell unerw&#xfc;nscht sein">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1736948788817" ID="ID_239959705" MODIFIED="1736949060127" TEXT="Beispiel: geklammerte Sequenz in der Syntax, weitere Sequenz">
<richcontent TYPE="NOTE"><html>
@ -55630,7 +55707,7 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#380f69" CREATED="1736968942247" ID="ID_917376104" MODIFIED="1737511498798" TEXT="mu&#xdf; Anfangswert der Fold-Sequenz explizit konstruieren">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#380f69" CREATED="1736968942247" FOLDED="true" ID="ID_917376104" MODIFIED="1737511498798" TEXT="mu&#xdf; Anfangswert der Fold-Sequenz explizit konstruieren">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1736971224510" ID="ID_1155045892" MODIFIED="1736972005211" TEXT="das kann aber durch Binding-Komposition realisiert werden">
<richcontent TYPE="NOTE"><html>
@ -55797,8 +55874,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1736988419593" ID="ID_364383845" MODIFIED="1737511653707" TEXT="Pattern-Match und Spezialfall-Implementierung">
<icon BUILTIN="pencil"/>
<node COLOR="#338800" CREATED="1736988419593" ID="ID_364383845" MODIFIED="1738185722929" TEXT="Pattern-Match und Spezialfall-Implementierung">
<linktarget COLOR="#387ba0" DESTINATION="ID_364383845" ENDARROW="Default" ENDINCLINATION="188;-1058;" ID="Arrow_ID_1232592082" SOURCE="ID_1951563893" STARTARROW="None" STARTINCLINATION="1081;40;"/>
<icon BUILTIN="button_ok"/>
<node CREATED="1736988439351" ID="ID_396611819" MODIFIED="1736988490982" TEXT="verwende ein explizit definiertes Tag: Sub&lt;X&gt;"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1736988542489" ID="ID_1635129166" MODIFIED="1737234629319" TEXT="Model-Join extrahieren">
<arrowlink COLOR="#465acd" DESTINATION="ID_226754618" ENDARROW="Default" ENDINCLINATION="-418;52;" ID="Arrow_ID_1636406845" STARTARROW="None" STARTINCLINATION="-11;79;"/>
@ -55869,8 +55947,8 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1737048069726" ID="ID_129104167" MODIFIED="1737048085836" TEXT="Fall-Differenzierung der _Join-Konstruktoren">
<icon BUILTIN="flag-pink"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#4e1da1" CREATED="1737048069726" ID="ID_129104167" MODIFIED="1738185172292" TEXT="Fall-Differenzierung der _Join-Konstruktoren">
<icon BUILTIN="forward"/>
<node CREATED="1737234497746" ID="ID_936287985" MODIFIED="1737234549166" TEXT="Sequence">
<icon BUILTIN="info"/>
<node COLOR="#435e98" CREATED="1737234502793" ID="ID_1552148571" MODIFIED="1737234536557" TEXT="akzeptiere zwei Werte &#x27f6; Paar"/>
@ -55882,6 +55960,10 @@
<node COLOR="#435e98" CREATED="1737511691172" ID="ID_1192322879" MODIFIED="1737511740655" TEXT="akzeptiere AltModel + Wert &#x27f6; neuen Fall f&#xfc;r &#xab;Wert&#xbb; zum AltModel hinzuf&#xfc;gen"/>
</node>
</node>
<node BACKGROUND_COLOR="#c3c9ac" COLOR="#338800" CREATED="1738185189251" HGAP="-3" ID="ID_1949817857" MODIFIED="1738185220941" TEXT="das gen&#xfc;gt um das Thema in den Griff zu bekommen" VSHIFT="7">
<font NAME="SansSerif" SIZE="10"/>
<icon BUILTIN="button_ok"/>
</node>
</node>
</node>
<node COLOR="#338800" CREATED="1737048133742" ID="ID_1028852897" MODIFIED="1737511601637" TEXT="Einbindung in die DSL-Notation (class Syntax)">
@ -56023,7 +56105,7 @@
<node COLOR="#338800" CREATED="1737511832794" ID="ID_209338146" MODIFIED="1737511947153" TEXT="Steuerung der Model-Komposition l&#xf6;sen">
<arrowlink COLOR="#579bd2" DESTINATION="ID_226754618" ENDARROW="Default" ENDINCLINATION="6;427;" ID="Arrow_ID_220186183" STARTARROW="None" STARTINCLINATION="1852;-83;"/>
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1737511902291" HGAP="21" ID="ID_1061539705" MODIFIED="1737512327118" TEXT="die F&#xe4;lle werden &#xfc;bersetzt in Template-Spezialisierungen" VSHIFT="19"/>
<node COLOR="#435e98" CREATED="1737511902291" HGAP="22" ID="ID_1061539705" MODIFIED="1737512327118" TEXT="die F&#xe4;lle werden &#xfc;bersetzt in Template-Spezialisierungen" VSHIFT="36"/>
<node COLOR="#435e98" CREATED="1737511916591" ID="ID_1159668962" MODIFIED="1737511950227" TEXT="zus&#xe4;tzliches Marker-Template um verschachtelte Sub-Ausdr&#xfc;cke auszuklammern"/>
<node COLOR="#438798" CREATED="1737512313284" HGAP="21" ID="ID_1608529418" LINK="#ID_1402725802" MODIFIED="1737512347700" TEXT="(partielle) Typsicherheit auch beim Variant-Model">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737512357123" ID="ID_1348106042" MODIFIED="1737512388092" TEXT="Aber: im Model-Binding mu&#xdf; man die Selektoren korrekt verwenden"/>
@ -57237,6 +57319,20 @@
<node CREATED="1737817647567" ID="ID_1641437634" MODIFIED="1737817658826" TEXT="bindMatch() k&#xf6;nnte noch mehr tun"/>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1737849826967" ID="ID_1650492122" MODIFIED="1737849845902" TEXT="erst mal weiter sehen wie sehr das in der Praxis hindert">
<icon BUILTIN="hourglass"/>
<node CREATED="1738184826030" ID="ID_1210934055" MODIFIED="1738184962313" TEXT="denke n&#xe4;mlich: mit konsistentem Schema nicht so schlimm">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...rein nach Bauchgef&#252;hl d&#252;rfte das in der Praxis dann doch nicht so schlimm werden, sofern man konsistent jede Klausel auch mit einem Binding ausstattet, und die Ergebnistypen systematisch aufbaut. Schlie&#223;lich ist <i>das ja auch die Aufgabe schlechthin beim Parsen</i>
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#8f8aac" DESTINATION="ID_1009402167" ENDARROW="Default" ENDINCLINATION="545;-25;" ID="Arrow_ID_1645190934" STARTARROW="None" STARTINCLINATION="798;36;"/>
</node>
<node CREATED="1738185035229" ID="ID_485779056" MODIFIED="1738185093251" TEXT="noch eine Vereinfachung f&#xfc;r Alternativen...">
<arrowlink COLOR="#747687" DESTINATION="ID_944982552" ENDARROW="Default" ENDINCLINATION="306;23;" ID="Arrow_ID_1188443457" STARTARROW="None" STARTINCLINATION="467;31;"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1737776743702" ID="ID_1501521982" MODIFIED="1737817618502" TEXT="sonderbares Verhalten mit zwe sub-Syntax-Klauseln und Binder">
@ -57747,9 +57843,10 @@
<arrowlink COLOR="#a670c5" DESTINATION="ID_476963617" ENDARROW="Default" ENDINCLINATION="63;87;" ID="Arrow_ID_1307955722" STARTARROW="None" STARTINCLINATION="391;0;"/>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1737509793049" ID="ID_1654271031" MODIFIED="1738091231539" TEXT="erwartete Verwendung im Test durchspielen">
<node COLOR="#338800" CREATED="1737509793049" ID="ID_1654271031" MODIFIED="1738184702812" TEXT="erwartete Verwendung im Test durchspielen">
<arrowlink COLOR="#69a19e" DESTINATION="ID_1564220447" ENDARROW="Default" ENDINCLINATION="365;-30;" ID="Arrow_ID_30873436" STARTARROW="None" STARTINCLINATION="-288;17;"/>
<icon BUILTIN="pencil"/>
<arrowlink COLOR="#69a19e" DESTINATION="ID_984253455" ENDARROW="Default" ENDINCLINATION="207;0;" ID="Arrow_ID_1995388637" STARTARROW="None" STARTINCLINATION="-288;17;"/>
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#0d4d48" CREATED="1738089850124" ID="ID_169271928" MODIFIED="1738092642222" TEXT="Beispiel: numerischer Ausdruck">
<icon BUILTIN="button_ok"/>
<node CREATED="1738089863497" ID="ID_988046108" MODIFIED="1738091511457" TEXT="&#xbb;der Klassiker&#xab;">
@ -57788,6 +57885,7 @@
</node>
<node CREATED="1738090134820" ID="ID_1211990966" MODIFIED="1738090144679" TEXT="daf&#xfc;r kann der Visitor einen Wert liefern"/>
<node COLOR="#435e98" CREATED="1738090145459" ID="ID_944982552" MODIFIED="1738090158609" TEXT="vordefiniert als AltModel::getAny()">
<linktarget COLOR="#747687" DESTINATION="ID_944982552" ENDARROW="Default" ENDINCLINATION="306;23;" ID="Arrow_ID_1188443457" SOURCE="ID_485779056" STARTARROW="None" STARTINCLINATION="467;31;"/>
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f4a" CREATED="1738090228760" ID="ID_1868530708" MODIFIED="1738090248792" TEXT="compiliert nur bei kompatiblen Typen"/>
@ -57807,6 +57905,7 @@
</p>
</body>
</html></richcontent>
<linktarget COLOR="#8f8aac" DESTINATION="ID_1009402167" ENDARROW="Default" ENDINCLINATION="545;-25;" ID="Arrow_ID_1645190934" SOURCE="ID_1210934055" STARTARROW="None" STARTINCLINATION="798;36;"/>
</node>
</node>
<node BACKGROUND_COLOR="#e4eda1" COLOR="#007199" CREATED="1738090286760" ID="ID_1538254940" MODIFIED="1738090327155" STYLE="fork" TEXT="kann &#x3a6; ausrechnen">
@ -57817,9 +57916,9 @@
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1738092650202" ID="ID_1683123511" MODIFIED="1738092666047" TEXT="Beispiel: verschachtelte Definition">
<icon BUILTIN="pencil"/>
<node BACKGROUND_COLOR="#c8b8b6" COLOR="#464398" CREATED="1738092667144" ID="ID_195611513" MODIFIED="1738093265339" TEXT="der Anla&#xdf; warum ich dieses Parser-Framework baue...">
<node COLOR="#338800" CREATED="1738092650202" ID="ID_1683123511" MODIFIED="1738184455603" TEXT="Beispiel: verschachtelte Definition">
<icon BUILTIN="button_ok"/>
<node BACKGROUND_COLOR="#c8b8b6" COLOR="#464398" CREATED="1738092667144" ID="ID_195611513" MODIFIED="1738185016897" TEXT="der Anla&#xdf; warum ich dieses Parser-Framework baue...">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
@ -57828,7 +57927,7 @@
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#2469a2" DESTINATION="ID_461276578" ENDARROW="Default" ENDINCLINATION="1338;-36;" ID="Arrow_ID_1078242662" STARTARROW="Default" STARTINCLINATION="1431;72;"/>
<arrowlink COLOR="#2469a2" DESTINATION="ID_461276578" ENDARROW="Default" ENDINCLINATION="1338;-36;" ID="Arrow_ID_1078242662" STARTARROW="Default" STARTINCLINATION="1743;85;"/>
<icon BUILTIN="idea"/>
</node>
<node CREATED="1738122898074" ID="ID_1357593394" MODIFIED="1738122916309" TEXT="Ansatz">
@ -57858,7 +57957,7 @@
<node COLOR="#338800" CREATED="1738123171366" ID="ID_276974401" MODIFIED="1738123177620" TEXT="funktioniert grunds&#xe4;tzlich">
<icon BUILTIN="button_ok"/>
</node>
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1738123178974" ID="ID_1533306886" MODIFIED="1738123194597" TEXT="interessantes Fehlverhalten im Test">
<node COLOR="#435e98" CREATED="1738123178974" ID="ID_1533306886" MODIFIED="1738183220672" TEXT="subtiles Fehlverhalten im Test">
<icon BUILTIN="broken-line"/>
<node CREATED="1738123415378" ID="ID_1843918790" MODIFIED="1738123415378" TEXT="apply(spec)(&quot; prey .( haul \&quot;,loot!&quot;) ? = prey .(">
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#b0020b" CREATED="1738123430342" HGAP="69" ID="ID_1506770904" MODIFIED="1738123808483" TEXT="h&#xe4;tte die &#xf6;ffnende Klammer nicht mitnehmen d&#xfc;rfen" VSHIFT="-1">
@ -57872,11 +57971,73 @@
<font NAME="SansSerif" SIZE="11"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1738182888797" ID="ID_1993951028" MODIFIED="1738182912516">
<richcontent TYPE="NODE"><html>
<head/>
<body>
<p>
Beobachtung: beide haben zwei <b>f&#252;hrende Leerzeichen</b>
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
<node CREATED="1738182914123" ID="ID_394609963" MODIFIED="1738182928052" TEXT="best&#xe4;tigt: wenn man die wegl&#xe4;&#xdf;t..."/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1738183187384" ID="ID_343204836" MODIFIED="1738183346750" TEXT="Fehler in bindMatch &#x27f6; toStringConnex">
<icon BUILTIN="broken-line"/>
<node CREATED="1738183227236" ID="ID_1686109910" MODIFIED="1738183247164" TEXT="hier der fallback-Zweig wirksam">
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1738183248251" ID="ID_740895759" MODIFIED="1738183344746" TEXT="wir ermitteln nochmal erneut den leading Whitespace">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
das liegt daran, da&#223; wir diese Info nicht aufzeichnen, weil generell das Akzeptieren (und Backtracking) durch rekursiven Funktionsaufruf auf Substrings realisiert ist...
</p>
</body>
</html></richcontent>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1738183296979" ID="ID_643934059" MODIFIED="1738183337373" TEXT="wenn vorne ein Pr&#xe4;fix wegf&#xe4;llt, mu&#xdf; nat&#xfc;rlich die L&#xe4;nge gek&#xfc;rzt werden!">
<icon BUILTIN="broken-line"/>
</node>
</node>
</node>
</node>
<node CREATED="1737048820482" ID="ID_235554745" MODIFIED="1737048832524" TEXT="generisches Model-Binding"/>
</node>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1738186832857" ID="ID_175116703" MODIFIED="1738186839257" TEXT="Fazit">
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="forward"/>
<node CREATED="1738186840421" ID="ID_795784976" MODIFIED="1738186853307" TEXT="ein Header lib/parse.hpp mit minimalen Dependencies"/>
<node CREATED="1738186854355" ID="ID_1978636423" MODIFIED="1738186880579" TEXT="DSL-Einstieg util::parse::accept(SPEC)"/>
<node CREATED="1738186885365" ID="ID_966881156" MODIFIED="1738186905222" TEXT="Recursive-Descent LL(n)-Parser ohne Lexer"/>
<node CREATED="1738186909557" ID="ID_1064621860" MODIFIED="1738186931396" TEXT="Parser-Kombinator-Technik eingebettet in eine DSL">
<node CREATED="1738186932909" ID="ID_1673393435" MODIFIED="1738186950076" TEXT="Kombinatoren sind reine Implementierungs-Technik"/>
<node CREATED="1738186951862" ID="ID_1935160846" MODIFIED="1738186986013" TEXT="Syntax-Objekt als Kapsel mit DSL &#x2014; keine &#xfc;berladenen Operatoren"/>
<node CREATED="1738187102068" ID="ID_247180538" MODIFIED="1738187128828" TEXT="funktionaler Ansatz f&#xfc;r Backtracking und Model-Binding"/>
</node>
<node CREATED="1738187009166" ID="ID_1048355173" MODIFIED="1738187047066" TEXT="Kein Syntax-Baum &#x2014; stattdessen komplex verschachtelte explizite &#x3bb;-Typen"/>
<node CREATED="1738187071641" ID="ID_63380090" MODIFIED="1738187073702" TEXT="Aufbau">
<node CREATED="1738187077563" ID="ID_147014086" MODIFIED="1738187098670" TEXT="Eval &#x27f5; Parse-Ergebnis"/>
<node CREATED="1738188401579" ID="ID_77338495" MODIFIED="1738188426340" TEXT="Connex &#x27f5; Parser-Funktionsbaustein"/>
<node CREATED="1738188435390" ID="ID_1061346176" MODIFIED="1738188450792" TEXT="buildXXConnex &#x27f5; die Kombinatoren als freie Funktionen"/>
<node CREATED="1738188451684" ID="ID_1681615382" MODIFIED="1738188464223" TEXT="Parser &#x27f5; Interface &#xfc;ber einen Connex"/>
<node CREATED="1738188464959" ID="ID_652466565" MODIFIED="1738188493194" TEXT="Syntax &#x27f5; verbindet Parser und ein Eval-State + DSL"/>
</node>
<node CREATED="1738188522420" ID="ID_815505663" MODIFIED="1738188532853" TEXT="Anwendung">
<node CREATED="1738188533801" ID="ID_754612180" MODIFIED="1738188565308" TEXT="eine Syntax aufbauen">
<icon BUILTIN="full-1"/>
</node>
<node CREATED="1738188547420" ID="ID_1858683440" MODIFIED="1738188567655" TEXT="auf dieser die parse()-Funktion aufrufen">
<icon BUILTIN="full-2"/>
</node>
<node CREATED="1738188555935" ID="ID_972096316" MODIFIED="1738188570346" TEXT="Ergebnis-State auswerten">
<icon BUILTIN="full-3"/>
</node>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1736884111530" ID="ID_1649572298" MODIFIED="1736897372481" TEXT="Parse_test">
@ -57943,8 +58104,31 @@
<linktarget COLOR="#69a19e" DESTINATION="ID_1564220447" ENDARROW="Default" ENDINCLINATION="365;-30;" ID="Arrow_ID_30873436" SOURCE="ID_1654271031" STARTARROW="None" STARTINCLINATION="-288;17;"/>
</node>
</node>
<node CREATED="1737845308863" ID="ID_383219766" MODIFIED="1737845313627" TEXT="simpleUsage">
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1737845314577" ID="ID_453689160" MODIFIED="1737845324102" TEXT="puh ... was zeigen wir da?">
<node COLOR="#338800" CREATED="1738184503016" ID="ID_1456096857" MODIFIED="1738184539829" TEXT="nested backets/quotes">
<icon BUILTIN="button_ok"/>
<node CREATED="1738184543947" ID="ID_988653432" MODIFIED="1738184595763" TEXT="der tats&#xe4;chliche Anwendungsfall...">
<richcontent TYPE="NOTE"><html>
<head/>
<body>
<p>
...der diese Entwicklung eines Parser-Frameworks angesto&#223;en hat
</p>
</body>
</html></richcontent>
<icon BUILTIN="ksmiletris"/>
</node>
<node COLOR="#435e98" CREATED="1738184597252" ID="ID_220015780" MODIFIED="1738184697143" TEXT="schrittweise aufbauen">
<node CREATED="1738184602060" ID="ID_1298384168" MODIFIED="1738184604647" TEXT="quotes"/>
<node CREATED="1738184605163" ID="ID_379105406" MODIFIED="1738184609791" TEXT="escapes"/>
<node CREATED="1738184610378" ID="ID_1369081517" MODIFIED="1738184614550" TEXT="geklammerter Term"/>
</node>
<node COLOR="#435e98" CREATED="1737509774878" ID="ID_984253455" MODIFIED="1738184687735" TEXT="dann die volle Spezifikations-Syntax zusammengesetzt">
<linktarget COLOR="#69a19e" DESTINATION="ID_984253455" ENDARROW="Default" ENDINCLINATION="207;0;" ID="Arrow_ID_1995388637" SOURCE="ID_1654271031" STARTARROW="None" STARTINCLINATION="-288;17;"/>
</node>
</node>
<node COLOR="#338800" CREATED="1737845308863" ID="ID_383219766" MODIFIED="1738195025527" TEXT="simpleUsage">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1737845314577" ID="ID_453689160" MODIFIED="1738195028122" TEXT="puh ... was zeigen wir da?">
<icon BUILTIN="help"/>
<node CREATED="1737845330906" ID="ID_775079358" MODIFIED="1737845372016" TEXT="nicht zu komplex machen">
<icon BUILTIN="yes"/>
@ -57953,6 +58137,9 @@
<icon BUILTIN="yes"/>
</node>
</node>
<node COLOR="#435e98" CREATED="1738188654289" ID="ID_333857981" MODIFIED="1738195032916" TEXT="Term mit Argument-Token">
<icon BUILTIN="forward"/>
</node>
</node>
</node>
</node>
@ -105160,9 +105347,9 @@ StM_bind(Builder&lt;R1&gt; b1, Extension&lt;R1,R2&gt; extension)
</body>
</html></richcontent>
</node>
<node CREATED="1738092795598" ID="ID_461276578" MODIFIED="1738093238630" TEXT="uuuuund ... kaum wart&apos; ma zwei Wochen, schon k&#xf6;nnen wir das">
<node CREATED="1738092795598" ID="ID_461276578" MODIFIED="1738185016897" TEXT="uuuuund ... kaum wart&apos; ma zwei Wochen, schon k&#xf6;nnen wir das">
<arrowlink COLOR="#996494" DESTINATION="ID_1363201028" ENDARROW="Default" ENDINCLINATION="-20;-32;" ID="Arrow_ID_621419348" STARTARROW="None" STARTINCLINATION="195;9;"/>
<linktarget COLOR="#2469a2" DESTINATION="ID_461276578" ENDARROW="Default" ENDINCLINATION="1338;-36;" ID="Arrow_ID_1078242662" SOURCE="ID_195611513" STARTARROW="Default" STARTINCLINATION="1431;72;"/>
<linktarget COLOR="#2469a2" DESTINATION="ID_461276578" ENDARROW="Default" ENDINCLINATION="1338;-36;" ID="Arrow_ID_1078242662" SOURCE="ID_195611513" STARTARROW="Default" STARTINCLINATION="1743;85;"/>
<icon BUILTIN="smily_bad"/>
</node>
</node>