Assegnazione come espressione nella grammatica antlr
Domanda
Sto cercando di estendere La grammatica della piccola lingua trattare l'assegnazione come espressione. Quindi sarebbe valido scrivere
a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
a = 1 = 2; // invalid
L'assegnazione differisce dagli altri operatori in due aspetti. È l'associazione giusta (non un grosso problema) e il suo lato sinistro deve essere una variabile. Quindi ho cambiato la grammatica in questo modo
statement: assignmentExpr | functionCall ...;
assignmentExpr: Identifier indexes? '=' expression;
expression: assignmentExpr | condExpr;
Non funziona, perché contiene una decisione non ll (*). Ho anche provato questa variante:
assignmentExpr: Identifier indexes? '=' (expression | condExpr);
Ma ho ricevuto lo stesso errore. sono interessato a
- Questa domanda specifica
- Data una grammatica con una decisione non ll (*), come trovare i due percorsi che causano il problema
- Come sistemarlo
Soluzione
La chiave qui è che devi "assicurare" il parser che all'interno di un'espressione, c'è qualcosa che soddisfa l'espressione. Questo può essere fatto usando un predicato sintattico (il ( ... )=>
parti nel add
e mult
regole).
Una breve demo:
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();};
che analizzerà l'input:
a = b = 1; // -> a = (b = 1)
a = 2 * (b = 1); // contrived but valid
Nel seguente AST:
Altri suggerimenti
Penso che tu possa cambiare la tua grammatica in questo modo per ottenere lo stesso, senza usare predicati sintattici:
statement: Expr ';' | functionCall ';'...;
Expr: Identifier indexes? '=' Expr | condExpr ;
condExpr: .... and so on;
Ho modificato l'esempio di Bart con questa idea in mente:
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();};
E per l'input:
a=b=4;
a = 2 * (b = 1);
Ottieni seguire l'albero di analisi: