C语言编写源程序建立LR(1)分析器
语法分析代码2(LR分析器 C语言实现)
#include"status_stack.h"#include"symbol_instr_stack.h"#include"lr.h"//打印LR分析器的工作过程void print(status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p) {int i;out_stack(status_p);for(i=0;i<20-status_p->top;i++)printf(" ");out_stack1(symbol_p);for(i=0;i<20;i++)printf(" ");out_stack2(instr_p);printf("\n");}//状态转换函数int goto_char(status *status_p,symbol_instr *instr_p){char x;int y,z;x = get_top(instr_p);y = get_top(status_p);z = get_index_char(x);return table[y][z];}//移进--规约函数void action(status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p) {int i,j,x;char a;i = goto_char(status_p,instr_p);//规约出错if(i == -1)printf("\n===============规约出错!================\n");//规约成功if(i == 12)printf("\n===============规约成功!================\n");//移进动作if(i>=0 && i<=11){push(status_p,i);a = pop(instr_p);push(symbol_p,a);print(status_p,symbol_p,instr_p);action(status_p,symbol_p,instr_p);}//规约动作if(i>=21 && i<=26){x = r[i-21].y;for(j=0;j<x;j++){pop(status_p);pop(symbol_p);}push(instr_p,r[i-21].x);action(status_p,symbol_p,instr_p);}}int main(){char x;//分配空间status *status_p;symbol_instr *symbol_p,*instr_p ;status_p = (status *)malloc(sizeof(status));symbol_p = (symbol_instr *)malloc(sizeof(symbol_instr));instr_p = (symbol_instr *)malloc(sizeof(symbol_instr));//初始化各栈init_stack(status_p);init_stack(symbol_p);init_stack(instr_p);//压进栈初始元素push(status_p,0);//push(symbol_p,'#');////输入表达式printf("\n请输入要规约的输入串,各字符之间不能有空格,以'#'字符结束!\n");printf("===========Expression =");//先将输入串压进符号栈do{scanf("%c",&x);push(symbol_p,x);}while(x != '#');//然后由符号栈弹出,压进输入栈while( symbol_p->top != 0){x = pop(symbol_p);push(instr_p,x);}printf("\n\n");//打印框架printf("\n状态栈==============符号栈==============输入串\n");print(status_p,symbol_p,instr_p);//打印初始分析表//移进,规约,并打印每一步分析过程action(status_p,symbol_p,instr_p);return 0;}。
编译原理语法分析程序设计(LL(1)分析法)
编译原理语法分析程序设计(LL(1)分析法)1. 实验目的:掌握 LL(1)分析法的基本原理,掌握 LL(1)分析表的构造方法,掌握 LL(1)驱动程序的构造方法。
2.实验要求:实现 LR分析法(P147,例 4.6)或预测分析法(P121,例4.3)。
3.实验环境:一台配置为 1G 的 XP 操作系统的 PC机;Visual C++6.0.4.实验原理:编译程序的语法分析器以单词符号作为输入,分析单词符号串是否形成符合语法规则的语法单位,如表达式、赋值、循环等,最后看是否构成一个符合要求的程序,按该语言使用的语法规则分析检查每条语句是否有正确的逻辑结构,程序是最终的一个语法单位。
编译程序的语法规则可用上下文无关文法来刻画。
语法分析的方法分为两种:自上而下分析法和自下而上分析法。
自上而下就是从文法的开始符号出发,向下推导,推出句子。
而自下而上分析法采用的是移进归约法,基本思想是:用一个寄存符号的先进后出栈,把输入符号一个一个地移进栈里,当栈顶形成某个产生式的一个候选式时,即把栈顶的这一部分归约成该产生式的左邻符号。
自顶向下带递归语法分析:1、首先对所以的生成式消除左递归、提取公共左因子2、在源程序里建立一个字符串数组,将所有的生成式都存在这个数组中。
3、给每个非终结符写一个带递归的匹配函数,其中起始符的函数写在 main 函数里。
这些函数对生成式右边从左向右扫描,若是终结符直接进行匹配,匹配失败,则调用出错函数。
如果是非终结符则调用相应的非终结符函数。
4、对输入的符号串进行扫描,从起始符的生成式开始。
如果匹配成功某个非终结符生成式右边的首个终结符,则将这个生成式输出。
匹配过程中,应该出现的非终结符没有出现,则出错处理。
5.软件设计与编程:对应源程序代码:#include#include1#includeusing namespace std;struct Node1{char vn;char vt;char s[10];}MAP[20];//存储分析预测表每个位置对应的终结符,非终结符,产生式int k;//用 R 代表E”,W 代表T”,e 代表空char start=“E”;int len=8;charG[10][10]={“E->TR”,”R->+TR”,”R->e”,”T->FW”,”W->*FW”,”W ->e”,”F->(E)”,”F->i”};//存储文法中的产生式char VN[6]={“E”,”R”,”T”,”W”,”F”};//存储非终结符char VT[6]={“i”,”+”,”*”,”(“,”)”,”#”};//存储终结符charSELECT[10][10]={“(,i”,”+”,”),#”,”(,i”,”*”,”+,),#”,”(“,”i”};//存储文法中每个产生式对应的 SELECT 集charRight[10][8]={“->TR”,”->+TR”,”->e”,”->FW”,”->*FW”,”->e”,”->(E)”,”->i”};stack stak;bool compare(char *a,char *b){2int i,la=strlen(a),j,lb=strlen(b);for(i=0;i1;j--){stak.push(action[j]);}}}if(strcmp(output,”#”)!=0)return “ERROR”;}int main (){freopen(“in.txt”,”r”,stdin);char source[100];int i,j,flag,l,m;printf(“\n***为了方便编写程序,用 R 代表E”,W 代表T”,e 代表空*****\n\n”);printf(“该文法的产生式如下:\n”);for(i=0;i>source){ printf(“\n 分析结果:%s\n\n”,Analyse(source));}return 0;}6. 程序测试结果:3。
编译原理 COMPILER_LR(1)文法
编译原理实验报告--LR(1)文法班级:小组人员:实验2.3 LR(1)分析法一.实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子。
二.实验平台Windows + VC + Win32 Console三.实验过程和指导1.范例程序文法S → BBB → aBB → b要求:(1)请输出完整的分析过程。
即详细输出每一步骤状态栈和符号栈的变化情况.(2)请输出最终的分析结果, 即输入串“合法”或“非法”步骤:(1)构造LR(1)项目集规范族I0S →·S I1Goto[I0,S] I2Goto[I0,B] S →·BB S →S· S →B·BB →·aB B →·aBB →·b B →·bI3Goto[I0,a] I4Goto[I0,b] I5Goto[I1,S]B →a·B B →b·S →BB·B →a·BB →·bI6Goto[I2,a] I7Goto[I2,b] I8Goto[I3,B]B →a·B B →b· B →aB·B →·aBB →·bI9Goto[I6,B]B →aB·(2)构造LR(1)分析表(3)程序代码:4-LR1.c1)输入符合文法的字符串abab#,结果显示如图:输入的字符串符合文法要求,结果为接受状态该文法分析步骤:第一步,符号栈#进栈,0进状态栈,Action表中0—#执行S3,所以3进符号栈,a进符号栈。
第二步,此时符号栈#a,状态栈03,Action表中3—b执行S4,所有4进符号栈,b进符号栈。
第三步,此时符号栈#ab,状态栈034,Action表中4—a执行r3,所以用第三个式B → b规约,Goto表中转向8状态。
第四步,此时符号栈是#aB,状态栈038,Action表中8—a执行r2,所以用第二个式B → aB规约,Goto表中转向2状态。
编译原理报告二 LR分析器
LR分析器一、目的和要求通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,进一步掌握常用的语法分析方法。
1、选择最有代表性的语法分析方法,如LL(1) 语法分析程序、算符优先分析程序和LR 分析分析程序,并至少完成两个题目。
2、选择对各种常见程序语言都用的语法结构,如赋值语句(尤指表达式)作为分析对象,并且与所选语法分析方法要比较贴切。
⑴实验前的准备按实验的目的和要求,编写语法分析程序,同时考虑相应的数据结构。
⑵调试调试例子应包括符合语法规则的算术表达式,以及分析程序能够判别的若干错例。
⑶输出对于所输入的算术表达式,不论对错,都应有明确的信息告诉外界。
⑷扩充有余力的同学,可适当扩大分析对象。
譬如:①算术表达式中变量名可以是一般标识符,还可含一般常数、数组元素、函数调用等等。
②除算术表达式外,还可扩充分析布尔、字符、位等不同类型的各种表达式。
③加强语法检查,尽量多和确切地指出各种错误。
⑸编写上机实习报告。
二、背景知识※自下而上分析技术-LR(K)方法LR(K)方法是一种自下而上的语法分析方法,是当前最广义的无回溯的“移进- 归约”方法。
它根据栈中的符号串和向前查看的k(k 0)个输入符号,就能唯一确定分析器的动作是移进还是归约,以及用哪个产生式进行归约。
优点:文法适用范围广;识别效率高;查错能力强;可自动构造。
逻辑组成:总控程序+LR分析表LR分析器的结构:一个LR分析器实际是一个带先进后出存储器(栈)的确定下推自动机,它由一个输入串、一个下推栈和一个带有分析表的总控程序组成。
栈中存放着由“历史”和“展望”材料抽象而来的各种“状态”。
任何时候,栈顶的状态都代表了整个的历史和已推测出的展望。
为了有助于明确归约手续,我们把已归约出的文法符号串也同时放进栈里。
LR分析器的每一动作都由栈顶状态和当前输入符号所唯一确定。
LR分析器模型图分析器的任何一次移动都是根据栈顶状态S m和当前输入符号a i,去查看ACTION表并执行ACTION(S m,a i)规定的动作,直至分析成功或失败。
编译原理实验报告LR(1)分析法
河南工业大学实验报告课程编译原理实验名称实验四LR(1)分析法一.实验目的1.掌握LR(1)分析法的基本原理;2.掌握LR(1)分析表的构造方法;3.掌握LR(1)驱动程序的构造方法。
二.实验内容及要求根据某一文法编制调试LR(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对LR(1)分析法的理解。
对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(0)E->S(1)S->BB(2)B->aB(3)B->b程序输入一以#结束的符号串(包括a、b、#),如:abb#。
输出过程如下:步骤状态栈符号栈输入串ACTION GOTO1 0 # abb# S3... ... ... ... ... ...三.实验过程及结果(说明:实验结果可以是运行画面的抓屏,抓屏图片要尽可能的小。
)实验代码:#include<stdio.h>#include<string.h>char *action[10][3]={"S3#","S4#",NULL, /*ACTION表*/ NULL,NULL,"acc","S6#","S7#",NULL,"S3#","S4#",NULL,"r3#","r3#",NULL,NULL,NULL,"r1#","S6#","S7#",NULL,NULL,NULL,"r3#","r2#","r2#",NULL,NULL,NULL,"r2#"};int goto1[10][2]={1,2, /*GOTO表*/0,0,0,5,0,8,0,0,0,0,0,9,0,0,0,0,0,0};char vt[3]={'a','b','#'}; /*存放非终结符*/ char vn[2]={'S','B'}; /*存放终结符*/ char *LR[4]={"E->S#","S->BB#","B->aB#","B->b#"};/*存放产生式*/int a[10];char b[10],c[10],c1;int top1,top2,top3,top,m,n;void main(){int g,h,i,j,k,l,p,y,z,count;char x,copy[10],copy1[10];top1=0;top2=0;top3=0;top=0;a[0]=0;y=a[0];b[0]='#';count=0;z=0;printf("请输入表达式\n");/*输出状态栈、输出符号栈、输出输入串*/do{scanf("%c",&c1);c[top3]=c1;top3=top3+1;}while(c1!='#');printf("步骤\t状态栈\t\t符号栈\t\t输入串\t\tACTION\tGOTO\n"); do{y=z;m=0;n=0; /*y,z指向状态栈栈顶*/ g=top;j=0;k=0;x=c[top];count++;printf("%d\t",count);while(m<=top1){ /*输出状态栈*/printf("%d",a[m]);m=m+1;}printf("\t\t");while(n<=top2){ /*输出符号栈*/printf("%c",b[n]);n=n+1;}printf("\t\t");while(g<=top3){ /*输出输入串*/ printf("%c",c[g]);g=g+1;}printf("\t\t");while(x!=vt[j]&&j<=2) j++;if(j==2&&x!=vt[j]){printf("error\n");return;}if(action[y][j]==NULL){printf("error\n");return;}elsestrcpy(copy,action[y][j]);if(copy[0]=='S'){ /*处理移进*/ z=copy[1]-'0';top1=top1+1;top2=top2+1;a[top1]=z;b[top2]=x;i=0;while(copy[i]!='#'){printf("%c",copy[i]);i++;}printf("\n");}if(copy[0]=='r'){ /*处理归约*/ i=0;while(copy[i]!='#'){printf("%c",copy[i]);i++;}h=copy[1]-'0';strcpy(copy1,LR[h]);while(copy1[0]!=vn[k]) k++;l=strlen(LR[h])-4;top1=top1-l+1;top2=top2-l+1;y=a[top1-1];a[top1]=p;b[top2]=copy1[0];z=p;printf("\t");printf("%d\n",p);} }while(action[y][j]!="acc");printf("acc\n");getchar();}截屏如下:四.实验中的问题及心得同前面一样。
LR(1)分析法
LR(1)分析法一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容对文法G[E]进行语法分析,文法G如下所示:G[E]:E→ E+T | TT→ T*F | FF→ (E) | i根据LR(1)分析法,将表达式进行语法分析,判断一个表达式是否正确。
三、实验步骤程序源代码#include<iostream>#include<stack>#include<stdlib.h>#include<string>using namespace std;//初始化预测分析表string action[12][6]={{"s5", "error", "error", "s4", "error", "error"},{"error", "s6", "error", "error", "error", "acc"},{"error", "r2", "s7", "error", "r2", "r2"},{"error", "r4", "r4", "error", "r4", "r4"},{"s5", "error", "error", "s4", "error", "error"},{"error", "r6", "r6", "error", "r6", "r6"},{"s5", "error", "error", "s4", "error", "error"},{"s5", "error", "error", "s4", "error", "error"},{"error", "s6", "error", "error", "s11", "error"},{"error", "r1", "r7", "error", "r1", "r1"},{"error", "r3", "r3", "error", "r3", "r3"},{"error", "r5", "r5", "error", "r5", "r5"}};string go[12][3] = {{"1", "2", "3"},{"error", "error", "error"},{"error", "error", "error"},{"error", "error", "error"},{"8", "2", "3"},{"error", "error", "error"},{"error", "9", "3"},{"error", "error", "10"},{"error", "error", "error"},{"error", "error", "error"},{"error", "error", "error"},{"error", "error", "error"},};char Vt[6] = {'i', '+', '*', '(', ')', '#'}; //终结符表string LR[6] = {"E->E+T", "E->T", "T->T*F", "T->F", "F->(E)", "F->i"}; //LR文法stack<int> S;//状态栈stack<char> X;//符号栈char input[10];//输入字符int num(string s){ //判断字符串中的数字int i;string str = "";for(int j = 0; j < s.length(); j++){if(s[j] >= '0' && s[j] <= '9')str = str + s[j];}i = atoi(str.c_str());return i;}void preview(char *c){for(int j = 0; c[j]!='#'; j++)cout << c[j];cout << endl;}void print(int i, char *c) //剩余输入串的输出{for(int j = i; c[j-1]!='#'; j++)cout << c[j];cout << '\t';}int same(char a){ //用于查找终结符for(int i=0;i<6;i++){if(a==Vt[i])return i;}return -1;}void analyse(){//**********分析程序bool flag = true; //循环条件控制int step = 1, point = 0, state = 0; //步骤、指针、状态char ch1,ch2;int m, n, l; //用于判断终结符,分析表,表达式右部的长度string str1;//用于判断对应分析表中的符号string str2 = "#", str3 = "0"; //记录符号栈的所有元素cout<<"请输入要规约的字符串,并以#号结束:"<<endl;cin>>input;cout << "您输入的字符串为:";preview(input);X.push('#');S.push(0);cout << "步骤" << '\t' << "状态栈" << '\t' << "符号栈" << '\t' << "输入串" << '\t' << "动作" << endl;cout << step++ << '\t' << str3 << '\t' << str2 << '\t';print(point, input);cout << "初始化" << endl; //*************初始化while(flag){//************进入循环state = S.top();ch1 = input[point];m = same(ch1);str1 = action[state][m];//***********移进动作if(str1[0]=='s'){n=num(str1);S.push(n);X.push(ch1);str2=str2+ch1;ch2=n+48;str3=str3+ch2;point++;cout << step++ << '\t' << str3 << '\t' << str2 << '\t';print(point, input);cout << str1 << ':' << "移进" << endl;}else if(str1[0]=='r'){//**********归约动作n=num(str1);l = LR[n - 1].length() - 3;for(int i = 1; i <= l; i++){S.pop();str3 = str3.substr(0, str3.length() - 1);X.pop();str2 = str2.substr(0, str2.length() - 1);}X.push(LR[n - 1][0]);str2 = str2 + LR[n - 1][0];state = S.top();if(LR[n - 1][0] == 'E'){S.push(num(go[state][0]));ch2 = num(go[state][0]) + 48;str3 = str3 + ch2;}else if(LR[n - 1][0] == 'T'){S.push(num(go[state][1]));ch2 = num(go[state][1]) + 48;str3 = str3 + ch2;}else if(LR[n - 1][0] == 'F'){S.push(num(go[state][2]));ch2 = num(go[state][2]) + 48;str3 = str3 + ch2;}cout << step++ << '\t' << str3 << '\t' << str2 << '\t';print(point, input);cout << str1 << ':' << LR[n - 1] << "归约" << endl;}//*********出错else if(str1=="error"){cout << "Error!\n" << "程序错误,分析结束!" << endl;flag = false;}//**********分析成功else if(str1 == "acc"){cout << "Acc!\n"<<"分析成功,终止程序!" << endl;flag = false;}}}int main(){analyse();return 0;}程序运行截图输入i+i输入i+ii。
《编译原理》LR分析法与构造LR(1)分析表的步骤-例题解析
《编译原理》LR分析法与构造LR(1)分析表的步骤-例题解析《编译原理》LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析笔记直接做题是有⼀些特定步骤,有技巧。
但也必须先了解⼀些基本概念,本篇会通过例题形式解释概念,会容易理解和记忆,以及解决类似问题。
如果只想做题可以直接下拉⾄习题部分。
(⼀)关于状态对于产⽣式 A→aBcD,就可以分解为下⾯⼏个不同的识别状态:(1)A→.aBcD(2)A→a.BcD(3)A→aB.cD(4)A→aBc.D(5)A→aBcD.“.” 的左部符号表⽰已被识别出来的那部分句柄符号状态(1)表⽰:处于句柄的头状态(2)表⽰:已经识别出字符 a,等待形成以 B 为产⽣式左部的右部状态(3)表⽰:刚刚进⾏了⼀次规约,即把关于 B 的产⽣式右部规约成 B状态(4)表⽰:已经识别出字符 c,等待形成以 D 为产⽣式左部的右部状态(5)表⽰:已经到达句柄的尾巴,可以把 aBcD 规约为产⽣式左部的符号 A(⼆)什么是 LR(k) 分析法?字⾯意思理解:字符含义L表⽰从左到右扫描输⼊串R表⽰利⽤最右分析⽅法来识别句⼦,即构造⼀个最右推导的逆过程k表⽰向右查看输⼊串符号的个数LR 分析过程是规范归约的过程规范规约是最右推导的逆过程,最右推导是规范推导,所以最左规约是规范规约。
LR 分析法根据当前分析栈中的符号串和向右顺序查看输⼊串的 k 个符号就可以唯⼀确定分析器的动作是移进还是归约、利⽤那个产⽣式进⾏归约。
当没有指明 k 是⼏的时候,默认为 1(三)⽂法的拓⼴?⽂法的拓⼴是对现有⽂法,添加⼀个 S',并对⽂法进⾏展开。
例如:对于⽂法 G[E]:E → E+T|TT → T*F|FF → i|(E)可以把它拓⼴为⽂法 G[E']:E' → EE → E+T|TT → T*F|FF → i|(E)此时可能会有疑问,不就是加了个开始符号,有什么意义呢?为什么要再加个开始符号呢?加开始符号是为了状态的表⽰,这样原来的 S 会成为右部,可以表⽰ .S 和 S.那同⼀⾮终结符的右部有多种情况为什么不展开呢?这⾥是说拓⼴⽂法,是添加开始符号,可以展开可以不展开,但是⼀般默认要展开,⼀般⼀道题不会只让求拓⼴⽂法,⽽是为了后⾯。
编译原理LR分析法
编译原理是研究如何将高级语言程序转换成等价的低级机器语言程序的学科, LR分析法是其中一种重要的语法分析方法。
何为编译原理
编译原理是计算机科学的一个分支,研究将高级语言程序转换为等价的底层机器代码的过程。它涉及词法分析、 语法分析、语义分析、优化和代码生成等多个阶段。
LR分析法的概述
LR分析法的步骤
1
1. 构建LR项集族
基于文法的产生式,生成LR(0)项集族,
2. 构建LR分析表
2
包括起始项集和其它项集。
根据LR项集族和文法的终结符和非终结
符,构建LR分析表,包括移进、规约和
接受操作。Leabharlann 33. 进行语法分析
使用构建的LR分析表,对输入的符号串 进行逐步解析,直到接受或出错。
构建LR分析表
项集的闭包
通过对项集进行闭包运算,计算 出项集中的所有项。
项集的转移
根据项目集的状态和接收符号, 进行项集的状态转移。
规约项的处理
确定规约的产生式和规约动作, 构建规约表。
LR分析表的使用
使用构建的LR分析表,可进行能够解析输入符号串的自底向上语法分析。它 根据输入符号和栈顶符号,执行移进、规约或接受操作来推导和验证语法结 构。
优缺点和应用
优点
具有广泛适用性,支持大多 数上下文无关文法。解析效 率高,能够快速生成语法树。
缺点
对于某些复杂的语法,可能 需要构建大型的分析表。编 写LR分析器的难度较高。
应用
LR分析法被广泛用于编译器 设计、解析器生成器和语法 分析工具的开发中。
LR分析法是一种自底向上的语法分析方法,用于构建一个确定性的有限状态 自动机(LR自动机)以解析各种语法结构。它具有广泛的应用,包括编译器 设计和语法分析工具的开发。
LR(1)实验报告(附代码)
实验三LR(1) 分析法实验学时: 4实验类型:验证实验要求:必修一、实验目的构造LR(1) 分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR (K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容对下列文法,用LR( 1)分析法对任意输入的符号串进行分析:(产生式有误,进行修改)( 1 ) E- E+T( 2) E- E —T( E->T)( 3) T- T*F( 4) T- T/F (T->F)( 5) F- (E)( 6) F- i三、实验目的1、编程时注意编程风格:空行的使用、注释的使用、缩进的使用等。
2、如果遇到错误的表达式,应输出错误提示信息。
3、程序输入/输出实例:输入一以#结束的符号串(包括+—*/ () i#):在此位置输入符号串输出过程如下:步骤状态栈符号栈剩余输入串动作1 0 # i+i*i#移进实验报告正文的内容:描述LR(1)语法分析程序的设计思想:定义项目的一般形式是[A —• , a ©…a],这样的一个项目称为一个LR(k)项目。
项目中的a©…a称为它的向前搜索符串(或展望串),令K=1,即为LR(1)语法分析程序。
在此,重新定义CLOSURE( I 的算法:项目集I的闭包CLOSURED构造方法:1.I的任何项目都属于CLOSURE(I)2.若项目[A —•B , a]属于CLOSURE(I) B—是一个产生式,那么,对于FIRST( a)中的每个终结符b,如果[B —•b]原来不在CLOSURE(I中,则把它加进去。
3.重复执行步骤2,直至CLOSURE(不再增大为止。
GO()的算法保持与LR语法分析程序一样,通过以下方法构造文法分析表:动作ACTION和状态转换GOT构造如下:1.若项目[A —•a , b]属于I k 且GO(I k, a) = I j, a 为终结符,则置ACTION[k, a]为“sj ”。
编译原理上机源代码LR语法分析器
输入:3+4*6输出:27(当然中间包括LR(1)语法分析过程程序提供主要为了给大家提供一些方便,你懂得。
呵呵如有问题,QQ:718561468来自:大连理工大学软件学院#include<iostream>using namespace std;#include<stack>#include<queue>#include<fstream>#include<string>stringAnalyzeChart[16][11]={//LR文法的分析表"s5", "e1", "e1", "s4", "e2", "e1", "1", "2", "3", "e1", "e1","e3", "s6", "e1", "e3", "e2", "acc", "error", "error", "error", "s7", "e1","e6", "r2", "s8", "e6", "r2", "r2", "error", "error", "error", "r2", "s9","e6", "r4", "r4", "e6", "r4", "r4", "error", "error", "error", "r4", "r4","s5", "e1", "e1", "s4", "e2", "e1", "10", "2", "3", "e1", "e1","e5", "r6", "r6", "e3", "r6", "r6", "error", "error", "error", "r6", "r6","s5", "e1", "e1", "s4", "e2", "e1", "error", "11", "3", "e1", "e1","s5", "e1", "e1", "s4", "e2", "e1", "error", "12", "3", "e1", "e1","s5", "e1", "e1", "s4", "e2", "e1", "error", "error", "13", "e1", "e1","s5", "e1", "e1", "s4", "e1", "e1", "error", "error", "14", "e1", "e1","e3", "s6", "e1", "e3", "s15", "r3", "error", "error", "error", "s9", "e1","e6", "r1", "s8", "e6", "r1", "r1", "error", "error", "error", "r1", "s9","e6", "r7", "s8", "e6", "r7", "r7", "error", "error", "error", "r7", "s9","e6", "r3", "r3", "e6", "r3", "r3", "error", "error", "error", "r3", "r3","e6", "r8", "r8", "e6", "r8", "r8", "error", "error", "error", "r8", "r8","e6", "r5", "r5", "e6", "r5", "r5", "error", "error", "error","r5", "r5",};stack<float> digit;queue<float> digit1;queue<int>inputid;char *FinalSymbol[6]={"i","+","*","(",")","#"//终结符};char *UnfinalSymbol[5]={"E","E'","T","T'","F"//非终结符};stack<char>ufstack;//状态栈void initialize(){ufstack.push('0');inputid.push(0);}char * keyword[6] = {"for","if","then","else","while","do"}; int flag1=-1,flag2=-1;typedefstruct sign{int line;int token;char temp[10];int i;};void reset(sign & s){s.i = 0;memset(s.temp,'$',10);s.token = -1;}boolis_key_word(sign & s){inti,r;for(i=0;i<6;i++){r = memcmp(s.temp,keyword[i],s.i);if(r == 0){s.token = i+1;return true;break;}}return false;}boolis_id(sign & s){int i;bool b = false;if( (s.temp[0]>='a' &&s.temp[0]<='z') | (s.temp[0]>='A' &&s.temp[0]<='Z') )b = true;elsereturn b;for(i=1;i<strlen(s.temp);i++){if( (s.temp[i]>='a' &&s.temp[i]<='z') | (s.temp[i]>='A' &&s.temp[i]<='Z') | (s.temp[i]>='0' &&s.temp[i]<='9'));else{b = false;return b;}}return b;}boolis_num(sign & s){digit.push(0);bool b = true;char c;int state = 12;for(int i=0;i<strlen(s.temp);i++){c = s.temp[i];inttn;switch(state){case 12:{if(c>='0' && c<='9' || c=='-'){state = 13;}elsereturn false;break;}case 13:{if(c>='0' && c<='9') state = 13;else if(c=='.') state=14;else if(c=='E' || c=='e') state=16;else return false;break;}case 14:{if(c>='0' && c<='9') state=15;else return false;break;}case 15:{if(c>='0' && c<='9') state=15;else if(c=='E' || c=='e') state=16;else return false;break;}case 16:{if(c=='+' || c=='-') state=17;else if(c>='0' && c<='9') state=18;else return false;break;}case 17:{if(c>='0' && c<='9') state=18;else return false;break;}case 18:{if(c>='0' && c<='9') state=18;else return false;break;}}}return b;}int handle(sign & s){s.temp[s.i] = '\0';if(strlen(s.temp)==0)return 0;if(is_key_word(s)){cout<<"("<<s.token<<","<<keyword[s.token-1]<<")";inputid.push(s.token);returns.token;}else if(is_id(s)){cout<<"(10,"<<s.temp<<")";inputid.push(10);return 10;}else if(is_num(s)){cout<<"(11,"<<s.temp<<")";inputid.push(11);int i=0;float n=0;int n1=0;while(i<s.i){ n1=n1*10;if(s.temp[i]=='.'){n1=1;i++;}else{n=n*10+(s.temp[i]-'0');i++;}}if(n1!=0)n=n/n1;// cout<<s.i<<" "<<s.temp<<" "<<n<<endl;digit1.push(n);n=0;reset(s);return 11;}else{return 0;}reset(s);}void scan(FILE * fp){sign mark = {1,-1,{'$','$','$','$','$','$','$','$','$','$'},0};charch;do{ch = fgetc(fp);if(ch=='\n'){mark.line++;handle(mark);}else if(ch==' ')handle(mark);else if(ch=='+'){handle(mark);cout<<"(13,"<<ch<<")";inputid.push(13);}else if(ch=='-'){handle(mark);cout<<"(14,"<<ch<<")";inputid.push(14);}else if(ch=='*'){handle (mark);cout<<"(15,"<<ch<<")";inputid.push(15);}else if(ch=='/'){handle (mark);cout<<"(16,"<<ch<<")";inputid.push(16);}else if(ch==':'){handle (mark);mark.temp[mark.i++] = ch;cout<<"(17,"<<ch<<")";inputid.push(17);}else if(ch=='<'){handle (mark);cout<<"(20,"<<ch<<")";inputid.push(20);}else if(ch=='>'){handle (mark);cout<<"(23,"<<ch<<")";inputid.push(23);}else if(ch=='='){if(mark.temp[mark.i-1]==':'){cout<<"(18,:=)";reset(mark);inputid.push(18);}else{handle(mark);cout<<"(25,"<<ch<<")";inputid.push(25);}}else if(ch==';'){handle (mark);cout<<"(26,"<<ch<<")";inputid.push(26);}else if(ch=='('){handle (mark);cout<<"(27,"<<ch<<")";inputid.push(27);}else if(ch==')'){handle (mark);cout<<"(28,"<<ch<<")";inputid.push(28);}else{mark.temp[mark.i++] = ch;// handle(mark);}}while(ch!='#');cout<<endl;}int main(intargc ,char *argv[]){initialize();//初始化stackFILE * fp;fp = fopen("test.txt","r");scan(fp);//cout<<inputid.size()<<endl;string temp;int h=0;int z=30;inputid.pop();inputid.push(0);while((!inputid.empty()) && z>0){z--;while(true){int state=-1,sflag2=0;char temp1=ufstack.top();int sflag1=inputid.front();//cout<<sflag1<<endl;{if(sflag1==11)flag1=0;else if(sflag1==13)flag1=1;else if(sflag1==15)flag1=2;else if(sflag1==27)flag1=3;else if(sflag1==28)flag1=4;else if(sflag1==0)flag1=5;else if(sflag1==14)flag1=9;else if(sflag1==16)flag1=10;else flag1=-1;}if(flag1==-1){cout<<"Unexpected symbol!"<<endl;}state=temp1-'0';// cout<<state<<"VVVVV"<<flag1<<endl;charsta=0;char t1=ufstack.top();ufstack.pop();if(!ufstack.empty() &&ufstack.top()>='0' &&ufstack.top()<='9'){sta=ufstack.top()-'0';if(sta>0)state=state+sta*10;}elseufstack.push(t1);cout<<"("<<state<<", "<<flag1<<") ------"<<AnalyzeChart[state][flag1].c_str ()<<"-----"<<endl;if(strcmp(AnalyzeChart[state][flag1].c_str (),"s5")==0)//移近{ufstack.push('i');ufstack.push('5');cout<<"移进id"<<endl;//ip++;digit.push(digit1.front());digit1.pop();cout<<inputid.front();inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"s4")==0)//移近{ufstack.push('(');ufstack.push('4');cout<<"移进( "<<endl;//ip++;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"s6")==0)//移近{ufstack.push('+');ufstack.push('6');cout<<"移进+ "<<endl;//ip++;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"s7")==0)//移近{ufstack.push('-');ufstack.push('7');cout<<"移进- "<<endl;//ip++;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"s8")==0)//移近{ufstack.push('*');ufstack.push('8');cout<<"移进* "<<endl;//ip++;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"s9")==0)//移近{ufstack.push('/');ufstack.push('9');cout<<"移进/ "<<endl;//ip++;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r1")==0)//归约{for(int i=0;i<6;i++)ufstack.pop();cout<<"归约E->E+T"<<endl;floatntop=digit.top();//digit.pop();digit.pop();cout<<ntop<<"+"<<digit.top()<<"=";ntop+=digit.top();digit.pop();digit.push(ntop);cout<<digit.top()<<endl;intst=ufstack.top()-'0';ufstack.push('E');charch=*AnalyzeChart[st][6].c_str ();if(strcmp(AnalyzeChart[st][6].c_str (),"10")==0){ufstack.push(*(AnalyzeChart[st][6].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r7")==0)//归约{for(int i=0;i<6;i++)ufstack.pop();cout<<"归约E->E-T"<<endl;floatntop=digit.top();//digit.pop();digit.pop();cout<<digit.top()<<"-"<<ntop<<"=";ntop=digit.top()-ntop;digit.pop();digit.push(ntop);cout<<digit.top()<<endl;intst=ufstack.top()-'0';ufstack.push('E');charch=*AnalyzeChart[st][6].c_str ();if(strcmp(AnalyzeChart[st][6].c_str (),"10")==0){ufstack.push(*AnalyzeChart[st][6].c_str ());ufstack.push(*(AnalyzeChart[st][6].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r2")==0)//归约{ufstack.pop();ufstack.pop();cout<<"归约E->T"<<endl;intst=ufstack.top()-'0';ufstack.push('E');charch=*AnalyzeChart[st][6].c_str ();if(strcmp(AnalyzeChart[st][6].c_str (),"10")==0){ufstack.push(*(AnalyzeChart[st][6].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r3")==0)//归约{for(int i=0;i<6;i++)ufstack.pop();cout<<"归约T->T*F"<<endl;floatntop=digit.top();digit.pop();// digit.pop();cout<<ntop<<"*"<<digit.top()<<"=";ntop=ntop*digit.top();digit.pop();digit.push(ntop);cout<<ntop<<endl;intst=ufstack.top()-'0';ufstack.push('T');charch=*AnalyzeChart[st][7].c_str ();if(strcmp(AnalyzeChart[st][7].c_str (),"11")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}else if(strcmp(AnalyzeChart[st][7].c_str (),"12")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r8")==0)//归约{for(int i=0;i<6;i++)ufstack.pop();cout<<"归约T->T/F"<<endl;floatntop=digit.top();digit.pop();// digit.pop();cout<<digit.top()<<"/"<<ntop<<"=";if(ntop!=0)ntop=digit.top()/ntop;else{cout<<"error,除数不能是零"<<endl;ntop=0;}cout<<ntop<<endl;digit.pop();digit.push(ntop);//cout<<ntop<<"_________"<<digit.top()<<endl;intst=ufstack.top()-'0';ufstack.push('T');charch=*AnalyzeChart[st][7].c_str ();if(strcmp(AnalyzeChart[st][7].c_str (),"11")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}else if(strcmp(AnalyzeChart[st][7].c_str (),"12")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r4")==0)//归约{ufstack.pop();ufstack.pop();cout<<"归约T->F"<<endl;intst=ufstack.top()-'0';ufstack.push('T');charch=*AnalyzeChart[st][7].c_str ();if(strcmp(AnalyzeChart[st][7].c_str (),"11")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}else if(strcmp(AnalyzeChart[st][7].c_str (),"12")==0){ufstack.push(*AnalyzeChart[st][7].c_str ());ufstack.push(*(AnalyzeChart[st][7].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r5")==0)//归约{for(int i=0;i<6;i++)ufstack.pop();cout<<"归约F->(E)"<<endl;intst=ufstack.top()-'0';ufstack.push('F');charch=*AnalyzeChart[st][8].c_str ();if(strcmp(AnalyzeChart[st][8].c_str (),"13")==0){ufstack.push(*AnalyzeChart[st][8].c_str ());ufstack.push(*(AnalyzeChart[st][8].c_str ()+1));}else if(strcmp(AnalyzeChart[st][8].c_str (),"14")==0){ufstack.push(*AnalyzeChart[st][8].c_str ());ufstack.push(*(AnalyzeChart[st][8].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"r6")==0)//归约{for(int i=0;i<2;i++)ufstack.pop();cout<<"归约F->id"<<endl;intst=ufstack.top()-'0';ufstack.push('F');charch=*AnalyzeChart[st][8].c_str ();if(strcmp(AnalyzeChart[st][8].c_str (),"13")==0){ufstack.push(*AnalyzeChart[st][8].c_str ());ufstack.push(*(AnalyzeChart[st][8].c_str ()+1));}else if(strcmp(AnalyzeChart[st][8].c_str (),"14")==0){ufstack.push(*AnalyzeChart[st][8].c_str ());ufstack.push(*(AnalyzeChart[st][8].c_str ()+1));}elseufstack.push(ch);}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"acc")==0) {cout<<"Analyze complate! "<<endl;inputid.pop();break;}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"e2")==0) {cout<<"不配对的右括号!"<<endl;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"e3")==0) {cout<<"缺少运算符"<<endl;inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"e1")==0) {cout<<"缺少运算对象"<<endl;//ufstack.push('i');//ufstack.push('5');inputid.pop();}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"e4")==0) {cout<<"缺少右括号"<<endl;ufstack.push(')');ufstack.push('11');}else if(strcmp(AnalyzeChart[state][flag1].c_str (),"e5")==0){cout<<"算符重复"<<endl;inputid.pop();}else //M[X,a]=一个产生式{cout<<"Strange error happen !"<<endl;break;}}h++;}cout<<"最终结果是"<<digit.top()<<endl;return 0;}。
利用C、 C++语言求的LR(1)分析方法
如:给定一文法:Z->aAcB|BdA->cDD->aBD|dB->bCC->BcA|@能求出其first集:First(Z)={a,b}First(A)={c}First(B)={b}First(C)={b,@}First(D)={a,d}First(a)={a}First(b)={b}First(c)={c}First(d)={d}first(@)={@}follow集:FOLLOW(A) = { c, #, d, a }FOLLOW(B) = { #, d, a, c }FOLLOW(C) = { #, d, a, c }FOLLOW(D) = { c, #, d, a }FOLLOW(Z) = { # }select集:SELECT(Z->aAcB) = { a }SELECT(Z->Bd) = { b }SELECT(A->cD) = { c }SELECT(D->aBD) = { a }SELECT(D->d) = { d }SELECT(B->bC) = { b }SELECT(C->BcA) = { b }SELECT(C->@) = { @ ,#,d,a,c}给定一字符处让其判定如acabdcb,结果能接受程序:#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]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/ char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/char empty[20]; /*记录可直接推出@的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*//*******************************************判断一个字符是否在指定字符串中********************************************/int in(char c,char *p){int i;if(strlen(p)==0)return(0);for(i=0;;i++){if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/}}/*******************************************得到一个不是非终结符的符号********************************************/char c(){char c='A';while(in(c,non_ter)==1)c++;return(c);}/*******************************************分解含有左递归的产生式********************************************/void recur(char *point){ /*完整的产生式在point[]中*/ int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++){if(point[n]==point[0]){ /*如果'|'后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++){while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|'){n=j+1;break;}}}else{ /*如果'|'后的首符号和左部不同*/left[count]=ch;right[count][0]='@';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;}}}/******************************************* 分解不含有左递归的产生式********************************************/ void non_re(char *point){int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;}/*******************************************读入一个文法********************************************/ 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,k;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();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("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);}return(s);}/*******************************************将单个符号或符号串并入另一符号串********************************************/void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的' @ '一并并入目串;type=2,源串中的' @ '不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++){if(type==2&&s[i]=='@');else{for(j=0;;j++){if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d)){d[j]=s[i];d[j+1]='\0';break;}}}}}/*******************************************求所有能直接推出@的符号********************************************/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);emp(left[i]);}}}/*******************************************求某一符号能否推出' @ '********************************************/int _emp(char c){ /*若能推出,返回1;否则,返回0*/ int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++){if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/{j=strlen(right[i]); /*j为右部的长度*/ if(j==1&&in(right[i][0],empty)==1)return(1);else if(j==1&&in(right[i][0],termin)==1)return(0);else{for(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;else{for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);}}}if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);}}}/*******************************************判断读入的文法是否正确********************************************/int judge(){int i,j;for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/printf("\nerror1!");validity=0;return(0);}for(j=0;j<=strlen(right[i])-1;j++){if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='@'){ /*若右部某一符号不在非终结符、终结符中且不为' @ ',报错*/ printf("\nerror2!");validity=0;return(0);}}}return(1);}/*******************************************求单个符号的FIRST********************************************/void first2(int i){ /*i为符号在所有输入符号中的序号*/ char c,temp[20];int j,k,m;c=v[i];char ch='@';emp(ch);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++){if(left[j]==c){if(in(right[j][0],termin)==1||right[j][0]=='@') {temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);}else if(in(right[j][0],non_ter)==1){if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0'){first2(k);f[k]='1';}merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++) {empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1){for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0'){first2(m);f[m]='1';}merge(first1[i],first1[m],2);}else if(_emp(right[j][k])==1&&k==strlen(right[j])-1){temp[0]='@';temp[1]='\0';merge(first1[i],temp,1);}elsebreak;}}}}}f[i]='1';}/*******************************************求各产生式右部的FIRST********************************************/void FIRST(int i,char *p){int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/ {if(p[0]=='@'){{first[i][0]='@';first[i][1]='\0';}else{TEMP[0]='@';TEMP[1]='\0';}}else{for(j=0;;j++)if(v[j]==p[0])break;if(i>=0){memcpy(first[i],first1[j],strlen(first1[j]));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])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])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){int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);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) /*找一个右部含有c的产生式*/ {for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1){merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++){empt[0]='\0';result*=_emp(right[j][n]);}if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);}}}F[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';f[j]='0';F[j]='0';}for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\n各非终结符导出的first集:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\n能导空的非终结符集合:%s",empty);// printf("\n_emp:");//for(j=0;j<=strlen(v)-1;j++)// printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0){fo[0]='\0';FOLLOW(j);}}//printf("\nfirst:");//for(i=0;i<=count-1;i++)// printf("%s ",first[i]);printf("\nfollow集合:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='@')result=1;if(result==1){for(j=0;;j++)if(v[j]==left[i])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]))return(0);}else{temp[0]='\0';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++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++){for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++){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;}else{S[strlen(S)-1]='\0';j++;ch=str[j];}}else{for(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++){if(termin[k]==ch)break;if(k==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<=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 ",left[i]);if(validity==1)validity=judge();//printf("\nvalidity=%d",validity);if(validity==1){ll=ll1();// printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");else{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();}}}。
实验5---语法分析器(自下而上):LR(1)分析法
实验5---语法分析器(自下而上):LR(1)分析法实验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.编写主程序利用上文描述算法实现本实验要求。
编写lr分析器课程设计
编写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分析器对简单编程语言进行语法分析,转化为语法分析树。
编译原理LL(1)分析器(C语言)
*
知
FOLLOW (T ) FOLLOW ( F )
,
即
FOLLOW(F)={*,+,),#}。 4 LL(1)分析表 知道了 FIRST 集和 FOLLOW 集, 我们就可以构造出 LL(1)分析表。 文法 G[E] 的分析表如表 1:
表1 i E E’ T T’ F + 文法 G[E]的分析表 * ( ) #
if(ch[l]!=cha) { if(ch[l]!=39) { switch(ch[l]) { case 'E': m=0;break; case 'T': m=2;break; case 'F': m=4;break; default: m=-1;break; } }/*if(ch[l]!=''')*/ else { switch(ch[l-1]) { case 'E': m=1;break; case 'T': m=3;break; default: m=-1;break; } }/*if(ch[l])=='''*/ }/*if ch[l]!=cha*/ if(m!=-1) { if(ch[l]!=cha) { how=ll1[m][j]; if(how==1) { printf("Pop %c,push E->TE' by reversing!\n",ch[l]); n=3; l=l+n-1; ch[l]='T'; ch[l-1]=39; ch[l-2]='E'; step=step+1; }/*if how==1*/
编译原理课程设计-LL(1)语法分析器的构造
LL(1)语法分析器的构造摘要语法分析的主要任务是接收词法分析程序识别出来的单词符由某种号串,判断它们是否语言的文法产生,即判断被识别的符号串是否为某语法部分。
一般语法分析常用自顶向下方法中的LL分析法,采用种方法时,语法分程序将按自左向右的顺序扫描输入的的符号串,并在此过程中产生一个句子的最左推导,即LL是指自左向右扫描,自左向右分析和匹配输入串。
经过分析,我们使用VC++作为前端开发工具,在分析语法成分时比较方便直观,更便于操作。
运行程序的同时不断修正改进程序,直至的到最优源程序。
关键字语法分析文法自顶向下分析 LL(1)分析最左推导AbstractGrammatical analysis of the main tasks was to receive lexical analysis procedure to identify the words from a website, string, and judge whether they have a grammar of the language, that is, judging by the series of symbols to identify whether a grammar part. General syntax analysis commonly used top-down methods of LL analysis, using methods, Grammar hours will be from the procedures of the order left-to-right scanning input string of symbols, and in the process produced one of the most left the sentence is derived, LL is scanned from left to right, From left to right analysis and matching input strings. After analysis, we use VC + + as a front-end development tool for the analysis of syntax ingredients more convenient visual, more easy to operate. Operational procedures at the same time constantly improving procedures, until the source of optimal .Key WordsGrammatical analysis grammar Top-down analysis LL (1) AnalysisMost left Derivation目录摘要 (1)引言 (3)第一章设计目的 (4)第二章设计的内容和要求 (5)2.1 设计内容 (5)2.2 设计要求 (5)2.3 设计实现的功能 (5)第三章设计任务的组织和分工 (6)3.1 小组的任务分工 (6)3.2 本人主要工作 (6)第四章系统设计 (9)4.1 总体设计 (9)4.2 详细设计 (9)第五章运行与测试结果 (22)5.1 一组测试数据 (22)5.2 界面实现情况 (23)第六章结论 (27)课程设计心得 (28)参考文献 (29)致谢 (30)附录(核心代码清单) (31)引言编译器的构造工具是根据用户输入的语言的文法,编译器的构造工具可以生成程序来处理以用户输入的文法书写的文本。
编译原理课程设计LR(1)语法分析构造器的设计
前言计算机语言之所以能由单一的机器语言发展到现今的数千种高级语言,就是因为有了编译技术,编译原理技术是计算机科学中发展的最迅速、最成熟的一个分支,它集中体现了计算机发展成果与精华。
未来计算机工作者,都应该掌握这门基础的专业基础知识。
“编译原理”是计算机及其相关专业的重要专业基础课,主要研究设计和构造编译程序的原理和方法。
全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技。
编译原理蕴涵着计算机学科中解决问题的思路、形式化问题和解决问题的方法,对应用软件和系统软件的设计与开发有一定的启发和指导作用,编译程序构造的原理和技术在软件工程、语言转换等许多领域中有着广泛应用。
语法分析是编译程序的核心部分。
语法分析的作用是识别由词法分析给出的单词符号序列是否是给定文法的正确句子,目前语法分析常用的方法有自顶向下分析和自顶向上分析两大类。
自顶向上分析包括确定分析和不确定分析,自顶向上分析又包括算符优先分析和LR分析。
鉴于此,运用这些分析方法构造一个简单的分析程序是很有实践意义的。
目录编译原理课程设计任务书 (3)第1章概述 (5)1.1 背景 (5)1.2 目的 (5)1.3 软件定义 (5)1.4 开发环境 (5)第2章需求分析 (6)2.1 问题陈述 (6)2.2 需完成的功能 (6)第3章逻辑设计 (7)3.1 模块设计 (7)3.1.1 LR(1)项目集规范族的构造算法 (8)3.1.2 LR(1)分析表的构造算法 (8)3.2 流程图 (9)第4章总体设计 (15)4.1 构造项目集规范族模块 (15)4.2 构造预测分析表模块 (15)4.3 分析串程序模块 (15)第5章界面设计 (16)小结 (33)致谢 (34)参考文献 (35)附录源程序清单 (36)《编译原理课程设计》任务书1、本课题的目的及意义课程设计实践对学生巩固所学基础专业课程知识、进行编译系统基本技能训练、培养实践动手能力,从而掌握编译系统的基本工作原理、基本方法和基本开发技术,最终达到具有一定的编译系统的实际开发能力有重要意义。
编译原理课程设计LR1分析语法分析器实现(C++)
编译原理课程设计LR1分析语法分析器实现(C++)输⼊的⽂法(第⼀⾏是终结符)将⽂法保存在txt中,命名为text.txt,与LR1.cpp放在同⼀⽬录中即可运⾏。
text.txtabcdeS->aAdS->bAcS->aecS->bedA->e实现代码:LR1.cpp1 #include<fstream>2 #include<iostream>3 #include<string>4 #include<vector>5 #include <algorithm>6#define MAX_Count 1007 #include <set>8 #include <stack>9 #include <iomanip>10 #include <sstream>11 #include <string>12 #include<cstring>13 #include <map>14using namespace std;151617// 重载⼀下+号运算符18 template <typename CSS_LR1>19 vector<CSS_LR1> &operator +(vector<CSS_LR1> &v1,vector<CSS_LR1> &v2)20 {21 v1.insert(v1.end(),v2.begin(),v2.end());22return v1;23 }242526struct VN_Set{27string VN_name;//⾮终结符28set<string> FIRST; //First集合29set<string> FOLLOW;30 };31struct CSS{32string start;//⾮终结符33 vector<string> next; //First集合34 };35struct CSS_LR1{36string start;//⾮终结符37 vector<string> next; //First集合38int num;39 vector<string> tail;40//41// bool operator==(CSS_LR1& rhs) const {42// return (start == rhs.start &&43// next == rhs.next &&44// num == rhs.num &&45// tail == rhs.tail);46// }47bool operator==(const CSS_LR1& rhs) {48return (start == rhs.start &&49 next == rhs.next &&50 num == rhs.num &&51 tail == rhs.tail);52 }5354 };5556int CSSCount = 0;57 CSS css[MAX_Count];//产⽣式58 VN_Set VN_First[MAX_Count];//⾮终结符集的First集合59set<string> VN;// ⾮终结符集合60set<string> VT;//终结符集合61int I_count = 0;//记录LR1项⽬数62 vector<CSS_LR1> I[MAX_Count]; //项⽬集63 map<string,int> mark_Follow;//⽤于标记Follow 防⽌套娃64 map<string,int> GOTO[MAX_Count];65 map<string,string> ACTION[MAX_Count];666768bool cmp_vector(vector<CSS_LR1>&v1, vector<CSS_LR1>&v2)69 {70if(v1.size()!=v2.size()) return false;71for (int i=0; i<v2.size(); i++)72 {73 CSS_LR1 t;74 t = v2[i];75 vector<CSS_LR1>::iterator result = find(v1.begin( ), v1.end( ),t); //查找376if (result == v1.end( )) //没找到77return false;78 }79return true;80 }8182/*83*实现编译原理语法分析中计算⾮终结符的First集Follow集84*/85set<string> get_FIRST(string a){ //求First集合86set<string> T;87for(int i = 0;i<CSSCount;i++){88if(css[i].start==a){ // a->..89for(int j=0;j<css[i].next.size();j++){90if(VT.find(css[i].next[j])!=VT.end()){ //是终结符开头91 T.insert(css[i].next[j]);92// T.erase("*");93break;94 }95else{96if(css[i].next[j]==css[i].start){102if(j!=css[i].next.size()-1)103 T.erase("$");104 }else{105106break;107 }108 }109110111 }112113 }114 }115116return T;117 }118119set<string> get_FOLLOW(string a){120set<string> T;121//cout<<"现在在求"<<a<<" 的Follow"<<endl;122 mark_Follow[a]++;123if(mark_Follow[a]>=2){124return T;125 }126127set<string> temp;128if(a==css[0].start){129 T.insert("#");130 }131for(int i = 0;i<CSSCount;i++){132for(int j =0;j<css[i].next.size();j++){133if(VT.find(css[i].next[j])==VT.end()&&a==css[i].next[j]){ //是⾮终结符,求FOLLOW集合134if(j==css[i].next.size()-1&&a!=css[i].start){//S->...a135set<string> tt = get_FOLLOW(css[i].start);136 T.insert(tt.begin(),tt.end());137 }138for(int k=j+1;k<css[i].next.size();k++){139if(VT.find(css[i].next[k])!=VT.end()){//后⾯⼀个是终结符 S->..av..140 T.insert(css[i].next[k]);141break;142 }143else{144 temp = get_FIRST(css[i].next[k]);145if(temp.find("$")!=temp.end()){//有$ S->..a B..146 T.insert(temp.begin(),temp.end());147 T.erase("$");148if(k==css[i].next.size()-1){ //S->..a B149set<string> tt = get_FOLLOW(css[i].start);150 T.insert(tt.begin(),tt.end());151break;152 }153 }else{154 T.insert(temp.begin(),temp.end());155break;156 }157 }158 }159160 }161 }162163 }164//cout<<a<<" "<<mark_Follow[a]<<endl;165 mark_Follow[a]=0;166return T;167 }168169170void GetFirst_and_Follow(){171set<string>::iterator it;172int count = 0;173 cout<<"========================================="<<endl;174 cout<<'\t' <<"FIRST集合"<<""<<"FOLLOW集合"<<endl;175for(it=VN.begin ();it!=VN.end ();it++)176 {177178 VN_First[count].VN_name = *it;179 VN_First[count].FIRST = get_FIRST(*it);180181 mark_Follow[*it]=0;182 VN_First[count].FOLLOW = get_FOLLOW(*it);183184//-----------输出FIRST--------------------185186 cout<<VN_First[count].VN_name<<'\t';187set<string>::iterator it;188for(it=VN_First[count].FIRST.begin();it!=VN_First[count].FIRST.end();it++){189 cout<<*it<<"";190 }191 cout<<'\t'<<"";192//----------------------------------------193194195196197//------------输出FOLLOW--------------198set<string>::iterator it1;199for(it1=VN_First[count].FOLLOW.begin();it1!=VN_First[count].FOLLOW.end();it1++){200 cout<<*it1<<"";201 }cout<<endl;202203//----------------------204205 count++;206 }cout<<"=========================================";207 cout<<endl<<endl;208 }209210211212213214void input(){215//创建⼀个⽂件输⼊流对象216 ifstream inFile;217//打开⽂件218 inFile.open("test.txt");223 cout << "file doesn't exist" << endl;224225string temp;226 getline(inFile,temp);227for(int j=0;j<temp.length();j++){228 VT.insert(temp.substr(j,1));229 }230set<string>::iterator p;231 cout<<"终结符号:";232for(p = VT.begin();p!=VT.end();p++){233 cout<<*p<<",";234 }cout<<endl;235236int count = 0;//⽂件⾏数237while(getline(inFile,temp)) //按⾏读取⽂件内容238 {239 css[count].start = temp[0] ;240for(int j=3;j<temp.length();j++){241 css[count].next.push_back(temp.substr(j,1));242 }243 VN.insert(css[count].start);//⾮终结符244245 cout<<css[count].start<<"->";246 vector<string>::iterator it;247for(it=css[count].next.begin();it!=css[count].next.end();it++){248 cout<<*it;249 }250 cout<<endl;251252253 count++;254 }255 CSSCount = count;256257258 }259260bool find_in_vector(vector<CSS_LR1> T,CSS_LR1 p){261 vector<CSS_LR1>::iterator it;262for(it=T.begin();it!=T.end();it++){263if(*it==p){264return true;265 }266 }267return false;268 }269270271 vector<CSS_LR1> CLOSURE(CSS_LR1 I){//求闭包272 vector<CSS_LR1> T;273//T.push_back(I);274if(I.num>=I.next.size()) { //规约项⽬A->α.或者接受项⽬275return T;276 }277else{278string temp = I.next[I.num];279if(VT.find(temp)!=VT.end()){ //点后⾯的是终结符 ,移进项⽬ A→α.aβ280return T;281 }282else{ //待约项⽬283for(int i = 0;i<CSSCount;i++){284if(css[i].start==temp){285 CSS_LR1 p;286 p.start = css[i].start;287 p.num = 0;//点在最前⾯288 p.next = css[i].next;289290set<string> f1;291for(int j = I.num+1;j<I.next.size();j++){292set<string> f2;//⽤于暂存first293294if(VT.find(I.next[j])!=VT.end()){295296 f2.insert(I.next[j]);297 }else{298 f2 = get_FIRST(I.next[j]);299 }300301 f1.insert(f2.begin(),f2.end());302if(f2.find("$")==f2.end()){303304break;305 }306 }307308if(f1.size()==0){309 p.tail=I.tail;310 }311else{312 vector<string> first_tail;313if(f1.find("$")!=f1.end()){314 f1.erase("$");315 copy(f1.begin(),f1.end(), back_inserter(first_tail));316 first_tail.insert(first_tail.end(),I.tail.begin(),I.tail.end()); 317 }else{318 copy(f1.begin(),f1.end(), back_inserter(first_tail));319//cout<<first_tail[0]<<endl;320 }321// vector<string>::iterator l;322// for(l=first_tail.begin();l!=first_tail.end();l++){323// cout<<*l<<" ";324// }cout<<endl;325 p.tail=first_tail;326 }327if(!find_in_vector(T,p)){328329 T.push_back(p);330 vector<CSS_LR1> ol = CLOSURE(p);331 vector<CSS_LR1>::iterator z;332for(z=ol.begin();z!=ol.end();z++){333if(find_in_vector(T,*z)){334 }else{335 T.push_back(*z);336 }337 }338339 }344 }345346return T;347 }348349void showI(vector<CSS_LR1> I){//展⽰项⽬集350 vector<CSS_LR1>::iterator it;351for(it=I.begin();it!=I.end();it++){352 CSS_LR1 p = *it;353 cout<<p.start<<"->";354 vector<string>::iterator s;355for(int j = 0;j<p.next.size();j++){356if(j==p.num) cout<<".";357 cout<<p.next[j];358 }if(p.num==p.next.size())cout<<".";359 cout<<",";360for(int k = 0;k<p.tail.size();k++){361 cout<<p.tail[k];362 }cout<<endl;363 }364 }365366void LR1_Analyse(){367 CSS_LR1 p;368//初始项⽬ S’->.S ,#369 p.start = css[0].start+"^";370 p.num = 0;//点在最前⾯371 p.tail.push_back("#");372 p.next.push_back(css[0].start);373374 I[0] = CLOSURE(p);//求闭包后的I[0]375 I[0].insert(I[0].begin(),p);///////////////求闭包遇到了⼀些问题376 I_count=1;377378//计算项⽬集379for(int i=0;i<I_count;i++){//每个项⽬集项⽬集I(i)380381 cout<<"==================="<<endl;382 cout<<"现在在计算项⽬集I"<<i<<endl;383 showI(I[i]);//展⽰项⽬集384 cout<<"==================="<<endl;385386//---------求ACTION的r部分--------------387 vector<CSS_LR1>::iterator t;388for(t=I[i].begin();t!=I[i].end();t++){389 CSS_LR1 t2 = *t;390if(t2.num==t2.next.size()){391int num =0;392for(int xp=0;xp<CSSCount;xp++){393if(css[xp].start==t2.start&&css[xp].next==t2.next){394 num = xp;395break;396 }397 }398399 std::stringstream ss;400 ss<<num;401string s = ss.str();402for(int q = 0;q<t2.tail.size();q++){403 ACTION[i][t2.tail[q]] = "r"+s;404 }405if(t2.num==1&&t2.next[0]==css[0].start){406 ACTION[i]["#"] = "acc";407 }408 }409 }410//--------------------------------------411412413414set<string>::iterator it;415for(it=VN.begin();it!=VN.end();it++){ //每个⾮终结符416//cout<<"项⽬集I"<<i<<"输⼊"<<*it<<endl;417 vector<CSS_LR1> temp;418//cout<<"项⽬集⼤⼩"<<I[i].size()<<endl;419for(int j = 0;j<I[i].size();j++){420 CSS_LR1 lr = I[i][j];421if(lr.num<lr.next.size()&&lr.next[lr.num]==*it){422//cout<<*it<<endl;423 vector<CSS_LR1> t2;424 lr.num++;425 t2 = CLOSURE(lr);426 t2.push_back(lr);427428 temp=temp+t2;429 }430 }431//cout<<"temp.size"<< temp.size()<<endl;432433if(temp.size()>0){434int k;435for(k=0;k<I_count;k++){//找⼀找项⽬集是否已经存在436if(cmp_vector(I[k],temp)){437break;438 }439 }440if(k==I_count){441//产⽣了新的项⽬集442 I[I_count] = temp;443/*444 cout<<"---------------------"<<endl;445 cout<<"新的项⽬集I"<<I_count<<endl;446 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<I_count<<endl<<endl; 447 showI(I[I_count]);//展⽰项⽬集448 cout<<"---------------------"<<endl;449*/450 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<I_count<<endl<<endl; 451 GOTO[i][*it] = I_count;//更新goto表452 I_count++;453 }else{454//项⽬集已经存在,需要⾃⼰指向⾃⼰455 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<k<<endl<<endl;456 GOTO[i][*it] = k;457458 }459460 }465 vector<CSS_LR1> temp;466467for(int j = 0;j<I[i].size();j++){468 CSS_LR1 lr = I[i][j];469470if(lr.num<lr.next.size()&&lr.next[lr.num]==*it){471 vector<CSS_LR1> t2;472 lr.num++;473 t2 = CLOSURE(lr);//闭包求出的结果不包含本⾝474 t2.insert(t2.begin(),lr);/////////求闭包遇到了⼀些问题475//showI(t2);476 temp=temp+t2;477 }478 }479//cout<<"temp.size"<< temp.size()<<endl;480if(temp.size()>0){481int k;482for(k=0;k<I_count;k++){//找⼀找项⽬集是否已经存在483if(cmp_vector(I[k],temp)){484break;485 }486 }487if(k==I_count){488//产⽣了新的项⽬集489 I[I_count] = temp;490/*491 cout<<"---------------------"<<endl;492 cout<<"新的项⽬集I"<<I_count<<endl;493 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<I_count<<endl<<endl;494 showI(I[I_count]);//展⽰项⽬集495 cout<<"---------------------"<<endl;496*/497 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<I_count<<endl<<endl;498 std::stringstream ss;499 ss<<I_count;500string s = ss.str();501 ACTION[i][*it] = "S"+s;//更新AVTION表502 I_count++;503 }else{504//项⽬集已经存在,需要⾃⼰指向⾃⼰505 cout<<" I"<<i<<" -- "<<*it<<"->"<<"I"<<k<<endl<<endl;506 std::stringstream ss;507 ss<<k;508string s = ss.str();509 ACTION[i][*it] = "S"+s;510511 }512513 }514 }515516517 }518519520 }521522void print_line(){523 cout<<"-----------------------------------------------------------------------------"<<endl;524 }525526527528void print_ACTION_GOTO(){529set<string>::iterator it;530 print_line();531 cout<<setw(27) << setiosflags(ios::right) <<"ACTION";532 cout<<setw(20) << setiosflags(ios::left)<<" GOTO"<<endl;533 print_line();534 cout<<setw(8)<<"项⽬集"<<"|";535536for(it=VT.begin();it!=VT.end();it++){537 cout<<setw(8)<<*it<<"|";538 }539 cout<<setw(8)<<"#"<<"|";540for(it=VN.begin();it!=VN.end();it++){541 cout<<setw(8)<<*it<<"|";542 }543 cout<<endl;544for(int j =0;j<I_count;j++){545 cout<<setw(6)<<"I"<<setw(2)<<j<<"|";546for(it=VT.begin();it!=VT.end();it++){547 cout<<setw(8)<<ACTION[j][*it]<<"|";548 }549 cout<<setw(8)<<ACTION[j]["#"]<<"|";550for(it=VN.begin();it!=VN.end();it++){551552if(GOTO[j][*it])//GOTO表为0553 cout<<setw(8)<<GOTO[j][*it]<<"|";554else{555 cout<<setw(8)<<""<<"|";556 }557 }558 cout<<endl;559 }560 print_line();561562 }563564565566//对栈容器进⾏输出,i=0,返回status中的字符串,i=1,返回sign中的字符串,i=2返回inputStr中的字符串567string vectTrancStr(int i,vector<int> status,vector<string> sign){568string buf;569int count = 0;570//输出状态栈571if(i == 0){572 vector<int>::iterator it =status.begin();573//将数字转化为字符串574string str,tempStr;575for(it;it!= status.end();it++){576 stringstream ss;577 ss << *it;578 ss >> tempStr;579 str+=tempStr;580 }581return str;586for(it ; it != sign.end() ;it++){587 buf += *it;588 count++;589 }590 }591592593string str(buf);594return str;595 }596597598599void Input_Analyse(){//输⼊句⼦,开始分析600601 vector<int> status;//定义状态栈602 vector<string> sign;//定义符号栈603604int step = 1; //步骤605string input;606 cout<<"请输⼊分析的字符串(请以#结尾):";607 cin>>input;//输⼊待分析的句⼦608 input = input+"#";609610 status.push_back(0);//把状态0⼊栈611//把#加⼊符号栈612 sign.push_back("#");613//输出初始栈状态614 cout<<setw(10)<<"步骤"<<setw(10)<<"状态栈"<<setw(10)<<"符号栈"<<setw(10)<<"输⼊串"<<setw(25)<<"动作说明"<<endl;615616int s =0;//初始状态617618int oldStatus;//保存之前的状态619620621string input_s; //获取初始符号622 input_s = input.substr(0,1);623624while(ACTION[s][input_s] != "acc"){//如果action[s][input_s] =="acc" ,则分析成功625//获取字符串626string str = ACTION[s][input_s];627//如果str为空,报错并返回628if(str.size() == 0){629 cout<<"出错";630return ;631 }632//获取S或r后⾯的数字633 stringstream ss;634 ss << str.substr(1);635 ss >> s;//新的状态号636//如果是移进637if(str.substr(0,1) == "S"){638 cout<<setw(10)<<step<<setw(10)<<vectTrancStr(0,status,sign)<<setw(10)<<vectTrancStr(1,status,sign)<<setw(10)<<input<<setw(10)<<"A"<<"CTION["<<status.back()<<","<<input_s<<"]=S"<<s<<","<<"状态"<<s<< 639 sign.push_back(input_s); //输⼊符号⼊栈640 input.erase(0,1);641 status.push_back(s);//将状态数字⼊栈642 }643//如果是规约644else if(str.substr(0,1) == "r"){645string kaitou;//产⽣式的头部646 kaitou = css[s].start;647int pop_num = css[s].next.size();//获取符号栈的出栈次数648649string r;650 stringstream ss;651 ss << s;652 ss >> r;653int oldStatus;//保存之前的状态654int status_size = status.size();655 oldStatus = status[status_size-1-pop_num];656 s=GOTO[oldStatus][kaitou];657 cout<<setw(10)<<step<<setw(10)<<vectTrancStr(0,status,sign)<<setw(10)<<vectTrancStr(1,status,sign)<<setw(10)<<input<<setw(10)<<(string)":产⽣式"+r+(string)"归约,GOTO("<<oldStatus<<","<<kaitou<<")="<<s<< 658//对符号栈进⾏出栈和状态栈进⾏出栈659while(pop_num--){660 sign.pop_back();661 status.pop_back();662 }663664 sign.push_back(kaitou);//再对产⽣式的开始符号⼊栈665 status.push_back(s);//再把新的状态⼊栈666 }667else{668//nothing669 }670671 step++; //步骤数加1672673 s = status.back();//获取栈顶状态674675 input_s = input.substr(0,1);//获取输⼊的字符676 }677 cout<<setw(10)<<step<<setw(10)<<vectTrancStr(0,status,sign)<<setw(10)<<vectTrancStr(1,status,sign)<<setw(10)<<input<<setw(10)<<"A"<<"cc:分析成功"<<endl;678679680 }681int main(){682 input();//输⼊⼆型⽂法683 GetFirst_and_Follow();//求First和Follow集合684 LR1_Analyse();685 print_ACTION_GOTO();//打印ACTION GOTO表686 Input_Analyse();//输⼊句⼦,开始分析687 }LR1.cpp代码的输⼊写的⽐较草率,可以⾃⾏修改⼀下,只要保存到相应的数据结构中,就不影响后⾯的LR1分析。
编译原理-LR(1)算法源代码
一.实验目的1.掌握LR(1)分析法的基本原理2.掌握LR(1)分析表的构造方法3.掌握LR(1)驱动程序的构造方法二.实验内容及要求构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
根据某一文法编制调试LR(1)分析程序,以便对任意输入的符号串进行分析。
本次实验的目的主要是加深对LR(1)分析法的理解。
程序输入/输出示例:对下列文法,用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)输出过程如下:步骤状态栈符号栈剩余输入串动作1 0 # i+i*i# 移进(或者为合法符号串)备注:(1)在“所用产生式”一列中如果对应有推导则写出所用产生式;如果为匹配终结符则写明匹配的终结符;如分析异常出错则写为“分析出错”;若成功结束则写为“分析成功”。
注意:1.表达式中允许使用运算符(+-*/)、分割符(括号)、字符i,结束符#;2.如果遇到错误的表达式,应输出错误提示信息(该信息越详细越好);3.对学有余力的同学,测试用的表达式事先放在文本文件中,一行存放一个表达式,同时以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;4.可采用的其它的文法。
三.实验过程1、使用LR(1)的优点:(1)LR分析器能够构造来识别所有能用上下文无关文法写的程序设计语言的结构。
(2)LR分析方法是已知的最一般的无回溯移进-归约方法,它能够和其他移进-归约方法一样有效地实现。
(3)LR方法能分析的文法类是预测分析法能分析的文法类的真超集。
(4)LR分析器能及时察觉语法错误,快到自左向右扫描输入的最大可能。
编译原理LR语法分析器控制程序实验报告范文word编辑版词法分析器c语言
编译原理LR语法分析器控制程序实验报告范文word编辑版词法分析器c语言学号姓名时间专业班级实验题目:LR语法分析器的控制程序实验目的:手工模拟控制程序计算,对源程序进行LR语法分析主要是分析表的构造实验内容与步骤:将要进行LR语法分析的源程序和LR语法分析器控制程序放在同一文件夹中。
用C语言编写LR语法分析器控制程序,程序代码如下:#include<ftream.h>#include<iotream.h>#include<tdlib.h>#include<tring.h>tructcode_val{charcode;charval[20];};contchar某p[]={//产生式"S→E","E→E+T","E→T","T→T某F","T→F","F→(E)","F→i"};contcharTNT[]="+某()i#ETF";//LR分析表列的字符contintM[][9]={//LR分析表数字化,列字符+某()i#ETF用数字012345678标识。
{0,0,4,0,5,0,1,2,3},//0表示出错,4用4表示。
{6,0,0,0,0,99},//Acc用99表示{-2,7,0,-2,0,-2},//r2用-2表示{-4,-4,0,-4,0,-4},{0,0,4,0,5,0,8,2,3},{-6,-6,0,-6,0,-6},{0,0,4,0,5,0,0,9,3},{0,0,4,0,5,0,0,0,10},{6,0,0,11},{-1,7,0,-1,0,-1},{-3,-3,0,-3,0,-3},{-5,-5,0,-5,0,-5}};intcol(char);//列定位函数原型voidmain(){inttate[50]={0};//状态栈初值charymbol[50]={'#'};//符号栈初值inttop=0;//栈顶指针初值oftreamcout("par_r.t某t");//语法分析结果输出至文件par_r.t某tiftreamcin("le某_r.t某t");//le某_r.t某t存放词法分析结果,语法分析器从该文件输入数据。
C语言编写源程序建立LR(1)分析器
目录前言 (2)用C语言编写源程序建立LR(1)分析器 (3)一, 设计目的, 要求, 算法与设计思想 (2)1.设计内容 (3)2.设计要求 (3)3.设计的基本原理 (3)1.CLOSURE(I)的构造 (3)2.GO(I,X)的构造 (3)3.FIRST集合的构造 (4)4.LR(1)分析表的构造 (4)二, LR(1)分析器 (4)1.LR(1)分析器的实现图: (4)2.LR分析器与逻辑结构及工作过程 (5)三, 总体方案设计 (5)1.各模块设计 (6)四, 程序测试 (7)1.教科书的第142页文法的LR1分析器的构造和语法分析 (8)2.表达式文法的LR1分析器的构造和语法分析器 (9)五, 源程序 (10)六, 总结 (19)七, 参考文献 19前言《编译原理》是计算机专业的一门重要的专业课程, 其中包含大量软件设计细想。
通过课程设计, 实现一些重要的算法, 或设计一个完整的编译程序模型, 能够进一步加深理解和掌握所学知识, 对提高自己的软件设计水平具有十分重要的意义。
我选的是老师给的题, 并予以扩充。
即对任意给定的问法G构造LR(1)项目集规范族, 其中要实现CLOSURE(1), GO(I,X), FIRST集合符。
在此基础上, 构造了LR(1)分析表。
然后对输入的句子进行语法分析, 给出接受或出错报告。
程序采用文件输入输出方式。
其中包括两个输入文件: 文法grammar.txt, 以及输入串input.txt;两个输出文件:项目集items.txt和文法的LR(1)分析表action_table.txt。
由于语法分析的结果只给出接受或错误报告, 比较简单。
所以直接在屏幕上输出, 也便于用户查看。
在具体编写程序中, 对文法操作的各个功能模块独立成为一个子程序, 而对具体输入穿得分析则放在main()函数中进行。
各个变量奇函数的意义和用法我将在论述程序设计的通体方案中向西给出。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录前言 (2)用C语言编写源程序建立LR(1)分析器 (3)一,设计目的,要求,算法与设计思想 (3)1.设计内容 (3)2.设计要求 (3)3.设计的基本原理 (3)1.CLOSURE(I)的构造 (3)2.GO(I,X)的构造 (3)3.FIRST集合的构造 (4)4.LR(1)分析表的构造 (4)二,LR(1)分析器 (4)1.LR(1)分析器的实现图: (4)2.LR分析器与逻辑结构及工作过程 (5)三,总体方案设计 (5)1. 各模块设计 (6)四,程序测试 (8)1.教科书的第142页文法的LR1分析器的构造和语法分析 (8)2.表达式文法的LR1分析器的构造和语法分析器 (9)五,源程序 (10)六,总结 (19)七,参考文献 (19)前言《编译原理》是计算机专业的一门重要的专业课程,其中包含大量软件设计细想。
通过课程设计,实现一些重要的算法,或设计一个完整的编译程序模型,能够进一步加深理解和掌握所学知识,对提高自己的软件设计水平具有十分重要的意义。
我选的是老师给的题,并予以扩充。
即对任意给定的问法G构造LR(1)项目集规范族,其中要实现CLOSURE(1),GO(I,X),FIRST集合符。
在此基础上,构造了LR(1)分析表。
然后对输入的句子进行语法分析,给出接受或出错报告。
程序采用文件输入输出方式。
其中包括两个输入文件:文法grammar.txt,以及输入串input.txt;两个输出文件:项目集items.txt和文法的LR(1)分析表action_table.txt。
由于语法分析的结果只给出接受或错误报告,比较简单。
所以直接在屏幕上输出,也便于用户查看。
在具体编写程序中,对文法操作的各个功能模块独立成为一个子程序,而对具体输入穿得分析则放在main()函数中进行。
各个变量奇函数的意义和用法我将在论述程序设计的通体方案中向西给出。
程序的通体算法细想来自《编译原理》课程。
具体实现有我独立完成。
程序用C/C++语言编写。
在Microsoft Visual C++2005环境下调使通过。
用C语言编写源程序建立LR(1)分析器一,设计目的,要求,算法与设计思想1.设计内容对任意给定的上下文无关文法G,构造其LR(1)项目集族,并且在此基础上进一步构造其LR(1)分析表。
然后分析输入的句子。
2.设计要求对输入的文法G(要求是上下文无关文法),在程序终实现CLOSURE(1),GO(I,X),FRIST等的构造,并利用这些功能函数构造出LR(1)项目集族。
并且输出结果。
在此基础上构造G的LR(1)分析表(这个表也输出给用户),并对输入的句子进行语法分析表,给出分析结果。
3.设计的基本原理1.CLOSURE(I)的构造CLOSURE(I)表示和I中项目可以识别同样活前缀的所有项目的集合。
它可以有以下方法得到:(1)I中的所有项目都属于CLOSURE(I);(2)若项目[A→a.Bβ,a]属于CLOSURE(I),B→ξ是一个产生式,那么,对于FIRST<βa>中的每一个中介符b,如果[β→.ξ,b]原来不在CLOSURE(I)中,则把它加进去;(3)重复执行步骤(2),直到CLOSURE(I)不再增大为止。
2.GO(I,X)的构造GO(I,X)=CLOSURE(J)其中J={任何形如[A→aX.Β,a]的项目[A→a.X.Β,a]属于I}3.FIRST集合的构造在这个程序中使用的是FIRST(βa),这基于每一个非终结符的FRIST集合(终结符的FIRST就是它本身)。
所以需要对每一个非终结符构造其FIRST集合。
方法如下:连续使用下面的规则,直到每个集合FIRST不再增大为止。
(1)若X属于V T,则FIRST(X)={X}。
(2)若X属于V N,且有产生式X→a…,则把A加入到FIRST(X)中;若X→ξ也是一条产生式,则把ξ也加入到FIRST中。
4.LR(1)分析表的构造在实现GO(I,X)时,记录下状态的转化。
得到分析表中的移进部分。
然后再扫描所有的项目集,找到其中包含归约项目的哪些项目集,根据其中项目,得到分析表中那些鬼月的部分。
二,LR(1)分析器1.LR(1)分析器的实现图:图1 LR(1)分析器的实现2.LR分析器与逻辑结构及工作过程图2 LR分析器的逻辑结构三,总体方案设计在main()函数中读入文件,并堆文法进行扩展,同时记录下文法的所有终结符和非终结符,对每个非终结符计算它的FIRST集合。
以备在计算CLOSURE(1)时使用。
然后调用GO()函数。
完成LR(1)项目集组的计算。
计算的结果记录到ITEMS.TXT中。
并且记录下状态之间转换关系。
接下来,调用GET_ACTION()根据上面的项目集族和记录的状态转换数组获得LR(1)分析表。
然后就可以对输入的句子进行语法检查。
程序中主要变量以及函数的说明如下:char str_vn[20][20]; // 存放输入的文法:为简单起见,设问发的产生式条数不多于20条,每个产生式不多与20个字符,用@表示,且产生式输入的时候要以S结束。
int length [20]; // 每条产生式的长度int number=0; // 产生式的条数bool tempofinput //记录哪些ASCII字符在文法中,以求得所有的V T和V N char str_vn[20]; //记录所有的非终结符int size_vn=0; //记录非终结符的个数char str_vt[150]; //记录所有的终结符int size_vt=0; //记录终结符的个数bool first_vn[30][150]; //记录每个非终结符的FIRST集char buffer[50]; //用来存放CLOSURE(I)时需要的FIRST_SET也用来读入用户的输入电int bsize=0 // buffer的有效长度struct thri{int beg;int nex;char ch;};thri trans[200]; //定义状态转换组中的元素格式int size-trans=0; //用来在go()函数中记录状态间的转换trans数组的大小struct proj{int part;char expc;}; //定义项目集的格式proj irems[100][100]; //项目集数组,假设项目集的个数不超过100个,且每个项目集中的项目个数不超过100个int CCOUNT=0; //项目集的个数int size_item[100]; //每个项目集中的项目个数struct action{char ch; //定义状态转换表的格式int nxt_sta;}; //定义状态转换表的格式action action_table[100][100]; //状态转换表int size_act_table[100]; // 输入文法的文件指针ifstream G_ifile; // 输入句子的文件指针ofstream input_ifile; // 输出项目集族的文件指针ofstream items_ofile; // 输出转换表的文件指针void read_G() // 计算每个非终结符的FIRST集合void get_first() // 判断项目temp是否已经在项目集族items[T]中bool is_in(proj temp,int,T) // 计算item[T]closure(1)时用到的frst(βa)void e_closure(intT) // 计算items[T]的closure闭包int is_containd() //判断新生成的项目集是否已经de 在项目集族中void go() //实现go(1)的功能void get_action() //生成LR(1)表int main() // 调用个个子模块,并在其中堆输入串进行语法分析1.各模块设计1.读入模块:Read_G()文法要为上下无关文法。
输入文件的格式为:首先输入产生式的条数:每条产生式的第一个字符为非终结符。
以S结尾。
输入的同时用tempofinput[temp]=true来记录符temp。
为统计有哪些非终结符和终结符作准备。
这些都通过ASCLL码对应位是否为true来判断。
2.计算FIRST模块:get_first()现设计FLAG1表示本轮扫描first_vn中有没有新增加的内容。
要是有,还有进行下一次扫描。
每一轮扫描所有的产生式,在扫描每一个产生式的时候,设置一个下标指针t用来保证不会扫过本产生式,还设置flag表示t的位置是否式一个可以推导出ξ的非终结符。
是的话,还有进行下一个t位置的检查。
如果t走到产生式的最后位置的下一个位置,则表明ξ属于此产生式左边非终结符的first集合。
3.判断项目数是否在项目集里:is_in(proj temp,int T)Scan项目集原有的每一个项目,和新生成的项目作比较。
若有相同的就返回true,否则返回false。
4.获得计算closure(I)时需要的First(βa):gete_expc(proj temp)设计Flag表示是否还要进行下一轮计算,若处理的位置已经查过了产生式的长度,则直接把项目中的那个搜索字符添加进去。
这个模块的返回结果放在BUFFER数据中。
5.项目集的CCLUSER计算:e_closure(int T)在GO()函数中会产生items[T]的一些基本项目。
对items[T]中已经有的每一个项目检查在“。
”之后的是否为非终结符;若是,则计算FIRST(a),把每一个BUFFER中的元素和相应的产生式构成一个项目,加入到项目集中。
(注意,此时的项目记得大小时随着项目的不断加入而变大的,所以可以用FOR循环保证项目集中不会有错误。
6.检查项目集是否已经在项目族里:is_contation()把已经有的项目集和新生成的项目集进行比较,要是有相等的话则表示已经存在相同的项目集合,此时返回相同的那个项目集的编号,否则,返回0.四,程序测试。
7.GO()函数地实现:第一步制作一个初始项目(即扩展文法的第一条产生式),然后用e_closure 构造项目集0.在程序中Ccount制作项目集的计数从0开始到(包括n),所以在for循环中是。
即扫描每一个项目集,对每一个项目在“.”之后的终结符,向后移动一位“.”的位置生成新的项目,暂存在buf数组中。
然后预生成项目集,并且求其closure,再判断新的项目集是否已经存在,若存在了,就删除这个项目集,并设置相应的trans。
否则就生成的项目集,也设置相应的trans。
在以上过程中,每次确定生成一个项目集的时候都把它输出到items.txt中。