2016-03-07 105 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到你的野牛動作中。

相關問題