中间代码的形式
- 逆波兰式
《逆波兰表达式&后缀表达式》 - 三元式和树形
每个三元式由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
}
数据和结构的翻译
- 数组说明和数据元素引用
- 结构说明和引用