为什么 Bison 中的每个操作都有一个规则

Why a rule for each operation in Bison

在搜索 Bison 语法时,我找到了这个 C 语法示例:

https://www.lysator.liu.se/c/ANSI-C-grammar-y.html

logical_and_expression
    : inclusive_or_expression
    | logical_and_expression AND_OP inclusive_or_expression
    ;
logical_or_expression
    : logical_and_expression
    | logical_or_expression OR_OP logical_and_expression
    ;

我不明白每个逻辑操作的规则的原因。比下面这个结构有优势吗?

binary_expression:
    : object // imagine it can be bool, int, real ...
    | binary_expression AND_OP binary_expression
    | binary_expression OR_OP binary_expression
    ;

你引用的语法没有歧义。

尽管 yacc/bison 允许您使用优先规则来解决歧义,但您建议的那个是模棱两可的。

使用使运算符优先级明确的语法有一些优点:

  • 是对语言的精确描述。优先规则不是语法形式主义的一部分,可能很难推理。特别是,没有通用的方法来证明他们做的是期望的事情。

  • 语法自成一体。有歧义的语法只能通过添加优先规则来理解。这对于语言标准中使用的语法尤为重要,但它通常会影响自动构建其他基于语法的工具的尝试。

  • 显式语法更通用。并非所有运算符限制都可以通过数字优先级比较轻松描述。

  • 优先规则可以隐藏语法中的错误,方法是不正确地解决语法中其他地方恰好使用某些相同标记的 shift-reduce 冲突。由于未报告已解决的冲突,因此不会向语法作者发出问题警告。

另一方面,优先规则确实有一些优势:

  • 优先级table简洁地描述了运算符的优先级,便于快速参考。

  • 生成的语法需要更少的单元产生式,略微提高了解析速度。 (通常不明显,但仍然...)

  • 有些冲突使用优先级声明更容易解决,尽管了解冲突的解决方式可能并不明显。 (典型的例子就是dangling-else歧义。)这种情况与对运算符优先级的直观理解几乎没有关系,所以使用优先级规则有点hack。

语法的总大小并没有真正受到使用优先规则的影响。如前所述,优先规则避免了单元制作的需要,但每个单元制作对应一个优先声明,所以总行数是相同的。非终端较少,但非终端成本低; yacc/bison 中的主要烦恼是声明所有语义类型,但这很容易自动化。