Affectation comme expression dans la grammaire antlr
Question
J'essaye d'étendre la grammaire de la petite langue pour traiter l'attribution comme une expression. Il serait donc valable d'écrire
a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
a = 1 = 2; // invalid
L'attribution diffère des autres opérateurs sous deux aspects. C'est droit associatif (pas un gros problème), et son côté gauche doit être une variable. Alors j'ai changé la grammaire comme ça
statement: assignmentExpr | functionCall ...;
assignmentExpr: Identifier indexes? '=' expression;
expression: assignmentExpr | condExpr;
Cela ne fonctionne pas, car il contient une décision non LL (*). J'ai également essayé cette variante:
assignmentExpr: Identifier indexes? '=' (expression | condExpr);
Mais j'ai eu la même erreur. Je suis intéressé par
- Cette question spécifique
- Étant donné une grammaire avec une décision non LL (*), comment trouver les deux chemins qui causent le problème
- Comment le réparer
La solution
La clé ici est que vous devez "assurer" à l'analyseur qu'à l'intérieur d'une expression, il y a quelque chose qui satisfait à l'expression. Cela peut être fait en utilisant un prédicat syntaxique (le ( ... )=>
parties dans le add
et mult
règles).
Une démo rapide:
grammar TL;
options {
output=AST;
}
tokens {
ROOT;
ASSIGN;
}
parse
: stat* EOF -> ^(ROOT stat+)
;
stat
: expr ';' -> expr
;
expr
: add
;
add
: mult ((('+' | '-') mult)=> ('+' | '-')^ mult)*
;
mult
: atom ((('*' | '/') atom)=> ('*' | '/')^ atom)*
;
atom
: (Id -> Id) ('=' expr -> ^(ASSIGN Id expr))?
| Num
| '(' expr ')' -> expr
;
Comment : '//' ~('\r' | '\n')* {skip();};
Id : 'a'..'z'+;
Num : '0'..'9'+;
Space : (' ' | '\t' | '\r' | '\n')+ {skip();};
qui analysera l'entrée:
a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
dans le AST suivant:
Autres conseils
Je pense que vous pouvez changer votre grammaire comme celle-ci pour réaliser la même chose, sans utiliser de prédicats syntaxiques:
statement: Expr ';' | functionCall ';'...;
Expr: Identifier indexes? '=' Expr | condExpr ;
condExpr: .... and so on;
J'ai modifié l'exemple de Bart avec cette idée à l'esprit:
grammar TL;
options {
output=AST;
}
tokens {
ROOT;
}
parse
: stat+ EOF -> ^(ROOT stat+)
;
stat
: expr ';'
;
expr
: Id Assign expr -> ^(Assign Id expr)
| add
;
add
: mult (('+' | '-')^ mult)*
;
mult
: atom (('*' | '/')^ atom)*
;
atom
: Id
| Num
| '('! expr ')' !
;
Assign : '=' ;
Comment : '//' ~('\r' | '\n')* {skip();};
Id : 'a'..'z'+;
Num : '0'..'9'+;
Space : (' ' | '\t' | '\r' | '\n')+ {skip();};
Et pour l'entrée:
a=b=4;
a = 2 * (b = 1);
Vous obtenez l'arbre d'analyse suivant: