Parsing 在Menhir中,如果规则没有运算符,是否可以使其左关联?
我正在尝试使用Menhir为正则表达式语言编写解析器。在修改语法以消除歧义之前,我想要的语法看起来有点像下面的示例。请注意,“排序/连接”是隐式的,并且没有与该操作关联的标记Parsing 在Menhir中,如果规则没有运算符,是否可以使其左关联?,parsing,ocaml,lalr,menhir,Parsing,Ocaml,Lalr,Menhir,我正在尝试使用Menhir为正则表达式语言编写解析器。在修改语法以消除歧义之前,我想要的语法看起来有点像下面的示例。请注意,“排序/连接”是隐式的,并且没有与该操作关联的标记 %token LPAREN RPAREN %token CHAR STAR PIPE %token EOF %start <unit> parse %% parse: re EOF {()} re: | LPAREN re RPAREN {()} (* Grouping *) | CHAR
%token LPAREN RPAREN
%token CHAR STAR PIPE
%token EOF
%start <unit> parse
%%
parse: re EOF {()}
re:
| LPAREN re RPAREN {()} (* Grouping *)
| CHAR {()} (* Single character *)
| re STAR {()} (* Kleene star *)
| re re {()} (* Sequencing / Concatenation *)
| re PIPE re {()} (* Alternation *)
我认为这可能是因为menhir无法判断序列应该是左关联的,但我不能100%确定这是否是问题的原因
到目前为止,我能找到的唯一解决方案是将re
规则分解为一系列不同的规则,以明确优先级和关联性:
%token LPAREN RPAREN
%token CHAR STAR PIPE
%token EOF
%start <unit> parse
%%
parse: re EOF {()}
re: re3 {()}
re0:
| LPAREN re RPAREN {()} (* Grouping *)
| CHAR {()} (* Single character *)
re1:
| re0 {()}
| re0 STAR {()} (* Kleene star *)
re2:
| re1 {()}
| re2 re1 {()} (* Sequencing / Concatenation *)
re3:
| re2 {()}
| re3 PIPE re2 {()} (* Alternation *)
%LPAREN RPAREN令牌
%令牌字符星型管
%令牌EOF
%开始解析
%%
parse:re-EOF{()}
re:re3{()}
re0:
|LPAREN re RPAREN{()}(*分组*)
|字符{()}(*单个字符*)
re1:
|re0{()}
|re0星{()}(*Kleene星*)
re2:
|re1{()}
|re2 re1{()}(*排序/串联*)
re3:
|re2{()}
|re3管道re2{()}(*替换*)
虽然最后一个例子很好,但我真的很好奇,是否可以通过使用优先级和关联性声明来删除所有的umbiguity和冲突,而不需要重写语法。首先,这在Menhir上并不完全是个问题,但在Menhir接受的语法中,它位于
LR(1)
集合中。如果您提供的语法不需要优先级注释,则该语法将被视为SLR(1)
,是LR(1)
的子集
上一个示例之所以有效,是因为每个优先级都有产品(比如解析表达式语法,本质上是明确的),这绝对不是一种糟糕的编写方式;一些现代编译器使用这种符号来处理更复杂的语言
为了了解您的问题,让我们首先请Menhir向我们解释冲突发生的地点:
menhir——解释解析器.mly
它将生成一个解析器。冲突
文件,解释它可以在哪些状态下同时执行操作、减少和转移:
...
** In state 8, looking ahead at STAR, shifting is permitted
** because of the following sub-derivation:
re re
re . STAR
** In state 8, looking ahead at STAR, reducing production
** re -> re re
** is permitted because of the following sub-derivation:
re STAR // lookahead token appears
re re .
** Conflict (shift/reduce) in state 7.
** Tokens involved: STAR PIPE LPAREN CHAR
** The following explanations concentrate on token STAR.
** This state is reached from parse after reading:
re PIPE re
** The derivations that appear below have the following common factor:
** (The question mark symbol (?) represents the spot where the derivations begin to differ.)
parse
re EOF
(?)
对于LR(1)
,语法非常模糊,因此:
CHAR CHAR STAR
可计算为:
(CHAR)星号
CHAR(CHAR-STAR)
list
实现连接:
re:
| term PIPE re
| term { } (* Left associativity *)
term:
| list(base STAR* { }) { } (* Concatenation is taken by list *)
base:
| CHAR
| LPAREN re RPAREN { }
谢谢你的回答!我得到的印象是,这里真正的教训是,可以使用多个级别的
re
规则来创建更明确的语法,而不是试图巧妙地使用优先级声明。即使在上一个示例中,真正解决问题的是您有单独的re
、term
和base
规则。
CHAR CHAR STAR
re:
| term PIPE re
| term { } (* Left associativity *)
term:
| list(base STAR* { }) { } (* Concatenation is taken by list *)
base:
| CHAR
| LPAREN re RPAREN { }