Sample语言编译与运行及简单虚拟机器的设计实现

记录一下编译原理课程设计的内容(Java )。这是一次课程设计,代码中有很多漏洞,欢迎来喷。

Sample语言的编译包括,词法分析,语法分析,语义分析及中间代码生成,中间代码转化为汇编代码。词法分析采用有穷自动机实现,语法分析和语义分析均为自上而下进行。中间代码转化为汇编的过程中统一采用变址寻址方式,简单粗暴,未做更多优化。

Sample语言具有一般高级语言的共同特征:字符集包括所有的大小写字母、数字和一些分界符;有多种内部数据类型:整型、实型、布尔型和字符型;语句说明包括说明语句和可执行语句;语句控制包括顺序、条件和循环3种结构。具体来说主要包括如下一些语法成分。

(1)     由字母、数字以及下划线构成的字符集。

(2)     由关键字、标识符、常数、界符和运算符构成的单词集。

(3)     有整形、布尔型、实型和字符型4中数据结构。

(4)     包括算术表达式、逻辑表达式和关系表达式3种类型的表达式;语句由说明语句和可执行语句两种类型构成;说明语句包括常量说明(用const定义)和变量说明(用var定义);可执行语句有赋值语句、if语句、while语句、do-while语句等。

(5)     程序由关键字program开头。

语法分析阶段涉及的句法如下:

算术表达式的语法定义如下。

(1)<算术表达式>::=<项> <加法运算符> <项> | <项>

(2)<项>::=<因子> <乘法运算符> <因子> | <因子>

(3)<因子>::=<标识符> | <无符号整数> |(<算术表达式>)

(4)<加法运算符>::= + | -

(5)<乘法运算符>::=* | /

布尔表达式的语法定义如下。

(1)<布尔表达式>::=<布尔项> or <布尔表达式> | <布尔项>

(2)<布尔项>::=<布尔因子> or <布尔项> | <布尔因子>

(3)<布尔因子>::=<布尔量> | !<布尔因子>

(4)<布尔量>::=<布尔表达式> | <算术表达式> <关系符> <算术表达式>

(5)<关系符>::= < | > | < > | <=| >= | == |=

if,while、for、赋值等语句的定义如下。文字表达可能不太清楚,所以用图的形式描述。


目标代码生成是将语义分析所产生的中间代码变换成目标代码,从而实现了源程序的最后翻译,此阶段的工作也是最复杂的。它的复杂性在于,翻译工作有赖于目标机器的系统结构,涉及内存的使用、指令的选择以及寄存器的调度。因此我们将四元式到机器码的翻译分为两步,第一步是四元式到汇编语言的翻译,第二步是汇编语言到机器码的翻译。

 

接下来就是简单虚拟机器的设计的实现了。该虚拟机将完成从汇编代码到二进制代码的转换,并将二进制代码加载到内存、执行。

我们首先需要设计一台抽象的计算机——虚拟裸机,包括寄存器的设计与使用、内存的设计与使用、指令格式的设计、寻址方式的设计等。

抽象计算机的虚拟硬件配置。

1、内存为256×256个单元(64K),一个单元成为一个字,一个字有两个字节,地址为0~65535。单元可以存放置零,也可以存放数据。内存单元若存放数据,则数据范围为-32768~+32767或0~65535。一条机器指令占用一个单元,若不考虑数据占用的内存单元,程序最大长度为256×256。

2、虚拟机具有四个通用寄存器(2字节)、一个标志寄存器FlagReg和一个堆栈寄存器TopReg。4个通用寄存器分别标记为R0、R1、R2、R3,除可用于存放操作数和计算结果外,还可用于变址寻址。标志寄存器FlagReg用于保存cmp指令比较结果。堆栈寄存器TopReg用作系统栈顶指针。

 

寻址方式及寄存器功能说明。

1、内存单元若存放指令,高四位(第15、14、13、12位)为操作码、低12位(11~0)

       用于描述地址。第11、10位表征第一地址,第一地址只能是寄存器。

                 00:表示第一地址为R0;

                 01:表示第一地址为R1;

                 02:表示第一地址为R2;

                 03:表示第一地址为R3;

                 第9、8位表征第二地址的寻址方式,第二地址可以是内存直接地址、寄存器或变

       址寻址,还可以是0~255范围内的直接数。

00:表示直接地址寻址(M),第二操作数在内存低地址区域,地址范围为0~255,7~0位表示内存地址。

01:表示寄存器寻址,3~0位的值可为0~3,分别表示R0~R3(实际上是用第一位和第0位)。7~4位或为0,或为1(实际上使用第5位)。0表示寄存器直接寻址(Ri),

第二操作数在寄存器Ri中;1表示寄存器间址寻址(@Ri),在寄存器Ri中存放的是第二操作数地址。

       10:表示直接数访问立即寻址(D),7~0位表示直接数,直接数范围为0~255。

       11:表示以C*255为基址,以R3为位移的变址寻址(C[R3],0≤C≤FFh),7~0位表示C。C相当于段号或页号,R3相当于段内位移或页内位移。当R3用于变址寻址时,R3仅低8位有效,地址计算公式为:C*256+(R3&0x00ff)。因二进制位有限,这里约定只有R3可以作为变址寄存器。

       2、堆栈寄存器TopReg(2字节)的初始值为0,系统堆栈从内存地址65535开始(0-1=65535)。执行call指令时,TopReg减1,系统将断点存入TopReg所指的内存单元,入口由call指令的第二地址确定;当执行ret指令时,从TopReg所指的单元获取断点,系统将TopReg增1。用户程序从地址0开始存放,CPU模拟器从该地址开始执行程序指令。在编制用户程序时,应注意和堆栈存储区域的冲突。

       3、输入输出指令无第二地址,由于第一地址只能是寄存器,故输入输出指令只能对寄存器进行操作。jmp、jmpneg、jmppos、jmpzero和call指令无第一地址。因断点在堆栈中,故ret指令无第一、第二地址。

       4、对于某些指令,某些二进制位可能不使用,在编写机器语言程序时,统一将其置位0。

 

机器语言指令描述。

1、read(0h):从键盘读一个字到第一地址。等待用户从键盘输入一个十进制数据,数值范围为-32768~+32767。数据可以空格、Tab和回车结束。在输入过程中,可利用Backspace键删除已输入的字符,也可键入Esc键终止程序执行。若输入数据中存在非法字符,则虚拟裸机拒绝接受,要求用户重新输入。

2、write(1h):从第一地址写一个字到屏幕。

3、load(2h):从第二地址将字装入第一地址。

4、store(3h):将第一地址中的字存放到第二地址。

5、call(4h):转移到第二地址指定的内存单元,执行子程序,断点保留在系统堆栈中。

6、ret(5h):由系统堆栈获得断点,返回。

7、add(6h):将第一地址中的字加上第二地址中的字,结果保留在第一地址中。

8、sub(7h):将第一地址中的字减去第二地址中的字,结果保留在第一地址中。

9、mul(8h):将第一地址中的字乘以第二地址中的字,结果保留在第一地址中。

10、div(9h):将第一地址中的字除以第二地址中的字,结果保留在第一地址中。

11、cmp(Ah):将第一地址中的字和第二地址中的字比较,由系统置位标志寄存器FlagReg。

标志寄存器FlagReg=-1,表示第一地址中的字小于第二地址中的字。

标志寄存器FlagReg=1,表示第一地址中的字大于第二地址中的字。

标志寄存器FlagReg=0,表示第一地址中的字等于第二地址中的字。

 

12、jmp(Bh):无条件转移到第二地址指定的内存单元。

13、jmpneg(Ch):若标志寄存器FlagReg中的值为-1,转移到第二地址指定的内存单元。

14、jmppos(Dh):若标志寄存器FlagReg中的值为1,转移到第二地址指定的内存单元。

15、jmpzero(Eh):若标志寄存器FlagReg中的值为0,转移到第二地址指定的内存单元。

16、halt(Fh):终止程序执行。

指令系统。

指令格式如下(16Bit):

15-12                11-10             9-8                  7-0

操作码

第一地址

寻址方式

第二地址

①    操作码

②    第一地址为寄存器(R0-R3)

③    寻址方式和第二地址

④    指令分类

 

到此为止一个简单的编译器已经完成了。测试程序中有一个辗转相减法求最大公约数和最小公倍数的例程。


运行结果如下。


上图中12和30为输入数据,输出6为最大公约数,60为最小公倍数。

代码地址:https://github.com/fhlt/Compile.git

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值