实验报告Word文件下载.docx
- 文档编号:6428259
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:42
- 大小:88.09KB
实验报告Word文件下载.docx
《实验报告Word文件下载.docx》由会员分享,可在线阅读,更多相关《实验报告Word文件下载.docx(42页珍藏版)》请在冰点文库上搜索。
=等等,识别后将类别存放在SYM中。
6.打印源程序,边读入字符边打印。
由于一个单词是由一个或多个字符组成的,所以在词法分析程序GETSYM中定义一个读字符过程GETCH。
3.程序设计:
(1)首先将标识符,变量,常量,运算符,关键字,标点符号分别放入数组中。
(2)构造实验所需要的方法:
如下源代码中所示(包括文本的搜索和读入等)。
(3)根据要编译的程序中的空格将其中的单词等分辨出来,并将其保存在相应的数组中。
(4)将结果写入文件。
实验二:
PL/0语言建立一个语法分析程序BLOCK(函数)
实验内容:
PL/0编译程序采用一遍扫描的方法,所以语法分析和代码生成都有在BLOCK中完成。
BLOCK的工作分为两步:
a)说明部分的处理
说明部分的处理任务就是对每个过程(包括主程序,可以看成是一个主过程)的说明对象造名字表。
填写所在层次(主程序是0层,在主程序中定义的过程是1层,随着嵌套的深度增加而层次数增大。
PL/0最多允许3层),标识符的属性和分配的相对地址等。
标识符的属性不同则填写的信息不同。
所造的表放在全程量一维数组TABLE中,TX为指针,数组元素为结构体类型数据。
LEV给出层次,DX给出每层的局部量的相对地址,每说明完一个变量后DX加1。
例如:
一个过程的说明部分为:
consta=35,b=49;
varc,d,e;
procedurep;
varg;
对它的常量、变量和过程说明处理后,TABLE表中的信息如下:
NAME:
a
b
c
d
e
p
KIND:
CONSTANT
VARIABLE
VAEIABLE
PROCEDURE
VAL:
35
49
LEVEL:
LEV
ADR:
DX
DX+1
DX+2
g
。
。
LEV+1
对于过程名的ADR域,是在过程体的目标代码生成后返填过程体的入口地址。
TABLE表的索引TX和层次单元LEV都是以BLOCK的参数形式出现,在主程序调用BLOCK时实参的值为0。
每个过程的相对起始位置在BLOCK内置初值DX=3。
2.语句处理和代码生成
对语句逐句分析,语法正确则生目标代码,当遇到标识符的引用则去查TABLE表,看是否有过正确的定义,若有则从表中取出相关的信息,供代码生成用。
PL/0语言的代码生成是由过程GEN完成。
GEN过程有三个参数,分别代表目标代码的功能码、层差、和位移量。
生成的目标代码放在数组CODE中。
CODE是一维数组,数组元素是结构体类型数据。
PL/0语言的目标指令是一种假想的栈式计算机的汇编语言,其格式如下:
fl
其中f代表功能码,l代表层次差,a代表位移量。
目标指令有8条:
①LIT:
将常数放到运栈顶,a域为常数。
②LOD:
将变量放到栈顶。
a域为变量在所说明层中的相对位置,l为调用层与说明层的层差值。
③STO:
将栈顶的内容送到某变量单元中。
a,l域的含义与LOD的相同。
④CAL:
调用过程的指令。
a为被调用过程的目标程序的入中地址,l为层差。
⑤INT:
为被调用的过程(或主程序)在运行栈中开辟数据区。
a域为开辟的个数。
⑥JMP:
无条件转移指令,a为转向地址。
⑦JPC:
条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。
⑧OPR:
关系和算术运算。
具体操作由a域给出。
运算对象为栈顶和次顶的内容进行运算,结果存放在次顶。
a域为0时是退出数据区。
实验主要步骤:
1.首先运行词法分析器,逐个读取文件中的单词,
2.然后识别每个单词,判定每个单词的类别
3.之后根据单词的类别来选择不同的处理方式
4.而且在语法分析函数的block函数中定义了两个可变数组,分别存放table表和code代码。
5.另外定义了error数组,分别存放出错的类型,但是数量有限,不能完全识别所有错误。
实验三:
建立一个解释执行目标程序的函数
编译结束后,记录源程序中标识符的TABLE表已退出内存,内存中只剩下用于存放目标程序的CODE数组和运行时的数据区S。
S是由解释程序定义的一维整型数组。
解释执行时的数据空间S为栈式计算机的存储空间。
遵循后进先出的规则,对每个过程(包括主程序)当被调用时,才分配数据空间,退出过程时,则所分配的数据空间被释放。
为解释程序定义四个寄存器:
1.I:
指令寄存器,存放当前正在解释的一条目标指令。
2.P:
程序地址寄存器,指向下一条要执行的目标指令(相当于CODE数组的下标)。
3.T:
栈顶寄存器,每个过程运行时要为它分配数据区(或称为数据段),该数据区分为两部分。
静态部分:
包括变量存放区和三个联单元。
动态部分:
作为临时工作单元和累加器用。
需要时临时分配,用完立即释放。
栈顶寄存器T指出了当前栈中最新分配的单元(T也是数组S的下标)。
4.B:
基地址寄存器,指出每个过程被调用时,在数据区S中给出它分配的数据段起始地址,也称为基地址。
每个过程被调用时,在栈顶分配三个联系单元。
这三个单元的内容分别是:
SL:
静态链,它是指向定义该过程的直接外过程运行时数据段的基地址。
DL:
动态链,它是指向调用该过程前正在运行过程的数据段的基地址。
RA:
返回地址,记录调用该过程时目标程序的断点,即当时的程序地址寄存器P的值。
具体的过程调用和结束,对上述寄存器及三个联系单元的填写和恢复由下列目标指令完成。
1.INT0a
a:
为局部量个数加3
2.OPR00
恢复调用该过程前正在运行过程(或主程序)的数据段的基地址寄存器的值,恢复栈顶寄存器T的值,并将返回地址送到指令寄存器P中。
3.CALla
a为被调用过程的目标程序的入口,送入指令地址寄存器P中。
CAL指令还完成填写静态链,动态链,返回地址,给出被调用过程的基地址值,送入基址寄存器B中。
部分源代码如下:
packagepl0;
importjava.util.Vector;
publicclassgenerate
{
publicwordanalysisCiFa;
publicwordword;
publicStringid=null;
//用于登录名字表时的word名字
publicintlineNum;
//用于错误处理时的行数记录
publicinterrorNumber=0;
//用于保存语法分析中的错误数目
publicErrorerror=newError();
intcx;
//VectorCode'
ssize
intcx0;
ssize,保存当前代码的地址
intdx;
//给出每层的局部量的相对地址
intlev=-1;
//记录层次
interrorNum=0;
VectorCODE=newVector();
;
//生成一个vector矢量!
//此矢量用作存放CodeElement的数组
VectorTABLE=newVector();
//生成一个存放矢量作为名字表;
publicgenerate(wordanalysisCF)//语法分析构造函数
{
CiFa=CF;
//从主程序传入一个词法分析对象,将其赋给CiFa
word=CiFa.GetWord();
//获得一个word
analyse();
//然后调用分析程序
}
publicintgetErroNumber()
returnerrorNumber;
publicvoidprintTable()//用来查看符号表内容的
for(intt=1;
t<
TABLE.size();
t++)
{
tabname=(tab)TABLE.get(t);
if(name.kind.equals("
constant"
))
name.showConst();
elseif(name.kind.equals("
variable"
name.show();
procedure"
{
//?
?
t++
t++;
tabtempname=(tab)TABLE.get(t);
//此时的name.adr为0
name.adr=tempname.adr;
//?
//System.out.println("
tempname:
"
);
//tempname.show();
}
}
publicvoidprintTable(inti)//用来查看符号表内容的
intt=i;
publicvoidprintCode()//CodeElement的显示方法,如果没有错误,则打印CodeElement代码
for(intk=1;
k<
CODE.size();
k++)
Codecode=(Code)CODE.get(k);
code.print(k);
//System.out.println(n+"
\t"
+code.getF()+"
+code.getL()
//+"
+code.getA());
//Codecode=(Code)CODE.get(n);
publicvoidprintCode(inti)//CodeElement的显示方法,如果没有错误,则打印CodeElement代码
intk=i;
/**
*语法分析
*调用常量声明、变量声明、过程声明
*递归调用analyse
*/
publicvoidanalyse()
inttx0;
lev++;
dx=3;
//初始ADR,以后每遇到一个变量,dx+1
tx0=TABLE.size();
//用tx0保存当前层的符号在符号表中的起始位置
TABLE.addElement(newtab("
"
"
0,0,0));
//在这里给符号表填加一个元素,否则下一条代码会运行出界
((tab)TABLE.get(tx0)).setAdr(CODE.size());
//在上面加的那个元素里的私有字段adr里保存当前层代码的开始位置
CODE.addElement(newCode("
jmp"
0,0));
//生成跳转指令 由于跳转位置未知 暂时添0
System.out.println("
1:
+CODE.size());
while(word.getSym().equals("
constsym"
)
||word.getSym().equals("
varsym"
procsym"
if(word.getSym().equals("
))//常量处理
word=CiFa.GetWord();
constDefine();
//调用常量声明,注意常量声明完毕时还要再次读取一个word
//若在常量声明后读取的word为逗号,则要继续进行常量声明,这里采用while循环,直到word不是逗号
while(word.getSym().equals("
sym"
{
word=CiFa.GetWord();
constDefine();
//调用常量声明,注意常量声明完毕时还要再次读取一个word
}
if(word.getSym().equals("
sym"
))//若word不是逗号,则应该是分号了,标志常量声明结束
}else
errorNumber++;
error.error(word.getLineNum(),5);
//如果常量声明完毕后没有遇到分号;
则抛出15号错误
//变量处理
elseif(word.getSym().equals("
//读取一个word,应该是一个ident标识符
varDefine();
//调用变量声明
varDefine();
//调用变量声明,注意常量声明完毕时还要再次读取一个word
//如果变量声明完毕后没有遇到分号;
则调用错误处理程序抛出5号错误
//循环声明各个子过程
//这里为什么要用while?
?
改成if语句结果也正确,主要是例子里面没有嵌套的过程吧。
while(word.getSym().equals("
ident"
id=word.getName();
add("
id);
error.error(word.getLineNum(),4);
//过程名不是标识符,抛出4号错误
}//过程名后没有分号
//保存当前的ADE和lev
inttempdx=dx;
intlevv=lev;
//在这里递归调用下一层的分程序段分析,接下来如果不是常量、变量、过程声明,
//那么就直接跳过analyse开始的while循环,开始进行语句的分析了
analyse();
dx=tempdx;
lev=levv;
//若end;
后的符号不在ident,procsym,begin,call,if,while中,则调用6号错误
Stringsym=word.getSym();
if(!
(sym.equals("
)||sym.equals("
||sym.equals("
beginsym"
callsym"
ifsym"
whilesym"
)))
{
errorNumber++;
error.error(word.getLineNum(),6);
}
//?
下面又不懂了啊!
!
//把前面生成的跳转指令的跳转位置改成当前位置
System.out.println(CODE.size());
printCode(CODE.size()-1);
((Code)CODE.get(((tab)TABLE.get(tx0)).getAdr())).setA(CODE.size());
CODE"
+((tab)TABLE.get(tx0)).getAdr());
printCode(((tab)TABLE.get(tx0)).getAdr());
//在符号表中,对于过程名,adr应填入编译该过程所生成的CodeElement指令序列的入口地址
//目前TABLE.get(tx0))里面还没有什么内容。
TABLEtx0:
+tx0);
printTable(tx0);
cx0=CODE.size();
//在cx0中保存当前代码的分配地址
int"
0,dx));
//生成空间分配指令,分配dx个空间(3个空间+变量的数目)
//printCode(cx0-2);
//printCode(cx0-1);
//printCode(cx0);
statement();
//处理当前遇到的语句;
opr"
//生成子程序返回指令;
*常量声明
*
publicvoidconstDefine()//常量声明的方法
if(word.getSym().equals("
))//在analyse调用常量声明时,上一个word为const,这一个应该是ident标识符
id=word.getName();
//调用Word类的getNam方法,获得当前word的内容,这里将其保存在id中,为的是一会进行的符号表插入工作
word=CiFa.GetWord();
//然后再读取一个word,应该是等号"
="
了
:
=sym"
errorNumber++;
error.error(word.getLineNum(),1);
//如果不是等号,而是赋值符号:
=,抛出1号错误
}elseif(word.getSym().equals("
=sy
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 报告
![提示](https://static.bingdoc.com/images/bang_tan.gif)