我正在尝试使用 Menhir 为正则表达式语言编写解析器。在我修改它以消除歧义之前,我想要的语法看起来有点像下面的例子。请注意,“排序/连接”是隐式的,并且没有与该操作关联的标记。
%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 *)
如果我有连接的标记,我将能够通过使用优先声明来消除歧义
%token LPAREN RPAREN
%token CHAR STAR PIPE
%token CONCAT
%token EOF
%left PIPE
%left CONCAT
%nonassoc STAR
%start <unit> parse
%%
parse: re EOF {()}
re:
| LPAREN re RPAREN {()} (* Grouping *)
| CHAR {()} (* Single character *)
| re STAR {()} (* Kleene star *)
| re CONCAT re {()} (* Sequencing / Concatenation *)
| re PIPE re {()} (* Alternation *)
但是,如果没有连接规则中的 CONCAT 令牌,我将无法正常工作。我尝试使用%prec
声明,但仍然存在一些移位/减少冲突。
%token LPAREN RPAREN
%token CHAR STAR PIPE
%token CONCAT
%token EOF
%left PIPE
%left CONCAT
%nonassoc STAR
%start <unit> parse
%%
parse: re EOF {()}
re:
| LPAREN re RPAREN {()} (* Grouping *)
| CHAR {()} (* Single character *)
| re STAR {()} (* Kleene star *)
| re re %prec CONCAT {()} (* 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 *)
尽管最后一个示例运行良好,但我真的很好奇是否可以仅通过使用优先级和关联性声明来消除所有歧义和冲突,而无需重写语法。