编译原理:专题3_LL(1)语法分析设计原理与实现

1. 实验目的

通过实验,掌握LL(1)文法及其判定;掌握LL(1)分析表构造、分析和分析器的构造。

2. 实验要求

完成四则运算描述赋值语句的LL(1)文法分析,实现LL(1)分析中控制程序(表驱动程序);完成以下描述赋值语句文法的LL(1)分析过程。(1)输入串应是词法分析的输出二元式序列,即某算术表达式“专题1”的输出结果。输出为输入串是否为该文法定义的算术表达式的判断结果;(2)LL(1)分析过程应能发现输入串出错;(3)设计两个测试用例(尽可能完备,正确和出错),并给出测试结果;(4)考虑根据LL(1)文法编写程序构造LL(1)分析表,包括FIRST 集合和FOLLOW 集合,并添加到你的LL(1)分析程序中。

3. 程序实现

3.1. 相关环境介绍

操作系统:window 10 21H2
开发环境:Clion-2022.2.1-Windows
编译器:mwing-10.0

3.2. 主要数据结构

主要是单词的信息保存,建立了一个struct

01:struct Keyword{
02:    string notation;
03:    int class_num;
04:    int line;
05:    Keyword(string str, int num, int line_){
06:        notation = str;
07:        class_num = num;
08:        line = line_;
09:    }
10:    Keyword(char* str, int num, int line_){
11:        notation = string(str);
12:        class_num = num;
13:        line = line_;
14:    }
15:    Keyword(char str, int num, int line_){
16:        notation = str;
17:        class_num = num;
18:        line = line_;
19:    }
20:};

其中notation为单词的值,class_num 为单词所属的类别,line是单词在源程序中的行号。
利用map容器,制作了以string为index的二维数组。

21:map<string, map<string, vector<string>>> analyzer_table;  
22:map<string, set<string> > first;  
23:map<string, set<string> > follow;  
24:map<string, string> Vn;  
25:map<string, string> Vt;  
26:map<string, int> flag_e;  
27:map<string, vector<string>[ORMAXFORGRAMMAR] > grammar;  
28:map<pair<string,vector<string>>, set<string>> first_alpha;  

3.3. 程序结构描述

3.3.1. 设计方法

考虑到程序的通用性,程序的输入流全部都是txt文件。首先读入grammar文件,其中包括文法和Vn以及Vt集的定义。之后,在程序中创建Vn集合Vt集,然后求的first集合follow集,在这基础上构建出LL(1)分析表。

接下来是和词法分析程序的联动,本程序可以直接调用词法分析程序,因此测试样例直接准备源代码待分析即可。当然,语法分析部分当然还是词法分析的结果。其中的相应config配置依赖文件参考实验1。

3.3.2. 函数定义

create_Vn_Vt_grammar(grammar_path); 创建Vn Vt集和文法表。
create_first(grammar_path); 创建first集。
create_follow(); 创建follow集
create_analyzer_table(); 创建分析表
analyzer_stack(need_to_analysis); 分析栈入口,即分析驱动程序。

int correct_prom() 语句符合文法提示。
int error_prom() 语句不合文法提示。

还有一众辅助函数,不表。
主要函数的编写参照课程讲述。

4. 程序测试

Alu_test1.txt

这里一个文件中包含了4个测试样例。

01:3434 = 23434+34324+(a*b / c) +(a*b/ (2-2)) #
02:a = ( a+ b -c ) * 32 / a  #
03:b=(a+c * b #
04:k=a- b *c #

在这里插入图片描述

图表 4 1 test1中词法分析结果
在这里插入图片描述

图表 4 2 符号类号文件(词法分析程序的输出结果的一部分)
在这里插入图片描述

图表 4 3config文件
其中包括了一众依赖文件的路径还有默认待分析文件路径,最下边是书写格式。
在这里插入图片描述

图表 4 4 grammar文件
Grammar文件主要是Vn Vt集还有文法的输入,下方是特殊说明。

词法分析程序输出仍然采用了三元组,多了一个行号,方便错误提示,更多的我们直接用了Keyword结构,这对结果没有影响。
在这里插入图片描述

图表 4 5 本程序结果,信息提示

通过信息提示可以看出,程序对4个测试样例完成的很好,结果正确。
其中等号左侧只能是标识符,右侧实验指导书原文法标识符位置,可以出现数字常量。

5. 实验汇总

5.1. 技术难点及解决方案

实验本身的重要程序框图,已经在课堂上教授过了,主要是代码编写过程中的问题有些多,所幸最后都解决了。特别是first集和follow集的创建,人工建立和代码编写还是有一定的区别的,许多人工的取巧方法,机器都无法使用,这里也又一次感受到了程序编写的形式化魅力。
这里的实验和课堂上讲述的就是多了一个赋值语句,但是给的也十分的简单,如果V -> E 这样就是一般的情况,实验要求的是 V->I 这样会简单一些,直接判断就可以了。
实验代码编写完成之后,本人突然发现,实验指导的文法与正常编程语言的语法逻辑还是有一定区别的。其中i被定义为标识符,也就是变量,这在赋值文法的等号左侧是成立的,但是等号右侧的i出现的位置可以是标识符也可以是数字常量,甚至可以是一个表达式。这里我们在原有文法的基础上做了一点拓展,新增了一个n的Vt符号,作为数字常量的代指。这样我们的文法就变成了:

S -> V = E
E -> T E'
E' -> A T E' | e
T -> F T'
T' -> M F T' | e
F -> ( E ) | i | n
A -> + | -
M -> * | /
V -> i

幸运的是,在修改文法后本人的实验3程序居然没有一点问题,这真是值得欣慰的事。
当然其实我们也可以把i再拓展为表达式,这样其实是一种递归调用。

5.2. 实验感想和经验总结

这次实验主要的编码困难在于数据结构的建立。C++中的二维数组index都是整数,课堂上教授的分析表等表格都是字符作为index,这其中的转换是有难度的。最后,想到了使用STL中的map容器作为数据结构,二维数组就是map套map,还用了vector来存储文法产生式,这样就会出现“数据结构”一节中看似很复杂的容器嵌套结构。数据结构敲定之后,再定义出基本的操作方法,算法沿用课程中教授的,实验就不难完成了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值