Supponendo (a)()
sarebbe anche valido, ecco un modo per risolvere questo:
grammar T;
options {
output=AST;
}
tokens {
EXPR_LIST;
CALL;
INDEX;
LOOKUP;
}
parse
: expr EOF -> expr
;
expr
: add_expr
;
add_expr
: mul_exp (('+' | '-')^ mul_exp)*
;
mul_exp
: atom (('*' | '/')^ atom)*
;
atom
: fncall
| NUM
;
fncall
: (fncall_start -> fncall_start) ('(' expr_list ')' -> ^(CALL $fncall expr_list)
| '[' expr ']' -> ^(INDEX $fncall expr)
| '.' ID -> ^(LOOKUP $fncall ID)
)*
;
fncall_start
: ID
| '(' expr ')' -> expr
;
expr_list
: (expr (',' expr)*)? -> ^(EXPR_LIST expr*)
;
NUM : '0'..'9'+;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
Il parser generato dalla grammatica sopra sarebbe analizzare l'input:
(foo.bar().array[i*2])(42)(1,2,3)
e costruire la seguente AST:
Senza le regole di riscrittura degli alberi, la grammatica sarebbe la seguente:
grammar T;
parse
: expr EOF
;
expr
: add_expr
;
add_expr
: mul_exp (('+' | '-') mul_exp)*
;
mul_exp
: atom (('*' | '/') atom)*
;
atom
: fncall
| NUM
;
fncall
: fncall_start ('(' expr_list ')' | '[' expr ']' | '.' ID)*
;
fncall_start
: ID
| '(' expr ')'
;
expr_list
: (expr (',' expr)*)?
;
NUM : '0'..'9'+;
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
fonte
2012-05-09 17:52:07
Ti spiace spiegare come funzionano le predicate in questo contesto? Ma grazie mille per il codice. –
@luxun, non ho usato alcun predicato: è solo una (semplice) grammatica che crea un AST, quindi ci sono un paio di regole di riscrittura. Ho modificato la mia risposta per includere la stessa grammatica, ma senza le regole di riscrittura (inutile dire che la grammatica non creerà un AST come nell'immagine che ho postato ...). –
Ah, capisco. Grazie mille. –