我正在读这本书:正式的语法和语义 编程语言。我不明白这个练习:
考虑以下两个语法,每个语法生成字符串
正确平衡的括号和括号。确定是否两者之一
很暧昧。希腊字母ε
重新获得一个空字符串。
<string> ::= <string> <string> | ( <string> ) |[ <string> ] | ε
<string> ::= ( <string> ) <string> | [ <string> ] <string> | ε
答案 0 :(得分:1)
第一个是模棱两可的,第二个不是。这是一个关于如何将无上下文语法(CFG)转换为解析树的问题。在第一个CFG中,第一个产品是模糊性的来源。如果我写字符串&#34;()()()&#34;目前还不清楚这个字符串的哪一部分可以与左边的非终端匹配,哪个部分可以匹配正确的非终端。
该字符串的一个有效解析树是前两个字符&#34;()&#34;匹配第一个非终端,然后匹配第二个生产和其余的字符串&#34;()()&#34;匹配正确的非终端,再次匹配第一个生产。
另一个有效的解析树用于前四个字符&#34;()()&#34;匹配左边的非终端和其余的#34;()&#34;匹配正确的非终端。两者都同样有效,因此存在歧义。像LR解析器这样的解析器工具称之为转移/减少冲突。
如果您只想查看字符串是否属于某种语言,那么这绝对没有问题。如果任何解析有效,那么你很好。但是,如果你正在尝试创建一个解析树来用作编程语言的抽象语法树,那么这确实会产生问题。
要说明为什么这是解析语言的问题,请看一下这个例子。
<expression> ::= <expression> <expression> | <expression> + <expression> | <expression> * <expression>
你如何解析&#34; 1 + 2 * 3&#34;?是&#34;(1 + 2)* 3&#34;或&#34; 1+(2 * 3)&#34;?我给出的语法有一个shift / reduce冲突,因此没有指定。大多数LR解析工具会自动为您自动解决此冲突。这很危险,因为如果我正在编写一种编程语言,那么应该对程序员将获得的内容有一个明确的理解。由于这是一个典型的算术表达式,我们应该遵循数学惯例并得到答案为&#34; 1+(2 * 3)&#34;。
解决方案是重写语法,使其明确或许多解析器工具也只允许我们明确指定词法符号的关联性和优先级,这对于保持语法的美观性和可读性非常方便。