Signatur
Beschreibung
Parle\RParser ist Teil der Parle-Erweiterung und implementiert einen LALR(1)-Parser, dessen Grammatikregeln dynamisch zur Laufzeit definiert werden können. Im Unterschied zu Parle\Parser arbeitet er mit dem reflektierbaren Lexer Parle\RLexer, der erweiterte Introspektionsmöglichkeiten bietet.
Der typische Arbeitsablauf besteht darin, zunächst Token (Terminale) über token() zu registrieren, dann Produktionsregeln (Nicht-Terminale) mit push() hinzuzufügen, die Grammatik mittels build() zu kompilieren und anschließend den zu parsenden String zu analysieren. Die Parser-Instanz steuert dabei den RLexer, der die lexikalische Analyse übernimmt.
Typische Anwendungsfelder sind mathematische Ausdrucks-Parser, DSL-Interpreter, Konfigurationsdateien oder jede andere Situation, in der eine formale Grammatik zur Laufzeit — ohne Code-Generierung — definiert und ausgewertet werden soll.
Hinweis: Die Parle-Erweiterung muss als PECL-Paket installiert sein (pecl install parle). Sie ist standardmäßig nicht in PHP enthalten.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $flags | int | 0 | Optionale Flags zur Konfiguration des Parsers. Aktuell ist kein spezifischer Flag-Wert dokumentiert; üblicherweise wird 0 übergeben. |
Beispiele
Einfacher Ausdrucks-Parser für Addition ganzer Zahlen
<?php
// Parle-Erweiterung muss installiert sein
$lexer = new Parle\RLexer();
$parser = new Parle\RParser();
// Token registrieren
$tokenInteger = $parser->token('INTEGER');
$tokenPlus = $parser->token('\'+'\''');
// Startregel und Produktionen definieren
$parser->push('start', 'expr');
$exprPlusRule = $parser->push('expr', 'expr \'+\' expr');
$exprIntRule = $parser->push('expr', 'INTEGER');
// Grammatik kompilieren
$parser->build();
// Lexer-Regeln definieren (nach build() des Parsers)
$lexer->push('[0-9]+', $tokenInteger);
$lexer->push('\'+\'', $tokenPlus);
$lexer->build();
// Zu parsenden String einlesen
$input = '3 + 5';
$lexer->consume($input);
$parser->consume($input, $lexer);
$result = 0;
for ($parser->begin(); Parle\Parser::ACTION_ACCEPT != $parser->action; $parser->advance()) {
if (Parle\Parser::ACTION_ERROR === $parser->action) {
throw new RuntimeException('Parse-Fehler bei Position ' . $lexer->marker);
}
if (Parle\Parser::ACTION_REDUCE === $parser->action) {
$rule = $parser->reduceId;
if ($rule === $exprIntRule) {
// Ganzzahl-Produktion
$parser->sigil = (int) $parser->sigil(0);
} elseif ($rule === $exprPlusRule) {
// Additions-Produktion
$parser->sigil = (int) $parser->sigil(0) + (int) $parser->sigil(2);
}
}
}
echo $result;
Grammatik aufbauen und Validität prüfen
<?php
$lexer = new Parle\RLexer();
$parser = new Parle\RParser();
$tokWord = $parser->token('WORD');
$parser->push('start', 'sentence');
$parser->push('sentence', 'WORD');
$parser->build();
$lexer->push('[a-zA-Z]+', $tokWord);
$lexer->build();
$input = 'hello';
$lexer->consume($input);
$parser->consume($input, $lexer);
$parser->begin();
while (Parle\Parser::ACTION_ACCEPT !== $parser->action
&& Parle\Parser::ACTION_ERROR !== $parser->action) {
$parser->advance();
}
if (Parle\Parser::ACTION_ACCEPT === $parser->action) {
echo 'Eingabe ist gültig.';
} else {
echo 'Ungültige Eingabe!';
}
// Wichtig · Fallstricke
Abhängigkeit: Parle\RParser muss zwingend mit einer Parle\RLexer-Instanz verwendet werden; eine Mischung mit dem nicht-reflektierbaren Parle\Lexer ist nicht möglich.
Reihenfolge beachten: Token müssen vor Produktionen registriert und build() muss aufgerufen werden, bevor der Lexer Eingaben verarbeitet. Eine falsche Reihenfolge führt zu undefiniertem Verhalten oder Laufzeitfehlern.
Konflikte: LALR(1)-Parser können bei mehrdeutigen Grammatiken Shift/Reduce- oder Reduce/Reduce-Konflikte erzeugen. Diese sollten durch eindeutige Vorrang-Regeln (left(), right(), nonassoc()) aufgelöst werden.
Stabilität: Die Parle-API befindet sich noch in Entwicklung; Methoden-Signaturen und Verhalten können sich zwischen Minor-Versionen ändern. Immer die aktuelle PECL-Dokumentation konsultieren.