【发布时间】:2017-02-23 00:01:43
【问题描述】:
我目前正在编写一个类似于 Visual Basic 的 LALR(1) 语法,并面临这个特殊的移位/减少冲突,我不知道如何正确解决它。
语法有问题的部分是(请参阅 EDIT 1 和 EDIT 2 进行澄清):
Expression
: IndexExpression
| /* other expressions */
IndexExpression
: MemberExpression
| MemberExpression '(' ArgumentList ')'
MemberExpression
: ParenthesizedExpression
| Identifier
ParenthesizedExpression
: '(' Expression ')'
ArgumentList
: Expression
| Expression ',' ArgumentList
| ',' ArgumentList
移位/减少冲突是这样的:
State 109
237 ParenthesizedExpression: '(' Expression ')' .
$default reduce using rule 237 (ParenthesizedExpression)
...
State 295
231 IndexExpression: MemberExpression '(' . ArgumentList ')'
237 ParenthesizedExpression: '(' . Expression ')'
...
Expression go to state 352
...
State 352
182 ArgumentList: Expression .
183 | Expression . ',' ArgumentList
237 ParenthesizedExpression: '(' Expression . ')'
...
')' shift, and go to state 109
')' [reduce using rule 182 (ArgumentList)]
换句话说,解析器在面对一个用括号包裹的表达式时,不确定它是带有单个表达式的 ArgumentList 还是 ParenthesizedExpression。
有没有办法解决这个冲突,同时保持语法为 LALR(1)?
谢谢。
编辑 1:
/* 其他表达式 */ in Expression 其实并不是空的表达式,我只是为了简洁而写成这样。实际上它还有其他替代表达方式:
Expression
: IndexExpression
| Expression '+' Expression
| ...
编辑 2:
以下是@rici 指出可能有问题的语法的其他部分(尤其是语句的第一右手规则):
Statement
: MemberExpression ArgumentList
| MemberExpression '=' Expression
| MemberExpression '(' ArgumentList ')' '=' Expression
| ...
【问题讨论】:
-
你需要展示更多你的语法。或者,更好的是,创建一个真正可编译的语法,具有相同的问题,但只有几个产生式。顺便说一句,
argument_list语法很奇怪。为什么您发现使用左递归编写它很有用,而在 LALR(1) 解析器中通常应该避免这种情况?多个缺失的参数是什么意思?如果所有其他参数都可以省略,为什么最后一个参数不能呢? -
您是否允许使用 VB 语法,其中可以在不带括号的情况下调用带有一个参数的函数?如果是这样,那很可能是您的问题。
-
@rici 缺少参数:在这个特殊的 VB 方言中,它允许参数列表有空参数,除了最后一个。因为我真的不希望 Expression 为空,所以我最终将第三条规则放在 ArgumentList 上。 一个不带括号的参数:是的!事实上,在昨天更深入地寻找根本原因之后,我得出一个结论,这可能是原因。您对如何包含此语法有任何建议吗?
-
当您只能看到一小部分语法时,很难对语法提出建议。这是关于帮助其他人解决问题的一般性声明;如果您只是提供少量信息,则很难为您提供帮助,因为我们必须花时间尝试推断或猜测您没有解释的问题部分。提问的最佳方式是发送minimal reproducible example,这也是开始自己解决问题的好方法,因为它关注的是真正重要的事情(而不是你认为可能有趣的事情)。
-
我没有从您提供的小摘录中看到任何明显的冲突路径,但可能是您有另一种以表达式开头的语句类型。顺便说一句,我认为用
ParenthesizedExpression: '(' Expression ')'之类的作品来夸大你的语法并不是一种好的风格。这就是冗余评论综合症的语法(++count; /* Increase the count by 1 */)