lR语法分析器设计
- 格式:doc
- 大小:72.50 KB
- 文档页数:5
《编译原理》中LR(0)语法分析动态演示系统分析与设计1. 引言1.1 研究背景编译原理是计算机科学领域的重要基础课程,而LR(0)语法分析是编译原理中一个关键的内容。
LR(0)语法分析是一种自底向上的语法分析方法,能够准确地判断一个输入串是否是给定文法的句子,同时可以生成句子对应的语法树。
LR(0)语法分析比上下文无关文法分析更为强大,因此被广泛应用于编译器的设计和实现中。
对于学习者来说,理解和掌握LR(0)语法分析并不是一件容易的事情。
传统的教学方法往往是通过讲解和演示来进行,但存在一定的局限性,学生很难深入理解其中的逻辑和原理。
设计一个LR(0)语法分析动态演示系统是十分必要和有意义的。
这样的系统可以通过图形化的界面展示LR(0)语法分析的每个步骤和过程,帮助学生更直观地理解LR(0)语法分析的原理和实现。
1.2 研究目的研究目的是为了通过设计和实现一个LR(0)语法分析动态演示系统,帮助学生和从业者更好地理解和应用LR(0)语法分析算法。
具体来说,研究目的包括但不限于以下几点:通过分析LR(0)语法分析算法的原理和流程,深入探讨其在编译原理中的重要性和应用价值,为用户提供一个直观、动态的学习工具,帮助他们更好地理解和掌握这一算法的核心概念。
通过设计和实现一个功能齐全、易于操作的LR(0)语法分析动态演示系统,提供用户友好的界面和交互功能,使用户可以通过实际操作和观察,加深对LR(0)语法分析算法的认识,并在实践中掌握其使用方法和技巧。
通过系统测试和优化,不断改进系统性能和用户体验,确保系统稳定运行并具有良好的可用性和可靠性,为用户提供一个高质量的学习工具和应用工具。
通过这些努力,旨在提高用户对LR(0)语法分析算法的理解和应用能力,促进编译原理领域的教学和研究工作的发展。
1.3 研究意义编译原理是计算机专业的重要基础课程,而LR(0)语法分析是编译原理中一项重要的内容。
通过设计和实现一个LR(0)语法分析动态演示系统,可以帮助学生更加直观地理解和掌握LR(0)语法分析的原理和算法。
《编译原理》中LR(0)语法分析动态演示系统分析与设计一、引言随着计算机科学领域的不断发展,编译原理作为计算机科学的核心课程之一,对于理解编程语言和编译器的原理和技术具有重要意义。
LR(0)语法分析作为编译器中的重要组成部分,在编译原理课程中具有重要的地位。
为了更好地理解与掌握LR(0)语法分析,本文将课程中的相关理论与实践相结合,提出了一个LR(0)语法分析动态演示系统的设计与分析。
二、LR(0)语法分析概述在编译器的构建中,语法分析是非常重要的一环。
而LR(0)语法分析是一种常用的语法分析方法之一。
LR(0)语法分析使用的是LR(0)自动机进行分析,它是一种自底向上的语法分析方法,它的优势在于可以处理大部分的上下文无关文法(Context-Free Grammar, CFG),并且可以准确地进行语法分析。
LR(0)语法分析是通过构建状态机的方式,根据文法产生式中的右部项目来进行状态转换并最终得到文法的推导序列。
为了更好地理解LR(0)语法分析的原理与过程,我们需要深入学习LR(0)自动机的构建过程、状态转换的规则以及分析过程的具体步骤。
仅仅通过理论学习,学生们往往难以深刻理解LR(0)语法分析的工作原理与流程。
我们需要设计一个能够直观演示LR(0)语法分析过程的系统,通过动态的展示来帮助学生更好地理解LR(0)语法分析的过程和原理。
三、LR(0)语法分析动态演示系统的需求分析为了实现LR(0)语法分析动态演示系统,首先需要进行系统需求分析,明确系统的功能需要和用户需求。
根据LR(0)语法分析的原理与过程,系统的主要功能需求包括:1. 文法输入:能够接受用户输入的文法表达式,包括非终结符、终结符及产生式。
2. LR(0)自动机构建:根据用户输入的文法表达式自动生成LR(0)自动机,并进行展示。
3. 状态转换展示:根据LR(0)自动机中的状态转换规则,动态展示状态之间的转换过程及转换规则。
4. 分析过程展示:根据LR(0)自动机和输入的句子,展示分析过程中状态的变化和产生式的规约过程。
LR语法分析器的实现代码(python)•构造LR(0)项目集:–构造I的闭包CLOSURE(I)的算法如下:i.I的任何项目都属于CLOSURE(I);ii.若A→α•Bβ属于CLOSURE(I),对任何产生式B→γ,B→•γ也属于CLOSURE(I);iii.重复执行上述两步骤直至CLOSURE(I)不再增大为止。
iv.实现代码如下def get_CLOSURE(tmp): # 生成闭包 CLOSURE = [] for it in tmp:if(it not in CLOSURE): CLOSURE.append(it) x, y = it.split(".") if(y == ""): continue v = y[0] if(v in VN): res = get_VN_gram(v) # 返回非终结符产生的A->.aBb形式 forre in res: if(re not in CLOSURE): CLOSURE.append(re) return CLOSURE–Go(I,a)函数构造算法i.I为当前状态,X为文法符号,J为I中所有形如A->α·Xβ的项目的后续项目所组成的集合,而CLOSURE(J)就是项目集I关于X的后续状态ii.实现代码如下def go(item, v): #生成并返回下一个item tmp = [] for it in item: x, y = it.split(".") if(y!=""): if(y[0] == v): new_it = x + y[0] + "." + y[1:] tmp.append(new_it) if(len(tmp)!=0): new_item = get_CLOSURE(tmp) #print(tmp) #print("go(item, "+v + ") = " + str(new_item)) return new_item–判别LR项目集是否合法:•无移进项目和规约项目并存•无多个规约项目并存•代码如下:def lr_is_legal(: # 判别lr是否合法 has_protocol = 0 #是否存在规约项目 has_shift = 0 #是否存在移进项目 for item in items: for it in item: x, y = it.split(".") if(y ==""): if(has_protocol != 0 or has_shift != 0): return False has_protocol = 1 else: if(y[0] in VT): has_shift = 1 return True•构造LR(0)分析表–构造算法:i.假定项目集规范族C={I0,I1,…,In}。
编译原理实验实验二语法分析器实验二:语法分析实验一、实验目的根据给出的文法编制LR(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对LR(1)分析法的理解。
二、实验预习提示1、LR(1)分析法的功能LR(1)分析法的功能是利用LR(1)分析表,对输入符号串自下而上的分析过程。
2、LR(1)分析表的构造及分析过程。
三、实验内容对已给语言文法,构造LR(1)分析表,编制语法分析程序,要求将错误信息输出到语法错误文件中,并输出分析句子的过程(显示栈的内容);实验报告必须包括设计的思路,以及测试报告(输入测试例子,输出结果)。
语法分析器一、功能描述:语法分析器,顾名思义是用来分析语法的。
程序对给定源代码先进行词法分析,再根据给定文法,判断正确性。
此次所写程序是以词法分析器为基础编写的,由于代码量的关系,我们只考虑以下输入为合法:数字自定义变量+ * ()$作为句尾结束符。
其它符号都判定为非法。
二、程序结构描述:词法分析器:class wordtree;类,内容为字典树的创建,插入和搜索。
char gettype(char ch):类型处理代入字串首字母ch,分析字串类型后完整读入字串,输出分析结果。
因读取过程会多读入一个字母,所以函数返回该字母进行下一次分析。
bool isnumber(char str[]):判断是否数字代入完整“数字串”str,判断是否合法数字,若为真返回1,否则返回0。
bool isoperator(char str[]):判断是否关键字代入完整“关键字串”str,搜索字典树判断是否存在,若为存在返回1,否则返回0。
语法分析器:int action(int a,char b):代入当前状态和待插入字符,查找转移状态或归约。
node2 go(int a):代入当前状态,返回归约结果和长度。
void printstack():打印栈。
int push(char b):将符号b插入栈中,并进行归约。
实验5---语法分析器(自下而上):LR(1)分析法一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容程序输入/输出示例(以下仅供参考):对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(1)E->E+T(2)E->E—T(3)T->T*F(4)T->T/F(5)F-> (E)(6)F->i输出的格式如下:(1)LR(1)分析程序,编制人:姓名,学号,班级(2)输入一个以#结束的符号串(包括+—*/()i#):在此位置输入符号串(3)输出过程如下:3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照。
三、实验方法1.实验采用C++程序语言进行设计,文法写入程序中,用户可以自定义输入语句;2.实验开发工具为DEV C++。
四、实验步骤1.定义LR(1)分析法实验设计思想及算法①若ACTION[sm , ai] = s则将s移进状态栈,并把输入符号加入符号栈,则三元式变成为:(s0s1…sm s , #X1X2…Xm ai , ai+1…an#);②若ACTION[sm , ai] = rj则将第j个产生式A->β进行归约。
此时三元式变为(s0s1…sm-r s , #X1X2…Xm-rA , aiai+1…an#);③若ACTION[sm , ai]为“接收”,则三元式不再变化,变化过程终止,宣布分析成功;④若ACTION[sm , ai]为“报错”,则三元式的变化过程终止,报告错误。
2.定义语法构造的代码,与主代码分离,写为头文件LR.h。
3.编写主程序利用上文描述算法实现本实验要求。
五、实验结果1. 实验文法为程序既定的文法,写在头文件LR.h中,运行程序,用户可以自由输入测试语句。
词法分析器实验报告实验名称:语法分析器实验内容:利用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高,故仍选择该方法。
1.2 语法分析器设计语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查 语法错误,报告错误的性质和位置,并进行适当的纠错工作.法分析的方法有多 种多样,常用的方法有递归子程序方法、运算符优先数法、状态矩阵法、LL(K) 方法和 LR(K)方法。
归纳起来,大体上可分为两大类,即自顶向下分析方法和 自底向上分析方法. Syntax 进行语法分析.对于语法分析,这里采用 LR(1)分析 法,判断程序是否满足规定的结构.构造 LR(1)分析程序,利用它进行语法分析, 判断给出的符号串是否为该文法识别的句子,了解 LR(K)分析方法是严格的从 左向右扫描,和自底向上的语法分析方法。
1.2.1 LR分析过程的设计思想及算法1:LR-table.txt:存放分析表,其中正数表示移进,负数表示归约,100 表示接受状态, 0 表示不操作。
2:grammar.txt 存放文法开始符号 3:lengh.txt 存放产生式右部字符长度 4:inpur.txt 输入的程序语法规则定义的文法,如下: (0) Z---S (1) S---AB (2) A---->CDE (3) C---void (4) D---main (5) E---() (6) B---{F} (7) F---GF (8) F---G (9) G--->HIJ (10) H--int (11) I--KLM (12) K--character(13) L--= (14) M--->num (15) J--;根据上面文法画出的分层有限自动机并根据分层自动机构造的 LR(1)分析表:vo m ( { i ch = nu S A B C D E F G H I J K L M } ; #id ai )n armnt021831Ac2-33454-45676-57-281909-11205111 13511121-261235111-43581-47115612701-1621117981--811551--9992220122-1132232242 32-4142-5111.2.2 程序核心代码和注释:public void analyzer() { //*************************** //循环读取grammar.txt //*************************** /*此处代码略*/ //*************************** //循环读取 lengh.txt //*************************** /*此处代码略*/ //**************************** // 读入文件,进行语法分析 //**************************** string strReadFile; strReadFile="input.txt"; myTextRead.myStreamReader=new StreamReader(strReadFile); string strBufferText; int wid =0; Console.WriteLine("分析读入程序(记号ID):\n"); do { strBufferText =myTextRead.myStreamReader.ReadLine();if(strBufferText==null) break;foreach (String subString in strBufferText.Split()) {if(subString!="") {int ll; if(subString!=null) {ll= subString.Length; //每一个长度 } else {break; } int a=ll+1; char[] b = new char[a];StringReader sr = new StringReader(subString);sr.Read(b, 0, ll);//把substring 读到char[]数组里int sort=(int)b[0];// word[i] 和 wordNum[i]对应//先识别出一整个串,再根据开头识别是数字还是字母Word[wid]=subString;if(subString.Equals("void")){wordNum[wid]=0;}else{if(subString.Equals("main")){wordNum[wid]=1;}else{if(subString.Equals("()")){wordNum[wid]=2;}else{if(subString.Equals("{")){wordNum[wid]=3;}else{if(subString.Equals("int")){wordNum[wid]=4;}else{if(subString.Equals("=")){wordNum[wid]=6;}else{if(subString.Equals("}")){wordNum[wid]=22;}else{if(subString.Equals(";")){wordNum[wid]=23;}else //识别变量和数字{if(sort>47&sort<58){wordNum[wid]=7;}else{wordNum[wid]=5;}}}} } } } } } Console.Write(subString+"("+wordNum[wid]+")"+" ");wid++; } } Console.WriteLine("\n"); }while (strBufferText!=null); wordNum[wid]=24; myTextRead.myStreamReader.Close();//********************************* //读入LR分析表 // //***********************************/*此处代码略*/int[] state = new int[100]; string[] symbol =new string[100]; state[0]=0; symbol[0]="#"; int p1=0; int p2=0; Console.WriteLine("\n按文法规则归约顺序如下:\n"); //*************** // 归约算法如下所显示 //*************** while(true) {int j,k;j=state[p2];k=wordNum[p1]; t=LR[j,k]; //当出现t为0的时候 if(t==0) {//错误类型 string error;"+error);if(k==0) error="void";else if(k==1) error="main";else if(k==2) error="()";else if(k==3) error="{";else if(k==4) error="int";else if(k==6) error="=";else if(k==22) error="}";else if(k==23) error=";";else error="其他错误符号";Console.WriteLine("\n检测结果:"); Console.WriteLine("代码中存在语法错误"); Console.WriteLine("错误状况:错误状态编号为 "+j+" 读头下符号为break;}else{if(t==-100)//-100为达到接受状态{Console.WriteLine("\n");Console.WriteLine("\n检测结果:");Console.WriteLine("代码通过语法检测");break;}if(t<0&&t!=-100)//归约{string m=grammar[-t];Console.Write(m+" ");//输出开始符int length=lengh[-t]; p2=p2-(length-1); Search mySearch=new Search(); int right=mySearch.search(m); if(right==0) {Console.WriteLine("\n"); Console.WriteLine("代码中有语法错误"); break; } int a=state[p2-1]; int LRresult= LR[a,right]; state[p2]=LRresult; symbol[p2]=m; } if(t>0) { p2=p2+1; state[p2]=t; symbol[p2]=Convert.ToString(wordNum[p1]); p1=p1+1; } }} myTextRead.myStreamReader.Close(); Console.Read(); }示例:1:void main () {int i = 8 ; int aa = 10 ; int j = 9 ; }2:void main (){ intq i = 8 ; int aa = 10 ; int j = 9 ; } 对于 intq i=8 中 intq 这个错误类型,词法分析通过,而语法分析正确识别出了错误,达到 预期目标 产生出错信息: 运行显示如下:1.3 中间代码生成器设计进入编译程序的第三阶段:中间代码产生阶段。
编译原理LR分析法编译原理中的LR分析法是一种自底向上的语法分析方法,用于构建LR语法分析器。
LR分析法将构建一个识别句子的分析树,并且在分析过程中动态构建并操作一种非常重要的数据结构,称为句柄(stack)。
本文将详细介绍LR分析法的原理、算法以及在实际应用中的一些技巧。
1.LR分析法的原理LR分析法是从右向左(Right to Left)扫描输入串,同时把已处理的输入串的右侧部分作为输入串的前缀进行分析的。
它的核心思想是利用句柄来识别输入串中的语法结构,从而构建分析树。
为了实现LR分析法,需要识别和操作两种基本的语法结构:可规约项和可移近项。
可规约项指的是已经识别出的产生式右部,可以用产生式左部进行规约。
可移近项指的是当前正在处理的输入符号以及已处理的输入串的右侧部分。
2.LR分析法的算法LR分析法的算法包括以下几个步骤:步骤1: 构建LR分析表,LR分析表用于指导分析器在每个步骤中的动作。
LR分析表包括两个部分:动作(Action)表和状态(Goto)表。
步骤2: 初始化分析栈(stack),将初始状态压入栈中。
步骤3:从输入串中读取一个输入符号,并根据该符号和当前状态查找LR分析表中的对应条目。
步骤4:分析表中的条目可能有以下几种情况:- 移进(shift):将输入符号移入栈中,并将新的状态压入栈中。
- 规约(reduce):将栈中符合产生式右部的项规约为产生式左部,并将新的状态压入栈中。
- 接受(accept):分析成功,结束分析过程。
- 错误(error):分析失败,报告错误。
步骤5:重复步骤3和步骤4,直到接受或报错。
3.LR分析法的应用技巧在实际应用中,为了提高LR分析法的效率和准确性,一般会采用以下几种技巧:-使用LR分析表的压缩表示:分析表中的大部分条目具有相同的默认动作(通常是移进操作),因此可以通过压缩表示来减小分析表的大小。
-使用语法冲突消解策略:当分析表中存在冲突时,可以使用优先级和结合性规则来消解冲突,以确定应该选择的操作。
语法分析器的设计1.设计原则在设计语法分析器时,应遵循以下原则:-维护清晰的分析策略:选择合适的文法类别,以便能够使用适当的分析策略,如自上而下分析、自下而上分析或混合分析等。
-使用适当的数据结构:选择合适的数据结构来表示词法单元流和语法树,以提高分析效率和易读性。
-错误处理机制:有效地处理语法错误,提供有用的错误信息以帮助开发人员进行调试和修复。
-可扩展性和可维护性:设计一个灵活的框架,使得分析器能够适应新的语言特性和文法规则,并便于维护和修改。
2.文法规则分析例如,下面是一个简单的四则运算表达式的文法规则:```<expression> ::= <term> '+' <expression><term> '-' <expression<term<term> ::= <factor> '*' <term><factor> '/' <term<factor<factor> ::= '(' <expression> ')'<number<number> ::= [0-9]+```在编写语法分析器时,需要将这些规则翻译为具体的代码逻辑。
3.自上而下分析自上而下分析是一种从文法规则的最上层开始,逐步展开产生式规则,并根据输入的词法单元流进行匹配的分析方法。
以下是一个简单的自上而下分析的伪代码示例:```function parseExpression(:term = parseTermif currentToken.type == '+':match('+')expression = parseExpressionreturn BinaryExpression('+', term, expression)else if currentToken.type == '-':match('-')expression = parseExpressionreturn BinaryExpression('-', term, expression) else:return termfunction parseTerm(:factor = parseFactorif currentToken.type == '*':match('*')term = parseTermreturn BinaryExpression('*', factor, term) else if currentToken.type == '/':match('/')term = parseTermreturn BinaryExpression('/', factor, term) else:return factorfunction parseFactor(:if currentToken.type == '(':match('(')expression = parseExpressionmatch(')')return expressionelse if currentToken.type == 'number':number = currentToken.valuematch('number')return NumberLiteral(number)else:error("Invalid factor")function match(expectedType):if currentToken.type == expectedType:currentToken = getNextTokenelse:error("Unexpected token: " + currentToken.type)```代码示例中的`currentToken`表示当前正在处理的词法单元,`getNextToken(`获取下一个词法单元。
实验题目:语法分析程序设计与实现(LR)一.实验内容:编写语法分析程序,实现对算数表达式的语法分析。
要求所分析算数表达式由如下的文法产生。
E->E+T|E-T|TT->T*F|T/F|FF->id|(E)|num二.实现要求:在对输入表达式进行分析的过程中,输出所采用的产生式。
方法3:编写语法分析程序实现自底向上的分析,要求如下:1)构造识别所有或前缀的DFA2)构造LR分析表3)编程实现算法4.3,构造LR分析程序三.程序设计说明1.拓广文法。
加入产生式 S->·E。
2.构造项目集规范族(由于作图能力有限,DFA不在此进行显示)。
该过程中考虑到文法是通过字符串数组存储的,故分析过程是一个字符一个字符进行的,所以如果出现类似num,id多个字符构成一个整体的形式,难以处理,程序中对于这种情况采取只取第一个字符的方式处理,也就是用n代替num,i代替id。
对生成式进行编号后:0. S->E1.E->E+T 4.T->T*F 7.F->i2.E->E-T 5.T->T/F 8.F->(E)3.E->T 6.T->F 9.F->nI0 =closure({S′→·E})={ S′→·E,E→·E+T,E→·E-T,E→·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n}从I0出发的转移有I1=go(I0 ,E)=closure({S→E·}, {E→E·+T},{E→E·-T})={S→E·,E→E·+T,E→E·-T}I2=go(I0 ,T)=closure({E→T·}, { T→T·*F}, {T→T·/F})={ E→T·,T→T·*F,T→T·/F }I3=go(I0 ,F)=closure({T→F ·})={ T→F ·}I5=go( I0,( )= closure({F→(·E)})={ F→(·E), E→·E+T,E→·E-T,E→·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }I6=go(I0,n)= closure({F→n· })={ F→n· }从I1出发的转移有I7=go(I1,+)= closure({E→E+·T })={E→E+·T,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }I8=go(I1, -)= closure({E→E-·T })={ E→E-·T ,T→·T*F,T→·T/F,T→·F,F→·i,F→·(E),F→·n }从I2出发的转移有I9=go(I2, *)= closure({T→T*·F })={ T→T*·F,F→·i,F→·(E),F→·n } I10=go(I2, /)= closure({T→T/·F })={ T→T/·F,F→·i,F→·(E),F→·n }从I5出发的转移有I11=go(I5, E)= closure({F→(E·)}, { E→E·+T}, {E→E·-T })={F→(E·), E→E·+T, E→E·-T }go(I5, T)=I2 go(I5, i)=I4 go(I5, ( )=I5 go(I5, n)=I6从I7出发的转移有I12=go(I7, T)= closure({E→E+T·},{T→T·*F},{T→T·/F })={ E→E+T·,T→T·*F, T→T·/F }go(I7, F)=I3 go(I7, i)=I4 go(I7, ( )=I5 go(I7, n)=I6从I8出发的转移有I13=go(I7, T)= closure({E→E-T·},{T→T·*F},{T→T·/F })={ E→E-T·,T→T·*F, T→T·/F }go(I8, F)=I3 go(I8, i)=I4 go(I8, ( )=I5 go(I8, n)=I6从I9出发的转移有I14=go(I9,F)= closure({T→T*F· })={ T→T*F· }go(I9, i)=I4 go(I9, ( )=I5 go(I9, n)=I6从I10出发的转移有I15= go(I10,F)= closure({T→T/F· })go(I10, i)=I4 go(I10, ( )=I5 go(I10, n)=I6 从I11出发的转移有I16= go(I11, ))= closure({F→(E) ·})={F→(E) ·} go(I11, +)=I7 go(I11, - )=I8从I12出发的转移有go(I12, *)=I9 go(I12, / )=I10从I13出发的转移有go(I13, *)=I9 go(I13, / )=I103.构造分析表4. 根据算法4.3,构造LR预测分析程序。
1.2 语法分析器设计语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作.法分析的方法有多种多样,常用的方法有递归子程序方法、运算符优先数法、状态矩阵法、LL(K)方法和LR(K)方法。
归纳起来,大体上可分为两大类,即自顶向下分析方法和自底向上分析方法. Syntax进行语法分析.对于语法分析,这里采用LR(1)分析法,判断程序是否满足规定的结构.构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1.2.1LR分析过程的设计思想及算法1:LR-table.txt:存放分析表,其中正数表示移进,负数表示归约,100表示接受状态,0表示不操作。
2:grammar.txt 存放文法开始符号3:lengh.txt 存放产生式右部字符长度4:inpur.txt 输入的程序语法规则定义的文法,如下:(0)Z---→S(1)S---→AB(2)A---->CDE(3)C---→void(4)D---→main(5)E---→()(6)B---→{F}(7)F---→GF(8)F---→G(9)G--->HIJ(10)H--→int(11)I--→KLM(12)K--→character(13)L--→=(14)M--->num(15)J--→;根据上面文法画出的分层有限自动机并根据分层自动机构造的LR(1)分析表:v oi d main(){ intchar= numS A B C D E F G H I J K L M } ; #0 2 1 8 31 Ac2 -33 4 54 -45 6 76 -57 -28 199 -11 0 251113151 1 1 21 2 -61 3 25141315-81 4 -71 5 161721 6 -1 21 7 19181 8 -15-151 9 -9-92 0 21222 1 -1 32 2 23242 32 4 -1 42 5 -1 11.2.2 程序核心代码和注释:public void analyzer(){//***************************//循环读取grammar.txt//***************************/*此处代码略*///***************************//循环读取 lengh.txt//***************************/*此处代码略*///****************************// 读入文件,进行语法分析//****************************string strReadFile;strReadFile="input.txt";myTextRead.myStreamReader=new StreamReader(strReadFile);string strBufferText;int wid =0;Console.WriteLine("分析读入程序(记号ID):\n");do{strBufferText =myTextRead.myStreamReader.ReadLine();if(strBufferText==null)break;foreach (String subString in strBufferText.Split()){if(subString!=""){int ll;if(subString!=null){ll= subString.Length; //每一个长度}else{break;}int a=ll+1;char[] b = new char[a];StringReader sr = new StringReader(subString);sr.Read(b, 0, ll); //把substring 读到char[]数组里int sort=(int)b[0];// word[i] 和 wordNum[i]对应//先识别出一整个串,再根据开头识别是数字还是字母Word[wid]=subString;if(subString.Equals("void")){wordNum[wid]=0;}else{if(subString.Equals("main")){wordNum[wid]=1;}else{if(subString.Equals("()")){wordNum[wid]=2;}else{if(subString.Equals("{")){wordNum[wid]=3;}else{if(subString.Equals("int")){wordNum[wid]=4;}else{if(subString.Equals("=")){wordNum[wid]=6;}else{if(subString.Equals("}")){wordNum[wid]=22;}else{if(subString.Equals(";")){wordNum[wid]=23;}else//识别变量和数字{if(sort>47&sort<58){wordNum[wid]=7;}else{wordNum[wid]=5;}}}}}}}}}Console.Write(subString+"("+wordNum[wid]+")"+" ");wid++;}}Console.WriteLine("\n");}while (strBufferText!=null);wordNum[wid]=24;myTextRead.myStreamReader.Close();//*********************************//读入LR分析表////***********************************/*此处代码略*/int[] state = new int[100];string[] symbol =new string[100];state[0]=0;symbol[0]="#";int p1=0;int p2=0;Console.WriteLine("\n按文法规则归约顺序如下:\n");//***************// 归约算法如下所显示//***************while(true){int j,k;j=state[p2];k=wordNum[p1];t=LR[j,k]; //当出现t为0的时候if(t==0){//错误类型string error;if(k==0)error="void";elseif(k==1)error="main";elseif(k==2)error="()";elseif(k==3)error="{";elseif(k==4)error="int";elseif(k==6)error="=";elseif(k==22)error="}";elseif(k==23)error=";";elseerror="其他错误符号";Console.WriteLine("\n检测结果:");Console.WriteLine("代码中存在语法错误");Console.WriteLine("错误状况:错误状态编号为 "+j+" 读头下符号为"+error);break;}else{if(t==-100) //-100为达到接受状态{Console.WriteLine("\n");Console.WriteLine("\n检测结果:");Console.WriteLine("代码通过语法检测");break;}if(t<0&&t!=-100) //归约{string m=grammar[-t];Console.Write(m+" "); //输出开始符int length=lengh[-t];p2=p2-(length-1);Search mySearch=new Search();int right=mySearch.search(m);if(right==0){Console.WriteLine("\n");Console.WriteLine("代码中有语法错误");break;}int a=state[p2-1];int LRresult= LR[a,right];state[p2]=LRresult;symbol[p2]=m;}if(t>0){p2=p2+1;state[p2]=t;symbol[p2]=Convert.ToString(wordNum[p1]);p1=p1+1;}}}myTextRead.myStreamReader.Close();Console.Read();}示例:1:void main (){int i = 8 ;int aa = 10 ;int j = 9 ;}2:void main (){intq i = 8 ;int aa = 10 ;int j = 9 ;}对于intq i=8 中intq这个错误类型,词法分析通过,而语法分析正确识别出了错误,达到预期目标产生出错信息:运行显示如下:1.3中间代码生成器设计进入编译程序的第三阶段:中间代码产生阶段。
编写lr分析器课程设计一、课程目标知识目标:1. 学生理解LR分析的基本概念,掌握LR分析法的原理和步骤。
2. 学生掌握如何构建LR分析表,并能够运用它对简单程序语言进行语法分析。
3. 学生能够识别并使用不同的LR分析策略,如SLR(1)、LALR(1)等。
技能目标:1. 学生能够独立设计简单的LR分析器,并能够将程序代码转化为语法分析树。
2. 学生通过实践练习,培养问题解决能力和逻辑思维能力,提高编程技能。
3. 学生通过小组合作,培养团队协作能力和沟通技巧,共同完成复杂的LR分析任务。
情感态度价值观目标:1. 学生对程序语言和编译原理产生兴趣,激发对计算机科学领域探索的热情。
2. 学生在学习过程中培养坚持不懈、勇于尝试的精神,增强面对困难的自信心。
3. 学生通过课程学习,认识到编程语言在信息技术发展中的重要性,理解其在实际应用中的价值。
分析课程性质、学生特点和教学要求,本课程目标旨在使学生在掌握LR分析法基本理论的基础上,通过实践锻炼技能,同时培养积极的情感态度和价值观。
课程目标具体、可衡量,确保学生和教师能够明确课程预期成果,并为后续教学设计和评估提供依据。
二、教学内容1. LR分析基本概念:介绍LR分析的定义、特点及与其它分析方法的区别。
- 相关章节:教材第3章第2节2. LR分析法的原理与步骤:详细讲解LR分析法的原理,包括状态转换图、项目集合等概念。
- 相关章节:教材第3章第3节3. 构建LR分析表:学习如何根据给定的文法规则,构建LR分析表。
- 相关章节:教材第3章第4节4. LR分析策略:介绍SLR(1)、LALR(1)等不同的LR分析策略,对比分析其优缺点。
- 相关章节:教材第3章第5节5. 设计与实现LR分析器:通过实例讲解如何设计并实现一个简单的LR分析器。
- 相关章节:教材第3章第6节6. 实践练习:组织学生进行小组合作,完成实际的LR分析任务,巩固所学知识。
- 相关章节:教材第3章第7节7. 编程语言语法分析:运用LR分析器对简单编程语言进行语法分析,转化为语法分析树。
实验四LR(1)分析法实验学时:2实验类型:验证实验要求:必修一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(1)E- E+T(2)E- E—T(3)T- T*F(4)T- T/F(5)F- (E)(6)F- i三、LR(1)分析法实验设计思想及算法(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
LR分析器由三个部分组成:◆其中:SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。
状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
◆ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A- B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
LR语法分析实验报告班级:2010211308 姓名:杨娜学号:10211369一.题目:LR语法分析程序的设计与实现二.设计目的:(1)了解语法分析器的生成工具和编译器的设计。
(2)了解自上而下语法分析器的构造过程。
(3). 理解和掌握LR语法分析方法的基本原理;根据给出的LR)文法,掌握LR分析表的构造及分析过程的实现。
(4)掌握预测分析程序如何使用分析表和栈联合控制实现LR分析。
三.实验内容:编写语法分析程序,实现对算术表达式的语法分析,要求所分析算数表达式由如下的文法产生:E->E+T|E-T|TT->T/F|T*F|FF->i|n|(E)四.实验要求:编写LR语法分析程序,要求如下:(1)构造识别所有活动的DFA(2)构造LR分析表(3)编程实现算法4.3,构造LR分析程序五.算法流程分析程序可分为如下几步:六.算法设计1.数据结构s :文法开始符号line :产生式的个数G[i][0] :产生式的标号Vt[] :终结符Vn[] :非终结符id :项目集编号Prjt *next :指示下一个项目集Prjt[]:存储项目的编号,prjt[0]项目编号的个数Pointafter[] :圆点后的字符,pointafter[0]为字符个数Prjset*actorgo[]:存储出度Pointbefore:圆点前面的字符Form:动态数组下标,同时作为符号的编号Vn[] :非终结符序列Vt[]:终结符序列2.LR分析器由三个部分组成(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
LR分析程序设计
1实验目的
(1)构造LR 分析程序,利用它进行语法分析,判断给出的符号串是否为
该文法识别的句子;
(2)了解LR分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
2实验内容和实验要求
(1)LR分析器能够构造来识别所有能用上下文无关文法写的程序设计语言的结构。
(2)LR分析方法是已知的最一般的无回溯,移进-归约方法,它能够和其他移进-归约方法一样有效地实现。
(3)LR方法能分析的文法类是预测分析法能分析的文法类的真超集。
3 待分析的语法描述
E->vI:T
I->I,i|i
T->r
4算法描述
LR分析法基本思想
LR分析法是一种能够根据分析栈中的文法符号串(状态)和向右顺序查看第k个输入字符就能够唯一确定LR(k)分析器的动作是移进还是用哪一条产生式归约的分析方法。
采用LR(0)分析法进行本次实验,即无需向前查看输入符号就能够确定分析器的动作。
实现方法
LR(0)分析器由三个部分组成:
(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(ACTION)和状态转换(GOTO)表两个部分,它们都可用二维数组表示。
由于它是总控程序的依据,所以在程序的第一部分就已经定义好。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
(4)LR分析器及时察觉语法错误,快到自左向右扫描输入的最大可能。
为了使一个文法是LR的,只要保证当句柄出现在栈顶时,自左向右扫描的移进-归约分析器能够及时识别它便足够了。
当句柄出现在栈顶时,LR分析器必须要扫描整个栈就可以知道这一点,栈顶的状态符号包含了所需要的一切信息。
如果仅知道栈内的文法符号就能确定栈顶是什么句柄。
由于LR分析表的转移函数本
质上就是这样的有限自动机,因为,如果这个识别句柄的有限自动机自底向上读栈中的文法符号的话,它达到的状态正是这时栈顶的状态符号所表示的状态,所以,LR分析器可以从栈顶的状态确定它需要从栈中了解的一切。
算法分析
SP为栈指针,S[i]为状态栈,X[i]为文法符号栈。
状态转换表用GOTO[i,X]=j表示,规定当栈顶状态为i,遇到当前文法符号为X时应转向状态j,X为终结符或非终结符。
ACTION[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:
action[i,a]= Sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:
action[i,a]=r k:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A-B的产生式,若B的长度为R(即|B|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针SP减去R,并把A移入文法符号栈内,j=GOTO[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:
当归约到文法符号栈中只剩文法的开始符号S时,并且输入符号串已结束即当前输入符是'#',则为分析成功。
(4)报错:
当遇到状态栈顶为某一状态下出现不该遇到的文法符号时,则报错,说明输入端不是该文法能接受的符号串。
5 总控程序框图
6程序清单和程序运行结果
程序清单见磁盘
程序运行结果如下:
显示所要分析的文法,并且输入所要分析的句型:
2.输入所要分析的句型
(1)若所要分析的字符串不为该文法的句型,出错分析:例若为i-ii#,则出错显示如下:
(2)若正确输入该文法的句型如:vi,i:r#,则分析结果如下:
(3)选择是否要继续分析,若需要则选Y,若不需要,则选择N,则退出程序。
7实验感想
这是在做课程设计之前的最后一个实验:自底向下的语法分析法。
这种方法来分析的固定的文法,是可以凸现其通用性,虽然它没有算符优先分析方法效率那么高。
但是由于算符优先分析法是将当前句型中的最左素短语而不是句柄(最左直接短语)作为规约的子串,省略了所有单非终极符产生式对应的归约步骤,因此在分析过程中,虽然采取了相应的一些检查措施,但仍然有可能将错误的输入符号串归约为正确的句子。
而且很多的程序设计语言的文法也很难满足算符优先文法的条件,所以它只能局限在表达式的语法分析中。
但是对于LR分析法,其分析的过程更加符合程序设计语言文法的要求,这样使之通用性加强。
同样在做这个实验的时候,发现由于在构造goto表以及action表中的相关参数中,没有非常的有条理这样就导致了在程序分析过程中没有得到非常整齐的界面。
经过定义循环变量控制空格符的多少,使表格输出合理化。
由于LR分析方
法是可以有很多中形式的,虽然这次我只是选择了其中的一种方法。
但是实际上比较通行的时SLR(1)分析方法,因为它可以解决相应的一些移进归约,规约规约冲突。
通过这个实验,在进一步了解到编译程序前端三个步骤的重要以及运用的范围,同时也加深了对高级语言运用的熟练程度。