繁体   English   中英

看似等效的Menhir规则改变了语法中的移位/减少冲突

[英]Seemingly equivalent Menhir rules change the shift/reduce conflicts found in grammar

我正在使用Menhir创建一个解析器,并且有一种行为总是让我绊倒,但我不明白。 我创建了以下最小示例来演示它; 这以Go语言( http://golang.org/ref/spec#Method_declarations )的方法声明显示了接收方参数的声明:

%{

%}

%token <string> T_identifier
%token T_star

%start <unit> demo


%%


(* This rule has a shift/reduce conflict
demo:
| option(T_identifier) option(T_star) T_identifier { () } 
*)

(* This rule is okay. *)
demo:
| T_identifier T_star T_identifier { () }
| T_identifier T_identifier        { () }
| T_star T_identifier              { () }
| T_identifier                     { () }

据我所知,这两个规则在语义上是等效的:我们正在寻找一个可选的标识符(接收者的名称),一个可选的星号(是否为指针)和一个强制类型名称(接收者的类型)。 但是,第一个规则(已注释掉的规则)产生了移位/减少冲突,而第二个规则运行良好。

每当发生这种情况时,我就可以通过用多个规则替换option来在解析器中进行处理,但是我一直在that恼我不明白为什么会发生这种情况。

(如果您不知道menhir,它是一个LR(1)解析器生成器,因此可能会应用其他类似工具的工作知识。)

我想Menhir通过一些标准转换将EBNF还原为BNF。 这很普遍。 不幸的是,这些转换会破坏LR(1)的可分析性。

考虑您的规则,采用另一种类似于EBNF的语法:

demo → IDENTIFIER? STAR? IDENTIFIER

将其转换为BNF的一种方法将是您在第二组规则中所做的:定义四个不同的规则,每种可能性一个。 该转换永远不会改变LR(1)的可解析性,并且对于带有“可选”运算符的规则来说始终是可能的,但是它有两个缺点:

  1. 如果规则中有多个可选元素,则最终结果是大量生产。

  2. 它对重复运算符无效。

似乎更通用的另一种方法是为每个扩展的BNF运算符创建一个新的非终结符。 因此,我们可以这样做:

optional_identifier → IDENTIFIER | ε
optional_star       → STAR | ε
demo                → optional_identifier optional_star IDENTIFIER

类似的转换适用于x*

repeated_x → ε | repeated_x x

那肯定会产生等效的语言,但是现在语法可能不是LR(1)。

特别地, demo不再是LR(1)。 它在一开始就失败了。 假设第一个输入令牌是IDENTIFIER 那可能是

IDENTIFIER IDENTIFIER

要么

IDENTIFIER

(或其他一些可能性,但这足以说明问题。)

在第二种情况下(只是一种类型),我们需要先减小optional_identifieroptional_star然后才能移动IDENTIFIER 在第一种情况(变量和类型)中,我们需要立即移动IDENTIFIER 我们唯一可以分辨出的信息是前瞻令牌IDENTIFIER ,显然这还不够。

如果使用四向扩展生产,则没有问题:

demo → IDENTIFIER
     | STAR IDENTIFIER
     | IDENTIFIER IDENTIFIER
     | IDENTIFIER STAR IDENTIFIER

在这里,当我们看到IDENTIFIER ,我们不知道它是第一生产,第三生产还是第四生产的一部分。 但这并不重要,因为在所有情况下,我们只需移动IDENTIFIER并等待更多信息。

yacc/bison和其他允许中间规则动作(MRA)的解析器生成器也会发生类似的现象。 MRA变成了一个新的非终端,其唯一的生产是ε生产; 新的非终端的目的是在MRA减少时运行它。 这真的很酷,只是有时在我们不知道减少它是否合适的时候引入了新的非终端。 因此,即使语言没有更改,MRA仍可以将一个很好的LR(1)语法转换为非LR(1)语法。

尽管对于Menhir而言无关紧要,但可能有趣的是,上面的EBNF转换,如果仔细进行,不会引起歧义,否则就不会出现歧义。 因此,即使生成的语法不再是LR(1),它仍然是明确的,可以使用GLR解析器进行解析。 但是,据我所知,Menhir不会生成GLR解析器,因此这一事实可能不是很有用。

在第二条规则中,您明确指定了解决歧义的顺序。 确实,您可以通过对子句重新排序而以几种不同的方式重写第二条规则。 这就是为什么门希尔抱怨,他不知道你喜欢什么顺序。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM