连续使用两个运算符的"Rule useless in parser"



我想用像Matlab冒号运算符这样的运算符写一个语法,其中"a:b"one_answers"a:b:c"意味着稍微不同的东西。我更希望操作符是非结合的,因为"a:b:c:d"等没有意义。

这是我的语法的精简版本,以显示我是如何做到的:

%union {
  int ival;
}
%token tINT
%nonassoc ':'
%%
program: { }
       | expression ';' { }
expression: tINT { }
          | expression ':' expression { }
          | expression ':' expression ':' expression { }

由于某些原因,bison忽略了第二个冒号规则,并给出如下消息:

test.y:16.13-56: warning: rule useless in parser due to conflicts [-Wother]
           | expression ':' expression ':' expression { }
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

为什么bison不明白我在这里想要什么,我怎样才能改变我的语法使它工作?

编辑:如果有帮助,"bison -v"的输出包含

State 7
    4 expression: expression . ':' expression
    4           | expression ':' expression .
    5           | expression . ':' expression ':' expression
    5           | expression ':' expression . ':' expression
    ':'  error (nonassociative)
    $default  reduce using rule 4 (expression)

尽管我仍然不明白为什么野牛不允许这样做,也不明白如何解决这个问题。

您已经指定':'操作符是非关联的。去掉它,你就会得到预期的A:B:C冲突,可以解析为A:B:C, (A:B):C和A:(B:C)之一。

但是由于你想要它是非结合律的,这里有一种方法:

%token tINT
%%
program: { }
        | colonexpression ';' { }
        ;
colonexpression: expression { }
        | expression ':' expression ':' expression { }
        | expression ':' expression { }
        ;
expression: tINT { }
        ;
%%

啊!经过一番折腾,我终于找到了一种有效的方法,并且仍然允许我以"正确"的方式使用优先级,尽管如果我想避免大量的shift/reduce警告,它需要我为可以出现在表达式中的所有终端分配优先级。它还需要一个虚拟令牌来给单冒号规则一个适当的优先级(略低于':',以避免可理解的shift-reduce冲突)。

我对必须为像tINT这样的终端分配优先级并不完全满意,因为我的实际语法有一堆这样的东西,但我想这将不得不做,如果没有人有更好的主意。

%union {
  int ival;
}
%token tINT
%precedence nCOLON
%nonassoc ':'
%precedence tINT
%%
expression: tINT { }
          | expression_colon expression %prec nCOLON { }
          | expression_colon expression ':' expression { }
expression_colon: expression ':'

难道不能简单地使它具有适当的优先级,然后作为操作代码的一部分,如果有超过2个冒号,就抛出错误吗?也就是说,不要试图在语法中处理这个问题,而是将其作为语义约束,在C代码中强制执行。

我在想这样的东西——注意,这是纯粹的伪代码,因为我不知道你在构建什么样的解析树,但让我们假设你在构建一个抽象的语法树——

expression
    : expression ':' expression
    {
        if (Head($1) == DoubleColon)
            yyerror("Three-colon expressions are not allowed.");
        else if (Head($1) == Colon)
            $$ = DoubleColon(element_of($1, 1), element_of($1, 2), $3);
        else
            $$ = Colon($1, $3);
    }

根据您处理括号的方式,这可能会变得更复杂一些。(例如,如果你在解析树中显式地对它们进行编码,你可以使用上述技术,但否则你将需要一种方法来区分(a:b):ca:b:c。)

这是一个有趣的问题。我在自己编写的解析器中遇到了这个问题,但我从来没能想出一个通用的解决方案。在我的例子中,这两个冒号有不同的上下文和不同的优先级。这似乎是一个shift-reduce自动机应该能够做的事情,但是不清楚如何告诉Bison生成您想要的转换表。最后,我不得不使用词法分析器来解决这个问题,它回调解析器进行"模拟解析",这是Bison 3.0在其LAC特性中使用的一种技术。

最新更新