"规则在解析器中无用"与两个运营商连续

时间:2014-07-06 00:56:21

标签: bison

我想用Matlab冒号运算符之类的运算符编写语法,其中“a:b”和“a:b:c”表示略有不同。而且我更喜欢运算符是非关联的,因为“a:b:c:d”等没有意义。

这是我的语法的精简版,以显示我是如何尝试的:

%union {
  int ival;
}

%token tINT

%nonassoc ':'

%%

program: { }
       | expression ';' { }

expression: tINT { }
          | expression ':' expression { }
          | expression ':' expression ':' expression { }

出于某种原因,野牛忽略了第二个冒号规则,并带有以下信息:

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

为什么野牛不了解我想要的东西,我怎样才能改变语法以便它起作用呢?

编辑:如果有帮助,“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)

虽然我仍然不明白为什么野牛不应该允许这个,也不知道如何解决它。

3 个答案:

答案 0 :(得分:2)

您已指定':'运算符是非关联的。删除它,你将从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 { }
        ;

%%

答案 1 :(得分:1)

啊!经过大量的讨论,我终于找到了一种有效的方法,并且仍然允许我使用" right"虽然它需要我为表达式中出现的所有终端分配一个优先级,如果我想避免大量的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 :(得分:1)

你不能简单地将其与适当的优先级联系起来,然后作为行动代码的一部分,如果超过2个冒号会抛出错误吗?也就是说,不要尝试在语法中处理这个问题,但要使其成为语义约束,在C代码中强制执行。

我想到这样的事情 - 这是纯粹的伪代码,请注意,因为我不知道你正在构建什么样的解析树,但让我们假设你&#39 ;重建一个抽象语法树 -

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区分开来。)

这是一个有趣的问题。我在一个正在编写的解析器中面对它,我从来没有能够提出一个通用的解决方案。在我的例子中,两个冒号有不同的上下文和不同的优先级。这似乎是一种移位减少自动机应该能做到的事情,但它并不清楚如何告诉Bison生成你想要的转换表。最终我不得不用一个lexer hack解决它,它回调解析器进行一次"模拟解析," Bison 3.0在其LAC功能中使用的一种技术。