日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编译原理:全片知识难点总结

發(fā)布時間:2024/10/14 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编译原理:全片知识难点总结 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄

一、概念

二、詞法分析

三。自上而下分析語法——LL語法

1)消除左遞歸

? ?2) 消除回溯、提左因子? 、 FIRST集 和 FOLLOW 集

?3)預(yù)測分析法 與 FIRST集 和 FOLLOW 集的構(gòu)建。

4)預(yù)測分析法中 預(yù)測分析表M的構(gòu)建

四、自下而上的分析語法——算符優(yōu)先分析法

1)對每個非終結(jié)符構(gòu)建FIRSTVT 集 和LASTVT 集

2)構(gòu)造算符優(yōu)先關(guān)系表

五、語義分析

1)賦值語句和的簡單算數(shù)運(yùn)算表達(dá)式的翻譯

2)布爾表達(dá)式的翻譯方法

3)典型控制語句的翻譯方法

六、目標(biāo)代碼生成

1)基本塊劃分

2)寄存器選擇——寄存器的待用信息與活躍信息的確定

七、中間代碼的優(yōu)化

(1) 基于DAG圖的優(yōu)化方法?


一、概念

1)字母表、字符串、字符串和運(yùn)算

  • 字母表用 Σ 表示,是字符的非空有窮集合,字符是字母表Σ的元素
  • 字符串,是字母表Σ中字符組成的有窮序列,其長度用? ?|<字符串>|? 表示。空串用是ε表示, |ε| = 0
  • Σ* 指包括空串在內(nèi)的Σ上所有字符串的集合。稱之為字母表的閉包。
  • 字符串的方冪: 例如??? ?,指 連續(xù)n個a字符?
  • 對于集合A的正則閉包 +? ?
  • 對于集合A的閉包 * ,?

文法分類分為0型文法,1型文法,2型文法,3型文法,分別又稱為短語文法,上下文有關(guān)文法,上下文無關(guān)文法,正規(guī)文法 。

  • 0型文法,短語文法: 每個產(chǎn)生式? α ->β? 左部α中至少又一個非終結(jié)符
  • 1型文法,上下文有關(guān)文法: 在0型文法的基礎(chǔ)上,還滿足? |α|? <= |β|?
  • 2型文法: 每個產(chǎn)生式? A->β? ?,其中A 是非終結(jié)符? ,? ?β是終結(jié)符和非終結(jié)符的閉包。
  • 3型文法:每個產(chǎn)生式? A->αB? 或 A ->α 的形式,其中A和B 是非終結(jié)符,α是終結(jié)符

四元式:是?( op ,arg1,arg2,result) 形式的一個對象,其中op 表示中間代碼的操作符,result 表示 運(yùn)算結(jié)果的臨時變量。

后綴式、逆波蘭式:在抽象語法樹中的后續(xù)遍歷得到的式子。例如a+b(中序)改寫成后綴式為ab+

二、詞法分析

單詞分為關(guān)鍵字、算符、標(biāo)識符、常數(shù)、介符。詞法分析的目標(biāo)是為了將代碼分解成對應(yīng)的單詞,并對單詞打上些有意義的編碼,給后續(xù)的語法分析和語義分析使用。

單詞

編碼

單詞

編碼

單詞

編碼

單詞

編碼

end

1

or

11

21

:=

31

begin

2

program

12

22

=

32

bool

3

real

13

+

23

<=

33

do

4

then

14

-

24

<

34

else

5

true

15

*

25

<>

35

end

6

var

16

/

26

>

36

false

7

while

17

.

27

>=

37

if

8

標(biāo)識符

18

28

integer

9

整數(shù)

19

:

29

not

10

實數(shù)

20

30

對代碼進(jìn)行按行讀取,判斷每個單詞是否屬于關(guān)鍵字,或者介詞、標(biāo)識符還是標(biāo)識符等。大致方式

為:按行讀取,逐各讀取字符并將每個字符假如一個字符緩存變量中,讀取的字符如果是空格、換行、或者介詞、運(yùn)算符(對應(yīng)表格代碼是21~37)的話,則緩存變量中是一個完整的單詞。對著單詞表對單詞打上編碼,如果不存在則為標(biāo)識符..

三。自上而下分析語法——LL語法

1)消除左遞歸

? ? ? ? 對于類似的產(chǎn)生式 “ A ->Aα | β ”都可以化簡成

????????????????????????????????A ->?βA'

????????????????????????????????A' ->?αA'? |?ε

? ? ? ? 實際上對于產(chǎn)生式都可以化簡成

? ?? ? ? ? ? 和? ? ? ?

?

? ?2) 消除回溯、提左因子? 、 FIRST集 和 FOLLOW 集

? ? ? 對所有非終結(jié)符的A的每個候選是α,定義其終結(jié)首符集,FIRST

? ? ? ? ? ? ? ? ? ? ? ? ?

? ? ?對所有非終結(jié)符的A的每個候選是α,定義其后隨符號集,FOLLOW

? ? ? ? ? ? ? ? ? ? ? ? ?

?3)預(yù)測分析法 與 FIRST集 和 FOLLOW 集的構(gòu)建。

? ? ? ?統(tǒng)計每個非終結(jié)符的 FIRST? ?和FOLLOW 集 ,并構(gòu)建預(yù)測分析表。

?例如:對應(yīng)文法G[E]:

? ? ? ? ? ? ? ? ? ? ? ? E →? E? +? ?T? |? ?T

? ? ? ? ? ? ? ? ? ? ? ? T? → T * F? | F?

? ? ? ? ? ? ? ? ? ? ? ? F? →( E ) | i

現(xiàn)有輸入串? ? i? *(i + i) ,判斷其語法是否正確?

? ? ? 首先先消除左遞歸,得到新文法如下?

? ? ? ? ? ? ? ? ? ? ? ? ?E?→ T E'? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.....①

? ? ? ? ? ? ? ? ? ? ? ? E'?→ + T E' |?ε? ? ? ? ? ? ? ? ? ? ? ? ? ?.....②

? ? ? ? ? ? ? ? ? ? ? ? T? → F T'? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ....③

? ? ? ? ? ? ? ? ? ? ? ? T' →*FT' |ε? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ....④

? ? ? ? ? ? ? ? ? ? ? ? F? →( E ) | i? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.....⑤

因此,有非終結(jié)符? E, E',T, T', F.構(gòu)建FIRST集的過程為

  • ?自下而上遍歷對應(yīng)的產(chǎn)生式,把產(chǎn)生式右邊的首終結(jié)符加入到產(chǎn)生式左邊的FIRST中因此

? ? ? ? FIRST(F) = { ( , i ...}? ? ?FIRST(T')? = { * , ε ...}? ? FIRST(E’) =?{? ?+ ,?ε ....}?

  • ?對于? ? A →B....類似的文法應(yīng)該把 FIRST(B) 也加入到? FIRST(A)中因此

? FIRST(F) = { ( , i? }? ? ?FIRST(T')? = { * , ε}? ? FIRST(E‘) =?{? ?+ ,?ε}?

? FIRST(T)? ={ ( , i? }? ? FIRST (E) ={ ( , i? }?

構(gòu)建FOLLOW集的過程為:自上而下遍歷對應(yīng)的產(chǎn)生式形如? S? → ABC,

  • 把FIRST(C) / {ε}加入到FOLLOW(B)中,如果C是終結(jié)符, 那么終結(jié)符的FIRST集就是它自身,即FIRST(C) ={ C },
  • 把 FOLLOW(S)加入到 FOLLOW(C)中,如果C 可以間接推出?ε ,即ε∈ FIRST(C),那么把 FOLLOW(S)也加入到FOLLOW(B)中,
  • 往起始產(chǎn)生式的FOLLOW加入 ‘#’ 起始符。?

因此上述文法的

? ? ? ? FOLLOW (E) = {? # ,? )? }? ? ?....(第3個條件、⑤式匹配第一條件)

? ? ? ? FOLLOW(E') = FOLLOW(E)? = {? # ,? )? }? ? ? ? (①式匹配第4個條件)

? ? ? ? FOLLOW(T)? =FIRST(E')/{ε} ∪? FOLLOW(E) ={ + ,),# }? ? (②式匹配第一條件,①式匹配第二條件)

? ? ? ? 同理:

? ? ? FOLLOW (T' ) = FOLLOW(T)? =?{ + ,),# }

? ? ? FOLLOW(F) =?FIRST(T')/{ε} ∪? FOLLOW(T) ∪? FOLLOW(T')={ * , + ,),#}

4)預(yù)測分析法中 預(yù)測分析表M的構(gòu)建

  • ? ? 遍歷每個產(chǎn)生式 A ->α,對每個終結(jié)符 a? ∈ FIRST(A)? , 將 A->α 加入到 M[A,a]中,
  • ? ? 如果 ε? ∈ FIRST(A),則對任何終結(jié)符b?∈ FOLLOW(A),將 A->ε?加入到 M[A,B]中

因此,預(yù)測分析表如下:

i+*()#
EE?→ T E'E?→ T E'
E'E'?→ + T E'E' →εE' →ε
TT? → F T'T? → F T'
T'T' →εT' →*FT'T' →εT' →ε
Fi?F? →( E )

語法分析過程:

分析棧的起始狀態(tài)為? #<起始非終結(jié)符>? ,如果分析棧的輸入串的待匹配字符 和 分析棧頂元素按照預(yù)測分析表進(jìn)行化簡,如果棧頂和待匹配字符一致則匹配,如果都不滿足則輸入串語法錯誤。

步驟?分析棧輸入串備注
1#Ei? *(i + i)#E?→ T E'
2#E'Ti? *(i + i)#T? → F T'
3#E'T'Fi? *(i + i)#F? →i?
4#E'T'ii? *(i + i)#匹配
5#E'T'*(i + i)#T' →*FT'
6#E'T'F**(i + i)#匹配
7#E'T'F(i + i)#F? →( E )
8#E'T')E((i + i)#匹配
9#E'T')Ei + i)#E?→ T E'
10#E'T')E'Ti + i)#T? → F T'
11#E'T')E'T'Fi + i)#F? →i?
12#E'T')E'T'ii + i)#匹配
13#E'T')E'T'+ i)#T' →ε
14#E'T')E'+ i)#E'?→ + T E'
15#E'T')E'T++ i)#匹配
16#E'T')E'Ti)#T? → F T'
17#E'T')E'T'Fi)#F? →i?
18#E'T')E'T'ii)#匹配
19#E'T')E'T')#T' →ε
17#E'T')E')#E' →ε
18#E'T'))#匹配
16#E'T'#T' →ε
17#E'#E' →ε
18##匹配
19語法正確

? ? ? ? ? ? ? ?

四、自下而上的分析語法——算符優(yōu)先分析法

對于一個文法,如果其每個產(chǎn)生式的右部都不含兩個相鄰的非終結(jié)符,形如:S->.....QR....,則為算符文法。

假如G 是一個不含?ε 的算符文法

?a =·?b : 當(dāng)且僅當(dāng)文法G含有? S? ->? ...ab... 或?? S? ->? ...aQb...?

?a <·?b : 當(dāng)且僅當(dāng)文法G含有? S? ->? ...aQ... 且 Q ->b... 或 Q ->Rb

?a >·?b :?當(dāng)且僅當(dāng)文法G含有? S? ->? ...Qb... 且 Q ->...s 或 Q ->....aR?

當(dāng)一個算符文法的任意終結(jié)符(a,b) 最多只滿足a =·?b,a <·?b,a >·?b 關(guān)系之一,則該文法為算符優(yōu)先文法。也就是說,任意一對終結(jié)符,最多只有一種優(yōu)先關(guān)系成立。

例如、對于文法

? ? ? ? E'? ->? #E#? ? ? .......①

? ? ? ? E -> E+T |T? ? ........②

? ? ? ? T -> T * F | F? ........③

? ? ? ? F->P ↑ F? | P .........④

? ? ? ? P -> (E) | i? ?...........⑤

用算法優(yōu)先分析輸入串為? ( i+i )*i

1)對每個非終結(jié)符構(gòu)建FIRSTVT 集 和LASTVT 集

? ? FIRSTVT(P) 和?LASTVT (P)表示 非終結(jié)符P可推出產(chǎn)生式的第一個終結(jié)符和最后一個終結(jié)符集合??

? ? ?FIRSTVT (P )? =? { a | P => a...? 或 P => Qa....? ,a ∈ 終結(jié)符, Q∈非終結(jié)符}

? ? ?LASTVT (P )? =? { a | P => ....a? 或 P =>.....aQ? ,a ∈ 終結(jié)符, Q∈非終結(jié)符}

因此可以自下而上的用下面的規(guī)則構(gòu)造FIRSTVT,

  • 若有產(chǎn)生式? ?P->a.?或 P -> Qa....? ,則 a∈FIRSTVT (P )?
  • 若有 a∈FIRSTVT (Q)? 且有產(chǎn)生式? ?P->?Q... 則,a∈FIRSTVT (P )

同理,可以自下而上的用下面的規(guī)則構(gòu)造LASTVT,

  • 若有產(chǎn)生式? ?P->....a? ?或 P ->.....aQ? ,則 a∈LASTVT (P )?
  • 若有 a∈LASTVT (Q)? 且有產(chǎn)生式? ?P-> ....Q?則,a∈LASTVT(P )

? ? FIRSTVT (P)? = { (,i }? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? LASTVT(P') ={ ),i}

? ? FIRSTVT (F) = {↑,(, i}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?LASTVT(F) = {↑, ),i}

? ? FIRSTVT (T) = {*,↑,(, i}? ? ? ? ? ? ? ? ? ? ? ? ? ? LASTVT (T) = {*,↑,), i}

? ? FIRSTVT (E) = {+,*,↑,(, i}???????????????????????? LASTVT (E) = {+,*,↑,), i}

? ? FIRSTCT (E') = {#}? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??LASTVT (E') = {#}

2)構(gòu)造算符優(yōu)先關(guān)系表

? 形如有產(chǎn)生式? ....aP.....,那么對任何 b ∈ FIRSTVT(P) ,都有 a <· b

? 形如有產(chǎn)生式? ....Pb.....,那么對任何 a?∈ LASTVT(P) ,都有 a? >· b

? 遍歷每個產(chǎn)生式因此算符優(yōu)先關(guān)系表如下

+*i()#
+
*
i
(
)
#

當(dāng)分析棧頂元素與輸入緩沖區(qū)的第一個字符作優(yōu)先對比,如果是<· 則將緩沖區(qū)的第一個字符移進(jìn)分析棧中即push分析棧,如果是>·則進(jìn)行規(guī)約,即pop分析棧。如果是=·那么緩沖區(qū)的第一個字符和分析棧頂同時移除

步驟分析棧輸入緩沖區(qū)備注
1#( i+i )*i##<·(,移進(jìn)
2#(i+i )*i#(<·i,移進(jìn)
3#(i+i )*i#i>·+,規(guī)約
4#(+i )*i#(<·+移進(jìn)
5#(+i )*i#+<·i,移進(jìn)
6#(+i)*i#i>·),規(guī)約
7#(+)*i#+>·),規(guī)約
8#()*i#( =· ) ,同時移出
9#*i##<·*,移進(jìn)
10#*i#*<·i,移進(jìn)
11#*i#i>· #,規(guī)約
12#*#*>· #,規(guī)約
13### =·# ,同時移出
語法正確

五、語義分析

? ? ? ?語義分析的主要目的是為了在語法分析中規(guī)約、匹配、接受等時執(zhí)行相應(yīng)的動作指令,最終生成一組四元式,四元式可以為接下來的中間代碼生成中解析。

對于算符文法語法語義分析的流程圖大致如下

在文法翻譯可以粗略地分為:聲明語句的翻譯、賦值語句的翻譯、簡單算數(shù)運(yùn)算表達(dá)式的翻譯,布爾表達(dá)式的翻譯、控制語句的翻譯。其中聲明語句的翻譯涉及符號表相關(guān)動作,非本文重點。

動作函數(shù)及屬性說明如下:

  • Entry(id) :在符號表中標(biāo)識符id的位置
  • S.code : 語句S對應(yīng)的后綴式代碼序列
  • E.place : 與非終結(jié)符E相聯(lián)系的臨時變量地址
  • E.true : 當(dāng)E的表達(dá)式為真時,控制流轉(zhuǎn)向的語句編號(四元式編號)
  • E.false : 當(dāng)E的表達(dá)式為假時,控制流轉(zhuǎn)向的語句編號(四元式編號)
  • Gen(op,arg1,arg2,result) : 創(chuàng)建四元式,屬性result默認(rèn)值為空。
  • nextquad:下一個生成的四元式編號,即比當(dāng)前最大的四元式編號多1。執(zhí)行一次Gen,nextquad就加1,
  • E.quad:E對應(yīng)的四元式編號,
  • S.next : S對應(yīng)的代填轉(zhuǎn)移鏈,通常在S規(guī)約后,回填S.next集合中對應(yīng)的跳轉(zhuǎn)四元式
  • Merg(P1,P2), 把四元式鏈表P1 和鏈P2,并返回新鏈的鏈?zhǔn)字羔?/li>
  • Backpatch (p,t) :把t回填到四元式鏈表P中每一個節(jié)點(四元式)中的result項。
  • Newtemp() : 生成一個臨時變量

注:產(chǎn)生式S統(tǒng)一計為語句;E計為表達(dá)式,L計為語句塊 , A 為賦值語句,M為語句塊的起始四元式編號,N語句塊的結(jié)束四元式編號

1)賦值語句和的簡單算數(shù)運(yùn)算表達(dá)式的翻譯

產(chǎn)生式語義動作
? ? A->id := E? ? ?{Gen(":=" , E.place, "_" , Entry(id))? }
E -> E1? + E2

{E.place = Newtemp() ;

GEN("+",E1.place,E2.place,E.place) }

E -> E1? * E2

{E.place = Newtemp() ;

GEN("*",E1.place,E2.place,E.place) }

E -> -E1??

{E.place = Newtemp() ;

GEN("minus",E1.place,"_",E.place) }

E-> ( E1 )E.place =E1.place?
E -> id?E.place = Entry(id)

2)布爾表達(dá)式的翻譯方法

注:rel_op為布爾運(yùn)算符

產(chǎn)生式語義動作
? E -> E1?or ME2 ?

{backpatch(E1.false, M.quad) ;

E.true := merge(E1.true , E2.true);

E.false := E2.false}

E -> E1? and? ME2

{backpatch(E1.true, M.quad) ;

E.true := E2.true?;?

E.false := merge(E1.false,E2.false)}

E -> not E1?

E.true := E1.false ;?E.false := E1.true?;?

E-> ( E1 )

E.true :=E1.true ;? ?E.false :=E.1false?

E->? id? rel_op? ?id?

{E.true :=nextquad ;? E.false :=??nextquad+1 ;

Gen( "j <rel_op>"? , id1.place? ,? id2.place ,0?);

Gen("j" ,"_" ,"_",0);

}

E -> id?

{E.true :=nexquad ;? E.false :=??nexquad+1 ;

Gen( "jnz"? , id1.place? ,?"_" ,0?);

Gen("j" ,"_" ,"_",0);

}

M ->εM.xq =nextquad

? ? ? ? ? ? ?

例如:布爾表達(dá)式 “?a<b or c<d? and e<f ”的四元式序列?設(shè)序列起始值為100

因為對于自下而上的語法分析中,語義動作是在產(chǎn)生式規(guī)約的時候發(fā)生的,所以語義執(zhí)行順序是按照逆波蘭式順序執(zhí)行的

????????

首先發(fā)生規(guī)約的是? ? E ->? a <b 產(chǎn)生式;對照的語義動作表得到的控制流鏈號見上圖,得到的四元式為;

100 :("j<" , a,b,0)

101: (j,_,_0)

接下來發(fā)生規(guī)約的是M ->ε ,此時nextquad下一個四元式編號是102,再接下來發(fā)生規(guī)約是E ->c < d

102 :("j<" , c,d,0)

103: (j,_,_0)

接下來發(fā)生規(guī)約的是M ->ε ,此時nextquad下一個四元式編號是104,再接下來發(fā)生規(guī)約是E ->e < f

104 :("j<" , e,f,0)

105: (j,_,_0)

接下來發(fā)生規(guī)約的是??E -> E1? and? ME2? ,見上表對應(yīng)的語義動作是把?M.quad回填到E1.true控制流四元式的跳轉(zhuǎn)值。即backpatch(102, 104),修改編號102的四元式成? ?102 :("j<" , c,d,104)

接下來發(fā)生規(guī)約的是??? E -> E1?or ME2 ? ,見上表對應(yīng)的語義動作是把?M.quad回填到E1.false控制流四元式的跳轉(zhuǎn)值。即backpatch(101, 102),修改編號101的四元式成? ?101: (j,_,_102)

因此 此布爾表達(dá)式得到的最終序列是:

100 :("j<" , a,b,0)

101: (j,_,_102)

102 :("j<" , c,d,104)

103: (j,_,_0)

104 :("j<" , e,f,0)

105: (j,_,_0)

上述四元式的含義是

100:如果 a<b 為真時,跳轉(zhuǎn)到第0個四元式(即退出程序),否則繼續(xù)往下執(zhí)行

101:直接跳轉(zhuǎn)到102號四元式

102:如果 c <d? 為真時跳轉(zhuǎn)到第104號四元式,否則繼續(xù)往下執(zhí)行

........

3)典型控制語句的翻譯方法

產(chǎn)生式語義動作
? S -> if E then MS1??

{backpatch(E.true, M.quad) ;

S.next?:= merge(E1.false?, S1.next);

}

S -> if E then M1 S1 N else M2 S2

{backpatch(E.true, M1.quad) ;

backpatch(E.false, M2.quad) ;

S.next:= merge(S1.next,N.next,S2.next)}

E -> while M1 E do M2 S1

{backpatch(S.next, M1.quad) ;

backpatch(E.true, M2.quad) ;

S.next:=E.false;

Gen(" j?",_ , _ M1.quad)}

S-> Begin L end?

S.next = L.next

S -> A

S.next 初始化

L -> L1? ;? MS

backpatch(L1.next, M.quad) ;

L.next =S.next

L? -> SL.next =S.next
M ->εM.quad =nextquad
N->ε

N.next =nextquad ;

Gen(" j ", _ ,_ ,0)

?例如:程序語句

while a > 0 and x < 0 do begin x := x +1 ;if a > 0 or b <0 then a := a-1 else b := b -1end

的四元式序列?設(shè)序列起始值為100

:還是畫語法樹并自下而上按照逆波蘭式順序規(guī)約填寫控制流

?總結(jié)一下:

  • 四則運(yùn)算會生成一個四元式
  • 賦值語句會生成一個四元式
  • 布爾比較運(yùn)算符會生成兩個跳轉(zhuǎn)四元式,跳轉(zhuǎn)目標(biāo)待回填
  • 條件控制語句,如果布爾比較是真值則跳轉(zhuǎn)到控制語句塊的起始位置M中。每一個分支語句結(jié)束(規(guī)約)時N會產(chǎn)生一個直接跳轉(zhuǎn)四元式,最后一個分支應(yīng)省略。這些直接跳轉(zhuǎn)四元式的目標(biāo)地址是整個控制語句結(jié)束后編碼。即 L -> L1; MS中的M
  • 循環(huán)控制語句:如果布爾比較是真值則跳轉(zhuǎn)到控制語句塊的起始位置M中,控制語句塊結(jié)束時會產(chǎn)生一個直接跳轉(zhuǎn)四元式,直接到布爾比較中。如果布爾比較是假值,則跳轉(zhuǎn)到控制語句結(jié)束后編碼。
  • 語句S的語法子樹的結(jié)束入口通常需要S自身規(guī)約時才可以確定,所以用S.next存儲S的語法子樹中的待回填的退出地址。

因此:得到下述四元式,用T來表示臨時變量

100:? ("j>" ,a,0,102)

101: (" j " ,_,_,0)

102:(" j<" ,x,0,104);

103: (" j " ,_,_,0)

104:(" +" ,x,1,T1)

105:(":=",T1,_,x )

106:(" j>" ,a,0,110)

107:(" j " ,_,_,108)

108:(" j<",b,0,110)

109:(" j ",_,_113)

110:(" - ",a,1,T2)

111:(":=",T2,_,x)

112: (" j ",_,_,100)

113:( " - " ,b,1,T3)

114:(" :=",T3,_ ,b)

115"(" j ",_,_,100)

0: 程序結(jié)束

六、目標(biāo)代碼生成

? ? ? ? 目標(biāo)代碼生成的任務(wù)是為了把四元式序列轉(zhuǎn)化成對應(yīng)的代碼。而這個轉(zhuǎn)化后的代碼通常是匯編語言。在上例中的的偽Pascal文法下的代碼片段,其每一個四元式都有對應(yīng)的含義。例如四元式102:(" j<" ,x,0,104)? 對應(yīng)的意義是當(dāng) x<0 時跳轉(zhuǎn)到104號四元式。對應(yīng)的匯編代碼是:

CMP x,0

JE? <代碼塊標(biāo)簽名稱>?

類似的

指令碼

意義

條件

JZ, JE

結(jié)果為0或相等則轉(zhuǎn)

Z=1,(A) = (B)

JNZ, JNE

結(jié)果不為0或不相等則轉(zhuǎn)

Z=0,(A)≠(B)

JNL, JGE

大于等于轉(zhuǎn)(不小于)

(S∨O)=0,(A)≥(B)

JL, JNGE

小于轉(zhuǎn)(不大于等于)

(S∨O)=1,(A)<(B)

JG, JNLE

大于轉(zhuǎn)(不小于等于)

(S∨O∨Z)=0,(A)>(B)

JMP

無條件轉(zhuǎn)移

那么 <代碼塊標(biāo)簽名稱> 該怎么確定呢?

1)基本塊劃分

? ? ? ? 代碼塊標(biāo)簽名稱通常是自定義的,通常是當(dāng)作 goto語句的跳轉(zhuǎn)代碼位置。而四元式的基本塊相當(dāng)于程序語言的語句塊,就是一堆順序執(zhí)行的語句序列。而基本塊入口的確定滿足以下條件的其中一個就行:

  • 程序第一個四元式為基本塊入口
  • 跳轉(zhuǎn)四元式的下一個四元式為基本塊入口
  • 跳轉(zhuǎn)語句要跳轉(zhuǎn)到的四元式,該四元式為基本塊入口

最后,相鄰兩個基本塊入口之間的四元式構(gòu)成一個基本塊(其中包含前者入口,不包含后者入口)。跳轉(zhuǎn)語句的跳轉(zhuǎn)位置也就是基本塊的名字。

對于上例的四元式序列劃分的基本塊如下:

---------GOTOBLOCK1------------ 100:("j>" ,a,0,102) ---------GOTOBLOCK2------------ 101:(" j " ,_,_,0) ---------GOTOBLOCK3------------ 102:(" j<" ,x,0,104) ---------GOTOBLOCK4------------ 103:(" j " ,_,_,0) ---------GOTOBLOCK5------------ 104:(" +" ,x,1,T1) 105:(":=",T1,_,x ) 106:(" j>" ,a,0,110) ---------GOTOBLOCK6------------ 107:(" j " ,_,_,108) ---------GOTOBLOCK7------------ 108:(" j<",b,0,110) ---------GOTOBLOCK8------------ 109:(" j ",_,_113) ---------GOTOBLOCK9------------ 110:(" - ",a,1,T2) 111:(":=",T2,_,x) 112:(" j ",_,_,100) ---------GOTOBLOCK10------------ 113:( " - " ,b,1,T3) 114:(" :=",T3,_ ,b) 115"(" j ",_,_,100) ---------END--------------------

因此:102:(" j<" ,x,0,104) 要跳轉(zhuǎn)的104四元式對應(yīng)的的基本塊GOTOBLOCK5因此對應(yīng)的目標(biāo)代碼是:

CMP x,0 JE? GOTOBLOCK5

除了比較跳轉(zhuǎn)的四元式外,:還有四則運(yùn)算和賦值語句

賦值語句對應(yīng)的是:? ?MOV? 變量名 ,<寄存器名稱>? ,?

而四則運(yùn)算對應(yīng)的代碼則為? ?

  • ADD?<寄存器名稱> ,<變量或寄存器名稱>?
  • ADD?<寄存器名稱> ,<變量或寄存器名稱>?
  • MUL <寄存器名稱> ,<變量或寄存器名稱>?
  • DIV <寄存器名稱> ,<變量或寄存器名稱>?

每個寄存器只能存一個值,因此如何選擇寄存器是目標(biāo)代碼生成的一個重點

2)寄存器選擇——寄存器的待用信息與活躍信息的確定

? ? ? ? 在同一個基本塊中,如果中間代碼(四元式) i?對 A 定值,中間代碼 j 引用了? A 值,且從 i 到 j 之間沒有 A 的其他定值,則 j 是代碼 i 中變量? A 的待用信息? ,且 A在 i 處是活躍的。

????????通俗來講,就是存在寄存器里的值還需要被后續(xù)代碼 j 引用到,那么就 j 使用的寄存器就應(yīng)該是 A ,且? i 到 j 之間的代碼不能使用寄存器A。 即 代碼 j 待使用 A 的值 ,A的值是來源于代碼 i。

? ? ? ? 對于變量待用信息的計算:

(1)開始時,把基本塊中各個變量在符號表中的待用信息域初始化為“非待用”,根據(jù)基本塊出口之后是否活躍(變量生命周期是否結(jié)束)來初始化活躍信息域 "活躍" 或 "非活躍"。

(2)由后向前遍歷從基本塊出口至基本塊入口中的每一行中間代碼形如? ( op , B , C, A) 或??( := , B ,_, A)形式的依次執(zhí)行以下步驟:

  • 把符號表中變量A的待用信息和活躍信息附加在中間代碼i上
  • 把符號表中變量A的待用信息和活躍信息分別置為 "非待用" 和 "非活躍"
  • 把符號表中變量B 和 變量 C 的待用信息和活躍信息?附加在中間代碼i上
  • 把符號表中的 B 和 C 的待用信息均置為 i? , 活躍信息都置為 "活躍"
  • 例如:某一個基本塊的中間代碼序列如下,假設(shè)基本塊結(jié)束后W時活躍變量,假設(shè)由R1,R2,R3寄存器,寫出目標(biāo)代碼;

    ①? T :=? A +B

    ②? U := A? - C

    ③? V := T? + U

    ④? W := V? + U

    由④遍歷到①代碼得到待用信息與活躍信息表

    序號中間代碼?TABCUVW
    W := V? + U

    非待用

    非活躍

    非待用

    非活躍

    非待用

    活躍

    V := T? + U

    非待用

    非活躍

    4,活躍4,活躍

    非待用

    活躍

    U := A? - C3,活躍

    非待用

    非活躍

    非待用

    非活躍

    3,活躍4,活躍

    非待用

    活躍

    T :=? A +B3,活躍2,活躍

    非待用

    非活躍

    2,活躍3,活躍4,活躍

    非待用

    活躍

    所以當(dāng)代碼執(zhí)行到 ①時,存放值B的寄存器使用完了可以直接釋放,存放A值的寄存器要等代碼②執(zhí)行完,才可以釋放,存放值T的寄存器要等代碼③執(zhí)行完才變成"非待用"后可以釋放。

    同理類推....得到目標(biāo)代碼

    MOV R1 , A MOV R2 , B ADD R2 , R1 --B值以后用不到了R2釋放,R2用來存T MOV R3 , C SUB R1 , R3 -- C以后用不到了R3釋放 ,A值以后用不到了R1釋放,R1用來存U ADD R2 , R3 -- T值以后用不到了R2釋放,R2用來存 V ADD R1 , R2 -- U值以后用不到了R1釋放,V值以后用不到了R2釋放,R1用來存W

    最后:五-3 示例中得到的目標(biāo)代碼為

    CODEBLOCK1:CMP a , 0JG CODEBLOCK3 CODEBLOCK2:JMP CODEEND CODEBLOCK3:CMP x , 0 JL CODEBLOCK5 CODEBLOCK4:JMP CODEEND CODEBLOCK5:MOL AX , xADD AX , 1MOV x ,AXCMP a , 0 JG CODEBLOCK9 CODEBLOCK6:JMP CODEBLOCK8 CODEBLOCK7:CMP b,0JL CODEBLOCK9 CODEBLOCK8:JMP CODEBLOCK10: CODEBLOCK9:MOL AX , aSUB AX , 1MOV x ,AXJMP CODEBLOCK1 CODEBLOCK10:MOL AX , bSUB AX , 1MOV b ,AXJMP CODEBLOCK1 CODEEND:

    七、中間代碼的優(yōu)化

    ? ? ? ? 中間代碼的優(yōu)化有三個原則:等價原則,有效原則,合算原則。即優(yōu)化后的效果必須要和原來一致,不會增加無效代碼,并且對性能有提高的。每個對于不可達(dá)代碼,可以畫流圖來確認(rèn)哪些基本塊是永遠(yuǎn)沒機(jī)會執(zhí)行的,對于這些不可達(dá)的基本塊可以直接從代碼中刪除。對于算數(shù)計算的優(yōu)化可以用有向無環(huán)圖(DAG)進(jìn)行代碼優(yōu)化。原理大致是,每一個節(jié)點代表一個值可以被一個或多個變量引用。然后重寫語句。

    (1) 基于DAG圖的優(yōu)化方法?

    例如、給定某個基本塊代碼如下:

  • ?T0 := 3.14
  • ?T1 :=? 2 * T
  • ?T2 := R + r
  • ?A? ?:=? T1 * T2
  • ?B? :=? A
  • ?T3 := 2? *? T0
  • ?T4 := R + r
  • ?T5 := T3 * T4
  • ?T6 :=? R - r
  • ?B? ?:=? T5 *? T6?
  • 常量是葉子節(jié)點,計算符是內(nèi)部節(jié)點

    ?

    ? ? ?最后得到的DAG圖是

    確認(rèn)哪個是基本塊退出后的活躍變量,(假設(shè)是 B),以活躍變量為根節(jié)點,刪除非活躍變量的引用,但是每個內(nèi)部節(jié)點要保留至少一個引用,葉子節(jié)點保留值就行。

    假設(shè)基本塊退出后的只有一個活躍變量,優(yōu)化后的中間代碼可以為:

    T2 := R - r

    T6 := R + r

    A := 6.18 * T2

    B := A * T6

    ?

    總結(jié)

    以上是生活随笔為你收集整理的编译原理:全片知识难点总结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。