当然有很多关于解决移位/减少错误的文档和方法。野牛文档建议正确的解决方案通常只是 %expect 他们并处理它。
当你有这样的事情:
S: S 'b' S | 't'
您可以像这样轻松解决它们:
S: S 'b' T | T
T: 't'
我的问题是:最好是让语法有点模棱两可并期望转移/减少问题,还是尝试调整语法以避免它们更好?我怀疑有一个平衡,它是基于作者的需要,但我真的不知道。
当然有很多关于解决移位/减少错误的文档和方法。野牛文档建议正确的解决方案通常只是 %expect 他们并处理它。
当你有这样的事情:
S: S 'b' S | 't'
您可以像这样轻松解决它们:
S: S 'b' T | T
T: 't'
我的问题是:最好是让语法有点模棱两可并期望转移/减少问题,还是尝试调整语法以避免它们更好?我怀疑有一个平衡,它是基于作者的需要,但我真的不知道。
您可以使用运算符优先级指导冲突解决。声明'b'
为左或右关联运算符,您至少已经涵盖了这种情况。
对于更复杂的模式,只要最终解析器在所有情况下都能产生正确的结果,警告就不用担心了。虽然如果你不能让它使用声明给出正确的结果,你将不得不重写语法。
当我读到它时,您的问题是“什么时候可以使用模棱两可的语法或生产规则?”
首先考虑您所描述的语言。允许在语言中使用模棱两可的生产规则意味着什么。
您的示例描述了一种可能包含如下表达式的语言:t b t b t b t
如您的第二个示例中那样解析的表达式将是(((( t ) b t) b t ) b t )
,但在一个模棱两可的语法中,它也可能成为( t b ( t b ( t b ( t))))
or 甚至( t b t ) b ( t b t )
。哪个可能有效可能取决于语言。如果b
算子模拟减法,确实不应该模棱两可,但如果是加法,它可能没问题。这真的取决于语言。
The second question to consider is what the resulting grammar source file ends up looking like, after the conflicts are resolved. As with other source code, a grammar is meant to be read by humans, and secondarily also by computers. Prefer a notation that gives a clearer explanation of what the parser is trying to do from the grammar. That is, if the parser is executing some possibly undefined behavior, for example, order of evaluation of a function's arguments in an eager language, make the grammar look ambiguous.
在我上学期的编译器课程中,我们使用了 bison,并为 pascal 的一个子集构建了一个编译器。
如果语言足够复杂,就会出现一些错误。只要您了解它们为何存在,以及您必须如何移除它们,我们就觉得没问题。如果有什么东西在那里,但由于行为会按照我们的意愿工作,并且需要大量的思考和工作才能让它变得有价值(并且也会使语法复杂化),我们就不理会它了。只需确保您完全理解错误,并将其记录在某个地方(甚至为您自己),以便您始终知道它发生了什么。
一旦事情真正涉及,这是一个成本/收益分析,但恕我直言,修复它应该被认为是第一个,然后实际弄清楚工作将是什么(如果这项工作破坏了其他事情,或者使其他事情变得更难),然后从那里。永远不要把它们当作家常便饭。
当我需要证明语法是明确的时,我倾向于先将其编写为Parsing Expression Grammar,然后手动将其转换为我用于项目所需的工具集的任何语法类型。以我的经验,这种级别的证明需要非常罕见,因为我遇到的大多数移位/减少冲突都是相当微不足道的,以显示(按照你的例子的顺序)的正确性。