实验2语法分析程序.docx
- 文档编号:7681193
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:43
- 大小:30.10KB
实验2语法分析程序.docx
《实验2语法分析程序.docx》由会员分享,可在线阅读,更多相关《实验2语法分析程序.docx(43页珍藏版)》请在冰豆网上搜索。
实验2语法分析程序
实验2语法分析程序
一、实验目的与要求
1.复习上下文无关文法的基本概念、判断方法即构造技术;
2.学习根据文法产生式使用递归子程序来构造语法分析器,进而理解递归下降分析法的理论基础、技术原理及实现步骤;
3.理解文法存在左递归、回溯现象的害处及消除方法,掌握FIRST集、FOLLOW集的含义、求解方法与用途,掌握LL
(1)文法的判断方法;
4.掌握预测分析法的理论精髓,理解下推自动机的基本概念;
5.学会基于上下文无关文法构造LL
(1)预测表,并能使用VisualC++编写基于LL
(1)预测表的语法分析器;
6.能利用预测分析法,在给定的文法基础上,分析特定输入串的语法结构,能判断其是否合法,并能提取大部分中间信息,以备后续分析时使用。
二、实验仪器及设备
1.微型电子计算机80台
2.配置Windows2000及以上版本操作系统
3.安装VisualC++6.0/VisualC#2000/Delphi6.0等以上版本的开发环境
三、实验内容及步骤
已知某正规文法G1[E]如下:
E→E+T|T
T→T*F|F
F→(E)|i
首先消除文法左递归,得到下面的文法G1'[E]:
E→TE'
E'→+TE'|
T→FT'
T'→*FT'|
F→(E)|i
请用两种方法构造该文法的语法分析程序。
(一)基于递归下降分析法构造语法分析器
按照递归下降分析的基本思想,为每个非终结符编写一个子程序。
从E开始,依据产生式右部的符号组成,调用相关的子程序,完成输入串“(i+i)*i”的语法分析。
下面是参考代码(部分):
#include"iostream.h"
#include"stdlib.h"
#include"string"
usingnamespacestd;
classCRDM//递归下降分析法(Recursive,Descent,Method)
{
public:
CRDM()//构造函数
{
myExpression="(i+i)*i#";//输入串以“#”作为结束标识
}
voidBeginRDM();//开始递归分析
private:
voidE();//对应非终结符E的子程序
voidE1();//对应非终结符E'的子程序
voidT();//对应非终结符T的子程序
voidT1();//对应非终结符T'的子程序
voidF();//对应非终结符F的子程序
voidmatch(stringt);//匹配函数
voidERROR();
stringnexttoken();
private:
stringmyExpression;//表达式
stringch;//符号
inti;//符号序号
};
//获取下一个符号:
stringCRDM:
:
nexttoken()
{
stringtemp;
i++;
temp=myExpression.substr(i,1);
returntemp;
}
//启动递归下降分析程序:
voidCRDM:
:
BeginRDM()
{
i=-1;
ch=nexttoken();
E();
if(!
(pare("#")))
{
cout<<"恭喜您,匹配成功!
"< exit(0); } else ERROR(); } //错误提示函数: voidCRDM: : ERROR() { cout< "< exit (1); } //产生式: E→TE' voidCRDM: : E() { T(); E1(); } //产生式: E'→+TE'|ε voidCRDM: : E1() { if(! (pare("+"))) { match("+"); T(); E1(); } } //产生式: T→FT' voidCRDM: : T() { F(); T1(); } //产生式: T'→*FT'|ε voidCRDM: : T1() { if(! (pare("*"))) { match("*"); F(); T1(); } } //产生式: F→(E)|i voidCRDM: : F() { if(! (pare("i"))) match("i"); elseif(! (pare("("))) { match("("); E(); if(! (pare(")"))) match(")"); else ERROR(); } else ERROR(); } //匹配函数: voidCRDM: : match(stringt) { if(! (pare(t))) { ch=nexttoken(); } else ERROR(); } //主函数: voidmain() { CRDMrdm; rdm.BeginRDM(); } 请完成下述操作: 1.分别输入四组数据: (i+i)*i#、i+i*i#、(i*i)+i#、i+i*i+#,测试它们是否合法,若不合法,请给出原因分析。 2.若将上述文法G1[E]进行修改(红色部分),得到G2[E]: E→E+T|E-T|T(增加了减法“-”) T→T*F|T/F|F(增加了除法“/”) F→(E)|i (1)请修改上述程序,使之适应新文法的语法要求。 提示: 主要考虑如何消除左递归,得到新的无左递归文法G2'[E]。 (2)依次输入四组符号串(i+i-i)*i#、(i+i)-*i#、(i/i)+i*i#、i+i*i/i-#,分别测试它们是否合法,并说明理由。 (二)基于预测分析法构造语法分析程序 这里需要借助实验1中建立的文法类CGrammar文件Grammar.h和Grammar.cpp,并在此基础上,公有派生出LL (1)文法类: CLL1Grammar,在CLL1Grammar类中完成语法分析的预测分析过程。 下面是参考代码,具体实现原理请参考教材有关章节或相关文献资料。 头文件LL1Grammar.h如下: #include"Grammar.h" #include"stack" structNodeStruct { stringSign;//元素 NodeStruct*Next;//指针 }; //FIRST和FOLLOW的结构体,相同: structFFStruct { stringGrammarSign;//元素 boolFlag;//表示已求过 NodeStruct*Next;//指针 }; //SELECT的结构体: structSELECTStruct { stringLeft;//左部 stringRight;//右部 NodeStruct*Next;//指针 }; //LL (1)文法类: classCLL1Grammar: publicCGrammar { public: CLL1Grammar() { //预先划分一块内存给vector使用 FIRSTofSingleSign.reserve(1000); FIRSTofSignString.reserve(2000); SELECTofCR.reserve(2000); FOLLOWofVN.reserve(2000); } ~CLL1Grammar() { } //显示信息: voidDisplayAllSingleSignFIRST(char*Filename);//保存所有单符号的FIRST到文件 voidDisplayAllSignStringFIRST(char*Filename);//保存所有右部符号串的FIRST到文件 voidDisplayAllSingleSignFIRST();//显示所有单符号的FIRST voidDisplayAllSignStringFIRST();//显示所有右部符号串的FIRST vector vector voidDisplayAllVNFOLLOW();//显示所有非终结符的FOLLOW voidDisplayAllVNFOLLOW(char*Filename);//保存所有FOLLOW到文件 vector voidDisplayAllSELECT();//显示所有SELECT voidDisplayAllSELECT(char*Filename);//保存所有SELECT到文件 voidDisplayMMTable();//显示预测分析表 voidDisplayMMTable(char*Filename);//保存预测分析表到文件 voidDisplaySentencePressing(stringsignstr,char*Filename);//将句子分析过程保存到文件中 public: voidIniLL1CGrammar();//初始化 boolGetIsLL1Grammar();//是否为LL (1)文法 voidCreateMM();//构造预测分析表M boolIsSentenceofLL1(stringsignstr);//基于LL (1)分析法判断一个串是否是合法的句子 private: voidFIRSTSetOfSingleSign(stringstrnum);//求解单符号的FIRST集 voidFIRSTSetOfAllSingleSign();//求解所有单符号的FIRST集 voidFOLLOWSetofVN(stringstrVN);//求非终结符的FOLLOW集 voidFOLLOWSetOfAllVN();//求所有非终结符的FOLLOW集 voidFIRSTSetOfAllSignString();//计算所有右部符号串的FIRST FFStruct*FIRSTSetOfSTR(stringstr1);//求指定的符号串的FIRST voidSELECTSetOfAllCR();//计算所有产生式的SELECT voidCheckLL1Grammar();//判断是否为LL (1)文法 voidClearStack();//清空栈 voidPreprocessing_LeftRecursion();//预处理 boolFindInList(stringstrVT,FFStruct*Head);//检查某首字符strVT是否已在Head中 intGetPtrFromstr(stringstr,vector boolEnableToEmpty(stringstr);//字符串能否推出ε voidMerge(FFStruct*Head,NodeStruct*head,boolFlagtemp);//合并集合 voidInsterNode(FFStruct*Head,stringstr);//将str加入链表; intGetSignInVector(stringstr,vector stringGetStack(stack private: boolIsLL1Grammar;//是否是LL (1)文法 vector vector vector vector vector vector stack }; 实现文件LL1Grammar.cpp如下: #include"LL1Grammar.h" #include #include //预处理 voidCLL1Grammar: : Preprocessing_LeftRecursion() { //判断文法是否为2型或3型: if(GetGrammarType()>=2) { //消除左递归 if(GetHavingLeftRecursion()) { if(DelIndirectLeftRecursion()) { cout< "< DisplayGrammar(); if(HavingRedundance()) { MiniGrammar();//文法化简: cout< "< DisplayGrammar(); } } } } } //初始化(要调用CLL1Grammar的相关功能,必须首先执行此函数) voidCLL1Grammar: : IniLL1CGrammar() { // (1)判断是否有左递归,若有则消除左递归 Preprocessing_LeftRecursion(); // (2)数据初始化 //A: 初始化FIRSTofSingleSign FFStructtemp1; inti; //非终结符NoEndSign: for(i=0;i { temp1.GrammarSign=NoEndSign[i]; temp1.Flag=false; temp1.Next=NULL; FIRSTofSingleSign.push_back(temp1); } //终结符EndSign: for(i=0;i { temp1.GrammarSign=EndSign[i]; temp1.Flag=false; temp1.Next=NULL; FIRSTofSingleSign.push_back(temp1); } //B: 根据产生式数组GR_Array的右部,来初始化FIRSTofSignString //注意: 不同的产生式的右部可能相同。 FFStructtemp2; for(i=0;i { intj; for(j=0;j if(! (GR_Array[i].RightPpare(FIRSTofSignString[j].GrammarSign))) break; if(j==FIRSTofSignString.size()) { temp2.GrammarSign=GR_Array[i].RightPart; temp2.Flag=false; temp2.Next=NULL; FIRSTofSignString.push_back(temp2); } } //C: 初始化FOLLOWofVN FFStructtemp3; for(i=0;i { temp3.GrammarSign=NoEndSign[i]; temp3.Flag=false; temp3.Next=NULL; FOLLOWofVN.push_back(temp3); } //D: 初始化SELECTofCR SELECTStructtemp4; for(i=0;i { temp4.Left=GR_Array[i].LeftPart; temp4.Right=GR_Array[i].RightPart; temp4.Next=NULL; SELECTofCR.push_back(temp4); } //(3)预执行有关函数: FIRSTSetOfAllSingleSign();//1.计算所有单个符号的FIRST FIRSTSetOfAllSignString();//2.计算所有右部符号串的FIRST FOLLOWSetOfAllVN();//3.计算所有非终结符的FOLLOW SELECTSetOfAllCR();//4.计算所有产生式的SELECT CheckLL1Grammar();//5.判断是否为LL (1)文法 } //检查某首字符strVT是否已在链表Head中: boolCLL1Grammar: : FindInList(stringstrVT,FFStruct*Head) { NodeStruct*p; p=Head->Next; while(p) { if(! (p->Spare(strVT))) returntrue; p=p->Next; } returnfalse; } //将str加入链表的尾部: voidCLL1Grammar: : InsterNode(FFStruct*Head,stringstr) { NodeStruct*q=newNodeStruct; q->Sign=str; q->Next=NULL; if(! Head->Next)//若只有表头 Head->Next=q; else//若已有节点 { NodeStruct*p=Head->Next; while(p->Next) p=p->Next; p->Next=q; } } //根据str得到其在FFSet中的指针 intCLL1Grammar: : GetPtrFromstr(stringstr,vector { for(intnum=0;num if(! (FFSet[num].GrammarSpare(str))) returnnum; return-1; } //确定符号串str在容器VnVt中的位置: intCLL1Grammar: : GetSignInVector(stringstr,vector { for(inti=0;i if(! (VnVt[i].compare(str))) returni; return-1; } //判断字符串str能否推出ε: boolCLL1Grammar: : EnableToEmpty(stringstr) { if(! (pare("ε")))//若为ε,则当然可以导出ε returntrue; vector : iteratorIter1;//迭代器 boolFlag1=false,Flag2; for(Iter1=GR_Array.begin();Iter1! =GR_Array.end();Iter1++) { if(! ((*Iter1).LeftPpare(str)))//若左部为str, { if((*Iter1).RightPart.length()==1//若右部长度==1, &&FindSign((*Iter1).RightPart,EndSign))//,且是终结符,则 { Flag1=Flag1||false; } elseif((*Iter1).RightPart.length()==2//若右部长度==2, &&! ((*Iter1).RightPpare("ε")))//,且是ε,则 { Flag1=Flag1||true; } else { //将产生式*Iter1的右部分解为单个符号: vector Flag2=true; for(inti=0;i { Flag2=Flag2&&EnableToEmpty(tempRight[i]);//递归求解 } Flag1=Flag1||Flag2; } } } returnFlag1; } //将head合并到Head,参数Flagtemp表示是否剔除ε。 voidCLL1Gr
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验2 语法分析程序 实验 语法分析 程序
![提示](https://static.bdocx.com/images/bang_tan.gif)