使用预定义标记(%标记)和使用YACC规则中的单个字符之间的区别

时间:2014-05-22 09:51:35

标签: c parsing bison yacc lex

我有一个非常大的YACC文件要调试,但我目前关注的部分看起来像这样:

....

%token TOKEN_HASH 123 "#"

...

    RULE1 : TOKEN_XYZ TOKEN_HASH '(' ')' 
             {
              //DO something here
              //some C code
             }

我想按如下方式编写RULE1:

RULE1 : TOKEN_XYZ '#' '(' ')' 
         {
          //DO something here
          //some C code
         }

yacc中不允许这样做吗? 因为第二个代码我得到以下错误:

  

parser.y:冲突:1次/减少

     

parser.y:预期0班次/减少冲突

非常感谢任何形式的帮助/评论。

谢谢!

2 个答案:

答案 0 :(得分:2)

bison不允许您使用单引号终端('#')并定义一个命名终端(如TOKEN_HASH),其数字代码等同于引用字符(在这种情况下,35)。如果您使用'#'并指定

,则不会抱怨
%token TOKEN_HASH 123 "#"

因为123'#'不同;相反,它是'{'的值。但是,这样的声明具有很大的误导性:它告诉读者一个TOKEN_HASH是一个哈希字符,但它实际上是一个开放式括号。 (当然,你的词法分析器在遇到哈希时可能会返回一个开放式大括号,但这会更加令人困惑。)

%token声明(或语法)中的双引号字符串仅用于文档目的。因此,您应该尝试确保文档准确无误。 bison和flex都不会强制执行甚至不注意双引号内的内容,因此您不会收到任何错误或警告误导性标签。

总的来说,你不应该混合和匹配命名的单字符标记和引用的单字符标记,你不应该为命名标记指定整数代码,即使bison允许你这样做。在这种情况下你所做的一切都让那些阅读你的代码(很可能是你自己)和创建维护问题的人感到困惑。

现在,转换/减少冲突将与包含终端'#'的语法中的其他一些生产有关。由于TOKEN_HASH'#'的终端不同,因此其他作品不会与RULE1 : TOKEN_XYZ TOKEN_HASH '(' ')'发生冲突。但它肯定会与RULE1 : TOKEN_XYZ '#' '(' ')'冲突。

如果您提供bison -v标记,则会生成一个扩展名为.output的文件,该文件将提供有用的信息来跟踪冲突。

答案 1 :(得分:0)

你应该节约%token指令,并在语法中尽可能使用实际的字符文字。这样你也可以节省flex指令:你不需要每个特殊字符,你只需要这个:

. return yytext[0];

作为你的最后一条规则。