语法分析代码
语法分析程序的设计与实现
◆词法分析 用户必须提供一个词法分析器来读取输入流并把记号(带有值, 如果需要的话)传达到解析器。词法分析器使叫做 yylex 的整数值的 函数。这个函数返回一个整数的记号编号,它表示读取的记号的种类。 如果这个记号关联着一个值,应当把它赋予外部变量 yylval。 为使通信得以发生,解析器和词法分析器必须在记号编号上达成 一致。编号可以由 Yacc 或用户来选择。在这两种情况下,使用 C 语 言的“# define”机制允许词法分析器使用符号来返回这些编号。例如, 假定在 Yacc 规定文件的声明段中已经定义记号名字 DIGIT。 它的意图是返回一个 DIGIT 记号编号,和等于这个数字的数值 的一个值。倘若词法分析器代码位于规定文件的程序段,标识符 DIGIT 将被定义为与记号 DIGIT 关联的记号编号。 这种机制导致清晰的、易于修改的词法分析器;唯一的缺点是在 文法中需要避免使用任何在 C 语言或解析器中保留的或有意义的记 号名字;例如,使用记号名字 if 或 while 就一定会导致编译词法分 析器时出现严峻的困难。记号名字 error 保留给错误处理,不应该随 便使用。 同上所述,记号编号可以由 Yacc 或用户来选择。在缺省的条件 下,编号由 Yacc 选择。文字字符的缺省记号编号是它在本地字符集 中的字符数值。其他名字赋予从 257 开始的记号编号。 要把一个记号编号赋予一个记号(包括文字),可以在声明段中记 号或文字的第一次出现时直接跟随着一个非负整数。这个整数被接受
第四:YACC 内部名称: ................................................................................................ 7 第五:运行结果(源代码见附录).............................................................................. 8 第六:实验总结 ............................................................................................................... 8 第七:附录 ..................................................................................................................... 10
如何进行代码的静态分析
如何进行代码的静态分析代码的静态分析是指在不实际运行代码的情况下对代码进行全面的检查和分析。
静态分析可以帮助开发人员发现潜在的代码问题并改进代码质量,同时也可以帮助团队更好地理解代码和进行代码评审。
在本文中,我们将探讨代码的静态分析的原理、方法和工具,并讨论如何有效地进行静态分析以提高代码质量和开发效率。
一、静态分析的原理静态分析是在不进行代码执行的情况下对源代码进行分析和检查,这意味着分析是基于代码的结构、语法和语义进行的。
静态分析的原理主要包括以下几个方面:1.语法分析:静态分析首先要对代码进行语法分析,检查代码是否符合语法规范。
语法分析通常是通过词法分析和语法分析器来实现的,词法分析负责将源代码分解为一个个的词法单元,而语法分析器则负责根据语法规则进行语法分析,以确保代码的结构是正确的。
2.数据流分析:数据流分析是静态分析的核心内容之一,它用来分析代码中的数据流和控制流,以发现潜在的错误和问题。
数据流分析可以帮助开发人员找到未初始化变量、内存泄漏、空指针引用等问题,并帮助发现代码中可能的逻辑错误和安全漏洞。
3.符号执行:符号执行是一种将代码用符号代替具体数值进行分析的技术,它可以帮助开发人员发现代码中可能的边界条件错误和逻辑错误。
符号执行会将代码中的变量和条件用符号代替,然后进行逻辑分析和验证,从而发现可能的错误和问题。
4.控制流分析:控制流分析可以帮助开发人员理解代码的执行顺序和流程,发现代码中的循环和递归等问题。
控制流分析通常包括对代码的控制结构、条件分支、循环和递归等进行分析,以发现可能的逻辑错误和问题。
二、静态分析的方法静态分析包括多种方法和技术,主要包括以下几种:1.代码审查:代码审查是一种通过人工检查和评审代码来进行静态分析的方法,这是一种最直接和有效的方法。
代码审查可以帮助发现潜在的问题和错误,同时也可以帮助团队更好地理解和沟通代码。
2.静态代码分析工具:静态代码分析工具是一种通过自动分析代码来发现潜在问题和错误的方法,主要包括静态分析器、代码检查工具和静态分析插件等。
LR语法分析器的实现代码(python)
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插入栈中,并进行归约。
编译原理实验词法分析语法分析
本代码只供学习参考:词法分析源代码:#include<iostream>#include<fstream>#include<string>using namespace std;string key[8]={"do","end","for","if","printf","scanf","then","while"}; string optr[4]={"+","-","*","/"};string separator[6]={",",";","{","}","(",")"};char ch;//判断是否为保留字bool IsKey(string ss) {int i;for(i=0;i<8;i++)if(!strcmp(key[i].c_str(),ss.c_str()))return true;return false;}//字母判断函数bool IsLetter(char c) {if(((c>='a')&&(c<='z'))||((c>='A')&&(c<='Z')))return true;return false;}//数字判断函数bool IsDigit(char c) {if(c>='0'&&c<='9')return true;return false;}//运算符判断函数bool IsOptr(string ss) {int i;for(i=0;i<4;i++)if(!strcmp(optr[i].c_str(),ss.c_str()))return true ;return false;}//分界符判断函数bool IsSeparator(string ss) {int i;for(i=0;i<6;i++)if(!strcmp(separator[i].c_str(),ss.c_str()))return true;return false;}void analyse(ifstream &in) {string st="";char ch;int line=1,row=0;while((in.get(ch))) {st="";if((ch==' ')||(ch=='\t')){} //空格,tab健elseif(ch=='\n') {line++;row=0; } //换行行数加一处理elseif(IsLetter(ch)) //关键字、标识符的处理{row++;while(IsLetter(ch)||IsDigit(ch)){st+=ch;in.get(ch);}in.seekg(-1,ios::cur);//文件指针(光标)后退一个字节if(IsKey(st)) //判断是否为关键字查询关键字表;cout<<st<<"\t("<<st<<","<<1<<")"<<'\t'<<'\t'<<"关键字"<<'\t'<<"("<<line<<","<<row<<")"<<endl;else //否则为标示符cout<<st<<"\t("<<st<<","<<2<<")"<<'\t'<<'\t'<<"标识符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;}elseif(IsDigit(ch)) //无符号整数处理{row++;while(IsDigit(ch)){st+=ch;ch=in.get();}in.seekg(-1,ios::cur);cout<<st<<"\t("<<st<<","<<3<<")"<<'\t'<<'\t'<<"常数"<<'\t'<<"("<<line<<","<<row<<")"<<endl;// break;}else{st="";st+=ch;if(IsOptr(st)) //运算符处理{row++;cout<<st<<"\t("<<st<<","<<4<<")"<<'\t'<<'\t'<<"运算符"<<"("<<line<<","<<row<<")"<<endl;}elseif(IsSeparator(st))//分隔符处理{ row++;cout<<st<<"\t("<<st<<","<<5<<")"<<'\t'<<'\t'<<"分界符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;}else{switch(ch){row++;case'=' : {row++;cout<<"="<<"\t("<<"="<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;}case'>' :{row++;ch=in.get();if(ch=='=')cout<<">="<<'\t'<<"("<<">="<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;else {cout<<">"<<"\t("<<">"<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;in.seekg(-1,ios::cur);}} break;case'<' :{row++;ch=in.get();if(ch=='=')cout<<"<="<<'\t'<<"("<<"="<<","<<"6"<<")"<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;else if(ch=='>') cout<<"<>"<<'\t'<<"("<<"<>"<<","<<"6"<<")"<<'\t'<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;else{cout<<"<"<<"\t("<<"<"<<","<<"6"<<")"<<"\t"<<"\t关系运算符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;in.seekg(-1,ios::cur);}}break;default :{row++; cout<<ch<<'\t'<<"\t$无法识别字符"<<'\t'<<"("<<line<<","<<row<<")"<<endl;}}}}}}int main(){ifstream in;in.open("test.txt",ios::in);cout<<"关键字-》1 标识符-》2 常数-》3 运算符-》4 分隔符-》5"<<endl;if(in.is_open()){analyse(in);in.close();system("pause");}elsecout<<"文件操作出错"<<endl;}语法分析实验源代码LL#include<iostream>using namespace std;const int MaxLen=20; //初始化栈的长度const int Length=20;//初始化数组长度char Vn[5]={'E','G','T','S','F'};//非终结符数组char Vt[8]={'i','(',')','+','-','*','/','#'};//终结符数组char ch,X;//ch读当前字符,X获取栈顶元素char strToken[Length];//存储规约表达式struct LL//ll(1)分析表的构造字初始化{char*c;};LL E[8]={"TG","TG","error","error","error","error","error","error"};LL G[8]={"error","error","null","+TG","-TG","error","error","null"};LL T[8]={"FS","FS","error","error","error","error","error","error"};LL S[8]={"error","error","null","null","null","*FS","/FS","null"};LL F[8]={"i","(E)","error","error","error","error","error","error"};class stack//栈的构造及初始化{public:stack();//初始化bool empty() const;//是否为空bool full() const;//是否已满bool get_top(char &c)const;//取栈顶元素bool push(const char c);//入栈bool pop();//删除栈顶元素void out();//输出栈中元素~stack(){}//析构private:int count;//栈长度char data[MaxLen];//栈中元素};stack::stack(){count=0;}bool stack::empty() const{if(count==0)return true;return false;}bool stack::full() const{if(count==MaxLen)return true;return false;}bool stack::get_top(char &c)const{if(empty())return false;else{c=data[count-1];return true;}}bool stack::push(const char c){if(full())return false;data[count++]=c;return true;}bool stack::pop(){if(empty())return false;count--;return true;}void stack::out(){for(int i=0;i<count;i++)cout<<data[i];cout<<'\t';}int length(char *c){int l=0;for(int i=0;c[i]!='\0';i++)l++;return l;}void print(int i,char*c)//剩余输入串的输出{for(int j=i;j<Length;j++)cout<<c[j];cout<<'\t';}void run(){bool flag=true;//循环条件int step=0,point=0;//步骤、指针int len;//长度cout<<"输入规约的字符串:"<<endl;cin>>strToken;ch=strToken[point++];//读取第一个字符stack s;s.push('#');//栈中数据初始化s.push('E');s.get_top(X);//取栈顶元素cout<<"步骤\t"<<"分析栈\t"<<"剩余输入串\t\t"<<"所用产生式\t"<<"动作"<<endl;cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<'\t'<<"初始化"<<endl;while(flag){if((X==Vt[0])||(X==Vt[1])||(X==Vt[2])||(X==Vt[3])||(X==Vt[4])||(X==Vt[5])||(X==Vt[6])) //判断是否为终结符(不包括#){if(X==ch)//终结符,识别,进行下一字符规约{s.pop();s.get_top(X);ch=strToken[point++];cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<'\t'<<"GETNEXT(I)"<<endl;}else{flag=false;}}else if(X=='#')//规约结束{if(X==ch){cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<ch<<'\t'<<"结束"<<endl;s.pop();flag=false;}else{flag=false;}}else if(X==Vn[0]) //非终结符E{for(int i=0;i<8;i++)//查分析表if(ch==Vt[i]){if(strcmp(E[i].c,"error")==0)//出错{flag=false;}else{ //对形如X->X1X2的产生式进行入栈操作s.pop();len=length(E[i].c)-1;for(int j=len;j>=0;j--)s.push(E[i].c[j]);cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<E[i].c<<'\t'<<"POP,PUSH(";for(int j=len;j>=0;j--)cout<<E[i].c[j];cout<<")"<<endl;s.get_top(X);}}}else if(X==Vn[1]) //同上,处理G{for(int i=0;i<8;i++)if(ch==Vt[i]){if(strcmp(G[i].c,"null")==0){s.pop();cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<"ε"<<'\t'<<"POP"<<endl;s.get_top(X);}else if(strcmp(G[i].c,"error")==0){flag=false;}else{s.pop();len=length(G[i].c)-1;for(int j=len;j>=0;j--)s.push(G[i].c[j]);cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<G[i].c<<'\t'<<"POP,PUSH(";for(int j=len;j>=0;j--)cout<<G[i].c[j];cout<<")"<<endl;s.get_top(X);}}}else if(X==Vn[2]) //同上处理T{for(int i=0;i<8;i++)if(ch==Vt[i]){if(strcmp(T[i].c,"error")==0){flag=false;}else{s.pop();len=length(T[i].c)-1;for(int j=len;j>=0;j--)s.push(T[i].c[j]);cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<T[i].c<<'\t'<<"POP,PUSH(";for(int j=len;j>=0;j--)cout<<T[i].c[j];cout<<")"<<endl;s.get_top(X);}}}else if(X==Vn[3])//同上处理S{for(int i=0;i<8;i++)if(ch==Vt[i]){if(strcmp(S[i].c,"null")==0){s.pop();cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<"ε"<<'\t'<<"POP"<<endl;s.get_top(X);}else if(strcmp(S[i].c,"error")==0){flag=false;}else{s.pop();len=length(S[i].c)-1;for(int j=len;j>=0;j--)s.push(S[i].c[j]);cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<S[i].c<<'\t'<<"POP,PUSH(";for(int j=len;j>=0;j--)cout<<S[i].c[j];cout<<")"<<endl;s.get_top(X);}}}else if(X==Vn[4]) //同上处理F{for(int i=0;i<7;i++)if(ch==Vt[i]){if(strcmp(F[i].c,"error")==0){flag=false;}else{s.pop();len=length(F[i].c)-1;for(int j=len;j>=0;j--)s.push(F[i].c[j]);cout<<step++<<'\t';s.out();print(point-1,strToken);cout<<X<<"->"<<F[i].c<<'\t'<<"POP,PUSH(";for(int j=len;j>=0;j--)cout<<F[i].c[j];cout<<")"<<endl;s.get_top(X);}}}else //出错处理{flag= false;}}}int main(){cout<<"实验二"<<endl;run();system("pause");return 0;}语法实验源代码LR#include<iostream>using namespace std;const int MaxLen=20; //初始化栈的长度const int Length=20;//初始化数组长度char ch,Y;//全局变量,ch用于读当前字符,Y用于获取栈顶元素char strToken[Length];//存储规约表达式bool flag=true;//循环条件int point=0,step=1;//步骤、指针class stack//栈的构造及初始化{public:stack();//初始化bool empty() const;//是否为空bool full() const;//是否已满bool get_top(char &c)const;//取栈顶元素bool push(const char c);//入栈bool pop();void out();//输出栈中元素void out1();~stack(){}//析构private:int count;//栈长度char data[MaxLen];//栈中元素};stack l,r;//l代表符号栈,r代表状态栈stack::stack(){count=0;}bool stack::empty() const{if(count==0)return true;return false;}bool stack::full() const{if(count==MaxLen)return true;return false;}bool stack::get_top(char &c)const{if(empty())return false;else{c=data[count-1];return true;}}bool stack::push(const char c){if(full())return false;data[count++]=c;return true;}bool stack::pop(){if(empty())return false;count--;return true;}void stack::out(){for(int i=0;i<count;i++)cout<<data[i];cout<<'\t';}void stack::out1(){for(int i=0;i<count;i++)cout<<int(data[i]);cout<<'\t';}void print(int i,char*c)//剩余输入串的输出{for(int j=i;j<Length;j++)cout<<c[j];cout<<'\t';}void Goto(int i,char c)//状态转换函数,对应于表中GOTO {if(i==0){if(c=='E'){r.push(1);cout<<",GOTO(0,E)=1入栈"<<endl;}else if(c=='T'){r.push(2);cout<<",GOTO(0,T)=2入栈"<<endl;}else if(c=='F'){r.push(3);cout<<",GOTO(0,F)=3入栈"<<endl;}elseflag=false;}else if(i==4){if(c=='E'){r.push(8);cout<<",GOTO(4,E)=8入栈"<<endl;}else if(c=='T'){r.push(2);cout<<",GOTO(4,T)=2入栈"<<endl;}else if(c=='F'){r.push(3);cout<<",GOTO(4,F)=3入栈"<<endl;}elseflag=false;}else if(i==6){if(c=='T'){r.push(9);cout<<",GOTO(6,T)=9入栈"<<endl;}else if(c=='F'){r.push(3);cout<<",GOTO(6,F)=3入栈"<<endl;}elseflag=false;}else if(i==7){if(c=='F'){r.push(10);cout<<",GOTO(7,F)=10入栈"<<endl;}elseflag=false;}elseflag=false;}void Action0()//状态0时{if(ch=='i')//下一个操作符为i ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[0,i]=S5,状态5入栈"<<endl;r.push(5);l.push(ch);ch=strToken[point++];}else if(ch=='(')//下一个操作符为( ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[0,(]=S4,状态4入栈"<<endl;r.push(4);l.push(ch);ch=strToken[point++];}elseflag=false;}void Action1()//状态1{if(ch=='+')//下一个操作符为i ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[1,+]=S6,状态6入栈"<<endl;r.push(6);l.push(ch);ch=strToken[point++];}else if(ch=='#')//分析成功{flag=false;cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"Acc:分析成功"<<endl;}elseflag=false;}void Action2() //状态2{if(ch=='*')//下一个操作符为* ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[2,*]=S7,状态7入栈"<<endl;r.push(7);l.push(ch);ch=strToken[point++];}else if((ch=='+')||(ch==')')||(ch=='#'))//下一个操作符为+,),#规约{cout<<step++<<'\t';r.out1();l.out();l.pop();l.push('E');print(point-1,strToken);cout<<"r2: E→T归约";r.pop();r.get_top(Y);Goto(int(Y),'E');}elseflag=false;}void Action3()//状态3{if((ch=='+')||(ch=='*')||(ch==')')||(ch=='#'))//下一个操作符为+,*,),#规约{cout<<step++<<'\t';r.out1();l.out();l.pop();l.push('T');print(point-1,strToken);cout<<"r4: T→F归约";r.pop();r.get_top(Y);Goto(int(Y),'T');}elseflag=false;}void Action4_6_7(int x)//状态4,6,7{if(ch=='i')//下一个操作符为i ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[";cout<<x<<",i]=S5,状态5入栈"<<endl;r.push(5);l.push(ch);ch=strToken[point++];}else if(ch=='(')//下一个操作符为(,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[";cout<<x<<",(]=S4,状态4入栈"<<endl;r.push(4);l.push(ch);ch=strToken[point++];}elseflag=false;}void Action5()//状态5{if((ch=='+')||(ch=='*')||(ch==')')||(ch=='#'))//下一个操作符为+,*,),#规约{cout<<step++<<'\t';r.out1();l.out();l.pop();l.push('F');print(point-1,strToken);cout<<"r6: F→i归约";r.pop();r.get_top(Y);Goto(int(Y),'F');}elseflag=false;}void Action8()//状态8{if(ch=='+')//下一个操作符为+ ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[8,+]=S6,状态6入栈"<<endl;r.push(6);l.push(ch);ch=strToken[point++];}else if(ch==')')//下一个操作符为),移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[8,)]=S11,状态11入栈"<<endl;r.push(11);ch=strToken[point++];}elseflag=false;}void Action9()//状态9{if(ch=='*')//下一个操作符为* ,移进{cout<<step++<<'\t';r.out1();l.out();print(point-1,strToken);cout<<"ACTION[9,*]=S7,状态7入栈"<<endl;r.push(7);l.push(ch);ch=strToken[point++];}else if((ch=='+')||(ch==')')||(ch=='#'))//下一个操作符为+,,),#规约{cout<<step++<<'\t';r.out1();l.out();l.pop();l.pop();l.pop();l.push('E');print(point-1,strToken);cout<<"r1: E→E+T归约";r.pop();r.pop();r.pop();r.get_top(Y);Goto(int(Y),'E');}elseflag=false;}void Action10()//状态10{if((ch=='+')||(ch=='*')||(ch==')')||(ch=='#'))//下一个操作符为+,*,),#规约{cout<<step++<<'\t';l.out();l.pop();l.pop();l.pop();l.push('T');print(point-1,strToken);cout<<"r3: T→T*F归约";r.pop();r.pop();r.pop();r.get_top(Y);Goto(int(Y),'T');}elseflag=false;}void Action11()//状态11{if((ch=='+')||(ch=='*')||(ch==')')||(ch=='#'))//下一个操作符为+,*,),#规约{cout<<step++<<'\t';r.out1();l.out();l.pop();l.pop();l.pop();l.push('F');print(point-1,strToken);cout<<"r5: F→(E)归约";r.pop();r.pop();r.pop();r.get_top(Y);Goto(int(Y),'F');}elseflag=false;}void run()//规约{cout<<"请输入要规约的字符串:"<<endl;cin>>strToken;cout<<"步骤\t"<<"状态栈\t"<<"符号栈\t"<<"输入串\t\t"<<"动作说明"<<endl;ch=strToken[point++];//读取第一个字符l.push('#');r.push(0);r.get_top(Y);while(flag)//循环规约{if(int(Y)==0)Action0();else if(int(Y)==1)Action1();else if(int(Y)==2)Action2();else if(int(Y)==3)Action3();else if((int(Y)==4)||(int(Y)==6)||(int(Y)==7))Action4_6_7(int(Y));else if(int(Y)==5)Action5();else if(int(Y)==8)Action8();else if(int(Y)==9)Action9();else if(int(Y)==10)Action10();else if(int(Y)==11)Action11();elseflag=false;r.get_top(Y);}}int main(){cout<<"实验三"<<endl;run();system("pause");return 0;}。
语法分析器源代码
语法分析程序的源代码#include<stdio.h>#include<string.h>char prog[80],token[6];char ch;int syn,p,m,n,sum,kk=0;char * rwtab[6]={"begin","if","then","while","do","end"};main(){p=0;printf("\nplease intput string:");do{ch=getchar();prog[p++]=ch;}while(ch!='#');p=0;scaner();lrparser();getch();}/*词法扫描程序:*/scaner(){for(n=0;n<8;n++)token[n]=NULL;m=0;ch=prog[p++];while(ch==' ')ch=prog[p++];if((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')){while((ch<='z'&&ch>='a')||(ch<='Z'&&ch>='A')||(ch<='9'&&ch>='0')) {token[m++]=ch;ch=prog[p++];}token[m++]='\0';ch=prog[--p];syn=10;for(n=0;n<6;n++)if(strcmp(token,rwtab[n])==0){syn=n+1;break;}}elseif((ch<='9'&&ch>='0')){sum=0;while((ch<='9'&&ch>='0')){sum=sum*10+ch-'0';ch=prog[p++];}ch=prog[--p];syn=11;}elseswitch(ch){case '<':m=0;token[m++]=ch;ch=prog[p++];if(ch=='>'){syn=21;token[m++]=ch;}elseif(ch=='='){syn=22;token[m++]=ch;}else{syn=20;ch=prog[--p];}break;case '>':token[m++]=ch;ch=prog[p++];if(ch=='='){syn=24;token[m++]=ch;}else{syn=23;ch=prog[--p];}break;case ':':token[m++]=ch;ch=prog[p++];if(ch=='='){syn=18;token[m++]=ch;}else{syn=17;ch=prog[--p];}break;case '+':syn=13;token[0]=ch;break;case '-':syn=14;token[0]=ch;break;case '*':syn=15;token[0]=ch;break;case '/':syn=16;token[0]=ch;break;case ':=':syn=18;token[0]=ch;break;case '<>':syn=21;token[0]=ch;break;case '<=':syn=22;token[0]=ch;break;case '>=':syn=24;token[0]=ch;break;case '=':syn=25;token[0]=ch;break;case ';':syn=26;token[0]=ch;break;case '(':syn=27;token[0]=ch;break;case ')':syn=28;token[0]=ch;break;case '#':syn=0;token[0]=ch;break;default:syn=-1;}}lrparser(){if(syn==1){scaner();if(syn==6){scaner();if((syn==0)&&(kk==0))printf("sucess");}else{if(kk!=1) printf("lost end error!");kk=1;}}else{printf("output of begin is error!");kk=1;}return;}yucu(){statement();while(syn==26){scaner();statement();}return;}statement(){if(syn==10){scaner();if(syn==18){scaner();expression();}{printf("output of equal is error!");kk=1;}}else{printf("input of sentence is error!");kk=1;}return;}expression(){term();while(syn==13||syn==14){scaner();term();}return;}term(){factor();while(syn==15||syn==16){scaner();factor();}return;}factor(){if(syn==10||syn==11)scaner();elseif(syn==27){scaner();expression();if(syn==28)scaner();else{printf("output ')' is error!");kk=1;}}else{printf("output expression is error!");kk=1;}return;}。
C语言编译原理词法分析和语法分析
C语言编译原理词法分析和语法分析编程语言的编写和使用离不开编译器的支持,而编译器的核心功能之一就是对代码进行词法分析和语法分析。
C语言作为一种常用的高级编程语言,也有着自己的词法分析和语法分析规则。
一、词法分析词法分析是编译器的第一阶段,也是将源代码拆分为一个个独立单词(token)的过程。
在C语言中,常见的单词包括关键字(如if、while等)、标识符(如变量名)、常量(如数字、字符常量)等。
词法分析器会根据预定义的规则对源代码进行扫描,并将扫描到的单词转化为对应的符号表示。
词法分析的过程可以通过有限自动机来实现,其中包括各种状态和状态转换规则。
词法分析器通常会使用正则表达式和有限自动机的方法来进行实现。
通过词法分析,源代码可以被分解为一个个符号,为后续的语法分析提供基础。
二、语法分析语法分析是编译器的第二阶段,也是将词法分析得到的单词序列转换为一棵具有语法结构的抽象语法树(AST)的过程。
在C语言中,语法分析器会根据C语言的文法规则,逐句解析源代码,并生成相应的语法树。
C语言的语法规则相对复杂,其中包括了各种语句、表达式、声明等。
语法分析的过程主要通过递归下降分析法、LR分析法等来实现。
语法分析器会根据文法规则建立语法树的分析过程,对每个语法结构进行逐步推导和分析,最终生成一棵完整的语法树。
三、编译器中的词法分析和语法分析在编译器中实现词法分析和语法分析是一项重要的技术任务。
编译器通常会将词法分析和语法分析整合在一起,形成一个完整的前端。
在C语言编译器中,词法分析和语法分析器会根据C语言的词法规则和文法规则,对源代码进行解析,并生成相应的中间表示形式,如语法树或者中间代码。
词法分析和语法分析的结果会成为后续编译器中各个阶段的输入,如语义分析、中间代码生成、目标代码生成等。
编译器的优化和错误处理也与词法分析和语法分析有密切关系。
因此,对词法分析和语法分析的理解和实现对于编译器开发者而言是非常重要的。
编译原理词法分析和语法分析报告+代码(C语言版)[1]
词法分析一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面:⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};图3-1(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。
编译原理词法分析和语法分析报告+代码(C语言版)[1]
词法分析一、实验目的二、设计、编制并调试一个词法分析程序, 加深对词法分析原理的理解。
三、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符: = + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM), 通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID.SUM、运算符、界符和关键字, 词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:输入: 所给文法的源程序字符串。
输出: 二元组(syn,token或sum)构成的序列。
其中: syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如: 对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件, 经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号, 其基本思想是根据扫描到单词符号的第一个字符的种类, 拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面:⑴关键字表的初值。
关键字作为特殊标识符处理, 把它们预先安排在一张表格中(称为关键字表), 当扫描程序识别出标识符时, 查关键字表。
如能查到匹配的单词, 则该单词为关键字, 否则为一般标识符。
关键字表为一个字符串数组, 其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};图3-1(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量: ①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn 用来存放单词符号的种别码。
编译程序的工作过程:词法分析、语法分析、语义分析、优化、目标代码生成
编译程序的⼯作过程:词法分析、语法分析、语义分析、优化、
⽬标代码⽣成
词法分析:也就是从左到右⼀个⼀个地读⼊源程序,识别⼀个单词或符号,并进⾏归类。
语法分析:在词法分析的基础上,将单词序列分解成各类语法短语,如“程序”语句“表达式”等
语义分析:审查源程序是否有语义的错误,当不符合语⾔规范的时候,程序就会报错。
代码优化:这个阶段是对前阶段的中间代码进⾏变换或改造,⽬的是使⽣成的⽬标代码更为⾼效,即节省时间和空间。
⽬标代码⽣成:也就是吧优化后的中间代码变换成指令代码或汇编代码。
【经典】LR(1)分析表语法分析报告
学生实验报告实验项目名称: LR(1)分析表语法分析实验学时: 6 同组学生姓名:无实验地点: B513 实验日期: 2011.4.7/4.21 实验成绩:批改教师:批改时间:一、实验目的和要求语法分析主要目的是按照程序语言的语法规则,从由词法分析输出的源程序符号串中识别出各类语法成分,同时进行语法检查,为语义分析和代码生成作准备.语法分析程序在分析过程中检查符号串是否为该程序的句子.若是则输出该句子的分析树,否则就表示源程序存在语法错误,并报告错误的性质与位置.二、实验仪器和设备主机一台:有Visual Studio 2005工具三、实验过程说明:此程序共有两个类,Lexical进行词法分析,Syntax进行语法分析.对于语法分析,采用LR(1)分析法,判断程序是否满足规定的结构.1:LR-table.txt:存放分析表,其中正数表示移进,负数表示归约,100表示接受状态,0表示不操作。
2:grammar.txt 存放文法开始符号3:lengh.txt 存放产生式右部字符长度4:inpur.txt 输入的程序语法规则:定义的文法,如下:(0)Z---→E(1)E---→E+T(2)E---->T(3)T---→T*F(4)T---→F(5)F---→{E}(6)F---→i根据上面文法画出的分层有限自动机并根据分层自动机构造的LR(1)分析表:语法分析的核心代码和注释如下:using System;using System.Text;using System.IO;namespace Syntax_Analyzer{class Syntax{StreamReader myStreamReader;int t;int[] lengh;int l =0;string[] grammar;int s=0;string[] Word;int w=0;int[] wordNum ;int n =0;int[,] LR;public Syntax(){lengh = new int[7];grammar=new string[7];Word=new string[100];wordNum = new int[100];LR=new int[30,30];}public void analyzer(){//读入grammarSyntax myTextRead=new Syntax();Console.WriteLine("-----------------------------语法分析开始---------------------------------\n");//***************************//循环读取文法//***************************string strStart;strStart="grammar.txt";myTextRead.myStreamReader=new StreamReader(strStart);string strBufferStart;int uu=0;do{strBufferStart =myTextRead.myStreamReader.ReadLine();if(strBufferStart==null)break;foreach (String subString in strBufferStart.Split()){grammar[uu]=subString; //每行文法存入grammar[]uu++;}}while (strBufferStart!=null);myTextRead.myStreamReader.Close();//***************************//循环读取lengh//***************************strStart="lengh.txt";myTextRead.myStreamReader=new StreamReader(strStart);uu=0;do{strBufferStart =myTextRead.myStreamReader.ReadLine();if(strBufferStart==null)break;foreach (String subString in strBufferStart.Split()){lengh[uu]=Convert.ToInt32(subString); //每行文法存入grammar[]uu++;}}while (strBufferStart!=null);myTextRead.myStreamReader.Close();//****************************// 读入文件,进行语法分析////****************************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("+")){wordNum[wid]=0;}else{if(subString.Equals("*")){wordNum[wid]=1;}else{if(subString.Equals("(")){wordNum[wid]=2;}else{if(subString.Equals(")")){wordNum[wid]=3;}else{if(subString.Equals("i")){wordNum[wid]=4;}}}}}Console.Write(subString+"("+wordNum[wid]+")"+" ");wid++;}}Console.WriteLine("\n");}while (strBufferText!=null);wordNum[wid]=5;myTextRead.myStreamReader.Close();//*********************************//读入LR分析表////***********************************string strLR;strLR="LR-table.txt";myTextRead.myStreamReader=new StreamReader(strLR);string strBufferLR;int pp=0;do{strBufferLR =myTextRead.myStreamReader.ReadLine();if(strBufferLR==null)break;else{int j=0;foreach (String subString in strBufferLR.Split()){if(subString!=null){int lllr=Convert.ToInt16(subString);LR[pp,j]=lllr; //把行与列读入数组j++;}}}pp++;}while (strBufferLR!=null);myTextRead.myStreamReader.Close();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为的时候if(t==0){//错误类型string error = "" ;if (k == 0)error = "+";elseif (k == 1)error = "*";elseif (k == 2)error = "(";elseif (k == 3)error = ")";elseif (k == 4)error = "i";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.WriteLine("-----------------------------语法分析结束---------------------------------\n");Console.Read();}}class Search{public int search(string x){string[] mysymbol=new string[3];mysymbol[0]="E";mysymbol[1]="T";mysymbol[2]="F";int r = 0;for(int s=0;s<=2;s++){if(mysymbol[s].Equals(x))r=s+6 ;}return r;}}}示例:1:输入”( i + i ) * i”字符串,分析如下图所示:2:输入” i + i ”字符串,分析如下图所示:四.实验结果与分析从这次语法分析实验中,我感到语法分析的过程要比之前的词法分析实验复杂的多,其中涉及到文法规则,自顶向下分析方法和许多编程的细节问题,有一处不正确,语法分析便不能成功。
编译原理中的语法分析与中间代码生成
编译原理中的语法分析与中间代码生成编译原理是计算机科学中一门非常重要的学科,主要研究将高级语言翻译成机器语言的方法和技术。
其中,语法分析和中间代码生成是编译器实现的两个重要步骤。
一、语法分析语法分析是编译器将源代码转换成抽象语法树的过程。
在这个阶段,编译器会检查源代码的语法是否符合语言规范,并将代码转化为一系列的语法结构。
一个好的语法分析器能够快速准确地识别代码中的语言结构,同时能够在出现语法错误的时候给出有意义的错误报告。
常见的语法分析方法包括LL(1)分析、LR分析等。
LL(1)分析器通过构造预测分析表来实现分析,而LR分析器则采用自底向上的分析方法,通过状态迁移来实现分析。
在语法分析的过程中,编译器还需要处理语法的优先级,如算术运算符的优先级,逻辑运算符的优先级等。
对于不同的语言规范,将有不同的算法来处理语法。
例如,C语言中的运算符优先级和结合性与其他语言不同,因此需要特殊的处理方式。
二、中间代码生成中间代码生成是语法分析后的下一步,它的作用是将抽象语法树转化为中间表示,通常是三地址码或四地址码。
中间代码可以看作是目标代码的前一步,它是一种更加抽象的代码形式,方便后续的优化和翻译。
中间代码的生成方法有很多种,最常用的是遍历抽象语法树并根据语法结构生成中间代码。
不同的语言规范会对中间代码的生成方式有不同的要求。
例如,Java语言规范对着重于类型检查和异常处理的中间代码生成,而C语言的中间代码生成则着重于指针和数组的处理等。
在生成中间代码的过程中,编译器还需要考虑优化问题。
编译器能够在生成中间代码的时候进行一些基本的优化,例如删除冗余代码、常量合并等等,这样可以减少目标代码的大小和程序的运行时间。
总之,语法分析和中间代码生成是编译器实现的两个关键步骤。
它们需要一个好的算法和优秀的实现方式,以便在编译过程中产生高效、可靠的目标代码。
编译原理实验二:LL(1)语法分析器
编译原理实验⼆:LL(1)语法分析器⼀、实验要求 1. 提取左公因⼦或消除左递归(实现了消除左递归) 2. 递归求First集和Follow集 其它的只要按照课本上的步骤顺序写下来就好(但是代码量超多...),下⾯我贴出实验的⼀些关键代码和算法思想。
⼆、基于预测分析表法的语法分析 2.1 代码结构 2.1.1 Grammar类 功能:主要⽤来处理输⼊的⽂法,包括将⽂法中的终结符和⾮终结符分别存储,检测直接左递归和左公因⼦,消除直接左递归,获得所有⾮终结符的First集,Follow集以及产⽣式的Select集。
#ifndef GRAMMAR_H#define GRAMMAR_H#include <string>#include <cstring>#include <iostream>#include <vector>#include <set>#include <iomanip>#include <algorithm>using namespace std;const int maxn = 110;//产⽣式结构体struct EXP{char left; //左部string right; //右部};class Grammar{public:Grammar(); //构造函数bool isNotTer(char x); //判断是否是终结符int getTer(char x); //获取终结符下标int getNonTer(char x); //获取⾮终结符下标void getFirst(char x); //获取某个⾮终结符的First集void getFollow(char x); //获取某个⾮终结符的Follow集void getSelect(char x); //获取产⽣式的Select集void input(); //输⼊⽂法void scanExp(); //扫描输⼊的产⽣式,检测是否有左递归和左公因⼦void remove(); //消除左递归void solve(); //处理⽂法,获得所有First集,Follow集以及Select集void display(); //打印First集,Follow集,Select集void debug(); //⽤于debug的函数~Grammar(); //析构函数protected:int cnt; //产⽣式数⽬EXP exp[maxn]; //产⽣式集合set<char> First[maxn]; //First集set<char> Follow[maxn]; //Follow集set<char> Select[maxn]; //select集vector<char> ter_copy; //去掉$的终结符vector<char> ter; //终结符vector<char> not_ter; //⾮终结符};#endif 2.1.2 AnalyzTable类 功能:得到预测分析表,判断输⼊的⽂法是否是LL(1)⽂法,⽤预测分析表法判断输⼊的符号串是否符合刚才输⼊的⽂法,并打印出分析过程。
编译原理词法分析和语法分析报告+代码[C语言版]
词法分析一、实验目的设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。
二、实验要求2.1 待分析的简单的词法(1)关键字:begin if then while do end所有的关键字都是小写。
(2)运算符和界符:= + - * / < <= <> > >= = ; ( ) #(3)其他单词是标识符(ID)和整型常数(SUM),通过以下正规式定义:ID = letter (letter | digit)*NUM = digit digit*(4)空格有空白、制表符和换行符组成。
空格一般用来分隔ID、SUM、运算符、界符和关键字,词法分析阶段通常被忽略。
2.2 各种单词符号对应的种别码:表2.1 各种单词符号对应的种别码2.3 词法分析程序的功能:输入:所给文法的源程序字符串。
输出:二元组(syn,token或sum)构成的序列。
其中:syn为单词种别码;token为存放的单词自身字符串;sum为整型常数。
例如:对源程序begin x:=9: if x>9 then x:=2*x+1/3; end #的源文件,经过词法分析后输出如下序列:(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)……三、词法分析程序的算法思想:算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。
3.1 主程序示意图:主程序示意图如图3-1所示。
其中初始包括以下两个方面:⑴关键字表的初值。
关键字作为特殊标识符处理,把它们预先安排在一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。
如能查到匹配的单词,则该单词为关键字,否则为一般标识符。
关键字表为一个字符串数组,其描述如下:Char *rwtab[6] = {“begin”, “if”, “then”, “while”, “do”, “end”,};是图3-1(2)程序中需要用到的主要变量为syn,token和sum3.2 扫描子程序的算法思想:首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。
实验5-LL(1)语法分析程序的设计与实现(C语言)
实验五LL(1)文法识别程序设计一、实验目的通过LL(1)文法识别程序的设计理解自顶向下的语法分析思想。
二、实验重难点FIRST集合、FOLLOW集合、SELECT集合元素的求解,预测分析表的构造。
三、实验内容与要求实验内容:1.阅读并理解实验案例中LL(1)文法判别的程序实现;2.参考实验案例,完成简单的LL(1)文法判别程序设计。
四、实验学时4课时五、实验设备与环境C语言编译环境六、实验案例1.实验要求参考教材93页预测分析方法,94页图5.11 预测分析程序框图,编写表达式文法的识别程序。
要求对输入的LL(1)文法字符串,程序能自动判断所给字符串是否为所给文法的句子,并能给出分析过程。
表达式文法为:E→E+T|TT→T*F|FF→i|(E)2.参考代码为了更好的理解代码,建议将图5.11做如下标注:/* 程序名称: LL(1)语法分析程序 *//* E->E+T|T *//* T->T*F|F *//* F->(E)|i *//*目的: 对输入LL(1)文法字符串,本程序能自动判断所给字符串是否为所给文法的句子,并能给出分析过程。
/********************************************//* 程序相关说明 *//* A=E' B=T' *//* 预测分析表中列号、行号 *//* 0=E 1=E' 2=T 3=T' 4=F *//* 0=i 1=+ 2=* 3=( 4=) 5=# *//************************************/#include"iostream"#include "stdio.h"#include "malloc.h"#include "conio.h"/*定义链表这种数据类型参见:*/struct Lchar{char char_ch;struct Lchar *next;}Lchar,*p,*h,*temp,*top,*base;/*p指向终结符线性链表的头结点,h指向动态建成的终结符线性链表节点,top和base分别指向非终结符堆栈的顶和底*/char curchar; //存放当前待比较的字符:终结符char curtocmp; //存放当前栈顶的字符:非终结符int right;int table[5][6]={{1,0,0,1,0,0},{0,1,0,0,1,1},{1,0,0,1,0,0},{0,1,1,0,1,1},{1,0,0,1,0,0}};/*存放预测分析表,1表示有产生式,0表示无产生式。
编译原理-语法分析
自顶向下的语法分析方法简单直观,易于实现,但可能存在 左递归和回溯的问题。
自底向上的语法分析
01
自底向上的语法分析方法从源代码中的每个符号出发
,逐步归约到文法的起始符号。
02
该方法通常采用LR(0)、SLR(1)、LALR(1)等算法进行
实现。
03
自底向上的语法分析方法可以避免回溯问题,但需要
• 随着人工智能和机器学习技术的不断发展,可以利用这些技术来辅助语法分析 过程,提高语法分析的准确性和效率。例如,可以使用机器学习算法来自动识 别和处理语法规则和歧义问题。
• 另外,随着软件工程和代码质量的重视程度不断提高,对编译器和语法分析器 的要求也越来越高。未来的研究需要更加注重编译器和语法分析器的可维护性 和可扩展性,以满足不断变化的软件需求。
词法分析的算法
自底向上算法
自底向上算法是从源代码的左向右进行扫描,并从下到上构建语法结构。常见 的自底向上算法有预测分析法和移进-规约法。
自顶向下算法
自顶向下算法是从语法结构的顶层开始,向下进行推导,直到找到与源代码相 匹配的语法结构。常见的自顶向下算法有规范分析法和贪婪分析法。
语法分析概述
语法分析是编译过程的核心环节,其任务是将源代码分解成一系列的语法 结构,以便后续的语义分析和代码生成。
自底向上的算法,通过构建归 约表进行移进和规约操作。
LALR(1)算法
扩展的LR(0)算法,能够处理 更广泛的文法,生成更小的归 约表。
03
语义分析
语义分析概述
01
Байду номын сангаас02
03
语义分析是编译过程的 一个阶段,它是在语法
分析之后进行的。
语义分析的主要任务是 检查源代码的语义是否 正确,例如变量是否已 经声明,类型是否匹配
编译原理——语法分析程序设计实验报告
实验二语法分析程序设计[实验目的]:1.了解语法分析的主要任务。
2.熟悉编译程序的编制。
[实验内容]:根据某文法,构造一基本递归下降语法分析程序。
给出分析过程中所用的产生式序列。
[实验要求]:1.选择一个文法,进行实验,可选的文法包括以下三个:P190 4.8P190 4.9P190 4.102.设计语法分析程序的输出形式(输出应为语法树或推导),一个可以参考的例子,可见图1。
3.编写递归下降语法分析程序(参考P148-149 Topdown parsing byrecursive-descent),实现基本的递归下降分析器,能够分析任给的符号串是否为该文法所定义的合法句子。
实验报告中要说明分析使用的方法。
4.根据所作业题选项e所给出的input,生成并输出分析过程中所用的产生式序列(show the actions of parser):1 产生式12 产生式2……5.自已设计一个不合法的句子,作为输出进行分析,给出结果。
[实验过程]本次实验选择的文法为P190 4.8lexp->atom|listatom->number|identifierlist->(lexp-seq)lexp-seq->lexp lexp-seq1.写出实现的算法,并画流程图。
本次实验采用递归下降算法,算法流程图如下图1-1:图1-1 算法流程图2.根据你选择的文法,分析左递归或左因子是否会影响本算法的结果。
会影响本算法的结果。
递归下降分析法要求的文法是LL(1)文法,需要消除左递归和左因子的影响。
如果存在左因子,对相同的字符跳转到不同的函数,无法实现递归。
3.列举实验设计过程中出现的问题及解决的方法(至少3条,选择实验中最困扰的问题)。
1).会多次输出accept/error结果解决方案:所有的递归函数返回类型为int,若accept返回1,error返回0,在main主函数中统一判断输出语句。
语法分析器的源代码
using System;using System.IO;using System.Collections.Generic;using ponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Windows.Forms;namespace WindowsFormsApplication3{public partial class Form1 : Form{public Form1(){InitializeComponent();}struct pronode{public char leftch;public string midch;public string rightch;public string select;}struct unnifo{public char ch;public string first;public string follow;}unnifo[] firstfollow = new unnifo[20];//放first 和follow;pronode[] proNode = new pronode[30];//产生式pronode[,] table1 = new pronode[15, 15];//分析表string vnstr;//非终结符string vtstr;//终结符string kong;//含有空的终结符int lenvn;//定义非终结符的个数int lenwenfa;//定义产生式的数目public void getvnstr()//取非终结符函数{int i;int len = proNode.Length;for (i = 0; i < len; i++){if (vnstr == null){vnstr += proNode[i].leftch;}else{int lenth = vnstr.Length;int j;for (j = 0; j < lenth; j++){if (proNode[i].leftch == vnstr[j]){break;}}if (j == lenth){vnstr += proNode[i].leftch;}}}}public void getvtstr()//取终结符函数{bool flag;int i;int len = proNode.Length;for (i = 0; i < lenwenfa; i++){int lenth = proNode[i].rightch.Length;int j;for (j = 0; j < lenth; j++){flag = true;if (isvn(proNode[i].rightch[j])){flag = false;}else{if (proNode[i].rightch[j] == '?'){flag = false;if (kong == null){kong += proNode[i].leftch;}else{int k;int leng = kong.Length;for (k = 0; k < leng; k++){if (proNode[i].rightch[j] == kong[k]){break;}}if (k == leng + 1){kong += proNode[i].leftch;}}}else{if (flag){if (vtstr == null){vtstr += proNode[i].rightch[j];}else{int h;int lenvt = vtstr.Length;for (h = 0; h < lenvt; h++){if (proNode[i].rightch[j] == vtstr[h]){break;}}if (h == lenvt){vtstr += proNode[i].rightch[j];}}}}}}}}public void createfirf()//定义first和follow 集函数{int i;int len = vnstr.Length;for (i = 0; i < len; i++){firstfollow[i].ch = vnstr[i];firstfollow[i].first = "";firstfollow[i].follow = "";}}public void getlenvn()//取终结符个数函数{lenvn = vnstr.Length;}public Boolean isvn(char ch)//比较是非终结符{int i;string vn;vn = textBox1.Text;for (i = 0; i < vn.Length; i++){if (vn[i] == ch){return true;}}return false;}public Boolean isvt(char ch)//比较是终结符函数{int i;string vt;vt = textBox2.Text;for (i = 0; i < vt.Length; i++){if (vt[i] == ch){return true;}}return false;}public string addchar(string vtstrch, char ch)//在字符串中加字符{bool flag = true;int temlen = vtstrch.Length;for (int i = 0; i < temlen; i++){if (vtstrch[0] == ch){flag = false;break;}}if (flag){vtstrch = vtstrch + ch;}return vtstrch;}public Boolean iskongch(char ch)//判断字符为能推出空集的非终结符;{int i;string temkong;temkong = textBox3.Text;for (i = 0; i < temkong.Length; i++){if (ch == temkong[i]){return true;}}return false;}public string addchtoch(string chstr, string otherarr)//在字符串终结字符串函数{int otherlen = otherarr.Length;for (int j = 0; j < otherlen; j++){bool flag = true;int tmlen = chstr.Length;for (int i = 0; i < tmlen; i++){if (chstr[i] == otherarr[j]){flag = false;break;}}if (flag){if (otherarr[j] != '?'){chstr = chstr + otherarr[j].ToString();}}}return chstr;}public void first1()//求first集的第一步骤{int i;for (i = 0; i < lenvn; i++){for (int j = 0; j < lenwenfa; j++){if (firstfollow[i].ch == proNode[j].leftch){int lenth = firstfollow[i].first.Length;int k;for (k = 0; k < lenth; k++){if (firstfollow[i].first[k] == proNode[j].rightch[0]){break;}}if (k == lenth){firstfollow[i].first += proNode[j].rightch[0].ToString();}}}}}public void first2()//求first集的第二步骤{int i;for (i = 0; i < lenvn; i++){int j;char ch;int lenth = firstfollow[i].first.Length;for (j = 0; j <= lenth - 1; j++){if (isvn(firstfollow[i].first[j]) == true)//判断first集中是否有非终结符;{ch = firstfollow[i].first[j];for (int h = 0; h < lenvn; h++){if (firstfollow[h].ch == ch){firstfollow[i].first = firstfollow[i].first.Remove(j, 1);firstfollow[i].first = addchtoch(firstfollow[i].first, firstfollow[h].first);}}lenth = firstfollow[i].first.Length;j = 0;}}}}public void follow1()//求follow 集的第一步{int i;firstfollow[0].follow = addchar(firstfollow[0].follow, '#');//开始符要先加‘#’;for (i = 0; i < lenvn; i++){for (int j = 0; j < lenwenfa; j++){int k;for (k = 0; k < proNode[j].rightch.Length; k++){if (proNode[j].rightch[k] == firstfollow[i].ch)//判断右边的字符串中的非终结符有等于等于要求follow集的非终结符;{if (k + 1 == proNode[j].rightch.Length)//判断要求follow集的非终结符为右边字符串的最后一个字符;{int lenth2 = firstfollow[i].follow.Length;if (lenth2 == 0){firstfollow[i].follow = firstfollow[i].follow + proNode[j].leftch;//将该文法产生式的左边字符加到follow集中}else{for (int m = 0; m < lenth2; m++){if (firstfollow[i].follow[m] != proNode[j].leftch){firstfollow[i].follow = firstfollow[i].follow + proNode[j].leftch;}}}}if (k + 1 < proNode[j].rightch.Length)//判断要求follow集的非终结符的在右边字符串中出现且不是在最后一个字符{char ch = proNode[j].rightch[k + 1];if (isvt(ch))//判断是终结符{int lenth1 = firstfollow[i].follow.Length;if (lenth1 == 0){firstfollow[i].follow = firstfollow[i].follow + ch;}else{firstfollow[i].follow = addchar(firstfollow[i].follow, ch);}}if (isvn(ch))//判断为非终结符{if (!iskongch(ch))//该非终结不能推出空集;{for (int n = 0; n < lenvn; n++){if (firstfollow[n].ch == ch){addchtoch(firstfollow[i].follow, firstfollow[n].first);}}}else{for (int w = 0; w < lenvn; w++){if (firstfollow[w].ch == ch){addchtoch(firstfollow[i].follow, firstfollow[w].first);}int lenth3 = firstfollow[i].follow.Length;for (int l = 0; l < lenth3; l++){if (firstfollow[i].follow[l] != proNode[j].leftch){firstfollow[i].follow += proNode[j].leftch;}}}}}}}}}}}public void follow2()//求follow集的第二步{int i;for (i = 0; i < lenvn; i++){char ch;int lenth = firstfollow[i].follow.Length;int j;for (j = 0; j < lenth; j++){if (isvn(firstfollow[i].follow[j]))//判断follow集中是否有非终结符;{ch = firstfollow[i].follow[j];for (int k = 0; k < lenvn; k++){if (firstfollow[k].ch == ch){firstfollow[i].follow = firstfollow[i].follow.Remove(j, 1);firstfollow[i].follow = addchtoch(firstfollow[i].follow, firstfollow[k].follow);}}lenth = firstfollow[i].follow.Length;j = 0;}}}}public void select()//求select集{int i;for (i = 0; i < lenwenfa; i++){if (isvt(proNode[i].rightch[0])){int lenth = proNode[i].select.Length;int j;for (j = 0; j < lenth; j++){if (proNode[i].select[j] == proNode[i].rightch[0]){break;}}if (j == lenth){proNode[i].select += proNode[i].rightch[0];}}if (proNode[i].rightch[0] == '?')//集中'?'来表示空集;{int k;for (k = 0; k < lenvn; k++){if (firstfollow[k].ch == proNode[i].leftch){proNode[i].select = addchtoch(proNode[i].select, firstfollow[k].follow);}}}if (isvn(proNode[i].rightch[0])){int h;for (h = 0; h < lenvn; h++){if (firstfollow[h].ch == proNode[i].rightch[0]){int len = firstfollow[h].first.Length;int m;proNode[i].select = addchtoch(proNode[i].select, firstfollow[h].first);for (m = 0; m < len; m++){if (firstfollow[h].first[m] == '?')//集中'?'来表示空集;{int n;for (n = 0; n < lenvn; n++){if (firstfollow[n].ch == proNode[i].leftch){proNode[i].select = addchtoch(proNode[i].select, firstfollow[n].follow);}}}}}}}}}public int getvn(char ch)//求字符在非终结中的位置{int i;string vn;vn = textBox1.Text;for (i = 0; i < vn.Length; i++){if (vn[i] == ch){return i;}}return -1;}public int getvt(char ch)//求字符在终结符中的位置{int j;string vt;vt = textBox2.Text;for (j = 0; j < vt.Length; j++){if (vt[j] == ch){return j;}}return -1;}public void create_table()//建立分析表{int row;int col;int k;for (k = 0; k < lenwenfa; k++){int m;int lensel = proNode[k].select.Length;for (m = 0; m < lensel; m++){row = getvn(proNode[k].leftch);col = getvt(proNode[k].select[m]);table1[row, col] = proNode[k];}}}public void prtable(int m, int n)//输出表中每个元素{if (m != -1 && n != -1){richTextBox1.AppendText(table1[m, n].leftch + table1[m, n].midch + table1[m, n].rightch);}}public void shtabel()//显示表的内容{richTextBox1.AppendText("\t");int i;string vt;vt = textBox2.Text;for (i = 0; i < vt.Length; i++){richTextBox1.AppendText(vt[i] + "\t");}int k;for (k = 0; k < vt.Length; k++){if (vt[k] == '#'){richTextBox1.AppendText("\n");break;}}if (k == vt.Length)richTextBox1.AppendText("#" + "\n");}int j;string vn;vn = textBox1.Text;for (j = 0; j < vn.Length; j++){richTextBox1.AppendText(vn[j] + "\t");for (int n = 0; n < lenvn; n++){prtable(j, n);richTextBox1.AppendText("\t");}richTextBox1.AppendText("\n");}}public char getfirst(string str)//取第一个字符{char ch;int len;len = str.Length;if (len == 0){return (' ');}else{ch = str[0];return ch;}}public string remfirst(string str1)//删除第一个字符{int len = str1.Length;if (len == 0){return ("");}else{str1 = str1.Remove(0, 1);return str1;}public char getlast(string str)//取最后一个字符{char ch;int len;len = str.Length;if (len == 0){return (' ');}else{ch = str[len - 1];return ch;}}public string remlast(string str1)//删除最后一个字符{int len = str1.Length;if (len == 0){return ("");}else{str1 = str1.Remove(len - 1, 1);return str1;}}public void error(){richTextBox1.AppendText("分析错误!" + "\n"); }public void success(){richTextBox1.AppendText("Successful!" + "\n"); }public void scan()//分析过程{string prstr;int step = 1;int left;int right;char ch;char ch1;bool flag = true;string temstr = "#S";prstr = textBoxch.Text;richTextBox1.AppendText("步骤" + "\t" + "符号栈" + "\t" + "读入符号" + "\t" + "剩余符号串" + "\t" + "使用产生式" + "\n");richTextBox1.AppendText(step + "\t" + temstr + "\t");step++;ch = getfirst(prstr);prstr = remfirst(prstr);richTextBox1.AppendText(ch + "\t" + "\t");while (flag){richTextBox1.AppendText(prstr + "\t" + "\t");ch1 = getlast(temstr);temstr = remlast(temstr);left = getvn(ch1);right = getvt(ch);prtable(left, right);if (isvt(ch1)){if (ch1 == ch){richTextBox1.AppendText(ch1 + "匹配" + "\n");ch = getfirst(prstr);prstr = remfirst(prstr);richTextBox1.AppendText(step + "\t" + temstr + "\t" + ch + "\t" + "\t");step++;}else{flag = false;error();}}else{if (ch1 == '#'){if (ch == ch1){richTextBox1.AppendText("分析成功!" + "\n");success();flag = false;}else{flag = false;error();}}else{left = getvn(ch1);right = getvt(ch);if (right != -1){if (table1[left, right].leftch != '\0'){if (table1[left, right].rightch[0] != '?')//集中'?'来表示空集;{richTextBox1.AppendText("\n");int lenrigth = table1[left, right].rightch.Length;int len1;for (len1 = lenrigth - 1; len1 >= 0; len1--){temstr += table1[left, right].rightch[len1];}richTextBox1.AppendText(step + "\t" + temstr + "\t" + ch + "\t" + "\t");step++;}else{richTextBox1.AppendText("\n");richTextBox1.AppendText(step + "\t" + temstr + "\t" + ch + "\t" + "\t");step++;}}else{flag = false;error();}}else{flag = false;error();}}}}}public void getwenfa()//初始化文法数组{string[] s = richTextBox2.Text.Split('\n');int i;lenwenfa = s.Length - 1;for (i = 0; i < lenwenfa; i++){int j;proNode[i].leftch = s[i][0];proNode[i].midch += s[i][1];proNode[i].midch += s[i][2];for (j = 3; j < s[i].Length; j++){proNode[i].rightch += s[i][j];}proNode[i].select = "";}}private void Form1_Load(object sender, EventArgs e){for (int i = 0; i < lenwenfa; i++){richTextBox2.AppendText(proNode[i].leftch + proNode[i].midch + proNode[i].rightch + "\n");}}private void button2_Click(object sender, EventArgs e)//求字符按钮{getwenfa();getvnstr();textBox1.Text = vnstr;getvtstr();textBox2.Text = vtstr;textBox3.Text = kong;createfirf();getlenvn();}private void butn_Click_1(object sender, EventArgs e)//分析按钮{string temstr;first1();first2();follow1();follow2();richTextBox1.AppendText("非终结符" + "\t" + "FIRST集" + "\t" + "\t" + "FOLLOW 集" + "\n");for (int i = 0; i < lenvn; i++){richTextBox1.AppendText(firstfollow[i].ch + "\t" + "\t" + firstfollow[i].first + "\t" + "\t" + firstfollow[i].follow + "\n");}richTextBox1.AppendText("\n");select();richTextBox1.AppendText("文法产生式" + "\t" + "SELECT集" + "\n");for (int j = 0; j < lenwenfa; j++){richTextBox1.AppendText(proNode[j].leftch + proNode[j].midch + proNode[j].rightch + "\t" + "\t" + proNode[j].select + "\n");}richTextBox1.AppendText("\n");create_table();richTextBox1.AppendText("**************欢迎你使用该语法分析器**************" + "\n");richTextBox1.AppendText("\n");richTextBox1.AppendText("预测分析表:" + "\n");shtabel();richTextBox1.AppendText("\n");temstr = textBoxch.Text;if (temstr != "")//要求输入一个句子{int lenth = temstr.Length;if (temstr[lenth - 1] == '#')//要求输入的句子以‘#’结束;{scan();}else{MessageBox.Show("请以“#“结尾!");richTextBox1.Text = "";}}else{MessageBox.Show("请输入句子!");textBoxch.Text = "";richTextBox1.Text = "";}}private void button1_Click(object sender, EventArgs e)//清除按钮{textBoxch.Text = "";richTextBox1.Text = "";}private void 清除ToolStripMenuItem_Click_1(object sender, EventArgs e) {textBoxch.Text = "";richTextBox1.Text = "";}private void 说明ToolStripMenuItem_Click_1(object sender, EventArgs e) {MessageBox.Show("本程序所有权属于本程序的开发者!");}private void button3_Click(object sender, EventArgs e)//打开文件按钮{if (openFileDialog1.ShowDialog() == DialogResult.OK){FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open);StreamReader sw = new StreamReader(fs);while (!sw.EndOfStream){richTextBox2.AppendText(sw.ReadLine() + "\n");}sw.Close();}}}}。
北方工业大学计算机专业编译原理实验报告——语法分析器详细代码报告
else if(m==0)
cout<<"="<<setw(8);
else
cout<<"<"<<setw(8);
cout<<a<<setw(10);
cout<<&strings[k]<<setw(10);
if(t)
{
cout<<"归约"<<setw(8);
No[n++]=step-1;
}
else
cout<<"移进"<<setw(8);
{
push(a);
print(0,0);
if(stack[top]!='#')
goto u;
}
else
{
error(j);
a='#';
}
}
}while(a!='#');
}
void main()
{
cout<<"*********算符优先语法分析程序*********"<<endl;
cout<<" E->E+T|E-T|T"<<endl;
}
else
printf("\n错误e3:非法右括号!");
}
void prior_analysis()
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第三次上机-语法分析1目的:熟练掌握自上而下的语法分析方法,并能用程序实现。
要求:1. 使用的文法如下:E TEE +TE|εT FTT *FT|εF (E)|id2. 对于任意给定的输入串(词法记号流)进行语法分析,递归下降方法和非递归预测分析方法可以任选其一来实现。
3. 要有一定的错误处理功能即对错误能提示,并且能在一定程度上忽略尽量少的记号来进行接下来的分析。
可以参考书上介绍的同步记号集合来处理。
可能的出错情况:idid*id, id**id, (id+id,+id*+id ……4. 输入串以#结尾,输出推导过程中使用到的产生式。
例如:输入:id+id*id#输出:E TE'T FT'F idE +TE'T FT'……如果输入串有错误,则在输出中要体现是跳过输入串的某些记号了,还是弹栈,弹出某个非终结符或者是终结符了,同时给出相应的出错提示信息。
比如:idid*id对应的出错信息是:"输入串跳过记号id,用户多输入了一个id";id**id对应的出错信息是:"弹栈,弹出非终结符F,用户少输入了一个id"(id+id对应的出错信息是:"弹栈,弹出终结符) ,用户少输入了一个右括号(或者说,括号不匹配)"有余力的同学可进一步考虑如下扩展:1.将递归下降方法和非递归预测分析方法都实现2.在语法分析的过程中调用前两次上机的结果,即利用词法分析器来返回一个记号给语法分析器。
3.编写First和Follow函数,实现其求解过程。
*/#include<stdio.h>#include<dos.h>#include<stdlib.h>#include<string.h>char a[50] ,b[50];char ch;int n1,i1=0,flag=1,n=5,signal=0;int total=0;/*步骤计数器*/int E();int T();int E1();/*E'*/int T1();/*T'*/int F();void input();void input1();void main() /*递归分析*/{int f,j=0;printf("请输入字符串(长度<50,以#号结束)\n");do{scanf("%c",&ch);a[j]=ch;j++;}while(ch!='#');n1=j;ch=b[0]=a[0];printf("步骤\t文法\t\t分析串\t\t分析字符\t剩余串\n");f=E();if (f==0) return;if (ch=='#')printf("accept\n");else{printf("error\n");return;}printf("\n");}int E(){ int f,t;printf("%d\tE-->TE'\t\t",total);total++;flag=1;input();input1();if (i1==0){while (ch=='+'||ch=='*'){if (ch=='+') // +i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("串首部多输入了一个+!error\n");ch=a[++i1];}if (ch=='*') // *i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("串首部多输入了一个*!error\n");ch=a[++i1];}}}f=T();if (f==0) return(0);t=E1();if (t==0) return(0);else return(1);}int T(){ int f,t;printf("%d\tT-->FT'\t\t",total);total++;flag=1;input();input1();f=F();if (f==0) return(0);t=T1();if (t==0) return(0);else return(1);}int E1(){ int f,t;if(ch=='+'){b[i1]=ch;printf("%d\tE'-->+TE'\t",total);total++;flag=0;input();input1();ch=a[++i1];if (ch=='+') // i++i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("少输入了一个i!error\n");ch=a[++i1];}if (ch=='*') // i+*i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("少输入了一个i!error\n");ch=a[++i1];}f=T();if (f==0) return(0);t=E1();if (t==0) return(0);else return (1);}printf("%d\tE'-->ε\t\t",total);total++;flag=1;input();input1();return(1);}int T1(){int f,t;if(ch=='*') {b[i1]=ch;printf("%d\tT'-->*FT'\t",total);total++;flag=0;input();input1();ch=a[++i1];if (ch=='*') // i**i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("少输入了一个i!error\n");ch=a[++i1];}if (ch=='+') // i*+i{b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("少输入了一个i!error\n");ch=a[++i1];}f=F();if (f==0) return(0);t=T1();if (t==0) return(0);else return(1);}printf("%d\tT'-->ε\t\t",total);total++;flag=1;a[i1]=ch;input();input1();return(1);}int F(){ int f;if(ch=='('){b[i1]=ch;printf("%d\tF-->(E)\t\t",total);total++;flag=0;signal=1;input();input1();ch=a[++i1];f=E();if (f==0) return(0);if(ch==')'){b[i1]=ch;printf("%d\tF-->(E)\t\t",total);total++;flag=0;input();input1();ch=a[++i1]; signal=0;}else{printf("缺少右括号!error\n");// return(0); //考虑容忍没有右)的情况}}else if(ch=='i'){b[i1]=ch;printf("%d\tF-->i\t\t",total);total++;flag=0;input();input1();ch=a[++i1];if (ch==')'&&!signal){b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("缺少左括号!error\n");ch=a[++i1];}if (ch=='i'){b[i1]=ch;printf("%d\t\t\t",total);total++;flag=0;input();input1();printf("多输入了一个i!error\n");ch=a[++i1];}}else{printf("error\n");//return(0);}return(1);}void input(){int j=0;for (;j<=i1-flag;j++)printf("%c",b[j]); /*输出分析串*/printf("\t\t");printf("%c\t\t",ch); /*输出分析字符*/ }void input1(){int j;for (j=i1+1-flag;j<n1;j++)printf("%c",a[j]); /*输出剩余字符*/printf("\n");}。