Ausdrücke
Der Rumpf jeder Definition ist ein Ausdruck aus derselben kleinen Menge von Operatoren. Was darin vorkommen darf, hängt davon ab, ob der Rumpf zu einem Token oder zu einer Regel gehört.
Operatoren
| Form | Bedeutung |
|---|---|
a b | Folge: a, dann b |
a | b | geordnete Auswahl: a, und wenn das scheitert, b |
a* a+ a? | null oder mehr, eins oder mehr, null oder eins — immer gierig |
a{3} a{3,} a{3,7} | genau 3, mindestens 3, 3 bis 7 |
&a !a | nur wenn a folgt, nur wenn nicht — ohne etwas zu verbrauchen |
name:a | a unter name erfassen |
~a | kein übersprungener Leerraum vor a |
( a ) | Gruppierung |
Die Auswahl bindet am schwächsten, dann die Folge; eine Erfassung, ~, & und ! gelten für den einen Term dahinter, ein Quantor für den Term davor. & und ! selbst können keinen Quantor tragen.
Tokens und Regeln
| Element | Im Token | In der Regel |
|---|---|---|
"literal" | ja | ja — wird zum anonymen Token |
| Token-Name | ja | ja |
| Regel-Name | nein | ja |
[class] . /regex/ | ja | nein |
name: ~ @indent @samecol | nein | ja |
Die Trennung folgt aus den zwei Stufen: Eine Regel sieht immer nur Tokens, nie Zeichen. Ein Muster, das eine Regel braucht, bekommt zuerst einen Token-Namen.
a := [a-z]+
3:6: rules may not contain an inline character class -- give it a named TOKEN instead
A := a
3:6: a token body may only reference other tokens, not rule "a"
Zeichenketten-Literale
Zeichenketten stehen in doppelten Anführungszeichen und dürfen jedes Zeichen enthalten. Die Escapes sind \n, \r, \t, \\, \", \[, \], \/, \xHH mit genau zwei Hex-Ziffern und \u{H…} mit einer oder mehr; jedes andere escapte Satzzeichen steht für sich selbst, \- und \* funktionieren also auch.
Ein Suffix entscheidet die Groß-/Kleinschreibung für ein Literal: "lit"i ignoriert sie immer, "lit"cs nie. Ohne Suffix folgt ein Literal @case_insensitive, falls die Grammatik es setzt. Zeichenklassen sind davon nicht betroffen.
@grammar "literal" @root value @case_insensitive value := "true" | "false" | "null"cs
"TRUE" → ok "False" → ok "null" → ok "NULL" → 1:1: no token matches here
Zeichenklassen
[…] erkennt ein Zeichen aus einer Menge von Zeichen und a-z-Bereichen; [^…] ein Zeichen außerhalb davon, aber nie das Ende der Eingabe. Ein - direkt vor ] ist ein wörtlicher Bindestrich. In den Klammern stehen [:alpha:], [:alnum:], [:digit:], [:space:] und [:hex:] für die vordefinierten Tokens. . erkennt ein beliebiges Zeichen.
IDENT := [[:alpha:]_][[:alnum:]_]*
"_x1" → ok "1x" → 1:1: no token matches here
Wiederholung und Vorausschau
Wiederholung ist gierig und gibt nie zurück, was sie genommen hat. Auch innerhalb eines Tokens ist die Auswahl geordnet, wie dieses Farb-Token zeigt: #ff88 sind weder sechs Ziffern noch drei, also nimmt HEX{3} ff8, und die letzte 8 bleibt übrig.
COLOR := "#" (HEX{6} | HEX{3})"#ff8800" → ok "#f80" → ok "#ff88" → 1:5: no token matches here
Vorausschau prüft, ohne zu verbrauchen. Hier passt IF auf if nur, wenn kein Buchstabe und keine Ziffer folgt; iffy bleibt also ein Bezeichner:
IF := "if" !ALNUM IDENT := ALPHA ALNUM* stmt := IF IDENT | IDENT
"if x" → ok "iffy" → ok
Regex-Literale
In einem Token-Rumpf ist /muster/ eine Kurzschreibweise für den gleichwertigen Aether-Ausdruck. Unterstützt werden Zeichen, ., Klassen, |, Gruppen, alle Quantoren, (?=…) und (?!…) sowie \d \w \s \h mit ihren Negationen, die für DIGIT, ALNUM, SPACE und HEX stehen. Anker, Rückverweise und erfassende Gruppen haben in PEG keine Bedeutung und werden rundweg abgelehnt:
NUMBER := /\d+(\.\d+)?/
"3.14" → ok "3." → 1:2: no token matches here
A := /^a+$/
3:6: anchors (^) are not supported in /pattern/