语义分析(二)

中间代码的形式

  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
  
}

数据和结构的翻译

  • 数组说明和数据元素引用
  • 结构说明和引用
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值