2016-03-07 75 views
-1

我有一堆的规则复杂Yacc的文件,他们中的一些复杂的,例如:如何在Yacc/Bison中看到我所看到的内容?

start: program 
program: extern_list class 
class: T_CLASS T_ID T_LCB field_dec_list method_dec_list T_RCB 

确切的规则,我采取相应的行动并不重要,因为我想做的事情,似乎相当简单:只需使用我为其他目的定义的规则打印出现在源文件中的程序即可。但我很惊讶这样做有多困难。

首先,我尝试在上面的第二条规则中添加printf("%s%s", $1, $2)。这产生了“ @P @”。根据我的理解,解析后的文本也可以作为变量,yytext。我将printf("%s", yytext)添加到文件中的每个规则,并将extern char* yytext;添加到文件的顶部。这根据语言的语法从有效文件生成(null){void)1133331122222210101010--552222202020202222;;;;||||&&&&;;;;;;;;;;}}}}}}}}。最后,我将extern char* yytext;更改为extern char yytext[],认为这没有什么区别。它的输出差异最好显示为截图Gibberish

我在Xubuntu 14.04上使用Bison 3.0.2。

回答

2

如果您只是想在解析它时回显某些输出的源代码,那么在词法分析器中最容易做到这一点。你没有说明你用于词法分析器的东西,但是你提到了由lex/flex使用的yytext,所以我会假设这一点。

当您使用flex识别令牌时,变量yytext引用内部缓冲区flex用于识别令牌。在令牌的作用下,它可以用来获取令牌的文本,但只是暂时的 - 一旦动作完成并且下一个令牌被读取,它就不再有效。

所以,如果你有一个像柔性规则:

[a-zA-Z_][a-zA-Z_0-9]* { yylval.str = yytext, return T_ID; } 

这可能不会在所有的工作,因为你必须在晃来晃去你的程序跑来跑去的指针;可能是你看到的随机输出的来源。相反,你需要复制一份。如果你也想输出的输入不变,你可以在这里太:

[a-zA-Z_][a-zA-Z_0-9]* { yylval.str = strdup(yytext); ECHO; return T_ID; } 

此使用Flex宏观ECHO这大致相当于fputs(yytext, yyout) - 复制输入到一个名为yyoutFILE *(默认为stdout

2

如果在相应的右手侧的第一个符号是在一个野牛动作的终端,$1意思是“yylval通过时,它返回对应于该终端的令牌中的扫描仪产生的值。如果符号是非终端,则它指的是分配给的值期间减少非终端的行动评估。如果没有这样的动作,那么缺省$$ = $1将被执行,所以它将通过减少非终端中的第一个符号的语义值。

我道歉,如果一切是显而易见的,但你的片段是不足以表明:

  • 什么语义类型对于每一个非终端;

  • 每个终端的语义类型是什么;

  • 在扫描仪操作中将什么值(如果有)分配给yylval;

  • 什么样的值,如果有的话,被分配到$$在野牛行动。

如果其中任何语义类型的都没有,事实上,字符串,那么printf显然会产生垃圾。 (如果你用-Wall编译生成的代码,gcc可能会提醒你,尽管如果你使用旧版本的flex/bison,可能会出现虚假警告,但我认为这是总是值得编译与-Wall并仔细读取所产生的警告。)

在野牛动作使用yytext是有问题的,因为这将涉及最后令牌扫描,通常先行标记的文字。特别是,在输入结束时,yytext将是NULL,这就是您将在输入结束时发生的任何减少中获得的结果。 glibc的printf的实现非常好,可以打印(null),而不是在您将(char*)0提供为格式为%s的参数时进行分段转换,但我认为依靠它不是一个好主意。

最后,如果你有一个char*语义价值,而分配yylval = yytext(或yylval.sval = yytext;如果您使用的工会),那么你会遇到另一个问题,这是yytext点到临时缓冲由扫描仪拥有,并且该缓冲区在您使用该地址时可能会有完全不同的内容。所以如果你想将它传递给解析器,你总是需要复制yytext

如果你真的想要做的是看看解析器在做什么,我建议你启用野牛的yydebug parser-trace feature。它会给你很多有用的信息,而不需要你插入printf到你的野牛动作中。

相关问题