语义分析与代码生成解析Word文档格式.docx
- 文档编号:17685430
- 上传时间:2022-12-08
- 格式:DOCX
- 页数:62
- 大小:62.12KB
语义分析与代码生成解析Word文档格式.docx
《语义分析与代码生成解析Word文档格式.docx》由会员分享,可在线阅读,更多相关《语义分析与代码生成解析Word文档格式.docx(62页珍藏版)》请在冰豆网上搜索。
error(n)
ENDIF;
lc1:
=lc;
生成jumpf指令;
lc:
=lc+1;
IFsy=thensyTHEN
statement;
{处理语句}
IFsy=elsesyTHEN
lc2:
生成jump指令;
回填jumpf指令的转向目标;
图7.1
回填jump指令的转向目标;
ELSE
回填jumpf指令的转向目标
ENDIF
ENDIF;
可以看出,除了检查表达式类型外(敏感成分的处理),语义分析工作还包括转向目标的回填等操作。
与第四章给出的条件语句的语法分析算法相比,上述算法只是增加了如下几个操作:
op1>
:
boolsTHEN
error(n);
op2>
op3>
op4>
这相当于说上面的处理算法是根据如下文法规则写成的:
IF语句>
→IF<
表达式>
THEN<
语句>
ELSE<
即在文法规则中嵌入了相应的语义加工操作。
于是,语义分析及代码生成可以随着语法分析的进行,通过嵌入相应的语义加工操作来完成。
这种方法称为语法制导翻译,因为语言的文法规则确定了相应的语义分析类型及生成代码的性质,而且分析算法的主体控制是相应的文法规则。
本章后面将结合实例讨论各种典型的语言结构的语义分析及代码生成。
7.2目标机
为了完成代码生成工作,必须有一个提供运行环境的目标机。
最直接的方法是,在哪个机器上运行的编译程序就生成那个机器的目标代码,或生成那个机器的汇编语言程序,然后经过汇编程序汇编成可以执行的机器语言程序。
汇编后产生的目标代码可以具有绝对地址,从而可以装到内存的固定区域去执行;
也可以具有浮动的(相应的)地址,再由装入程序(或者是连接装配程序)来为地址代真(即转换成绝对地址),即可用于执行。
无论是哪一种情况,都需要知道机器的硬件,诸如有多少个累加器、特殊寄存器、地址空间的大小等。
但事实上,代码生成也可先脱离特定的硬件环境。
一种逐渐流行的方法是为一个抽象机生成代码,然后,在特定的机器上写一个解释程序来解释抽象机的指令。
下面我们将介绍一个抽象机,它是专为PASCAL-S设计的,与任何特定的计算机无关,不妨称为PASCAL-S处理机。
尽管PASCAL-S处理机在硬件上并不存在,但它的指令不难落实到任何特定的计算机上。
PASCAL-S处理机上有如下一些寄存器和一个存贮区:
ps:
程序状态字
ir:
指令寄存器
pc:
指令计数器
t:
栈顶寄存器
b:
基地址寄存器
display:
地址寄存器组
存贮区分为程序存贮区、表格区和栈区,如图7.2所示。
程序存贮区CODE用于存放目标代码,这部分存贮区在目标代码的执行期间保持不变,可看作只读存贮(ROM)。
表格区用来存放程序的静态信息。
栈区用作程序执行的数据空间。
栈区由一系列数据段组成,每个数据段包括如下内容:
图7.2
(1)标记部分。
(2)参数部分(可能为空)。
(3)局部量。
(4)处理语句时所需要的临时工作空间。
对应PASCAL-S中过程或函数的数据区,标记部分用来存放
(1)函数的返回结果。
(2)过程或函数的返回地址。
(3)静态链。
(4)动态链。
(5)过程或函数标识符在tab中的位置。
其中静态链与动态链指向栈区S的其它单元,返回地址指向代码区CODE中的单元,第(5)项则指向表格区中的单元。
PASCAL-S处理机是一个栈式的机器,它没有传统的累加器,所有对数据的操作均在栈顶进行。
例如,加法指令是把栈顶两个单元的内容相加,并把结果留在栈顶;
条件转向指令根据栈顶单元的内容决定是否转向,等等。
下面我们来介绍PASCAL-S机的指令系统。
因为这个指令系统是根据源语言PASCAL-S的特点而设计的,所以为了深刻理解各指令的意义,需要与后面将讨论的目标结构结合起来学习。
每条指令的格式为
操作码
操作数1
操作数2
当然,有些指令只有一个操作数,还有的指令没有操作数。
1.双操作指令(4条)
LODA:
x
y
将x(层号)和y(位移量)所确定的地址装到栈顶。
LODV:
1
根据x(层号)和y(位移量)确定单元地址,把单元的内容装到栈顶。
LOD*:
2
根据x(层号)和y(位移量)确定存放地址的单元,把那个地址所指单元的内容装到栈顶。
UPD:
3
x,y均为层号,根据静态链更新display从第x+1层到第y层的内容。
2.单操作指令(23条)
STAD:
8
调用y所确定的标准函数,自变量的值在栈顶,调用后的函数值取代原来的栈顶。
表7.1中给出了编号y与标准函数的对应关系。
表7.1
函数
整数abs
7
succ
14
ln
实数abs
pred
15
sqrt
整数sqr
9
round
16
arctan
实数sqr
10
trunc
17
eof
4
odd
11
sin
18
eoln
5
chr
12
cos
6
ord
13
exp
ADDL:
将栈顶单元的内容加y。
JUMP:
转到y所指的指令继续执行。
JUMPF:
当栈顶单元的内容为false时退掉栈顶单元并转到y所指的指令去执行。
JUMPX:
y为情况表的入口地址。
根据栈顶单元的内容从情况表中确定转向目标,然后完成转向并退掉栈顶单元。
ENTRY:
ENTRY总是成对出现。
第一条中的y为情况标号的值,第二条中的y为相应的情况子句的入口地址。
CASE语句的情况表由若干对ENTRY组成。
FORIUP:
FOR1UP在如下形式的循环语句中用作循环的入口条件测试。
FORi:
=E1TOE2DOSS
当执行到FOR1UP指令时,运行时栈的状态如图7.3所示。
图7.3
指令FOR1UP在初值小于终值时,为循环变量i赋初值,否则退掉栈顶三个单元并转到y(循环出口)所指的指令继续执行。
FOR2UP:
FOR2UP与FOR1UP配对使用。
FOR2UP用于循环的重复条件测试。
如果循环变量的值小于终值,则循环变量的值加上1,并转循环入口y;
否则退掉栈顶三个单元。
FOR1DOWN:
FOR2DOWN:
这两条指令与前两条类似,它们用于如下形式的循环语句中:
=E1DOWNTOE2DOS
MARK:
这条指令为过程语句或函数调用的第一条指令,y为过程或函数标识符在符号表的位置。
该指令在栈顶分配5个单元作为标记部分,并将y填入所分配的第5个单元中。
CALL:
19
这条指令为过程或函数调用的最后一条指令。
y为btab[j].psize—1;
由于栈顶指针t指向参数区最后一个单元,所以t-y恰为本层数据区的开始位置。
在MARK与CALL之间的指令用于为形参分配存贮。
CALL指令用于填写本层display内容(t-y);
填写标记部分(静态链,动态链,返回地址);
为局部量分配存贮,根据标识符表中的入口地址转过程体。
INDEX1:
20
INDEX:
21
这两条指令是为计算数组元素的地址而设计的,y是指向数组表的指针。
它的功能是将(栈顶单元内容—数组下界)*L加到次栈顶单元的内容上并退掉栈顶单元。
在INDEX1中,L=1;
在INDEX中,L=atab[y].elsize。
LODB:
22
将一串相连单元的内容装到栈顶,这串单元的个数由y指定,第一个单元的地址在原来的栈顶单元中,修改栈顶指针。
COPYB:
23
以栈顶单元所包含的地址为开始地址,复制y个单元的内容到次栈顶所含地址为开始的y个单元中。
LODL:
24
把y装到栈顶。
LODR:
25
y为指向实数表的指针。
这条指令是将y所指向的实数装到栈顶。
FLOAT:
26
将栈中从栈顶开始数的第y个单元的内容变成浮点数。
READ:
27
将y所指定类型的数据读到栈顶单元的内容所指定的单元中,并退掉栈顶单元。
WRITE0:
28
y为指向串表stab的指针。
这条指令是输出从y开始的一串字符,(输出字符的个数在栈顶单元中)并退掉栈顶单元。
WRITE1:
29
WRITE2:
30
这两条指令是输出简单变量的值,变量类型由y指定。
WRITE1输出栈顶单元的内容并退掉栈顶单元(输出域宽为缺省值)。
WRITE2按栈顶单元所示域宽输出次栈顶的内容并退掉栈顶两个单元。
3.无操作数指令(33条)
HALT:
31
终止目标程序执行。
EXITP:
32
这条指令是从过程返回的指令,它将栈顶指针恢复到执行MARK前的值;
根据动态链恢复基地址寄存器的内容;
按返回地址完成返回。
EXITF:
33
这条指令是从函数返回的指令,它将栈顶指针恢复到执行MARK前的值加1(栈顶为函数结果);
按返回地址返回。
FETCH:
34
以栈顶单元的内容作地址,取这个地址所指单元的内容回送到栈顶。
NOT:
35
将栈顶单元的内容求反(栈顶单元的内容为布尔值)。
NEGATE:
36
将栈顶单元的内容乘上-1。
WRITER:
37
这条指令的意义是用如下语句打印实数x:
write(x:
y:
z);
其中z在栈顶单元中,y在次栈顶单元中,而x在栈顶第三个单元中。
STORE:
38
将栈顶单元的内容存到次栈顶单元所指示的单元中。
READLN:
62
WRITELN:
63
这两条指令分别等价于PASCAL语言中的readln与writeln语句。
以下指令均是在栈顶两个单元间进行的数据操作,功能是
<
次栈顶>
运算>
栈顶>
并退掉栈顶单元。
表7.2给出了各种运算所对应的操作码及助记符。
表7.2
运算
助记符
实数相等
EQR
39
逻辑加
OR
51
实数不等
NEQR
40
逻辑与
AND
56
实数小于
LTR
41
实数小等
LER
42
整数加
ADDI
52
实数大于
GTR
43
整数减
SUBI
53
实数大等
GER
44
实数加
ADDR
54
整数相等
EQI
45
实数减
SUBR
55
整数不等
NEQI
46
整数乘
MULI
57
整数小于
LTI
47
整数除
DIVI
58
整数小等
LEI
48
求余数
MODI
59
整数大于
GTI
49
实数乘
MULR
60
整数大等
GEI
50
实数除
DIVR
61
我们之所以这样设计目标机,一方面是因为可以避免考虑特定计算机的具体细节,另一方面是因为可以简化编译程序的代码生成。
然而,由于这个目标机在实际上并不存在,因此,为了使目标程序可以真正执行,必须设法实现这个目标机。
我们的办法是用PASCAL语言写一个解释程序来执行这个目标机的指令。
目标机的各寄存器及存贮区可以用PASCAL的各种变量来模拟,比如:
CONST
maxlevel=7;
tabsize=100;
atabsize=30;
btabsize=20;
rconstsize=20;
stabsize=600;
codesize=800;
stacksize=1450;
TYPE
object=(konstant,vvariable,typel,prozedure,funktion);
types=(notyp,ints,reals,bools,chars,arrays,records);
order=PACKEDRECORD
f:
0..63;
x:
0..maxlevel;
ps:
(run,finish,error);
{程序状态字}
ir:
order;
{指令寄存器}
pc:
integer;
{指令计数器}
t:
{栈顶寄存器}
b:
{基地址寄存器}
display:
ARRAY[0..maxlevel]OFinteger;
{地址寄存器组}
code:
ARRAY[0..codesize]OForder;
{代码区}
tab:
ARRAY[0..tabsize]OF
PACKEDRECORD
name:
PACKEDARRAY[1..10]OFchar;
link:
0..tabsize;
obj:
object;
typ:
types;
ref:
normal:
boolean;
lev:
adr:
atab:
ARRAY[1..atabsize]OFPACKEDRECORD
inxtyp:
eltyp:
elref:
low:
hig:
elsize:
size:
btab:
ARRAY[1..btabsize]OFPACKEDRECORD
last,lastpar:
psize,vsize:
rconst:
ARRAY[1..rconstsize]OFreal;
stab:
PACKEDARRAY[0..stabsize]OFchar;
s:
ARRAY[1..stacksize]OF{栈区}
RECORD
CASEcn:
typesOF
ints:
(I:
integer);
reals:
(r:
real);
bools:
(b:
boolean);
chars:
(c:
char)
目标程序的执行则可以用如下语句模拟:
各寄存器及栈区初始化;
REPEAT
ir:
=code[pc];
=pc+1;
CASEir.fOF
LODA:
t:
=t+1;
s[t].i:
=display[ir.x]+ir.y;
LODV:
=s[display[ir.x]+ir.y];
LOD*:
s[t]:
=s[s[display[ir.x]+ir.y].i];
UPD:
h1:
=ir.y;
h2:
=ir.x;
h3:
=b;
REPEAT
display[h1]:
=h3;
h1:
=h1-1;
=s[h3+2].i
UNTILh1=h2;
STAD:
CASEir.yOF
0:
s[t].i:
=abs(s[t].i);
1:
s[t].r:
=abs(s[t].r);
16:
=atan(s[t].r);
17:
s[t].b:
=eof(prd);
18:
=eoln(prd)
ENDCASE;
ADDL:
=s[t].i+ir.y;
JUMP:
pc:
JUMPF:
IFNOTs[t].bTHEN
pc:
=ir.y
ENDIF;
t:
=t-1;
JUMPX:
=s[t].i;
=0;
IFcode[h2].f<
>
ENTRYTHEN
h3:
=1;
ps:
=caschk{情况语句出错}
IFcode[h2].y=h1THEN
=code[h2+1].y
h2:
=h2+2
UNTILh3<
0;
FOR1UP:
=S[t-1].i;
IFh1<
=s[t].iTHEN
s[s[t-2].i].i:
=h1
ELSE
=t-3;
ENDIF
FOR2UP:
=s[t-2].i;
=s[h2].i+1;
s[h2].i:
=h1;
=t-3
FOR1DOWN:
=s[t-1].i;
IFh1>
s[s]t-2[.i].i:
FOR2DOWN:
=s[h2].i-1
MARK:
=btab[tab[ir.y].re].vsize;
=t+5;
s[t-1].i:
CALL:
=t-ir.y;
=s[h1+4].i
=tab[h2].lev;
display[h3+1]:
h4:
=s[h1+3].i+h1
s[h1+1].i:
=pc;
s[h1+2].i:
=display[h3];
s[h1+3].i:
FORh3:
=t+1TOh4DO
s[h3].i:
=0
ENDFOR;
b:
=h4;
=tab[h2].adr;
INDEX1:
=atab[h1].low;
IFh3<
h2THEN
ps:
=inxchk{下标越界错}
IFh3>
atab[h1].highTHEN
=inxchk
=s[t].i+(h3-h2)
INDEX:
ps:
=s[t].i+(h3-h2)*atab[h1].elsize
LODB:
=ir.y+t;
WHILEt<
h2DO
BEGIN
=
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语义 分析 代码 生成 解析