編譯原理第四章語法分析by SixInNight


構造預測分析程序、狀態轉換圖、預測分析表


例1 給出 文法 G1

  • E → E + T | T
  • T → T * F | F
  • F → ( E ) | id
  1. 首先,改寫文法,消除左遞歸(只有LL(1)文法需要消除左遞歸),得到 文法 G1
  • E → T E
  • E → + T E | ε
  • T → F T
  • T * F T | ε
  • F → ( E ) | id
  1. 構造狀態轉換圖
  2. 狀態轉換圖的化簡
  3. 預測分析程序
  • E 的過程:
void procE(void) {
	procT();
	if (char == '+') {
		forward pointer;
		procE();
	}
}
  • T 的過程:
void procT(void) {
	procF();
	if (char == '*') {
		forward pointer;
		procT();
	}
}
  • F 的過程:
void procF(void) {
	if (char == '(') {
		forward pointer;
		procE();
		if (char == ')')
			forward pointer;
		else error();
	};
	else if (char == 'id')
			forward pointer;
		else error();
}
  1. 預測分析表
  • 對於 E → T E :由於 FIRST(T E ) = FIRST(T) = { (,id },故應把 E → T E 放入表項 M [ E,( ] 和 M [ E,id ] 中
  • 對於 E → + T E :由於 FIRST(+ T E ) = { + },故應把 E → + T E 放入表項 M [ E ,+ ] 中
  • 對於 E → ε:由於FOLLOW(E ) = {$,) },故應把 E → ε 放入表項 M [ E ,$] 和 M [ E ,) ] 中
  • 依次檢查其餘產生式,得到表 M



構造FIRST集合、FOLLOW集合、LL(1)文法


  • FIRST集合
  • FOLLOW集合
  • LL(1)文法



規範歸約、LR分析程序的工作過程、LR(0)項目


  • 規範歸約(最左歸約)過程是最右推導(規範推導)的逆過程,由最右推導得到的右句型也稱爲規範句型
  • 例2 具有如下產生式集合的 文法 G2LR 分析表 如圖所示,利用該分析表分析輸入符號串 id + id * id
    (1)E → E + T (2)E → T (3)T → T * F
    (4)T → F (5)F → ( E ) (6)F → id

    Si 中的 S 表示“移進”,即把當前輸入符號和狀態 i 壓入棧,i 成爲新的棧頂;Rj 中的 R 表示“歸約”,即用第 j 個產生式進行歸約;ACC 表示“接受”;空白表示“出錯”)
  1. 分析動作

  2. 常用的 LR 分析表有 SLR(1) 分析表、LR(1) 分析表、LALR(1) 分析表
  • 產生式 A → X Y Z 對應有 4 個 LR(0) 項目
    (1)A → • X Y Z
    (2)A → X • Y Z
    (3)A → X Y • Z
    (4)A → X Y Z •
    • 歸約項目:圓點在產生式最右端的 LR(0) 項目,如 A → X Y Z •
    • 接受項目:對文法開始符號的歸約項目,如 S → S •
    • 移進項目:圓點後第一個符號爲終結符號的 LR(0) 項目,如 A → α • a β
    • 待約項目:圓點後第一個符號爲非終結符號的 LR(0) 項目,如 A → α • B β


構造SLR(1)分析表


例3 構造如下 文法 G3LR(0) 項目集規範族識別所有活前綴的 DFA,並構造其 SLR(1) 分析表

  • S → a A | b B
  • A → c A | d
  • B → c B | d
  1. 構造文法 G3拓廣文法 G3
  • S → S
  • S → a A | b B
  • A → c A | d
  • B → c B | d
  1. 首先,構造活前綴 ε 的 LR(0) 有效項目集,記爲 I0
    I0 = closure( { S → • S } ) = { S → • S,S → • a A,S → • b B }
    現在,從 I0 出發構造其他活前綴的 LR(0) 有效項目集
    I0 出發的轉移有:
    I1 = go( I0,S ) = closure( { S → S • } ) = { S → S • }
    I2 = go( I0,a ) = closure( { S → a • A } ) = { S → a • A,A → • c A,A → • d }
    I3 = go( I0,b ) = closure( { S → b • B } ) = { S → b • B,B → • c B,B → • d }
    由於 I0 是活前綴 ε 的 LR(0) 有效項目集,所以 I1、I2、I3 分別是活前綴 S、a、b 的 LR(0) 有效項目集;由於 I1 中唯一的元素爲接受項目 S → S •,故沒有從 I1 出發的轉移
    I2 出發的轉移有:
    I4 = go( I2,A ) = closure( { S → a A • } ) = { S → a A • }
    I5 = go( I2,c ) = closure( { A → c • A } ) = { A → c • A,A → • c A,A → • d }
    I6 = go( I2,d ) = closure( { A → d • } ) = { A → d • }
    I4、I5、I6 分別是活前綴 aA、ac、ad 的 LR(0) 有效項目集
    I3 出發的 • • • • • •
    至此,不再有新的有效項目集出現,上面構造的 LR(0) 有效項目集 I0、I1、I2、I3、• • • 、I11 組成的 集合 C = { I0、I1、• • • 、I11 } 就是文法 G3 的 LR(0) 項目集規範族
  2. 識別文法 G3 的所有活前綴的 DFA
  3. 構造 SLR(1) 分析表,並判斷該文法是否爲 SLR(1) 文法:
    考察 I0 = { S → • S,S → • a A,S → • b B }
    對項目 S → • S,有 go( I0,S ) = I1,所以置 goto[ 0,S ] = 1
    對項目 S → • a A,有 go( I0,a ) = I2,所以置 action[ 0,a ] = S2
    對項目 S → • b B,有 go( I0,b ) = I3,所以置 action[ 0,b ] = S3
    考察 I1 = { S → S • }
    項目 S → S • 是接受項目,所以置 action[ 1,$] = ACC
    考察 I2 = { S → a • A,A → • c A,A → • d }
    對項目 S → a • A,有 go( I2,A ) = I4,所以置 goto[ 2,A ] = 4
    對項目 A → • c A,有 go( I2,c ) = I5,所以置 goto[ 2,c ] = S5
    對項目 A → • d,有 go( I2,d ) = I6,所以置 goto[ 2,d ] = S6
    考察 I3 = { S → b • B,B → • c B,B → • d }
    對項目 S → b • B,有 go( I3,B ) = I7,所以置 goto[ 3,B ] = 7
    對項目 B → • c B,有 go( I3,c ) = I8,所以置 goto[ 3,c ] = S8
    對項目 B → • d,有 go( I3,d ) = I9,所以置 goto[ 3,d ] = S9
    考察 I4 = { S → a A • }(假設產生式 S → a A 的編號爲 1)
    項目 S → a A • 是歸約項目,因爲 FOLLOW( S ) = {$},所以置 action[ 4,$] = R1
    考察 I5 • • • • • •
    最終可得到 SLR(1) 分析表 如下


    由於表中不存在任何衝突,所以 文法 G3 是 SLR(1) 文法


LR(0)文法、SLR(1)文法




構造LR(1)分析表


  • 例4 構造如下 文法 G4LR(1) 項目集規範族識別所有活前綴的 DFA,並構造其 LR(1)分析表

    • S → C C
    • C → c C | d
    1. 構造文法 G4拓廣文法 G4
      (0)S → S
      (1)S → C C
      (2)C → c C
      (3)C → d
    2. 構造其 LR(1) 項目集規範族識別所有活前綴的 DFA
    3. 構造 LR(1)分析表
  • 例5 構造如下 文法 G5LR(1) 項目集規範族識別所有活前綴的 DFA,並構造其 LR(1)分析表

    • S → L = R
    • S → R
    • L → * R
    • L → id
    • R → L
    1. 拓廣文法得到 G5
      (0)S → S
      (1)S → L = R
      (2)S → R
      (3)L → * R
      (4)L → id
      (5)R → L
    2. 構造 文法 G5LR(1) 項目集規範族識別所有活前綴的 DFA
    3. 構造 LR(1)分析表(由於表中不含有多重定義的表項,所以該文法是 LR(1) 文法):



LR(1)項目集特徵


  • 同心集
    如果 兩個 LR(1) 項目集 去掉向前看符號之後是相同的,即它們具有相同的心(core),則稱這兩個項目集是同心集
    LR(1) 項目集 的心就是一個 LR(0) 項目集
  • 項目集的核
    除初態項目集外,一個項目集的核(kernel)是由該項目集中那些圓點不在最左邊的項目組成的集合
    LR(1) 初態項目集 的核中有且只有項目 [ S → • S,$]


構造LALR(1)分析表


  • 思想:
    (1)合併 LR(1) 項目集規範族 中的 同心集(,以減少分析表的狀態數)
    (2)用 項目集的核 代替 項目集(,以減少項目集所需的存儲空間)
    :同心集合並後的項目集中 只可能 出現 歸約—歸約衝突絕不可能 出現 移進—歸約衝突
  • 步驟
    (1)構造 LR(1) 項目集規範族,如果 不存在衝突,說明該文法是 LR(1) 文法
    (2)檢查 LR(1) 項目集規範族中有沒有 同心集,若沒有,則該 LR(1) 分析表 就是 LALR(1) 分析表,若有,則 合併同心集
    (3)檢查合併同心集後的項目集規範族是否有 歸約—歸約衝突,若有,則 不存在 LALR(1) 分析表,若沒有,則根據它可以 構造文法的 LALR(1) 分析表
  • 例6 構造 文法 G4LALR(1) 分析表
  1. 例4 中,已經構造出該文法的 LR(1) 項目集規範族,也給出了 識別所有活前綴的 DFA,並且構造出了該文法的 LR(1) 分析表,說明 文法 G4 是 LR(1) 文法
  2. 構造 LALR(1) 分析表
    (i) 其 LR(1) 項目集規範族 有三對 同心集 可以合併,即

    (ii) 計算 轉移函數 go
    先看 go( I36,C ),存在 go( I3,C ) = I8、go( I6,C ) = I9,因 I8、I9 都是 I89 的一部分,故有 go( I36,C ) = I89
    再看 go( I2,c ),由於原來的 LR(1) 項目集規範族 中存在 go( I2,c ) = I6,因 I6 都是 I36 的一部分,因此 go( I2,c ) = I36(action[ 2,c ] = S36)
    (iii) 作出分析表,可以看出該表不存在衝突的表項,因此 文法 G4 是 LALR(1) 文法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章