L语言编译器的设计与实现之设计篇
来源:互联网 发布:广联达2013软件下载 编辑:程序博客网 时间:2024/06/05 18:24
L语言编译器的设计与实现之设计篇
1、任务:实现一个简单的编译程序,能够对指定程序设计语言进行编译。
编译器组成成分:
1.扫描器
该扫描器是一个子程序,其输入是源程序字符串,每调用一次输出一个单词符号。为了避免超前搜索,提高运行效率,简化扫描器的设计,假设程序设计语言中,基本字不能用作一般标识符,如果基本字、标识符和常数之间没有确定的运算符或界符作间隔,则用空白作间隔。
2.语法分析器
以算法优先分析方法为例,设计一个算符优先语法分析程序。算符优先分析属于自下而上的分析方法,该语法分析程序的输入是终结符号串(即单词符号串,以一个“#”结尾),如果输入串是句子则输出“YES”,否则输出“NO”和错误信息。当然,也可采用预测分析等方法设计语法分析器,具体方法自定。
3.语法制导翻译程序
采用语法制导翻译方法,实现算术表达式、赋值语句和基本控制语句等的翻译。本语法制导翻译程序的输入是终结符号串(即单词符号串,以一个“#”结尾),如果输入符号串是句子,则按照其语义进行翻译,输出等价的四元式序列。
4.目标代码生成器
将程序设计语言的中间代码程序翻译为目标代码程序,其输入是四元式序列,输出是一个汇编代码文件。
每个环节可作为一个独立的实践课题,分别编程调试,然后再连接在一起总调,从而实现一个完整的编译器。
2、L语言定义
程序定义:
〈程序〉→ program〈标识符〉〈程序体〉.
〈程序体〉→〈变量说明〉〈复合句〉
变量定义:
〈变量说明〉→ var〈变量定义〉|ε
〈变量定义〉→〈标识符表〉:〈类型〉;|〈标识符表〉:〈类型〉;〈变量定义〉
〈标识符表〉→〈标识符〉,〈标识符表〉|〈标识符〉
语句定义:
〈复合句〉→ begin〈语句表〉end
〈语句表〉→〈执行句〉;〈语句表〉|〈执行句〉 (执行句:while , If ,赋值语句)
〈执行句〉→〈简单句〉|〈结构句〉
〈简单句〉→〈赋值句〉
〈赋值句〉→〈变量〉:=〈表达式〉
〈变量〉→〈标识符〉
〈结构句〉→〈复合句〉|〈if句〉|〈WHILE句〉
〈if句〉→ if〈布尔表达式〉then〈执行句〉| if〈布尔表达式〉then〈执行句〉else〈执行句〉
〈while句〉→ while〈布尔表达式〉do〈执行句〉
表达式定义:
〈表达式〉→〈算术表达式〉|〈布尔表达式〉
〈算术表达式〉→〈项〉+〈算术表达式〉|〈项〉-〈算术表达式〉|〈项〉
〈项〉→〈项〉*〈因子〉|〈项〉/〈因子〉|〈因子〉
〈因子〉→〈算术量〉
〈算术量〉→〈标识符〉|〈整数〉|〈实数〉
〈布尔表达式〉→〈布尔项〉or〈布尔表达式〉|〈布尔项〉
〈布尔项〉→〈布尔因子〉and〈布尔项〉|〈布尔因子〉
〈布尔因子〉→ not〈布尔因子〉|〈布尔量〉
〈布尔量〉→〈布尔常数〉|〈标识符〉|(〈布尔表达式〉)|〈关系表达式〉
〈关系表达式〉→〈标识符〉〈关系运算符〉〈标识符〉
〈关系运算符〉→〈|〈= |=|〉=|〉|〈〉
类型定义:
〈类型名〉→ integer|bool | real
单词定义:
〈标识符〉→〈字母〉|〈标识符〉〈字母〉|〈标识符〉〈数字〉
〈整数〉→〈数字〉|〈整数〉〈数字〉
〈实数〉→〈整数〉.|〈实数〉〈数字〉
〈布尔常数〉→ true|false
字符定义:
〈字母〉→ A│B│C│D│E│F│G│H│I│J│K│L│M│N│O│P│Q│R│S│T│
U│V│W│X│Y│Z│a│b│c│d│e│f│g│h│i│j│k│l│m│n│o│
p│q│r│s│t│u│v│w│x│y│z
〈数字〉→ 0│1│2│3│4│5│6│7│8│9
3、源程序书写格式规定
(1) 单词必须在一行内写完,即:一个单词不能分两行写;
(2) 源程序语句的书写采用自由格式,即:一行可写多个语句,一个语句也可分多行写;
(3) 源程序不含注释;
(4) 语句以“;”结束,“end”前的一个语句的“;”不可以省略。
第二节 词法分析
1、目的
通过设计调试词法分析程序,实现从源程序中分出各种单词的方法;加深对课堂教学的理解;提高词法分析方法的实践能力;掌握词法分析器作为子程序以及一遍的处理过程。
2、任务
(1) 能对任何L语言源程序进行分析;
(2) 采用问答方式输入源程序文件名,然后进行词法分析;
(3) 分割单词并转换成机内表示形式,形成token文件(单词序列)、符号表文件;
(4) 删除空格等无用符号;
(5) 错误处理
l 给出的错误信息包括:总的出错个数,每个错误所在行号,错误编号及说明;
l 只处理以下两种错误,其它可不必考虑
1.非法字符:删除,即,不写入token文件
2.错误单词
a)包括三种形式:
i.数字开头的数字、字母串,如:3a56
ii.实数中出现两个小数点,如:3.14.15
iii.实数的小数部分出现字母,如:5.26B78
b)处理方式:截去后面出错部分,使其成为一个正确单词(即:常数)。如:3a56转换为3,3.14.15转换为3.14,5.26B78转换为5.26
3、数据结构
3.1输入
L源程序,为文本文件。
3.2输出
一个单词序列文件(即:token文件)和一个符号表文件,并输出错误信息。
(1) token文件结构
typedef struct token
{
int label; //单词序号
char name[30]; //单词本身
int code; //单词的机内码
int addr; //地址,单词为保留字时为-1,为标识符或常数时为大于0的数值,即在符号表中的入口地址。
} token;
单词的机内码表示:
(2) 符号表文件结构
符号表用来存放L语言源程序中出现的标识符和常数,文件结构如下:
typedef struct symble
{
intnumber; //序号
inttype; //类型
charname[30]; //名字
} symble;
4、词法分析程序流程图
第三节 语法/语义分析
1、目的
通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
2、任务
在词法分析程序产生的token文件、符号表文件基础上,完成语法和语义分析,产生相应的中间代码——四元式序列。在此,可把语法/语义分析作为独立的一遍进行处理。
采用如下四元式:
操作码助记符
四元式
意 义
:=
( 51, a, 0, r )
r←a
+
( 43, a, b, r )
r←a+b
-
( 45, a, b, r )
r←a-b
*
( 41, a, b, r )
r←a*b
/
( 48, a, b, r )
r←b/a
j<
( 53, a, b, n )
若a<b转至第n个四元式
j<=
( 54, a, b, n )
若a<=b转至第n个四元式
j>
( 57, a, b, n )
若a>b转至第n个四元式
j>=
( 58, a, b, n )
若a>=b转至第n个四元式
j =
( 56, a, b, n )
若a=b转至第n个四元式
j
( 52, 0, 0, n )
转至第n个四元式
j <>
( 55, a, b, n )
若a<>b转至第n个四元式
3、数据结构
3.1输入
token文件、符号表文件,其数据结构与词法分析产生的文件相同。
3.2输出
l 四元式序列文件,其纪录结构如下:
typedef struct equ
{
int op; //四元式操作码
int op1; //操作数在符号表中的入口地址
int op2; //操作数在符号表中的入口地址
int result; //结果变量在符号表中的入口地址
} equ;
l 程序中可用数组Equ存放四元式序列,定义为:equ Equ[EQU_LEN]
l 可用变量int LineOfEqu做指针,指向下一个即将产生的四元式
l 符号表文件的结构与输入相同,语法分析中对于符号表不做操作,只是在文件头部增加一个记录变量多少的数据。
4、程序结构说明
为方便编程,将语言文法整理如下:
L→S| S ; L
S→id:= E
S→ifB then S
S→ifB then S else S
S→whileB do S
S→beginL end
变量说明语句的文法:
S→varD|ε
D→L: K ; | L : K ; D
L→i, L | i
K→integer| bool | real
其中,B表示布尔表达式,E表示算术表达式
可采用递归下降分析法或其它方法进行语法分析。语法/语义分析程序可划分为三个模块,结构如下:
第四节 目标代码生成
1、目的
实践目标代码的生成方法。
2、任务
编写一个目标代码生成程序,将L语言的中间代码程序翻译为目标代码程序(汇编语言程序),如下图:
目标机说明:
l 以8086微处理机为目标机,生成8086汇编指令
l 8086是16位微处理器,数据总线为16位,地址总线为20位,可寻址1MB的空间
l 8086有8个16位通用寄存器和一个标志寄存器。这8个寄存器AX-DI都可以用作累加器。其中,BX和BP(基地址指针)寄存器通常用于指定数据区的基址,称为基址寄存器,SI和DI大多用来表示相对基址的偏移量,称为变址寄存器
l 8086的地址空间是分段的,每段64KB
l 简单起见,本实验不涉及段间寻址,数据与代码都放在一个段内
l 实验中选用以下寻址功能,圆括号表示取其内容:
n 寄存器寻址: MOV AX,BX;
功能:AX←(BX)
n 直接寻址:MOV AX,DATA;
功能:AX←(DATA)
l 常用指令:
n 传送指令:r表示寄存器,m表示内存单元
MOV r, r/m r←(r/m), r/m表示r或m
MOV r/m, r r/m←(r)
MOV r/m, imm r/m←imm, imm是立即数
n 运算指令:包括ADD,SUB,MUL,DIV,CMP等。下面以ADD为例说明其用法:
ADD r, r/m r←(r)+(r/m)
ADD r/m, r/imm r/m←(r/m)+(r)或imm
n CMP只影响标志位,不影响操作数的大小
n 转移指令:Z是标志位,S是符号位,O是溢出位
指令码
意义
条件
JZ, JE
结果为0或相等则转
Z=1,(A) = (B)
JNZ, JNE
结果不为0或不相等则转
Z=0,(A)≠(B)
JNL, JGE
大于等于转
(S∨O)=0,(A)≥(B)
JL, JNGE
小于转
(S∨O)=1,(A)<(B)
JG, JNLE
大于转
(S∨O∨Z)=0,(A)>(B)
JMP
无条件转移
3、数据结构
3.1输入
四元式序列文件和符号表文件,其结构与语法/语义分析程序的输出一致。
3.2输出
一个汇编代码文件,并无特殊数据结构。
4、程序参考结构:
将中间代码程序(四元式序列)翻译成汇编程序可按以下步骤进行:
(1) 划分基本块
(2) 对每个基本块生成基本块的目标代码
为了划分和记录基本块,对四元式结构作以下修改:
typedef struct GenStruct
{
int label;
char op[4];
int code;
int addr1;
int addr2;
int result;
int out_port; //记录该四元式是否为一个基本块的入口,是则为1,否则为0。
} GenStruct;
5、寄存器分配策略
主要采用四个通用寄存器:ax, bx, cx, dx, 其中,ax, cx的作用固定,ax用作累加器,cx用作循环计数器,在四元式翻译时直接应用不再分配。所以分配策略只用于bx与dx,具体算法如下:
if (bx未被使用或已分配给了变量a) {
bx分配给变量a;
}
else {
if (dx未被使用或已分配给了变量a){
dx分配给变量a;
}
else {
其它策略;
}
}
注:a为变量在符号表的入口地址。
6、代码生成器的模块结构及说明
实现时,整个程序的四元式表和目标代码文件说明为全局数据。调用划分基本块模块之后,返回新的四元式序列(带入口标记)。先根据基本块的入口,再查找下一入口,两个入口之间就是该基本块。
下一篇:L语言编译器的设计与实现之实践篇(一)
- L语言编译器的设计与实现之设计篇
- 编译器的设计与实现(1)-编译器的组成
- 一个脚本设计语言的设计与实现
- C-编译器的设计
- Linux:Shell语言实现《考试控制系统的设计与实现》
- Monster Card Game的设计与实现之框架篇
- Monster Card Game的设计与实现之服务器篇
- Monster Card Game的设计与实现之客户端篇
- GCC编译器下的-L与-l的区别
- GCC编译器下的-L与-l的区别
- GCC编译器下的-L与-l的区别
- GCC编译器下的-L与-l的区别
- 基于C语言的内存池的设计与实现
- 基于C语言的内存池的设计与实现
- 基于C语言的内存池的设计与实现
- 基于C语言的内存池的设计与实现
- 基于C语言的内存池的设计与实现
- 基于C语言的图书管理信息系统的设计与实现
- HIVE2 Error: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteExc
- Tabs
- dsp28335 IIC总结
- 第十六周oj题目计算该日是本年的第几天
- What's the difference between mvn:deploy and mvn:install commands?
- L语言编译器的设计与实现之设计篇
- tcp_sendmsg函数实现分析
- Spring AOP 记录日志
- Mybatis最入门---代码自动生成(generatorConfig.xml配置)
- python+selenium:不会定位元素----使用firepath工具
- 文档表示
- 这才是Angular2的灵魂!
- HTML5学习随笔02
- 各种标签去除