PLX编译程序改进与扩展设计书.docx
《PLX编译程序改进与扩展设计书.docx》由会员分享,可在线阅读,更多相关《PLX编译程序改进与扩展设计书.docx(34页珍藏版)》请在冰点文库上搜索。
PLX编译程序改进与扩展设计书
PL/X编译程序改进及扩展设计书
1介绍
1.1前言
根据课程设计要求制作PL/X语言的编译器,完成词法分析、语法分析、语义分析及代码生成、出错处理和解释运行程序,并添加一定的扩展,最终实现一个PL/X的编译器。
所完成扩展点说明:
1)支持三种注释
a)单行注释
b)/*---*/多行注释
c)(*---*)多行注释
2)支持read语句,因此可从终端获取输入
3)支持write语句,因此可从终端输出
4)支持for语句
5)支持do…while语句
6)call过程
7)求余运算%
8)整数的奇偶odd
9)幂运行**
10)求阶乘!
11)求和$
关于出错处理:
分为词法分析错误、句法分析错误、运行时错误(如除数为0)
允许变量名或函数名重复,但访问的时候以最后一次声明的为有效
2编译器
2.1PL/X编译器结构概述
图1PL/X编译程序的结构图
图2PL/X的解释执行结构
图3PL/X编译程序总体流程图
语法分析过程PROG是整个编译过程的核心,是指开始由主程序调用GETSYM取一个单词,再调用语法分析过程PROG,PROG由当前单词根据语法规则再调用其它过程,如说明处理、代码生成或出错处理等过程进行分析,当分析完一个单词后,PROG再调用GETSYM取下一个单词,一直重复到当前单词为结束符"."表明源程序已分析结束。
若未取到结束符".",而源程序已没有输入符号,这时表明源程序有错误,无法再继续分析。
图4PL/X过程调用相关示意图
2.2语法元素
关键字:
"and","begin","call","case","constant","do","else","end","false","for","if","integer","logical","not","or",“odd”,"procedure","program","read","repeat","switch","then","true","until","while","write"
操作符:
".",";","**","++",“--","+","-","*","/","%","=","<","<=",">",">=","==","!
","+=","-=","*=","/="
2.3语法图
程序
程序体
const
ident
number
=
var
;
ident
procedure
ident
;
;
程序体
;
语句序列
语句
条件
表达式
odd
表达式
=
<>
<
>
<=
>=
表达式
表达式
项
因子
因子
/
*
++
%
**
--
因子
1)prog="program"ds{proc}"begin"ss"end""."
2)proc="procedure"aident[ds]"begin"ss"end"
3)ds=d{";"d}
4)d="integer"aident{","aident}|
"logical"bident{","bident}|
"constant"aident"="number{","aident"="number}
5)ss=s{;s}
6)s=aident":
="ae|
bident":
="be|
"if"be"then"ss["else"ss]"end"|
"while"be"do"ss"end"|
"repeat"ss"until"be|
"write"ae.
"read"aident|bident
"for"s;be;s"do"ss"end"
"call"procedure
"do"ss".""while"be"end"
7)ae=["-"]at{("-"|"+")at}
8)at=af1{("*"|"/")af1}.
9)af1=af{("%"|"**")af}.//扩展的求余运算
10)af=aident|number|"("ae")"|constant
11)be=bt{"or"bt}
12)bt=bf{"and"bf}
13)bf=bident|"true"|"false"|"not"bf|"("be")"|re1
14)re1=oddre
15)re=(aident|number)("="|">"|">="|"<"|"<="|"/=")ae
16)ds=d{";"d}
2.4判断是否符合两条限制规则
1)结构:
B1={proc}
First(B1)={“procedure”};
Follow(B1)={“begin”};
B2=[ds]
First(B2)={“integer”,“logical”,“constant”};
Follow(B1)={“begin”};
B3={";"d}
First(B3)={“;”};
Follow(B3)={“procedure”,“begin”};
B4={","aident}
First(B4)={“,”};
Follow(B4)={“;”,“procedure”,“begin”};
B5={","bident}
First(B5)={“,”};
Follow(B5)={“;”,“procedure”,“begin”};
B6={","aident"="number}
First(B6)={“,”};
Follow(B6)={“;”,“procedure”,“begin”};
B7={;s}
First(B7)={“;”};
Follow(B7)={“end”,“until”,“else”};
B8=["else"ss]
First(B8)={“else”};
Follow(B8)={“end”};
B9=["-"]
First(B9)={“-”};
Follow(B9)={“(”,“aident”,“number”,“constant”};
B10={("-"|"+")at}
First(B10)={“-”,“+”};
Follow(B10)={“end”,“until”,“else”,“)”,“and”,“or”};
B11={"or"bt}
First(B11)={“or”};
Follow(B11)={“then”,“do”,“;”,“)”,“end”,“until”,“else”};
B12={("*"|"/")af}
First(B12)={"*","/"};
Follow(B12)={“+”,“-“,“end”,“until”,“else”,“)”,“and”,“or”};
B13={"and"bf}
First(B13)={"and”};
Follow(B13)={“or”,“then”,“do”,“;”,“)”,“end”,“until”,“else”};
2).判断是否符合两条限制规则
规则1:
找出图中每一个分支点,考察每个分支点的各个分支的头符号是否相异
规则2:
找出图中每一个结构,考察每个结构的头符号集合与其跟随符号是否相异
非终结符名
开始符号集合
后继符号集合
分程序
constvarprocedureidentifcallbeginwhilereadwrite
.;
语句
identcallbeginifwhilereadwrite
.;end
条件
odd+-(
identnumber
thendo
表达式
+-(
identnumber
.;)
ropendthendo
项
identnumber(
.;)
rop+-
endthendo
因子
identnumber(
.;+
-*/
endthendo
表5PL/X文法非终结符的开始符号与后继符号集合表
判断结果:
根据两条限制规则,发现该语法图分析符合两条限制规则
2.5语法出错表定义
无,出错信息均以字符串的形式在程序中标出。
3虚拟机
3.1虚拟机组织结构
程序存储器指令存储器数据存储区
程序地址寄存器基本地址寄存器地址寄存器
1)程序存储器
指令类型
enumfct{lit,opr,lod,sto,cal,
Int,jmp,jpc
};
指令
typedefstructinstruction{
fctf;
intl;
inta;
}Instruction;
指令数组
Instructioncode[InMax];
2)指令寄存器
inti;
3)数据存储器
intstack[StMax]
4)程序地址寄存器
intp;
5)基本地址寄存器
intb;
6)地址寄存器
intt;
3.2虚拟机指令格式
编译程序所产生的目标代码是一个假想栈式计算机的汇编语言,可称为类PCODE指令代码,它不依赖任何具体计算机,其指令集极为简单,指令格式也很单纯,其格式如下:
f
l
a
其中f代表功能码,l表示层次差,也就是变量或过程被引用的分程序与说明该变量或过程的分程序之间的层次差。
a的含意对不同的指令有所区别,对存取指令表示位移量,而对其它的指令则分别有不同的含义,见下面对每条指令的解释说明。
目标指令有8条:
①LIT:
将常量值取到运行栈顶。
a域为常数值。
②LOD:
将变量放到栈顶。
a域为变量在所说明层中的相对位置,l为调用层与说明层的层差值。
③STO:
将栈顶的容送入某变量单元中。
a,l域的含意同LOD指令。
④CAL:
调用过程的指令。
a为被调用过程的目标程序入口地址,l为层差。
⑤INT:
为被调用的过程(或主程序)在运行栈中开辟数据区。
a域为开辟的单元个数。
⑥JMP:
无条件转移指令,a为转向地址。
⑦JPC:
条件转移指令,当栈顶的布尔值为非真时,转向a域的地址,否则顺序执行。
⑧OPR:
关系运算和算术运算指令。
将栈顶和次栈顶的容进行运算,结果存放在次栈顶,此外还可以是读写等特殊功能的指令,具体操作由a域值给出。
(详见解释执行程序)。
指令功能表
LIT0a
将常数值取到栈顶,a为常数值
LODla
将变量值取到栈顶,a为偏移量,l为层差
STOla
将栈顶容送入某变量单元中,a为偏移量,l为层差
CALla
调用过程,a为过程地址,l为层差
INT0a
在运行栈中为被调用的过程开辟a个单元的数据区
JMP0a
无条件跳转至a地址
JPC0a
条件跳转,当栈顶布尔值非真则跳转至a地址,否则顺序执行
OPR00
过程调用结束后,返回调用点并退栈
OPR01
栈顶元素取反
OPR02
次栈顶与栈顶相加,退两个栈元素,结果值进栈
OPR03
次栈顶减去栈顶,退两个栈元素,结果值进栈
OPR04
次栈顶乘以栈顶,退两个栈元素,结果值进栈
OPR05
次栈顶除以栈顶,退两个栈元素,结果值进栈
增加了除数为0的判断
OPR06
栈顶元素的奇偶判断,结果值在栈顶
OPR07
OPR08
次栈顶与栈顶是否相等,退两个栈元素,结果值进栈
OPR09
次栈顶与栈顶是否不等,退两个栈元素,结果值进栈
OPR010
次栈顶是否小于栈顶,退两个栈元素,结果值进栈
OPR011
次栈顶是否大于等于栈顶,退两个栈元素,结果值进栈
OPR012
次栈顶是否大于栈顶,退两个栈元素,结果值进栈
OPR013
次栈顶是否小于等于栈顶,退两个栈元素,结果值进栈
OPR014
栈顶值输出至屏幕
OPR015
屏幕输出换行
OPR016
从命令行读入一个输入置于栈顶
OPR017
扩展求余
OPR018
扩展求幂
4程序设计
4.1全局变量、全局常量
#defineNumber26//保留字的个数
#defineTXMAX100//标识符表的长度
#defineInMax200//指令最多条数
#defineLeMax3//过程最大嵌套层次
#defineStMax500//最大栈长
#defineIMax10//标识符最长长度
#defineDMax14//数字允许的最长位数v
#defineAddMax2048//最址
charch;//最近一次从程序中读出的字符
charsym[IMax];//最近读出的符号
charid[IMax];//最近读出的标识符
intnum;//最近读出的数值
intcc;//行缓冲区指针
intll;//行缓冲区长度
intkk;//提高性能
charline[100];//行缓冲区
chara[IMax];//存放当前正在分析的词
intlineno;//当前分析的行号
inttx=0;//符号表序号
intindex;//指令索引
charssym[13][IMax];//符号对应的符号表
charfsym[33][IMax];//用于出错处理
interr;//记录错误数量
intstack[StMax];
FILE*file;//指向要编译的源文件
charword[Number][IMax]={//保留字
"and",
"begin",
"call",
"case",
"constant",
"do",
"else",
"end",
"false",
"for",
"if",
"integer",
"logical",
"not",
"or",
"odd",
"procedure",
"program",
"read",
"repeat",
"switch",
"then",
"true",
"until",
"while",
"write"
};
charwsym[Number][IMax]={//保留字对应的符号表
"andsym",
"beginsym",
"callsym",
"casesym",
"constsym",
"dosym",
"elsesym",
"endsym",
"falsesym",
"forsym",
"ifsym",
"intesym",
"logisym",
"notsym",
"orsym",
"oddsym",
"procsym",
"progsym",
"readsym",
"repeasym",
"switcsym",
"thensym",
"truesym",
"untilsym",
"whilesym",
"writesym"
};
charD_first[4][IMax]={//声明语句头符号集
"intesym",
"logisym",
"constant",
"over"
};
charD_follow[3][IMax]={//声明语句跟随符号集
"beginsym",
"procsym",
"over"
};
charS_first[11][IMax]={//语句的头符号集
"adient",
"ifsym",
"whilesym",
"repeasym",
"writesym",
"forsym",
"callsym",
"readsym",
"dosym",
"switcsym",
"over"
};
charS_follow[7][IMax]={//语句的跟随符号集
"endsym",
"elsesym",
"untilsym",
"dosym",
"period",
"over"
};
enumfct{//指令类型
lit,
opr,
lod,
sto,
cal,
Int,
jmp,
jpc
};
enumobjekt{//标识符类型
integer,
logical,
procedure,
constant
};
typedefstructinstruction{
fctf;
intl;
inta;
}Instruction;
Instructioncode[InMax];//指令数组
typedefstructTable{//符号表定义
charname[IMax];
objektkind;
intadr;
intlevel;
intsize;
}Table;
Tabletable[TXMAX];//符号表
4.2函数接口
函数原型
voidgetch()
参数描述
函数描述
从源文件中读取字符
返回值
函数原型
voidgetsym()
参数描述
函数描述
从源文件中取出字符串
返回值
函数原型
voidinit()
参数描述
函数描述
初始化ssym
返回值
函数原型
voidError(char*s1)
参数描述
s1:
出错信息
函数描述
打印错误
返回值
函数原型
voidenter(objekttype,int*pdx,intlev)
参数描述
type:
符号类型
pdx:
当前层次偏移量
lev:
符号层次
函数描述
符号记入符号表
返回值
函数原型
boolIsIn(chars1[][IMax])
参数描述
s1符号字符串数组
函数描述
检查当前符号是否在期望符号集合中
返回值
true:
:
在false:
不在
函数原型
boolss(intlev)
参数描述
lev:
当前层次
函数描述
ss=s{;s}
返回值
函数原型
intposition(char*id)
参数描述
id:
所查询的符号
函数描述
在符号表中查询符号
返回值
id在符号表中序号,返回-1表示不存在
函数原型
voidUnion(chars1[][IMax],chars2[][IMax])
参数描述
S1,s2为要合并的字符串数组
函数描述
用于出错处理:
合并开始符与跟随符集合
返回值
函数原型
voidtest(chars1[][AL],chars2[][AL],char*err)
参数描述
S1:
此程序段的跟随符集合
S2:
此程序段的开始符集合
err:
错误信息
函数描述
当前符号是否在期望符号集中,否则报错并跳过
返回值
函数原型
voidgen(fctx,inty,intz)
参数描述
x:
指令名
y,z:
指令对应参数
函数描述
生成指令
返回值
函数原型
boolprog()
参数描述
函数描述
prog="program"ds{proc}"begin"ss"end""."
返回值
函数原型
boolproc(intlev)
参数描述
lev:
此过程层次
函数描述
proc="procedure"aident[ds]"begin"ss"end"
返回值
函数原型
boolds(int*pdx,intlev)
参数描述
pdx:
当前层次偏移量
lev:
当前层次
函数描述
ds=d{";"d}
返回值
函数原型
boold(int*pdx,intlev)
参数描述
pdx:
当前层次偏移量
lev:
当前层次
函数描述
d="integer"aident{","aident}|
"logical"bident{","bident}|
"constant"aident"="number{","aident"="number}
返回值
函数原型
bools(intlev)
参数描述
lev:
当前层次
函数描述
aident":
="ae|
bident":
="be|
"if"be"then"ss["else"ss]"end"|
"while"be"do"ss"end"|
"repeat"ss"until"be|
"write"ae.
"read"aident|bident
"for"s;be;s"do"ss"end"
"call"aident
"do"ss".""while"be"end"
返回值
函数原型
boolae(intlev)
参数描述
lev:
当前层次
函数描述
ae=["-"]at{("-"|"+")at}
返回值
函数原型
boolat(intlev)
参数描述
lev:
当前层次
函数描述
at=af1{("*"|"/")af1}
返回值
函数原型
boolaf1(intlev)
参数描述
lev:
当前层次
函数描述
af1=af{("**"|"%")af}
返回值
函数原型
boolaf(intlev)
参数描述
lev:
当前层次
函数描述
af=