如何打印我在Yacc / Bison中看到的任何内容?

时间:2016-03-07 02:20:32

标签: c++ c parsing bison

我有一个复杂的Yacc文件,其中包含一系列规则,其中一些很复杂,例如:

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 个答案:

答案 0 :(得分:2)

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

当您使用flex识别标记时,变量yytext指的是内部缓冲区flex用于识别标记。在令牌的操作中,它可用于获取令牌的文本,但仅用于临时 - 一旦操作完成并且读取下一个令牌,它将不再有效。

所以如果你有一个像以下那样的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; }

这使用了与ECHO大致相当的flex宏fputs(yytext, yyout) - 将输入复制到名为FILE *的{​​{1}}(默认为yyout

答案 1 :(得分:2)

如果相应右侧的第一个符号是终端,则bison动作中的maybeToList表示“扫描仪返回与该终端对应的令牌时产生的$1的值” 。如果符号是非终端,则它指的是在评估减少该非终端的动作期间分配给yylval的值。如果没有这样的动作,则默认为{{1}将被执行,因此它将通过减少该非终端的第一个符号的语义值。

如果一切都很明显,我很抱歉,但你的代码片段不足以显示:

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

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

  • 在扫描程序操作中为$$分配了哪些值(如果有);

  • 在野牛行动中为$$ = $1分配了哪些值(如果有)。

如果这些语义类型中的任何一个实际上不是字符串,那么yylval显然会产生垃圾。 (如果用$$编译生成的代码,gcc可能会警告你这个问题。如果你使用旧版本的flex / bison有可能出现虚假警告,我认为总是< / em>值得用printf进行编译并仔细阅读产生的警告。)

在bison操作中使用-Wall会产生问题,因为它会引用扫描的 last 标记的文本,通常是预读标记。特别是,在输入结束时,-Wall将为yytext,这就是您在输入结束时发生的任何减少中所选择的内容。 glibc的yytext实现非常适合打印NULL,而不是在您将printf提供给形成为(null)的参数时进行segfaulting,但我认为这不是一个好主意依赖于此。

最后,如果您确实有(char*)0语义值,并且指定了%s(或char*,如果您正在使用联合),那么您将遇到另一个问题,即yylval = yytext指向扫描程序拥有的临时缓冲区,当您使用该地址时,该缓冲区可能具有完全不同的内容。因此,如果要将其传递给解析器,则始终需要复制yylval.sval = yytext;

如果 想要做的是查看解析器正在做什么,我建议您启用bison的yydebug parser-trace feature。它会为您提供大量有用的信息,而不需要您将printf插入到您的野牛行动中。