# 源语言和目标语言

本次大作业设计的编译器是将 PL/0 语言编译成类 P-code 语言的程序。

# PL/0 语言

PL/0 语言是一种功能及其有限的编程语言,其数据类型仅存在整数,控制流仅有 if...then...while...do... 两种。此外,其不存在函数传参和面向对象等 “现代” 的设计,而是仅存在 call 指令作为调用的方式。这一方面使得其编写思路与汇编语言相当类似,另一方面也使得其编译器十分简单。

# 类 P-Code 语言

类 P-code 语言是 PL/0 编译器的目标语言,是运行于纯栈式机器上的汇编语言。

其基本指令形式为 F L A , 三部分的各自含义如下:

  • F : 指令的操作码。
  • L : 若起作用,则表示引用层与声明层之间的层次差;若不起作用,则置为 0
  • A : 不同的指令含义不同。

具体的命令及解释如下:

FLA功能
INT0A在栈顶开辟 A 个存储单元
CALLA调用地址为 A 的过程,调用过程与被调用过程的层差为 L
LIT0A立即数 A 存入 tt 所指单元, tt 加 1
LODLA将层差为 L 、偏移量为 A 的存储单元的值取到栈顶, tt 加 1
STOLA将栈顶的值存入层差为 L 、偏移址为 A 的单元, tt 减 1
OPR00结束被调用过程,返回调用点并退栈
OPR01求栈顶元素的相反数,结果值留在栈顶
OPR06栈顶内容若为奇数则变为 1 ,若为偶数则变为 0
OPR02次栈顶与栈顶的值相加,结果存入次栈顶, tt 减 1
OPR03次栈顶的值减去栈顶的值,结果存放次栈顶, tt 减 l
OPR04次栈顶的值乘以栈顶的值,结果存放次栈顶, tt 减 1
OPR05次栈顶的值乘以栈顶的值,结果存放次栈顶, tt 减 l
OPR08次栈顶与栈顶内容若相等,则将 0 存于次栈顶, tt 减 1
OPR09次栈顶与栈顶内容若不相等,则将 0 存千次栈顶, tt 减 1
OPR010次栈顶内容若小于栈顶,则将 0 存于次栈顶, tt 减 1
OPR011次栈顶内容若小于等于栈顶,则将 0 存于次栈顶, tt 减 1
OPR012次栈顶内容若大于栈顶,则将 0 存于次栈顶, tt 减 1
OPR013次栈顶内容若大于等于栈顶,则将 0 存于次栈顶, tt 减 1
OPR014栈顶的值输出至控制台屏幕, tt 减 1
OPR015控制台屏幕输出一个换行
OPR016从控制台读入一行输人,置入栈顶, tt 加 1
JMP0A无条件转移至地址 A
JPC0A若栈顶为 0,则转移至地址 A, t 减 1

# 词法分析的实现

词法分析采用 DFA 实现。从文件流中每读取一个字符, DFA 进行一次循环和状态选择。

DFA 的基本状态如下:

// enum class for Lexer's DFA
enum Lex_state {
	START_STATE,        // 起始状态
	NUM_STATE,          // 数字
	ID_STATE,           // 标识符 & 关键字
	COMMENT_STATE,      // 注释
	GTR_STATE,          // >
	GEQ_STATE,          // >=
	LES_STATE,          // <
	LEQ_STATE,          // <=
	ASS_STATE,          // :=
};

# 语法分析和代码生成

在我的程序中,中间和目标代码生成在语法分析器的结构中实现。注意到, PL/0 语言是栈式计算机语言