编译原理 语法分析程序LL(1)和LR(0)实现

语法分析程序的设计与实现


目录

语法分析程序的设计与实现 1
一. 实验题目 1
二. 实验要求 2
方法1:编写递归调用程序实现自顶向下的分析. 2
方法2:编写LL(1)语法分析程序,要求如下. (必做) 2
方法3:编写语法分析程序实现自底向上的分析,要求如下.(必做) 2
方法4:利用YACC自动生成语法分析程序,调用LEX自动生成的词法分析程序. 2
三. 程序设计说明 2
(一) LL(1)语法分析程序 2

  1. 数据结构与函数说明 2
    2. 程序分析前的数据操作 4
    3. 构造预测分析表 4
    4. 构造预测分析程序 5
    (二) LR分析程序 6
    1. 数据结构及函数说明 6
    2. 构造识别该文法所有活前缀的DFA 7
    3. First集合与follow集合,构造该文法的LR分析表 7
    4. 编程实现算法4.3,构造LR分析程序 8
    四. 源程序 8
    五. 可执行程序 8
    六. 测试报告 9
  2. LL(1)程序测试 9
    (1) 第一组测试 9
    (2) 第二组测试 10
  3. SLR(1)程序测试 11
    (1) 第一组测试 11
    (2) 第二组测试 13
    (3) 第三组测试 15

一.实验题目

1.语法分析程序的设计与实现
2.编写语法分析程序,实现对算术表达式的语法分析。要求所分析
算数表达式由如下的文法产生。

E->E+T | E–T | T 
T->T*F | T/F | F 
F->(E) | num 

二.实验要求

在对输入的算术表达式进行分析的过程中,依次输出所采用的产生式.
方法1:编写递归调用程序实现自顶向下的分析.
方法2:编写LL(1)语法分析程序,要求如下. (必做)
(1) 编程实现算法4.2,为给定文法自动构造预测分析表.
(2) 编程实现算法4.1,构造LL(1)预测分析程序 .
方法3:编写语法分析程序实现自底向上的分析,要求如下.(必做)
(3)构造识别该文法所有活前缀的DFA.
(4)构造该文法的LR分析表.
(5)编程实现算法4.3,构造LR分析程序.
方法4:利用YACC自动生成语法分析程序,调用LEX自动生成的词法分 析程序.


三.程序设计说明

(一)LL(1)语法分析程序
1.数据结构与函数说明
① 设置class CAnalysisTable类

class CAnalysisTable{
private:
	string** AnalysisTable;  //存储预测分析表
	string StackString;    //栈字符串
	int AnalysisTableRow = 5;  //行数
	int AnalysisTableCol = 8;  //列数

	vector<string> Terminator;  //存储终结符
	map<string, vector<string> > FirstSet;    //存储first集合
	map<string, vector<string> > FollowSet;   //存储follow集合

	//分析程序
	stack<string> SymbolStack;    //符号栈
	string OutputResults;         //输出使用的表达式
	string CurrentString;         //当前字串
	map<string, int> NonterminalMap;    //非终结符对应预测分析表的行号
	map<string, int> TerminalMap;       //终结符对应预测分析表的列号

protected:
	//表达式的存储(一对多的形式)
map<string, vector<string> > expression;   //每个父表达式对应的全部子表达式
public:
	string CalculationEstr;      //待分析符号串
	vector<string> DealData(string str, string split);   //字符串的处理
	void Init();                 //文件读取内容,进行初始化存储变量
	void StructuralAnalysisTable();    //分析表的构造
	void ShowAnalysisTable();    //输出分析表

	//分析程序
	void init();                 //栈的初始化
	void LIAnalysisPExe();       //预测分析函数
	void CalNonOrTerminalMap();    //计算非终结符分别对应的预测分析表的行号
}; 

②函数实现说明
1)void Init();
在本程序中,所有的内容采取文件读取。

	fstream Einfile("expression.txt", ios::in);  //读取表达式
	fstream Tinfile("Terminator.txt", ios::in);  //读取终结符
	fstream NTinfile("Nonterminal.txt", ios::in);   //读取非终结符
	fstream Firstinfile("FirstSet.txt", ios::in);   //读取first集合
	fstream Followinfile("FollowSet.txt", ios::in);   //读取follow集合

2)vector<string> DealData(string str, string split);
文件读取出的数据进行处理的函数。
其中str是待切割的字符串,split字符串是进行切割的标志符号。

3)void StructuralAnalysisTable();
构造分析表,主体实现过程按照算法4.2进行实现。

4)void init();
栈的初始化
将栈初始化为存有”$“状态。
5)void CAnalysisTable::LIAnalysisPExe();
预测分析过程,主体实现过程按照算法4.1进行实现。

6)void CalNonOrTerminalMap();
计算非终结符分别对应的预测分析表的行号.
采用map类型进行存储,便于每次查找时,可以不使用循环就可以进行定位表格中的某个格子。

2.程序分析前的数据操作
(1)消除左递归
在这里插入图片描述

(2)找出元素的first集合与follow集合
在这里插入图片描述

3.构造预测分析表
根据算法4.2实现预测分析表的构造,并且加入了同步信息。
在这里插入图片描述

程序实现时输出的预测分析表如下所示:
其中空串使用“~”表示。
在这里插入图片描述

4.构造预测分析程序
(1) 根据算法4.1实现预测分析程序
在这里插入图片描述

(2)带有同步信息的分析表的错误处理
针对于两种情况的错误进行处理。

①分析栈的栈顶符号是终结符,但却与当前输入符号不匹配。
本程序中的处理方法:直接将栈顶的符号弹出。

②分析栈栈顶符号是非终结符号A,当前输入的符号a。
本程序中的处理方法:
a.若M[A,a]”error”,那么移动指向字符的指针,识别下一个字符;
b.若M[A,a]”synch”,那么从栈顶弹出A

实现的程序代码见附录。


(二)LR分析程序

1.数据结构及函数说明
//global variable
① map<string, int> title; //首行符号
② map<string, int> States; //状态符号
③ int actionendpos = 8, gotoendpos = 11; //结束位置
④ string** LRTable; //分析表
⑤ stack<string> StatesStack, SymbolStack; //状态栈,符号栈
⑥ vector<string> ExpressionVec; //存储表达式
⑦ vector<string> VecStatesStackStr, ``VecSymbolStackStr; //存储状态栈的字符和字符栈的字符

//Function Description
⑧ map<int,string> DealData(string &str); //数据读取处理函数
该函数用于处理文件读取的时,进行数据的提取,因为在文件格式中表格的存储方式是
按照格式:状态序号 + “:” + [num,S1][(,S5][E,2][T,3][F,4]的形式存储
经过此函数的处理之后,返回map<int,string>类型的变量,键值对为key = 非终结符或者终结符,value = 分析动作或者非终结符号。

⑨ void ShowLRTable();
该函数用于输出LR分析表,遍历即可实现。

⑩ string StrInput();
待分析的字符串的输入,其中进行输入字串的末尾加上”$”结束标识符。

⑪ void InitStack()
状态栈与符号栈的初始化。
状态栈首先入栈”0”,开始状态
符号栈首先入栈”-”,开始符号

⑫ void ShowProcess(string & currentstr,string &expre,int Cptr)
分析过程的输出

⑬ void LRAnalysisFunction(string &str)
LR分析函数,该函数按照算法4.3进行实现。
2. 构造识别该文法所有活前缀的DFA

在这里插入图片描述

3.First集合与follow集合,构造该文法的LR分析表

在这里插入图片描述

4.编程实现算法4.3,构造LR分析程序
在这里插入图片描述

四.源程序

见附件(“LL(1).cpp”是方法二的程序实现源代码,”LR(0).cpp”是方法三的程序实现源代码)

五.可执行程序

1.见附件
2.由于许多数据不是采用直接在代码中赋值的操作,而是采用文件读取的方式,所以“LL(1)可执行文件”这个文件夹包含exe文件和执行文件需要进行数据读取的文本文件,必须保证这些文本文件与exe文件在同一个目录下才能运行。
3.由于许多数据不是采用直接在代码中赋值的操作,而是采用文件读取的方式,所以“LR(0)可执行文件”这个文件夹包含exe文件和执行文件需要进行数据读取的文本文件,必须保证这些文本文件与exe文件在同一个目录下才能运行。
4.“LL(1)可执行文件”中每一个文本作用:
(1)“expression.txt”存储的是生成式
(2)“FirstSet.txt”存储的是非终结符的first集合
(3)“FollowSet.txt”存储的是非终结符的follow集合
(4)“Nonterminal.txt”存储的是非终结符
(5)“Terminator.txt”存储的是终结符
5.“LR(0)可执行文件”中每一个文本的作用:
(1)“Action.txt”存储的是第一行action中的符号
(2)“Goto.txt”存储的是第一行goto中的符号
(3)“Expression.txt”存储的是生成式集合
(4)“LRAnalysisTable.txt”存储的是LR分析表

六.测试报告

测试时的注意事项:
需要注意的是,输入的字符串中,数字是阿拉伯数字输入,不是num。
比如:输入字符串“2+3*3/3(90-1)”进行验证分析即可。
1.LL(1)程序测试
在这里插入图片描述

(1)第一组测试
输入:
在这里插入图片描述

运行结果:
在这里插入图片描述
在这里插入图片描述

结果分析:
所给的测试样例是正确的样例。
经过手工验证可知,该分析过程正确。

(2)第二组测试
输入:

在这里插入图片描述

运行结果:

在这里插入图片描述
在这里插入图片描述

结果分析:
此测试样例为输入错误,进行错误处理的检测。
1.在”1+”的后面,第二个”+”使用到同步信息处理,分析表中的该位置为”synch”,那么弹出栈顶的符号,执行正确。
2.num(19)的后面缺少运算符,那么分析表中该位置是error,那么移动向前指针,执行正确。

2.SLR(1)程序测试

在这里插入图片描述

(1)第一组测试
输入:

在这里插入图片描述

运行结果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结果分析:
测试样例符合文法规则,正确识别出字符,然后正常结束程序。

(2)第二组测试

		输入:

在这里插入图片描述

运行结果:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结果分析:
测试样例符合文法规则,正确识别出字符,然后正常结束程序。

(3)第三组测试
输入:
在这里插入图片描述

运行结果:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

结果分析:
该测试样例为错误的,不符合文法规则。
“2**1”,由于第二个”*”的后面缺少了运算的数值或者括号,那么导致程序中止运行。

下载源码和数据,请点击跳转 下载连接

  • 9
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值