Bison - 在语法上无用的非终结符
Bison - nonterminal useless in grammar
我正在尝试使用 Bison 创建一个简单的语法,但我收到一条警告,指出非终结符是无用的 (additive_expr)。
我的代码如下:
%%
multiplicative_expr:
CONSTANT_INTEGER
| multiplicative_expr MULTIPLICATION CONSTANT_INTEGER
;
additive_expr:
multiplicative_expr
| additive_expr ADDITION multiplicative_expr
我看到很多类似的问题,我以为是因为它没有在其他表达式中使用,但我创建了一个包含这个的新表达式,并且警告继续。
Bison 的语法由符号和规则组成,规则以可以用短语 "that symbol is the synthetic form of those ones" 理解的方式连接它们。同样,在相反的意义上,你会说 "those symbols are the expanded form of this one"。
一个符号可以合成一些基本的东西,如不可分割的单元,称为“终端符号”,或者像其他符号一样复杂,又可以合成更多的东西,在这种情况下,后者和前者被称为“非终结符号”。
所有这些关于综合和扩展的内容都可以被认为是通过不同形式来表示同一事物的一种方式。每次形式根据属于语法的规则发生变化,这就是一次重写,就像用不同的方式表达同一事物的概念。
根据这里的常识(以及关于解析器、Bison 等的文本所说的),随机重写符号没有多大意义。一系列重写应该朝着既定的目标推进,成功或失败,但始终能够检测到任何一种情况并停止并得到结果。 Bison 的方法是用户(程序员)突出语法符号集中的一个符号,它被认为完全合成了任何有效的符号字符串以及没有找到重写它的方法的无效字符串。这称为开始符号。
除此之外,在典型的语法布局中,并非所有符号都明确地在规则的相应右侧和左侧参与起始符号。与其余起始符号的连接的构造方式是,任何符号通过参与同一规则与另一个符号连接,并且这种构造是一次或多次,其中一个与起始符号建立连接。
综上所述,文法符号与起始符号无关是没有用的。因为重写是为了达到起始符号而驱动的,而断开连接的符号永远不会成功,所以它永远不会被使用。然后在 "useless symbol" 上发出警告,当然是在解析器生成阶段,因为这里的问题不在于符号字符串实例,而在于语法符号(符号类型)。
对于终端符号,控制不会被强制执行,因为 Bison 让终端围绕在这里用于其他目的(例如,建立优先级而不一定用于告诉符号组是如何制作的),而不是非终端,总是无用的,并在选项或指令未设置此选项时引发警告。
该报告没有错误严重性,因为您可以出于任何原因希望它存在,但 Bison 会忽略它。尽管如此,该警告仍应引起注意,因为它可能意味着键入错误导致语法未反映并且解析器未执行您想要的操作。
在继续解决之前,一些注意事项:
您的语法定义了 additive_exp 和 multiplicative_exp 的分组,这听起来像是数学运算 + 和 *.
您的语法很好地遵循了 Bison 关于递归性的建议,即,面对证据表明 multiplicative_expr MULTIPLICATION CONSTANT_INTEGER
或 CONSTANT_INTEGER MULTIPLICATION multiplicative_expr
的本质相同,您的语法很方便建造。 (Bison 手册,§ 3.3.3 递归规则)。
您的语法正确地避免了 Bison 的 reduce/reduce 和 shift/reduce 冲突,同时它符合*优先于 + 的更高优先级的数学意义。
考虑到上述情况属实,我将针对 "useless symbol" 的具体问题提出一些技巧。
Bison 不需要任何特定的规则顺序。除了第一个规则有权成为从中选择起始符号的规则之外,Bison 不介意规则是否提到了语法中未定义但在后面的符号。如果您交换规则,使 additive_exp 先出现,它将成为开始符号,并且因为它确实扩展到另一个而不是相反,所以警告将消失。或者在语法顶部的 %%
之前放置一个 %start additive_exp
,具有完全相同的效果。
考虑到您的语法有规则 additive_exp: multiplicative_exp
,出现了其他方法。按照参考书目,这种形式的规则通常称为 "single production",并引用它:
“当语法用于描述运算符的优先级和关联性时,会出现单一产生式的常见情况”。
[...]
“事实证明,在运算符优先级或结合性的表示中出现的单个产品总是可以消除的”
(“LR 解析”、“A.V.Aho”和“S.C.Johnson”)。
参考书目在这里说的完全适合你的情况,因为与你使用裸 exp
而不是 additive_exp
和 multiplicative_exp
的语法相比,你的语法没有更多的特征,这会给你留下一个开始符号,它又是唯一的非终结符,设置了非终结符无用的可能性,更重要的是,保留了语法的含义。
Bison 通过其指令 %prec、%left 和 %right 帮助您进行这种简化,尤其是它们在指令部分出现的顺序。通俗地说,它是关于运算符的优先级,但更准确地说,实际上正在改变的是 Bison 的解析器决定立即分组或延迟后者,因为遇到一个符号可以让出两种可能性。 Bison 的手册有关于它们的详细信息,Yacc 的手册也有(通常捆绑在 Bison 发行版中,因为两者非常相关),甚至可能更详细地说明优先级如何附加到语法规则。 (Bison 手册,§ 3.7.3 运算符优先级和 Yacc 手册,§ 6:优先级)。
在可能的情况下使用优先级指令,可能会帮助 Bison 节省一些时间,因为它避免了在构建解析器时通常会进行的一些优化。
同样,基于相同的来源(“LR Parsing”、“A.V.Aho”和“S.C.Johnson”):
“二义性语法立即生成简化的解析器,不需要这个优化算法”。
我正在尝试使用 Bison 创建一个简单的语法,但我收到一条警告,指出非终结符是无用的 (additive_expr)。
我的代码如下:
%%
multiplicative_expr:
CONSTANT_INTEGER
| multiplicative_expr MULTIPLICATION CONSTANT_INTEGER
;
additive_expr:
multiplicative_expr
| additive_expr ADDITION multiplicative_expr
我看到很多类似的问题,我以为是因为它没有在其他表达式中使用,但我创建了一个包含这个的新表达式,并且警告继续。
Bison 的语法由符号和规则组成,规则以可以用短语 "that symbol is the synthetic form of those ones" 理解的方式连接它们。同样,在相反的意义上,你会说 "those symbols are the expanded form of this one"。
一个符号可以合成一些基本的东西,如不可分割的单元,称为“终端符号”,或者像其他符号一样复杂,又可以合成更多的东西,在这种情况下,后者和前者被称为“非终结符号”。
所有这些关于综合和扩展的内容都可以被认为是通过不同形式来表示同一事物的一种方式。每次形式根据属于语法的规则发生变化,这就是一次重写,就像用不同的方式表达同一事物的概念。
根据这里的常识(以及关于解析器、Bison 等的文本所说的),随机重写符号没有多大意义。一系列重写应该朝着既定的目标推进,成功或失败,但始终能够检测到任何一种情况并停止并得到结果。 Bison 的方法是用户(程序员)突出语法符号集中的一个符号,它被认为完全合成了任何有效的符号字符串以及没有找到重写它的方法的无效字符串。这称为开始符号。
除此之外,在典型的语法布局中,并非所有符号都明确地在规则的相应右侧和左侧参与起始符号。与其余起始符号的连接的构造方式是,任何符号通过参与同一规则与另一个符号连接,并且这种构造是一次或多次,其中一个与起始符号建立连接。
综上所述,文法符号与起始符号无关是没有用的。因为重写是为了达到起始符号而驱动的,而断开连接的符号永远不会成功,所以它永远不会被使用。然后在 "useless symbol" 上发出警告,当然是在解析器生成阶段,因为这里的问题不在于符号字符串实例,而在于语法符号(符号类型)。
对于终端符号,控制不会被强制执行,因为 Bison 让终端围绕在这里用于其他目的(例如,建立优先级而不一定用于告诉符号组是如何制作的),而不是非终端,总是无用的,并在选项或指令未设置此选项时引发警告。
该报告没有错误严重性,因为您可以出于任何原因希望它存在,但 Bison 会忽略它。尽管如此,该警告仍应引起注意,因为它可能意味着键入错误导致语法未反映并且解析器未执行您想要的操作。
在继续解决之前,一些注意事项:
您的语法定义了 additive_exp 和 multiplicative_exp 的分组,这听起来像是数学运算 + 和 *.
您的语法很好地遵循了 Bison 关于递归性的建议,即,面对证据表明
multiplicative_expr MULTIPLICATION CONSTANT_INTEGER
或CONSTANT_INTEGER MULTIPLICATION multiplicative_expr
的本质相同,您的语法很方便建造。 (Bison 手册,§ 3.3.3 递归规则)。您的语法正确地避免了 Bison 的 reduce/reduce 和 shift/reduce 冲突,同时它符合*优先于 + 的更高优先级的数学意义。
考虑到上述情况属实,我将针对 "useless symbol" 的具体问题提出一些技巧。
Bison 不需要任何特定的规则顺序。除了第一个规则有权成为从中选择起始符号的规则之外,Bison 不介意规则是否提到了语法中未定义但在后面的符号。如果您交换规则,使 additive_exp 先出现,它将成为开始符号,并且因为它确实扩展到另一个而不是相反,所以警告将消失。或者在语法顶部的 %%
之前放置一个 %start additive_exp
,具有完全相同的效果。
考虑到您的语法有规则 additive_exp: multiplicative_exp
,出现了其他方法。按照参考书目,这种形式的规则通常称为 "single production",并引用它:
“当语法用于描述运算符的优先级和关联性时,会出现单一产生式的常见情况”。
[...]
“事实证明,在运算符优先级或结合性的表示中出现的单个产品总是可以消除的”
(“LR 解析”、“A.V.Aho”和“S.C.Johnson”)。
参考书目在这里说的完全适合你的情况,因为与你使用裸 exp
而不是 additive_exp
和 multiplicative_exp
的语法相比,你的语法没有更多的特征,这会给你留下一个开始符号,它又是唯一的非终结符,设置了非终结符无用的可能性,更重要的是,保留了语法的含义。
Bison 通过其指令 %prec、%left 和 %right 帮助您进行这种简化,尤其是它们在指令部分出现的顺序。通俗地说,它是关于运算符的优先级,但更准确地说,实际上正在改变的是 Bison 的解析器决定立即分组或延迟后者,因为遇到一个符号可以让出两种可能性。 Bison 的手册有关于它们的详细信息,Yacc 的手册也有(通常捆绑在 Bison 发行版中,因为两者非常相关),甚至可能更详细地说明优先级如何附加到语法规则。 (Bison 手册,§ 3.7.3 运算符优先级和 Yacc 手册,§ 6:优先级)。
在可能的情况下使用优先级指令,可能会帮助 Bison 节省一些时间,因为它避免了在构建解析器时通常会进行的一些优化。 同样,基于相同的来源(“LR Parsing”、“A.V.Aho”和“S.C.Johnson”): “二义性语法立即生成简化的解析器,不需要这个优化算法”。