我正在尝试用Irony编写一个小解析器。不幸的是,我得到了“轮班减少冲突”。语法不是我的强项,我只需要完成这一小事。这是产生错误的简化语法:
ExpressionTerm := "asd"
LogicalExpression :=
ExpressionTerm |
LogicalExpression "AND" LogicalExpression |
LogicalExpression "OR" LogicalExpression
“转移 - 减少冲突”是什么意思,我该如何解决?我认为这意味着我的语法含糊不清,但我不能充分扭曲我的逻辑,看看如何。
已添加:要澄清 - “asd”只是一个文字字符串“asd”。所以我希望这个语法解析下面的表达式:
asd
asd AND asd
asd AND asd OR asd
asd OR asd AND asd OR asd
已添加2:忘了说,语法的根目录为LogicalExpression
。
已添加3:啊,我明白了!歧义是因为像
这样的表达asd AND asd OR asd
可以用两种不同的方式解释:
(asd AND asd) OR asd
asd AND (asd OR asd)
但我怎么能解决这个问题?好吧,我可以把AND或OR中的一个强于另一个(我原本打算)。但是现在我看到即使只有一个操作员也会出现错误。换句话说,这也会产生相同的错误:
LogicalExpression := "asd" | LogicalExpression "OR" LogicalExpression
在这种情况下我想要这个:
asd OR asd OR asd
要解析为:
(asd OR asd) OR asd
这样做的非模糊方式是什么?
已添加4:知道了!
LogicalExpression1 := LogicalExpression1 "OR" LogicalExpression2 | LogicalExpression2
LogicalExpression2 := LogicalExpression2 "AND" LogicalExpression3 | LogicalExpression3
LogicalExpression3 := "NOT" LogicalExpression4 | LogicalExpression4
LogicalExpression4 := "asd" | "(" LogicalExpression1 ")"
这解析所有布尔表达式,运算符优先级为NOT-> AND-> OR。 “asd”可以替换为您的术语表达。
答案 0 :(得分:3)
如果你只使用一个前瞻,你的语法就会模糊不清。为了说明什么是“asd”?它是ExpressionTerm还是更长期的。这是转移减少冲突。我怀疑这里也有减少冲突的冲突。
大多数LL(1)/ LALR(1)生成器将通过优先级运算符提供一些处理shift-reduce冲突的方法。大多数人也会在出现换班减少冲突时默认为最长的序列,因此通常可以忽略这些序列(经过一些审查)。 (在这种情况下,您可能需要将单个术语移到底部才能使其正常运行)。
答案 1 :(得分:1)
Shift-Reduce冲突意味着你的语法含糊不清。使用递归规则,令牌“asd”可以解释为ExpressionTerm
或LogicalExpression
的一部分,并且解析器无法确定哪一个。需要一个额外的规则来打破平局。
答案 2 :(得分:0)
在解析器方面,转换减少冲突是让你的大脑更难的事情之一。说明冲突的最简单方法是使用伪代码:
if (a) then
if (b) then
printf('a + b');
else
print('this could be a + !b or !a');
else语句可以绑定到第一个或第二个if。在模糊语法的情况下,您通常会定义一个值来表示语法中预期的减少转移警告的数量。
或者,您可以使用LL(k)或LL(*)解析器。这些类型的解析器没有移位/减少歧义。根据您的应用程序,它们可能比LALR(1)解析器更容易或更难。
答案 3 :(得分:0)
语法在LL(1)
或LALR(1)
中不明确,因为asd令牌可以在ExpressionTerm
中替换,而LogicalExpression
也可以压缩语法规则来解决转移/减少冲突