以下各节的代码根据教材P288的附录A中的pascal代码改写而来。改写时的要求是
1、尽量使用原有的变量名和类型名、函数名和参数名
2、对c++中未提供的运算符或者函数,则额外实现
3、尽量不改动原有的处理流程。
此外,代码中的注释基本摘自技术高手李凡希的博客。地址为http://blog.csdn.net/lifanxi/article/details/3833
这里向这位技术大牛致以崇高的敬意!
由于代码较多,故分几次贴出,本次先贴出头文件包含语句和全局变量定义语句
/* PL/0编译程序与代码生成解释运行程序 */
/* PL/0 compiler with code generation */
/*引入必要的头文件和类型名*/
#include<set>
using std::set;
#include<fstream>
using std::fstream;
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::istream ;
using std::cin;
using std::cout;
using std::endl;
#include <iomanip>
using std::setw;
using std::left;
using std::boolalpha;
#include <cstring>
#include <cctype>
/* 常量定义 */
const int norw = 13; /* of reserved words */ /* 保留字的个数 */
const int txmax = 100; /* length of identifier table */ /* 标识符表的长度(容量) */
const int nmax = 14; /* max number of digits in numbers */ /* 数字允许的最长位数 */
const int al = 10; /* length of identifiers */ /* 标识符最长长度 */
const int amax = 2047; /* maximum address */ /* 寻址空间 */
const int levmax = 3; /* max depth of block nesting */ /* 最大允许的块嵌套层数 */
const int cxmax = 200; /* size of code array */ /* 类PCODE目标代码数组长度(可容纳代码行数) */
/* 类型定义 */
enum symbol
{nul, ident, number, plus, minus, times, slash, oddsym,
eql, neq, lss, leq, gtr, geq, lparen, rparen, comma,
semicolon, period, becomes, beginsym, endsym, ifsym,
thensym, whilesym, writesym, readsym, dosym, callsym,
constsym, varsym, procsym
}; /* symobl类型标识了不同类型的词汇 */
typedef char alfa[al]; /* alfa类型用于标识符 */
enum object{constant, variable, procedure}; /* object为三种标识符的类型 */
typedef set<symbol> symset; /* symset是symbol类型的一个集合类型,可用于存放一组symbol */
enum fct{lit, opr, lod, sto, cal, _int, jmp, jpc}; /* fct类型分别标识类PCODE的各条指令 */
struct instruction
{
fct f; /* function code */
int l; /* level */
int a; /* displacement addr */
}; /* 类PCODE指令类型,包含三个字段:指令f、层差l和另一个操作数a */
/*
lit 0, a load constant a
opr 0, a execute opr a
lod l, a load variable l, a
sto l, a store variable l, a
cal l, a call procedure a at level l
int 0, a increment t-register by a
jmp 0, a jump to a
jpc 0, a jump conditional to a
*/
/* 全局变量定义 */
ofstream fa; /* 文本文件fa用于列出源程序 */
ofstream fa1, fa2; /* 文本文件fa1用于列出类PCODE代码、fa2用于记录解释执行类PCODE代码的过程 */
bool listswitch; /* true set list object code */ /* 如果本变量置true,程序编译后将为列出类PCODE代码,
否则不列出类PCODE代码 */
char ch; /* last char read */ /* 主要用于词法分析器,存放最近一次从文件中读出的字符 */
symbol sym; /* last symbol read */ /* 词法分析器输出结果之用,存放最近一次识别出来的token的类型 */
alfa id; /* last identifier read */ /* 词法分析器输出结果之用,存放最近一次识别出来的标识符的名字 */
int num; /* last number read */ /* 词法分析器输出结果之用,存放最近一次识别出来的数字的值 */
int cc; /* character count */ /* 行缓冲区的列指针 */
int ll; /* line length */ /* 行缓冲区长度 */
int kk; /* 引入此变量是出于程序性能考虑,见getsym过程注释 */
int cx; /* code allocation index */ /* 代码分配指针,代码生成模块总在cx所指位置生成新的代码 */
char line[81];/* 行缓冲区,用于从文件读出一行,供词法分析获取单词时之用 */
alfa a; /* 词法分析器中用于临时存放正在分析的词 */
instruction code[cxmax];/* 生成的类PCODE代码表,存放编译得到的类PCODE代码 */
alfa word[norw];/* 保留字表 */
symbol wsym[norw];/* 保留字表中每一个保留字对应的symbol类型 */
symbol ssym['^'-' '+1];/* 一些符号对应的symbol类型表 */
char mnemonic[8][5]; /* 类PCODE指令助记符表 */
symset declbegsys, statbegsys, facbegsys; /* 声明开始、表达式开始和项开始符号集合 */
/* 符号表 */
struct{
alfa name; /* 符号的名字 */
object kind;
union
{
int val; /* 如果是常量名 val中放常量的值 */
struct{
int level, adr, size; /* 如果是变量名或过程名,存放层差、偏移地址和大小 */
};
};
}table[txmax+1];
ifstream fin; /* fin文本文件用于指向输入的源程序文件,fout程序中没有用到 */
alfa fname; /* 存放PL/0源程序文件的文件名 */
int err; /* 出错总次数 */