我有一个非常大的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班次/减少冲突
非常感谢任何形式的帮助/评论。
谢谢!
答案 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];
作为你的最后一条规则。