语法分析器(完整代码)1
软件开发中的语法分析器技术
软件开发中的语法分析器技术在软件开发中,语法分析器技术是一项十分重要的技术,它负责将代码进行解析和翻译,从而进行编译或执行。
语法分析器技术可以帮助开发人员识别并纠正代码中的错误,提高编程效率和代码质量。
本文将介绍语法分析器技术的相关知识和应用。
什么是语法分析器?语法分析器是一种翻译器,其作用是将源代码转换为目标代码或解释执行。
它的主要任务是进行句法分析和语义分析,检查代码的正确性和逻辑性,同时生成代码树以生成目标代码或解释执行。
语法分析器可以划分为两种类型:自下而上语法分析器和自上而下语法分析器。
自下而上语法分析器是一种逆向分析方式,它从最小的语法单元开始,将其组合成较大的语法单元,最终生成一棵代码树。
自上而下语法分析器则是先由代码的上层结构进行分析,逐级分解为更小的语法单元,最后得到一颗代码树。
语法分析器的作用语法分析器在软件开发中具有非常重要的作用,它可以提高代码的正确性和可读性,同时能够检测并纠正代码中的错误,加快软件开发过程。
具体来说,语法分析器能够:1.检查代码的正确性语法分析器能够在编译或执行代码之前检查代码的正确性。
它能够检查代码中的语法错误、类型错误、语义错误等,在代码编写过程中及时发现并及时纠正错误,提高代码的质量和可维护性。
2.加快编译及执行速度语法分析器能够将源代码转换为目标代码或解释执行,加快程序的执行速度。
它能够分析代码逻辑,优化相关代码的执行流程,同时减少代码执行的时间。
3.提高代码可读性语法分析器能够将代码转换成易于理解和维护的代码,同时增强代码的可读性。
例如,它可以将代码中重复的部分统一,提高代码的可读性和可维护性。
语法分析器的应用语法分析器在软件开发中广泛应用,具体包括以下方面: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}。
实验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.编写主程序利用上文描述算法实现本实验要求。
五、实验结果1. 实验文法为程序既定的文法,写在头文件LR.h中,运行程序,用户可以自由输入测试语句。
语法分析器源代码
语法分析程序的源代码#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;}。
编译原理实验报告《LL(1)语法分析器构造》(推荐文档)
《LL(1)分析器的构造》实验报告一、实验名称LL(1)分析器的构造二、实验目的设计、编制、调试一个LL(1)语法分析器,利用语法分析器对符号串的识别,加深对语法分析原理的理解。
三、实验内容和要求设计并实现一个LL(1)语法分析器,实现对算术文法:G[E]:E->E+T|TT->T*F|FF->(E)|i所定义的符号串进行识别,例如符号串i+i*i为文法所定义的句子,符号串ii+++*i+不是文法所定义的句子。
实验要求:1、检测左递归,如果有则进行消除;2、求解FIRST集和FOLLOW集;3、构建LL(1)分析表;4、构建LL分析程序,对于用户输入的句子,能够利用所构造的分析程序进行分析,并显示出分析过程。
四、主要仪器设备硬件:微型计算机。
软件: Code blocks(也可以是其它集成开发环境)。
五、实验过程描述1、程序主要框架程序中编写了以下函数,各个函数实现的作用如下:void input_grammer(string *G);//输入文法Gvoid preprocess(string *G,string *P,string &U,string &u,int &n,int &t,int &k);//将文法G预处理得到产生式集合P,非终结符、终结符集合U、u,int eliminate_1(string *G,string *P,string U,string *GG);//消除文法G中所有直接左递归得到文法GGint* ifempty(string* P,string U,int k,int n);//判断各非终结符是否能推导为空string* FIRST_X(string* P,string U,string u,int* empty,int k,int n);求所有非终结符的FIRST集string FIRST(string U,string u,string* first,string s);//求符号串s=X1X2...Xn的FIRST集string** create_table(string *P,string U,string u,int n,int t,int k,string* first);//构造分析表void analyse(string **table,string U,string u,int t,string s);//分析符号串s2、编写的源程序#include<cstdio>#include<cstring>#include<iostream>using namespace std;void input_grammer(string *G)//输入文法G,n个非终结符{int i=0;//计数char ch='y';while(ch=='y'){cin>>G[i++];cout<<"继续输入?(y/n)\n";cin>>ch;}}void preprocess(string *G,string *P,string &U,string &u,int &n,int &t,int &k)//将文法G预处理产生式集合P,非终结符、终结符集合U、u,{int i,j,r,temp;//计数char C;//记录规则中()后的符号int flag;//检测到()n=t=k=0;for( i=0;i<50;i++) P[i]=" ";//字符串如果不初始化,在使用P[i][j]=a时将不能改变,可以用P[i].append(1,a)U=u=" ";//字符串如果不初始化,无法使用U[i]=a赋值,可以用U.append(1,a) for(n=0;!G[n].empty();n++){ U[n]=G[n][0];}//非终结符集合,n为非终结符个数for(i=0;i<n;i++){for(j=4;j<G[i].length();j++){if(U.find(G[i][j])==string::npos&&u.find(G[i][j])==string::npos)if(G[i][j]!='|'&&G[i][j]!='^')//if(G[i][j]!='('&&G[i][j]!=')'&&G[i][j]!='|'&&G[i][j]!='^')u[t++]=G[i][j];}}//终结符集合,t为终结符个数for(i=0;i<n;i++){flag=0;r=4;for(j=4;j<G[i].length();j++){P[k][0]=U[i];P[k][1]=':';P[k][2]=':';P[k][3]='=';/* if(G[i][j]=='('){ j++;flag=1;for(temp=j;G[i][temp]!=')';temp++);C=G[i][temp+1];//C记录()后跟的字符,将C添加到()中所有字符串后面}if(G[i][j]==')') {j++;flag=0;}*/if(G[i][j]=='|'){//if(flag==1) P[k][r++]=C;k++;j++;P[k][0]=U[i];P[k][1]=':';P[k][2]=':';P[k][3]='=';r=4;P[k][r++]=G[i][j];}else{P[k][r++]=G[i][j];}}k++;}//获得产生式集合P,k为产生式个数}int eliminate_1(string *G,string *P,string U,string *GG)//消除文法G1中所有直接左递归得到文法G2,要能够消除含有多个左递归的情况){string arfa,beta;//所有形如A::=Aα|β中的α、β连接起来形成的字符串arfa、betaint i,j,temp,m=0;//计数int flag=0;//flag=1表示文法有左递归int flagg=0;//flagg=1表示某条规则有左递归char C='A';//由于消除左递归新增的非终结符,从A开始增加,只要不在原来问法的非终结符中即可加入for(i=0;i<20&&U[i]!=' ';i++){ flagg=0;arfa=beta="";for(j=0;j<100&&P[j][0]!=' ';j++){if(P[j][0]==U[i]){if(P[j][4]==U[i])//产生式j有左递归{flagg=1;for(temp=5;P[j][temp]!=' ';temp++) arfa.append(1,P[j][temp]);if(P[j+1][4]==U[i]) arfa.append("|");//不止一个产生式含有左递归}else{for(temp=4;P[j][temp]!=' ';temp++) beta.append(1,P[j][temp]);if(P[j+1][0]==U[i]&&P[j+1][4]!=U[i]) beta.append("|");}}}if(flagg==0)//对于不含左递归的文法规则不重写{GG[m]=G[i]; m++;}else{flag=1;//文法存在左递归GG[m].append(1,U[i]);GG[m].append("::=");if(beta.find('|')!=string::npos) GG[m].append("("+beta+")");else GG[m].append(beta);while(U.find(C)!=string::npos){C++;}GG[m].append(1,C);m++;GG[m].append(1,C);GG[m].append("::=");if(arfa.find('|')!=string::npos) GG[m].append("("+arfa+")");else GG[m].append(arfa);GG[m].append(1,C);GG[m].append("|^");m++;C++;}//A::=Aα|β改写成A::=βA‘,A’=αA'|β,}return flag;}int* ifempty(string* P,string U,int k,int n){int* empty=new int [n];//指示非终结符能否推导到空串int i,j,r;for(r=0;r<n;r++) empty[r]=0;//默认所有非终结符都不能推导到空int flag=1;//1表示empty数组有修改int step=100;//假设一条规则最大推导步数为100步while(step--){for(i=0;i<k;i++){r=U.find(P[i][0]);if(P[i][4]=='^') empty[r]=1;//直接推导到空else{for(j=4;P[i][j]!=' ';j++){if(U.find(P[i][j])!=string::npos){if(empty[U.find(P[i][j])]==0) break;}else break;}if(P[i][j]==' ') empty[r]=1;//多步推导到空else flag=0;}}}return empty;}string* FIRST_X(string* P,string U,string u,int* empty,int k,int n){int i,j,r,s,tmp;string* first=new string[n];char a;int step=100;//最大推导步数while(step--){// cout<<"step"<<100-step<<endl;for(i=0;i<k;i++){//cout<<P[i]<<endl;r=U.find(P[i][0]);if(P[i][4]=='^'&&first[r].find('^')==string::npos) first[r].append(1,'^');//规则右部首符号为空else{for(j=4;P[i][j]!=' ';j++){a=P[i][j];if(u.find(a)!=string::npos&&first[r].find(a)==string::npos)//规则右部首符号是终结符{first[r].append(1,a);break;//添加并结束}if(U.find(P[i][j])!=string::npos)//规则右部首符号是非终结符,形如X::=Y1Y2...Yk{s=U.find(P[i][j]);//cout<<P[i][j]<<":\n";for(tmp=0;first[s][tmp]!='\0';tmp++){a=first[s][tmp];if(a!='^'&&first[r].find(a)==string::npos)//将FIRST[Y1]中的非空符加入first[r].append(1,a);}}if(!empty[s]) break;//若Y1不能推导到空,结束}if(P[i][j]==' ')if(first[r].find('^')==string::npos)first[r].append(1,'^');//若Y1、Y2...Yk都能推导到空,则加入空符号}}}return first;}string FIRST(string U,string u,string* first,string s)//求符号串s=X1X2...Xn的FIRST集{int i,j,r;char a;string fir;for(i=0;i<s.length();i++){if(s[i]=='^') fir.append(1,'^');if(u.find(s[i])!=string::npos&&fir.find(s[i])==string::npos){ fir.append(1,s[i]);break;}//X1是终结符,添加并结束循环if(U.find(s[i])!=string::npos)//X1是非终结符{r=U.find(s[i]);for(j=0;first[r][j]!='\0';j++){a=first[r][j];if(a!='^'&&fir.find(a)==string::npos)//将FIRST(X1)中的非空符号加入fir.append(1,a);}if(first[r].find('^')==string::npos) break;//若X1不可推导到空,循环停止}if(i==s.length())//若X1-Xk都可推导到空if(fir.find(s[i])==string::npos) //fir中还未加入空符号fir.append(1,'^');}return fir;}string** create_table(string *P,string U,string u,int n,int t,int k,string* first)//构造分析表,P为文法G的产生式构成的集合{int i,j,p,q;string arfa;//记录规则右部string fir,follow;string FOLLOW[5]={")#",")#","+)#","+)#","+*)#"};string **table=new string*[n];for(i=0;i<n;i++) table[i]=new string[t+1];for(i=0;i<n;i++)for(j=0;j<t+1;j++)table[i][j]=" ";//table存储分析表的元素,“ ”表示error for(i=0;i<k;i++){arfa=P[i];arfa.erase(0,4);//删除前4个字符,如:E::=E+T,则arfa="E+T"fir=FIRST(U,u,first,arfa);for(j=0;j<t;j++){p=U.find(P[i][0]);if(fir.find(u[j])!=string::npos){q=j;table[p][q]=P[i];}//对first()中的每一终结符置相应的规则}if(fir.find('^')!=string::npos){follow=FOLLOW[p];//对规则左部求follow()for(j=0;j<t;j++){if((q=follow.find(u[j]))!=string::npos){q=j;table[p][q]=P[i];}//对follow()中的每一终结符置相应的规则}table[p][t]=P[i];//对#所在元素置相应规则}}return table;}void analyse(string **table,string U,string u,int t,string s)//分析符号串s{string stack;//分析栈string ss=s;//记录原符号串char x;//栈顶符号char a;//下一个要输入的字符int flag=0;//匹配成功标志int i=0,j=0,step=1;//符号栈计数、输入串计数、步骤数int p,q,r;string temp;for(i=0;!s[i];i++){if(u.find(s[i])==string::npos)//出现非法的符号cout<<s<<"不是该文法的句子\n";return;}s.append(1,'#');stack.append(1,'#');//’#’进入分析栈stack.append(1,U[0]);i++;//文法开始符进入分析栈a=s[0];//cout<<stack<<endl;cout<<"步骤分析栈余留输入串所用产生式\n";while(!flag){// cout<<"步骤分析栈余留输入串所用产生式\n"cout<<step<<" "<<stack<<" "<<s<<" ";x=stack[i];stack.erase(i,1);i--;//取栈顶符号x,并从栈顶退出//cout<<x<<endl;if(u.find(x)!=string::npos)//x是终结符的情况{if(x==a){s.erase(0,1);a=s[0];//栈顶符号与当前输入符号匹配,则输入下一个符号cout<<" \n";//未使用产生式,输出空}else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}if(x=='#'){if(a=='#') {flag=1;cout<<"成功\n";}//栈顶和余留输入串都为#,匹配成功else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}if(U.find(x)!=string::npos)//x是非终结符的情况{p=U.find(x);q=u.find(a);if(a=='#') q=t;temp=table[p][q];cout<<temp<<endl;//输出使用的产生式if(temp[0]!=' ')//分析表中对应项不为error{r=9;while(temp[r]==' ') r--;while(r>3){if(temp[r]!='^'){stack.append(1,temp[r]);//将X::=x1x2...的规则右部各符号压栈i++;}r--;}}else{cout<<"error\n";cout<<ss<<"不是该文法的句子\n";break;}}step++;}if(flag) cout<<endl<<ss<<"是该文法的句子\n";}int main(){int i,j;string *G=new string[50];//文法Gstring *P=new string[50];//产生式集合Pstring U,u;//文法G非终结符集合U,终结符集合uint n,t,k;//非终结符、终结符个数,产生式数string *GG=new string[50];//消除左递归后的文法GGstring *PP=new string[50];//文法GG的产生式集合PPstring UU,uu;//文法GG非终结符集合U,终结符集合uint nn,tt,kk;//消除左递归后的非终结符、终结符个数,产生式数string** table;//分析表cout<<" 欢迎使用LL(1)语法分析器!\n\n\n";cout<<"请输入文法(同一左部的规则在同一行输入,例如:E::=E+T|T;用^表示空串)\n";input_grammer(G);preprocess(G,P,U,u,n,t,k);cout<<"\n该文法有"<<n<<"个非终结符:\n";for(i=0;i<n;i++) cout<<U[i];cout<<endl;cout<<"该文法有"<<t<<"个终结符:\n";for(i=0;i<t;i++) cout<<u[i];cout<<"\n\n 左递归检测与消除\n\n";if(eliminate_1(G,P,U,GG)){preprocess(GG,PP,UU,uu,nn,tt,kk);cout<<"该文法存在左递归!\n\n消除左递归后的文法:\n\n"; for(i=0;i<nn;i++) cout<<GG[i]<<endl;cout<<endl;cout<<"新文法有"<<nn<<"个非终结符:\n";for(i=0;i<nn;i++) cout<<UU[i];cout<<endl;cout<<"新文法有"<<tt<<"个终结符:\n";for(i=0;i<tt;i++) cout<<uu[i];cout<<endl;//cout<<"新文法有"<<kk<<"个产生式:\n";//for(i=0;i<kk;i++) cout<<PP[i]<<endl;}else{cout<<"该文法不存在左递归\n";GG=G;PP=P;UU=U;uu=u;nn=n;tt=t;kk=k;}cout<<" 求解FIRST集\n\n";int *empty=ifempty(PP,UU,kk,nn);string* first=FIRST_X(PP,UU,uu,empty,kk,nn);for(i=0;i<nn;i++)cout<<"FIRST("<<UU[i]<<"): "<<first[i]<<endl;cout<<" 求解FOLLOW集\n\n";for(i=0;i<nn;i++)cout<<"FOLLOW("<<UU[i]<<"): "<<FOLLOW[i]<<endl; cout<<"\n\n 构造文法分析表\n\n"; table=create_table(PP,UU,uu,nn,tt,kk,first);cout<<" ";for(i=0;i<tt;i++) cout<<" "<<uu[i]<<" ";cout<<"# "<<endl;for( i=0;i<nn;i++){cout<<UU[i]<<" ";for(j=0;j<t+1;j++)cout<<table[i][j];cout<<endl;}cout<<"\n\n 分析符号串\n\n";cout<<"请输入要分析的符号串\n";cin>>s;analyse(table,UU,uu,tt,s);return 0;}3、程序演示结果(1)输入文法(2)消除左递归(3)求解FIRST和FOLLOW集(4)构造分析表(5)分析符号串匹配成功的情况:匹配失败的情况五、思考和体会1、编写的LL(1)语法分析器应该具有智能性,可以由用户输入任意文法,不需要指定终结符个数和非终结符个数。
词法分析器(含完整源码)
void Scanner(char ch[],int chLen,Table table[Max],int nLine) {
int chIndex = 0;
while(chIndex < chLen) //对输入的字符扫描 { /**************************处理空格和 tab ************************/
六、总结:
词法分析是构造编译器的起始阶段,也是相应比较简单的一个环节。词法分析的主要任 务是:根据构造的状态转换图,从左到右逐个字符地対源程序进行扫描,识别开源程序中具 有独立含义的最小语法单位——符号或单词,如变量标识符,关键字,常量,运算符,界符 等。
然后将提取出的标识符以内码的形式表示,即用 int 类型的数字来表示其类型和在 display 表中的位置,而无须保留原来标识符本身的字符串,这不仅节省了内存空间,也有 利于下一阶段的分析工作。
typedef struct DisplayTable {
int Index; //标识符所在表的下标 int type; //标识符的类型 int line; //标识符所在表的行数 char symbol[20]; //标识符所在表的名称 }Table;
int TableNum = 0; //display 表的下标 char Word[WordMaxNum][20]; //标识符表 char Digit[WordMaxNum][20]; //数字表 int WordNum = 0; //变量表的下标 int DigNum = 0; //常量表的下标 bool errorFlag = 0; //错误标志
当然,在扫描源程序串的同时,进行一些简单的处理,如删除空格、tab、换行等无效 字符,也进行了一些基本的错误处理,如变量长度的判别,有些不合词法规则的标识符判别 等。总之,严格说来,词法分析程序只进行和词法分析相关的工作。
visual studio antlr4 语法
在Visual Studio 中使用Antlr4(另一种语言)进行语法分析,通常需要以下步骤:1. 安装Antlr4:如果你还没有安装Antlr4,你需要首先下载并安装它。
2. 安装Antlr4 Visual Studio 插件:安装了Antlr4 后,你还需要安装一个适用于VisualStudio 的插件,以便更方便地在VS 中使用Antlr4。
一个流行的插件是"Antlr4 Tools for Visual Studio",你可以在Visual Studio 的扩展和更新管理器中搜索并安装它。
3. 创建语法文件:使用Antlr4 语法文件(通常具有 .g4 扩展名)定义你的语法。
这些文件描述了你的语言的语法规则。
4. 生成解析器和词法分析器:使用Antlr4 工具从你的语法文件生成C# 代码。
这通常通过命令行完成,但你也可以在Visual Studio 中使用插件来自动化这个过程。
5. 编写代码以使用解析器和词法分析器:在你的C# 代码中,你需要编写代码来使用Antlr4 生成的解析器和词法分析器。
这通常涉及到创建一个解析器实例,并使用它来解析文本。
6. 测试和调试:最后,你需要测试和调试你的语法分析器以确保它可以正确地解析你的语言。
以下是一个简单的例子,说明如何在Visual Studio 中创建一个基本的Antlr4 项目:1. 安装Antlr4 和插件:按照上面提到的步骤安装Antlr4 和适用于Visual Studio 的插件。
2. 创建新的Antlr4 项目:在Visual Studio 中,创建一个新的项目,并选择"Antlr4Project"。
3. 添加语法文件:在项目中添加一个新的Antlr4 语法文件(.g4 文件)。
4. 定义语法规则:在 .g4 文件中定义你的语法规则。
例如:antlrgrammar MyGrammar;start: expression EOF;expression: NUMBER| ID;NUMBER : [0-9]+ ;ID : [a-zA-Z]+ ;WS : [ \t\n\r]+ -> skip ;生成解析器和词法分析器:在Visual Studio 中,右键点击 .g4 文件,并选择"Generate Code"。
编译原理词法分析器和语法分析器(急急急!!!)
编译原理实验报告词法分析器实验目的1.熟练掌握词法分析程序的基本原理2.掌握词法分析程序的设计和实现实验内容1.针对一个简化的C语言子集完成对它的词法分析程序的设计与实现2.C语言子集的单词符号挤内码值程序代码:#include "stdio.h"#include "string.h"int i,j,k;char s;char a[20],token[20];int letter(){if((s>=97)&&(s<=122))return 1;else return 0;}int digit(){if((s>=48)&&(s<=57))return 1;else return 0;}void get(){s=a[i];i=i+1;}void retract(){i=i-1;}int lookup(){if(strcmp(token, "while")==0)return 1;else if(strcmp(token, "if")==0)return 2;else if(strcmp(token,"else")==0)return 3;else if(strcmp(token,"switch")==0)return 4;else if(strcmp(token,"case")==0)return 5;else return 0;}void main(){printf("输入源程序,结束用'#':\n");i=0;do{i++;scanf("%c",&a[i]);}while(a[i]!='#');i=1;memset(token,0,sizeof(char)*20);j=0;get();while(s!='#'){if(s==' ')get();else{switch(s){case'a':case'b':case'c':case'd':case'e':case'f':case'g':case'h':case'i':case'j':case'k':case'l':case'm':case'n':case'o':case'p':case'q':case'r':case's':case't':case'u':case'v':case'w':case'x':case'y':case'z':while(letter(s)||digit(s)){token[j]=s;j++;get();}retract();k=lookup();if(k==0)printf("(%d,%s)\n",6,token); else printf("(%d,unll)\n",k); break;case'0':case'1':case'2':case'3':case'4':case'5':case'6':case'7':case'8':case'9':while(digit(s)){token[j]=s;j=j+1;get();}retract();printf("(%d,%s)\n",7,token); break;case'+':printf("(+,null)\n"); break;case'-':printf("(-,null)\n");break;case'*':printf("(*,null)\n");break;case'<':get();if(s=='=')printf("(relop,LE)\n");else {retract();printf("(relop,LT)\n");}break;case'=':get();if(s=='=')printf("(relop,EQ)\n");else{retract();printf("(=,null)\n");}break;case';':printf("(;,null)\n");break;default:printf("(%c,error)\n",s);break;}memset(token,0,sizeof(char)*10);j=0;get();}}}运行结果:编译原理实验报告语法分析器实验目的1.熟练掌握语法分析程序的基本原理2.掌握用算符优先分析法来构造,设计优先函数3.掌握语法分析程序的设计与实现实验内容1.针对一个简单文法完成对它的语法分析程序的设计与实现2.通过语法分析程序来完成多输入的算数表达式进行计算并相应得到的对应四元式程序代码:#include <stdio.h>char a[20],optr[10],s,op;int i,j,k,opnd[10],x1,x2,x3;int operand(char s){if((s>='0')&&(s<='9'))return 1;elsereturn 0;}int f(char s){switch(s){case'+':return 6;case'-':return 8;case'*':return 10;case'/':return 12;case'(':return 2;case')':return 12;case'#':return 2;default:printf("error!\n");}}int g(char s){switch(s){case'+':return 5;case'-':return 7;case'*':return 9;case'/':return 11;case'(':return 13;case')':return 2;case'#':return 2;default:printf("error!\n");}}void get(){i=i+1;s=a[i];}void main(){printf("请输入算数表达式,以'#'结束:\n");i=0;do{i=i+1;scanf("%c",&a[i]);}while(a[i]!='#');i=0;j=0;k=0;optr[j]='#';get();while((optr[j] != '#')||(s != '#')){if(operand(s)){opnd[k]=s-'0';k=k+1;get();}else if(f(optr[j])>g(s)){op=optr[j];j=j-1;x2=opnd[k-1];x1=opnd[k-2];k=k-2;switch(op){case'+':x3=x1+x2;break;case'-':x3=x1-x2;break;case'*':x3=x1*x2;break;case'/':x3=x1/x2;break;}opnd[k]=x3;k=k+1;printf("(%c,%d,%d,%d)\n",op,x1,x2,x3);}else if(f(optr[j]) < g(s)){j=j+1;optr[j]=s;get();}else if(f(optr[j]) == g(s)){j=j-1;get();}elseprintf("error!");}}运行结果:。
编译原理语法分析器
编译原理语法分析器编译原理语法分析器是编译器中的重要组成部分,它负责将源代码解析成抽象语法树,为后续的语义分析和代码生成做准备。
本文将介绍语法分析器的原理、分类和常用算法。
一、语法分析器的原理语法分析器的主要任务是根据给定的文法定义,将源代码解析成一个个语法单元,并构建出一棵抽象语法树。
它通过递归下降、预测分析和LR分析等算法来实现。
1. 递归下降法递归下降法是一种基于产生式的自顶向下分析方法。
它从文法的开始符号出发,通过不断地推导和回溯,逐步地构建抽象语法树。
递归下降法易于理解和实现,但对左递归和回溯有一定的局限性。
2. 预测分析法预测分析法也是自顶向下的分析方法,它通过预测下一个输入符号来选择适当的产生式进行推导。
为了提高效率,预测分析法使用预测分析表来存储各个非终结符和终结符的关系。
3. LR分析法LR分析法是一种自底向上的分析方法,它使用LR自动机和LR分析表来进行分析。
LR自动机是一个有限状态控制器,通过状态转移和规约动作来解析源代码。
LR分析表存储了状态转移和规约的规则。
二、语法分析器的分类根据语法分析器的特性和实现方式,可以将其分为LL分析器和LR 分析器。
1. LL分析器LL分析器是基于递归下降法和预测分析法的一类分析器。
它从左到右、从左到右地扫描源代码,并根据预测分析表进行推导。
常见的LL分析器有LL(1)分析器和LL(k)分析器。
2. LR分析器LR分析器是基于LR分析法的一类分析器。
它先通过移进-归约的方式建立一棵语法树,然后再进行规约操作。
LR分析器具有强大的语法处理能力,常见的LR分析器有LR(0)、SLR(1)、LR(1)和LALR(1)分析器。
三、常用的语法分析算法除了递归下降法、预测分析法和LR分析法,还有一些其他的语法分析算法。
1. LL算法LL算法是一种递归下降法的改进算法,它通过构造LL表和预测分析表实现分析过程。
LL算法具有很好的可读性和易于理解的特点。
2. LR算法LR算法是一种自底向上的分析方法,它通过建立LR自动机和构造LR分析表来进行分析。
编译原理实验二: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)⽂法,⽤预测分析表法判断输⼊的符号串是否符合刚才输⼊的⽂法,并打印出分析过程。
编译原理课程设计-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)引言编译器的构造工具是根据用户输入的语言的文法,编译器的构造工具可以生成程序来处理以用户输入的文法书写的文本。
编译原理名词解释
编译原理名词解释1. 词法分析器(Lexer):也称为扫描器(Scanner),用于将源代码分割成一个个单词(Token)。
2. 语法分析器(Parser):将词法分析器生成的单词序列转换成语法树(Parse Tree)或抽象语法树(Abstract Syntax Tree)。
3. 语法树(Parse Tree):表示源代码的语法结构的树状结构,它由语法分析器根据语法规则生成。
4. 抽象语法树(Abstract Syntax Tree):比语法树更加简化和抽象的树状结构,用于表示源代码的语义结构。
5. 语义分析器(Semantic Analyzer):对抽象语法树进行语义检查,并生成中间代码或目标代码。
6. 中间代码(Intermediate code):一种介于源代码和目标代码之间的中间表示形式,可以被不同的优化器和代码生成器使用。
7. 目标代码生成器(Code Generator):将中间代码转换成特定目标平台的机器代码。
8. 优化器(Optimizer):用于对中间代码进行优化,以提高代码的执行效率和资源利用率。
9. 符号表(Symbol Table):用于存储程序中的标识符(变量、函数等)的信息,包括名称、类型等。
10. 语言文法(Grammar):定义了一种语言的语法规则,常用的形式包括上下文无关文法和正则文法。
11. 上下文无关文法(Context-free Grammar):一种形式化的语法表示方法,由产生式和非终结符组成,描述一种语言的句子结构。
12. 语言解释器(Interpreter):将源代码逐行解释执行的程序,不需要生成目标代码。
13. 回溯法(Backtracking):一种递归式的算法,用于在语法分析过程中根据产生式进行选择。
14. 正则表达式(Regular Expression):用于描述一类字符串的表达式,可以用于词法分析中的模式匹配。
15. 自顶向下分析(Top-down Parsing):从文法的起始符号开始,按照语法规则逐步构建语法树的过程。
编译原理课程(词法分析器及语法分析器)
编译原理实验报告词法分析器与语法分析器I. 问题描述设计、编制并调试一个词法分析子程序,完成识别语言单词的任务;设计、编制、调试一个语法分析程序,并用它对词法分析程序所提供的单词序列进行语法检查和结构分析。
ii. 设计简要描述界面需求:为了更加形象的模拟过程,此实验使用图形界面。
要求从图形界面上输入输入串,点击词法分析,可以将词法分析后识别的单词符号显示,点击语法分析,可以将语法分析的堆栈过程显示,并且显示结果(是否是符合文法的句子),清空则可以将所有置空。
功能分析:1、由用户输入输入串;2、用户点击“词法分析”,可以将词法分析后识别的单词符号显示。
3、用户点击语法分析,可以将语法分析的堆栈过程显示,并且显示结果(是否是符合文法的句子)4、用户点击清空,则将界面所有组件置为空思路描述:一、设计构想:本实验决定编写一个简易C语言的词法分析器和语法分析器。
使其能够识别while,if等关键字,可以判断赋值语句、条件语句、循环语句。
二、文法分析1、需要识别的关键字及其识别码有:关键字识别码关键字识别码关键字识别码main 0 - 11 ;22int 1 * 12 > 23char 2 / 13 < 24if 3 ( 14 >= 25else 4 ) 15 <= 26for 5 [ 16 == 27while 6 ] 17 != 28ID 7 { 18 ERROR -1NUM 8 } 19= 9 , 20+ 10 : 212、文法〈程序〉→ main()〈语句块〉〈语句块〉→{〈语句串〉}〈语句串〉→〈语句〉;〈语句串〉|〈语句〉;〈语句〉→〈赋值语句〉|〈条件语句〉|〈循环语句〉〈赋值语句〉→ ID =〈表达式〉;〈条件语句〉→ if〈条件〉〈语句块〉〈循环语句〉→ while〈条件〉〈语句块〉〈条件〉→(〈表达式〉〈关系符〉〈表达式〉)〈表达式〉→〈表达式〉〈运算符〉〈表达式〉|(〈表达式〉)|ID|NUM〈运算符〉→+|-|*|/〈关系符〉→<|<=|>|>=|=|!>转化为符号表示:S→ main() K|空K→ { C }C→Y;C |空Y→F | T | XF→ ID = BT→ if J KX→ while J KJ→( B G B )B→ B Z B |( B )| ID | NUMZ→ + | - | * | /G→< | <= | > | >= | == | !>表示含义:S:程序 K:语句块 C:语句串 Y:语句 F :赋值语句T:条件语句 X:循环语句 J:条件 B:表达式 I:项 Z :运算符G:关系符3、LL(1)分析表(1),求出first集及follow集:FIRST(S)={mian}FIRST(K)={{}FIRST(C)= FIRST(Y)= {ID,if,while,空};FIRST(Y)= FIRST(F)+ FIRST(T)+ FIRST(X)={ID,if,while};FIRST(F)={ID};FIRST(T)={if};FIRST(X)={while};FIRST(J)= FIRST(B)={};FIRST(B)={(,ID,NUM };FIRST(Z)={+,-,*,/}FIRST(G)={<,<= ,>,>=,==,!= };FOLLO W(S)={#};FOLLO W(K)={;};FOLLO W(C)={}};FOLLO W(Y)={;}FOLLO W(F)={;};FOLLO W(T)={;};FOLLO W(X)={;};FOLLO W(J)={{,;};FOLLO W(B)={+,-,*,/,),<,<= ,>,>=,==,!=,;};FOLLO W(B’)={+,-,*,/,),<,<= ,>,>=,==,!=,;};FOLLO W(Z)={(,ID,NUM };FOLLO W(G)={(,ID,NUM };(2)消除左递归,拆分文法关系并编号0、S→ 空1、S→ main() K2、K→ { C }3、C→Y;C4、C→空5、Y→ F6、Y→ T7、Y→ X8、F→ ID = B9、T→ if J K10、X→ while J K11、J→( B G B )12、 B→( B )B'13、B→ ID B'14、B→ NUM B'15、B'→ BZB B'16、B'→空17、Z→ +18、Z→ -19、Z→ *20、Z→ /21、 G→ <22、 G→ <=23、 G→ >24、 G→ >=25、 G→ ==26、 G→ !=(3)构造LL(1)分析表(注:在表中用上一步的编号表示所需要的产生式)main 空( ) { } ; = if while ID num + - * / < <= > >= == != #iii. 详细设计描述 项目构架:各函数功能介绍:1、word.wordList 包(存储了关键字):word :此类是定义了存储关键字的结构:包括String 型的关键字,和int 型的识别符。
java antlr语法
Java ANTLR语法1. 介绍在Java编程中,ANTLR(ANother Tool for Language Recognition)是一种非常有用的工具,用于构建语法分析器。
它可以根据给定的语法规则生成解析器和词法分析器,并且可以应用于生成代码、进行语法检查、执行语义分析等多个领域。
2. ANTLR的基本原理ANTLR的基本原理是使用上下文无关文法(Context-Free Grammar,简称CFG)描述语言的语法规则,并根据这些规则生成解析器和词法分析器。
ANTLR支持LL()语法和LR()语法两种类型,并可以通过语法规则的定义灵活地生成不同类型的解析器。
2.1 上下文无关文法上下文无关文法是一种形式化的语法规范,用于描述一类形式语言的句法结构。
它包含四个部分:终结符(Terminals)、非终结符(Non-terminals)、产生式规则(Productions)和起始符(Start symbol)。
ANTLR使用扩展的巴科斯范式(Extended Backus-Naur Form,简称EBNF)来描述上下文无关文法。
2.2 语法规则定义在ANTLR中,语法规则由标识符、参数列表、返回类型和规则体四个部分组成。
语法规则的定义基本形式如下:ruleName [返回类型] [参数列表]: 执行体;其中,ruleName表示规则名称,返回类型和参数列表可选。
执行体是规则的具体实现,用于描述规则的语义。
2.3 解析器和词法分析器的生成在ANTLR中,通过定义完整的语法规则,并使用ANTLR工具根据这些规则生成解析器和词法分析器。
生成的解析器和词法分析器可以直接应用于源代码的解析和语法检查。
3. ANTLR语法规则示例下面是一个简单的ANTLR语法规则示例,用于解析简单的数学表达式:grammar MathExpression;// 语法规则start : expression EOF;expression : expression op=('*' | '/')| expression op=('+' | '-')| '(' expression ')'| NUMBER;// 词法规则NUMBER : DIGIT+;WS : [ \t\n\r]+ -> skip;// 辅助规则fragment DIGIT : [0-9];4. ANTLR语法规则说明上述示例中,定义了一个名为MathExpression的语法规则,用于解析简单的数学表达式。
ll 1 语法分析实验报告
ll 1 语法分析实验报告语法分析实验报告一、引言语法分析是编译器中的重要步骤之一,它负责将输入的源代码转化为语法树或抽象语法树,以便后续的语义分析和代码生成。
本实验旨在通过实现一个简单的LL(1)语法分析器,加深对语法分析原理和算法的理解。
二、实验目的1. 理解LL(1)语法分析的原理和算法;2. 掌握使用LL(1)文法描述语言的方法;3. 实现一个简单的LL(1)语法分析器。
三、实验环境本实验使用C++编程语言,开发环境为Visual Studio。
四、实验步骤1. 设计LL(1)文法在开始实现LL(1)语法分析器之前,我们需要先设计一个LL(1)文法。
LL(1)文法是一种满足LL(1)分析表构造要求的文法,它能够保证在语法分析过程中不会出现二义性或回溯。
通过仔细分析待分析的语言的语法规则,我们可以设计出相应的LL(1)文法。
2. 构造LL(1)分析表根据设计的LL(1)文法,我们可以构造出对应的LL(1)分析表。
LL(1)分析表是一个二维表格,其中的行表示文法的非终结符,列表示文法的终结符。
表格中的每个元素表示在某个非终结符和终结符的组合下,应该进行的语法分析动作。
3. 实现LL(1)语法分析器基于构造的LL(1)分析表,我们可以开始实现LL(1)语法分析器。
分析器的主要工作是根据输入的源代码和LL(1)分析表进行分析,并输出语法树或抽象语法树。
五、实验结果与分析经过实验,我们成功实现了一个简单的LL(1)语法分析器,并对一些简单的语言进行了分析。
实验结果表明,我们设计的LL(1)文法和LL(1)分析表能够正确地进行语法分析,没有出现二义性或回溯。
六、实验总结通过本次实验,我们深入学习了LL(1)语法分析的原理和算法,并通过实现一个简单的LL(1)语法分析器加深了对其的理解。
实验过程中,我们发现LL(1)文法的设计和LL(1)分析表的构造是实现LL(1)语法分析器的关键。
同时,我们也意识到LL(1)语法分析器在处理复杂的语言时可能会面临一些困难,需要进一步的研究和优化。
(完整版)编译原理词法分析和语法分析报告+代码(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用来存放单词符号的种别码。
3.6 语法分析器的自动生成解析
Yacc生成的语法分析器的工作原理:
Yacc生成的语法分析器由一个带栈的有穷 自动机组成。 此状态机只有四种动作:移进(shift)、规 约(reduce)、接受(accept)和错误(error)
输入符号串 总控程序 输出
状态与符号栈2018/10/10来自Action/Goto表
11
支持例程:
%% void main() { printf("Yacc Starting...\n"); yyparse(); } yylex(){ int c; /* while ( ( c = getchar ( ) ) == ' ' ); if ( ( c == '.' ) || (isdigit(c) ) ) { ungetc (c, stdin); scanf ( "%lf", &yylval); return NUMBER; } return c; */ /* 接受实数 */ 2018/10/10
12
支持例程(2):
c=getchar(); if (isdigit(c)){ yylval = c - '0'; return NUMBER; }; return c;
/* 接受1位整数 */
} yyerror(char *s) { fprintf(stderr,"...%s \n",s); } alloca() { }
编 译 原 理 Principle of Compiling
郭 一 晶
厦门大学嘉庚学院 2007 年 9 月
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
语法分析实验报告一、实验目的:1. 了解单词(内部编码)符号串中的短语句型结构形成规律。
2. 理解和掌握语法分析过程中语法分析思想(LL,LR)的智能算法化方法。
二、实验内容:构造自己设计的小语言的语法分析器:1. 小语言的语法描述(语法规则)的设计即文法的设计;2. 把文法形式符号中所隐含的信息内容挖掘出来并用LL或LR 的资料形式(分析表)表示出来;3. 语法分析的数据输入形式和输出形式的确定;4. 语法分析程序各个模块的设计与调试。
主要设备和材料:电脑、winxp操作系统、VC语言系统三、实验分工:四、实验步骤:1、语法规则①<程序>::= {<变量定义语句>|<赋值语句>|<条件语句> |<循环语句> }②<变量定义语句>::=var 变量{,变量};③<赋值语句>::=变量:= <表达式>;④<表达式>::=标识符{运算符标识符};⑤<标识符>::=变量|常量⑥<运算符>::=+ | - | * | / | >= | <=⑦<条件语句>::=<if语句>[<else语句>]⑧<if语句>::=if(表达式) then[begin] {赋值语句|条件语句| 循环语句}[end]⑨<else语句>::=[begin] {赋值语句|条件语句| 循环语句} [end]⑩<循环语句>::=while(表达式) [begin] {赋值语句| 条件语句| 循环语句} [end]<输出语句>::=prn 表达式--注1:若if语句、else语句、循环语句中出现begin,后面的end 必须出现,即begin与end同对出现--注2:if、while后的"(",")"表示终结符,而不是定义成分优先的说明符号2、分析表:: = 变量常量,;运算()符变量定义->②->②->②->②赋值语句->③->③->③->③->③条件语句->⑦->⑦->⑦->⑦->⑦->⑦->⑦循环语句->⑩->⑩->⑩->⑩->⑩->⑩->⑩输出语句->->->分析表(续):while var begin end if then prn 变量定义->②赋值语句条件语句->⑦->⑦->⑦->⑦循环语句->⑩->⑩->⑩输出语句-> 3、调试和测试五、源代码(见附录):六、实验总结:本实验在词法分析的基础上,对提取出的标识符进行语法判断。
对已有的语法规则运用LL(1)文法判别并进行构造分析表时,遇到的最大困难是:当发生规约冲突时,该如何处理。
如对于产生式s-->aAb,当对a进行规约时,满足语法规则的β(用户输入串中当前要进行规约的标识符)只有有限种,而不满足的却有无限种情况。
当发生规约冲突时,如何在这无限种情况中,确定冲突的具体信息,以便用户查找。
在反复的尝试和验证中,我们发现发生冲突的用户输入串满足一定的规律,且按这种规律可以把这无限种情况化归为有限类,于是我们找出其中规律并进行划分,然后再对这些有限类冲突进行处理。
七、实验心得:通过这次实验有以下几点收获:1.LR(1)的构造使得对理论的知识理解的更加透彻。
其中LR(1)分析表构造了很多遍,一直无法得到正确结果,这是恒心的考验。
2.在写程序中用类数组来存放单词属性使得对单词各项值的调用更加方便,特别是对出错信息的检测有很大的作用。
3.本实验是在词法基础上的更进一步,在词法程序上添加语法程序,更加理解二者之间的关系。
词法分析为语法分析提供了词法单元,方便分析,使程序模块化,易于读懂。
附录:#include <iostream>#include <fstream>#include <string>#include <math.h>#include <ctype.h>#include <cstdlib>using namespace std;#define Max 655 //最大代码长度#define WordMaxNum 256 //变量最大个数#define DigitNum 256 //常量最大个数#define MaxKeyWord 32 //关键字数量#define MaxOptANum 8 //运算符最大个数#define MaxOptBNum 4 //运算符最大个数#define MaxEndNum 11 //界符最大个数typedef struct DisplayTable{int Index; //标识符所在表的下标int type; //标识符的类型int line; //标识符所在表的行数char symbol[20]; //标识符所在表的名称}Table;int TableNum = 0; //display表的表项总数char Word[WordMaxNum][20]; //标识符表char Digit[WordMaxNum][20]; //数字表int WordNum = 0; //变量表的下标int DigNum = 0; //常量表的下标bool errorFlag = 0; //错误标志int T ableIndex = -1; //display 表的下标索引int beginCount = 0;//遇到begin加1,遇到end减1int ifCount = 0; //遇到if加1Table *table = new Table[Max];//关键字const char* const KeyWord[MaxKeyWord] = {"and","array", "begin","case","char","constant","do","else","end","false","for","if","input","integer","not","of","or","output", "packed","procedure","program","read","real","repeat","set", "then", "to", "type", "until", "var","while", "with","prn"};// 单目运算const char OptA[] = {'+','-','*','/','=','#','<','>'};//双目运算符const char *OptB[] = {"<=",">=",":=","<>"};// 界符const char End[] = {'(', ')' , ',' , ';' , '.' , '[' , ']' , ':' , '{' , '}' , '"'};void error(char str[20],int nLine, int errorType){errorFlag = 1;cout <<" \nError : ";switch(errorType){case 1:cout << "第" << nLine-1 <<"行" << str << " 变量的长度超过限制!\n";break;case 2:cout << "第" << nLine-1 <<"行" << str << " 小数点错误!\n";break;case 3:cout << "第" << nLine-1 <<"行" << str << " 常量的长度超过限制!\n";break;}//switch}//errorvoid Scanner(char ch[],int chLen,int nLine){int chIndex = 0;while(chIndex < chLen) //对输入的字符扫描{/****************处理空格和tab***************************/ //忽略空格和tabwhile(ch[chIndex] == ' ' || ch[chIndex] == 9 ){ chIndex ++; }/*************************处理换行符*********************///遇到换行符,行数加1while(ch[chIndex] == 10){ nLine++;chIndex ++;}/***************************标识符**********************/ if( isalpha(ch[chIndex])) //以字母、下划线开头{char str[256];int strLen = 0;//是字母、下划线while(isalpha(ch[chIndex]) || ch[chIndex] == '_' ) {str[strLen ++] = ch[chIndex];chIndex ++;while(isdigit(ch[chIndex]))//不是第一位,可以为数字{str[strLen ++] = ch[chIndex];chIndex ++;}}str[strLen] = 0; //字符串结束符if(strlen(str) > 20) //标识符超过规定长度,报错处理{error(str,nLine,1);}else{int i;for(i = 0;i < MaxKeyWord; i++) //与关键字匹配//是关键字,写入table表中if(strcmp(str, KeyWord[i]) == 0){strcpy(table[TableNum].symbol,str);table[TableNum].type = 1; //关键字table[TableNum].line = nLine;table[TableNum].Index = i;TableNum ++;break;}if(i >= MaxKeyWord) //不是关键字{table[TableNum].Index = WordNum;strcpy(Word[WordNum++],str);table[TableNum].type = 2; //变量标识符strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;TableNum ++;}}}/**************************常数**************************/else if(isdigit(ch[chIndex])) //遇到数字{int flag = 0;char str[256];int strLen = 0;//数字和小数点while(isdigit(ch[chIndex]) || ch[chIndex] == '.') {//flag表记小数点的个数,0时为整数,1时为小数,2时出错if(ch[chIndex] == '.')flag ++;str[strLen ++] = ch[chIndex];chIndex ++;}str[strLen] = 0;if(strlen(str) > 20) //常量标识符超过规定长度20,报错处理{error(str,nLine,3);}if(flag == 0){table[TableNum].type = 3; //整数}if(flag == 1){table[TableNum].type = 4; //小数}if(flag > 1){error(str,nLine,2);}table[TableNum].Index = DigNum;strcpy(Digit[DigNum ++],str);strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;TableNum ++;}/*************************运算符************************/ else{//用来区分是不是无法识别的标识符,0为运算符,1为界符int errorFlag;char str[3];str[0] = ch[chIndex];str[1] = ch[chIndex + 1];str[2] = '\0';int i;for( i = 0;i < MaxOptBNum;i++)//MaxOptBNum) if(strcmp(str,OptB[i]) == 0){errorFlag = 0;table[T ableNum].type = 6;strcpy(table[TableNum].symbol,str);table[T ableNum].line = nLine;table[T ableNum].Index = i;TableNum ++;chIndex = chIndex + 2;break;}if(i >= MaxOptBNum){for( int k = 0;k < MaxOptANum; k++)if(OptA[k] == ch[chIndex]){errorFlag = 0;table[TableNum].type = 5;table[TableNum].symbol[0] = ch[chIndex];table[TableNum].symbol[1] = 0;table[TableNum].line = nLine;table[TableNum].Index = k;TableNum ++;chIndex ++;break;}/*************************界符************************/ for(int j = 0;j < MaxEndNum;j ++)if(End[j] ==ch[chIndex]){errorFlag = 1;table[TableNum].line = nLine;table[TableNum].symbol[0] = ch[chIndex];table[TableNum].symbol[1] = 0;table[TableNum].Index = j;table[TableNum].type = 7;TableNum ++;chIndex ++;}/********************其他无法识别字符*****************/ //开头的不是字母、数字、运算符、界符if(errorFlag != 0 && errorFlag != 1) { char str[256];int strLen = -1;str[strLen ++] = ch[chIndex];chIndex ++;while(*ch != ' ' || *ch != 9 || ch[chIndex] != 10){str[strLen ++] = ch[chIndex];chIndex ++;}str[strLen] = 0;table[TableNum].type = 8;strcpy(table[TableNum].symbol,str);table[TableNum].line = nLine;table[TableNum].Index = -2;TableNum ++;}}}}}/**************把十进制小数转为16进制******************/ void Trans(double x,int p) //把十进制小数转为16进制{int i=0; //控制保留的有效位数while(i<p){if(x==0) //如果小数部分是0break; //则退出循环else{int k=int(x*16); //取整数部分x=x*16-int(k); //得到小数部分if(k<=9)cout<<k;elsecout<<char(k+55);};i++;};};/***********************语法错误*************************/void Gerror(int errorType,int nIndex){errorFlag = 1;switch(errorType){case 1:cout << "第" << table[nIndex].line <<"行:" << table[nIndex].symbol <<" 应该为赋值号:= \n";break;case 2:cout << "第" << table[nIndex].line <<"行:" <<table[nIndex].symbol <<" 应为变量\n";break;case 3:cout << "第" << table[nIndex].line <<"行:" <<table[nIndex].symbol <<" 应为逗号\n";case 4:cout << "第" << table[nIndex].line <<"行:" << table[nIndex].symbol <<" 应为分号\n";break;case 5:cout << "第" << table[nIndex].line <<"行:" << table[nIndex].symbol <<" 应为运算符\n";break;case 6:cout << "第" << table[nIndex].line <<"行:" << table[nIndex].symbol <<" 应为变量或常量\n";break;case 7:cout << "第" <<table[T ableIndex].line <<"行"<< table[nIndex].symbol << "与"<<table[TableIndex + 1].symbol<<"之间缺少运算符\n";break;case 8:cout << "第" << table[nIndex].line <<"行:" << table[nIndex + 1 ].symbol <<" 应为'(' \n";case 9:cout << "第" <<table[T ableIndex].line <<"行"<< table[TableIndex].symbol << "与"<<table[nIndex + 1].symbol <<"之间缺少'(' \n";break;case 10:cout << "第" << table[T ableIndex - 1].line<< " 行: 缺少'then'" << endl;break;case 11:cout << "第" << table[T ableIndex].line << " 行:"<<table[nIndex].symbol << "应为then \n"; break;case 12:cout << "第" << table[T ableIndex].line << " 行: end 后不能接" <<table[TableIndex].symbol << endl;break;case 13:cout << "第" << table[nIndex].line <<"行:"<< table[nIndex - 1].symbol <<"与"<<table[TableIndex].symbol <<"之间缺少变量\n";break;case 14:cout << "第" <<table[nIndex ].line <<"行"<< table[nIndex ].symbol << "后缺少';' \n";break;case 15:cout << "第" << table[T ableIndex].line << " 行:"<<table[nIndex].symbol << "应为')' \n";break;case 16:cout << "第" << table[T ableIndex].line<< " 行,begin 后不能接"<<table[TableIndex].symbol << endl;break;}}/************************表达式判断********************/bool express(){while(1 )if(table[TableIndex].type==2||table[TableIndex].type == 3 ){if(table[T ableIndex].type==3&&table[TableIndex+ 1].type == 2 && table[TableIndex].line == table[TableIndex + 1].line){Gerror(7,T ableIndex); //出错信息:该处缺少运算符//TableIndex = TableIndex + 2;TableIndex ++;}if(table[T ableIndex].line != table[T ableIndex + 1].line){// Gerror(14,T ableIndex); //出错信息:该语句缺少分号return 1;}TableIndex ++;}else{if(table[T ableIndex].type == 5||table[TableIndex].type == 6)Gerror(13,T ableIndex);TableIndex ++;}else{Gerror(6,TableIndex); //出错信息:该处应为变量或常量}TableIndex ++;}if(table[T ableIndex].type ==5|| table[TableIndex].type == 6 ) TableIndex ++;else if(table[T ableIndex].type == 7)return 1;else if(TableIndex >= TableNum) //|| ){Gerror(14,T ableIndex); //出错信息:该语句缺少分号return 1;}else{Gerror(5,T ableIndex); //出错信息:此处应为运算符TableIndex ++;}}}/*******************赋值语句判断*************************/ bool Assign() //赋值语句的判断{TableIndex ++;if(strcmp( ":=" , table[TableIndex].symbol) == 0){TableIndex ++;}else{Gerror(1,T ableIndex); //出错信息:赋值号应该为":="TableIndex ++;}if(express()) //":="后可以为变量或常量{if(strcmp(";",table[TableIndex].symbol) == 0){return 1;}else{if(TableIndex >= TableNum){Gerror(14,T ableIndex); //出错信息:该语句缺少分号return 1;}else if(table[T ableIndex].line != table[TableIndex + 1].line) {Gerror(14,T ableIndex); //出错信息:该语句缺少分号return 1;//TableIndex ++;}}}else{Gerror(6,T ableIndex); //出错信息:":="后应为变量或常量TableIndex ++;}return 0;}/**********************语句判断*************************/ bool judge() //条件、循环、初始化语句的判断{/**************************begin**********************/if(strcmp("begin",table[T ableIndex].symbol)==0) //匹配begin {beginCount ++;if(table[TableIndex + 1].type == 7){TableIndex ++;cout << "第" << table[T ableIndex].line<< " 行,begin 后不能接"<<table[TableIndex].symbol << endl;return 1;}}/**************************end***********************/if(strcmp("end",table[TableIndex].symbol) == 0) //匹配end {beginCount --;if(TableIndex < TableNum)if(table[T ableIndex+1].type==7||table[TableIndex+ 1].type == 8){TableIndex ++;Gerror(12,T ableIndex);return 1;}}/**************************else**********************/if(strcmp("else",table[TableIndex].symbol) == 0) //匹配else {ifCount --;return 1;}if(strcmp("prn",table[TableIndex].symbol) == 0) //匹配prn {TableIndex ++;if(table[TableIndex].type == 2 || table[TableIndex].type == 3) // prn 后为变量或常量{TableIndex ++;//语句结束,“;”if(strcmp(";",table[TableIndex].symbol) == 0) {return 1;}else{Gerror(4,TableIndex);//出错信息:此处应为";"}} //ifelse{Gerror(2,T ableIndex);//出错信息:此处应为变量TableIndex ++;}}//if_prn/**********************var变量定义**********************/if(strcmp("var",table[TableIndex].symbol) == 0)// var a,b,c; {TableIndex ++;if(table[T ableIndex].type != 2){if(strcmp(",",table[TableIndex].symbol) == 0)Gerror(13,T ableIndex);else Gerror(2,TableIndex);//出错信息:此处应为变量}TableIndex ++;if(strcmp(",",table[TableIndex].symbol) !=0){Gerror(3,TableIndex); //出错信息:此处应为","TableIndex ++;}while(1){while(strcmp(",",table[TableIndex].symbol)==0){TableIndex = TableIndex + 1;if(table[T ableIndex].type !=2){Gerror(2,TableIndex);//出错信息:此处应为变量TableIndex ++;}TableIndex ++;}if(strcmp(";",table[TableIndex].symbol)==0){return 1;}else{Gerror(4,TableIndex);//出错信息:此处应为分号";"return 0;}}}/*****************if语句判断************************///if语句else if(strcmp("if",table[TableIndex].symbol) == 0){ifCount ++; //if个数加1if(table[TableIndex +1].type == 2 || table[T ableIndex + 1].type == 3){Gerror(9,TableIndex); //出错信息:此处缺少')'TableIndex ++;}else if(strcmp("(",table[T ableIndex + 1].symbol) != 0) {Gerror(8,TableIndex);//出错信息:此处应为分号"("}TableIndex = TableIndex + 2;if(express()){if(strcmp(")",table[TableIndex].symbol) == 0) //'('匹配{TableIndex ++;if(strcmp("begin",table[T ableIndex ].symbol) == 0){beginCount ++;if(table[T ableIndex + 1].type == 7){Gerror(16,T ableIndex);TableIndex ++;return 1;}Gerror(10,T ableIndex);//出错信息:此处缺少"then"return 0;}if(strcmp("then",table[TableIndex].symbol) != 0){Gerror(11,T ableIndex);//出错信息:此处应为"then"return 0;}//if_thenelse{return 1;}}//if_)else{Gerror(15,T ableIndex);return 0;}} //if_express}//if_if//return 1;}int main(){ifstream in;ofstream out;char in_file_name[26],out_file_name[26];char ch[Max];cin.getline(ch,Max,'#');int nLine = 1;/**********************调用词法分析**********************/ Scanner(ch, strlen(ch),nLine);//for(int i = 0; i < TableNum;i ++)// cout << table[i].type<< " "<< table[i].symbol<< ""<<table[i].Index<<" "<<table[i].line<< endl;/**********************调用语法分析**********************/ cout << endl << "语法分析结果:\n "<< endl;while(TableIndex <= TableNum){TableIndex ++;if(table[T ableIndex].type == 1)judge();else if(table[T ableIndex].type == 2)Assign(); //赋值语句}if(ifCount < 0){errorFlag = 1;cout << "程序缺少if \n";}if(beginCount <0){errorFlag = 1;cout << "程序缺少begin \n";}if(beginCount >0){errorFlag = 1;cout << "程序缺少end \n"; }if(errorFlag == 0){cout << "语法分析成功!";}return 0;}。