我试图在解析器中实现圆括号,但语法有冲突。"语法冲突:前瞻性标记为时可能有多个操作("这是它的简化版本:
// 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引用中的语法相似:
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"],