语法分析器的设计实验报告一、实验内容语法分析程序用LL(1)语法分析方法。
首先输入定义好的文法书写文件(所用的文 法可以用LL(1)分析),先求出所输入的文法的每个非终结符是否能推出空, 再分 别计算非终结符号的FIRST 集合,每个非终结符号的FOLLOW 集合,以及每个 规则的SELECT 集合,并判断任意一个非终结符号的任意两个规则的 SELECT 集的交集是不是都为空,如果是,则输入文法符合 LL(1)文法,可以进行分析。
对于文法: G[E]: E->E+T|T T->T*F|F F->i|(E)分析句子i+i*i 是否符合文法。
二、基本思想1、语法分析器实现语法分析是编译过程的核心部分,它的主要任务是按照程序的语法规则,从由词 法分析输出的源程序符号串中识别出各类语法成分, 同时进行词法检查,为语义 分析和代码生成作准备。
这里采用自顶向下的 LL(1)分析方法。
语法分析程序的流程图如图5-4所示。
该程序可分为如下几步:读入文法 判断正误若无误,判断是否为LL(1)文法 若是,构造分析表; 由句型判别算法判断输入符号串是为该文法的句型。
三、核心思想该分析程序有15部分组成:(1) 首先定义各种需要用到的常量和变量; (2) 判断一个字符是否在指定字符串中;(1) (2) (3) (4)(5)(3) (4) (5)(6)(7)(8)(9)(10) (11) (12) (13) (14)(15) 下面是其中几部分程序段的算法思想: 1、求能推出空的非终结符集I 、实例中求直接推出空的 empty 集的算法描述如下: void emp (char c ){ 参数 c 为空符号 chartemp[10]; 定义临时数组 int i;for (i=0;i<=count-1;i++) 从文法的第一个产生式开始查找 {if 产生式右部第一个符号是空符号并且右部长度为 then 将该条产生式左部符号保存在临时数组 将临时数组中的元素合并到记录可推出}n 、求某一符号能否推出&int _emp (char c ) {//若能推出 &,返回 1 ;否则,返回 0int i,j,k,result=1,mark=0; char temp[20]; temp[0]=c; temp[1]='\0';存放到一个临时数组 empt 里,标识此字符已查找其是否可推出空字 如果 c 在可直接推出空字的empty[] 中,返回 1 for (i=0;;i++){if (i==count )return (0);找一个左部为 c 的产生式 j=strlen (right[i]);if 右部长度为 if 右部长度为 else{读入一个文法; 将单个符号或符号串并入另一符号串; 求所有能直接推出 & 的符号;求某一符号能否推出‘ & '; 判断读入的文法是否正确; 求单个符号的 FIRST ; 求各产生式右部的 FIRST ; 求各产生式左部的 FOLLOW ; 判断读入文法是否为一个 LL (1) 文法; 构造分析表 M ; 句型判别算法; 一个用户调用函数; 主函数;1, temp 中 & 符号的数组 empty 中。
//j 为 c 所在产生式右部的长度1且右部第一个字符在 empty[]中.then 返回1(A->B,B 可推出空) 1 但第一个字符为终结符 ,then 返回 0(A->a,a 为终结符 )for(k=0;k<=j-1;k++){查找临时数组 empt[]. 并标记 mark-=1(A->AB)if 找到的字符与当前字符相同 (A->AB) 结束本次循环 else(mark 等于 0)查找右部符号是否可推出空字 ,把返回值赋给 result 把当前符号加入到临时数组empt[] 里.当前字符不能推出空字且还没搜索完全部的产生式 then 跳出本次循环继续搜索下一条产生式 else if // 当前字符可推出空字 ,返回}2、计算每个符号的 first 集: 实例中求单个符号的 FIRST 集的算法描述如下: void first2(int i) { 参数 i 为符号在所有输入符号中的序号 c 等于指示器 i 所指向的符号 在保存终结符元素的 termin[] 数组查找 cif c 为终结符(c € V T ), then FIRST(c)={c} 在保存终结符元素的 non_ter[] 数组查找 c if c 是非终结符(c € V N )在所有产生式中查找 c 所在的产生式 if 产生式右部第一个字符为终结符或空 把 a 或 & 加进 FIRST(c) if 产生式右部第一个字符为非终结符if 产生式右部的第一个符号等于当前字符 then 跳到下一条产生式进行查找 求当前非终结符在所有字符集中的位置 if 当前非终结符还没求其 FIRST 集 then 查找它的FIRST 集并标识此符号已求其 FIRST 集 求得结果并入到 c 的 FIRST 集 .if 当前产生式右部符号可推出空字且当前字符不是右部的最后一个字符 获取右部符号下一个字符在所有字符集中的位置 if 此字符的 FIRST 集还未查找 then 找其FIRST 集 ,并标其查找状态为 1 把求得的 FIRST 集并入到 c 的 FIRST 集 . if 当前右部符号串可推出空且是右部符号串的最后一个字符(即产生式为 c7丫1丫2…Y k ,若对一切 1<=i<=k ,均有 & € FIRST(Y i ),则将 & €符号加进 FIRST(c)) then把空字加入到当前字符 c 的FIRST 集.else不能推出空字则结束循环标识当前字符c 已查找其FIRST 集.}3. 计算 FOLLOWFOLLOW 集的构造可用如下方法来求:对于文法中的符号 X V N ,其FOLLOW(A)集合可反复应用下列规则计算,直到FOLLOW(A)集合不再增大为止。
(1) 对于文法开始符号 S ,因为S S ,故# FOLLOW(S); (2) 若 A7 B ,其中 B V N ,(V T V N )*、 (V T V N )+,贝UFIRST( )-{ } FOLLOW(B); (3) 若 A 7 B 或 A 7 B (禺),贝yFOLLOW(A) FOLLOW(B)。
FOLLOW 集的算法描述如下: void FOLLOW(i nt i)}if(即 C7 a (a € V T )或 &) thenthenthenX为待求的非终结符把当前字符放到一临时数组fo叩中,标识求已求其FOLLOW集.避免循环递归if X 为开始符号then # € FOLLOW(X)对全部的产生式找一个右部含有当前字符X的产生式注:比如求FOLLOW(B)则找A7a X或A7 X (兰> £ )的产生式if X在产生式右部的最后(形如产生式A7 X) then 查找非终结符A是否已经求过其FOLLOW 集.避免循环递归if 非终结符A已求过其FOLLOW集thenFOLLOW(A) € FOLLOW(X)继续查下一条产生式是否含有Xelse求A之FOLLOW 集,并标识为A已求其FOLLOW 集else if X不在产生式右部的最后(形如A 7 B ) thenif右部X后面的符号串能推出空字then查找是否已经求过其FOLLOW集.避免循环递归if 已求过的FOLLOW 集thenFOLLOW(A) € FOLLOW(B)结束本次循环else if 不能推出空字then求FIRST()把FIRST()中所有非空元素加入到FOLLOW(B)中标识当前要求的非终结符X的FOLLOW 集已求过4.计算 SELECT!SELECT集的构造算法如下:对所有的规则产生式 A 7 X:(1)若X 不能推出空字,贝y SELECT(A 7X) = FIRST(x);(2)若X 可推出空字,贝U SELECT(A 7x)=FIRST(x) - { } FOLLOW(A)。
算法描述如下:for(i=0;i<=产生式总数-1;i++)先把当前产生式右部的FIRST集(一切非空元素,不包括£放入到当前产生式的SELECT(i);if 产生式右部符号串可推出空字 then 把 i 指向的当前产生式左部的非终结符号的 FOLLOW 集并入到 SELECT(i) 中 5.判断是否 LL(1) 文法 要判断是否为 LL(1) 文法,需要输入的文法 G 有如下要求: 具有相同左部的规则的 SELECT 集两两不相交,即: SELECT(A T ) nSELECT(A )= 如果输入的文法都符合以上的要求,则该文法可以用 算法描述如下: 把第一条产生式的 SELECT(0) 集放到一个临时数组 temp[] 中 for(i=1;i<= 产生式总数 -1;i++) 求 temp 的长度 length if i 指向的当前产生式的左部等于上一条产生式的左部 temp 数组中 length 加上 SELECT (i) 的长度LL(1) 方法分析。
then 把 SELECT(i) 并入到 If temp 的长度小于 返回 0else 把 temp 清空 把 SELECT (i) 存放到 结果返回 1 ; 四、算法 temp 中#include<stdlib.h> #include<stdio.h> #include<string.h> /*******************************************/ int count=0; int number;char start; char termin[50]; char non_ter[50]; char v[50]; charleft[50]; char right[50][50]; //产生式的个数//所有终结符和非终结符的总数 //开始符号 //终结符号 //非终结符号//所有符号 //左部 //右部char first[50][50],follow[50][50]; char first1[50][50]; charselect[50][50]; char firstflag[50],followflag[50]; char empty[20]; char nonempty[20]; char empt[20]; char TEMP[50]; int int //各产生式右部的 FIRST 和左部的 FOLLOW 集合 // 所有单个符号的 FIRST 集合 //各个产生式的 SELECT 集合 //记录各符号的 FIRST 和 FOLLOW 是否已求过 //记录可推出 & 的符号 //记录不可推出 & 的符号II 求_em p()时使用 //求 FOLLOW 时存放某一符号串的 FIRST 集合 in tvalidity=1; ll=1; M[20][20]; II 表示输入文法是否有效 II 表示输入文法是否为 LL(1)文法 II 分析表}} }char choose; //用户输入时使用 char foll[20]; // 求 FOLLOW 集合时使用/******************************************* 判断一个字符 c 是否在指定字符串 p 中 ********************************************/ int in(char c,char *p) { int i; if(strlen(p)==0) return(0); for(i=0;;i++) {if(p[i]==c)return(1); if(i==(int)strlen (p)) return(0); //若在,返回 1 //若不在,返回 0 /******************************************* 将单个符号或符号串并入另一符号串 ********************************************/void merge(char *d,char *s,int type) { 〃是目标符号串,s 是源串,type = 1,源串中的&一并并入目串;//type = 2,源串中的&不并入目串int i,j; for(i=0;i<=(int)strlen(s)-1;i++) {if(type==2&&s[i]=='&'); else{for(j=0;;j++){if(j<(int)strlen(d)&&s[i]==d[j])break;//若已存在,则退出,继续看下一个源串字符if(j==(int)strlen(d)) //若不存在,则并入{d[j]=s[i]; d[j+1]='\0'; break;}/*******************************************读入一个文法********************************************/ char grammer(char *t,char *n,char *left,char right[50][50]){char vn[50],vt[50]; char s; char p[50][50]; int i,j;printf(" 请输入文法的非终结符号串: "); scanf("%s",vn); getchar(); i=strlen(vn); memcpy(n,vn,i); n[i]='\0';printf(" 请输入文法的终结符号串: scanf("%s",vt); getchar(); i=strlen(vt); memcpy(t,vt,i); t[i]='\0';printf(" 请输入文法的开始符号: scanf("%c",&s); getchar();printf(" 请输入文法产生式的条数: scanf("%d",&i); getchar(); count=i; for(j=1;j<=i;j++) {printf(" 请输入文法的第 %d 条(共 %d 条)产生式: ",j,i); scanf("%s",p[j-1]); getchar();}for(j=0;j<=i-1;j++){if(p[j][1]!='-'||p[j][2]!='>') // 检测输入错误 {printf("\n 输入错误 !"); validity=0; return('\0');}return(s);"); ");");} }}/******************************************* 判断读入的文法是否正确 ********************************************/ int judge() {int i,j; for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ // 若左部不在非终结符中,报错 printf("\n 文法左部出错 !"); validity=0;return(0);}for(j=0;j<=(int)strlen(right[i])-1;j++){//若右部某一符号不在非终结符、终结符中且不为'&' ,报错printf("\n 文法右部出错 !"); validity=0; return(0);} }}return(1);/*******************************************求所有能直接推出 & 的符号********************************************/ void emp(char c){char temp[10]; int i;for(i=0;i<=count-1;i++) {if(right[i][0]==c&&strlen(right[i])==1){temp[0]=left[i]; temp[1]='\0';merge(empty,temp,1);// 求所有能直接推出 '&" 的符号 ,结果保存到 empty[] 中 emp(left[i]);if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right [i][j]!='&') {}/*******************************************求某一符号能否推出'&' ********************************************/ int _emp(char c){ //若能推出&,返回1;否则,返回0int i,j,k,result=1,mark=0;char temp[20]; temp[0]=c;temp[1]='\0';merge(em pt,tem p,1);//存放到一个临时数组empt里,标识此字符已查找其是否可推出空字if(in(c,empty)==1)//如果c在可直接推出空字的empty[]中,返回1return(1);for(i=0;;i++){ if(i==count) return(0);if(left[i]==c)//找一个左部为 c 的产生式{j=strlen(right[i]); //j 为 c 所在产生式右部的长度if(j==1&&in(right[i][0],empty)==1)// 右部长度为 1 且右部第一个字符在empty[] 中.返回1(A->B,B 可推出空)return(1);else if(j==1&&in(right[i][0],termin)==1)// 右部长度为 1 但第一个字符为终结符返回0(A->a,a 为终结符)continue;else{for(k=0;k<=j-1;k++){if(in(right[i][k],empt)==1)// 查找临时数组empt[].(A->AB) mark=1;}if(mark==1) //找到的字符与当前字符相同(A->AB)continue; //结束本次循环else //(mark 等于0){for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);// 递归调用,查找右部符号是否可推出空字, 把返回值赋给resulttemp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);//把当前符号加入到临时数组empt[]里,标记已查找}if(result==0&&i<count)// 如果当前字符不能推出空字且还没搜索完全部的产生 式,贝跳出本次循环继续搜索下一条产生式continue;else if(result==1&&i<count)// 当前字符可推出空字 ,返回 1 return(1);}}/*******************************************求单个符号的 FIRST********************************************/ void first2(int i){char c,temp[20]; int j,k,m; char ch='&'; c=v[i];emp(ch);//求所有能直接推出空字的符号,结果保存到empty[]中 if(in(c,termin)==1){first1[i][0]=c; first1[i][1]='\0';}else if(in(c ,non_ter)==1){for(j=0;j<=count-1;j++) //j 为所有产生式中的序列{if(left[j]==c) // 找一个左部为 c 的产生式{if(in(right[j][0],termin)==1||right[j][0]=='&') {//若产生式右部第一个字符为终结符或空.---产生式X 7 a (a € VT)或X&, 贝把 a 或&加进 FIRST(X)temp[0]=right[j][0]; temp[1]='\0'; merge(first1[i],temp ,1);}//——X 7 Y1Y2…Yk 的产生式,若 丫1 € VN ,则把FIRST(Y1)中的一切非空符号加进 FIRST(X)else if(in(right[j][0],non_ter)==1)// 产生式右部第一个字符为非终结符{//i 为符号在所有输入符号中的序号〃若为终结符--C € VT ,贝y FIRST(c)={c}//若为非终结符if(right[j][0]==c)II 产生式右部的第一个符号等于当前字符break;}if(firstflag[m]=='0')II 如果此字符的 FIRST 集还未查找 ,则找其 FIRST 集,并标其查找状态为 1{first2(m); firstflag[m]='1';}merge(first1[i],first1[m],2);// 把求得结果并入到 X 的 FIRST集.}II ——产生式为 X7 Y1Y2…Yk,若对一切 1<=i<=k ,均有& € FIRST(Yi),则将& €符号加进FIRST(X)else if(_emp(right[j][k])==1&&k==(int)strlen(right[j])-1) {II 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&'; temp[1]='\0';merge(first1[i],temp,1);II 把空字加入到当前字符 X 的 FIRST集.,则跳到下一条产生式进行查找 可推出空字 一个字符 有字符集中的位置 continue; for(k=0;;k++){if(v[k]==right[j][0])II 求右部第一个字符在所有字符集中的位置 kbreak;}if(firstflag[k]=='0'){first2(k);II 求其 FIRST 集 firstflag[k]='1';II 标识其为查找状态}merge(first1[i],first1[k],2);// 求得结果并入到 X 的 FIRST集. for(k=0;k<(int)strlen(right[j]);k++){empt[0]='\0';// 存放到一个临时数组里 , 标识此字符已查找其是否 if(_emp(right[j][k])==1&&k<(int)strlen(right[j])-1){II 当前产生式右部符号可推出空字 ,且当前字符不是右部的最for(m=0;;m++){if(v[m]==right[j][k+1])// 获取右部符号下一个字符在所}elsebreak;//不能推出空字则结束循环}}}firstflag[i]='1';//标识当前字符c 已查找其FIRST 集 }/******************************************* 求各产生式右部的 FIRST ********************************************/ void FIRST(int i,char *p) {//指针 p 指向右部符号串int len gth;//标识右部符号串的长度 int j,k,m; char temp[20];length=strlen(p); if(length==1){if(p[0]=='&')// 右部符号串字符为 "&" 空字 {if(i>=0)//i 不为 -1 时是产生式的序号 {TEMP[0]='&'; TEMP[1]='\0';}else//右部符号串字符不为 {for(j=0;;j++){if(v[j]==p[0])//求右部符号的第一个字符 p[0]在所有字符集中的位置 jbreak;}if(i>=0){//如果右部为单个符号first[i][0]='&'; //把"&" 加入到当前符号串的 FIRST 集 }else//i 为-1时,表示求FOLLOW 时用到的产生式右部的 FIRST 集 ,保存在 TEMP[]"&" 空字memcpy(first[i],first1[j],strlen(first1[j]));// 把j 所指向的单个符号的FIRST 集拷贝到该右部符号串的FIRST 集first[i][strlen(first1[j])]='\0';} else{memcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';} else{//如果右部为符号串for(j=0;;j++){if(v[j]==p[0])// 求右部符号的第一个字符p[0] 在所有字符集中的位置j break;}if(i>=0) merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2); for(k=0;k<=length-1;k++){empt[0]='\0';if(_emp(p[k])==1&&k<length-1){ // 当前产生式右部符号可推出空字, 且当前字符不是右部的最后一个字符for(m=0;;m++){if(v[m]==right[i][k+1]) break;} if(i>=0)merge(first[i],first1[m],2); elsemerge(TEMP,first1[m],2);}else if(_emp(p[k])==1&&k==length-1){// 当前右部符号串可推出空且是右部符号串的最后一个字符temp[0]='&';temp[1]='\0';if(i>=0)merge(first[i],temp,1);elsemerge(TEMP,temp,1);}else if(_emp(p[k])==0)break;}}/*******************************************求各产生式左部的 FOLLOW ********************************************/ void FOLLOW(int i){ // 参数 i 为该符号在非终结符中的位置 int j,k,m,n,result=1; char c,temp[20]; c=non_ter[i];temp[0]=c; temp[1]='\0';merge(foll,temp,1);// 把当前字符放到一临时数组 foll[] 中 ,标识求已求其 FOLLOW 集.避免循环递归中的位置}for(m=0;;m++){}〃如果c 在产生式右部的最后,形如产生式 A fa B,则FOLLOW(A) € FOLLOW(B)if(k==(int)strlen(right[j])-1){if(in(v[m],foll)==1)// 查找该非终结符是否已经求过其 FOLLOW 集.避免循//c 为待求的非终结符if(c==start){temp[0]='#'; temp[1]='\0';merge(follow[i],temp,1);}for(j=0;j<=count-1;j++){if(in(c,right[j])==1) {//比如求 FOLLOW(B)for(k=0;;k++){if(right[j][k]==c) break;//若为开始符号-----开始符号S ,则#€ FOLLOW(S)c 的产生式A faB 或 A fa B 3 ( 3 =>*&)的产生式 //找一个右部含有当前字符 则找 //k 为 c 在该产生式右部的序号 ,如 B 在产生式 Afa Bif(v[m]==left[j])//m 为产生式左部非终结符在所有符号中的序号{//是则 FOLLOW(A) € FOLLOW(B)merge(follow[i],follow[m],1);// 把 c 所在产生式的左部非终结符的 集加入到FOLLOW(c) 中 continue;//结束本次循环,进入j++循环}if(followflag[m]=='0'){//如果该非终结符的 FOLLOW 未求过FOLLOW(m);// 求之 FOLLOW 集 followflag[m]='1';// 标识为 1}merge(follow[i],follow[m],1);//FOLLOW(A) € FOLLOW(B)//如果 c 不在产生式右部的最后 ,形如 Afa B3 for(n=k+1;n<=(int)strlen(right[j])-1;n++){empt[0]-\0';//把empt[]置空,因为求此字符是否可推出空字 _emp(c)时环递归FOLLOW}else{用到result*=_emp(right[j][n]);}if(result==1) {//如果右部 c 后面的符号串能推出空,A fa B 3 (3 =>*&)则FOLLOW(A)€ FOLLOW(B)if(in(v[m],foll)==1){//查找该非终结符是否已经求过其FOLLOW 集 .避免循环递归merge(follow[i],follow[m],1);//FOLLOW(A )continue;€ FOLLOW(B)}// 若 A fa B 3,其中 FOLLOW(B) ;}if(followflag[m]=='0'){FOLLOW(m); followflag[m]='1';}merge(follow[i],follow[m],1);B € VN , a€ (VT U VN)*、3€ (VT U VN)+,贝U FIRST( 3 )-{ £ } €for(n=k+1;n<=(int)strlen(right[j])-1;n++) {temp[n-k-1]=right[j][n];}temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);// 求 FIRST(3 )merge(follow[i],TEMP,2);// 把 FOLLOW(B)}}followflag[i]='1';// 标识当前要求的非终结符的}/******************************************* 判断读入文法是否为一个 LL(1) 文法 ********************************************/ int LL1(){int i,j,length,result=1; char temp[50]; for(j=0;j<=49;j++) {first[j][0]='\0'; follow[j][0]='\0'; first1[j][0]='\0'; select[j][0]='\0'; TEMP[j]='\0'; temp[j]='\0';firstflag[j]='0';// 用来记录该字符的 FIRST 集是否已求过 .1 表示已求 ,0 表示未求 followflag[j]='0';// 用来记录该字符的 FOLLOW 集是否已求过 .1 表示已求 ,0 表示未求 }for(j=0;j<=(int)strlen(v)-1;j++){first2(j);}printf("\n 各非终结符推出的 first 集 :\n"); for(j=0;j<=(int)strlen(v)-1;j++) {printf("%c:%s ",v[j],first1[j]);}printf("\n 能导空的非终结符集合 :%s",empty); printf("\n_emp:"); for(j=0;j<=(int)strlen(v)-1;j++)printf("%d ",_emp(v[j])); for(i=0;i<=count-1;i++) FIRST(i,right[i]);//求 FIRSTfor(j=0;j<=(int)strlen(non_ter)-1;j++) { //求 FOLLOWif(foll[j]==0)FIRST( 3 )中所有非空元素加入到FOLLOW 集已求过//初始化//求单个符号的 FIRST 集合,结果保存在 first1[] 里{// 求每一产生式的 SELECT 集合memcpy(select[i],first[i],strlen(first[i]));//first[]存放的是各产生式右部的 FIRST 集select[i][strlen(first[i])]='\0'; for(j=0;j<=(int)strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='&')// 形如产生式 A->& result=1; if(result==1){for(j=0;;j++)if(v[j]==left[i])//j 为左部符号在所有字符集中的位置 break;merge(select[i],follow[j],1);}printf("\nselect 集合顺序是 :"); for(i=0;i<=count-1;i++) printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0])); temp[strlen(select[0])]='\0'; for(i=1;i<=count-1;i++) {/* 判断输入文法是否为 LL(1) 文法 */length=strlen(temp); if(left[i]==left[i-1]){merge(temp,select[i],1); if(strlen(temp)<length+strlen(select[i]))// 比较两个产生式的 SELECT 长度 return(0);}elsetemp[0]='\0';{foll[0]='\0'; FOLLOW(j);}}printf("\nfirst 集 :"); for(i=0;i<=count-1;i++)printf("%s ",first[i]); printf("\nfollow 集合 :"); for(i=0;i<=(int)strlen(non_ter)-1;i++)printf("%s ",follow[i]); for(i=0;i<=count-1;i++) {memcpy(temp,select[i],strlen(select[i])); temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M ********************************************/ void MM(){int i,j,k,m; for(i=0;i<=19;i++){for(j=0;j<=19;j++)// 初始化分析表,全部置为空(-1) {M[i][j]=-1;}}i=strlen(termin);termin[i]='#'; //将#加入终结符数组termin[i+1]='\0';for(i=0;i<=count-1;i++)// 查看每个产生式的SELECT 集{for(m=0;;m++){if(non_ter[m]==left[i])break; //m 为产生式左部非终结符的序号}for(j=0;j<=(int)strlen(select[i])-1;j++)// 对每个SELECT 集中的所有元素进行操作{ if(in(select[i][j],termin)==1){ for(k=0;;k++) { if(termin[k]==select[i][j]) break; //k 为产生式右部终结符的序号}M[m][k]=i;}/*******************************************判断符号串是否是该文法的句型********************************************/ void syntax(){int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf(" 请输入该文法的句型:"); scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1){if(in(S[strlen(S)-1],termin)==1) {if(S[strlen(S)-1]!=ch){printf(" 该符号串不是文法的句型!"); return;}else if(S[strlen(S)-1]=='#'){printf(" 该符号串是文法的句型."); return;} elseS[strlen(S)-1]='\0'; j++; ch=str[j];} } elsefor(i=0;;i++)if(non_ter[i]==S[strlen(S)-1]) break;{for(k=0;;k++){if(termin[k]==ch)break;if(k==(int)strlen(termin)){printf(" 词法错误!");return;}}if(M[i][k]==-1){printf(" 语法错误!");return;}else{m=M[i][k]; if(right[m][0]=='@')S[strlen(S)-1]='\0';else{p=strlen(S)-1;q=p;for(n=strlen(right[m])-1;n>=0;n--)S[p++]=right[m][n];S[q+strlen(right[m])]='\0';}}}printf("S:%s str:",S);for(p=j;p<=(int)strlen(str)-1;p++)printf("%c",str[p]);printf(" \n");}}/*******************************************一个用户调用函数********************************************/ void menu(){ syntax(); printf("\n 是否继续?(y or n):"); scanf("%c",&choose);本文档如对你有帮助,请帮忙下载支持! {getchar();while(choose=='y'){ menu();}}/******************************************* 主函数********************************************/void main() {int i,j;start=grammer(termin,non_ter,left,right); printf("count=%d",count); printf("\n开始符号为 :%c",start);strcpy(v,non_ter); strcat(v,termin);printf("\n 所有符号集为 :%s",v);printf("\n 非终结符集合 :{%s",non_ter);printf("}"); printf("\n 终结符集合 :{%s",termin); printf("}");printf("\n 文法所有右边表达式依次是for(i=0;i<=count-1;i++) {printf("%s ",right[i]);}printf("\n 文法所有左边开始符依次是for(i=0;i<=count-1;i++) {printf("%c } if(validity==1) validity=judge(); printf("\nvalidity=%d",validity);if(validity==1) { ll=LL1(); printf("\nll=%d",ll);if(ll==0)printf("\n 该文法不是一个else//读入一个文法 :");:");",left[i]);LL1 文法!"); printf("\n 该文法是一个 LL(1) 文法!");本文档如对你有帮助,请帮忙下载支持!MM();printf("\n");for(i=0;i<=19;i++)for(j=0;j<=19;j++)if(M[i][j]>=0) printf("M[%d][%d]=%d ",i,j,M[i][j]); menu();}}} 由于算法仍有很多错误,最终结果没能实现,这点很失望!五、实验心得通过本次实验,我收获了很多东西。