怎麼提取左公共因子編譯原理
⑴ 因子分析中,提取公共因子的一般原則是
在因子分析鐵器供應供因此的原則,就是先要找出兩個人的最大公因數,提取所有項包含的共同因子,那麼這個最大的公因數就是分子提取的公共因子。
因子分析是指研究從變數群中提取共性因子的統計技術。因子分析可在許多變數中找出隱藏的具有代表性的因子。將相同本質的變數歸入一個因子,可減少變數的數目,還可檢驗變數間關系的假設。
因子分析的方法有兩類。一是探索性因子分析,不事先假定因子與測度項之間的關系,而讓數據「自己說話」。另一類是驗證性因子分析,假定因子與測度項的關系是部分知道的,即哪個測度項對應於哪個因子,雖然我們尚且不知道具體的系數。
因子分析中的隱性變數
因子分析的主要目的是用來描述隱藏在一組測量到的變數中的一些更基本的,但又無法直接測量到的隱性變數 。
比如,如果要測量學生的學習積極性,課堂中的積極參與,作業完成情況,以及課外閱讀時間可以用來反應積極性。而學習成績可以用期中,期末成績來反應。
這些變數無法直接測量。可以直接測量的可能只是它所反映的一個表徵,或者是它的一部分。隱性變數是因,而表徵是果,比如學習積極性是課堂參與程度 (表徵測度)的一個主要決定因素。
⑵ 編譯原理-LL1文法詳細講解
我們知道2型文法( CFG ),它的每個產生式類型都是 α→β ,其中 α ∈ VN , β ∈ (VN∪VT)*。
例如, 一個表達式的文法:
最終推導出 id + (id + id) 的句子,那麼它的推導過程就會構成一顆樹,即 CFG 分析樹:
從分析樹可以看出,我們從文法開始符號起,不斷地利用產生式的右部替換產生式左部的非終結符,最終推導出我們想要的句子。這種方式我們稱為自頂向下分析法。
從文法開始符號起,不斷用非終結符的候選式(即產生式)替換當前句型中的非終結符,最終得到相應的句子。
在每一步推導過程中,我們需要做兩個選擇:
因為一個句型中,可能存在多個非終結符,我們就不確定選擇那一個非終結符進行替換。
對於這種情況,我們就需要做強制規定,每次都選擇句型中第一個非終結符進行替換(或者每次都選擇句型中最後一個非終結符進行替換)。
自頂向下的語法分析採用最左推導方式,即總是選擇每個句型的最左非終結符進行替換。
最終的結果是要推導出一個特定句子(例如 id + (id + id) )。
我們將特定句子看成一個輸入字元串,而每一個非終結符對應一個處理方法,這個處理方法用來匹配輸入字元串的部分,演算法如下:
方法解析:
這種方式稱為遞歸下降分析( Recursive-Descent Parsing ):
當選擇的候選式不正確,就需要回溯( backtracking ),重新選擇候選式,進行下一次嘗試匹配。因為要不斷的回溯,導致分析效率比較低。
這種方式叫做預測分析( Predictive Parsing ):
要實現預測分析,我們必須保證從文法開始符號起,每一個推導過程中,當前句型最左非終結符 A 對於當前輸入字元 a ,只能得到唯一的 A 候選式。
根據上面的解決方法,我們首先想到,如果非終結符 A 的候選式只有一個以終結符 a 開頭候選式不就行了么。
進而我們可以得出,如果一個非終結符 A ,它的候選式都是以終結符開頭,並且這些終結符都各不相同,那麼本身就符合預測分析了。
這就是S_文法,滿足下面兩個條件:
例子:
這就是一個典型的S_文法,它的每一個非終結符遇到任一終結符得到候選式是確定的。如 S -> aA | bAB , 只有遇到終結符 a 和 b 的時候,才能返回 S 的候選式,遇到其他終結符時,直接報錯,匹配不成功。
雖然S_文法可以實現預測分析,但是從它的定義上看,S_文法不支持空產生式(ε產生式),極大地限制了它的應用。
什麼是空產生式(ε產生式)?
例子
這里 A 有了空產生式,那麼 S 的產生式組 S -> aA | bAB ,就可以是 a | bB ,這樣 a , bb , bc 就變成這個文法 G 的新句子了。
根據預測分析的定義,非終結符對於任一終結符得到的產生式是確定的,要麼能獲取唯一的產生式,要麼不匹配直接報錯。
那麼空產生式何時被選擇呢?
由此可以引入非終結符 A 的後繼符號集的概念:
定義: 由文法 G 推導出來的所有句型,可以出現在非終結符 A 後邊的終結符 a 的集合,就是這個非終結符 A 的後繼符號集,記為 FOLLOW(A) 。
因此對於 A -> ε 空產生式,只要遇到非終結符 A 的後繼符號集中的字元,可以選擇這個空產生式。
那麼對於 A -> a 這樣的產生式,只要遇到終結符 a 就可以選擇了。
由此我們引入的產生式可選集概念:
定義: 在進行推導時,選用非終結符 A 一個產生式 A→β 對應的輸入符號的集合,記為 SELECT(A→β)
因為預測分析要求非終結符 A 對於輸入字元 a ,只能得到唯一的 A 候選式。
那麼對於一個文法 G 的所有產生式組,要求有相同左部的產生式,它們的可選集不相交。
在 S_文法基礎上,我們允許有空產生式,但是要做限制:
將上面例子中的文法改造:
但是q_文法的產生式不能是非終結符打頭,這就限制了其應用,因此引入LL(1)文法。
LL(1)文法允許產生式的右部首字元是非終結符,那麼怎麼得到這個產生式可選集。
我們知道對於產生式:
定義: 給定一個文法符號串 α , α 的 串首終結符集 FIRST(α) 被定義為可以從 α 推導出的所有串首終結符構成的集合。
定義已經了解清楚了,那麼該如何求呢?
例如一個文法符號串 BCDe , 其中 B C D 都是非終結符, e 是終結符。
因此對於一個文法符號串 X1X2 … Xn ,求解 串首終結符集 FIRST(X1X2 … Xn) 演算法:
但是這里有一個關鍵點,如何求非終結符的串首終結符集?
因此對於一個非終結符 A , 求解 串首終結符集 FIRST(A) 演算法:
這里大家可能有個疑惑,怎麼能將 FIRST(Bβ) 添加到 FIRST(A) 中,如果問文法符號串 Bβ 中包含非終結符 A ,就產生了循環調用的情況,該怎麼辦?
對於 串首終結符集 ,我想大家疑惑的點就是,串首終結符集到底是針對 文法符號串 的,還是針對 非終結符 的,這個容易弄混。
其實我們應該知道, 非終結符 本身就屬於一個特殊的 文法符號串 。
而求解 文法符號串 的串首終結符集,其實就是要知道文法符號串中每個字元的串首終結符集:
上面章節我們知道了,對於非終結符 A 的 後繼符號集 :
就是由文法 G 推導出來的所有句型,可以出現在非終結符 A 後邊的終結符的集合,記為 FOLLOW(A) 。
仔細想一下,什麼樣的終結符可以出現在非終結符 A 後面,應該是在產生式中就位於 A 後面的終結符。例如 S -> Aa ,那麼終結符 a 肯定屬於 FOLLOW(A) 。
因此求非終結符 A 的 後繼符號集 演算法:
如果非終結符 A 是產生式結尾,那麼說明這個產生式左部非終結符後面能出現的終結符,也都可以出現在非終結符 A 後面。
我們可以求出 LL(1) 文法中每個產生式可選集:
根據產生式可選集,我們可以構建一個預測分析表,表中的每一行都是一個非終結符,表中的每一列都是一個終結符,包括結束符號 $ ,而表中的值就是產生式。
這樣進行語法推導的時候,非終結符遇到當前輸入字元,就可以從預測分析表中獲取對應的產生式了。
有了預測分析表,我們就可以進行預測分析了,具體流程:
可以這么理解:
我們知道要實現預測分析,要求相同左部的產生式,它們的可選集是不相交。
但是有的文法結構不符合這個要求,要進行改造。
如果相同左部的多個產生式有共同前綴,那麼它們的可選集必然相交。
例如:
那麼如何進行改造呢?
其實很簡單,進行如下轉換:
如此文法的相同左部的產生式,它們的可選集是不相交,符合現預測分析。
這種改造方法稱為 提取公因子演算法 。
當我們自頂向下的語法分析時,就需要採用最左推導方式。
而這個時候,如果產生式左部和產生式右部首字元一樣(即A→Aα),那麼推導就可能陷入無限循環。
例如:
因此對於:
文法中不能包含這兩種形式,不然最左推導就沒辦法進行。
例如:
它能夠推導出如下:
你會驚奇的發現,它能推導出 b 和 (a)* (即由 0 個 a 或者無數個 a 生成的文法符號串)。其實就可以改造成:
因此消除 直接左遞歸 演算法的一般形式:
例如:
消除間接左遞歸的方法就是直接帶入消除,即
消除間接左遞歸演算法:
這個演算法看起來描述很多,其實理解起來很簡單:
思考 : 我們通過 Ai -> Ajβ 來判斷是不是間接左遞歸,那如果有產生式 Ai -> BAjβ 且 B -> ε ,那麼它是不是間接左遞歸呢?
間接地我們可以推出如果一個產生式 Ai -> αAjβ 且 FIRST(α) 包括空串ε,那麼這個產生式是不是間接左遞歸。
⑶ 消除左遞歸及提取左公因子
如果一個文法中有一個非終禪扮結符號A使得對某個串α存在一個推導A=》Aα,那麼這個文法就是左遞歸的。遞歸分為立即左遞歸和非立即左遞歸。立即左遞歸單步即可看出來,非立即左遞歸
舉個例子:
消除立即左遞歸只需要遵循以下規律進行轉換就ok。
立即左遞歸:
非立即左遞歸:
和數學中的公因子含義相同,就是公共的因子,而左公因子就是最左邊的公因子。
例如:
可以看出前n項擁有一個共同的左公因念信子:a,所以仔襲輪可以把他提取出來。
so easy啦
S → aB1|aB2|aB3|aB4|...|aBn|y
可以看出前n項擁有一個共同的左公因子:a,所以可以把他提取出來。
提取規則
so easy啦
S → aS'|y
S'→ B1|B2|B3|...|Bn
⑷ 編譯原理 無法提取左公因子,都有公共前綴
就是有公共前綴才可以提取左公因子啊……
bool -> expr expr'
expr' -> e
| < expr
| <= expr
| > expr
| >= expr
後面幾個比較操作符如果還算公因子的話,還可以繼續提:
用expr1 代替 < expr 和 <= expr,刪除這兩個右部,添加右部 <expr1,添加產生式expr1-> expr|= expr
用expr2 代替 > expr 和 >= expr,刪除這兩個右部,添加右部 >expr2,添加產生式expr2-> expr|= expr
⑸ 關於LL(1)文法的編譯原理題目
判斷是不是LL(1),首先看候選式的首字元有沒有相同的,第二判斷首字元迭代進去是否會構成左遞歸。
如果首字元不相同,也沒用左遞歸就說明此文法是LL(1)
M→MaH|H
H→(M)|b(M)|b
第一個產生式中存在左遞歸:M->MaH
第二個產生式中存在首字元相同:H->b(M) ,
H->b
怎麼改呢?
對第一個產生式,消除左遞歸就是要變成右遞歸,把右邊剩下的符號提到前面:
M->aHM'
M'->aHM'
對第二個產生式,提出公共因子
H->b( (M)|ε)
=>
H->bH'
H'->(M)|ε