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 typu IDENTIFIER

    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 typu BAR

    Ten tekst jest zgodny z regułą BAR zdefiniowaną przed regułą IDENTIFIER , a zatem ma pierwszeństwo.

  • baz jest typu IDENTIFIER

    Ten tekst jest zgodny z regułą BAZ , ale pasuje również do reguły IDENTIFIER . Ten ostatni jest wybierany zgodnie z definicją przed BAR .

    Biorąc pod uwagę gramatykę, BAZ nigdy nie będzie w stanie dopasować, ponieważ reguła IDENTIFIER obejmuje już wszystko, co BAZ może dopasować.

  • barz jest typu IDENTIFIER

    Reguła BAR może pasować do pierwszych 3 znaków tego ciągu ( bar ), ale reguła IDENTIFIER będzie pasować do 4 znaków. Ponieważ IDENTIFIER pasuje do dłuższego podłańcucha, jest wybierany BAR .

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 tryby popMode

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.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow