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
aaaest de typeIDENTIFIERSeule la règle
IDENTIFIERpeut correspondre à ce jeton, il n'y a pas d'ambiguïté.
fooest de type'foo'La règle d'analyse syntaxique
randomParserRuleintroduit le type de jeton implicite'foo', qui est prioritaire sur la règleIDENTIFIER.
barest du typeBARCe texte correspond à la règle
BARdéfinie avant la règleIDENTIFIERet a donc la priorité.
bazest de typeIDENTIFIERCe 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,
BAZne sera jamais en mesure de correspondre, car la règleIDENTIFIERcouvre déjà tout ce queBAZpeut égaler.
barzest du typeIDENTIFIERLa règle
BARpeut correspondre aux 3 premiers caractères de cette chaîne (bar), mais la règleIDENTIFIERcorrespond à 4 caractères. CommeIDENTIFIERcorrespond à 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.