Ricerca…


Regole semplici

Le regole di Lexer definiscono i tipi di token. Il loro nome deve iniziare con una lettera maiuscola per distinguerli dalle regole del parser.

INTEGER: [0-9]+;
IDENTIFIER: [a-zA-Z_] [a-zA-Z_0-9]*;

OPEN_PAREN: '(';
CLOSE_PAREN: ')';

Sintassi di base:

Sintassi Senso
A Abbina la regola del lexer o il frammento denominato A
AB Abbina A seguito da B
(A|B) Abbina A o B
'text' Abbina letteralmente "testo"
A? Corrisponde A zero o una volta
A* Abbina A zero o più volte
A+ Partita A una o più volte
[A-Z0-9] Abbina un carattere negli intervalli definiti (in questo esempio tra AZ o 0-9)
'a'..'z' Sintassi alternativa per un intervallo di caratteri
~[AZ] Negazione di un intervallo: corrisponde a qualsiasi singolo carattere non compreso nell'intervallo
. Abbina qualsiasi singolo personaggio

frammenti

I frammenti sono parti riutilizzabili delle regole del lexer che non possono corrispondere da sole: devono essere referenziate da una regola del lexer.

INTEGER: DIGIT+
       | '0' [Xx] HEX_DIGIT+
       ;

fragment DIGIT: [0-9];
fragment HEX_DIGIT: [0-9A-Fa-f];

Regole implicite del lexer

Quando i token come '{' sono usati in una regola parser , per essi verrà creata una regola implicita per il lexer a meno che non esista una regola esplicita.

In altre parole, se hai una regola lexer:

OPEN_BRACE: '{';

Quindi entrambe le regole del parser sono equivalenti:

parserRule: '{';
parserRule: OPEN_BRACE;

Ma se la regola del lexer OPEN_BRACE non è definita, verrà creata una regola anonima implicita. In tal caso, la regola implicita verrà definita come se fosse definita prima delle altre regole: avrà una priorità più alta rispetto ad altre regole.

Regole di priorità

Diverse regole di lexer possono corrispondere allo stesso testo di input. In tal caso, il tipo di token sarà scelto come segue:

  • Innanzitutto, seleziona la regola lexer che corrisponde all'ingresso più lungo
  • Se il testo corrisponde a un token implicitamente definito (come '{' ), usa la regola implicita
  • Se diverse regole di lexer corrispondono alla stessa lunghezza di input, scegliere la prima , in base all'ordine di definizione

La seguente grammatica combinata:

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;

Dato il seguente input:

aaa foo bar baz barz

Produrrà la seguente sequenza di token dal lexer:

IDENTIFIER 'foo' BAR IDENTIFIER IDENTIFIER
  • aaa è di tipo IDENTIFIER

    Solo la regola IDENTIFIER può corrispondere a questo token, non vi è alcuna ambiguità.

  • foo è di tipo 'foo'

    La regola parser randomParserRule introduce il tipo di token 'foo' implicito, che è prioritario rispetto alla regola IDENTIFIER .

  • bar è di tipo BAR

    Questo testo corrisponde alla regola BAR , che è definita prima della regola IDENTIFIER e quindi ha la precedenza.

  • baz è di tipo IDENTIFIER

    Questo testo corrisponde alla regola BAZ , ma corrisponde anche alla regola IDENTIFIER . Quest'ultimo viene scelto come definito prima della BAR .

    Data la grammatica, BAZ non sarà mai in grado di eguagliare, poiché la regola IDENTIFIER copre già tutto ciò che BAZ può eguagliare.

  • barz è di tipo IDENTIFIER

    La regola BAR può corrispondere ai primi 3 caratteri di questa stringa ( bar ), ma la regola IDENTIFIER corrisponderà a 4 caratteri. Poiché IDENTIFIER corrisponde a una sottostringa più lunga, viene scelto su BAR .

Come regola generale, le regole specifiche dovrebbero essere definite prima di più regole generiche. Se una regola può solo abbinare un input che è già coperto da una regola precedentemente definita, non verrà mai utilizzato.

Le regole definite in modo implicito come 'foo' comportano come se fossero state definite prima di tutte le altre regole di lexer.

Comandi Lexer

Una regola lexer può avere comandi associati:

WHITESPACE: [ \r\n] -> skip;

I comandi sono definiti dopo un -> alla fine della regola.

  • skip : salta il testo corrispondente, non verrà emesso alcun token
  • channel(n) : emette il token su un altro canale
  • type(n) : cambia il tipo di token emesso
  • mode(n) , pushMode(n) , popMode , more : controlla le modalità lexer

Azioni e predicati semantici

Un'azione lexer è un blocco di codice arbitrario nella lingua di destinazione circondata da { ... } , che viene eseguita durante la corrispondenza:

IDENTIFIER: [A-Z]+ { log("matched rule"); };

Un predicato semantico è un blocco di codice arbitrario nella lingua di destinazione circondato da { ... }? , che valuta un valore booleano. Se il valore restituito è falso, la regola del lexer viene saltata.

IDENTIFIER: [A-Z]+ { identifierIsValid() }?;

I predicati semantici dovrebbero essere definiti alla fine della regola quando possibile per motivi di prestazioni.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow