語義分析(二)

中間代碼的形式

  1. 逆波蘭式
    逆波蘭表達式&後綴表達式
  2. 三元式和樹形
    每個三元式由3部分組成:算符,運算對象1,運算對象2。

例如a= b * c + bd;
(1)(
,b,c)
(2)(*,b,d)
(3)(+,(1),(2))
(4)(=,(3),a)
其中第三個式子的(1)和(2),表示第一式子和第二式子的運算結果
對於一自運算,只需要選用一個運算對象如-3表示爲(-,3,‘’)

樹形表示是三元式的翻版

=
a
+
*
*
b
c
b
d
  1. 四元式
    四元式是一種比較普遍採用的中間代碼形式。
    每個三元式由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=b
d
(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
  
}

數據和結構的翻譯

  • 數組說明和數據元素引用
  • 結構說明和引用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章