我试图在Jison中为编程语言创建一个语法,并且遇到了调用问题。使用以下语法调用我的语言中的函数:
functionName arg1 arg2 arg3
为了做一些不仅仅是简单表达式的参数,它们需要包含在这样的括号中:
functionName (1 + 2) (3 + 3) (otherFunction 5)
但是,我的语法中存在一个错误,导致我的解析器将functionName arg1 arg2 arg3
解释为functionName(arg1(arg2(arg3)))
而不是functionName(arg1, arg2, arg3)
。
我的jison语法文件的相关部分如下所示:
expr:
| constantExpr { $$ = $1; }
| binaryExpr { $$ = $1; }
| callExpr { $$ = $1; }
| tupleExpr { $$ = $1; }
| parenExpr { $$ = $1; }
| identExpr { $$ = $1; }
| blockExpr { $$ = $1; }
;
callArgs:
| callArgs expr { $$ = $1.concat($2); }
| expr { $$ = [$1]; }
;
callExpr:
| path callArgs { $$ = ast.Expr.Call($1, $2); }
;
identExpr:
| path { $$ = ast.Expr.Ident($1); }
;
如何让Jison更喜欢callArgs
而不是expr
?
答案 0 :(得分:1)
你可以通过玩具有优先关系的游戏来做到这一点,但我认为最直接的解决方案是明确。
您想说的是callArgs
无法直接包含callExpr
。在您的示例中,如果您想传递callExpr
作为参数,则需要将其括在括号中,在这种情况下,它将匹配其他一些产品(可能是parenExpr
)。
所以你可以直接写下来:
callArgExpr
: constantExpr
| binaryExpr
| tupleExpr
| parenExpr
| identExpr
| blockExpr
;
expr
: callArgExpr
| callExpr
;
callArgs
: callArgs callArgExpr { $$ = $1.concat($2); }
| callArgExpr { $$ = [$1]; }
;
callExpr
: path callArgs { $$ = ast.Expr.Call($1, $2); }
;
事实上,您可能希望进一步限制callArgs
,因为(如果我理解正确的话)func a + b
并不意味着“将a+b
应用于func
” ,本来是func (a + b)
。因此,您可能还希望从binaryExpr
删除callArgExpr
,也可能删除其他一些jison
。我希望上面的模型显示如何做到这一点。
顺便说一句,我删除了所有空制作,假设它们是无意的(除非jison
有一些该语法的例外;我不是真正的{ $$ = $1; }
专家。我删除了jison
,我认为{{1}}与经典的yacc / bison / etc中一样不必要,因为它是默认操作。
答案 1 :(得分:0)
重要的是要检查语法的其他部分以给出准确的答案。我不知道我认为是对的,但是从我在你的代码中看到的,你可以按照你想要的顺序为参数显式创建一个规则,而不是将一个嵌套在另一个中:
args:
| "(" simple_expression ")" args { /*Do something with $2*/ }
| "\n"
;
我希望这对你有所帮助。问候。