一些编译器书籍/文章/论文讨论了语法的设计及其运算符关联性的关系。我是自上而下的忠实粉丝,尤其是递归下降、解析器和迄今为止我编写的大多数(如果不是全部)编译器都使用以下表达式语法:
Expr ::= Term { ( "+" | "-" ) Term }
Term ::= Factor { ( "*" | "/" ) Factor }
Factor ::= INTEGER | "(" Expr ")"
这是此 BNF 的 EBNF 表示:
Expr ::= Term Expr'
Expr' ::= ( "+" | "-" ) Term Expr' | ε
Term ::= Factor Term'
Term' ::= ( "*" | "/" ) Factor Term' | ε
Factor = INTEGER | "(" Expr ")"
根据我读到的内容,一些人认为这种语法是“错误的”,因为运算符关联性的变化(这 4 个运算符从左到右)由向右而不是向左生长的解析树证明。对于通过属性语法实现的解析器,这可能是正确的,因为 l 属性值要求首先创建此值,然后将其传递给子节点。但是,当使用正常的递归下降解析器实现时,由我决定是先构造该节点然后传递给子节点(自上而下)还是先创建子节点然后将返回值添加为该节点的子节点(传递在此节点的构造函数中)(自下而上)。这里应该有一些我想念的东西,因为我不同意这种语法“错误”的说法 并且这种语法已用于多种语言,尤其是。威斯安的。通常(或全部?)说它促进 LR 解析而不是 LL 的阅读。