语法分析器实验报告
lr语法分析实验报告
lr语法分析实验报告LR语法分析实验报告引言在计算机科学领域,语法分析是编译器设计中非常重要的一个环节。
它负责将输入的源代码按照给定的文法规则进行解析,并生成语法树或分析表。
本实验报告将介绍LR语法分析器的设计与实现,并通过实验结果进行分析和评估。
一、背景知识1.1 语法分析语法分析是编译器的一个重要组成部分,它负责将输入的源代码转化为抽象语法树或分析表。
语法分析器根据给定的文法规则,逐个读取输入的字符并进行规约或移进操作,最终确定输入串是否符合给定的文法。
1.2 LR语法分析LR语法分析是一种自底向上的语法分析方法,它利用有限状态自动机进行分析。
LR分析器根据输入的文法规则和状态转移表,逐步推导输入串,直到达到最终的语法树或分析表。
二、实验设计2.1 实验目标本实验旨在设计和实现一个LR语法分析器,包括以下主要内容:- 设计和实现文法规则- 构建LR分析表- 实现LR分析器的状态转移和语法规约操作2.2 实验环境本实验使用Python语言进行实现,使用了Python的语法分析库PLY(Python Lex-Yacc)。
三、实验过程3.1 文法规则设计在本实验中,选择了一个简单的算术表达式文法作为示例:```E -> E + T| E - T| TT -> T * F| T / F| FF -> ( E )| number```该文法规则描述了四则运算表达式的语法结构,其中E表示表达式,T表示项,F表示因子。
3.2 构建LR分析表根据给定的文法规则,我们可以构建LR分析表。
该表记录了分析器在不同状态下的状态转移和规约操作。
3.3 实现LR分析器基于PLY库,我们可以很方便地实现LR分析器的状态转移和规约操作。
首先,我们需要定义文法规则的各个产生式对应的处理函数。
然后,通过PLY库提供的API,我们可以构建分析器对象,并进行状态转移和规约操作。
四、实验结果与分析4.1 实验结果经过实验,我们成功地实现了LR语法分析器,并对多个测试用例进行了分析。
编译原理语法分析试验报告
编译原理语法分析试验报告语法分析是编译原理中的重要内容之一,主要用于对源程序进行语法检查,判断其是否符合给定的语法规则。
本次试验通过使用ANTLR工具,对C语言的子集进行了语法分析的实现。
一、实验目的:1.了解语法分析的基本概念和方法;2.使用ANTLR工具生成语法分析器;3.掌握ANTLR工具的基本使用方法;4.实现对C语言子集的语法分析。
二、实验内容:本次试验主要内容是使用ANTLR工具生成C语言子集的语法分析器,并对给定的C语言子集进行语法分析。
三、实验步骤:1.学习ANTLR工具的基本概念和使用方法;2.根据C语言子集的语法规则,编写ANTLR的语法文件(.g文件);3.使用ANTLR工具生成语法分析器;4.编写测试代码,对给定的C语言子集进行语法分析。
四、实验结果:经过以上的步骤,得到了一个完整的C语言子集的语法分析器,并且通过测试代码对给定的C语言子集进行了语法分析。
五、实验总结:通过本次实验,我对语法分析有了更深入的了解,掌握了使用ANTLR工具生成语法分析器的基本方法,同时也巩固了对C语言的基本语法规则的理解。
在实验过程中,遇到了一些问题,例如在编写ANTLR的语法文件时,对一些特殊语法规则的处理上有些困惑,但通过查阅资料和与同学的探讨,最终解决了这些问题。
本次试验对于我的学习有很大的帮助,我了解到了编译原理中的重要内容之一,也更深入地理解了语法分析的基本原理和方法。
通过实验,我发现使用ANTLR工具能够更方便地生成语法分析器,大大提高了开发效率。
总之,本次试验让我对编译原理中的语法分析有了更深入的了解,并且提高了我的编程能力和分析问题的能力。
在今后的学习和工作中,我将继续深入研究编译原理相关的知识,并应用到实际项目中。
语法法分析实验报告
一、实验目的1. 理解语法分析的基本概念和原理。
2. 掌握语法分析器的构建方法。
3. 培养实际操作能力,提高编程水平。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发工具:PyCharm三、实验内容1. 语法分析概述2. 词法分析3. 语法分析4. 实验实现四、实验步骤1. 语法分析概述(1)了解语法分析的定义、作用和意义。
(2)掌握语法分析的基本原理和流程。
2. 词法分析(1)编写词法分析器代码,将源代码分解成单词序列。
(2)实现词法分析器的各个功能,如:识别标识符、关键字、运算符等。
3. 语法分析(1)设计语法分析器,将单词序列转换为抽象语法树(AST)。
(2)实现语法分析器的各个功能,如:识别表达式、语句、函数等。
4. 实验实现(1)创建Python项目,导入相关库。
(2)编写词法分析器代码,实现单词序列的分解。
(3)编写语法分析器代码,实现抽象语法树的构建。
(4)测试语法分析器,验证其正确性。
五、实验结果与分析1. 词法分析结果实验中,我们成功地将源代码分解成单词序列,包括标识符、关键字、运算符等。
词法分析器的输出结果如下:```identifier: akeyword: intoperator: +identifier: boperator: =integer: 5```2. 语法分析结果通过语法分析器,我们将单词序列转换成抽象语法树。
以下是一个示例的抽象语法树:```Program├── Declaration│ ├── Type│ │ ├── Identifier│ │ └── Integer│ └── Identifier│ └── a└── Statement├── Expression│ ├── Identifier│ └── a└── Operator└── =└── Expression├── Identifier└── b└── Integer└── 5```从实验结果可以看出,我们的语法分析器能够正确地将源代码转换为抽象语法树。
国开电大 编译原理 实验4:语法分析实验报告
国开电大编译原理实验4:语法分析实
验报告
1. 实验目的
本实验的目的是研究和掌握语法分析的原理和实现方法。
2. 实验内容
本次实验主要包括以下内容:
- 设计并实现自顶向下的LL(1)语法分析器;
- 通过语法分析器对给定的输入串进行分析,并输出相应的分析过程;
- 编写测试用例,验证语法分析器的正确性。
3. 实验步骤
3.1 设计LL(1)文法
首先,根据实验要求和给定的语法规则,设计LL(1)文法。
3.2 构建预测分析表
根据所设计的LL(1)文法,构建预测分析表。
3.3 实现LL(1)语法分析器
根据预测分析表,实现自顶向下的LL(1)语法分析器。
3.4 对输入串进行分析
编写程序,通过LL(1)语法分析器对给定的输入串进行分析,并输出相应的分析过程和结果。
3.5 验证语法分析器的正确性
设计多组测试用例,包括正确的语法串和错误的语法串,验证语法分析器的正确性和容错性。
4. 实验结果
经过实验,我们成功设计并实现了自顶向下的LL(1)语法分析器,并对给定的输入串进行了分析。
实验结果表明该语法分析器具有较好的准确性和容错性。
5. 实验总结
通过本次实验,我们对语法分析的原理和实现方法有了更深入的了解。
同时,我们也学会了如何设计并实现自顶向下的LL(1)语
法分析器,并验证了其正确性和容错性。
这对于进一步研究编译原理和深入理解编程语言的语法结构具有重要意义。
6. 参考资料
- 《编译原理与技术》
- 课程实验文档及代码。
编译原理语法分析器实验报告
编译原理语法分析器实验报告班级:学号:姓名:实验名称语法分析器一、实验目的1、根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
2、本次实验的目的主要是加深对自上而下分析法的理解。
二、实验内容[问题描述]递归下降分析法:0.定义部分:定义常量、变量、数据结构。
1.初始化:从文件将输入符号串输入到字符缓冲区中。
2.利用递归下降分析法分析,对每个非终结符编写函数,在主函数中调用文法开始符号的函数。
LL(1)分析法:模块结构:1、定义部分:定义常量、变量、数据结构。
2、初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体等);3、运行程序:让程序分析一个text文件,判断输入的字符串是否符合文法定义的规则;4、利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示简单的错误提示。
[基本要求]1. 对数据输入读取2. 格式化输出分析结果2.简单的程序实现词法分析public static void main(String args[]) {LL l = new LL();l.setP();String input = "";boolean flag = true;while (flag) {try {InputStreamReader isr = newInputStreamReader(System.in);BufferedReader br = new BufferedReader(isr);System.out.println();System.out.print("请输入字符串(输入exit退出):");input = br.readLine();} catch (Exception e) {e.printStackTrace();}if(input.equals("exit")){flag = false;}else{l.setInputString(input);l.setCount(1, 1, 0, 0);l.setFenxi();System.out.println();System.out.println("分析过程");System.out.println("----------------------------------------------------------------------");System.out.println(" 步骤| 分析栈| 剩余输入串| 所用产生式");System.out.println("----------------------------------------------------------------------");boolean b = l.judge();System.out.println("----------------------------------------------------------------------");if(b){System.out.println("您输入的字符串"+input+"是该文法的一个句子");}else{System.out.println("您输入的字符串"+input+"有词法错误!");}}}}//实现各函数并且加注释三、编程并上机调试运行运行结果如下图:四、实验小结通过这次实验,我对语法分析有了更深刻的了解,对它的形成有了更清楚得认识。
语法分析器实验报告
词法分析器实验报告实验名称:语法分析器实验内容:利用LL(1)或LR(1)分析语句语法,判断其是否符合可识别语法。
学会根据状态变化、first、follow或归约转移思想构造状态分析表,利用堆栈对当前内容进行有效判断实验设计:1.实现功能可对一段包含加减乘除括号的赋值语句进行语法分析,其必须以$为终结符,语句间以;隔离,判断其是否符合语法规则,依次输出判断过程中所用到的产生式,并输出最终结论,若有错误可以报错并提示错误所在行数及原因2.实验步骤3.算法与数据结构a)LLtable:left记录产生式左端字符;right记录产生式右端字符;ln记录产生式右端字符长度Status:记录token分析情况Token:category,类型;value,具体内容b)根据LL(1)算法,手工构造分析表,并将内容用数组存储,便于查找c)先将当前语句的各token按序存储,当前处理语句最后一个token以#标记,作为输入流与产生式比较,堆栈中初始放入#,x,a为处理输入流中当前读头内容✓若top=a=‘#‘表示识别成功,退出分析程序✓若top=a!=‘#‘表示匹配,弹出栈顶符号,读头前进一个✓若top为i或n,但top!=a,出错,输出当前语句所在行,出错具体字符✓若top不为i或n,查预测分析表,若其中存放关于top产生式,则弹出top,将产生式右部自右向左压入栈内,输出该产生式,若其中没有产生式,出错,输出当前语句所在行,出错具体字符d)以;作为语句终结,每次遇到分号则处理之前语句并清空后预备下语句处理,当遇到$表示该段程序结束,停止继续处理4.分析表构造过程a)x->i=ee->e+t|e-t|tt->t*f|t/f|ff->(e)|i|nnote: i表示变量,n表示数字,!表示空串b)提取左公因子x->i=ee->ea|ta->+t|-tt->tb|fb->*f|/ff->(e)|i|nc)消除左递归x->i=ee->tcc->ac|!a->+t|-tt->fdd->bd|!b->*e|/ff->(e)|i|n5.类class parser{public:LLtable table[100][100]; //LL(1)表void scanner(); //扫描输入流中内容并分析parser(istream& in); //初始化,得到输入文件地址int getLine() const; //得到当前行数private:int match(); //分析语法stack <char> proStack; //分析堆栈void constructTable(); //建立LL(1)表int getRow(char ch); //取字符所在表中行int getCol(char ch); //取字符所在表中列istream* pstream; //输入流void insertToken(token& t); //插入当前tokenstatus getToken(token& t); //找到tokenint getChar(); //得到当前字符int peekChar(); //下一个字符void putBackChar(char ch); //将字符放回void skipChar(); //跳过当前字符void initialization(); //初始化堆栈等int line; //当前行数token tokens[1000]; //字符表int counter; //记录当前字符表使用范围}6.主要代码void parser::constructTable() //建立LL(1)表{for (int i=0;i<8;i++){for (int j=0;j<9;j++){table[i][j].left=' ';for (int k=0;k<3;k++)table[i][j].right[k]=' ';}}table[0][6].left='x';table[0][6].ln=3;table[0][6].right[0]='i';table[0][6].right[1]='=';table[0][6].right[2]='e';table[1][4].left='e';table[1][4].ln=2;table[1][4].right[0]='t';table[1][4].right[1]='c';table[1][6].left='e';table[1][6].ln=2;table[1][6].right[0]='t';table[1][6].right[1]='c';table[1][7].left='e';table[1][7].ln=2;table[1][7].right[0]='t';table[1][7].right[1]='c';table[2][0].left='c';table[2][0].ln=2;table[2][0].right[0]='a';table[2][0].right[1]='c';table[2][1].left='c';table[2][1].ln=2;table[2][1].right[0]='a';table[2][1].right[1]='c';table[2][5].left='c';table[2][5].ln=0;table[2][5].right[0]='!';table[2][8].left='c';table[2][8].ln=0;table[2][8].right[0]='!';table[3][0].left='a';table[3][0].ln=2;table[3][0].right[0]='+'; table[3][0].right[1]='t'; table[3][1].left='a';table[3][1].ln=2;table[3][1].right[0]='-'; table[3][1].right[1]='t'; table[4][4].left='t';table[4][4].ln=2;table[4][4].right[0]='f'; table[4][4].right[1]='d'; table[4][6].left='t';table[4][6].ln=2;table[4][6].right[0]='f'; table[4][6].right[1]='d'; table[4][7].left='t';table[4][7].ln=2;table[4][7].right[0]='f'; table[4][7].right[1]='d'; table[5][0].left='d';table[5][0].ln=0;table[5][0].right[0]='!'; table[5][1].left='d';table[5][1].ln=0;table[5][1].right[0]='!'; table[5][2].left='d';table[5][2].ln=2;table[5][2].right[0]='b'; table[5][2].right[1]='d'; table[5][3].left='d';table[5][3].ln=2;table[5][3].right[0]='b'; table[5][3].right[1]='d'; table[5][5].left='d';table[5][5].ln=0;table[5][5].right[0]='!'; table[5][8].left='d';table[5][8].ln=0;table[5][8].right[0]='!'; table[6][2].left='b';table[6][2].ln=2;table[6][2].right[0]='*'; table[6][2].right[1]='f'; table[6][3].left='b';table[6][3].ln=2;table[6][3].right[0]='/'; table[6][3].right[1]='f'; table[7][4].left='f';table[7][4].ln=3;table[7][4].right[0]='(';table[7][4].right[1]='e';table[7][4].right[2]=')';table[7][6].left='f';table[7][6].ln=1;table[7][6].right[0]='i';table[7][7].left='f';table[7][7].ln=1;table[7][7].right[0]='n';}int parser::match() //分析语法{ofstream ofs("out.txt",ios::app);char a;int i=0;for (int p=0;p<counter;p++){cout<<tokens[p].value;ofs<<tokens[p].value;}cout<<endl;ofs<<endl<<"ANALYSIS:"<<endl;while(1){if(tokens[i].category=='n' || tokens[i].category=='i')a=tokens[i].category;elsea=(tokens[i].value)[0];if(a==proStack.top()){if(a=='#'){cout<<"This is valid!"<<endl<<endl;ofs<<"This is valid!"<<endl<<endl;return 0;}else{proStack.pop();i++;}}else{if(proStack.top() =='n'|| proStack.top() =='i'){if(a!='#'){cout<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;}else{cout<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;}cout<<"This is invalid!"<<endl<<endl;ofs<<"This is invalid!"<<endl<<endl;return 0;}else{if((table[getRow(proStack.top())][getCol(a)]).left!=' '){char pst=proStack.top();int n=table[getRow(pst)][getCol(a)].ln;int k=0;ofs<<table[getRow(pst)][getCol(a)].left<<"->"<<table[getRow(pst)][getCol(a)].right[0]<<table[getRow(pst)][g etCol(a)].right[1]<<table[getRow(pst)][getCol(a)].right[2]<<endl;proStack.pop();while (n>0){//cout<<n<<" "<<table[getRow(pst)][getCol(a)].right[n-1]<<endl;proStack.push(table[getRow(pst)][getCol(a)].right[n-1]);n--;}}else{if(a!='#'){cout<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): "<<a<<" cannot be matched"<<endl;}else{cout<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;ofs<<"ERROR(LINE "<<getLine()<<" ): Unexpected ending"<<endl;}cout<<"This is invalid!"<<endl<<endl;ofs<<"This is invalid!"<<endl<<endl;return 0;}}}}}实验结果:●输入(in.txt)●输出1输出2(out.txt)实验总结:原本以为处理四则运算赋值将会很困难,但在使用LL(1)后发现,思路还是挺清晰简单的,但在实验过程中,由于LL(1)不能出现左递归和左公因子,不得不将其消除,原本简单的产生式一下变多了,而在产生式理解上也没有原来直观,不过其状态复杂度没有LR高,故仍选择该方法。
编译原理实验报告(语法分析器)
.编译原理实验专业:13级网络工程语法分析器1一、实现方法描述所给文法为G【E】;E->TE’E’->+TE’|空T->FT’T’->*FT’|空F->i|(E)递归子程序法:首先计算出五个非终结符的first集合follow集,然后根据五个产生式定义了五个函数。
定义字符数组vocabulary来存储输入的句子,字符指针ch指向vocabulary。
从非终结符E函数出发,如果首字符属于E的first集,则依次进入T函数和E’函数,开始递归调用。
在每个函数中,都要判断指针所指字符是否属于该非终结符的first集,属于则根据产生式进入下一个函数进行调用,若first集中有空字符,还要判断是否属于该非终结符的follow集。
以分号作为结束符。
二、实现代码头文件shiyan3.h#include<iostream>#include<cstdio>#include<string>using namespace std;#define num 100char vocabulary[num];char *ch;void judge_E();void judge_EE();void judge_T();void judge_TT();void judge_F();源文件#include"shiyan3.h"void judge_E(){if(*ch==';'){cout<<"该句子符合此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}elseif(*ch=='('||*ch=='i'){judge_T();judge_EE();}else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}void judge_EE(){if(*ch==';'){cout<<"该句子符合此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}if(*ch=='+'){ch++;judge_T();judge_EE();}elseif(*ch=='#'||*ch==')')return;else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}void judge_T(){if(*ch==';'){cout<<"该句子符合此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}if(*ch=='('||*ch=='i'){judge_F();judge_TT();}else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}void judge_TT(){if(*ch==';'){cout<<"该句子符合此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}if(*ch=='*'){ch++;judge_F();judge_TT();}elseif(*ch==')'||*ch=='+'||*ch=='#')return;else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}void judge_F(){if(*ch==';'){cout<<"该句子符合此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}if(*ch=='('){ch++;judge_E();if(*ch==')'){ch++;}else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}elseif(*ch=='i'){ch++;//cout<<*ch;}else{cout<<"该句子不匹配此文法!"<<endl;int a=0;cout<<"按1结束程序"<<endl;cin>>a;if(a==1)exit(0);}}void main(){//char *ch;cout<<"**********************欢迎使用语法分析器************************"<<endl;cout<<"请输入一个句子:"<<endl;cin.getline(vocabulary,15);ch=vocabulary;judge_E();cout<<endl;cout<<"************************结束使用,再见!**************************"<<endl;}三、运行结果四、心得体会此次实验使用的是递归子程序法,用这个方法最大的问题就是函数里的递归调用,一不小心就把人绕糊涂了。
语法分析实验报告
语法分析实验报告语法分析实验报告引言语法分析是自然语言处理中的一项重要任务,它旨在根据给定的语法规则和输入句子,确定句子的结构和语法成分,并进行语义解析。
本实验旨在探索语法分析的基本原理和方法,并通过实际操作来加深对其理解。
实验目标本实验的主要目标是实现一个简单的自底向上的语法分析器,即基于短语结构文法的分析器。
具体而言,我们将使用Python编程语言来实现一个基于CYK 算法的语法分析器,并对其进行评估和分析。
实验过程1. 语法规则的定义在开始实验之前,我们首先需要定义一个适当的语法规则集。
为了简化实验过程,我们选择了一个简单的文法,用于分析包含名词短语和动词短语的句子。
例如,我们定义了以下语法规则:S -> NP VPNP -> Det NVP -> V NP2. 实现CYK算法CYK算法是一种自底向上的语法分析算法,它基于动态规划的思想。
我们将使用Python编程语言来实现CYK算法,并根据定义的语法规则进行分析。
具体而言,我们将根据输入的句子和语法规则,构建一个二维的表格,用于存储句子中各个子串的语法成分。
通过填充表格并进行推导,我们可以确定句子的结构和语法成分。
3. 实验结果与分析我们使用几个示例句子来测试我们实现的语法分析器,并对其结果进行分析。
例如,对于句子"the cat eats fish",我们的语法分析器可以正确地识别出该句子的结构,并给出相应的语法成分。
具体而言,我们的分析器可以识别出句子的主语是"the cat",谓语是"eats",宾语是"fish"。
通过对多个句子的测试,我们可以发现我们实现的语法分析器在大多数情况下都能正确地分析句子的结构和语法成分。
然而,在一些复杂的句子中,我们的分析器可能会出现一些错误。
这可能是由于语法规则的不完备性或者算法的限制所致。
结论与展望通过本实验,我们深入了解了语法分析的基本原理和方法,并实现了一个简单的自底向上的语法分析器。
编译原理_语法分析器
编译原理实验报告语法分析器一.实验目的及内容实验目的:编制一个语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析。
实验内容:在上机(一)词法分析的基础上,采用递归子程序法或其他适合的语法分析方法,实现其语法分析程序。
要求编译后能检查出语法错误。
已知待分析的C语言子集的语法,用EBNF表示如下:<程序>→main()<语句块><语句块> →‘{’<语句串>‘}’<语句串> → <语句> {; <语句> };<语句> → <赋值语句> |<条件语句>|<循环语句><赋值语句>→ID=<表达式><条件语句>→if‘(‘条件’)’<语句块><循环语句>→while’(‘<条件>’)‘<语句块><条件> → <表达式><关系运算符> <表达式><表达式> →<项>{+<项>|-<项>}<项> → <因子> {* <因子> |/ <因子>}<因子> →ID|NUM| ‘(’<表达式>‘)’<关系运算符> →<|<=|>|>=|==|!=二、实验原理及基本技术路线图(方框原理图或程序流程图)三、所用仪器、材料(设备名称、型号、规格等或使用软件)1台PC以及VISUAL C++6.0软件四、实验方法、步骤(或:程序代码或操作过程)#include <iostream>#include <string>using namespace std;char prog[80],token[8];char ch;int syn,p,m,n,sum,k=0;char *key[6]={"main","int","char","if","else","while"};void scaner();void lrparser();void yucu();void statement();void expression();void term();void factor();void main(){p=0;cout<<"语法分析"<<endl;cout<<"请输入字符串,以“@”结尾:"<<endl;do {ch = getchar(); prog[p++]=ch;}while(ch!='@');p=0;scaner();lrparser();}void scaner(){sum=m=0;for(n=0;n<8;n++) token[n]=NULL;ch=prog[p++];while(ch==' ') ch=prog[p++];if((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')){while((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')) {token[m++]=ch; ch=prog[p++];}token[m++]='\0';p--;syn=10;for(n=0;n<6;n++)if(strcmp(token,key[n])==0){syn=n+1; break;}}else if(ch>='0'&&ch<='9'){while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=prog[p++];}p--;syn=20;}elseswitch(ch){case '<': m=0;token[m++]=ch;ch=prog[p++];if(ch=='<') {syn=33; token[m++]=ch;}else if(ch=='=') {syn=35; token[m++]=ch;}break;case '>': m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=34; token[m++]=ch;}else {syn=32; p--;}break;case '=':token[m++]=ch;ch=prog[p++];if(ch=='='){ syn=36;token[m++]=ch;}else{ syn=21;p--;}break;case ':': m=0;token[m++]=ch;ch=prog[p++];if(ch=='=') {syn=18; token[m++]=ch;}else {syn=17; p--;}break;case '+': syn=22; token[0]=ch; break;case '-': syn=23; token[0]=ch; break;case '*': syn=24; token[0]=ch; break;case '/': syn=25; token[0]=ch; break;case ';': syn=31; token[0]=ch; break;case '(': syn=26; token[0]=ch; break;case ')': syn=27; token[0]=ch; break;case '@': syn=0; token[0]=ch; break;default : syn=-1;}}void lrparser(){if(syn==1){scaner();yucu();if(syn=6){scaner();if(syn==0 && (k==0))cout<<"\nsuccess\n"<<endl;}else{if(k!=1)cout<<"\nwhile error\n"<<endl;k=1;}}else{cout<<"\nmain error\n"<<endl;k=1;}return;}void yucu(){statement();while(syn==31){scaner();statement();}return;}void statement(){if(syn==10){scaner();if(syn==18){scaner();expression();}else{cout<<"\nscentence error\n"<<endl;k=1;}}return;}void expression(){term();while(syn==22||syn==23){scaner();term();}return;}void term(){factor();while(syn==24||syn==25){scaner();factor();}return;}void factor(){if(syn==10||syn==20)scaner();else if(syn==26){scaner();expression();if(syn==27)scaner();else{cout<<"( error"<<endl;k=1;}}else{cout<<"expression error"<<endl;k=1;}return;}五、实验过程原始记录( 测试数据、图表、计算等)六、实验结果、分析和结论(误差分析与数据处理、成果总结等。
语法分析器设计实验报告
语法分析器设计实验报告一、引言语法分析器是编译器中的重要组成部分,其主要功能是根据给定的文法规则,对输入的程序代码进行语法分析,判断其是否符合语法规范。
本实验旨在设计一个简单的语法分析器,通过实际实现一个基于LL(1)文法的语法分析器,深入了解语法分析的原理和实现方法。
二、实验目标本实验的目标是设计一个能够接受一个输入的程序代码并进行语法分析的程序。
具体而言,需要实现以下功能:1. 构建一个文法规则集合,用于描述程序代码的语法规范;2. 设计并实现一个LL(1)分析表,用于存储语法分析所需的预测分析表;3. 实现语法分析器,能够根据输入的程序代码,逐步地进行语法分析,并输出相应的结果。
三、实验环境本实验使用的是Java语言进行实现,操作系统环境为Windows 10。
使用的集成开发环境为Eclipse。
四、实验步骤1. 设计文法规则集合在语法分析器设计中,首先需要设计一个文法规则集合,用于描述需要分析的程序代码的语法规范。
文法规则集合的设计要符合LL(1)文法的要求,即每个非终结符的产生式至多有一个与输入符号串首符号相关的产生式。
2. 构建LL(1)分析表根据文法规则集合,构建一个LL(1)分析表,用于存储语法分析所需的预测分析表。
LL(1)分析表是一个二维表,其中行表示非终结符,列表示终结符。
表中的每个元素表示相应的产生式编号,用于指示语法分析器在分析过程中应该使用哪个产生式。
构建LL(1)分析表的方法包括:- 遍历文法规则集合,计算每个非终结符的FIRST集合和FOLLOW集合;- 根据计算得到的FIRST集合和FOLLOW集合,填充LL(1)分析表。
3. 实现语法分析器根据LL(1)分析表,实现一个语法分析器。
语法分析器的输入是一个程序代码,输出是语法分析器的分析结果。
实现语法分析器的主要过程包括:- 初始化分析栈,将文法规则的开始符号入栈;- 从输入的程序代码中读取下一个终结符;- 如果分析栈的栈顶是非终结符,根据LL(1)分析表中对应的产生式编号,将产生式右部的符号依次入栈;- 如果分析栈的栈顶是终结符,并且与输入的终结符相同,则将该终结符出栈,并继续读取下一个终结符;- 重复上述过程,直到分析栈为空或者无法继续推导。
编译原理实验——语法分析器报告
组员学号姓名实验名称对各算术表达式进行语法分析实验室实验目的或要求实验目的:1、掌握语法分析器生成工具的使用和了解编译器的设计;2、了解自上而下语法分析器的构造过程;3、能够构造LR分析表,编写由该分析表驱动的语法分析器程序;4、借助语法制导翻译,可在语法分析的同时,完成对语义的翻译;5、借助语法分析,设计一个表达式的判断分析器,即从键盘上输入算术表达式,分析器将显示该表达式的正确与否。
实验原理(算法流程)实验算法流程图如下所示:开始输入表达式表达式保存到数ch第一个元素为)+-*/YCh[i]=’(’i++YNCh[i]=NULLNCh[i]是0~9i++YCh[i]是0~9Ch[i]=+ -*/)N多了+ -*/)Y其他错误NYCh[i]=* /Ni++YCh[i]=+ -*/NY多了+ -*/Ch[i]=+ -NNCh[i]=)Y少了)N错误首部多了) +-*/结束程序界面(效果图)实验结果界面:只选择几个典型的例子进行分析,可进行任意表达式输入。
1)未进行语法分析时的界面;2)输入正确的表达式(1+2)*(6-3)+1进行语法分析时的界面结果;3)输入错误的表达式1*2+(2+3并进行语法分析时的界面结果;程序界面(效果图)4)输入错误的表达式1+(+5+6)并进行语法分析时的界面结果;程序界面(效果图)程序代码 #include "stdafx.h"#include "grammer.h"#include "mfc_语法分析器.h"#include "mfc_语法分析器Dlg.h"int flag;int i,j;int length;CString string;int grammer(CString str){i=0;flag=0;char ch[MAX];length=str.GetLength();strcpy(ch,str);if(length!=0){F(ch);if(flag==0){MessageBox(NULL,"输入表达式符合文法","正确",MB_OK|MB_ICONINFORMATION);}//str=ch;//return flag;}else{MessageBox(NULL,"表达式为空","提示",MB_OK|MB_ICONW ARNING);//MessageBox(NULL,"表达式为空","提示",MB_OK|MB_ICONERROR);return -1;}return flag;}void F(char ch[]){if(ch[0]=='+'){程序代码flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR); MessageBox(NULL,"开始处多了+","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='-'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了-","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='*'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了*","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]=='/'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了/","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}elseif(ch[0]==')'){flag=0;MessageBox(NULL,"输入表达式不符合文法0","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"开始处多了)","提示",MB_OK|MB_ICONINFORMA TION);flag=1;}/*上述为对第一个字符的特殊处理*/elseif(ch[i]!=NULL){if(ch[i]=='('){i++;F(ch);程序代码if(ch[i]!=')'){if(flag==0){MessageBox(NULL,"输入表达式不符合文法1","错误",MB_OK|MB_ICONERROR);MessageBox(NULL,"少了')'","提示",MB_OK|MB_ICONINFORMATION);}flag=1;}else{i++;if(ch[i]!=NULL)T(ch);}}elseif(ch[i]<='9'&&ch[i]>='0'){while(ch[i]<='9'&&ch[i]>='0')i++;if(ch[i]!=NULL)T(ch);}else{if(flag==0){if(ch[i]!=NULL&&ch[i]!=')'){MessageBox(NULL,"输入表达式不符合文法2.1","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='+') {MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);程序代码else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]==NULL){MessageBox(NULL,"输入表达式不符合文法2.2","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]!=NULL&&ch[i]==')'){MessageBox(NULL,"输入表达式不符合文法2.3","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='(') MessageBox(NULL,"含有一对空括号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}}flag=1;}}}void T(char ch[]){if(ch[i]=='*'||ch[i]=='/')程序代码{i++;if(ch[i]!=NULL&&ch[i]!='+'&&ch[i]!='-'&&ch[i]!='*'&&ch[i]!='/')F(ch);else{if(flag==0){MessageBox(NULL,"输入表达式不符合文法3","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='+') MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}flag=1;}}elseE(ch);}void E(char ch[]){if(ch[i]=='+'||ch[i]=='-'){i++;if(ch[i]!=NULL&&ch[i]!='+'&&ch[i]!='-'&&ch[i]!='*'&&ch[i]!='/')F(ch);else{if(flag==0){if(ch[i]!=NULL){MessageBox(NULL,"输入表达式不符合文法4.1","错误",MB_OK|MB_ICONERROR);if(ch[i]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);程序代码else if(ch[i]=='+') MessageBox(NULL,"多了'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='-') MessageBox(NULL,"多了'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='*') MessageBox(NULL,"多了'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i]=='/') MessageBox(NULL,"多了'/'号","提示",MB_OK|MB_ICONINFORMA TION);}else if(ch[i]==NULL){MessageBox(NULL,"输入表达式不符合文法4.2","错误",MB_OK|MB_ICONERROR);if(ch[i-1]==' ') MessageBox(NULL,"含有空格","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='+') MessageBox(NULL,"多了最后的'+'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='-') MessageBox(NULL,"多了最后的'-'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='*') MessageBox(NULL,"多了最后的'*'号","提示",MB_OK|MB_ICONINFORMA TION);else if(ch[i-1]=='/') MessageBox(NULL,"多了最后的'/'号","提示",MB_OK|MB_ICONINFORMA TION);}}flag=1;}}else if(ch[i]!=')'){if(flag==0){MessageBox(NULL,"输入表达式不符合文法5","错误",MB_OK|MB_ICONERROR);if(ch[i]=='('&&ch[i+2]==')') MessageBox(NULL,"含有一对多余的括号","提示",MB_OK|MB_ICONINFORMA TION);else MessageBox(NULL,"其他类型的错误","提示",MB_OK|MB_ICONINFORMA TION);}flag=1;}}实验结果分析及心得体会实验结果分析:本次实验借助语法分析,设计一个表达式的判断分析器,从键盘上输入算术表达式,分析器对该表达式的正确与否进行分析。
语法分析实验报告
语法分析实验报告一、实验目的语法分析是编译原理中的重要环节,本次实验的目的在于深入理解和掌握语法分析的基本原理和方法,通过实际操作和实践,提高对编程语言语法结构的分析能力,为进一步学习编译技术和开发相关工具打下坚实的基础。
二、实验环境本次实验使用的编程语言为 Python,使用的开发工具为 PyCharm。
三、实验原理语法分析的任务是在词法分析的基础上,根据给定的语法规则,将输入的单词符号序列分解成各类语法单位,并判断输入字符串是否符合语法规则。
常见的语法分析方法有自顶向下分析法和自底向上分析法。
自顶向下分析法包括递归下降分析法和预测分析法。
递归下降分析法是一种直观、简单的方法,但存在回溯问题,效率较低。
预测分析法通过构建预测分析表,避免了回溯,提高了分析效率,但对于复杂的语法规则,构建预测分析表可能会比较困难。
自底向上分析法主要包括算符优先分析法和 LR 分析法。
算符优先分析法适用于表达式的语法分析,但对于一般的上下文无关文法,其适用范围有限。
LR 分析法是一种功能强大、适用范围广泛的方法,但实现相对复杂。
四、实验内容(一)词法分析首先,对输入的源代码进行词法分析,将其分解为一个个单词符号。
单词符号包括关键字、标识符、常量、运算符、分隔符等。
(二)语法规则定义根据实验要求,定义了相应的语法规则。
例如,对于简单的算术表达式,可以定义如下规则:```Expression > Term | Expression '+' Term | Expression ''TermTerm > Factor | Term '' Factor | Term '/' FactorFactor >'(' Expression ')'| Identifier | Number```(三)语法分析算法实现选择了预测分析法来实现语法分析。
首先,根据语法规则构建预测分析表。
然后,从输入字符串的起始位置开始,按照预测分析表的指导进行分析。
编译原理语法分析实验报告
编译原理语法分析实验报告一、实验目的本实验主要目的是学习和掌握编译原理中的语法分析方法,通过实验了解和实践LR(1)分析器的实现过程,并对比不同的文法对语法分析的影响。
二、实验内容1.实现一个LR(1)的语法分析器2.使用不同的文法进行语法分析3.对比不同文法对语法分析的影响三、实验原理1.背景知识LR(1)分析器是一种自底向上(bottom-up)的语法分析方法。
它使用一个分析栈(stack)和一个输入缓冲区(input buffer)来处理输入文本,并通过移进(shift)和规约(reduce)操作进行语法分析。
2.实验步骤1)构建文法的LR(1)分析表2)读取输入文本3)初始化分析栈和输入缓冲区4)根据分析表进行移进或规约操作,直至分析过程结束四、实验过程与结果1.实验环境本实验使用Python语言进行实现,使用了语法分析库ply来辅助实验。
2.实验步骤1)构建文法的LR(1)分析表通过给定的文法,根据LR(1)分析表的构造算法,构建出分析表。
2)实现LR(1)分析器使用Python语言实现LR(1)分析器,包括读取输入文本、初始化分析栈和输入缓冲区、根据分析表进行移进或规约操作等功能。
3)使用不同的文法进行语法分析选择不同的文法对编写的LR(1)分析器进行测试,观察语法分析的结果。
3.实验结果通过不同的测试案例,实验结果表明编写的LR(1)分析器能够正确地进行语法分析,能够识别出输入文本是否符合给定文法。
五、实验分析与总结1.实验分析本实验通过实现LR(1)分析器,对不同文法进行语法分析,通过实验结果可以观察到不同文法对语法分析的影响。
2.实验总结本实验主要学习和掌握了编译原理中的语法分析方法,了解了LR(1)分析器的实现过程,并通过实验提高了对语法分析的理解。
六、实验心得通过本次实验,我深入学习了编译原理中的语法分析方法,了解了LR(1)分析器的实现过程。
在实验过程中,我遇到了一些问题,但通过查阅资料和请教老师,最终解决了问题,并完成了实验。
ll 1 语法分析实验报告
ll 1 语法分析实验报告语法分析实验报告一、引言语法分析是编译器中的重要步骤之一,它负责将输入的源代码转化为语法树或抽象语法树,以便后续的语义分析和代码生成。
本实验旨在通过实现一个简单的LL(1)语法分析器,加深对语法分析原理和算法的理解。
二、实验目的1. 理解LL(1)语法分析的原理和算法;2. 掌握使用LL(1)文法描述语言的方法;3. 实现一个简单的LL(1)语法分析器。
三、实验环境本实验使用C++编程语言,开发环境为Visual Studio。
四、实验步骤1. 设计LL(1)文法在开始实现LL(1)语法分析器之前,我们需要先设计一个LL(1)文法。
LL(1)文法是一种满足LL(1)分析表构造要求的文法,它能够保证在语法分析过程中不会出现二义性或回溯。
通过仔细分析待分析的语言的语法规则,我们可以设计出相应的LL(1)文法。
2. 构造LL(1)分析表根据设计的LL(1)文法,我们可以构造出对应的LL(1)分析表。
LL(1)分析表是一个二维表格,其中的行表示文法的非终结符,列表示文法的终结符。
表格中的每个元素表示在某个非终结符和终结符的组合下,应该进行的语法分析动作。
3. 实现LL(1)语法分析器基于构造的LL(1)分析表,我们可以开始实现LL(1)语法分析器。
分析器的主要工作是根据输入的源代码和LL(1)分析表进行分析,并输出语法树或抽象语法树。
五、实验结果与分析经过实验,我们成功实现了一个简单的LL(1)语法分析器,并对一些简单的语言进行了分析。
实验结果表明,我们设计的LL(1)文法和LL(1)分析表能够正确地进行语法分析,没有出现二义性或回溯。
六、实验总结通过本次实验,我们深入学习了LL(1)语法分析的原理和算法,并通过实现一个简单的LL(1)语法分析器加深了对其的理解。
实验过程中,我们发现LL(1)文法的设计和LL(1)分析表的构造是实现LL(1)语法分析器的关键。
同时,我们也意识到LL(1)语法分析器在处理复杂的语言时可能会面临一些困难,需要进一步的研究和优化。
语法分析器实验报告
语法分析器实验报告实验报告:语法分析器的设计与实现摘要:语法分析器是编译器的一个重要组成部分,主要负责将词法分析器输出的词法单元序列进行分析和解释,并生成语法分析树。
本实验旨在设计与实现一个基于上下文无关文法的语法分析器,并通过实现一个简单的编程语言的解释器来验证其功能。
1.引言在计算机科学中,编译器是将高级程序语言转化为机器语言的一种工具。
编译器通常由词法分析器、语法分析器、语义分析器、中间代码生成器、优化器和目标代码生成器等多个模块组成。
其中,语法分析器负责将词法分析器生成的词法单元序列进行进一步的分析与解释,生成语法分析树,为后续的语义分析和中间代码生成提供基础。
2.设计与实现2.1上下文无关文法上下文无关文法(CFG)是指一类形式化的语法规则,其中所有的产生式规则都具有相同的左部非终结符,且右部由终结符和非终结符组成。
语法分析器的设计与实现需要依据给定的上下文无关文法来进行,在本实验中,我们设计了一个简单的CFG,用于描述一个名为"SimpleLang"的编程语言。
2.2预测分析法预测分析法是一种常用的自顶向下的语法分析方法,它利用一个预测分析表来决定下一步的推导选择。
预测分析表的构造依赖于给定的上下文无关文法,以及文法的FIRST集和FOLLOW集。
在本实验中,我们使用了LL(1)的预测分析法来实现语法分析器。
2.3语法分析器实现在实现语法分析器的过程中,我们首先需要根据给定的CFG构造文法的FIRST集和FOLLOW集,以及预测分析表。
接下来,我们将词法分析器输出的词法单元序列作为输入,通过不断地匹配输入符号与预测分析表中的预测符号,进行语法分析和推导。
最终,根据CFG和推导过程,构建语法分析树。
3.实验结果与分析通过实验发现,自顶向下的预测分析法在对简单的编程语言进行语法分析时具有较高的效率和准确性。
语法分析器能够正确地识别输入程序中的语法错误,并生成相应的错误提示信息。
语法分析器实验报告
杭州电子科技大学班级: 12052312 专业: 计算机科学与技术实验报告【实验名称】实验二语法分析一. 实验目的编写一个语法分析程序, 实现对词法分析程序所提供的单词序列的语法检查和结构分析。
二. 实验内容利用编程语言实现语法分析程序, 并对简单语言进行语法分析。
2.1 待分析的简单语言的语法用扩充的BNF表示如下:⑴<程序>: : =begin<语句串>end⑵<语句串>: : =<语句>{;<语句>}⑶<语句>: : =<赋值语句>⑷<赋值语句>: : =ID: =<表达式>⑸<表达式>: : =<项>{+<项> | -<项>}⑹<项>: : =<因子>{*<因子> | /<因子>⑺<因子>: : =ID | NUM | (<表达式>)2.2 实验要求说明输入单词串, 以“#”结束, 如果是文法正确的句子, 则输出成功信息, 打印“success”, 否则输出“error”。
例如:输入begin a:=9; x:=2*3; b:=a+x end #输出success!输入x:=a+b*c end #输出error测试以上输入的分析, 并完成实验报告。
2.3 语法分析程序的算法思想(1)主程序示意图如图2-1所示。
图2-1 语法分析主程序示意图(2)递归下降分析程序示意图如图2-2所示。
(3)语句串分析过程示意图如图2-3所示。
图2-3 语句串分析示意图图2-2 递归下降分析程序示意图(4)statement 语句分析程序流程如图2-4.2-5.2-6.2-7所示。
图2-4 statement 语句分析函数示意图 图2-5 expression 表达式分析函数示意图图2-7 factor 分析过程示意图三.个人心得一、 通过该实验, 主要有以下几方面收获: 二、 对实验原理有更深的理解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
语法分析器的设计实验报告一、实验内容语法分析程序用LL(1)语法分析方法。
首先输入定义好的文法书写文件(所用的文 法可以用LL(1)分析),先求出所输入的文法的每个非终结符是否能推出空, 再分 别计算非终结符号的FIRST 集合,每个非终结符号的FOLLOW 集合,以及每个 规则的SELECT 集合,并判断任意一个非终结符号的任意两个规则的 SELECT 集的交集是不是都为空,如果是,则输入文法符合 LL(1)文法,可以进行分析。
对于文法: G[E]: E->E+T|T T->T*F|F F->i|(E)分析句子i+i*i 是否符合文法。
二、基本思想1、语法分析器实现语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词 法分析输出的源程序符号串中识别出各类语法成分, 同时进行词法检查,为语义 分析和代码生成作准备。
这里采用自顶向下的 LL(1)分析方法。
语法分析程序的流程图如图5-4所示。
该程序可分为如下几步:读入文法 判断正误若无误,判断是否为LL(1)文法 若是,构造分析表; 由句型判别算法判断输入符号串是为该文法的句型。
三、核心思想该分析程序有15部分组成:(1) 首先定义各种需要用到的常量和变量; (2) 判断一个字符是否在指定字符串中;(1) (2) (3) (4)(5)(3) (4) (5)(6)(7)(8)(9)(10) (11) (12) (13) (14)(15) 下面是其中几部分程序段的算法思想: 1、求能推出空的非终结符集I 、实例中求直接推出空的 empty 集的算法描述如下: void emp (char c ){ 参数 c 为空符号 chartemp[10]; 定义临时数组 int i;for (i=0;i<=count-1;i++) 从文法的第一个产生式开始查找 {if 产生式右部第一个符号是空符号并且右部长度为 then 将该条产生式左部符号保存在临时数组 将临时数组中的元素合并到记录可推出}n 、求某一符号能否推出&int _emp (char c ) {//若能推出 &,返回 1 ;否则,返回 0int i,j,k,result=1,mark=0; char temp[20]; temp[0]=c; temp[1]='\0';存放到一个临时数组 empt 里,标识此字符已查找其是否可推出空字 如果 c 在可直接推出空字的empty[] 中,返回 1 for (i=0;;i++){if (i==count )return (0);找一个左部为 c 的产生式 j=strlen (right[i]);if 右部长度为 if 右部长度为 else{读入一个文法; 将单个符号或符号串并入另一符号串; 求所有能直接推出 & 的符号;求某一符号能否推出‘ & '; 判断读入的文法是否正确; 求单个符号的 FIRST ; 求各产生式右部的 FIRST ; 求各产生式左部的 FOLLOW ; 判断读入文法是否为一个 LL (1) 文法; 构造分析表 M ; 句型判别算法; 一个用户调用函数; 主函数;1, temp 中 & 符号的数组 empty 中。
//j 为 c 所在产生式右部的长度1且右部第一个字符在 empty[]中.then 返回1(A->B,B 可推出空) 1 但第一个字符为终结符 ,then 返回 0(A->a,a 为终结符 )for(k=0;k<=j-1;k++){查找临时数组 empt[]. 并标记 mark-=1(A->AB)if 找到的字符与当前字符相同 (A->AB) 结束本次循环 else(mark 等于 0)查找右部符号是否可推出空字 ,把返回值赋给 result 把当前符号加入到临时数组empt[] 里.当前字符不能推出空字且还没搜索完全部的产生式 then 跳出本次循环继续搜索下一条产生式 else if // 当前字符可推出空字 ,返回}2、计算每个符号的 first 集: 实例中求单个符号的 FIRST 集的算法描述如下: void first2(int i) { 参数 i 为符号在所有输入符号中的序号 c 等于指示器 i 所指向的符号 在保存终结符元素的 termin[] 数组查找 cif c 为终结符(c € V T ), then FIRST(c)={c} 在保存终结符元素的 non_ter[] 数组查找 c if c 是非终结符(c € V N )在所有产生式中查找 c 所在的产生式 if 产生式右部第一个字符为终结符或空 把 a 或 & 加进 FIRST(c) if 产生式右部第一个字符为非终结符if 产生式右部的第一个符号等于当前字符 then 跳到下一条产生式进行查找 求当前非终结符在所有字符集中的位置 if 当前非终结符还没求其 FIRST 集 then 查找它的FIRST 集并标识此符号已求其 FIRST 集 求得结果并入到 c 的 FIRST 集 .if 当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符 获取右部符号下一个字符在所有字符集中的位置 if 此字符的 FIRST 集还未查找 then 找其FIRST 集 ,并标其查找状态为 1 把求得的 FIRST 集并入到 c 的 FIRST 集 . if 当前右部符号串可推出空且是右部符号串的最后一个字符(即产生式为 c7丫1丫2…Y k ,若对一切 1<=i<=k ,均有 & € FIRST(Y i ),则将 & €符号加进 FIRST(c)) then把空字加入到当前字符 c 的FIRST 集.else不能推出空字则结束循环标识当前字符c 已查找其FIRST 集.}3. 计算 FOLLOWFOLLOW 集的构造可用如下方法来求:对于文法中的符号 X V N ,其FOLLOW(A)集合可反复应用下列规则计算,直到FOLLOW(A)集合不再增大为止。
(1) 对于文法开始符号 S ,因为S S ,故# FOLLOW(S); (2) 若 A7 B ,其中 B V N ,(V T V N )*、 (V T V N )+,贝UFIRST( )-{ } FOLLOW(B); (3) 若 A 7 B 或 A 7 B (禺),贝yFOLLOW(A) FOLLOW(B)。
FOLLOW 集的算法描述如下: void FOLLOW(i nt i)}if(即 C7 a (a € V T )或 &) thenthenthenX为待求的非终结符把当前字符放到一临时数组fo叩中,标识求已求其FOLLOW集.避免循环递归if X 为开始符号then # € FOLLOW(X)对全部的产生式找一个右部含有当前字符X的产生式注:比如求FOLLOW(B)则找A7a X或A7 X (兰> £ )的产生式if X在产生式右部的最后(形如产生式A7 X) then 查找非终结符A是否已经求过其FOLLOW 集.避免循环递归if 非终结符A已求过其FOLLOW集thenFOLLOW(A) € FOLLOW(X)继续查下一条产生式是否含有Xelse求A之FOLLOW 集,并标识为A已求其FOLLOW 集else if X不在产生式右部的最后(形如A 7 B ) thenif右部X后面的符号串能推出空字then查找是否已经求过其FOLLOW集.避免循环递归if 已求过的FOLLOW 集thenFOLLOW(A) € FOLLOW(B)结束本次循环else if 不能推出空字then求FIRST()把FIRST()中所有非空元素加入到FOLLOW(B)中标识当前要求的非终结符X的FOLLOW 集已求过4.计算 SELECT!SELECT集的构造算法如下:对所有的规则产生式 A 7 X:(1)若X 不能推出空字,贝y SELECT(A 7X) = FIRST(x);(2)若X 可推出空字,贝U SELECT(A 7x)=FIRST(x) - { } FOLLOW(A)。
算法描述如下:for(i=0;i<=产生式总数-1;i++)先把当前产生式右部的FIRST集(一切非空元素,不包括£放入到当前产生式的SELECT(i);if 产生式右部符号串可推出空字 then 把 i 指向的当前产生式左部的非终结符号的 FOLLOW 集并入到 SELECT(i) 中 5.判断是否 LL(1) 文法 要判断是否为 LL(1) 文法,需要输入的文法 G 有如下要求: 具有相同左部的规则的 SELECT 集两两不相交,即: SELECT(A T ) nSELECT(A )= 如果输入的文法都符合以上的要求,则该文法可以用 算法描述如下: 把第一条产生式的 SELECT(0) 集放到一个临时数组 temp[] 中 for(i=1;i<= 产生式总数 -1;i++) 求 temp 的长度 length if i 指向的当前产生式的左部等于上一条产生式的左部 temp 数组中 length 加上 SELECT (i) 的长度LL(1) 方法分析。
then 把 SELECT(i) 并入到 If temp 的长度小于 返回 0else 把 temp 清空 把 SELECT (i) 存放到 结果返回 1 ; 四、算法 temp 中#include<stdlib.h> #include<stdio.h> #include<string.h> /*******************************************/ int count=0; int number;char start; char termin[50]; char non_ter[50]; char v[50]; charleft[50]; char right[50][50]; //产生式的个数//所有终结符和非终结符的总数 //开始符号 //终结符号 //非终结符号//所有符号 //左部 //右部char first[50][50],follow[50][50]; char first1[50][50]; charselect[50][50]; char firstflag[50],followflag[50]; char empty[20]; char nonempty[20]; char empt[20]; char TEMP[50]; int int //各产生式右部的 FIRST 和左部的 FOLLOW 集合 // 所有单个符号的 FIRST 集合 //各个产生式的 SELECT 集合 //记录各符号的 FIRST 和 FOLLOW 是否已求过 //记录可推出 & 的符号 //记录不可推出 & 的符号II 求_em p()时使用 //求 FOLLOW 时存放某一符号串的 FIRST 集合 in tvalidity=1; ll=1; M[20][20]; II 表示输入文法是否有效 II 表示输入文法是否为 LL(1)文法 II 分析表}} }char choose; //用户输入时使用 char foll[20]; // 求 FOLLOW 集合时使用/******************************************* 判断一个字符 c 是否在指定字符串 p 中 ********************************************/ int in(char c,char *p) { int i; if(strlen(p)==0) return(0); for(i=0;;i++) {if(p[i]==c)return(1); if(i==(int)strlen (p)) return(0); //若在,返回 1 //若不在,返回 0 /******************************************* 将单个符号或符号串并入另一符号串 ********************************************/void merge(char *d,char *s,int type) { 〃是目标符号串,s 是源串,type = 1,源串中的&一并并入目串;//type = 2,源串中的&不并入目串int i,j; for(i=0;i<=(int)strlen(s)-1;i++) {if(type==2&&s[i]=='&'); else{for(j=0;;j++){if(j<(int)strlen(d)&&s[i]==d[j])break;//若已存在,则退出,继续看下一个源串字符if(j==(int)strlen(d)) //若不存在,则并入{d[j]=s[i]; d[j+1]='\0'; break;}/*******************************************读入一个文法********************************************/ char grammer(char *t,char *n,char *left,char right[50][50]){char vn[50],vt[50]; char s; char p[50][50]; int i,j;printf(" 请输入文法的非终结符号串: "); scanf("%s",vn); getchar(); i=strlen(vn); memcpy(n,vn,i); n[i]='\0';printf(" 请输入文法的终结符号串: scanf("%s",vt); getchar(); i=strlen(vt); memcpy(t,vt,i); t[i]='\0';printf(" 请输入文法的开始符号: scanf("%c",&s); getchar();printf(" 请输入文法产生式的条数: scanf("%d",&i); getchar(); count=i; for(j=1;j<=i;j++) {printf(" 请输入文法的第 %d 条(共 %d 条)产生式: ",j,i); scanf("%s",p[j-1]); getchar();}for(j=0;j<=i-1;j++){if(p[j][1]!='-'||p[j][2]!='>') // 检测输入错误 {printf("\n 输入错误 !"); validity=0; return('\0');}return(s);"); ");");} }}/******************************************* 判断读入的文法是否正确 ********************************************/ int judge() {int i,j; for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ // 若左部不在非终结符中,报错 printf("\n 文法左部出错 !"); validity=0;return(0);}for(j=0;j<=(int)strlen(right[i])-1;j++){//若右部某一符号不在非终结符、终结符中且不为'&' ,报错printf("\n 文法右部出错 !"); validity=0; return(0);} }}return(1);/*******************************************求所有能直接推出 & 的符号********************************************/ void emp(char c){char temp[10]; int i;for(i=0;i<=count-1;i++) {if(right[i][0]==c&&strlen(right[i])==1){temp[0]=left[i]; temp[1]='\0';merge(empty,temp,1);// 求所有能直接推出 '&" 的符号 ,结果保存到 empty[] 中 emp(left[i]);if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right [i][j]!='&') {}/*******************************************求某一符号能否推出'&' ********************************************/ int _emp(char c){ //若能推出&,返回1;否则,返回0int i,j,k,result=1,mark=0;char temp[20]; temp[0]=c;temp[1]='\0';merge(em pt,tem p,1);//存放到一个临时数组empt里,标识此字符已查找其是否可推出空字if(in(c,empty)==1)//如果c在可直接推出空字的empty[]中,返回1return(1);for(i=0;;i++){ if(i==count) return(0);if(left[i]==c)//找一个左部为 c 的产生式{j=strlen(right[i]); //j 为 c 所在产生式右部的长度if(j==1&&in(right[i][0],empty)==1)// 右部长度为 1 且右部第一个字符在empty[] 中.返回1(A->B,B 可推出空)return(1);else if(j==1&&in(right[i][0],termin)==1)// 右部长度为 1 但第一个字符为终结符返回0(A->a,a 为终结符)continue;else{for(k=0;k<=j-1;k++){if(in(right[i][k],empt)==1)// 查找临时数组empt[].(A->AB) mark=1;}if(mark==1) //找到的字符与当前字符相同(A->AB)continue; //结束本次循环else //(mark 等于0){for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);// 递归调用,查找右部符号是否可推出空字, 把返回值赋给resulttemp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);//把当前符号加入到临时数组empt[]里,标记已查找}if(result==0&&i<count)// 如果当前字符不能推出空字且还没搜索完全部的产生 式,贝跳出本次循环继续搜索下一条产生式continue;else if(result==1&&i<count)// 当前字符可推出空字 ,返回 1 return(1);}}/*******************************************求单个符号的 FIRST********************************************/ void first2(int i){char c,temp[20]; int j,k,m; char ch='&'; c=v[i];emp(ch);//求所有能直接推出空字的符号,结果保存到empty[]中 if(in(c,termin)==1){first1[i][0]=c; first1[i][1]='\0';}else if(in(c ,non_ter)==1){for(j=0;j<=count-1;j++) //j 为所有产生式中的序列{if(left[j]==c) // 找一个左部为 c 的产生式{if(in(right[j][0],termin)==1||right[j][0]=='&') {//若产生式右部第一个字符为终结符或空.---产生式X 7 a (a € VT)或X&, 贝把 a 或&加进 FIRST(X)temp[0]=right[j][0]; temp[1]='\0'; merge(first1[i],temp ,1);}//——X 7 Y1Y2…Yk 的产生式,若 丫1 € VN ,则把FIRST(Y1)中的一切非空符号加进 FIRST(X)else if(in(right[j][0],non_ter)==1)// 产生式右部第一个字符为非终结符{//i 为符号在所有输入符号中的序号〃若为终结符--C € VT ,贝y FIRST(c)={c}//若为非终结符if(right[j][0]==c)II 产生式右部的第一个符号等于当前字符break;}if(firstflag[m]=='0')II 如果此字符的 FIRST 集还未查找 ,则找其 FIRST 集,并标其查找状态为 1{first2(m); firstflag[m]='1';}merge(first1[i],first1[m],2);// 把求得结果并入到 X 的 FIRST集.}II ——产生式为 X7 Y1Y2…Yk,若对一切 1<=i<=k ,均有& € FIRST(Yi),则将& €符号加进FIRST(X)else if(_emp(right[j][k])==1&&k==(int)strlen(right[j])-1) {II 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&'; temp[1]='\0';merge(first1[i],temp,1);II 把空字加入到当前字符 X 的 FIRST集.,则跳到下一条产生式进行查找 可推出空字 一个字符 有字符集中的位置 continue; for(k=0;;k++){if(v[k]==right[j][0])II 求右部第一个字符在所有字符集中的位置 kbreak;}if(firstflag[k]=='0'){first2(k);II 求其 FIRST 集 firstflag[k]='1';II 标识其为查找状态}merge(first1[i],first1[k],2);// 求得结果并入到 X 的 FIRST集. for(k=0;k<(int)strlen(right[j]);k++){empt[0]='\0';// 存放到一个临时数组里 , 标识此字符已查找其是否 if(_emp(right[j][k])==1&&k<(int)strlen(right[j])-1){II 当前产生式右部符号可推出空字 ,且当前字符不是右部的最for(m=0;;m++){if(v[m]==right[j][k+1])// 获取右部符号下一个字符在所}elsebreak;//不能推出空字则结束循环}}}firstflag[i]='1';//标识当前字符c 已查找其FIRST 集 }/******************************************* 求各产生式右部的 FIRST ********************************************/ void FIRST(int i,char *p) {//指针 p 指向右部符号串int len gth;//标识右部符号串的长度 int j,k,m; char temp[20];length=strlen(p); if(length==1){if(p[0]=='&')// 右部符号串字符为 "&" 空字 {if(i>=0)//i 不为 -1 时是产生式的序号 {TEMP[0]='&'; TEMP[1]='\0';}else//右部符号串字符不为 {for(j=0;;j++){if(v[j]==p[0])//求右部符号的第一个字符 p[0]在所有字符集中的位置 jbreak;}if(i>=0){//如果右部为单个符号first[i][0]='&'; //把"&" 加入到当前符号串的 FIRST 集 }else//i 为-1时,表示求FOLLOW 时用到的产生式右部的 FIRST 集 ,保存在 TEMP[]"&" 空字memcpy(first[i],first1[j],strlen(first1[j]));// 把j 所指向的单个符号的FIRST 集拷贝到该右部符号串的FIRST 集first[i][strlen(first1[j])]='\0';} else{memcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';} else{//如果右部为符号串for(j=0;;j++){if(v[j]==p[0])// 求右部符号的第一个字符p[0] 在所有字符集中的位置j break;}if(i>=0) merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2); for(k=0;k<=length-1;k++){empt[0]='\0';if(_emp(p[k])==1&&k<length-1){ // 当前产生式右部符号可推出空字, 且当前字符不是右部的最后一个字符for(m=0;;m++){if(v[m]==right[i][k+1]) break;} if(i>=0)merge(first[i],first1[m],2); elsemerge(TEMP,first1[m],2);}else if(_emp(p[k])==1&&k==length-1){// 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);}else if(_emp(p[k])==0)break;}}/*******************************************求各产生式左部的 FOLLOW ********************************************/ void FOLLOW(int i){ // 参数 i 为该符号在非终结符中的位置 int j,k,m,n,result=1; char c,temp[20]; c=non_ter[i];temp[0]=c; temp[1]='\0';merge(foll,temp,1);// 把当前字符放到一临时数组 foll[] 中 ,标识求已求其 FOLLOW 集.避免循环递归中的位置}for(m=0;;m++){}〃如果c 在产生式右部的最后,形如产生式 A fa B,则FOLLOW(A) € FOLLOW(B)if(k==(int)strlen(right[j])-1){if(in(v[m],foll)==1)// 查找该非终结符是否已经求过其 FOLLOW 集.避免循//c 为待求的非终结符if(c==start){temp[0]='#'; temp[1]='\0';merge(follow[i],temp,1);}for(j=0;j<=count-1;j++){if(in(c,right[j])==1) {//比如求 FOLLOW(B)for(k=0;;k++){if(right[j][k]==c) break;//若为开始符号-----开始符号S ,则#€ FOLLOW(S)c 的产生式A faB 或 A fa B 3 ( 3 =>*&)的产生式 //找一个右部含有当前字符 则找 //k 为 c 在该产生式右部的序号 ,如 B 在产生式 Afa Bif(v[m]==left[j])//m 为产生式左部非终结符在所有符号中的序号{//是则 FOLLOW(A) € FOLLOW(B)merge(follow[i],follow[m],1);// 把 c 所在产生式的左部非终结符的 集加入到FOLLOW(c) 中 continue;//结束本次循环,进入j++循环}if(followflag[m]=='0'){//如果该非终结符的 FOLLOW 未求过FOLLOW(m);// 求之 FOLLOW 集 followflag[m]='1';// 标识为 1}merge(follow[i],follow[m],1);//FOLLOW(A) € FOLLOW(B)//如果 c 不在产生式右部的最后 ,形如 Afa B3 for(n=k+1;n<=(int)strlen(right[j])-1;n++){empt[0]-\0';//把empt[]置空,因为求此字符是否可推出空字 _emp(c)时环递归FOLLOW}else{用到result*=_emp(right[j][n]);}if(result==1) {//如果右部 c 后面的符号串能推出空,A fa B 3 (3 =>*&)则FOLLOW(A)€ FOLLOW(B)if(in(v[m],foll)==1){//查找该非终结符是否已经求过其FOLLOW 集 .避免循环递归merge(follow[i],follow[m],1);//FOLLOW(A )continue;€ FOLLOW(B)}// 若 A fa B 3,其中 FOLLOW(B) ;}if(followflag[m]=='0'){FOLLOW(m); followflag[m]='1';}merge(follow[i],follow[m],1);B € VN , a€ (VT U VN)*、3€ (VT U VN)+,贝U FIRST( 3 )-{ £ } €for(n=k+1;n<=(int)strlen(right[j])-1;n++) {temp[n-k-1]=right[j][n];}temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);// 求 FIRST(3 )merge(follow[i],TEMP,2);// 把 FOLLOW(B)}}followflag[i]='1';// 标识当前要求的非终结符的}/******************************************* 判断读入文法是否为一个 LL(1) 文法 ********************************************/ int LL1(){int i,j,length,result=1; char temp[50]; for(j=0;j<=49;j++) {first[j][0]='\0'; follow[j][0]='\0'; first1[j][0]='\0'; select[j][0]='\0'; TEMP[j]='\0'; temp[j]='\0';firstflag[j]='0';// 用来记录该字符的 FIRST 集是否已求过 .1 表示已求 ,0 表示未求 followflag[j]='0';// 用来记录该字符的 FOLLOW 集是否已求过 .1 表示已求 ,0 表示未求 }for(j=0;j<=(int)strlen(v)-1;j++){first2(j);}printf("\n 各非终结符推出的 first 集 :\n"); for(j=0;j<=(int)strlen(v)-1;j++) {printf("%c:%s ",v[j],first1[j]);}printf("\n 能导空的非终结符集合 :%s",empty); printf("\n_emp:"); for(j=0;j<=(int)strlen(v)-1;j++)printf("%d ",_emp(v[j])); for(i=0;i<=count-1;i++) FIRST(i,right[i]);//求 FIRSTfor(j=0;j<=(int)strlen(non_ter)-1;j++) { //求 FOLLOWif(foll[j]==0)FIRST( 3 )中所有非空元素加入到FOLLOW 集已求过//初始化//求单个符号的 FIRST 集合,结果保存在 first1[] 里{// 求每一产生式的 SELECT 集合memcpy(select[i],first[i],strlen(first[i]));//first[]存放的是各产生式右部的 FIRST 集select[i][strlen(first[i])]='\0'; for(j=0;j<=(int)strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='&')// 形如产生式 A->& result=1; if(result==1){for(j=0;;j++)if(v[j]==left[i])//j 为左部符号在所有字符集中的位置 break;merge(select[i],follow[j],1);}printf("\nselect 集合顺序是 :"); for(i=0;i<=count-1;i++) printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0])); temp[strlen(select[0])]='\0'; for(i=1;i<=count-1;i++) {/* 判断输入文法是否为 LL(1) 文法 */length=strlen(temp); if(left[i]==left[i-1]){merge(temp,select[i],1); if(strlen(temp)<length+strlen(select[i]))// 比较两个产生式的 SELECT 长度 return(0);}elsetemp[0]='\0';{foll[0]='\0'; FOLLOW(j);}}printf("\nfirst 集 :"); for(i=0;i<=count-1;i++)printf("%s ",first[i]); printf("\nfollow 集合 :"); for(i=0;i<=(int)strlen(non_ter)-1;i++)printf("%s ",follow[i]); for(i=0;i<=count-1;i++) {memcpy(temp,select[i],strlen(select[i])); temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M ********************************************/ void MM(){int i,j,k,m; for(i=0;i<=19;i++){for(j=0;j<=19;j++)// 初始化分析表,全部置为空(-1) {M[i][j]=-1;}}i=strlen(termin);termin[i]='#'; //将#加入终结符数组termin[i+1]='\0';for(i=0;i<=count-1;i++)// 查看每个产生式的SELECT 集{for(m=0;;m++){if(non_ter[m]==left[i])break; //m 为产生式左部非终结符的序号}for(j=0;j<=(int)strlen(select[i])-1;j++)// 对每个SELECT 集中的所有元素进行操作{ if(in(select[i][j],termin)==1){ for(k=0;;k++) { if(termin[k]==select[i][j]) break; //k 为产生式右部终结符的序号}M[m][k]=i;}/*******************************************判断符号串是否是该文法的句型********************************************/ void syntax(){int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf(" 请输入该文法的句型:"); scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1){if(in(S[strlen(S)-1],termin)==1) {if(S[strlen(S)-1]!=ch){printf(" 该符号串不是文法的句型!"); return;}else if(S[strlen(S)-1]=='#'){printf(" 该符号串是文法的句型."); return;} elseS[strlen(S)-1]='\0'; j++; ch=str[j];} } elsefor(i=0;;i++)if(non_ter[i]==S[strlen(S)-1]) break;{for(k=0;;k++){if(termin[k]==ch)break;if(k==(int)strlen(termin)){printf(" 词法错误!");return;}}if(M[i][k]==-1){printf(" 语法错误!");return;}else{m=M[i][k]; if(right[m][0]=='@')S[strlen(S)-1]='\0';else{p=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';}}}printf("S:%s str:",S);for(p=j;p<=(int)strlen(str)-1;p++)printf("%c",str[p]);printf(" \n");}}/*******************************************一个用户调用函数********************************************/ void menu(){ syntax(); printf("\n 是否继续?(y or n):"); scanf("%c",&choose);本文档如对你有帮助,请帮忙下载支持! {getchar();while(choose=='y'){ menu();}}/******************************************* 主函数********************************************/void main() {int i,j;start=grammer(termin,non_ter,left,right); printf("count=%d",count); printf("\n开始符号为 :%c",start);strcpy(v,non_ter); strcat(v,termin);printf("\n 所有符号集为 :%s",v);printf("\n 非终结符集合 :{%s",non_ter);printf("}"); printf("\n 终结符集合 :{%s",termin); printf("}");printf("\n 文法所有右边表达式依次是for(i=0;i<=count-1;i++) {printf("%s ",right[i]);}printf("\n 文法所有左边开始符依次是for(i=0;i<=count-1;i++) {printf("%c } if(validity==1) validity=judge(); printf("\nvalidity=%d",validity);if(validity==1) { ll=LL1(); printf("\nll=%d",ll);if(ll==0)printf("\n 该文法不是一个else//读入一个文法 :");:");",left[i]);LL1 文法!"); printf("\n 该文法是一个 LL(1) 文法!");本文档如对你有帮助,请帮忙下载支持!MM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0) printf("M[%d][%d]=%d ",i,j,M[i][j]); menu();}}} 由于算法仍有很多错误,最终结果没能实现,这点很失望!五、实验心得通过本次实验,我收获了很多东西。