pl0语言功能扩充Word格式.docx
《pl0语言功能扩充Word格式.docx》由会员分享,可在线阅读,更多相关《pl0语言功能扩充Word格式.docx(14页珍藏版)》请在冰豆网上搜索。
![pl0语言功能扩充Word格式.docx](https://file1.bdocx.com/fileroot1/2022-10/12/ccc25180-0c92-4d14-be9e-bd5d5743c972/ccc25180-0c92-4d14-be9e-bd5d5743c9721.gif)
(1)整型一维数组,数组的定义格式为:
VAR<
数组标识名>
(<
下界>
:
<
上界>
)
其中上界和下界可以是整数或者常量标识名。
访问数组元素的时候,数组下表是整型的表达式,包括整数、常量或者变量和他们的组合。
(2)扩充条件语句,格式为:
条件语句>
=
EF<
条件>
THEN<
语句>
[ELSE<
]
(3)增加REPEAT语句,格式为:
复合语句>
REPEAT<
UNTL<
四.实验过程
(1)PL/0编译程序的C语言源代码输入
(2)运行PL/0编译程序的C语言源代码,调试运行PL/0编译程序
(3)对PL/0编译程序进行功能扩充
(4)PL/0编译程序功能扩充部分的分析与设计
(5)对PL/0编译程序进行功能扩充,即编写代码
(6)进行PL/0编译程序功能扩充部分的运行调试
(7)完成实验报告总结
五.PL/0编译程序的功能扩充程序说明
(1)扩充赋值运算:
+=,-=.此功能扩充只需在语句分析里面进行增加如下程序:
if(SYM==BECOMES||SYM==PLUSBECOMES||SYM==MINUSBECOMES){
if(SYM==BECOMES)
{
GetSym();
EXPRESSION(FSYS,LEV,TX);
}
else
if(SYM==PLUSBECOMES||SYM==MINUSBECOMES)
GEN(LOD,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);
if(SYM==PLUSBECOMES){
FACTOR(FSYS,LEV,TX);
GEN(OPR,0,2);
if(SYM==MINUSBECOMES){
GEN(OPR,0,3);
if(i!
=0)
GEN(STO,LEV-TABLE[i].vp.LEVEL,TABLE[i].vp.ADR);
(2)扩充FORTO和FORDOWNTO语句,此功能的关键是如何判断条件是否成立,并如何进行程序跳转.在这里用到了几条指令,和地址回填技术.扩充程序如下:
caseFORSYM:
if(SYM!
=IDENT)Error(31);
//FOR后面要标识符
i=POSITION(ID,TX);
if(i==0)Error(11);
else
if(TABLE[i].KIND!
=VARIABLE){/*ASSIGNMENTTONON-VARIABLE*/
Error(12);
//变量
=BECOMES)
Error(13);
EXPRESSION(SymSetUnion(SymSetNew(TOSYM,DOWNTOSYM,DOSYM),FSYS),LEV,TX);
//表达式
if(SYM==DOWNTOSYM)
CX1=CX;
//保存结果至变量单元
//重新调入栈顶
EXPRESSION(SymSetAdd(DOSYM,FSYS),LEV,TX);
GEN(OPR,0,11);
//判断运算
CX2=CX;
GEN(JPC,0,0);
//如果栈顶非真跳转
///重新调入栈顶
GEN(LIT,0,1);
//送1到栈顶
//减运算
if(SYM==DOSYM){
STATEMENT(FSYS,LEV,TX);
GEN(JMP,0,CX1);
CODE[CX2].A=CX;
elseif(SYM==TOSYM)
GetSym();
//保存结果至变量单元
/重新调入栈顶
//表达式分析
GEN(OPR,0,13);
GEN(LIT,0,1);
//回填地址
elseError(35);
break;
(3)增加条件语句的ELSE子
ELSE语句的语法语义分析程序:
caseIFSYM:
GetSym();
CONDITION(SymSetUnion(SymSetNew(THENSYM,DOSYM),FSYS),LEV,TX);
if(SYM==THENSYM)GetSym();
elseError(16);
CX1=CX;
STATEMENT(FSYS,LEV,TX);
GEN(JMP,0,CX+1);
CODE[CX1].A=CX;
if(SYM==SEMICOLON)GetSym();
if(SYM==ELSESYM)
}//addthestatementofELSE
elseSTATEMENT(FSYS,LEV,TX);
break;
(4)修改单词:
不等号#改为<
>
if(CH=='
'
)
{
GetCh();
if(CH=='
='
){SYM=LEQ;
GetCh();
if(CH=='
){SYM=NEQ;
elseSYM=LSS;
六.实验设计思想
1.设计说明
PL/0语言是Pascal语言的一个子集,这里分析的PL/0的编译程序包括了对PL/0语言源程序进行分析处理、编译生成类PCODE代码,并在虚拟机上解释运行生成的类PCODE代码的功能。
PL/0语言编译程序采用以语法分析为核心、一遍扫描的编译方法。
词法分析和代码生成作为独立的子程序供语法分析程序调用。
语法分析的同时,提供了出错报告和出错恢复的功能。
在源程序没有错误编译通过的情况下,调用类PCODE解释程序解释执行生成的类PCODE代码。
2.各功能模块描述
词法分析子程序分析:
词法分析子程序名为GETSYM,功能是从源程序中读出一个单词符号(TOTAKEN),把它的信息放入全局变量SYM、ID和NUM中,字符变量放入CH中,语法分析器需要单词时,直接从这三个变量中获得。
Getch过程通过反复调用Getch子过程从源程序过获取字符,并把它们拼成单词。
GETCH过程中使用了行缓冲区技术以提高程序运行效率。
词法分析器的分析过程:
调用GETSYM时,它通过GETCH过程从源程序中获得一个字符。
如果这个字符是字母,则继续获取字符或数字,最终可以拼成一个单词,查保留字表,如果查到为保留字,则把SYM变量赋成相应的保留字类型值;
如果没有查到,则这个单词应是一个用户自定义的标识符(可能是变量名、常量名或是过程的名字),把SYM置为IDENT,把这个单词存入ID变量。
查保留字表时使用了二分法查找以提高效率。
如果Getch获得的字符是数字,则继续用Getch获取数字,并把它们拼成一个整数或实数,然后把SYM置为INTEGER或REAL,并把拼成的数值放入NUM变量。
如果识别出其它合法的符号(比如:
赋值号、大于号、小于等于号等),则把SYM则成相应的类型。
如果遇到不合法的字符,把SYM置成NUL。
语法分析子程序分析:
语法分析子程序采用了自顶向下的递归子程序法,语法分析同时也根据程序的语义生成相应三元代码,并提供了出错处理的机制。
语法分析主要由分程序分析过程(BLOCK)、参数变量分析过程(ParaDeclaration)、参数变量处理过程(ParaGetSub)、数组处理过程(ParaGetSub)、常量定义分析过程(ConstDeclaration)、变量定义分析过程(Vardeclaration)、语句分析过程(Statement)、表达式处理过程(Expression)、项处理过程(Term)、因子处理过程(Factor)和条件处理过程(Condition)构成。
这些过程在结构上构成一个嵌套的层次结构。
除此之外,还有出错报告过程(Error)、代码生成过程(Gen)、测试单词合法性及出错恢复过程(Test)、登录名字表过程(Enter)、查询名字表函数(Position)以及列出类PCODE代码过程(Listcode)作过语法分析的辅助过程。
由PL/0的语法图可知:
一个完整的PL/0程序是由分程序和句号构成的。
因此,本编译程序在运行的时候,通过主程序中调用分程序处理过程block来分析分程序部分(分程序分析过程中还可能会递归调用block过程),然后,判断最后读入的符号是否为句号。
如果是句号且分程序分析中未出错,则是一个合法的PL/0程序,可以运行生成的代码,否则就说明源PL/0程序是不合法的,输出出错提示即可。
下面按各语法单元分析PL/0编译程序的运行机制。
分程序处理过程:
语法分析开始后,首先调用分程序处理过程(Block)处理分程序。
过程入口参数置为:
0层、符号表位置0、出错恢复单词集合为句号、声明符或语句开始符。
进入Block过程后,首先把局部数据段分配指针设为3,准备分配3个单元供运行期存放静态链SL、动态链DL和返回地址RA。
然后用Tx0记录下当前符号表位置并产生一条Jmp指令,准备跳转到主程序的开始位置,由于当前还没有知到主程序究竟在何处开始,所以Jmp的目标暂时填为0,稍后再改。
同时在符号表的当前位置记录下这个Jmp指令在代码段中的位置。
在判断了嵌套层数没有超过规定的层数后,开始分析源程序。
首先判断是否遇到了常量声明,如果遇到则开始常量定义,把常量存入符号表。
接下去用同样的方法分析变量声明,变量定义过程中会用Dx变量记录下局部数据段分配的空间个数。
然后如果