实验一_文法分析方法及其应用 (1)
LR(0)文法分析

实验名称:LR(0)文法分析一、实验目的:输入:任意的压缩了的上下文无关文法。
输出:相应的LR(0)分析表。
二、实验原理:对于LR文法,我们可以自动构造相应的LR分析表。
为了构造LR分析表,我们需要定义一个重要概念——文法的规范句型“活前缀”。
这种句柄之后不含任何符号的前缀称为活前缀。
在LR分析工作过程中的任何时候,栈里的文法符号(自栈底而上)X1X2…X m应该构成活前缀,把输入串的剩余部分配上之后即应成为规范句型(如果整个输入串确实构成一个句子)。
因此,只要输入串的已扫描部分保持可归约成一个活前缀,那就意味着所扫描过的部分没有错误。
对于一个文法G,我们可以构造一个有限自动机,它能识别G的所有活前缀,然后把这个自动机转变成LR分析表,按照该LR分析表进行LR分析,就能保证在分析的过程中,如果分析的句子是正确的,栈里的文法符号(自栈底而上)始终构成活前缀。
假若一个文法G的拓广文法G'的活前缀识别自动机中的每个状态(项目集)不存在下述情况:(1)既含移进项目又含归约项目;(2)含有多个归约项目,则称G是一个LR(0)文法。
该自动机的状态集合即为该文法的LR(0)项目集规范族。
构造识别文法活前缀DFA有3种方法:(1)根据形式定义求出活前缀的正则表达式,然后由此正则表达式构造NFA 再确定为DFA;(2)求出文法的所有项目,按一定规则构造识别活前缀的NFA再确定化为DFA;(3)使用闭包函数(CLOSURE)和转向函数(GO(I,X))构造文法G’的LR(0)的项目集规范族,再由转换函数建立状态之间的连接关系来得到识别活前缀的DFA。
符号串的前缀是指该符号串的任意首部,包括空串ε。
例如,对于符号串abc,其前缀有ε,a,ab,abc。
如果输入串没有错误的话,一个规范句型的活前缀是该句型的一个前缀,但它不含句柄之后的任何符号。
之所以称为活前缀,是因为在该前缀后联接尚未输入的符号串可以构成一个规范句型。
编译原理LL(1)文法分析器实验(java)

编译原理LL(1)文法分析器实验本程序是基于已构建好的某一个语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。
基本实现思想:接收用户输入的字符串(字符串以“#”表示结束)后,对用做分析栈的一维数组和存放分析表的二维数组进行初始化。
然后取出分析栈的栈顶字符,判断是否为终结符,若为终结符则判断是否为“#”且与当前输入符号一样,若是则语法分析结束,输入的字符串为文法的一个句子,否则出错若不为“#”且与当前输入符号一样则将栈顶符号出栈,当前输入符号从输入字符串中除去,进入下一个字符的分析。
若不为“#”且不与当前输入符号一样,则出错。
若栈顶符号为非终结符时,查看预测分析表,看栈顶符号和当前输入符号是否构成产生式,若产生式的右部为ε,则将栈顶符号出栈,取出栈顶符号进入下一个字符的分析。
若不为ε,将产生式的右部逆序的入栈,取出栈顶符号进入下一步分析。
程序流程图:本程序中使用以下文法作对用户输入的字符串进行分析:E→TE’E’→+TE’|εT→FT’T’→*FT’|εF→i|(E)该文法的预测分析表为:1、显示预测分析表,提示用户输入字符串2、输入的字符串为正确的句子:3、输入的字符串中包含了不属于终结符集的字符4、输入的字符串不是该文法能推导出来的句子程序代码:package ;import java.io.*;public class LL {String Vn[] = { "E", "E'", "T", "T'", "F" }; // 非终结符集String Vt[] = { "i", "+", "*", "(", ")", "#" }; // 终结符集String P[][] = new String[5][6]; // 预测分析表String fenxi[] ; // 分析栈int count = 1; // 步骤int count1 = 1;//’分析栈指针int count2 = 0, count3 = 0;//预测分析表指针String inputString = ""; // 输入的字符串boolean flag;public void setCount(int count, int count1, int count2, int count3){this.count = count;this.count1 = count1;this.count2 = count2;this.count3 = count3;flag = false;}public void setFenxi() { // 初始化分析栈fenxi = new String[20];fenxi[0] = "#";fenxi[1] = "E";}public void setP() { // 初始化预测分析表for (int i = 0; i < 5; i++) {for (int j = 0; j < 6; j++) {P[i][j] = "error";}}P[0][0] = "->TE'";P[0][3] = "->TE'";P[1][1] = "->+TE'";P[1][4] = "->ε";P[1][5] = "->ε";P[2][0] = "->FT'";P[2][3] = "->FT'";P[3][1] = "->ε";P[3][2] = "->*FT'";P[3][4] = "->ε";P[3][5] = "->ε";P[4][0] = "->i";P[4][3] = "->(E)";// 打印出预测分析表System.out.println(" 已构建好的预测分析表");System.out.println("----------------------------------------------------------------------");for (int i=0; i<6; i++) {System.out.print(" "+Vt[i]);}System.out.println();System.out.println("----------------------------------------------------------------------");for (int i=0; i<5; i++) {System.out.print(" "+Vn[i]+" ");for (int j=0; j<6; j++) {int l = 0;if (j>0) {l = 10-P[i][j-1].length();}for (int k=0; k<l; k++) {System.out.print(" ");}System.out.print(P[i][j]+" ");}System.out.println();}System.out.println("----------------------------------------------------------------------"); }public void setInputString(String input) {inputString = input;}public boolean judge() {String inputChar = inputString.substring(0, 1); // 当前输入字符boolean flage = false;if (count1 >= 0) {for (int i=0; i<6; i++) {if (fenxi[count1].equals(Vt[i])) { // 判断分析栈栈顶的字符是否为终结符flage = true;break;}}}if (flage) {// 为终结符时if (fenxi[count1].equals(inputChar)) {if (fenxi[count1].equals("#")&&inputString.length()==1) { // 栈顶符号为结束标志时// System.out.println("最后一个");String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("接受");flag = true;return true;} else {// 分析栈栈顶符号不为结束标志符号时String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("\"" + inputChar + "\"" + "匹配");// 将栈顶符号出栈,栈顶指针减一fenxi[count1] = null;count1 -= 1;if (inputString.length() > 1) { // 当当前输入字符串的长度大于1时,将当前输入字符从输入字符串中除去inputString = inputString.substring(1, inputString.length());} else { // 当前输入串长度为1时inputChar = inputString;}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);// System.out.println(count + inputChar + "匹配");count++;judge();}}else { // 判断与与输入符号是否一样为结束标志System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}} else {// 非终结符时boolean fla = false;for (int i=0; i<6; i++) { // 查询当前输入符号位于终结符集的位置if (inputChar.equals(Vt[i])) {fla = true;count2 = i;break;}}if(!fla){System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}for (int i=0; i<5; i++) { // 查询栈顶的符号位于非终结符集的位置if (fenxi[count1].equals(Vn[i])) {count3 = i;break;}}if (P[count3][count2] != "error") { // 栈顶的非终结符与输入的终结符存在产生式时String p = P[count3][count2];String s1 = p.substring(2, p.length()); // 获取对应的产生式if (s1.equals("ε")) { // 产生式推出“ε”时String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);// 将栈顶符号出栈,栈顶指针指向下一个元素fenxi[count1] = null;count1 -= 1;count++;judge();} else { // 产生式不推出“ε”时int k = s1.length();String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);for (int i=1; i<=k; i++) { // 将产生式右部的各个符号入栈String s2 = s1.substring(s1.length() - 1, s1.length());s1 = s1.substring(0, s1.length() - 1);if (s2.equals("'")) {s2 = s1.substring(s1.length() - 1, s1.length())+ s2;i++;s1 = s1.substring(0, s1.length() - 1);}fenxi[count1] = s2;if (i < k)count1++;// System.out.println("count1=" + count1);}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);count++;// System.out.println(count);judge();}} else {System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}}return flag;}public static void main(String args[]) {LL l = new LL();l.setP();String input = "";boolean flag = true;while (flag) {try {InputStreamReader isr = new InputStreamReader(System.in);BufferedReader br = new BufferedReader(isr);System.out.println();System.out.print("请输入字符串(输入exit退出):");input = br.readLine();} catch (Exception e) {e.printStackTrace();}if(input.equals("exit")){flag = false;}else{l.setInputString(input);l.setCount(1, 1, 0, 0);l.setFenxi();System.out.println();System.out.println("分析过程");System.out.println("----------------------------------------------------------------------");System.out.println(" 步骤| 分析栈| 剩余输入串| 所用产生式");System.out.println("----------------------------------------------------------------------");boolean b = l.judge();System.out.println("----------------------------------------------------------------------");if(b){System.out.println("您输入的字符串"+input+"是该文发的一个句子");}else{System.out.println("您输入的字符串"+input+"有词法错误!");}}}}}。
编译原理词法分析,语法分析实验报告

编译原理实验报告一.LL(1)文法分析1.设计要求(1)对输入文法,它能判断是否为LL(1)文法,若是,则转(2);否则报错并终止;(2)输入已知文法,由程序自动生成它的LL(1)分析表;(3)对于给定的输入串,应能判断识别该串是否为给定文法的句型。
2.分析该程序可分为如下几步:(1)读入文法(2)判断正误(3)若无误,判断是否为LL(1)文法(4)若是,构造分析表;(5)由总控算法判断输入符号串是否为该文法的句型。
3.流程图开始读入文法有效?是是LL(1)文法?是判断句型报错结束4.源程序/*******************************************语法分析程序作者:xxx学号:xxx********************************************/#include<stdlib.h>#include<stdio.h>#include<string.h>/*******************************************/int count=0; /*分解的产生式的个数*/int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin[50]; /*终结符号*/char non_ter[50]; /*非终结符号*/char v[50]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/ char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/char empty[20]; /*记录可直接推出^的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*//*******************************************判断一个字符是否在指定字符串中********************************************/int in(char c,char *p){int i;if(strlen(p)==0)return(0);for(i=0;;i++){if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/}}/*******************************************得到一个不是非终结符的符号********************************************/char c(){char c='A';while(in(c,non_ter)==1)c++;return(c);}/*******************************************分解含有左递归的产生式********************************************/void recur(char *point){ /*完整的产生式在point[]中*/int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++){if(point[n]==point[0]){ /*如果‘|’后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++){while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|'){n=j+1;break;}}}else{ /*如果‘|’后的首符号和左部不同*/ left[count]=ch;right[count][0]='^';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;}}}/*******************************************分解不含有左递归的产生式********************************************/void non_re(char *point){int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++){if(point[j]!='|')temp[m++]=point[j];else{left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;}}left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;}/*******************************************读入一个文法********************************************/ char grammer(char *t,char *n,char *left,char right[50][50]) {char vn[50],vt[50];char s;char p[50][50];int i,j,k;printf("\n请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("请输入文法的开始符号:");scanf("%c",&s);getchar();printf("请输入文法产生式的条数:");scanf("%d",&i);getchar();for(j=1;j<=i;j++){printf("请输入文法的第%d条(共%d条)产生式:",j,i);scanf("%s",p[j-1]);getchar();}for(j=0;j<=i-1;j++)if(p[j][1]!='-'||p[j][2]!='>'){ printf("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);}return(s);}/*******************************************将单个符号或符号串并入另一符号串********************************************/void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的‘^ ’一并并入目串;type=2,源串中的‘^ ’不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++){if(type==2&&s[i]=='^');else{for(j=0;;j++){if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d)){d[j]=s[i];d[j+1]='\0';}}}}}/*******************************************求所有能直接推出^的符号********************************************/void emp(char c){ /*即求所有由‘^ ’推出的符号*/ char temp[10];int i;for(i=0;i<=count-1;i++){if(right[i][0]==c&&strlen(right[i])==1){temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);emp(left[i]);}}}/*******************************************求某一符号能否推出‘^ ’********************************************/int _emp(char c){ /*若能推出,返回1;否则,返回0*/ int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++){if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/{j=strlen(right[i]); /*j为右部的长度*/if(j==1&&in(right[i][0],empty)==1)else if(j==1&&in(right[i][0],termin)==1)return(0);else{for(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;else{for(k=0;k<=j-1;k++){result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);}}}if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);}}}/*******************************************判断读入的文法是否正确********************************************/int judge(){int i,j;for(i=0;i<=count-1;i++){if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/ printf("\nerror1!");validity=0;return(0);}for(j=0;j<=strlen(right[i])-1;j++){if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='^'){ /*若右部某一符号不在非终结符、终结符中且不为‘^ ’,报错*/ printf("\nerror2!");validity=0;return(0);}}}return(1);}/*******************************************求单个符号的FIRST********************************************/void first2(int i){ /*i为符号在所有输入符号中的序号*/char c,temp[20];int j,k,m;c=v[i];char ch='^';emp(ch);if(in(c,termin)==1) /*若为终结符*/{first1[i][0]=c;first1[i][1]='\0';}else if(in(c,non_ter)==1) /*若为非终结符*/{for(j=0;j<=count-1;j++){if(left[j]==c){if(in(right[j][0],termin)==1||right[j][0]=='^'){temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);}else if(in(right[j][0],non_ter)==1){if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0'){first2(k);f[k]='1';}merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++){empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1){for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0'){first2(m);f[m]='1';}merge(first1[i],first1[m],2);}else if(_emp(right[j][k])==1&&k==strlen(right[j])-1){temp[0]='^';temp[1]='\0';merge(first1[i],temp,1);}elsebreak;}}}}}f[i]='1';}/*******************************************求各产生式右部的FIRST********************************************/void FIRST(int i,char *p){int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/ {if(p[0]=='^'){if(i>=0){first[i][0]='^';first[i][1]='\0';}else{TEMP[0]='^';TEMP[1]='\0';}}else{for(j=0;;j++)if(v[j]==p[0])break;if(i>=0){memcpy(first[i],first1[j],strlen(first1[j]));first[i][strlen(first1[j])]='\0';}else{memcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';}}}else /*如果右部为符号串*/{for(j=0;;j++)if(v[j]==p[0])break;if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++){empt[0]='\0';if(_emp(p[k])==1&&k<length-1){for(m=0;;m++)if(v[m]==right[i][k+1])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){int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);if(c==start){ /*若为开始符号*/temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);}for(j=0;j<=count-1;j++){if(in(c,right[j])==1) /*找一个右部含有c的产生式*/{for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1){merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++){empt[0]='\0';result*=_emp(right[j][n]);}if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;}if(F[m]=='0'){FOLLOW(m);F[m]='1';}merge(follow[i],follow[m],1);}for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);}}}F[i]='1';}/*******************************************判断读入文法是否为一个LL(1)文法********************************************/int ll1(){int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ /*初始化*/first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';f[j]='0';F[j]='0';}for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\nfirst1:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\nempty:%s",empty);printf("\n:::\n_emp:");for(j=0;j<=strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/printf("\n");for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0){fo[0]='\0';FOLLOW(j);}}printf("\nfirst:");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='^')result=1;if(result==1){for(j=0;;j++)if(v[j]==left[i])break;merge(select[i],follow[j],1);}}printf("\nselect:");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++){ /*判断输入文法是否为LL(1)文法*/ length=strlen(temp);if(left[i]==left[i-1]){merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))return(0);}else{temp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';}}return(1);}/*******************************************构造分析表M********************************************/void MM(){int i,j,k,m;for(i=0;i<=19;i++)for(j=0;j<=19;j++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++){for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/for(j=0;j<=strlen(select[i])-1;j++){if(in(select[i][j],termin)==1){for(k=0;;k++)if(termin[k]==select[i][j])break; /*k为产生式右部终结符的序号*/ M[m][k]=i;}}}}/*******************************************总控算法********************************************/void syntax(){int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf("请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1){if(in(S[strlen(S)-1],termin)==1){if(S[strlen(S)-1]!=ch){printf("\n该符号串不是文法的句型!");return;}else if(S[strlen(S)-1]=='#'){printf("\n该符号串是文法的句型.");return;}else{S[strlen(S)-1]='\0';j++;ch=str[j];}}else{for(i=0;;i++)if(non_ter[i]==S[strlen(S)-1])break;for(k=0;;k++){if(termin[k]==ch)break;if(k==strlen(termin)){printf("\n词法错误!");return;}}if(M[i][k]==-1){printf("\n语法错误!");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("\nS:%s str:",S);for(p=j;p<=strlen(str)-1;p++)printf("%c",str[p]);printf(" ");}}/*******************************************一个用户调用函数********************************************/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("\nstart:%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\nv:%s",v);printf("\nnon_ter:%s",non_ter);printf("\ntermin:%s",termin);printf("\nright:");for(i=0;i<=count-1;i++)printf("%s ",right[i]);printf("\nleft:");for(i=0;i<=count-1;i++)printf("%c ",left[i]);if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1){printf("\n文法有效");ll=ll1();printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");else{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]);printf("\n");menu();}}}5.执行结果(1)输入一个文法(2)输入一个符号串(3)再次输入一个符号串,然后退出程序二.词法分析一、问题描述识别简单语言的单词符号识别简单语言的基本字、标识符、无符号整数、运算符和界符。
实验 LL(1)文法 计算器

主程序的代码结构是一致的
递归子程序法中主程序的结构是一样的,它们都是读入第一个符 号,然后调用开始符对应的子程序。
主程序: 开始
读第一个单词
开始符子程序
# OK 结束
n
error
例如:G(S): S→aS|b
S子程序: 开始
主程序: 开始 读第一个符号
a
n
b
y next
n
S
error #
S
结束
y next
# OK 结束
y next E
结束
扩展
可进行多行表达式计算 让计算器支持括号 让计算器支持负数
实验检查
2015年10月9日(第四周)做ppt汇报实验
按y=f(x)的思路进行汇报
先随机选三位同学汇报 鼓励做得更好的同学进行汇报
G(S): S→ABC
主程序:
A→ad
B→be
S子程序:
C→cf
A子程序:
开始
next
开始
开始 a
next n error
A B n
error
S
#
OK 结束
读第一个单词
……
n error
C
结束
d
next 结束
递归子程序法的思想
例如:设文法G(S)的一个产生式如下
S→A1A2…An
Ai∈(VN∪VT)
error
n
error
③
开始
y
OK 结束
y next S
结束
a
n b
n
error 返回
y next #
例:设文法G(S) 如下
自动机实验报告(3篇)

第1篇一、实验目的1. 理解自动机的概念和分类。
2. 掌握有限自动机(FA)和正规文法(CFG)的基本原理。
3. 学习自动机的应用,如词法分析、语法分析等。
4. 通过实验加深对自动机理论的理解。
二、实验内容1. 有限自动机(FA)- 实验一:设计并实现一个识别特定字符串的有限自动机实验步骤:(1)根据题目要求,确定输入字母表和输出字母表。
(2)设计有限自动机的状态转移图。
(3)编写代码实现有限自动机的状态转移功能。
(4)测试有限自动机对特定字符串的识别能力。
- 实验二:分析并验证有限自动机的正确性实验步骤:(1)根据实验一的结果,分析有限自动机的状态转移图。
(2)验证有限自动机是否满足题目要求。
(3)如果有限自动机不满足要求,修改状态转移图,重新进行实验。
2. 正规文法(CFG)- 实验一:设计并实现一个正规文法实验步骤:(1)根据题目要求,确定正规文法中的非终结符、终结符和产生式。
(2)编写代码实现正规文法的生成功能。
(3)测试正规文法生成的句子是否满足题目要求。
- 实验二:将正规文法转换为有限自动机实验步骤:(1)根据实验一的结果,分析正规文法。
(2)将正规文法转换为有限自动机。
(3)测试有限自动机对句子进行词法分析的能力。
三、实验结果与分析1. 实验一:有限自动机- 在实验一中,我们成功设计并实现了识别特定字符串的有限自动机。
通过测试,我们发现有限自动机能够正确识别给定的字符串。
- 在实验二中,我们分析了有限自动机的状态转移图,并验证了其正确性。
我们发现有限自动机满足题目要求,能够正确识别给定的字符串。
2. 实验二:正规文法- 在实验一中,我们成功设计并实现了正规文法。
通过测试,我们发现正规文法能够生成满足题目要求的句子。
- 在实验二中,我们将正规文法转换为有限自动机,并测试了其对句子进行词法分析的能力。
我们发现有限自动机能够正确对句子进行词法分析。
四、实验总结通过本次实验,我们掌握了有限自动机和正规文法的基本原理,并学会了如何将它们应用于实际问题。
LL(1)分析法

LL(1)分析法编译原理实验报告日期:班级:题目:LL(1)分析法组员:LL(1)语法分析程序1. 实验目的:1.根据某一文法编制调试LL (1)分析程序,以便对任意输入的符号串进行分析。
2.本次实验的目的主要是加深对预测分析LL (1)分析法的理解。
2. 实验平台Windows + VC + Win32 Console范例程序: “3-LL1.c ”3. 实验内容1. 在范例程序的基础上完善功能对下列文法,用LL (1)分析法对任意输入的符号串进行分析:(1)E→TG(2)G→+TG|—TG(3)G→ε(4)T→FS(5)S→*FS|/FS(6)S →ε(7)F →(E)(8)F →i程序输入/输出示例:程序现有功能:输入: 一个以 # 结束的符号串(包括 + * ( )i # )输出: 只能输出步骤1, 格式如下:程序目前还不能对所有输入串进行正确的分析. 需要完善的功能:(1) 请输出完整的分析过程。
即详细输出每一步骤分析栈和剩余串的变化情况, 及每一步所用的产生式.(2) 请输出最终的分析结果, 即输入串 “合法”或 “非法”.(3)示例程序只能完成 + 、* 、(、)的语法分析, 请加入 - 和 / 的语法分析(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。
同时将预期的输出结果写在另一个文本文件中,以便和输出进行对照;备注:1. 在“所用产生式”一列中,如果对应有推导,则写出所用产生式;如果为匹配终结符,则写明匹配的终结符; 如分析异常出错则,写为“分析出错”;如成功结束则写为“分析成功”。
步骤 分析栈 剩余输入串 所用产生式 1 #E i+i*i# E →TG2. 对一个新的文法实现LL(1)分析。
4.程序代码第一种文法#include<stdio.h>#include<stdlib.h>#include<string.h>#include<dos.h>char A[20];/*分析栈*/char B[20];/*剩余串*/char v1[20]={'i','+','-','*','/','(',')','#'};/*终结符*/ char v2[20]={'E','G','T','S','F'};/*非终结符*/ int j=0,b=0,top=0,l;/*L为输入串长度*/ typedef struct type/*产生式类型定义*/ char origin;/*大写字符*/char array[7];/*产生式右边字符*/int length;/*字符个数*/}type;type e,t,g,g0,g1,s,s0,s1,f,f1;/*结构体变量*/ type C[10][10];/*预测分析表*/void print()/*输出分析栈*/int a;/*指针*/for(a=0;a<=top+1;a++)printf("%c",A[a]);printf("\t\t");}/*print*/void print1()/*输出剩余串*/int j;for(j=0;j<b;j++)/*输出对齐符*/printf(" ");for(j=b;j<=l;j++)printf("%c",B[j]);printf("\t\t\t");}/*print1*/void main()int m,n,k=0,flag=0,finish=0;char ch,x;type cha;/*用来接受C[m][n]*//*把文法产生式赋值结构体*/e.origin='E';strcpy(e.array,"TG");e.length=2;t.origin='T';strcpy(t.array,"FS");t.length=2;g.origin='G';strcpy(g.array,"+TG");g.length=3;g0.origin='G';strcpy(g0.array,"-TG");g0.length=3;g1.origin='G';g1.array[0]='^';g1.length=1;s.origin='S';strcpy(s.array,"*FS");s.length=3;s0.origin='S';strcpy(s0.array,"/FS");s0.length=3;s1.origin='S';s1.array[0]='^';s1.length=1;f.origin='F';strcpy(f.array,"(E)");f.length=3;f1.origin='F';f1.array[0]='i';f1.length=1;for(m=0;m<=4;m++)/*初始化分析表*/for(n=0;n<=7;n++)C[m][n].origin='N';/*全部赋为空*//*填充分析表*/C[0][0]=e;C[0][5]=e;C[1][1]=g;C[1][2]=g0;C[1][6]=g1;C[1][7]=g1;C[2][0]=t;C[2][5]=t;C[3][1]=s1;C[3][2]=s1;C[3][3]=s;C[3][4]=s0;C[3][6]=s1;C[3][7]=s1;C[4][0]=f1;C[4][5]=f;printf("提示:本程序只能对由'i','+','-','*','/','(',')'构成的以'#'结束的字符串进行分析,\n");printf("请输入要分析的字符串:\n");do/*读入分析串*/scanf("%c",&ch);if ((ch!='i') &&(ch!='+') &&(ch!='-') &&(ch!='*') &&(ch!='/') &&(ch!='(') &&(ch!=')') &&(ch!='#')) printf("输入串中有非法字符\n");exit(1);B[j]=ch;j++;}while(ch!='#');l=j;/*分析串长度*/ch=B[0];/*当前分析字符*/A[top]='#'; A[++top]='E';/*'#','E'进栈*/printf("步骤\t\t分析栈\t\t剩余字符\t\t所用产生式\n"); dox=A[top--];/*x为当前栈顶字符*/printf("%d",k++);printf("\t\t");for(j=0;j<=7;j++)/*判断是否为终结符*/if(x==v1[j])flag=1;break;if(flag==1)/*如果是终结符*/if(x=='#')finish=1;/*结束标记*/printf("合法\n");/*接受*/getchar();getchar();exit(1);}/*if*/if(x==ch)print();print1();printf("%c匹配\n",ch);ch=B[++b];/*下一个输入字符*/flag=0;/*恢复标记*/}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",ch);/*输出出错终结符*/exit(1);}/*else*/}/*if*/else/*非终结符处理*/for(j=0;j<=4;j++)if(x==v2[j])m=j;/*行号*/break;for(j=0;j<=7;j++)if(ch==v1[j])n=j;/*列号*/break;cha=C[m][n];if(cha.origin!='N')/*判断是否为空*/print();print1();printf("%c->",cha.origin);/*输出产生式*/for(j=0;j<cha.length;j++)printf("%c",cha.array[j]);printf("\n");for(j=(cha.length-1);j>=0;j--)/*产生式逆序入栈*/A[++top]=cha.array[j];if(A[top]=='^')/*为空则不进栈*/top--;}/*if*/else/*出错处理*/print();print1();printf("%c出错\n",x);/*输出出错非终结符*/exit(1);}/*else*/}/*else*/}while(finish==0);}/*main*/测试一(1)测试i+i#(2)测试i-i(3)测试i*i#(4)测试i/i#(5)测试i+i*i#(6)测试输入非法字符i+i*#第二中文发#include<stdlib.h>#include<stdio.h>#include<string.h>int count=0; /*分解的产生式的个数*/int number; /*所有终结符和非终结符的总数*/char start; /*开始符号*/char termin[50]; /*终结符号*/char non_ter[50]; /*非终结符号*/char v[50]; /*所有符号*/char left[50]; /*左部*/char right[50][50]; /*右部*/char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/char first1[50][50]; /*所有单个符号的FIRST集合*/char select[50][50]; /*各单个产生式的SELECT集合*/char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/ char empty[20]; /*记录可直接推出^的符号*/char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/ int validity=1; /*表示输入文法是否有效*/int ll=1; /*表示输入文法是否为LL(1)文法*/int M[20][20]; /*分析表*/char choose; /*用户输入时使用*/char empt[20]; /*求_emp()时使用*/char fo[20]; /*求FOLLOW集合时使用*/判断一个字符是否在指定字符串中int in(char c,char *p)int i;if(strlen(p)==0)return(0);for(i=0;;i++)if(p[i]==c)return(1); /*若在,返回1*/if(i==strlen(p))return(0); /*若不在,返回0*/得到一个不是非终结符的符号char c()char c='A';while(in(c,non_ter)==1)c++;return(c);分解含有左递归的产生式void recur(char *point){ /*完整的产生式在point[]中*/int j,m=0,n=3,k;char temp[20],ch;ch=c(); /*得到一个非终结符*/k=strlen(non_ter);non_ter[k]=ch;non_ter[k+1]='\0';for(j=0;j<=strlen(point)-1;j++)if(point[n]==point[0]){ /*如果'|'后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++)while(point[j]!='|'&&point[j]!='\0')temp[m++]=point[j++];left[count]=ch;memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';m=0;count++;if(point[j]=='|')n=j+1;break;else{ /*如果'|'后的首符号和左部不同*/ left[count]=ch;right[count][0]='^';right[count][1]='\0';count++;for(j=n;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';printf(" count=%d ",count);m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]=ch;right[count][m+1]='\0';count++;m=0;分解不含有左递归的产生式void non_re(char *point)int m=0,j;char temp[20];for(j=3;j<=strlen(point)-1;j++)if(point[j]!='|')temp[m++]=point[j];elseleft[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';m=0;count++;left[count]=point[0];memcpy(right[count],temp,m);right[count][m]='\0';count++;m=0;读入一个文法char grammer(char *t,char *n,char *left,char right[50][50]) char vn[50],vt[50];char s;char p[50][50];int i,j,k;printf("\n请输入文法的非终结符号串:");scanf("%s",vn);getchar();i=strlen(vn);memcpy(n,vn,i);n[i]='\0';printf("请输入文法的终结符号串:");scanf("%s",vt);getchar();i=strlen(vt);memcpy(t,vt,i);t[i]='\0';printf("请输入文法的开始符号:");scanf("%c",&s);getchar();printf("请输入文法产生式的条数:");scanf("%d",&i);getchar();for(j=1;j<=i;j++)printf("请输入文法的第%d条(共%d条)产生式:",j,i);scanf("%s",p[j-1]);getchar();for(j=0;j<=i-1;j++)if(p[j][1]!='-'||p[j][2]!='>'){ printf("\ninput error!");validity=0;return('\0');} /*检测输入错误*/for(k=0;k<=i-1;k++){ /*分解输入的各产生式*/if(p[k][3]==p[k][0])recur(p[k]);elsenon_re(p[k]);return(s);将单个符号或符号串并入另一符号串void merge(char *d,char *s,int type){ /*d是目标符号串,s是源串,type=1,源串中的' ^ '一并并入目串;type=2,源串中的' ^ '不并入目串*/int i,j;for(i=0;i<=strlen(s)-1;i++)if(type==2&&s[i]=='^')elsefor(j=0;;j++)if(j<strlen(d)&&s[i]==d[j])break;if(j==strlen(d))d[j]=s[i];d[j+1]='\0';break;求所有能直接推出^的符号void emp(char c){ /*即求所有由' ^ '推出的符号*/char temp[10];int i;for(i=0;i<=count-1;i++)if(right[i][0]==c&&strlen(right[i])==1)temp[0]=left[i];temp[1]='\0';merge(empty,temp,1);emp(left[i]);求某一符号能否推出' ^ 'int _emp(char c){ /*若能推出,返回1;否则,返回0*/int i,j,k,result=1,mark=0;char temp[20];temp[0]=c;temp[1]='\0';merge(empt,temp,1);if(in(c,empty)==1)return(1);for(i=0;;i++)if(i==count)return(0);if(left[i]==c) /*找一个左部为c的产生式*/j=strlen(right[i]); /*j为右部的长度*/if(j==1&&in(right[i][0],empty)==1)return(1);else if(j==1&&in(right[i][0],termin)==1)return(0);elsefor(k=0;k<=j-1;k++)if(in(right[i][k],empt)==1)mark=1;if(mark==1)continue;elsefor(k=0;k<=j-1;k++)result*=_emp(right[i][k]);temp[0]=right[i][k];temp[1]='\0';merge(empt,temp,1);if(result==0&&i<count)continue;else if(result==1&&i<count)return(1);判断读入的文法是否正确int judge()int i,j;for(i=0;i<=count-1;i++)if(in(left[i],non_ter)==0){ /*若左部不在非终结符中,报错*/printf("\nerror1!");validity=0;return(0);for(j=0;j<=strlen(right[i])-1;j++)if(in(right[i][j],non_ter)==0&&in(right[i][j],termin)==0&&right[i][j]!='^'){ /*若右部某一符号不在非终结符、终结符中且不为' ^ ',报错*/ printf("\nerror2!");validity=0;return(0);return(1);求单个符号的FIRSTvoid first2(int i){ /*i为符号在所有输入符号中的序号*/char c,temp[20];int j,k,m;c=v[i];char ch='^';emp(ch);if(in(c,termin)==1) /*若为终结符*/first1[i][0]=c;first1[i][1]='\0';else if(in(c,non_ter)==1) /*若为非终结符*/for(j=0;j<=count-1;j++)if(left[j]==c)if(in(right[j][0],termin)==1||right[j][0]=='^')temp[0]=right[j][0];temp[1]='\0';merge(first1[i],temp,1);else if(in(right[j][0],non_ter)==1)if(right[j][0]==c)continue;for(k=0;;k++)if(v[k]==right[j][0])break;if(f[k]=='0')first2(k);f[k]='1';merge(first1[i],first1[k],2);for(k=0;k<=strlen(right[j])-1;k++)empt[0]='\0';if(_emp(right[j][k])==1&&k<strlen(right[j])-1)for(m=0;;m++)if(v[m]==right[j][k+1])break;if(f[m]=='0')first2(m);f[m]='1';merge(first1[i],first1[m],2);else if(_emp(right[j][k])==1&&k==strlen(right[j])-1)temp[0]='^';temp[1]='\0';merge(first1[i],temp,1);elsebreak;f[i]='1';求各产生式右部的FIRSTvoid FIRST(int i,char *p)int length;int j,k,m;char temp[20];length=strlen(p);if(length==1) /*如果右部为单个符号*/if(p[0]=='^')if(i>=0)first[i][0]='^';first[i][1]='\0';elseTEMP[0]='^';TEMP[1]='\0';elsefor(j=0;;j++)if(v[j]==p[0])break;if(i>=0)memcpy(first[i],first1[j],strlen(first1[j]));first[i][strlen(first1[j])]='\0';elsememcpy(TEMP,first1[j],strlen(first1[j]));TEMP[strlen(first1[j])]='\0';else /*如果右部为符号串*/ for(j=0;;j++)if(v[j]==p[0])break;if(i>=0)merge(first[i],first1[j],2);elsemerge(TEMP,first1[j],2);for(k=0;k<=length-1;k++)empt[0]='\0';if(_emp(p[k])==1&&k<length-1)for(m=0;;m++)if(v[m]==right[i][k+1])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;求各产生式左部的FOLLOWvoid FOLLOW(int i)int j,k,m,n,result=1;char c,temp[20];c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c;temp[1]='\0';merge(fo,temp,1);if(c==start){ /*若为开始符号*/temp[0]='#';temp[1]='\0';merge(follow[i],temp,1);for(j=0;j<=count-1;j++)if(in(c,right[j])==1) /*找一个右部含有c的产生式*/for(k=0;;k++)if(right[j][k]==c)break; /*k为c在该产生式右部的序号*/for(m=0;;m++)if(v[m]==left[j])break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1){ /*如果c在产生式右部的最后*/if(in(v[m],fo)==1)merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);else{ /*如果c不在产生式右部的最后*/for(n=k+1;n<=strlen(right[j])-1;n++)empt[0]='\0';result*=_emp(right[j][n]);if(result==1){ /*如果右部c后面的符号串能推出^*/if(in(v[m],fo)==1){ /*避免循环递归*/merge(follow[i],follow[m],1);continue;if(F[m]=='0')FOLLOW(m);F[m]='1';merge(follow[i],follow[m],1);for(n=k+1;n<=strlen(right[j])-1;n++)temp[n-k-1]=right[j][n];temp[strlen(right[j])-k-1]='\0';FIRST(-1,temp);merge(follow[i],TEMP,2);F[i]='1';判断读入文法是否为一个LL(1)文法int ll1()int i,j,length,result=1;char temp[50];for(j=0;j<=49;j++){ /*初始化*/first[j][0]='\0';follow[j][0]='\0';first1[j][0]='\0';select[j][0]='\0';TEMP[j]='\0';temp[j]='\0';f[j]='0';F[j]='0';for(j=0;j<=strlen(v)-1;j++)first2(j); /*求单个符号的FIRST集合*/ printf("\nfirst1:");for(j=0;j<=strlen(v)-1;j++)printf("%c:%s ",v[j],first1[j]);printf("\nempty:%s",empty);printf("\n:::\n_emp:");for(j=0;j<=strlen(v)-1;j++)printf("%d ",_emp(v[j]));for(i=0;i<=count-1;i++)FIRST(i,right[i]); /*求FIRST*/printf("\n");for(j=0;j<=strlen(non_ter)-1;j++){ /*求FOLLOW*/if(fo[j]==0)fo[0]='\0';FOLLOW(j);printf("\nfirst:");for(i=0;i<=count-1;i++)printf("%s ",first[i]);printf("\nfollow:");for(i=0;i<=strlen(non_ter)-1;i++)printf("%s ",follow[i]);for(i=0;i<=count-1;i++){ /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i]));select[i][strlen(first[i])]='\0';for(j=0;j<=strlen(right[i])-1;j++)result*=_emp(right[i][j]);if(strlen(right[i])==1&&right[i][0]=='^')result=1;if(result==1)for(j=0;;j++)if(v[j]==left[i])break;merge(select[i],follow[j],1);printf("\nselect:");for(i=0;i<=count-1;i++)printf("%s ",select[i]);memcpy(temp,select[0],strlen(select[0]));temp[strlen(select[0])]='\0';for(i=1;i<=count-1;i++){ /*判断输入文法是否为LL(1)文法*/length=strlen(temp);if(left[i]==left[i-1])merge(temp,select[i],1);if(strlen(temp)<length+strlen(select[i]))return(0);elsetemp[0]='\0';memcpy(temp,select[i],strlen(select[i]));temp[strlen(select[i])]='\0';return(1);构造分析表Mvoid MM()int i,j,k,m;for(i=0;i<=19;i++)for(j=0;j<=19;j++)M[i][j]=-1;i=strlen(termin);termin[i]='#'; /*将#加入终结符数组*/termin[i+1]='\0';for(i=0;i<=count-1;i++)for(m=0;;m++)if(non_ter[m]==left[i])break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++)if(in(select[i][j],termin)==1)for(k=0;;k++)if(termin[k]==select[i][j])break; /*k为产生式右部终结符的序号*/ M[m][k]=i;总控算法void syntax()int i,j,k,m,n,p,q;char ch;char S[50],str[50];printf("请输入该文法的句型:");scanf("%s",str);getchar();i=strlen(str);str[i]='#';str[i+1]='\0';S[0]='#';S[1]=start;S[2]='\0';j=0;ch=str[j];while(1)if(in(S[strlen(S)-1],termin)==1)if(S[strlen(S)-1]!=ch)printf("\n该符号串不是文法的句型!");return;else if(S[strlen(S)-1]=='#')printf("\n该符号串是文法的句型.");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==strlen(termin))printf("\n词法错误!");return;if(M[i][k]==-1)printf("\n语法错误!");return;elsem=M[i][k];if(right[m][0]=='^')S[strlen(S)-1]='\0';elsep=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("\nS:%s str:",S);for(p=j;p<=strlen(str)-1;p++)printf("%c",str[p]);printf(" ");一个用户调用函数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("\nstart:%c",start);strcpy(v,non_ter);strcat(v,termin);printf("\nv:%s",v);printf("\nnon_ter:%s",non_ter);printf("\ntermin:%s",termin);printf("\nright:");for(i=0;i<=count-1;i++)printf("%s ",right[i]);printf("\nleft:");for(i=0;i<=count-1;i++)printf("%c ",left[i]);if(validity==1)validity=judge();printf("\nvalidity=%d",validity);if(validity==1)printf("\n文法有效");ll=ll1();printf("\nll=%d",ll);if(ll==0)printf("\n该文法不是一个LL1文法!");elseMM();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]);printf("\n");menu();测试二(1)测试输入一个文法(2)测试输入一个符号串(3)测试再次输入一个符号串,然后退出程序5.缺少功能要求(4)可将测试用的表达式事先放在文本文件中,一行存放一个表达式,以分号分割。
LL(1)文法预测分析法实验报告

一、实验原理LL(1)分析法,就是指从左到右扫描输入串(源程序),同时采用最左推导,且对每次直接推导只需向前看一个输入符号,便可确定当前所应当选择的规则。
实现LL(1)分析的程序又称为LL(1)分析程序或LL(1)分析器。
一个文法要能进行LL(1)分析,那么这个文法应该满足:无二义性,无左递归,无左公因子。
当文法满足条件后,再分别构造文法每个非终结符的FIRST和FOLLOW集合,然后根据FIRST和FOLLOW集合构造LL(1)分析表,最后利用分析表,根据LL(1)语法分析构造一个分析器。
LL(1)的语法分析程序包含了三个部分:控制程序,预测分析表函数,先进先出的语法分析栈。
LL(1)预测分析程序的总控程序在判断STACK栈顶符号X和当前的输入符号a做哪种过程的。
对于任何(X,a),总控程序每次都执行下述三种可能的动作之一:(1)若X = a =‘#’,则宣布分析成功,停止分析过程。
(2)若X = a !=‘#’,则把X从STACK栈顶弹出,让a指向下一个输入符号。
(3)若X是一个非终结符,则查看预测分析表M。
若M[A,a]中存放着关于X的一个产生式,那么,首先把X弹出STACK栈顶,然后,把产生式的右部符号串按反序一一弹出STACK栈(若右部符号为ε,则不推什么东西进STACK栈)。
若M[A,a]中存放着“出错标志”,则调用出错诊断程序ERROR。
1 LL(1)分析法LL(1)分析法又称预测分析法,是一种不带回溯的非递归自顶向下分析法。
LL(1)的含义是:第一个L表明自顶向下分析是从左至右扫描输入串的;第二个L 表明分析过程中将用最左推导;“1”表明只需向右查看一个符号就可以决定如何推导(即可知用哪一个产生式进行推导)。
LL(1)分析器结构如图1:图 1 LL(1)分析器使用 L L(1)分析法将会涉及到 L L(1)分析表,而分析表又会涉及到 FIRST 集 和 F OLLOW 集。
FIRST 集构造对文法中的每一个非终结符 X 构造 F IRST(X),其方法是连续使用以下规则, 直到每个集合的 F IRST 不再增大为止。
(完整word版)SLR(1)文法分析实验报告

《编译原理》课程设计报告—SLR(1)分析的实现学院计算机科学与技术专业计算机科学与技术学号学生姓名指导教师姓名2015年12月26日目录1.设计的目的与内容 (1)1。
1课程设计的目的 (1)1。
2设计内容 (1)1。
3设计要求 (1)1。
4理论基础 (1)2算法的基本思想 (2)2.1主要功能函数 (2)2.2算法思想 (3)SLR文法构造分析表的主要思想: (3)解决冲突的方法: (3)SLR语法分析表的构造方法: (4)3主要功能模块流程图 (5)3。
1主函数功能流程图 (5)4系统测试 (6)5 结论 (11)附录程序源码清单 (12)1.设计的目的与内容1.1课程设计的目的编译原理课程设计是计算机专业重要的教学环节,它为学生提供了一个既动手又动脑,将课本上的理论知识和实际有机的结合起来,独立分析和解决实际问题的机会.●进一步巩固和复习编译原理的基础知识.●培养学生结构化程序、模块化程序设计的方法和能力。
●提高学生对于编程语言原理的理解能力。
●加深学生对于编程语言实现手段的印象。
1.2设计内容构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
1。
3设计要求1)SLR(1)分析表的生成可以选择编程序生成,也可选择手动生成;2)程序要求要配合适当的错误处理机制;3)要打印句子的文法分析过程。
1。
4理论基础由于大多数适用的程序设计语言的文法不能满足LR(0)文法的条件,即使是描述一个实数变量说明这样简单的文法也不一定是LR(0)文法.因此对于LR(0)规范族中有冲突的项目集(状态)用向前查看一个符号的办法进行处理,以解决冲突。
这种办法将能满足一些文法的需要,因为只对有冲突的状态才向前查看一个符号,以确定做那种动作,因而称这种分析方法为简单的LR(1)分析法,用SLR(1)表示。
12算法的基本思想2。
最新广东海洋大学编译原理LL(1)文法分析器实验(java)

GDOU-B-11-112广东海洋大学学生实验报告书(学生用表)实验名称实验3:语法分析课程名称编译原理课程号16242211 学院(系) 数学与计算机学院专业计算机科学与技术班级计科1141学生姓名学号实验地点科425 实验日期2017.4.21一、实验目的熟悉语法分析的过程;理解相关文法的步骤;熟悉First集和Follow集生成二、实验要求对于给定的文法,试编写调试一个语法分析程序:要求和提示:(1)可选择一种你感兴趣的语法分析方法(LL(1)、算符优先、递归下降、SLR(1)等)作为编制语法分析程序的依据。
(2)对于所选定的分析方法,如有需要,应选择一种合适的数据结构,以构造所给文法的机内表示。
(3)能进行分析过程模拟。
如输入一个句子,能输出与句子对应的语法树,能对语法树生成过程进行模拟;能够输出分析过程每一步符号栈的变化情况。
设计一个由给定文法生成First集和Follow集并进行简化的算法动态模拟。
三、实验过程1:文法:E->TE’E’->+TE’|εT->FT’T’->*FT’|εF->(E)|i:2程序描述(LL(1)文法)本程序是基于已构建好的某一个语法的预测分析表来对用户的输入字符串进行分析,判断输入的字符串是否属于该文法的句子。
基本实现思想:接收用户输入的字符串(字符串以“#”表示结束)后,对用做分析栈的一维数组和存放分析表的二维数组进行初始化。
然后取出分析栈的栈顶字符,判断是否为终结符,若为终结符则判断是否为“#”且与当前输入符号一样,若是则语法分析结束,输入的字符串为文法的一个句子,否则出错若不为“#”且与当前输入符号一样则将栈顶符号出栈,当前输入符号从输入字符串中除去,进入下一个字符的分析。
若不为“#”且不与当前输入符号一样,则出错。
四、程序流程图本程序中使用以下文法作对用户输入的字符串进行分析:E→TE’E’→+TE’|εT→FT’T’→*FT’|εF→i|(E)该文法的预测分析表为:五:结果及截图1、显示预测分析表,提示用户输入字符串2、输入的字符串为正确的句子:3、输入的字符串中包含了不属于终结符集的字符4、输入的字符串不是该文法能推导出来的句子程序代码:package complier;import java.io.*;public class LL {String Vn[] = { "E", "E'", "T", "T'", "F" }; // 非终结符集String Vt[] = { "i", "+", "*", "(", ")", "#" }; // 终结符集String P[][] = new String[5][6]; // 预测分析表String fenxi[] ; // 分析栈int count = 1; // 步骤int count1 = 1;//’分析栈指针int count2 = 0, count3 = 0;//预测分析表指针String inputString = ""; // 输入的字符串boolean flag;public void setCount(int count, int count1, int count2, int count3){ this.count = count;this.count1 = count1;this.count2 = count2;this.count3 = count3;flag = false;}public void setFenxi() { // 初始化分析栈fenxi = new String[20];fenxi[0] = "#";fenxi[1] = "E";}public void setP() { // 初始化预测分析表for (int i = 0; i < 5; i++) {for (int j = 0; j < 6; j++) {P[i][j] = "error";}}P[0][0] = "->TE'";P[0][3] = "->TE'";P[1][1] = "->+TE'";P[1][4] = "->ε";P[1][5] = "->ε";P[2][0] = "->FT'";P[2][3] = "->FT'";P[3][1] = "->ε";P[3][2] = "->*FT'";P[3][4] = "->ε";P[3][5] = "->ε";P[4][0] = "->i";P[4][3] = "->(E)";// 打印出预测分析表System.out.println(" 已构建好的预测分析表");System.out.println("----------------------------------------------------------------------");for (int i=0; i<6; i++) {System.out.print(" "+Vt[i]);}System.out.println();System.out.println("----------------------------------------------------------------------");for (int i=0; i<5; i++) {System.out.print(" "+Vn[i]+" ");for (int j=0; j<6; j++) {int l = 0;if (j>0) {l = 10-P[i][j-1].length();}for (int k=0; k<l; k++) {System.out.print(" ");}System.out.print(P[i][j]+" ");}System.out.println();}System.out.println("----------------------------------------------------------------------");}public void setInputString(String input) {inputString = input;}public boolean judge() {String inputChar = inputString.substring(0, 1); // 当前输入字符boolean flage = false;if (count1 >= 0) {for (int i=0; i<6; i++) {if (fenxi[count1].equals(Vt[i])) { // 判断分析栈栈顶的字符是否为终结符flage = true;break;}}}if (flage) {// 为终结符时if (fenxi[count1].equals(inputChar)) {if (fenxi[count1].equals("#")&&inputString.length()==1) { // 栈顶符号为结束标志时// System.out.println("最后一个");String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("接受");flag = true;return true;} else {// 分析栈栈顶符号不为结束标志符号时String fenxizhan = "";for (int i=0; i<=P.length; i++) { // 拿到分析栈里的全部内容(滤去null)if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println("\"" + inputChar + "\"" + "匹配");// 将栈顶符号出栈,栈顶指针减一fenxi[count1] = null;count1 -= 1;if (inputString.length() > 1) { // 当当前输入字符串的长度大于1时,将当前输入字符从输入字符串中除去inputString = inputString.substring(1, inputString.length());} else { // 当前输入串长度为1时inputChar = inputString;}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);// System.out.println(count + inputChar + "匹配 ");count++;judge();}}else { // 判断与与输入符号是否一样为结束标志System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}} else {// 非终结符时boolean fla = false;for (int i=0; i<6; i++) { // 查询当前输入符号位于终结符集的位置if (inputChar.equals(Vt[i])) {fla = true;count2 = i;break;}}if(!fla){System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}for (int i=0; i<5; i++) { // 查询栈顶的符号位于非终结符集的位置if (fenxi[count1].equals(Vn[i])) {count3 = i;break;}}if (P[count3][count2] != "error") { // 栈顶的非终结符与输入的终结符存在产生式时String p = P[count3][count2];String s1 = p.substring(2, p.length()); // 获取对应的产生式if (s1.equals("ε")) { // 产生式推出“ε”时String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" " + count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int k=0; k<farWay; k++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);// 将栈顶符号出栈,栈顶指针指向下一个元素fenxi[count1] = null;count1 -= 1;count++;judge();} else { // 产生式不推出“ε”时int k = s1.length();String fenxizhan = "";for (int i=0; i<=P.length; i++) {if (fenxi[i] == null) {break;} else {fenxizhan = fenxizhan + fenxi[i];}}// 输出当前分析栈情况,输入字符串,所用产生式或匹配System.out.print(" "+count);String countToString = Integer.toString(count);int farWay = 14 - countToString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(fenxizhan);farWay = 20 - fenxizhan.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.print(inputString);farWay = 25 - inputString.length();for (int o=0; o<farWay; o++) {System.out.print(" ");}System.out.println(fenxi[count1] + P[count3][count2]);for (int i=1; i<=k; i++) { // 将产生式右部的各个符号入栈String s2 = s1.substring(s1.length() - 1,s1.length());s1 = s1.substring(0, s1.length() - 1);if (s2.equals("'")) {s2= s1.substring(s1.length() - 1, s1.length())+ s2;i++;s1 = s1.substring(0, s1.length() - 1);}fenxi[count1] = s2;if (i < k)count1++;// System.out.println("count1=" + count1);}// System.out.println(" "+count+" "+fenxizhan+"// "+inputString +" "+P[count3][count2]);count++;// System.out.println(count);judge();}} else {System.out.println(" 分析到第" + count + "步时出错!");flag = false;return false;}}return flag;}public static void main(String args[]) {LL l = new LL();l.setP();String input = "";boolean flag = true;while (flag) {try {InputStreamReader isr = new InputStreamReader(System.in);BufferedReader br = new BufferedReader(isr);System.out.println();System.out.print("请输入字符串(输入exit退出):");input = br.readLine();} catch (Exception e) {e.printStackTrace();}if(input.equals("exit")){flag = false;}else{l.setInputString(input);l.setCount(1, 1, 0, 0);l.setFenxi();System.out.println();System.out.println("分析过程");System.out.println("----------------------------------------------------------------------");System.out.println(" 步骤 | 分析栈 | 剩余输入串 | 所用产生式 ");System.out.println("----------------------------------------------------------------------");boolean b = l.judge();System.out.println("----------------------------------------------------------------------");if(b){System.out.println("您输入的字符串"+input+"是该文发的一个句子");}else{System.out.println("您输入的字符串"+input+"有词法错误!");}}}}}六:实验心得通过本次实验基本掌握了语法分析的原理和LL(1)语法分析方法,以及预测分析表的构造,进一步熟悉了语法分析的详细过程,收获还是蛮大的,值得我们认真对待。
语法分析实验报告

语法分析实验报告一、实验目的语法分析是编译原理中的重要环节,本次实验的目的在于深入理解和掌握语法分析的基本原理和方法,通过实际操作和实践,提高对编程语言语法结构的分析能力,为进一步学习编译技术和开发相关工具打下坚实的基础。
二、实验环境本次实验使用的编程语言为 Python,使用的开发工具为 PyCharm。
三、实验原理语法分析的任务是在词法分析的基础上,根据给定的语法规则,将输入的单词符号序列分解成各类语法单位,并判断输入字符串是否符合语法规则。
常见的语法分析方法有自顶向下分析法和自底向上分析法。
自顶向下分析法包括递归下降分析法和预测分析法。
递归下降分析法是一种直观、简单的方法,但存在回溯问题,效率较低。
预测分析法通过构建预测分析表,避免了回溯,提高了分析效率,但对于复杂的语法规则,构建预测分析表可能会比较困难。
自底向上分析法主要包括算符优先分析法和 LR 分析法。
算符优先分析法适用于表达式的语法分析,但对于一般的上下文无关文法,其适用范围有限。
LR 分析法是一种功能强大、适用范围广泛的方法,但实现相对复杂。
四、实验内容(一)词法分析首先,对输入的源代码进行词法分析,将其分解为一个个单词符号。
单词符号包括关键字、标识符、常量、运算符、分隔符等。
(二)语法规则定义根据实验要求,定义了相应的语法规则。
例如,对于简单的算术表达式,可以定义如下规则:```Expression > Term | Expression '+' Term | Expression ''TermTerm > Factor | Term '' Factor | Term '/' FactorFactor >'(' Expression ')'| Identifier | Number```(三)语法分析算法实现选择了预测分析法来实现语法分析。
首先,根据语法规则构建预测分析表。
然后,从输入字符串的起始位置开始,按照预测分析表的指导进行分析。
编译原理 COMPILER__实验2.2-LL(1)分析法(1)

编译原理实验报告—LL(1)分析法程序班级:小组人员:实验2.2 LL(1)分析法一、实验目的:1.根据某一文法编制调试LL(1)分析程序,以便对任意输入的符号串进行分析。
2.本次实验的目的主要是加深对预测分析LL(1)分析法的理解。
二、实验平台Windows + VC++6.0程序:“3-LL1.cpp”三、实验内容1.对下列文法,用LL(1)分析法对任意输入的符号串进行分析:(1)E→TG(2)G→+TG|-TG(3)G→ε(4)T→FS(5)S→*FS|/FS(6)S→ε(7)F→(E)(8)F→i程序功能:输入:一个以# 结束的符号串(包括+ - * /()i # ):例如:i+i*i-i/i#输出: 经完善程序目前能对所有输入串进行正确的分析.算法思想:栈用于存放文法符号,分析开始时,栈底先放一个‘#’,然后,放进文法开始符号。
同时,假定输入串之后也总有一个‘#’,标志输入串结束。
现设置一个文法分析表(见表1),矩阵M[A,a]中存放着一条关于A的产生式,指出当A面临符号a时所采用的侯选。
对任何(X,a)其中X为栈顶符号,程序每次都执行下述动作之一:✧如果X=a=‘#’,则输出分析成功,停止分析过程;✧如果X=a且不等于‘#’,则把X从栈顶逐出,让a指向下一个输入符号;✧如果X是一个非终结符,则查看分析表M.若M[A,a]中存放着关于X的一个产生式,那么首先把X从栈顶逐出,然后,把产生式的右部符号串按反序一一推进栈内,若右部符号为ε,则就什么都不进栈。
把产生式推进栈内的同时应做这个产生式相应的语义动作,例如字符i匹配成功,字符出错,相应的产生式等。
输出如下:输出每一步骤分析栈和剩余串的变化情况, 及每一步所用的产生式都明确显示出来。
运行步骤:首先在相同的路径下建一文本文档例如11.txt,将表达式写入文档内如i+i*i-i/i#;运行程序,显示界面如下,输入相应的文件名字,(输入输出文件名是自行定义)打开pp.txt文件,文法分析结果如下:错误提示:1>.输入i++i*i#,结果如下存在的问题:现在只能是遇到错误就停止,而没能实现同步符号ll(1)分析。
ll1文法实验报告

ll1文法实验报告LL1文法实验报告引言LL1文法是一种重要的上下文无关文法,它在编译原理和自然语言处理等领域有着广泛的应用。
本实验旨在通过对LL1文法的分析和实验,探讨其在语法分析中的作用和应用。
实验目的1. 了解LL1文法的定义和特性;2. 分析LL1文法的构造和推导规则;3. 编写一个简单的LL1文法,并进行语法分析;4. 探讨LL1文法在实际应用中的局限性和改进方法。
实验过程首先,我们对LL1文法进行了深入的了解和学习,明确了其定义和特性。
LL1文法是一种上下文无关文法,具有唯一的左推导和右推导,且能够通过预测分析方法进行语法分析。
其构造和推导规则十分严格,要求每个非终结符的每个产生式的首符集都不能相交,且每个非终结符的产生式必须按照首符集进行分组。
接着,我们编写了一个简单的LL1文法,并进行了语法分析。
通过对文法的构造和推导规则进行分析,我们成功地实现了对输入字符串的语法分析,并得出了正确的语法树。
这表明LL1文法在语法分析中具有较高的准确性和可靠性。
然而,在实际应用中,我们也发现了LL1文法的局限性。
由于其严格的构造和推导规则,很多复杂的语法无法直接用LL1文法表示,需要进行一定的改进和优化。
因此,我们对LL1文法进行了进一步的探讨和改进,提出了一些解决方案和改进方法,以更好地满足实际应用的需求。
结论通过本次实验,我们对LL1文法有了更深入的了解和认识,明确了其在语法分析中的作用和应用。
同时,我们也发现了LL1文法的局限性,并提出了一些改进方法。
我们相信,在今后的研究和实践中,LL1文法将会得到更广泛的应用和发展。
LL(1)语法分析实验报告

LL(1)语法分析实验报告一、实验目的通过设计、编制、调试一个典型的语法分析程序,实现对词法分析程序所提供的单词序列进行语法检查和结构分析,检查语法错误,进一步掌握常用的语法分析方法。
二、实验内容构造LL(1)语法分析程序,任意输入一个文法符号串,并判断它是否为文法的一个句子。
程序要求为该文法构造预测分析表,并按照预测分析算法对输入串进行语法分析,判别程序是否符合已知的语法规则,如果不符合则输出错误信息。
消除递归前的文法消除递归后的等价文法E→E+T E→TE’E→T E’→+TE’|εT→T*F T→FT’T→F T’→*FT’|εF→(E)|i F→(E)|i根据已建立的分析表,对下列输入串:i+i*i进行语法分析,判断其是否符合文法。
三、实验要求1.根据已由的文法规则建立LL(1)分析表;2.输出分析过程。
请输入待分析的字符串: i+i*i符号栈输入串所用产生式#E i+i*i# E→TE’#E’T i+i*i# T→FT’#E’T’F i+i*i# F→i#E’T’i i+i*i##E’T’ +i*i# T’→ε#E’ +i*i# E’→+TE’#E’T+ +i*i##E’T i*i# T→FT’#E’T’F i*i# F→i#E’T’i i*i##E’T’ *i# T’→*FT’#E’T’F* *i##E’T’F i# F→i#E’T’i i##E’T’ # T’→ε#E’ # E’→ε# #四、程序思路模块结构:1、定义部分:定义常量、变量、数据结构。
2、初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体等);3、运行程序:让程序分析一个text文件,判断输入的字符串是否符合文法定义的规则;4、利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分析结果,如果遇到错误则显示简单的错误提示。
五、程序流程图输入要分析的串判断输入串是否正确判断分析句型是否完全匹配?成功失败否是是否八、程序调试与测试结果运行后结果如下:九、实验心得递归下降分析法是确定的自上而下分析法,这种分析法要求文法是LL(1)文法。
编译原理LL1文法实验(精选.)

{
//cout<<"匹配失败!"<<endl;
return false;
}
else
{
if (str[0]!='^')
{
for (int i=strlen(str)-1;i>=0;i--)
push(str[i]);
}
print();
cout<<'\t'<<v2[m]<<"-->"<<str<<endl;
第三次是函数调用错误,改错。
实验结果截图:
i+i*i#Leabharlann i*(i+i)#四、
本次实验较上次稍难,主要是移近匹配已经判断的思想和流程要充分的理解到位。虽然,老师课上已经讲解了许多,而且实验时也指导了我们一些该注意的地方,但是,在真正编程的过程中还是遇到了许多问题,比如说,如何用一个数组实现让字符串逆序进栈,以及文件的读取和存取内容的相关操作。当然问题最多的还是栈顶元素与剩余字符串的移进匹配过程,这一点我老是搞不太清楚。不过在同学的帮助和指导下这些问题都慢慢的解决了。本次试验共花费了四天时间,历时教长,当然程序中依然存在很多问题,比如对匹配失败的具体原因没有详细显现出来。不过总体来说,使我的编程能力得到了很大的提高。
}
else if(iszhongjie(X)!=-1)
{sym=fgetc(fp);}
else if(!chabiao(X,sym)){
cuo=true;
}
}
return 0;
}
三、实验过程记录:
LL(1)文法分析

编译原理课程设计报告选题名称:LL(1)语法分析系(院):计算机工程系专业:计算机科学与技术学年学期:2010 ~ 2011 学年第 1 学期2010 年12 月30 日设计任务书指导教师(签章):年月日摘要:语法分析是编译程序的核心部分。
语法分析的作用是识别由词法分析给出的单词符号序列是否是给定的文法的正确句子。
目前语法分析常用的方法右自顶向下分析和自底向上分析两大类.确定的自顶向下方法,是从文法的开始符号,考虑如何根据当前的输入符号(单词)唯一的确定选用哪个产生式替换相应非终结符往下推导。
LL(1)文法是一种确定的自顶向下的分析方法.LL(1)分析法的功能是利用LL(1)控制程序根据显示栈顶内容、向前看符号以及LL(1)分析表,对输入符号串自上而下的分析过程。
可通过消除左递归、提取左因子把非LL(1)文法改造成LL(1)文法。
当文法满足条件后,分别构造出文法的每个非终结符的FIRST、FOLLOW集合和SELECT集,根据SELECT 集合判断是否是LL(1)文法.在LL(1)预测分析程序设计过程中,最重要的两个问题是预测分析表的构造和相关数据结构的设计。
而预测分析表的构造首先必须计算文法每个非终结符的FIRST集和FOLLOW集。
要知道一串符号是不是该文法的一个句子,只要判断是否能从文法的开始符号出发推导出这个输入串。
语法分析可以分为两类,一类是自上而下的分析法,一类是自下而上的分析法。
自上而下的主旨是,对任何输入串,试图用一切可能的办法,从文法开始符号出发,自上而下的为输入串建立一棵语法树。
或者说,为输入串寻找一个最左推倒,这种分析过程的本质是一种试探过程,是反复使用不同产生式谋求匹配输入串的过程我主要是自上而下的过程。
关键词:语法分析;LL(1)分析;FIRST集合;FOLLOW集合;自上而下分析目录1 课题综述 (1)1.1课题来源和意义 (1)1。
2预期目标 (1)1.3解决问题 (1)2 系统分析 (1)2.1涉及的知识基础 (1)2.1.1LL(1)文法……………………………………………………………………………………。
文法的实验报告

实验名称:文法分析实验实验日期:2023年4月10日实验地点:计算机实验室实验目的:1. 理解文法分析的基本概念和原理。
2. 掌握使用文法分析工具进行语法分析的方法。
3. 分析给定文本的语法结构,提高对自然语言处理的认知。
实验器材:1. 计算机2. 文法分析工具(如:LL(1)分析器、LR(1)分析器等)3. 实验教材和参考资料实验步骤:一、文法分析基本概念介绍1. 定义文法:文法是描述一组字符串集合的规则,用于判断一个字符串是否属于该集合。
2. 语法分析:语法分析是自然语言处理中的一项基本任务,旨在将自然语言文本转换为结构化表示,如抽象语法树(AST)。
3. 文法分类:根据文法生成的方法,文法可以分为正规文法和上下文无关文法。
二、文法分析工具使用1. LL(1)分析器:LL(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是易于实现,但只能处理部分上下文无关文法。
2. LR(1)分析器:LR(1)分析器是一种自底向上的分析器,适用于分析上下文无关文法。
其特点是能够处理更广泛的上下文无关文法,但实现相对复杂。
三、实验内容1. 分析给定文本的语法结构,提取出其文法规则。
2. 使用文法分析工具对文本进行语法分析,生成抽象语法树(AST)。
实验过程:一、文法规则提取以英文句子“Hello, how are you?”为例,其文法规则如下:S → NP VPNP → Det NVP → V NPDet → 'a' | 'an' | 'the'N → 'Hello' | 'how' | 'are' | 'you'V → 'are'二、文法分析工具使用1. 使用LL(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'are'V -> 'you'2. 使用LR(1)分析器对句子进行语法分析:输入:Hello, how are you?输出:S -> NP VPNP -> Det NVP -> V NPDet -> 'the'N -> 'Hello'V -> 'are'NP -> Det NVP -> V NPDet -> 'how'N -> 'you'实验结果分析:通过使用文法分析工具对给定文本进行语法分析,我们可以清晰地看到文本的语法结构。
实验1__词法分析实验报告

case -2: row=row++;break;
default: cout<<"("<<syn<<","<<token<<")"<<endl;break;
}
}
while (syn!=0);}
四:实验验证
}
else
{
syn=20;
p--;
}
break;case':':m=0;token[m++]=ch;
ch=prog[p++];
if(ch=='=')
{
syn=18;
token[m++]=ch;
}
else
{
syn=17;
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=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;case'\n':syn=-2;break;default: syn=-1;break;
实验一文法分析方法及其应用

字符集为26个字母+“〞〔空格〕+“\r\n〞〔回车换行〕;从文件开场一直到完毕,持续输出,不额外换行〔除非遇到生成的\r\n〕,总共输出的文件大小可控制。
过滤停用词:写一个程序,快速扫描待过滤文本,然后将待过滤文本中出现的所有停用词,交换为“**〞,要求禁用正那么表达式,不要误杀〔例如,假设停用词包括“abc〞,那么“abcd〞等不应该被误杀。
第三局部:文法化简
设计文法类,实现对文法G[S]=(Vt, Vn, P, S)的文件读写,文法的文件表示形式以及内存表示形式可自定义。本质上,文法就是3个集合+1个符号,重点〔难点〕是产生式集合如何处理。文法的文本形式可根据自己需要自由定义。在前述的根底上,实现文法化简的无用符号及无用产生式消除算法〔即课本算法2.1、2.2〕。
方法、步骤:
要完本钱实验,根据实验要求进展分解,需要完成的实验步骤是:
1.如何读写文件?
读写文法文件内容,需要用到文件IO,查阅、复习文件IO操作。
请在这里,补充完善你的设计思路,完成后,请删去这句话。
2.如何分词?
第一局部实验要求进展分词,源代码中的单词可以分成3类,一类是约定的保存字,一类是普通标识符,最后一类是数字
实验结论:
1.测试用例的设计与说明
对每局部的实验,你分别设计了什么测试数据〔测试用例〕进展测试,你设计测试数据的出发点是什么,有什么目的?
2.测试结果的说明与分析
对测试〔实验〕结果进展分析说明
心得体会:
除了实验的心得体会外,
还要额外增加说明你对文法、直接推导、推导、句型、句子、语言这些概念的理解。
指导老师批阅意见:
lr1文法实验报告

lr1文法实验报告竭诚为您提供优质文档/双击可除lr1文法实验报告篇一:实验四LR(1)分析法实验四LR(1)分析法实验学时:2实验类型:验证实验要求:必修一、实验目的构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。
二、实验内容对下列文法,用LR(1)分析法对任意输入的符号串进行分析:(1)e-e+T(2)e-e—T(3)T-T*F(4)T-T/F(5)F-(e)(6)F-i三、LR(1)分析法实验设计思想及算法(1)总控程序,也可以称为驱动程序。
对所有的LR分析器总控程序都是相同的。
(2)分析表或分析函数,不同的文法分析表将不同,同一个文法采用的LR分析器不同时,分析表将不同,分析表又可以分为动作表(AcTIon)和状态转换(goTo)表两个部分,它们都可用二维数组表示。
(3)分析栈,包括文法符号栈和相应的状态栈,它们均是先进后出栈。
分析器的动作就是由栈顶状态和当前输入符号所决定。
?LR分析器由三个部分组成:其中:sp为栈指针,s[i]为状态栈,x[i]为文法符号栈。
状态转换表用goTo[i,x]=j表示,规定当栈顶状态为i,遇到当前文法符号为x 时应转向状态j,x为终结符或非终结符。
AcTIon[i,a]规定了栈顶状态为i时遇到输入符号a应执行。
动作有四种可能:(1)移进:action[i,a]=sj:状态j移入到状态栈,把a移入到文法符号栈,其中i,j表示状态号。
(2)归约:action[i,a]=rk:当在栈顶形成句柄时,则归约为相应的非终结符A,即文法中有A-b的产生式,若b的长度为R(即|b|=R),则从状态栈和文法符号栈中自顶向下去掉R个符号,即栈指针sp减去R,并把A移入文法符号栈内,j=goT o[i,A]移进状态栈,其中i为修改指针后的栈顶状态。
(3)接受acc:当归约到文法符号栈中只剩文法的开始符号s时,并且输入符号串已结束即当前输入符是#,则为分析成功。
文法类型的实验报告

一、实验目的1. 理解文法类型的基本概念和分类方法。
2. 掌握常用文法类型的特点和应用场景。
3. 通过实验,提高对文法类型分析的实际操作能力。
二、实验背景文法类型是指按照一定的语法规则对自然语言进行分类的方法。
在自然语言处理领域,文法类型分析对于文本分类、信息提取、机器翻译等任务具有重要意义。
本文将介绍几种常见的文法类型,并通过实验进行分析。
三、实验内容1. 实验数据:选取一篇关于人工智能领域的中文文章作为实验数据。
2. 实验工具:Python编程语言,NLP库(如jieba、NLTK等)。
3. 实验步骤:(1)数据预处理:对实验数据进行分词、去停用词等操作。
(2)文法类型分类:根据实验数据的特点,选择合适的文法类型进行分类。
(3)结果分析:对比不同文法类型在实验数据上的分类效果。
四、实验结果与分析1. 数据预处理使用jieba分词库对实验数据进行分词,去除停用词,得到实验数据。
2. 文法类型分类(1)词性标注:使用jieba分词库对实验数据进行词性标注,得到每个词的词性。
(2)命名实体识别:使用jieba分词库对实验数据进行命名实体识别,识别出实验数据中的命名实体。
(3)句法分析:使用NLTK库对实验数据进行句法分析,提取句子成分。
(4)依存句法分析:使用Stanford CoreNLP库对实验数据进行依存句法分析,提取句子成分之间的依存关系。
3. 结果分析(1)词性标注结果实验数据中,名词、动词、形容词等词性占比最高,说明实验数据主要涉及人工智能领域的专业术语。
(2)命名实体识别结果实验数据中,人名、机构名、地点名等命名实体占比较高,说明实验数据主要涉及人工智能领域的相关实体。
(3)句法分析结果实验数据中,句子结构较为复杂,主语、谓语、宾语等句子成分齐全,说明实验数据具有较高的句法复杂性。
(4)依存句法分析结果实验数据中,句子成分之间的依存关系较为复杂,说明实验数据具有较高的依存句法复杂性。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第一部分:分词
输入:输入是一个文本文件,里面的内容是符合某个语言语法、词法要求的源代码(输入文件为C++或者Java源程序,词语、语法定义参考C++、Java即可;C++、Java大家只需要选择一种自己熟悉的语言就可以),例如“position= initial + rate * 60;”;
输出:设计并实现对输入文件的处理(禁用正则表达式),以获得如下输出,输出是一个文本文件,对前面例子,里面内容是:
深圳大学实验报告
课程名称:编译原理
实验项目名称:文法分析方法及其应用
学院:计算机与软件学院
专业:软件工程
指导教师:陈飞
报告人:学号:班级:
实验时间:2015年10月12日至2015年11月9日
实验报告提交时间:
教务处制
实验目的与要求:
目的:针对分词、停用词过滤等文法分析应用问题,设计并实现相应的解决方案,再通过设计文法相关类族,以及实现文法化简等方法,既加深对抽象的文法、推导、语言等形式语言理论基础概念的理解与掌握,也加强对面向对象程序编写能力和计算思维的培养。
2.1如何识别保留字?
2.2如何识别标识符?
2.3如何识别数字?
特别的,如果你有多种方法来识别这3类单词,那这些方法有何优缺点?分析并作出你的选择。
请在这里,补充完善你的设计思路,完成后,请删去这句话。
3.如何产生符合要求的随机停用词和待处理文本
第二部分实验要求先产生随机的停用词和待处理文本,主要是如何产生符合要求的这些词或文本?
第三部分:文法化简
设计文法类,实现对文法G[S]=(Vt, Vn, P, S)的文件读写,文法的文件表示形式以及内存表示形式可自定义。本质上,文法就是3个集合+1个符号,重点(难点)是产生式集合如何处理。文法的文本形式可根据自己需要自由定义。在前述的基础上,实现文法化简的无用符号及无用产生式消除算法(即课本算法2.1、2.2)。
(标识符,position)
(赋值运算符,=)
(标识符,initial)
(加法运算符,+)
(标识符,rate)
(乘法运算符,*)
(整数,60)
(分隔符,; )
第二部分:停用词过滤,分为“产生随机停用词”、“产生随机待过滤文本”和“过滤停用词”3个小实验。
产生随机停用词:生成一个文件长度和单词平均长度可控的文本文件,要求字符集为26个字母,每行生产一个单词,每个单词的长度随机,全部单词的平均长度可控制,通常为4、5(非严格要求),总共输出的文件长度可控制。
实验结论:
1.测试用例的设计与说明
对每部分的实验,你分别设计了什么测试数据(测试用例)进行测试,你设计测试数据的出发点是什么,有什么目的?
2.测试结果的说明与分析
对测试(实验)结果进行分析说明
心得体会:
除了实验的心得体会外,
还要额外增加说明你对文法、直接推导、推导、句型、句子、语言这些概念的理解。
指导教师批阅意见:
3.1如何产生随机停用词?
3.2如何控制随机停用词的平均长度(而不是固定长度)?
3.3如何产生待处理文本中的“段落”?
3.4如何控制待处理文本的长度?
请在这里,补充完善你的设计思路,完成后,请删去这句话。理文本中出现的停用词替换为“**”,那你如何准确、快速判断出文本中的停用词?
产生随机待过滤文本:生成一个文件大小和单词平均长度可控的文本文件,要求
字符集为26个字母+“”(空格)+“\r\n”(回车换行);从文件开始一直到结束,持续输出,不额外换行(除非遇到生成的\r\n),总共输出的文件大小可控制。
过滤停用词:写一个程序,快速扫描待过滤文本,然后将待过滤文本中出现的所有停用词,替换为“**”,要求禁用正则表达式,不要误杀(例如,若停用词包括“abc”,那么“abcd”等不应该被误杀。
方法、步骤:
要完成本实验,依据实验要求进行分解,需要完成的实验步骤是:
1.如何读写文件?
读写文法文件内容,需要用到文件IO,查阅、复习文件IO操作。
请在这里,补充完善你的设计思路,完成后,请删去这句话。
2.如何分词?
第一部分实验要求进行分词,源代码中的单词可以分成3类,一类是约定的保留字,一类是普通标识符,最后一类是数字
成绩评定:
指导教师签字:陈飞
2015年11月17日
备注:
5.如何设计文法类?
文法类里面,有3个集合,1个特别的非终结符——开始符号。集合应如何表示?Set<Type>是常见的范型,可使用例如Set<Production>来表示产生式的集合。也可直接采用数组等形式来表示,那种方法更好?分析并做出你的设计。
请在这里,补充完善你的设计思路,完成后,请删去这句话。
6.如何实现无用文法的化简算法?
算法2.1、2.2课本已经给出了说明,那你如何将算法说明变成代码?有什么主要内容?
请在这里,补充完善你的设计思路,完成后,请删去这句话。
实验过程及内容:
实验过程及内容,处理代码设计说明、代码及其注释外,特别关注编程过程。
要求,至少有一张照片,照片上出现你(正面)+正在写的代码(电脑要有外观)