如您所见,bison 没有实现? 正则表达式可选运算符。它也没有实现+ 或* 重复运算符。这是因为上下文无关文法中产生式的右侧不是正则表达式。
Yacc/bison 上下文无关语法确实允许| 交替运算符,但作为缩写:
a : b | c
和写完全一样
a : b
a : c
而语义动作只适用于指定它们的备选方案,因此
a : b | c { /* C action; */ }
相当于:
a : b { /* Implicit default action*/ }
a : c { /* C action; */ }
很容易创建X_opt 非终端来捕获X? 的语义:
X_opt: X | %empty { $$ = default_value; }
在许多简单的情况下都可以正常工作,但也有许多语法在其中引入了不必要的 shift-reduce 冲突。例如:
label: IDENT ':'
label_opt: label | %empty
statement: label_opt expr
由于expr 可以以标识符开头,因此无法知道IDENT 令牌是否以label 开头,或者它是否在空label_opt 之后开始expr。但是 LR(1) 要求在消耗 IDENT 之前减少空的 label_opt。所以上面的语法是LR(2),不能被LR(1)解析器正确解析。
如果不使用label_opt 快捷方式,则不会出现该问题:
label: IDENT ':'
statement: label expr
| expr
由于解析器现在在遇到':' 之前没有在label 和expr 之间做出决定。