PL0 语言文法编译器
实验报告
课程名称:程序设计语言编译原理
实验名称: PL0 语言文法编译器
学生学院:
学生班级:
学生学号:
学生姓名:
提交日期: 2019.12.11
目录
实验目标.................................................................................................................................................................. 3
实验概览.................................................................................................................................................................. 3
实验要求.........................................................................................................................................................3
PL0 语言文法的 BNF 表示........................................................................................................................3
词法分析.................................................................................................................................................................. 4
词法分析要完成的任务.............................................................................................................................4
词法分析实现分析...................................................................................................................................... 4
词法分析用到的存储结构和函数.................................................................................................4
Void Init()在类型表 sym 中填入类型.......................................................................................... 5
Void pretreatment(string line)去除掉当前行代码中多余的空格......................................6
int check(char x)检测字符类型并返回对应类型的整数 ....................................................... 7
Void getSym()读取文件并提取词汇............................................................................................7
void putIn(string) 对提取出的词汇进行分析的函数............................................................ 8
Void output()输出词法分析的结果..............................................................................................9
词法分析结果样例....................................................................................................................................10
语法分析................................................................................................................................................................11
语法分析要完成的任务.......................................................................................................................... 11
PL0 语言文法的 EBNF 表示................................................................................................................... 11
语法分析实现分析....................................................................................................................................13
实现语法分析需要的存储结构................................................................................................... 13
实现语法分析需要的函数............................................................................................................ 14
语义分析和目标代码生成............................................................................................................................... 16
说明部分的处理........................................................................................................................................ 16
说明部分处理的分析......................................................................................................................17
语句处理和目标代码生成......................................................................................................................17
8 条目标指令.....................................................................................................................................17
目标指令生成分析.......................................................................................................................... 18
解释执行................................................................................................................................................................18
解释执行部分用到的数据结构和函数.............................................................................................. 18
解释执行部分函数分析.......................................................................................................................... 19
Void getResult()................................................................................................................................19
Void OPR()..........................................................................................................................................21
Int getVar(int l,int a)........................................................................................................................ 23
Void changeVar(int l,int a)............................................................................................................24
代码结构解释...................................................................................................................................................... 25
问题和总结........................................................................................................................................................... 25
附件......................................................................................................................................................................... 25
头文件 pch.h...............................................................................................................................................25
头文件实现文件 pch.cpp....................................................................................................................... 29
主程序 Grammer.cpp...............................................................................................................................62
实验目标
本实验作为程序设计语言编译原理的实验课,旨在提升同学们的动手编程能力,借助实
验巩固上课所学习的编译原理相关的知识。
本实验可大致分为四个阶段,分别为词法分析、语法分析、语义分析和目标代码生成、
解释执行。四个部分相对独立,对应《高级程序语言编译原理》课本讲解顺序。实验课时长
32 学时,截止提交时间为本学期第 15 周周三。
实验概览
实验要求
PL0 语言相对来说是一种比较简易的编程语言语言,下一小节我们会给出 PL0 语言文法
的 BNF 表示。本实验的结果要求得到一个能够对 PL0 语言代码执行并能输出正确结果的程序。
词法分析:对代码进行词法分析,提取出代码中的词(包含标识符,数字,符号等);
语法分析:对代码进行语法分析,推导语言文法,给出语法树,同时检测不符合语法规
范的代码并报错;
语义分析和目标代码生成:对语法分析的结果进行语义分析,给出对应等价的中间代码;
解释执行:对中间代码解释执行,给出代码执行的结果。
PL0 语言文法的 BNF 表示
1. 〈程序〉→〈分程序〉。
2. 〈分程序〉→ [<常量说明部分>][<变量说明部分>][<过程说明部分>]〈语句〉
3.
4.
5.
6.
7.
8.
9.
10. <语句> → <赋值语句>|<条件语句>|<当型循环语句>|<过程调用语句>|<读语句>|<写语句>|<
<常量说明部分> → CONST<常量定义>{ ,<常量定义>};
<常量定义> → <标识符>=<无符号整数>
<无符号整数> → <数字>{<数字>}
<变量说明部分> → VAR<标识符>{ ,<标识符>};
<标识符> → <字母>{<字母>|<数字>}
<过程说明部分> → <过程首部><分程度>;{<过程说明部分>}
<过程首部> → procedure<标识符>;
复合语句>|<空>
11. <赋值语句> → <标识符>:=<表达式>
12. <复合语句> → begin<语句>{ ;<语句>}
13. <条件> → <表达式><关系运算符><表达式>|odd<表达式>
14. <表达式> → [+|-]<项>{<加减运算符><项>}
15. <项> → <因子>{<乘除运算符><因子>}
16. <因子> → <标识符>|<无符号整数>|(<表达式>)
17. <加减运符> → +|-
18. <乘除运算符> → *|/
19. <关系运算符> → =|#|<|<=|>|>=
20. <条件语句> → if<条件>then<语句>
21. <过程调用语句> → call<标识符>
22. <当型循环语句> → while<条件>do<语句>
23. <读语句> → read(<标识符>{ ,<标识符>})
24. <写语句> → write(<标识符>{,<标识符>})
25. <字母> → a|b|c…x|y|z
26. <数字> → 0|1|2…7|8|9
词法分析
把关键字、算符、界符称为语言固有的单词,标识符、常量称为用户自定义的单词。
词法分析要完成的任务
1. 滤掉单词间多余的空格
2. 识别关键字,用查关键字表的方式识别。
3. 识别标识符,标识符的类型为 ID。
4. 拼数,将数的类别 NUMBER 放在 SYM 中
5. 拼由两个字符组成的运算符,如>=、<=d 等等,识别后将其放在 SYM 中
6. 打印程序,将识别出来的字符打印
词法分析实现分析
词法分析用到的存储结构和函数
首先给出储存每一个分析出来的词汇的基本储存结构,
int ID;
string name;
int number;
Ternary(int a, string b, int c) {
//储存着词汇类型对应的 ID
//存储着分析出来词汇
//存储着这个词汇是对应 ID 的第几个
//重构函数
1. class Ternary {
2. public:
3.
4.
5.
6.
7.
8.
9.
ID = a;
name = b;
number = c;
}
10.
11. };
接下来给出主要的存储结构
1. vector sym;//类型表
2. vector sym_num;//当前这种类型的数量
3. vector word;//从程序中读到的东西
以下是词法分析部分会用到的函数
1. void init();//预处理,建立保留字/其他表格
2. int check(char);//检查当前字符的类别
3. void getSym();//词法分析部分
4. int getID(string);//获得当前单词的类别的 ID
5. void putIn(string);//把得到的单词放进 word 里
6. void output();//输出词法分析的结果
接下来的小节中,我们会介绍各个函数的实现机制。
Void Init()在类型表 sym 中填入类型
//生成类表
sym.push_back("$ID");
sym.push_back("$NUMBER");
1. void Grammer::init() {
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
sym.push_back("$+");
sym.push_back("$-");
sym.push_back("$*");
sym.push_back("$/");
sym.push_back("$=");
sym.push_back("$>");
sym.push_back("$<");
sym.push_back("$>=");
sym.push_back("$<=");
sym.push_back("$#");
sym.push_back("$,");
sym.push_back("$:=");
sym.push_back("$(");
sym.push_back("$)");
sym.push_back("$;");
sym.push_back("$.");
sym.push_back("$const");
sym.push_back("$var");
sym.push_back("$procedure");
sym.push_back("$begin");
sym.push_back("$end");
sym.push_back("$odd");
sym.push_back("$if");
sym.push_back("$then");
sym.push_back("$else");
sym.push_back("$call");
sym.push_back("$while");
sym.push_back("$do");
sym.push_back("$read");
sym.push_back("$write");
for (int i = 0; i < sym.size(); i++) {
sym_num.push_back(0);
}
tree->ID_Name = "PROGRAM";
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42. }
Void pretreatment(string line)去除掉当前行代码中多余的
空格
if (line[i] != ' ') {
if (b == true)
if (s != "") {
s += ' ';
string s = "";
bool b = false;
for (int i = 0; i < line.size(); i++)
1. string Pretreatment(string line) {//去除掉当前句子里多余的空格
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17. }
b = false;
s += line[i];
}
}
else {
b = true;
}
return s;
int check(char x)检测字符类型并返回对应类型的整数
1. int Grammer::check(char x) {//检查当前字符是不是分割单词的符号
2.
3.
4.
5.
6.
7. }
if (x == ' ') return 0;//是空格就返回 0
if (isalpha(x)) return 1;//是字母就返回 1
if (isdigit(x)) return 2;//是数字就返回 2
if (x == '_') return 3;//是下划线就返回 3
return 4;//是其他符号就返回 4
Void getSym()读取文件并提取词汇
//读入文件地址并打开文件
fstream f;
cout << "Please enter the file address:" << endl;
//cin >> fileName;
fileName = "./main.txt";
f.open(fileName, ios::in);
if (!f.is_open()) {
cout << "dont find the file" << endl;
return;
string line;
1. void Grammer::getSym() {
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
}
int hhh = 0;
while (!f.eof()) {
hhh++;
getline(f, line);//读取当前文件的一行
if (line.size() == 0) continue;//如果当前行为空则继续读下一行
string strtoken = "";//储存着当前读到的单词的部分
string oldStrtoken = "";//储存着上一个单词
int index = 0;
string sentence=Pretreatment(line);//对句子进行预处理,去除掉当前句子里
多余的空格
24.
25.
26.
27.
28.
29.
30.
cout << sentence << endl;
while (index < sentence.size()) {
int x = check(sentence[index]);
if ( x != 0 && x != 4 ) {
strtoken+=sentence[index];
}
else {
if (strtoken != "") {//对当前读到的单词进行处理
putIn(strtoken);
strtoken = "";
}
if (x == 4) {
情况下
strtoken += sentence[index];
if (index < sentence.size() - 1) {//在当前这一行没有读完的
if (sentence[index + 1] == ';') {//下一个字符是;时
putIn(strtoken);
strtoken = ";";
}
else {
if (check(sentence[index + 1]) == 4)//下一个字符
strtoken += sentence[++index];
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59. }
不是分号,但是符号
}
}
putIn(strtoken);
strtoken = "";
}
}
index++;
}
if (strtoken != "") {//对当前读到的单词进行处理
putIn(strtoken);
}
}
//cout << hhh << endl;
f.close();
void putIn(string) 对提取出的词汇进行分析的函数
if (isalpha(s[0])) {
1. void Grammer::putIn(string s) {
2.
3.
4.
5.
6.
7.
8.
9.
10.
}
else {//是保留字
int id = 0;
if ((id = getID(s)) == -1) {//是标识符
id = getID("ID");
Ternary t(id, s, ++sym_num[id]);
word.push_back(t);
word.push_back(Ternary(id,sym[id], ++sym_num[id]));