ANTLR
Zasady Lexera w wersji 4
Szukaj…
Proste zasady
Reguły Lexera definiują typy tokenów. Ich nazwa musi zaczynać się wielką literą, aby odróżnić je od reguł parsera.
INTEGER: [0-9]+;
IDENTIFIER: [a-zA-Z_] [a-zA-Z_0-9]*;
OPEN_PAREN: '(';
CLOSE_PAREN: ')';
Podstawowa składnia:
Składnia | Znaczenie |
---|---|
A | Dopasuj regułę leksykalną lub fragment o nazwie A |
AB | Dopasuj A a następnie B |
(A|B) | Dopasuj A lub B |
'text' | Dopasuj dosłowny „tekst” |
A? | Mecz zero lub jeden raz A |
A* | Mecz zero lub więcej razy A |
A+ | Mecz jeden lub więcej razy A |
[A-Z0-9] | Dopasuj jeden znak w zdefiniowanych zakresach (w tym przykładzie między AZ lub 0-9) |
'a'..'z' | Alternatywna składnia dla zakresu znaków |
~[AZ] | Negacja zakresu - dopasuj dowolny pojedynczy znak spoza zakresu |
. | Dopasuj dowolny pojedynczy znak |
Paprochy
Fragmenty są częściami wielokrotnego użytku reguł leksykalnych, które same nie mogą się dopasować - należy się do nich odwoływać z reguły leksykalnej.
INTEGER: DIGIT+
| '0' [Xx] HEX_DIGIT+
;
fragment DIGIT: [0-9];
fragment HEX_DIGIT: [0-9A-Fa-f];
Niejawne reguły leksykalne
Gdy tokeny takie jak '{'
są używane w regule parsera , zostanie utworzona dla nich niejawna reguła leksykalna, chyba że istnieje reguła jawna.
Innymi słowy, jeśli masz regułę leksykalną:
OPEN_BRACE: '{';
Zatem obie reguły parsera są równoważne:
parserRule: '{';
parserRule: OPEN_BRACE;
Ale jeśli nie zdefiniowano reguły OPEN_BRACE
, zostanie utworzona domniemana anonimowa reguła. W takim przypadku reguła niejawna zostanie zdefiniowana tak, jakby była zdefiniowana przed innymi regułami: będzie miała wyższy priorytet niż inne reguły.
Zasady pierwszeństwa
Kilka reguł leksykalnych może pasować do tego samego tekstu wejściowego. W takim przypadku typ tokena zostanie wybrany w następujący sposób:
- Najpierw wybierz regułę leksykalną, która pasuje do najdłuższego wejścia
- Jeśli tekst pasuje do domyślnie zdefiniowanego tokena (np.
'{'
), Użyj reguły niejawnej - Jeśli kilka reguł leksykalnych odpowiada tej samej długości wejściowej, wybierz pierwszą , na podstawie kolejności definicji
Następująca połączona gramatyka:
grammar LexerPriorityRulesExample;
// Parser rules
randomParserRule: 'foo'; // Implicitly declared token type
// Lexer rules
BAR: 'bar';
IDENTIFIER: [A-Za-z]+;
BAZ: 'baz';
WS: [ \t\r\n]+ -> skip;
Biorąc pod uwagę następujące dane wejściowe:
aaa foo bar baz barz
Wyodrębni następującą sekwencję żetonów z leksera:
IDENTIFIER 'foo' BAR IDENTIFIER IDENTIFIER
aaa
jest typuIDENTIFIER
Tylko reguła
IDENTIFIER
może dopasować ten token, nie ma dwuznaczności.
foo
jest typu'foo'
Reguła parsera
randomParserRule
wprowadza domyślny typ tokena'foo'
, który ma pierwszeństwo przed regułąIDENTIFIER
.
bar
jest typuBAR
Ten tekst jest zgodny z regułą
BAR
zdefiniowaną przed regułąIDENTIFIER
, a zatem ma pierwszeństwo.
baz
jest typuIDENTIFIER
Ten tekst jest zgodny z regułą
BAZ
, ale pasuje również do regułyIDENTIFIER
. Ten ostatni jest wybierany zgodnie z definicją przedBAR
.Biorąc pod uwagę gramatykę,
BAZ
nigdy nie będzie w stanie dopasować, ponieważ regułaIDENTIFIER
obejmuje już wszystko, coBAZ
może dopasować.
barz
jest typuIDENTIFIER
Reguła
BAR
może pasować do pierwszych 3 znaków tego ciągu (bar
), ale regułaIDENTIFIER
będzie pasować do 4 znaków. PonieważIDENTIFIER
pasuje do dłuższego podłańcucha, jest wybieranyBAR
.
Zasadniczo szczegółowe reguły powinny zostać zdefiniowane przed bardziej ogólnymi regułami. Jeśli reguła może pasować tylko do danych wejściowych, które są już objęte wcześniej zdefiniowaną regułą, nigdy nie zostanie użyta.
Niejawnie zdefiniowane reguły, takie jak 'foo'
działają tak, jakby były zdefiniowane przed wszystkimi innymi regułami leksykalnymi.
Polecenia Lexera
Reguła leksykalna może mieć powiązane polecenia :
WHITESPACE: [ \r\n] -> skip;
Polecenia są definiowane po ->
na końcu reguły.
-
skip
:skip
dopasowany tekst, żaden token nie będzie emitowany -
channel(n)
: Emituje token na innym kanale -
type(n)
: Zmienia typ emitowanego tokena -
mode(n)
,pushMode(n)
,popMode
,more
: Kontroluje trybypopMode
Działania i predykaty semantyczne
Lexer to blok dowolnego kodu w języku docelowym otoczony {
... }
, który jest wykonywany podczas dopasowywania:
IDENTIFIER: [A-Z]+ { log("matched rule"); };
Predykat semantyczny to blok arbitralnego kodu w języku docelowym otoczony {
... }?
, który daje wartość logiczną. Jeśli zwrócona wartość to false, reguła leksykalna jest pomijana.
IDENTIFIER: [A-Z]+ { identifierIsValid() }?;
O ile to możliwe, ze względów wydajnościowych predykaty semantyczne należy określać na końcu reguły.