Jison parser generator shift reduce 与括号冲突,如何解决?

Jison parser generator shift reduce conflict with parenthesis, how to solve?

我试图在我的解析器中实现括号,但我的语法出现冲突。 "Conflict in grammar: multiple actions possible when lookahead token is )" 这是它的简化版本:

// grammar
{
    "Root": ["", "Body"],
    "Body": ["Line", "Body TERMINATOR Line"],
    "Line": ["Expression", "Statement"],
    "Statement": ["VariableDeclaration", "Call", "With", "Invocation"],
    "Expression": ["Value", "Parenthetical", "Operation", "Assign"],
    "Identifier": ["IDENTIFIER"],
    "Literal": ["String", "Number"],
    "Value": ["Literal", "ParenthesizedInvocation"],
    "Accessor": [". Property"],
    "ParenthesizedInvocation": ["Value ParenthesizedArgs"],
    "Invocation": ["Value ArgList"],
    "Call": ["CALL ParenthesizedInvocation"],
    "ParenthesizedArgs": ["( )", "( ArgList )"],
    "ArgList": ["Arg", "ArgList , Arg"],
    "Arg": ["Expression", "NamedArg"],
    "NamedArg": ["Identifier := Value"],
    "Parenthetical": ["( Expression )"],
    "Operation": ["Expression + Expression", "Expression - Expression"]
}

//precedence
[
  ['right', 'RETURN'],
  ['left', ':='],
  ['left', '='],
  ['left', 'IF'],
  ['left', 'ELSE', 'ELSE_IF'],
  ['left', 'LOGICAL'],
  ['left', 'COMPARE'],
  ['left', '&'],
  ['left', '-', '+'],
  ['left', 'MOD'],
  ['left', '\'],
  ['left', '*', '/'],
  ['left', '^'],
  ['left', 'CALL'],
  ['left', '(', ')'],
  ['left', '.'],
]

在我的实现中,我需要这样的函数调用(括号和逗号分隔):

Foo(1, 2)
Foo 1, 2

并且能够使用正则括号来表示操作的优先级。即使在函数调用中(但仅在带括号的函数调用中):

Foo(1, (2 + 4) / 2)
Foo 1, 2

不带括号的函数调用被视为语句,带括号的函数调用被视为表达式。

我该如何解决这个冲突?

在VBA中,函数调用语句(相对于表达式)有两种形式(简化):

 CALL name '(' arglist ')'
 name arglist

请注意,第二个参数列表没有括号。这正是为了避免歧义:

Func (3) 

这就是您 运行 的歧义。

歧义在于不清楚括号是围绕参数列表的括号,还是围绕括号表达式的括号。这不是本质上的歧义,因为结果实际上是相同的。但它仍然很重要,因为程序可能会这样继续:

Foo (3), (4)

在这种情况下,必须将括号解析为括号表达式周围的括号。

因此,一种可能是将您的语法修改为类似于 VBA reference:

中的语法
call-statement = "Call" (simple-name-expression / member-access-expression / index-expression / with-expression)
call-statement =/ (simple-name-expression / member-access-expression / with-expression) argument-list

但我想您确实想实现一种类似于 VBA 的语言,但又不想严格遵守。这让事情稍微复杂一些。

作为第一个近似值,您可以要求表单 name '(' [arglist] ')' 至少有两个参数(除非它为空):

# Not tested
"Invocation": ["Literal '(' ArgList2 ')' ", "Literal '(' ')' ", "Literal ArgList"],
"ArgList": ["Arg", "ArgList2"],
"ArgList2": ["Arg ',' Arg", "ArgList2 ',' Arg"],