Was ist ein ‚semantisches Prädikat‘ in ANTLR?
Frage
Was ist ein semantische Prädikat in ANTLR?
Lösung
ANTLR 4
Für Prädikate in ANTLR 4, Check-out diese Stapel Überlauf Q & A:
ANTLR 3
semantisches Prädikat ist ein Weg, um zusätzliche zu erzwingen (semantische) Regeln auf Grammatik mit Klar Code Aktionen.
Es gibt 3 Arten von semantischen Prädikaten:
- Validieren semantische Prädikate;
- gated semantische Prädikate;
- Entscheider semantische Prädikate.
Beispiel Grammatik
Lassen Sie uns sagen haben Sie einen Textblock, der nur aus Zahlen, getrennt durch
Komma ist, keine weißen Flecken zu ignorieren. Sie möchten uns an dieser Eingabeprozess analysieren
Sie sicher, dass die Zahlen sind höchstens 3 Ziffern „long“ (höchstens 999). Folgende
Grammatik (Numbers.g
) würde so etwas tun:
grammar Numbers;
// entry point of this parser: it parses an input string consisting of at least
// one number, optionally followed by zero or more comma's and numbers
parse
: number (',' number)* EOF
;
// matches a number that is between 1 and 3 digits long
number
: Digit Digit Digit
| Digit Digit
| Digit
;
// matches a single digit
Digit
: '0'..'9'
;
// ignore spaces
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
Testing
Die Grammatik kann mit der folgenden Klasse getestet werden:
import org.antlr.runtime.*;
public class Main {
public static void main(String[] args) throws Exception {
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
NumbersLexer lexer = new NumbersLexer(in);
CommonTokenStream tokens = new CommonTokenStream(lexer);
NumbersParser parser = new NumbersParser(tokens);
parser.parse();
}
}
Test durch den Lexer und Parser zu erzeugen, Kompilieren alle .java
Dateien und
die Main
Klasse ausgeführt wird:
java -cp antlr-3.2.jar org.antlr.Tool Numbers.g javac -cp antlr-3.2.jar *.java java -cp .:antlr-3.2.jar Main
Dabei ist nichts auf die Konsole ausgegeben, die, dass nichts anzeigt ging schief. Versuchen Sie,:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7 , 89");
in:
ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777 , 89");
und machen Sie den Test erneut. Sie werden sehen, ein Fehler auf der Konsole direkt nach der Zeichenfolge 777
erscheinen
Semantic Prädikate
Dies bringt uns zu den semantischen Prädikaten. Angenommen, Sie möchten analysieren Zahlen zwischen 1 und 10 Stellen lang. Eine Regel wie:
number
: Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
| Digit Digit Digit Digit Digit Digit Digit Digit Digit
/* ... */
| Digit Digit Digit
| Digit Digit
| Digit
;
wäre mühsam geworden. Semantic Prädikate simplify diese Art der Regel helfen kann.
1. Validieren Semantic Prädikate
A Validieren semantische Prädikat ist nichts mehr als ein Code-Block durch ein Fragezeichen:
RULE { /* a boolean expression in here */ }?
Um das Problem zu lösen, oben mit einem Validieren
semantisches Prädikat, das number
Regel in der Grammatik ändern:
number
@init { int N = 0; }
: (Digit { N++; } )+ { N <= 10 }?
;
Die Teile { int N = 0; }
und { N++; }
sind reine Java-Anweisungen, von denen
der erste initialisiert wird, wenn der Parser „tritt“ die number
Regel. die eigentliche
Prädikat: { N <= 10 }?
, die der Parser verursacht eine werfen
FailedPredicateException
immer dann, wenn eine Zahl von mehr als 10 Ziffern lang sein.
Test durch die folgende ANTLRStringStream
mit:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
, die keine Ausnahme erzeugt, während die folgenden tut thow eine Ausnahme:
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
2. Gated Semantic Prädikate
A gated semantische Prädikat ist ähnlich ein Validieren semantische Prädikat ,
nur die gated Version erzeugt einen Syntaxfehler statt eines FailedPredicateException
.
Die Syntax eines gated semantisches Prädikat ist:
{ /* a boolean expression in here */ }?=> RULE
Um stattdessen löst das oben genannte Problem mit gated Prädikaten Zahlen zu 10 Stellen zusammenpassen lange würden Sie schreiben:
number
@init { int N = 1; }
: ( { N <= 10 }?=> Digit { N++; } )+
;
Test wieder mit beiden:
// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890");
und
// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");
und Sie werden die letzte sehen werden einen Fehler aus.
3. Disambiguieren Semantic Prädikate
Die letzte Art von Prädikat ist ein Entscheider semantisches Prädikat , die ein bisschen wie ein Validieren Prädikat aussieht ({boolean-expression}?
), sondern wirken eher wie eine Gated semantisches Prädikat (keine Ausnahme ausgelöst wird, wenn dieBooleschen Ausdruck ergibt false
). Sie können es zu Beginn einer Regel verwenden, das eine Eigenschaft der Regel zu überprüfen und lassen Sie den Parser Spiel der Regel oder nicht.
Lassen Sie uns sagen, dass die Beispielgrammatik erzeugt Number
Token (eine Lexer Regel statt einer Parser-Regel), die Zahlen im Bereich von 0..999 übereinstimmen. Jetzt im Parser, Sie mögen einen Unterschied zwischen Niedrig- und Höhe Zahlen machen (low: 0..500, hoch: 501..999). Dies könnte getan werden, eine mit Entscheider semantischem Prädikat , wo Sie inspizieren das Token als nächste in dem Stream (input.LT(1)
) zu überprüfen, ob es entweder niedrig oder hoch ist.
Eine Demo:
grammar Numbers;
parse
: atom (',' atom)* EOF
;
atom
: low {System.out.println("low = " + $low.text);}
| high {System.out.println("high = " + $high.text);}
;
low
: {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
;
high
: Number
;
Number
: Digit Digit Digit
| Digit Digit
| Digit
;
fragment Digit
: '0'..'9'
;
WhiteSpace
: (' ' | '\t' | '\r' | '\n') {skip();}
;
Wenn Sie jetzt die Zeichenfolge "123, 999, 456, 700, 89, 0"
analysieren, würden Sie die folgende Ausgabe sehen:
low = 123
high = 999
low = 456
high = 700
low = 89
low = 0
Andere Tipps
Ich habe immer den lapidaren Verweis auf ANTLR Prädikate auf wincent.com als meinen Führer verwendet.