Bison &引用;“语法分析器中的规则无效”;连续使用两个运算符

Bison &引用;“语法分析器中的规则无效”;连续使用两个运算符,bison,Bison,我想用一个操作符编写一个语法,比如Matlab冒号操作符,其中“a:b”和“a:b:c”的意思稍有不同。我更希望操作符是非关联的,因为“a:b:c:d”等没有意义 下面是我语法的精简版本,以展示我是如何尝试做到这一点的: %union { int ival; } %token tINT %nonassoc ':' %% program: { } | expression ';' { } expression: tINT { } | expressi

我想用一个操作符编写一个语法,比如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 { }
出于某种原因,bison会忽略第二个冒号规则,并显示以下消息:

test.y:16.13-56: warning: rule useless in parser due to conflicts [-Wother]
           | expression ':' expression ':' expression { }
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
为什么野牛不明白我在这里想要什么,我怎样才能改变我的语法,让它起作用

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


尽管我仍然不明白为什么bison不允许这样做,也不知道如何解决它。

您已经指定“:”操作符是非关联的。移除该选项,您将从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警告的话。它还需要一个伪标记来为单冒号规则提供适当的优先级(略低于“:”,以避免可理解的移位减少冲突)

我不太喜欢给像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代码中强制执行

我在想这样的事情--请注意,这是纯伪代码,因为我不知道您正在构建哪种类型的解析树,但是让我们假设您正在构建一个抽象语法树--

根据处理括号的方式,这可能会变得更复杂一些。(也就是说,如果您在解析树中显式地对它们进行编码,您可以使用上述技术,但除此之外,您需要一种方法来区分
(a:b:c
a:b:c


这是一个有趣的问题。我在一个我正在编写的解析器中遇到了这个问题,但我始终无法找到一个通用的解决方案。在我的例子中,两个冒号有不同的上下文和不同的先例。这似乎是一个shift-reduce自动机应该能够做到的事情,但不清楚如何告诉Bison生成所需的转换表。最后,我不得不用一个lexer hack来解决这个问题,它调用解析器来执行“模拟解析”,这是Bison 3.0在其LAC特性中使用的一种技术。

更改冒号生成的定义顺序。先配短的。第二个永远不会开火。Bison默认生成LR解析器。交换顺序没有帮助,只是在第15行出现了相同的错误。也许,但我的冒号运算符不是系统中唯一的运算符,我还有算术和条件等,所以它可能需要某种优先级。这看起来像是把它塞进其他操作符中会很混乱,除非我完全抛弃了yacc样式的优先级,而只是用递归下降样式编写所有规则?丑陋…好吧,我想如果所有其他方法都失败了,我可以对所有优先级低于冒号的运算符使用递归下降式规则(Matlab的优先级相当低),而对优先级较高的运算符仍然使用普通优先级。Hmmm…@Ove:这对于其他操作符的优先级关系很好,只要您手动将操作符分为两组:优先级高于的操作符和优先级较低的操作符。一组进入表达,另一组进入克隆表达。@rici:有趣的想法。但是,如果您向冒号表达式添加了更多运算符,那么您可能需要为冒号指定优先级,对吗?但是,添加第三种表达式可能就可以了。那可能行得通。尽管如此,这种方式还是有点不令人满意。。。我会再考虑的。@ove:是的,你必须把冒号放在优先列表中。但它会在预期的地方。就我个人而言,我不喜欢使用优先级,除非使用的是琐碎的,因为很难对结果进行推理,比如在基于优先级的解决方案中,我认为它不是一个可读的语法。和往常一样,口味各异;使用您喜欢的样式。我没有显式地编码括号,因此是的,这会有问题。在括号规则中设置的
表达式
的语义值中放置一个1位标志,否则不设置?我就是这样处理的。
%union {
  int ival;
}

%token tINT

%precedence nCOLON
%nonassoc ':'
%precedence tINT

%%

expression: tINT { }
          | expression_colon expression %prec nCOLON { }
          | expression_colon expression ':' expression { }

expression_colon: expression ':'
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);
    }