Themen
PEG-Kurzreferenz
Diese Seite ist keine Einführung und kein Tutorial.
Sie ist als schnelle Nachschlage-Seite gedacht: Was gibt es alles? Wie sieht
die Syntax aus? Was kommt zurück?
Für Erklärungen und schrittweisen Aufbau sind diese Kapitel besser:
Einstiegspunkte#
| API | Input | Erfolg | Fehlschlag | Zweck |
PEG.match(grammar, input) | String | Capture-Array | undef | knapper Text-Match |
PEG.match(grammar, input, start) | String + Startoffset | Capture-Array | undef | Text-Match ab Position |
PEG.match_result(grammar, input) | String | %Ok[captures] | %Err[msg] | Text-Match mit Diagnose |
PEG.match_result(grammar, input, start) | String + Startoffset | %Ok[captures] | %Err[msg] | Text-Match mit Diagnose ab Position |
PEG.match_bytes(grammar, input) | ByteString | Capture-Array | undef | binärer Match |
PEG.match_bytes(grammar, input, start) | ByteString + Byte-Offset | Capture-Array | undef | binärer Match ab Offset |
PEG.match_bytes_result(grammar, input) | ByteString | %Ok[captures] | %Err[msg] | binärer Match mit Diagnose |
PEG.match_bytes_result(grammar, input, start) | ByteString + Byte-Offset | %Ok[captures] | %Err[msg] | binärer Match mit Diagnose ab Offset |
Primitive Patterns#
| Form | Beispiel | Bedeutung | Modus |
| String-Literal | "cat" | matcht exakt diesen Text | Text, Bytes |
| positive Zahl | 3 | konsumiert blind genau 3 Zeichen oder Bytes | Text, Bytes |
-1 | -1 | matcht nur am Ende des Inputs | Text, Bytes |
| Character-Range | 'a'..'z' | matcht genau ein Zeichen im Bereich | Text |
| Regex-Primitiv | [:regex, regex"[0-9]+"] | matcht einen Regex-Praefix an der aktuellen Position | Text |
| Regel-Keyword | :word | springt in benannte Regel oder Built-in | Text, Bytes |
Eingebaute Zeichenklassen#
| Built-in | Bedeutung |
:a | alphanumerisch |
:d | Ziffer |
:w | Buchstabe |
:s | Whitespace |
:h | hexadezimales Zeichen |
:g | druckbares ASCII-Zeichen |
Struktur-Operatoren#
| Operator | Alias | Form | Bedeutung |
:sequence | :* | [:sequence, a, b, c] | alles nacheinander |
:choice | :+ | [:choice, a, b, c] | erste passende Alternative |
:any | - | [:any, x] | 0 oder mehr |
:some | - | [:some, x] | 1 oder mehr |
:opt | :? | [:opt, x] | 0 oder 1 |
:repeat | - | [:repeat, 3, x] | genau n Wiederholungen |
:between | - | [:between, 1, 5, x] | zwischen min und max |
Lookahead und Steuerung#
| Operator | Alias | Form | Bedeutung |
:not | :! | [:not, x] | negativer Lookahead, konsumiert nichts |
:if | - | [:if, cond, patt] | matcht patt nur wenn cond hier passt |
:to | - | [:to, x] | konsumiert bis direkt vor x |
:thru | - | [:thru, x] | konsumiert bis inklusive x |
:expect | - | [:expect, patt, "beschreibung"] | benennt einen Fehler lesbar |
:cut | - | [:cut] | commitet auf den aktuellen Ast |
Capture-Operatoren#
| Operator | Alias | Form | Ergebnis |
:capture | :<- | [:capture, patt] | konsumierter Ausschnitt als Capture |
:group | - | [:group, patt] | tiefere Captures als Unter-Array |
:position | - | [:position] | aktuelle Zeichen- oder Byte-Position |
:constant | - | [:constant, v] | statischer Wert auf dem Capture-Stack |
:replace | - | [:replace, patt, fn] | ersetzt die Captures von patt durch fn(...) |
Byte-Operatoren#
Diese Formen funktionieren nur in PEG.match_bytes(...) oder
PEG.match_bytes_result(...).
| Operator | Form | Bedeutung | Capture |
:bytes | [:bytes, n] | konsumiert genau n Bytes | nein |
:byte | [:byte, n] | matcht genau ein Byte mit Wert n | nein |
:u8 | [:u8] | liest 1 Byte als Integer | ja |
:u16be | [:u16be] | liest 2 Bytes big-endian | ja |
:u16le | [:u16le] | liest 2 Bytes little-endian | ja |
:u32be | [:u32be] | liest 4 Bytes big-endian | ja |
:u32le | [:u32le] | liest 4 Bytes little-endian | ja |
:u64be | [:u64be] | liest 8 Bytes big-endian | ja |
:u64le | [:u64le] | liest 8 Bytes little-endian | ja |
:cstring | [:cstring] | liest bis zum Null-Byte | ja, als ByteString |
:take | [:take, patt] | liest erst Länge mit patt, dann Payload | ja |
Was :capture im Byte-Modus liefert#
| Pattern | Textmodus | Byte-Modus |
[:capture, patt] | String-Literalwert | ByteString |
[:capture, [:bytes, n]] | nicht anwendbar | ByteString |
[:u8], [:u16be], ... | nicht anwendbar | Integer-Capture |
Typische Rückgabewerte#
| Muster | Rückgabe |
| Erfolg ohne Captures | [] |
| Erfolg mit Captures | z. B. ["age", "42"] |
Erfolg mit :group | z. B. [["age", "42"]] |
| Result-Erfolg | %Ok[...] |
| Result-Fehler | %Err["..."] |
Wann welches Werkzeug?#
| Bedarf | Empfehlung |
| nur schnell prüfen, ob etwas passt | PEG.match(...) |
| brauchbare Fehlermeldung für Text | PEG.match_result(...) |
| brauchbare Fehlermeldung für Bytes | PEG.match_bytes_result(...) |
| lesbarer Pflichtfehler | :expect |
| nach erkennbarem Präfix keinen Fallback mehr | :cut |
| mehrere Captures zu einem Knoten bündeln | :group |
| Capture transformieren | :replace |
Ein sehr kleines Musterarchiv#
| Ziel | Muster |
| ganzer Input muss passen | [:sequence, ..., -1] |
| Wort | [:some, :w] |
| Zahl | [:some, :d] |
name:42 | [:group, [:sequence, [:capture, [:some, :w]], ":", [:capture, [:some, :d]], -1]] |
| präziser Pflichtseparator | [:expect, ":", "colon"] |
| Commit nach Präfix | [:sequence, prefix, [:cut], ...] |
| bis Zeilenende lesen | [:to, :newline] |
Wichtigste Praxisregeln#
| Regel | Kurzfassung |
-1 nicht vergessen | sonst darf am Ende Müll übrig bleiben |
:expect sparsam, aber gezielt setzen | gute Fehler statt technischer Details |
:cut erst nach klarem Präfix setzen | sonst commitest du zu früh |
| bei echten Parsern eher Result-APIs nutzen | undef ist für Diagnose zu arm |
| Byte-Formate konsequent mit Byte-API parsen | Text- und Byte-Modus nicht mischen |
Quelle dieser Seite