Shift/Reduce 变量声明冲突

Shift/Reduce conflict in variable declaration

我正在使用 bison 编写类 C 语法的解析器,但我在变量声明中遇到问题。

我的变量可以是简单变量、数组或结构,所以我可以有一个像 a.b[3].c.

这样的变量

我有以下规则:

var : NAME             /* NAME is a string */
    | var '[' expr ']'
    | var '.' var
    ;

这给我带来了 shift/reduce 冲突,但我想不出解决这个问题的方法。

如何重写语法或使用 Bison 优先级来解决问题?

我不知道您为什么希望 .[] 运算符具有关联性,但是这样的事情可能会启发您。

y
%union{}

%token NAME

%start var

%left   '.'
%left   '['

%%

var:
    NAME
|   var '[' expr ']'
|   var '.' var

此外,由于var可能出现在expr中,因此语法可能存在其他问题。

当然可以通过优先级声明来解决这种 shift-reduce 冲突,但在我看来,这只会让语法更难阅读。最好让语法反映语言的语义。

A var(有些人可能称之为左值或引用)要么是简单标量变量的名称,要么是从 var 命名复杂值和选择器,成员名称或数组索引。换句话说:

var     : NAME
        | var selector
        ;
selector: '.' NAME
        | '[' expression ']'
        ;

这使得a.b[3].c的含义很清楚,例如;语义由解析树描述:

       a.b[3].c
     +----+----+
     |         |
   a.b[3]     .c
  +---+--+
  |      |
 a.b    [3]
+-+-+
|   |
a  .b

没有必要创建selector规则;将这两个规则放在一起是微不足道的。如果你不觉得上面写的更清楚,下面的也行:

var: NAME
   | var '.' NAME
   | var '[' expression ']'
   ;