我正在尝试为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); }
;
我怎样才能让吉森更喜欢callArgs
而不是expr
?
您可以通过玩具有优先级关系的游戏来做到这一点,但我认为最直接的解决方案是明确。
你想说的是,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)
的。因此,您可能还想从callArgExpr
中删除binaryExpr
,可能还有其他一些。我希望上面的模型显示了如何做到这一点。
顺便说一下,我删除了所有空产品,假设它们是无意的(除非jison
该语法有一些例外;我不是真正的jison
专家)。我删除了{ $$ = $1; }
,我认为这在jison
中与经典的yacc/野牛/等一样不必要,因为它是默认操作。
复习语法的其他部分以给出准确的答案非常重要。我不知道我认为是否正确,但是根据我在您的代码中看到的内容,您可以按照所需的顺序为参数显式创建规则,而无需将一个嵌套在另一个中:
args:
| "(" simple_expression ")" args { /*Do something with $2*/ }
| "n"
;
我希望这对你有所帮助。问候。