Recursion 如何删除左递归
我想做一个语法,允许curry函数调用 即:Recursion 如何删除左递归,recursion,antlr,antlr3,left-recursion,Recursion,Antlr,Antlr3,Left Recursion,我想做一个语法,允许curry函数调用 即: a() /// good a()() /// good a()()() /// good a(a) /// good a(a()()) /// good /// etc 我的第一次尝试是: ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*; fncall : expr '(' (expr (',' expr)*)? ')'; expr : ID|f
a() /// good
a()() /// good
a()()() /// good
a(a) /// good
a(a()()) /// good
/// etc
我的第一次尝试是:
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*;
fncall : expr '(' (expr (',' expr)*)? ')';
expr : ID|fncall;
但由于左递归,该方法失败。假设(a)(
也有效,下面是一种解决方法:
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'|'_')*;
根据上述语法生成的解析器将解析输入:
(foo.bar().array[i*2])(42)(1,2,3)
并构建以下AST:
如果没有树重写规则,语法将如下所示:
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'|'_')*;
你介意解释一下谓词在这个上下文中是如何工作的吗?但是非常感谢你的代码。@luxun,我没有使用任何谓词:它只是创建AST的(普通)语法,所以有几个重写规则。我编辑了我的答案以包含相同的语法,但没有重写规则(不用说,该语法不会像我发布的图像中那样创建AST…)。