編譯原理二義性
『壹』 如何消除二義性 編譯原理
1、需要在語法設計時就要考慮了,即使是C/C++也存在二義性、不確定性的語法,對於這種情況,各編譯器考慮的不同的方案,主要還是看你如何進行文法分析,可以選一種方便分析的一種去做。
2、要判斷二義性的存在,可以嘗試使用不同的優先順序解釋
假如解釋出現歧義,那麼一定存在二義性的語法(如經典的++運算)
3、要消除二義性,最簡單可行的就是定義優先順序,不過不一定適合所有情況。
『貳』 編譯原理 正則語言 二義文法 急~
這個沒有一個好老師,自己咬文嚼字看懂是很累的
二義性文法
【定義】 若文法中存在這樣的句型,它具有兩棵不同的語法樹,則稱該文法是二義性文法。
二義性文法會引起歧義,應盡量避免之!
G(E):E -> E+E | E*E | (E) | i
這兩種展開
E E
E + E E * E
i E * E E + E i
i i i i
都可以表示i+i*i
所以;文法具有二義性。
『叄』 編譯原理文法定型規則
編譯原理中的文法定型規則是指將任意上下文無關文法(Context-Free Grammar, CFG)轉化為某個特定形式的上下文無關文法的規則。這個特定形式的上下文無關文法通常是Chomsky範式或Greibach範式。
以下是文法定型規則的具體步驟:
1. 消除文法中的ε產生式(epsilon-proction),即產生空串的產生式。
2. 消除文法中的單一產生式(unit-proction),即右側只有一個非終結符的產生式。
3. 消除文法中的左遞歸產生式(left-recursive proction)。
4. 將文法轉化為無二義性的文法。
上述步驟的具體實現方法如下:
1. 消除文法中的ε產生式:
1. 對於所有含有ε產生式的非終結符,將其ε產生式刪除。
2. 對於所有產生式右側含有已刪除非終結符的產生式,將其右側的已刪除非終結符替換為ε。
3. 重復執行上述步驟,直到所有含有ε的產生式都被消除為止。
2. 消除文法中的單一產生式:
1. 對於所有單一產生式A → B,將其刪除。
2. 對於所有產生式右側含有被刪除產生式的非終結符的產生式,將其替換為被刪除產生式的右側符號B。
3. 重復執行上述步驟,直到所有單一產生式都被消除為止。
3. 消除文法中的左遞歸產生式:
1. 對於每個非終結符A,將所有形如A → Aα的產生式改為A → β1A'、A' → β2A' | ε的形式。
2. 其中,β1是所有右側不含有A的A產生式的右側符號串,β2是所有右側含有A的A產生式的右側符號串,α是所有產生式右側不含有A的符號串。
3. 重復執行上述步驟,直到所有左遞歸產生式都被消除為止。
4. 將文法轉化為無二義性的文法:
1. 消除文法中的二義性產生式,即產生式右側存在兩個或以上的不同符號串。
2. 引入新的非終結符,將二義性產生式拆分為多個不同的產生式。
3. 對於所有產生式右側含有多個符號的產生式,使用括弧或其他符號進行明確區分。
4. 重復執行上述步驟,直到文法不存在二義性為止。
以上是文法定型規則的具體步驟和實現方法。通過執行這些步驟,可以將任意上下文無關文法轉化為某個特定形式的上下文無關文法,從而方便進行語法分析和編譯。
『肆』 編譯原理筆記9:語法分析樹、語法樹、二義性的消除
語法分析樹和語法樹不是一種東西 。習慣上,我們把前者叫做「具體語法樹」,其能夠體現推導的過程;後者叫做「抽象語法樹」,其不體現過程,只關心最後的結果。
語法分析樹是語言推導過程的圖形化表示方法。這種表示方法反映了語言的實質以及語言的推導過程。
定義:對於 CFG G 的句型,分析樹被定義為具有下述性質的一棵樹:
推導,有最左推導和最右推導,這兩種推導方式在推導過程中的分析樹可能不同,但因最終得到的句子是相同的,所以最終的分析樹是一樣的。
分析樹能反映句型的推導過程,也能反映句型的結構。然而實際上,我們往往不關心推導的過程,而只關心推導的結果。因此,我們要對 分析樹 進行改造,得到 語法樹 。語法樹中全是終結符,沒有非終結符。而且語法樹中沒有括弧
定義:
說白了,語法樹這玩意,就一句話: 葉子全是操作數,內部全是操作符 ,樹里沒有非終結符也不能有括弧。
語法樹要表達的東西,是操作符(運算)作用於操作數(運算對象)
舉倆例子吧:
【例】: -(id+id) 的語法樹:
【例】:-id+id 的語法樹:
顯然,我們從上面這兩個語法樹中,直接就能觀察出來它們的運算順序。
【例】:句型 if C then s1 else s2
二義性問題:一個句子可能對應多於一棵語法樹。
【例】: 設文法 G: E → E+E | E*E | (E) | -E | id
則,句子 id+id*id、id+id+id 可能的分析樹有:
在該例中,雖然 id+id+id 的 「+」 的結合性無論左右都不會影響結果。但萬一,萬一「+」的含義變成了「減法」,那麼左結合和右結合就會引起很大的問題了。
我們在這里講的「二義性」的「義」並非語義——我們現在在學習的內容是「語法分析器」,尚未到需要研究語言背後含義的階段。
我們現在講的「二義性」指的是一個句子對應多種分析樹。
二義性的體現,是文法對同一句子有不止一棵分析樹。這種問題由【句子產生過程中的某些推導有多於一種選擇】引起。懸空 else 問題就可以很好地體現這種【超過一種選擇】帶來的二義性問題,示例如下。
看下面這么個例子。。
(其實,我感覺這個其實比較像是「說話大喘氣」帶來的理解歧義問題。。。)上面的產生式中並沒體現出來該咋算分一塊,所以兩種完全不同的句子結構都是合法的。
二義性問題是有救的,大概有以下這三種辦法:
這些辦法的核心,其實都是將優先順序和結合性說明白。
核心:把優先順序和結合性說明白
既然要說明白,那就不能讓一個非終結符可以直接在當次推導中能推出會帶來優先順序和結合性歧義的東西。(對分析樹的一個內部節點,不會有出現在其下面的分支是相同的非終結符的情況。如果有得選,那就有得歧義了。沒得選才能確定地一路走到黑)
改寫為非二義文法的二義文法大概有下面這幾個特點:
改寫的關鍵步驟:
【例】改寫下面的二義文法為非二義文法。圖右側是要達成的優先順序和結合性
改寫的核心其實就兩句話:
所以能夠得到非終結符與運算的對應關系(因為不同的運算有不同的優先順序,我們想要引入多個優先順序就要引入多個新的非終結符。這樣每個非終結符就可以負責一個優先順序的運算符號,也就是說新的非終結符是與運算有關系的了。因此這里搞出來了「對應關系」四個字)如下:
優先順序由低到高分別是 +、 、-,而距離開始符號越近,優先順序越低。因此在這里的排序也可以+ -順序。每個符號對應一層的非終結符。根據所需要的結合性,則可確定是左遞歸還是右遞歸,以確定新的產生式長什麼樣子
【例】:規定優先順序和結合性,寫出改寫的非二義文法
我們已經掌握了一種叫做【改寫】的工具,能讓我們消除二義性。接下來我們就要用這個工具來嘗試搞搞懸空 else 問題!
懸空 else 問題出現的原因是 then 數量多於 else,讓 else 有多個可以結合的 then。在二義文法中,由於選哪兩個 then、else 配對都可以,故會引起出現二義的情況。在這里,我們規定 else 右結合,即與左邊最靠近的 then 結合。
為改寫此文法,可以將 S 分為完全匹配(MS)和不完全匹配(UMS)兩類。在 MS 中體現 then、else 個數相等即匹配且右結合;在UMS 中 then、else 不匹配,體現 else 右結合。
【例】:用改寫後的文法寫一個條件語句
經過檢查,無法再根據文法寫出其他分析樹,故已經消除了二義性
雖然二義文法會導致二義性,但是其並非一無是處。其有兩個顯著的優點:
在 Yacc 中,我們可以直接指定優先順序、結合性而無需自己重寫文法。
left 表示左結合,right 表示右結合。越往下的算符優先順序越高。
嗯就這么簡單。。。
我們其實可以把語言本身定義成沒有優先順序和結合性的。。然後所有的優先、結合都交由括弧進行控制,哪個先算就加括弧。把一個過程的結束用明確的標志標記出來。
比如在 Ada 中:
在 Pascal 中,給表達式加括弧:
『伍』 編譯原理中文法二義性問題
二義性文法
【定義】 若文法中存在這樣的句型,它具有兩棵不同的語法樹,則稱該文法是二義性文法。
二義性文法會引起歧義,應盡量避免之!
E E
E + E E * E
i E * E E + E i
i i i i
都可以表示i+i*i
所以G(E):E -> E+E | E*E | (E) | i ;文法具有二義性。
文法二義性的消除:
【方法1】不改變文法的原有規則,加進一些非形式規定。
加進運算符的優先順序和結合規則對G(E),規定*優於+,*和+服從左結合
【方法2】構造一個等價的無二義性文法,將排除 二義性的規則合並到文法中
G(E) -> G´(E) : E -> E+T | T T -> T*F | F F -> (E) | i ;
『陸』 如何由文法推導語法樹(編譯原理)
語法樹是一種用於表示句型生成過程的結構,特別是在上下文無關文法中非常有用。它能夠幫助我們理解句型是如何通過文法規則逐步構建起來的。在編譯原理課程中,構建語法樹是語法分析的一項重要任務。為了完成這項任務,我們通常需要應用各種語法分析方法,這些方法在學習過程中會逐漸掌握。
在學習這些方法之前,我們只能依賴直覺和經驗,通過猜測和拼湊的方式嘗試構建句型的語法樹。由於這種方法依賴於經驗和直覺,因此適用於較為簡單的句型。通過反復練習,可以逐漸積累一些構建語法樹的技巧,這些技巧主要是自頂向下的語法分析中的基本原則。
值得注意的是,對於同一文法,可能存在多個結構不同的語法樹。如果一個文法能夠產生多個不同的語法樹,這個文法就被稱為二義性文法。二義性文法的存在使得句型的解析變得復雜,因為同一個句型可能存在多種解釋。
然而,如果文法是非二義性的,那麼對於任何給定的句型,其對應的語法樹都是唯一的。這意味著,只要遵循文法中的規則,我們就能確定句型的正確結構。這種特性對於編譯器的設計和實現非常重要,因為它確保了解析過程的確定性和唯一性。
總之,理解如何構建語法樹以及文法的二義性問題,對於深入學習編譯原理至關重要。通過掌握各種語法分析方法,我們可以更准確地解析句型,從而為後續的編譯工作奠定堅實的基礎。
『柒』 【編譯原理】第二章:語言和文法
上述文法 表示,該文法由終結符集合 ,非終結符集合 ,產生式集合 ,以及開始符號 構成。
而產生式 表示,一個表達式(Expression) ,可以由一個標識符(Identifier) 、或者兩個表達式由加號 或乘號 連接、或者另一個表達式用括弧包裹( )構成。
約定 :在不引起歧義的情況下,可以只寫產生式。如以上文法可以簡寫為:
產生式
可以簡寫為:
如上例中,
可以簡寫為:
給定文法 ,如果有 ,那麼可以將符號串 重寫 為 ,記作 ,這個過程稱為 推導 。
如上例中, 可以推導出 或 或 等等。
如果 ,
可以記作 ,則稱為 經過n步推導出 ,記作 。
推導的反過程稱為 歸約 。
如果 ,則稱 是 的一個 句型(sentential form )。
由文法 的開始符號 推導出的所有句子構成的集合稱為 文法G生成的語言 ,記作 。
即:
例
文法
表示什麼呢?
代表小寫字母;
代表數字;
表示若干個字母和數字構成的字元串;
說明 是一個字母、或者是字母開頭的字元串。
那麼這個文法表示的即是,以字母開頭的、非空的字元串,即標識符的構成方式。
並、連接、冪、克林閉包、正閉包。
如上例表示為:
中必須包含一個 非終結符 。
產生式一般形式:
即上式中只有當上下文滿足 與 時,才能進行從 到 的推導。
上下文有關文法不包含空產生式( )。
產生式的一般形式:
即產生式左邊都是非終結符。
右線性文法 :
左線性文法 :
以上都成為正則文法。
即產生式的右側只能有一個終結符,且所有終結符只能在同一側。
例:(右線性文法)
以上文法滿足右線性文法。
以上文法生成一個以字母開頭的字母數字串(標識符)。
以上文法等價於 上下文無關文法 :
正則文法能描述程序設計語言中的多數單詞。
正則文法能描述程序設計語言中的多數單詞,但不能表示句子構造,所以用到最多的是CFG。
根節點 表示文法開始符號S;
內部節點 表示對產生式 的應用;該節點的標號是產生式左部,子節點從左到右表示了產生式的右部;
葉節點 (又稱邊緣)既可以是非終結符也可以是終結符。
給定一個句型,其分析樹的每一棵子樹的邊緣稱為該句型的一個 短語 。
如果子樹高度為2,那麼這棵子樹的邊緣稱為該句型的一個 直接短語 。
直接短語一定是某產生式的右部,但反之不一定。
如果一個文法可以為某個句子生成 多棵分析樹 ,則稱這個文法是 二義性的 。
二義性原因:多個if只有一個else;
消岐規則:每個else只與最近的if匹配。
『捌』 【編譯原理】自頂向下LL(1)分析中,消除左遞歸和提取左因子的目的是什麼
提取左因子---避免程序回溯;
消除左遞歸---消除死循環。