Jison规则优先
Jison rule precedence
我正尝试在 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 { $$ = ; }
| binaryExpr { $$ = ; }
| callExpr { $$ = ; }
| tupleExpr { $$ = ; }
| parenExpr { $$ = ; }
| identExpr { $$ = ; }
| blockExpr { $$ = ; }
;
callArgs:
| callArgs expr { $$ = .concat(); }
| expr { $$ = []; }
;
callExpr:
| path callArgs { $$ = ast.Expr.Call(, ); }
;
identExpr:
| path { $$ = ast.Expr.Ident(); }
;
如何让 Jison 更喜欢 callArgs
而不是 expr
?
复习语法的其他部分以给出准确答案很重要。我不知道我的想法是否正确,但根据我在您的代码中看到的情况,您可以按照您想要的顺序为参数显式创建规则,而无需将一个嵌套在另一个中:
args:
| "(" simple_expression ")" args { /*Do something with */ }
| "\n"
;
希望对您有所帮助。你好。
你可能可以通过玩具有优先关系的游戏来做到这一点,但我认为最直接的解决方案是明确。
你想说的是callArgs
不能直接包含一个callExpr
。在您的示例中,如果您想将 callExpr
作为参数传递,则需要将其括在括号中,在这种情况下它将匹配其他一些产品(大概是 parenExpr
)。
所以你可以直接这样写:
callArgExpr
: constantExpr
| binaryExpr
| tupleExpr
| parenExpr
| identExpr
| blockExpr
;
expr
: callArgExpr
| callExpr
;
callArgs
: callArgs callArgExpr { $$ = .concat(); }
| callArgExpr { $$ = []; }
;
callExpr
: path callArgs { $$ = ast.Expr.Call(, ); }
;
事实上,您可能想进一步限制 callArgs
,因为(如果我理解正确的话)func a + b
并不意味着 "apply a+b
to func
",它应该写成 func (a + b)
。因此,您可能还想从 callArgExpr
中删除 binaryExpr
,可能还有其他一些。我希望上面的模型展示了如何做到这一点。
顺便说一句,我删除了所有空的产生式,假设它们是无意的(除非 jison
对该语法有一些例外;我不是真正的 jison
专家)。我删除了 { $$ = ; }
,我认为它在 jison
中和在经典 yacc/bison/etc 中一样不必要,因为它是默认操作。
我正尝试在 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 { $$ = ; }
| binaryExpr { $$ = ; }
| callExpr { $$ = ; }
| tupleExpr { $$ = ; }
| parenExpr { $$ = ; }
| identExpr { $$ = ; }
| blockExpr { $$ = ; }
;
callArgs:
| callArgs expr { $$ = .concat(); }
| expr { $$ = []; }
;
callExpr:
| path callArgs { $$ = ast.Expr.Call(, ); }
;
identExpr:
| path { $$ = ast.Expr.Ident(); }
;
如何让 Jison 更喜欢 callArgs
而不是 expr
?
复习语法的其他部分以给出准确答案很重要。我不知道我的想法是否正确,但根据我在您的代码中看到的情况,您可以按照您想要的顺序为参数显式创建规则,而无需将一个嵌套在另一个中:
args:
| "(" simple_expression ")" args { /*Do something with */ }
| "\n"
;
希望对您有所帮助。你好。
你可能可以通过玩具有优先关系的游戏来做到这一点,但我认为最直接的解决方案是明确。
你想说的是callArgs
不能直接包含一个callExpr
。在您的示例中,如果您想将 callExpr
作为参数传递,则需要将其括在括号中,在这种情况下它将匹配其他一些产品(大概是 parenExpr
)。
所以你可以直接这样写:
callArgExpr
: constantExpr
| binaryExpr
| tupleExpr
| parenExpr
| identExpr
| blockExpr
;
expr
: callArgExpr
| callExpr
;
callArgs
: callArgs callArgExpr { $$ = .concat(); }
| callArgExpr { $$ = []; }
;
callExpr
: path callArgs { $$ = ast.Expr.Call(, ); }
;
事实上,您可能想进一步限制 callArgs
,因为(如果我理解正确的话)func a + b
并不意味着 "apply a+b
to func
",它应该写成 func (a + b)
。因此,您可能还想从 callArgExpr
中删除 binaryExpr
,可能还有其他一些。我希望上面的模型展示了如何做到这一点。
顺便说一句,我删除了所有空的产生式,假设它们是无意的(除非 jison
对该语法有一些例外;我不是真正的 jison
专家)。我删除了 { $$ = ; }
,我认为它在 jison
中和在经典 yacc/bison/etc 中一样不必要,因为它是默认操作。