中間代碼的形式
- 逆波蘭式
《逆波蘭表達式&後綴表達式》 - 三元式和樹形
每個三元式由3部分組成:算符,運算對象1,運算對象2。
例如a= b * c + bd;
(1)(,b,c)
(2)(*,b,d)
(3)(+,(1),(2))
(4)(=,(3),a)
其中第三個式子的(1)和(2),表示第一式子和第二式子的運算結果
對於一自運算,只需要選用一個運算對象如-3表示爲(-,3,‘’)
樹形表示是三元式的翻版
- 四元式
四元式是一種比較普遍採用的中間代碼形式。
每個三元式由4部分組成:算符,運算對象1,運算對象2,運算結果。
例如a= b * c + bd;
(1)(,b,c,t1)
(2)(*,b,d,t2)
(3)(+,t1,t2,t3)
(4)(=,t3,-,a)
其中t1和t2,分別表示第1和第2式子的運算結果,4式中-爲空符號。
有時爲了直觀,四元式的形式也可以寫成簡單的賦值語句,
(1)t1=bc
(2)t2=bd
(3)t3=t1+t2
(4)a=t3
再比如
(jump,-,-,L) 改成 jump L
(jrop,B,C,L) 必成 if B rop C goto L
賦值語句翻譯
S-> id = E
{
p = lookup(id.name); //表示id.name是否出現在符號表中,如果在返回指針,不在返回nil
if(p != nil) then
emit(p = E.place);//emit把四元式輸出到文件上, 四元式:(=,E.place,-,p)
else
error
}
E->-E1
{
E.place = newtemp
emit(E.place = 'uminus'E1.place )
}
E->E1*E2
{
E.place = newtemp
emit(E.place = E1.place * E2.place)
}
E->E1+E2
{
E.place = newtemp
emit(E.place = E1.place + E2.place)
}
E->(E1)
{
emit(E.place = E1.place )
}
E-> id
{
p = lookup(id.name);
if(p != nil) then
E.place = p
else
error
}
如果考慮上類型轉換的問題
E -> E1 * E2
{
E.place = newtemp;
if E1.type = int AND E2.type = int then
emit(E.place = E1.place * E2.place)
E.type = int;
else if E1.type = real AND E2.type = real
emit(E.place = E1.place * E2.place)
E.type = real;
else if E1.type = int AND E2.type = real
t = newtemp;
emit(t = 'itr'E1.place) //'itr'是類型轉換real
emit(E.place = t * E2.place)
E.type = real;
else if E1.type = real AND E2.type = int
t = newtemp;
emit(t = 'itr'E2.place) //'itr'是類型轉換real
emit(E.place = t * E1.place)
E.type = real;
}
布爾表達式翻譯
E -> E1 or E2
{
E.place = newtemp;
emit(E.place = E1.place or E2.place)
}
E -> E1 and E2
{
E.place = newtemp;
emit(E.place = E1.place and E2.place)
}
E -> not E1
{
E.place = newtemp;
emit(E.place = not E1.place)
}
E->(E1)
{
emit(E.place = E1.place )
}
E-> id1 rop id2 //rop表示關係符,< = > !=
{
E.place = newtemp;
emit(if id1.place rop id2.place goto nextstat+3) //nextstat 表示當前4元式序號。
emit(E.place = 0)
emit(goto nextstat+2)
emit(E.place = 1)
}
E-> true
{
E.place = newtemp;
emit(E.place = 1)
}
E-> false
{
E.place = newtemp;
emit(E.place = 0)
}
因爲這個是二義文法,約定算符優先順序爲 not, and, or,並且 and 和 or服從左結合。
控件語句中的布爾表達式
S -> if E then S1 | if E then S1 else S2 | while E do S1
比如if E then S1 else S2, E.true表示此表達式的真出口(S1位置),E.false爲假出門(S1位置)
例:a<b or c<d and e>f,
得
(1)if a<b goto E.true
(2)goto 3
(3)if c>d goto 5
(4)goto E.false
(5)if e>f goto E.true
(6)goto E.false
但是E.true在翻譯a<b的是不知道的因此採用回填的方法
(1)if a<b goto p[0]
(2)goto 3
(3)if c>d goto 5
(4)goto E.false
(5)if e>f goto p[1]
(6)goto E.false
(7)把p所鏈接的四元式第4區域改爲(7)
得
E -> E1 or E2
{
//E2.codebegin爲E2開始代碼的序號
//把E1的假地址設爲E2的代碼的起始地址
backpatch(E1.flase , E2.codebegin)
E.codebegin = E1.codebegin //E的起始地址就是E1的起始地址
//將E1真地址鏈合到E2真地址鏈後面,並返回鏈首值
E.true = merge(E1.true,E2.true)
E.false = E2.false
}
E -> E1 and E2
{
backpatch(E1.true , E2.codebegin)
E.codebegin = E1.codebegin //E的起始地址就是E1的起始地址
E.true = E2.true
E.false = merge(E1.false,E2.false)
}
E -> not E1
{
E.codebegin = E1.codebegin
E.true = E1.false
E.false = E1.true
}
E->(E1)
{
E.codebegin = E1.codebegin
E.true = E1.true
E.false = E1.false
}
E-> id1 rop id2 //rop表示關係符,< = > !=
{
E.codebegin = nextstat
E.true = nextstat
E.false = nextstat + 1
emit(if id1.place rop id2.place goto - )
emit(goto -)
}
E-> true
{
E.codebegin = nextstat
E.true = nextstat
emit(goto -)
}
E-> false
{
E.codebegin = nextstat
E.false = nextstat
emit(goto -)
}
控制語句的翻譯
- 條件轉移 if-then,if-then-else,while-do
- 開頭語句switch
- 循環語句for
- 出口語句exit
- goto語句
- 過程調用(函數的調用)
S -> call i(<arglist>){
for 隊列arglist的每一項p do GEN(par,-,-,p) //放出實參
GEN(call,-,-,entry(i)) //調用
}
<arglist> -> <arglist>1 , E
{
arglist.queue.push(E.place)//加入參數隊尾
}
<arglist> -> E
{
建立個保包含一項的E.place的實參隊列
}
說明語句的翻譯
- 簡單說明語句(變量聲明)
{
D -> int id
{
enter(id,int)//放入符號表
D.att = int
}
D -> real id
{
enter(id,real)
D.att = real
}
D -> D1 , id
{
enter(id,D1.att)
D.att = D1.att
}
}
- 過程中的說明(函數參數)
D -> real id
{
enter(id,real,offset);//offset相對過程的地址
D.att = real
D.width = 8 //real的寬度爲8
offset = offset + D.width
}
數據和結構的翻譯
- 數組說明和數據元素引用
- 結構說明和引用