ANTLR
Règles Lexer en v4
Recherche…
Règles simples
Les règles Lexer définissent les types de jeton. Leur nom doit commencer par une lettre majuscule pour les distinguer des règles d’analyseur.
INTEGER: [0-9]+;
IDENTIFIER: [a-zA-Z_] [a-zA-Z_0-9]*;
OPEN_PAREN: '(';
CLOSE_PAREN: ')';
Syntaxe de base:
Syntaxe | Sens |
---|---|
A | Faire correspondre la règle ou le fragment lexer nommé A |
AB | Match A suivi de B |
(A|B) | Match soit A ou B |
'text' | Match littéral "texte" |
A? | Match A zéro ou une fois |
A* | Match A zéro ou plusieurs fois |
A+ | Match A une ou plusieurs fois |
[A-Z0-9] | Faire correspondre un caractère dans les plages définies (dans cet exemple, entre AZ et 0-9) |
'a'..'z' | Syntaxe alternative pour une plage de caractères |
~[AZ] | Négation d'une plage - correspond à n'importe quel caractère unique qui n'est pas dans la plage |
. | Correspond à n'importe quel caractère |
Fragments
Les fragments sont des parties réutilisables des règles de lexer qui ne peuvent pas correspondre seules. Elles doivent être référencées à partir d'une règle de lexer.
INTEGER: DIGIT+
| '0' [Xx] HEX_DIGIT+
;
fragment DIGIT: [0-9];
fragment HEX_DIGIT: [0-9A-Fa-f];
Règles implicites de lexer
Lorsque des jetons comme '{'
sont utilisés dans une règle d' analyse , une règle lexer implicite sera créée à moins qu'une règle explicite n'existe.
En d'autres termes, si vous avez une règle de lexer:
OPEN_BRACE: '{';
Ensuite, ces deux règles d'analyse sont équivalentes:
parserRule: '{';
parserRule: OPEN_BRACE;
Mais si la règle OPEN_BRACE
OPEN_BRACE n'est pas définie, une règle anonyme implicite sera créée. Dans ce cas, la règle implicite sera définie comme si elle était définie avant les autres règles: elle aura une priorité plus élevée que les autres règles.
Règles de priorité
Plusieurs règles de lexer peuvent correspondre au même texte d'entrée. Dans ce cas, le type de jeton sera choisi comme suit:
- Tout d'abord, sélectionnez la règle lexer qui correspond à l'entrée la plus longue
- Si le texte correspond à un jeton défini implicitement (comme
'{'
), utilisez la règle implicite - Si plusieurs règles de lexer correspondent à la même longueur d'entrée, choisissez la première en fonction de l'ordre de définition.
La grammaire combinée suivante:
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;
Compte tenu de l'entrée suivante:
aaa foo bar baz barz
Produira la séquence de jetons suivante à partir du lexer:
IDENTIFIER 'foo' BAR IDENTIFIER IDENTIFIER
aaa
est de typeIDENTIFIER
Seule la règle
IDENTIFIER
peut correspondre à ce jeton, il n'y a pas d'ambiguïté.
foo
est de type'foo'
La règle d'analyse syntaxique
randomParserRule
introduit le type de jeton implicite'foo'
, qui est prioritaire sur la règleIDENTIFIER
.
bar
est du typeBAR
Ce texte correspond à la règle
BAR
définie avant la règleIDENTIFIER
et a donc la priorité.
baz
est de typeIDENTIFIER
Ce texte correspond à la règle
BAZ
, mais il correspond également à la règleIDENTIFIER
. Ce dernier est choisi tel qu'il est défini avantBAR
.Compte tenu de la grammaire,
BAZ
ne sera jamais en mesure de correspondre, car la règleIDENTIFIER
couvre déjà tout ce queBAZ
peut égaler.
barz
est du typeIDENTIFIER
La règle
BAR
peut correspondre aux 3 premiers caractères de cette chaîne (bar
), mais la règleIDENTIFIER
correspond à 4 caractères. CommeIDENTIFIER
correspond à une sous-chaîne plus longue, il est choisi surBAR
.
En règle générale, les règles spécifiques doivent être définies avant des règles plus génériques. Si une règle ne peut correspondre qu'à une entrée déjà couverte par une règle précédemment définie, elle ne sera jamais utilisée.
Les règles implicitement définies telles que 'foo'
agissent comme si elles étaient définies avant toutes les autres règles lexer.
Commandes Lexer
Une règle lexer peut avoir des commandes associées:
WHITESPACE: [ \r\n] -> skip;
Les commandes sont définies après un ->
à la fin de la règle.
-
skip
: ignore le texte correspondant, aucun jeton ne sera émis -
channel(n)
: émet le jeton sur un canal différent -
type(n)
: change le type de jeton émis -
mode(n)
,pushMode(n)
,popMode
,more
: contrôle les modes lexer
Actions et prédicats sémantiques
Une action lexer est un bloc de code arbitraire dans le langage cible entouré de {
... }
, qui est exécuté lors de la correspondance:
IDENTIFIER: [A-Z]+ { log("matched rule"); };
Un prédicat sémantique est un bloc de code arbitraire dans le langage cible entouré de {
... }?
, qui évalue une valeur booléenne. Si la valeur renvoyée est false, la règle lexer est ignorée.
IDENTIFIER: [A-Z]+ { identifierIsValid() }?;
Les prédicats sémantiques doivent être définis à la fin de la règle chaque fois que cela est possible pour des raisons de performances.