1

我們正在爲Al Aho的編譯器類編寫一個編譯器,我們正在考慮用於生成AST的以下代碼。這是一些背景。我們希望將範圍規則作爲一組名稱映射來實現,並且我們希望在我們進入併爲這些聲明生成節點之前將一組映射推送到堆棧上。下面的代碼段如何工作以生成AST?

compound_statement : {pushScope();} statement_list {popScope();} 

那麼,這是我的問題。這個怎麼用?這段代碼何時執行?當解析器減少了這個產量時它會被執行嗎?哪一部分發生?我應該去上班時間找出答案嗎?

回答

1

你的問題是關於構建AST節點的問題,但是你的解釋的主體是關於符號表的。這些想法是不一樣的! AST代表程序的結構。符號表代表關於哪些名稱在哪裏可見以及它們具有哪些類型的推論。

在您的符號表焦點之後,當您「輸入」一個塊並在「退出」時彈出它的概念在概念上是正確的,因爲它抽象地實現了每個塊的新範圍。

我不認爲你可以讓YACC做你說的話,因爲我不確定你可以在語法規則中的任何點附加語義動作。我相信你只能對整個規則附加行動,而且只有當規則被認可時(「減少」),行動纔會運行。所以,如果你真的想這樣做,你會想要彎曲語法來創建插入語義操作的機會。您可以通過重寫你的規則做到這一點(以下你的風格,我不認爲這實際上是有效的YACC語法):

compound_statement : block_start statement_list block_end ; 
    block_start = '{' pushScope() ; 
    block_end = '}' popScope(); 

我加入行動阻止開始和結束對稱的,但你可以多一點嗯,簡約(壞笑):

compound_statement : block_start statement_list '}' popScope() ; 
    block_start = '{' pushScope() ; 

真正的祕密在這裏被創造的減少/語義動作執行的機會,你輸入塊後,通過添加子規則的原始規則。我經常用空的規則做這件事:

compound_statement : '{' compound_statement_sub_rule block_start statement_list '}' popScope() ; 
    compound_statement_sub_rule = pushScope() ; 

已經顯示瞭如何做到這一點,我不認爲你想要這樣做。你正在做的是在解析過程中糾纏語義。如果沿着這條路走下去,你會發現自己用複雜的動作來修飾其餘的語法,以創建/查找標識符。通常使用語義操作來簡單地構建語法樹,然後在解析完成後,通過遍歷語法樹來實現符號表結構/標識符查找。

我會去辦公時間,問你想的問題,無論你認爲他們是否愚蠢。它會很好的回報。

+0

-1手動製作這樣的空規則毫無意義,因爲如果你願意,yacc會爲你做所有重要的事情。另外,語法指導翻譯(Aho的書)的要點是避免創建一個分析樹並在單獨的遍中遍歷它的開銷,所以如果這真的是Aho的類,那麼你可能不想那麼做。 。 – 2011-04-13 17:21:29

+0

@Chris Dodd:那你是說yacc會爲你插入虛擬規則和語義動作?好。我見過的大多數LALR解析器生成器都沒有(它很少見,額外的工具看起來沒有必要)。關於「語法指導翻譯」,你是對的,如果這就是他們所做的事情,他們必須把所有的東西編織在一起。一個合理的人將解釋OP的問題陳述「我們正在考慮下面的代碼來生成我們的AST」,因爲它表示他們沒有進行語法指導翻譯。 「Aho的書」也不完全是關於語法指導的翻譯。 – 2011-04-13 17:38:17

0

當你將一個動作粘貼到yacc中的規則的「中間」時,它實際上爲該動作創建一個新的隱藏的非終端,並在隱藏的非終端減少時執行該規則。所以,你的規則:

compound_statement : {pushScope();} statement_list {popScope();} ; 

等同放着清單:

compound_statement : hidden_rule statement_list {popScope();} ; 
hidden_rule : {pushScope();} ; 

與另外那YACC將適當修改$ N引用的行動,使它們指向正確的事。

所以pushScope將在hidden_rule的同時減少執行popScope所有語句被降低後執行(這是在statement_list任何聲明下降之前),所以這實際上將做的正是你想要的。

+0

nit:規則寫入的方式,無論是否遇到statement_list,pushScope都會發生。這肯定不是OP想要的;他需要確保已經處理了一個聲明列表(我猜他的意思是「塊」)的開始,並且沒有其他減少。我的回答包括必要的'{'...'}'標記來確保這一點,儘管我的Yacc語法可能稍微偏離了。 – 2011-04-13 17:49:01