三, 含数组元素的赋值语句的翻译
1,数组元素的地址计算公式
(1)数组定义的一般形式
array A[l1:u1,l2:u2,.,,,ln:un] of integer
其中,lk,uk分别称为第 k维的下, 上界;
dk=uk-lk+1 称为第 k维维长 ;
A[i1,i2,…,in]为某一数组元素 。
(2)按行存放时的地址公式
设每个元素占一个存储单元,则 A[i1,i2,…,in]
的地址
D=a+(i1-l1)*d2*d3*… *dn+(i2-l2)*d3*d4*… *dn
+… +(in-1-ln-1)*dn+(in-ln)
D=CONSPART+VARPART
CONSPART=a-C
C=(..,(l1*d2+l2)*d3+.,, +ln-1)*dn+ln
VARPART =(.,,(i1*d2+i2)*d3+.,,+in-1)*dn+in
(3)数组的描述符 — 内情向量
?内容,类型,维数,CONSPART,各维上, 下
界和维长
l1
l2
u1
u2
d1
d2
…..,
ln un dn
n type
CONSPART
(4)VARPART的计算
D1=i1,Dk=Dk-1*dk+ik,(k=2,3,.,,n)
2.含数组元素赋值语句的文法及改写
A→V:=E
V→i[Elist]│i
Elist→Elist1,E | E
E→E1 op E2│-E1│(E1)│V
为了在计算 VARPART的过程中随时查找数
组的内情向量,必须改写 Elist→Elist1,E | E
改写后的文法为,
A→V:=E
V→i│Elist]
Elist→i[E│Elist1,E
E→E1 op E2│-E1│(E1)│V
3,翻译方案
(1)新的语义变量和过程
?V.place:简单变量的存储地址
或 数组元素的 CONSPART
?V.offset,null
或 数组元素的 VARPART
?Elist.array:记录数组名
?Elist.place:记录归约过程中 VARPART
的中间结果
?Elist.dim:记录当前处理这一维的序号
?getc(Elist.array):从内情向量中取数组的
CONSPART
?limit(Elist.array,k):从内情向量中取数组
第 k维的维长
( 2)两条新的四元式
?变址取数
( =[],T1[T],_,X)
相当于 X:=T1[T]
?变址存数
( []=,_,X,T1[T])
相当于 T1[T]:=X
(3)语义子程序
?V→i
{ P:=lookup(i.name);
if P<>nil
then begin V.place:=P;
V.offset:=null
end
else error }
?Elist→i[E
{ P:=lookup(i.name);
if P<>nil
then begin Elist.array:=P;
Elist.place:=E.place;
Elist.dim:=1
end
else error }
?Elist→Elist1,E
{ t:=newtemp; k:= Elist1.dim+1;
dk:=limit(Elist1.array,k);
emit(*,Elist1.place,dk,t);
emit(+,t,E.place,t);
Elist.array:=Elist1.array;
Elist.place:=t;
Elist.dim:=k }
?V→Elist]
{ V.place:=getc(Elist.array);
V.offset:=Elist.place }
数组元素的宽度 W?1时,
V.offset:=newtemp;
emit(*,Elist.place,W,V.offset);
?E→V
{ if V.offset=null then E.place:=V.place
else begin
E.place:=newtemp;
emit(=[],V.place[V.offset],-,E.place);
end }
?E→E1 op E2
{ E.place:=newtemp;
emit(op,E1.place,E2.place,E.place) }
?E →-E1
{ E.place:=newtemp;
emit(@,E1.place,_,E.place) }
?E →(E1)
{ E.place:= E1.place }
?A→V:=E
{ if V.offset=null
then emit(:=,E.place,_,V.place)
else emit([ ]=,E.place,_,V.place[V.offset])
}
例 1,a:=X[b,c]+d的翻译
设 A[1:10,1:20],W=4,CONSPART=X0
a
V1 V.place=a
V.offset=null
V1:=X[b
V1:=X[E1 E1.place=b
V1:=Elist1 Elist1.array=X
Elist1.place=b
Elist1.dim=1
V1:=Elist1,c
V1:=Elist1,E2 E2.place=c
V1:=Elist2 Elist2.array=X (*,b,20,t1)
Elist2.place=t1 (+,t1,c,t1)
Elist2.dim=2
V1:=Elist2]
V1:=V2 V2.place= X0 (*,t1,4,t2)
V2.offset=t2
V1:=E3 E3.place=t3 (=[],X0[t2],_,t3)
V1:=E3+d
V1:=E3+E4 E4.place=d
V1:=E5 E5.place=t4 (+,t3,d,t4)
A (:=,t3,_,a)
例 2,X[i+2,j+1]:=m+n的翻译
设 A[1:10,1:20],W=4,CONSPART=X0
X[i
X[E1 E1.place=i
X[E1+2
X[E1+E2 E2.place=2
X[E3 E3.place=t1 (+,i,2,t1)
Elist1 Elist1.array=X
Elist1.place=t1
Elist1.dim=1
Elist1,j
Elist1,E4 E4.place=j
Elist1,E4+1
Elist1,E4+E5 E5.place=1
Elist1,E6 E6.place=t2 (+,j,1,t2)
Elist2 Elist2.array=X (*,t1,20,t3)
Elist2.place=t3 (+,t3,t2,t3)
Elist2.dim=2
Elist2]
V1 V1.place= X0 (*,t3,4,t4)
V1.offset=t4
V1:=m
V1:=E7 E7.place=m
V1:=E7+n
V1:=E7+E8 E8.place=n
V1:=E9 E9.place=t5 (+,m,n,t5)
A ([]=,t5,_,t4[X0])
四, 一类说明语句的翻译
1,文法
P→D
D→D1;D2│i:T
T→real│integer│array[num] of T1│↑T1
可见,非终结符 P产生一系列 i:T形式的说明
语句 。
2,主要工作
不产生可执行指令,仅负责填表,将被
说明对象的类型及相对存储位置记入各
自的符号表中 。
3,语义变量及过程
(1)offset:相对位移量,初值为 0,是一个
全局变量
(2)T.type:数据类型
(3)T.width:数据宽度
(4)enter:语义过程,将变量名及其类型
和相对存储位置记入符号表中 。
4,翻译方案
对一个程序来说, offset的初值为 0,针
对这个赋初值的语义动作, 引进了标记
非终结符 M及空字产生式 M→ε的归约 。
P→M D
M→ε {offset:=0}
D→D1;D2
D→i:T { enter(i.name,T.type,offset);
offset:=offset+T.width }
T→integer { T.type:=integer; T.width:=4 }
T→real { T.type:=real; T.width:=8 }
T→array[num] of T1
{ T.type:=array(num.val,T1.type);
T.width:=num.val*T1.width }
T→↑T1
{ T.type:=pointer(T1.type); T.width:=4 }
5,补充说明
(1)说明语句可能为如下形式
D→integer namelist│real namelist
namelist→namelist,i│i
先改写为 D→D,i│integer i│real i
(2)说明语句也可为如下形式
D→namelist integer | namelist real
namelist→namelist,i | i
翻译时需引进队列 namelist.QUEUE用以存
放变量名
(3)对数组说明的翻译:分配内情向量
表区,产生在运行时动态地建立内情向量
和分配数组空间的目标指令。