PL/0编译程序的简单实现

本文详细介绍了PL/0编译程序的关键组件,包括代码参考、结构图、GetCH和GetSym函数,以及PL/0的EBNF文法表示。内容涵盖了词法分析、语法解析规则、错误处理和目标代码的存储分配。深入理解了PL/0语言的编译过程和执行机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PL-0

代码参考

介绍

PL/0编译程序的简单实现

PL0编译程序的结构图与解释执行结构

image-20210602084502128

函数功能说明表

image-20210602084731130

过程和函数嵌套定义结构

image-20210602084903270

总体流程图

image-20210602084934596

GetCH()

GetSym()

在这里插入图片描述

词法分析程序GETSYM将完成下列任务:

  1. 空格;

  2. 识别保留字;

  3. 识别标识符;

  4. 拼数;

  5. 拼复合词,如:>=、:=、<=等单词;

  6. 输出源程序

在GETSYM中要调用GETCH,其功能是取字符。

BLOCK

image-20210602090317143

语法描述

image-20210602085102960

image-20210602085141112

image-20210602085211722

image-20210602085440556

image-20210602085519105

image-20210602085544509

image-20210602085634215

PL/0文法的EBNF表示

EBNF表示的符号说明

  • ‘< >’ 用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,为非终结符。

  • ‘::=’ 该符号的左部由右部定义,可读作“定义为”。

  • ‘|’ 表示“或”,为左部可由多个右部定义。

  • ‘{ }’ 表示花括号内的语法成分可以重复。在不加上下界时可重复0到任意次数,有上下界时为可重复次数的限制。

  • ‘[ ]’ 表示方括号内的成分为任选项。

  • ‘( )’ 表示圆括号内的成分优先。

上述符号称“元符号”,定义文法用到上述符号作为文法符号时需要引号 ‘’括起。

PL/0语言文法的EBNF表示:

  • <程序> ::= <分程序>.
  • <分程序> ::= [<常量说明部分>][<变量说明部分>][<过程说明部分>]<语句>
  • <常量说明部分> ::= CONST<常量定义>{,<常量定义>};
  • <常量定义> ::= <标识符>=<无符号整数>
  • <无符号整数> ::= <数字>{<数字>}
  • <变量说明部分> ::= VAR<标识符>{,<标识符>};
  • <标识符> ::= <字母>{<字母>|<数字>}
  • <过程说明部分> ::= <过程首部><分程序>{;<过程说明部分>};
  • <过程首部> ::= PROCEDURE<标识符>;
  • <语句> ::= <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<复合语句>|<空>
  • <赋值语句> ::= <标识符>:=<表达式>
  • <复合语句> ::= BEGIN<语句>{;<语句>}END
  • <条件> ::= <表达式><关系运算符><表达式>|ODD<表达式>
  • <表达式> ::= [+|-]<项>{<加法运算符><项>}
  • <项> ::= <因子>{<乘法运算符><因子>}
  • <因子> ::= <标识符>|<无符号整数>| ‘(’<表达式> ‘)’
  • <加法运算符> ::= +|-
  • <乘法运算符> ::= * | /
  • <关系运算法>::== | # | < | <= | > | >=
  • <条件语句> ::= IF<条件>THEN<语句>
  • <过程调用语句> ::= CALL<标识符>
  • <当型循环语句> ::= WHILE<条件>DO<语句>
  • <读语句> ::= READ‘(’<标识符>{,<标识符>} ‘)’
  • <写语句> ::= WRITE‘(’<表达式>{,<表达式>} ‘)’
  • <字母> ::= a|b|……|X|Y|Z
  • <数字> ::= 0|1|2|……|8|9

PL/0语言出错编号表

出错编号出错原因
1常数说明中的=写成:=
2常数说明中的=后应是数字
3常数说明中的表示符(标识符?)后应是=
4constvarprocedure后应是标识符
5漏掉了.;
6过程说明后的符号不正确(应是语句开始符,或过程定义符)
7应是语句开始符
8程序题内语句部分的后跟符不正确
9程序结尾丢了句号.
10语句之间漏了;
11标识符未说明
12赋值语句中,赋值号左部标识符属性应是变量
13赋值语句左部标识符后应是赋值号:=
14call后应为标识符
15call后标识符属性应为过程
16条件语句中丢了then
17丢了end;
18while型循环语句中丢了do
19语句后的符号不正确
20应为关系运算符
21表达式内标识符属性不能是过程
22表达式中漏掉右括号)
23因子后的非法符号
24表达式的开始符不能是此符号
31数越界
32过程嵌套层数大于最大允许的套层数
33read、write语句的后跟符应为)
34read、write保留字后应接(
35read语句中标识符应为变量
36read、write语句括号中应接标识符

PL/0编译程序的目标代码解释执行时的存储分配

​ 当编译程序经过语法分析,如果未发现错误时,由编译程序调用解释程序,对放在CODE中的目标代码从CODE[0]开始进行解释执行。当解释结束后,记录源程序中标示符的TABLE表已经没有作用了,因此存储区只需要以数组CODE存放的只读目标代码程序和运行时的数据区S,S是由解释程序定义的一维整型数组。由于PL/0语言的目标代码是一种假想的栈式计算机的汇编语言,用PASCAL语言解释执行,解释执行时的数据空间S为假栈式计算机存储空间。遵循后进先出规则,对每个过程当被调用时,才分配数据空间,退出程序时,则所有分配的数据被释放。

解释程序定义了4个寄存器。

​ I:指令寄存器。存放着当前正在执行的一条目标指令;

​ P:程序地址寄存器。指向下一条要执行的目标指令的地址(相当于CODE数组的下标);

​ T:栈顶寄存器。栈顶寄存器T指出了当前栈中最新分配单元。

​ B:基址寄存器。指向每个过程被调用时,在数据区S中给它分配的数据段起始地址。

由于每个过程当它运行时,给他分配的数据空间(数据段)可分为两部分:

​ 静态部分 包括变量存放区和三个联系单元(SL、DL、RA);

​ 动态部分 作为临时工作单元和累加器使用。需要随时分配,用完后立即释放。

​ 为了实现对每个过程调用时给它分配数据段,也就是对即将运行的过程所需数据段进栈;过程运行结束后释放数据段,即数据段退栈;以及嵌套过程之间对标识符引用的寻址问题。

每个过程被调用时,在栈顶分配三个联系单元:

​ SL静态链:它指向定义该过程的直接外接过程的数据段基地址;

​ DL 动态链:它指向调用该过程前正在运行过程的数据段基地址;

​ RA 返回地址:记录调用该过程是目标程序的断点,即当时程序的地址寄存器P的值,也就是调用过程指令的下一条指令的地址。

​ PL/0编译程序给变量分配的地址只是确定变量在数据段内的相对位置。对每个过程从DX := 3开始顺序增加。3以前的三个单元为上面指出的三个联系单元(SL、DL、RA)。因此静态连接的作用是当一个过程引用包围它的过程所定义的标识符时,首先沿静态链跳过个数为层差的数据段,找到定义该标识符过程的数据段基地址,再加上所给标识符分配的相对位置,就得到该标识符在整个数据栈中的绝对位置。动态链和返回地址的作用是当一个过程结束后,为恢复调用该过程前的执行状态而设置的。

例如,从后面的图中可以看出,当程序执行进入C过程后,在C中又调用B过程时,数据取栈中的状况,这时过程B的静态链是指向过程A的基地址的,而不是指向C的基地址。因为过程B是由A定义的,他的名字在A层的名字表中,当在C过程中调用B过程时,层差为2,所以这时应沿C过程数据的静态链,跳过两个数据段后的基地址,才是当前调用的B过程的静态链之值。这里可以看出,不管B过程在何时被调用,它的数据段静态链总是指向定义它的A过程的最新数据段基地址。

具体的过程调用和结束,对上述寄存器及三个联系单元的填写和恢复有下列目标指令完成。

(1)INT 0 A

​ 每个过程目标程序的入口都有这样一条指令,用以完成开辟数据段的工作。A域的值指出数据段的大小,即为局部变量个数+3(3个联系单元)。由编译程序的代码生成给出。开辟数据段的结果是改变栈顶寄存器T的值,T:=T+A。

image-20210527101740636

(2) OPR 0 0

​ 是每个过程出口处的一条目标指令。用已完成该过程运行结束后释放数据段的工作。恢复调用该过程前正在运行的过程的数据段基地址寄存器的值,和栈顶寄存器的值,并将返回地址送到指令地址寄存器P中,以使调用前的程序从断点开始继续执行。

(3)CAL L A

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Varixer

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值