c语言语法分析器
#include
#include
#include
/*******************************************/
int count=0; /*分解的产生式的个数*/
int number; /*所有终结符和非终结符的总数*/
char start; /*开始符号*/
char termin[50]; /*终结符号*/
char non_ter[50]; /*非终结符号*/
char v[50]; /*所有符号*/
char left[50]; /*左部*/
char right[50][50]; /*右部*/
char first[50][50],follow[50][50]; /*各产生式右部的FIRST和左部的FOLLOW集合*/ char first1[50][50]; /*所有单个符号的FIRST集合*/
char select[50][50]; /*各单个产生式的SELECT集合*/
char f[50],F[50]; /*记录各符号的FIRST和FOLLOW是否已求过*/
char empty[20]; /*记录可直接推出@的符号*/
char TEMP[50]; /*求FOLLOW时存放某一符号串的FIRST集合*/
int validity=1; /*表示输入文法是否有效*/
int ll=1; /*表示输入文法是否为LL(1)文法*/
int M[20][20]; /*分析表*/
char choose; /*用户输入时使用*/
char empt[20]; /*求_emp()时使用*/
char fo[20]; /*求FOLLOW集合时使用*/
/*******************************************
判断一个字符是否在指定字符串中
********************************************/
int in(char c,char *p)
{
int i;
if(strlen(p)==0)
return(0);
for(i=0;;i++)
{
if(p[i]==c)
return(1); /*若在,返回1*/
if(i==strlen(p))
return(0); /*若不在,返回0*/
}
}
/*******************************************
得到一个不是非终结符的符号
********************************************/
char c()
{
char c='A';
while(in(c,non_ter)==1)
c++;
return(c);
}
/*******************************************
分解含有左递归的产生式
********************************************/
void recur(char *point)
{ /*完整的产生式在point[]中*/ int j,m=0,n=3,k;
char temp[20],ch;
ch=c(); /*得到一个非终结符*/
k=strlen(non_ter);
non_ter[k]=ch;
non_ter[k+1]='\0';
for(j=0;j<=strlen(point)-1;j++)
{
if(point[n]==point[0])
{ /*如果'|'后的首符号和左部相同*/ for(j=n+1;j<=strlen(point)-1;j++)
{
while(point[j]!='|'&&point[j]!='\0')
temp[m++]=point[j++];
left[count]=ch;
memcpy(right[count],temp,m);
right[count][m]=ch;
right[count][m+1]='\0';
m=0;
count++;
if(point[j]=='|')
{
n=j+1;
break;
}
}
}
else
{ /*如果'|'后的首符号和左部不同*/ left[count]=ch;
right[count][0]='@';
right[count][1]='\0';
count++;
for(j=n;j<=strlen(point)-1;j++)
{
if(point[j]!='|')
temp[m++]=point[j];
else
{
left[count]=point[0];
memcpy(right[count],temp,m);
right[count][m]=ch;
right[count][m+1]='\0';
printf(" count=%d ",count);
m=0;
count++;
}
}
left[count]=point[0];
memcpy(right[count],temp,m);
right[count][m]=ch;
right[count][m+1]='\0';
count++;
m=0;
}
}
}
/******************************************* 分解不含有左递归的产生式
********************************************/ void non_re(char *point)
{
int m=0,j;
char temp[20];
for(j=3;j<=strlen(point)-1;j++)
{
if(point[j]!='|')
temp[m++]=point[j];
else
{
left[count]=point[0];
memcpy(right[count],temp,m);
right[count][m]='\0';
m=0;
count++;
}
}
left[count]=point[0];
memcpy(right[count],temp,m);
right[count][m]='\0';
count++;
m=0;
}
/*******************************************
读入一个文法
********************************************/ char grammer(char *t,char *n,char *left,char right[50][50]) {
char vn[50],vt[50];
char s;
char p[50][50];
int i,j,k;
printf("请输入文法的非终结符号串:");
scanf("%s",vn);
getchar();
i=strlen(vn);
memcpy(n,vn,i);
n[i]='\0';
printf("请输入文法的终结符号串:");
scanf("%s",vt);
getchar();
i=strlen(vt);
memcpy(t,vt,i);
t[i]='\0';
printf("请输入文法的开始符号:");
scanf("%c",&s);
getchar();
printf("请输入文法产生式的条数:");
scanf("%d",&i);
getchar();
for(j=1;j<=i;j++)
{
printf("请输入文法的第%d条(共%d条)产生式:",j,i); scanf("%s",p[j-1]);
getchar();
}
for(j=0;j<=i-1;j++)
if(p[j][1]!='-'||p[j][2]!='>')
{ printf("\ninput error!");
validity=0;
return('\0');
} /*检测输入错误*/
for(k=0;k<=i-1;k++)
{ /*分解输入的各产生式*/
if(p[k][3]==p[k][0])
recur(p[k]);
else
non_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 break; if(j==strlen(d)) { d[j]=s[i]; d[j+1]='\0'; break; } } } } } /******************************************* 求所有能直接推出@的符号 ********************************************/ void emp(char c) { /*即求所有由' @ '推出的符号*/ char temp[10]; int i; for(i=0;i<=count-1;i++) { if(right[i][0]==c&&strlen(right[i])==1) { temp[0]=left[i]; temp[1]='\0'; merge(empty,temp,1); emp(left[i]); } } } /******************************************* 求某一符号能否推出' @ ' ********************************************/ int _emp(char c) { /*若能推出,返回1;否则,返回0*/ int i,j,k,result=1,mark=0; char temp[20]; temp[0]=c; temp[1]='\0'; merge(empt,temp,1); if(in(c,empty)==1) return(1); for(i=0;;i++) { if(i==count) return(0); if(left[i]==c) /*找一个左部为c的产生式*/ { j=strlen(right[i]); /*j为右部的长度*/ if(j==1&&in(right[i][0],empty)==1) return(1); else if(j==1&&in(right[i][0],termin)==1) return(0); else { for(k=0;k<=j-1;k++) if(in(right[i][k],empt)==1) mark=1; if(mark==1) continue; else { for(k=0;k<=j-1;k++) { result*=_emp(right[i][k]); temp[0]=right[i][k]; temp[1]='\0'; merge(empt,temp,1); } } } if(result==0&&i continue; else if(result==1&&i 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 { 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); } else break; } } } } } 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); else merge(TEMP,first1[j],2); for(k=0;k<=length-1;k++) { empt[0]='\0'; if(_emp(p[k])==1&&k { for(m=0;;m++) if(v[m]==right[i][k+1]) break; if(i>=0) merge(first[i],first1[m],2); else merge(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); else merge(TEMP,temp,1); } else if(_emp(p[k])==0) break; } } } /******************************************* 求各产生式左部的FOLLOW ********************************************/ void FOLLOW(int i) { int j,k,m,n,result=1; char c,temp[20]; c=non_ter[i]; /*c为待求的非终结符*/ temp[0]=c; temp[1]='\0'; merge(fo,temp,1); if(c==start) { /*若为开始符号*/ temp[0]='#'; temp[1]='\0'; merge(follow[i],temp,1); } for(j=0;j<=count-1;j++) { if(in(c,right[j])==1) /*找一个右部含有c的产生式*/ { for(k=0;;k++) if(right[j][k]==c) break; /*k为c在该产生式右部的序号*/ for(m=0;;m++) if(v[m]==left[j]) break; /*m为产生式左部非终结符在所有符号中的序号*/ if(k==strlen(right[j])-1) { /*如果c在产生式右部的最后*/ if(in(v[m],fo)==1) { merge(follow[i],follow[m],1); continue; } if(F[m]=='0') { FOLLOW(m); F[m]='1'; } merge(follow[i],follow[m],1); } else { /*如果c不在产生式右部的最后*/ for(n=k+1;n<=strlen(right[j])-1;n++) { empt[0]='\0'; result*=_emp(right[j][n]); } if(result==1) { /*如果右部c后面的符号串能推出^*/ if(in(v[m],fo)==1) { /*避免循环递归*/ merge(follow[i],follow[m],1); continue; } if(F[m]=='0') { FOLLOW(m); F[m]='1'; } merge(follow[i],follow[m],1); } for(n=k+1;n<=strlen(right[j])-1;n++) temp[n-k-1]=right[j][n]; temp[strlen(right[j])-k-1]='\0'; FIRST(-1,temp); merge(follow[i],TEMP,2); } } } F[i]='1'; } /******************************************* 判断读入文法是否为一个LL(1)文法 ********************************************/ int ll1() { int i,j,length,result=1; char temp[50]; for(j=0;j<=49;j++) { /*初始化*/ first[j][0]='\0'; follow[j][0]='\0'; first1[j][0]='\0'; select[j][0]='\0'; TEMP[j]='\0'; temp[j]='\0'; f[j]='0'; F[j]='0'; } for(j=0;j<=strlen(v)-1;j++) first2(j); /*求单个符号的FIRST集合*/ printf("\n各非终结符导出的first集:"); for(j=0;j<=strlen(v)-1;j++) printf("%c:%s ",v[j],first1[j]); printf("\n能导空的非终结符集合:%s",empty); // printf("\n_emp:"); //for(j=0;j<=strlen(v)-1;j++) // printf("%d ",_emp(v[j])); for(i=0;i<=count-1;i++) FIRST(i,right[i]); /*求FIRST*/ for(j=0;j<=strlen(non_ter)-1;j++) { /*求FOLLOW*/ if(fo[j]==0) { fo[0]='\0'; FOLLOW(j); } } //printf("\nfirst:"); //for(i=0;i<=count-1;i++) // printf("%s ",first[i]); printf("\nfollow集合:"); for(i=0;i<=strlen(non_ter)-1;i++) printf("%s ",follow[i]); for(i=0;i<=count-1;i++) { /*求每一产生式的SELECT集合*/ memcpy(select[i],first[i],strlen(first[i])); select[i][strlen(first[i])]='\0'; for(j=0;j<=strlen(right[i])-1;j++) result*=_emp(right[i][j]); if(strlen(right[i])==1&&right[i][0]=='@') result=1; if(result==1) { for(j=0;;j++) if(v[j]==left[i]) break; merge(select[i],follow[j],1); } } printf("\nselect集合顺序是:"); for(i=0;i<=count-1;i++) printf("%s ",select[i]); memcpy(temp,select[0],strlen(select[0])); temp[strlen(select[0])]='\0'; for(i=1;i<=count-1;i++) { /*判断输入文法是否为LL(1)文法*/ length=strlen(temp); if(left[i]==left[i-1]) { merge(temp,select[i],1); if(strlen(temp) return(0); } else { temp[0]='\0'; memcpy(temp,select[i],strlen(select[i])); temp[strlen(select[i])]='\0'; } } return(1); } /******************************************* 构造分析表M ********************************************/ void MM() { int i,j,k,m; for(i=0;i<=19;i++) for(j=0;j<=19;j++) M[i][j]=-1; i=strlen(termin); termin[i]='#'; /*将#加入终结符数组*/ termin[i+1]='\0'; for(i=0;i<=count-1;i++) { for(m=0;;m++) if(non_ter[m]==left[i]) break; /*m为产生式左部非终结符的序号*/ for(j=0;j<=strlen(select[i])-1;j++) { if(in(select[i][j],termin)==1) { for(k=0;;k++) if(termin[k]==select[i][j]) break; /*k为产生式右部终结符的序号*/ M[m][k]=i; } } } } /******************************************* 判断符号串是否是该文法的句型 ********************************************/ void syntax() { int i,j,k,m,n,p,q; char ch; char S[50],str[50]; printf("请输入该文法的句型:"); scanf("%s",str); getchar(); i=strlen(str); str[i]='#'; str[i+1]='\0'; S[0]='#'; S[1]=start; S[2]='\0'; j=0; ch=str[j]; while(1) { if(in(S[strlen(S)-1],termin)==1) { if(S[strlen(S)-1]!=ch) { printf("该符号串不是文法的句型!"); return; } else if(S[strlen(S)-1]=='#') { printf("该符号串是文法的句型."); return; } else { S[strlen(S)-1]='\0'; j++; ch=str[j]; } } else { for(i=0;;i++) if(non_ter[i]==S[strlen(S)-1]) break; for(k=0;;k++) { if(termin[k]==ch) break; if(k==strlen(termin)) { printf("词法错误!"); return; } } if(M[i][k]==-1) { printf("语法错误!"); return; } else { m=M[i][k]; if(right[m][0]=='@') S[strlen(S)-1]='\0'; else { p=strlen(S)-1; q=p; for(n=strlen(right[m])-1;n>=0;n--) S[p++]=right[m][n]; S[q+strlen(right[m])]='\0'; } } } printf("S:%s str:",S); for(p=j;p<=strlen(str)-1;p++) printf("%c",str[p]); printf(" \n"); } } /******************************************* 一个用户调用函数 ********************************************/ void menu() { syntax(); printf("\n是否继续?(y or n):"); scanf("%c",&choose); getchar(); while(choose=='y') { menu(); } } /******************************************* 主函数 ********************************************/ void main() { int i,j; start=grammer(termin,non_ter,left,right); /*读入一个文法*/ printf("count=%d",count); printf("\n开始符号为:%c",start); strcpy(v,non_ter); strcat(v,termin); printf("\n所有符号集为:%s",v); printf("\n非终结符集合:{%s",non_ter); printf("}"); printf("\n终结符集合:{%s",termin); printf("}"); printf("\n文法所有右边表达式依次是:"); for(i=0;i<=count-1;i++) printf("%s ",right[i]); printf("\n文法所有左边开始符依次是:"); for(i=0;i<=count-1;i++) printf("%c ",left[i]); if(validity==1) validity=judge(); //printf("\nvalidity=%d",validity); if(validity==1) { ll=ll1(); // printf("\nll=%d",ll); if(ll==0) printf("\n该文法不是一个LL1文法!"); else { printf("\n该文法是一个LL(1)文法!"); MM(); // printf("\n"); //for(i=0;i<=19;i++) // for(j=0;j<=19;j++) // if(M[i][j]>=0) //printf("M[%d][%d]=%d ",i,j,M[i][j]); menu(); } } } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 编译原理 C语言词法分析器 一、实验题目 编制并调试C词法分析程序。 a.txt源代码: ?main() { int sum=0 ,it=1;/* Variable declaration*/ if (sum==1) it++; else it=it+2; }? 设计其词法分析程序,能识别出所有的关键字、标识符、常数、运算符(包括复合运算符,如++)、界符;能过滤掉源程序中的注释、空格、制表符、换行符;并且能够对一些词法规则的错误进行必要的处理,如:标识符只能由字母、数字与下划线组成,且第一个字符必须为字母或下划线。实验要求:要给出所分析语言的词法说明,相应的状态转换图,单词的种别编码方案,词法分析程序的主要算法思想等。 二、实验目的 1、理解词法分析在编译程序中的作用; 2、掌握词法分析程序的实现方法与技术; 3、加深对有穷自动机模型的理解。 三、主要函数 四、设计 1、主函数void main ( ) 2 3 4、整数类型判断函数 char *key1[]={" ","(",")","[","]","{","}",",",";","'"}; /*分隔符表*/ char *key2[]={" ","+","-","*","/","%","<",">","==",">=","<=","!=","!","&&","||","<<",">>","~","|","^","&","=","?:","->","++","--","、","+=","-=","*=","/="}; /*运算符表*/ int xx0[35],xx1[10],xx2[31]; int temp_key3=0,temp_c40=0,temp_c41=0,temp_c42=0,temp_c43=0; /******* 初始化函数*******/ void load() { int mm; for (mm=0;mm<=34;mm++) { xx0[mm]=0; } for (mm=0;mm<=9;mm++) { xx1[mm]=0; } for (mm=0;mm<=30;mm++) { xx2[mm]=0; } FILE *floading; if ((floading=fopen("key0、txt","w"))==NULL) { printf("Error! Can't create file : key0、txt"); return; } fclose (floading); /*建立保留字表文件:key0、txt*/ if ((floading=fopen("key1、txt","w"))==NULL) { printf("Error! Can't create file : key1、txt"); return; } /*建立分隔符表文件:key1、txt*/ if ((floading=fopen("key2、txt","w"))==NULL) { printf("Error! Can't create file : key2、txt"); return; } fclose(floading); /*建立运算符表文件:key2、txt*/ if ((floading=fopen("key3、txt","w"))==NULL) { printf("Error! Can't create file : key3、txt"); #include C语言编译器的设计与实现 01计算机4班18号任春妍2号陈俊我们设计的编译程序涉及到编译五个阶段中的三个,即词法分析器、语法分析器和中间代码生成器。编译程序的输出结果包括词法分析后的二元式序列、变量名表、状态栈分析过程显示及四元式序列程序,整个编译程序分为三部分: (1) 词法分析部分 (2) 语法分析处理及四元式生成部分 (3) 输出显示部分 一.词法分析器设计 由于我们规定的程序语句中涉及单词较少,故在词法分析阶段忽略了单词输入错误的检查,而将编译程序的重点放在中间代码生成阶段。词法分析器的功能是输入源程序,输出单词符号。我们规定输出的单词符号格式为如下的二元式:(单词种别,单词自身的值) #define ACC -2 #define syl_if 0 #define syl_else 1 #define syl_while 2 #define syl_begin 3 #define syl_end 4 #define a 5 #define semicolon 6 #define e 7 #define jinghao 8 #define s 9 #define L 10 #define tempsy 11 #define EA 12 #define EO 13 #define plus 14 #define times 15 #define becomes 16 #define op_and 17 #define op_or 18 #define op_not 19 #define rop 20 #define lparent 21 #define rparent 22 #define ident 23 #define intconst 24 词法分析 三、词法分析程序的算法思想: 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 3.1 主程序示意图: 扫描子程序主要部分流程图 其他 词法分析程序的C语言程序源代码: // 词法分析函数: void scan() // 数据传递: 形参fp接收指向文本文件头的文件指针; // 全局变量buffer与line对应保存源文件字符及其行号,char_num保存字符总数。 void scan() { char ch; int flag,j=0,i=-1; while(!feof(fp1)) { ch=fgetc(fp1); flag=judge(ch); printf("%c",ch);//显示打开的文件 if(flag==1||flag==2||flag==3) {i++;buffer[i]=ch;line[i]=row;} else if(flag==4) {i++;buffer[i]='?';line[i]=row;} else if(flag==5) {i++;buffer[i]='~';row++;} else if(flag==7) continue; else cout<<"\n请注意,第"< 词法分析 #include ch=s[--p]; syn=10; for(n=0;n<6;n++) if(strcmp(token,r[n])==0) { syn=n+1; break; } } void digit(bool positive)//数字的判断{ len=sum=0; ch=s[p]; while(ch>='0' && ch<='9') { sum=sum*10+ch-'0'; ch=s[++p]; } if(ch=='.') { dsum=sum; ch=s[++p]; pos=0.1; while(ch>='0' && ch<='9') { dsum=dsum+(ch-'0')*pos; pos=pos*0.1; ch=s[++p]; } if(ch=='e') { index[len++]=ch; ch=s[++p]; if(ch=='-' || ch=='+') { index[len++]=ch; ch=s[++p]; } if(!(ch>='0' && ch<='9')) { syn=-1; } else 编译原理课程设计报告 题目: 学院: 教师: 姓名: 学号: 班级: 评分: 签字: 编译原理课程设计一:设计c语言的词法分析器 一、实验目的 了解高级语言单词的分类,了解状态图以及如何表示并识别单词规则,掌握状态图到识别程序的编程,加深对词法原理的理解。 二、实验要求 了解高级语言单词的分类,了解状态图以及如何表示并识别单词规则,掌握状态图到识别程序的编程。 三、实验设计 3.1.单词分类及表示 3.1.1 C语言的子集分类 (1)标识符:以字母开头的字母数字串 (2)整数或浮点型。 (3)保留字:for,while,do,else,if,static,int,sizeof,break,continue (4)运算符:+,-,*,/,%,>,<,=,!=,==,<=,>=,!,&,&&,||; (5)界符:"(",")",",",":",";","{","}" 3.1.2单词二元组(单词分类号、单词自身值) 3.2 词法分析器的设计 3.2.1算法设计 3.2.1.1概要设计 从文件中逐个读取字符,只要这五大类的状态序列则继续读取,否则回退字符,在对应类别进行查找,输出单元二次组至另一文件夹。 3.2.1.2状态图设计 3.2.2输入输出设计 输入:通过文件指针从文件中一个一个读取字符 输出:输出单词二元组至文件。格式为(种别码,值) 3.2.3主要函数 void Getchar(FILE *fp ) //读入一个字符 void GetBC(FILE *fp)//读入一个非空字符 void contacat()//连接字符 int letter()//判断是否为字母 int digit()//判断是否为字母 void retract(FILE *fp,char *c)//回退 int reserve (char **k)//处理保留字 int sysmbol(identifier *id)//处理标识符,查找符号表并存放位置若没有则添加int constant(constnumber *con)//存入常数表,并返回它在常数表中的位置 词法分析 一、实验目的 设计、编制并调试一个词法分析程序,加深对词法分析原理的理解。 二、实验要求 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和sum 3.2 扫描子程序的算法思想: 首先设置3个变量:①token用来存放构成单词符号的字符串;②sum用来整型单词;③syn用来存放单词符号的种别码。扫描子程序主要部分流程如图3-2所示。 编译原理课程设计报告 设计题目编译代码生成器设计 学生姓名 班级 学号 指导老师 成绩 一、课程设计的目的 编译原理课程兼有很强的理论性和实践性,是计算机专业的一门非常重要的专业基础课程,它在系统软件中占有十分重要的地位,是计算机专业学生的一门主修课。为了让学生能够更好地掌握编译原理的基本理论和编译程序构造的基本方法和技巧,融会贯通本课程所学专业理论知识,提高他们的软件设计能力,特设定该课程的课程设计,通过设计一个简单的PASCAL语言(EL语言)的编译程序,提高学生设计程序的能力,加深对编译理论知识的理解与应用。 二、课程设计的要求 1、明确课程设计任务,复习编译理论知识,查阅复印相关的编译资料。 2、按要求完成课程设计内容,课程设计报告要求文字和图表工整、思路清晰、算法正 确。 3、写出完整的算法框架。 4、编写完整的编译程序。 三、课程设计的内容 课程设计是一项综合性实践环节,是对平时实验的一个补充,课程设计内容包括课程的主要理论知识,但由于编译的知识量较复杂而且综合性较强,因而对一个完整的编译程序不适合平时实验。通过课程设计可以达到综合设计编译程序的目的。本课程的课程设计要求学生编写一个完整的编译程序,包括词法分析器、语法分析器以及实现对简单程序设计语言中的逻辑运算表达式、算术运算表达式、赋值语句、IF语句、While语句以及do…while语句进行编译,并生成中间代码和直接生汇编指令的代码生成器。 四、总体设计方案及详细设计 总体设计方案: 1.总体模块 主程序 词法分析程序语法分析 程序 中间代码 生成程序 2. 表2.1 各种单词符号对应的种别码 单词符号种别码单词符号种别码bgin 1 :17 If 2 := 18 Then 3 < 20 wile 4 <> 21 do 5 <= 22 end 6 > 23 lettet(letter|digit)* 10 >= 24 dight dight* 11 = 25 + 13 ;26 —14 ( 27 * 15 ) 28 / 16 # 0 详细设计: 4.1界面导入设计 (1)一共三个选项: ①choice 1--------cifafenxi ②choice 2--------yufafenxi ③choice 3--------zhongjiandaima (2)界面演示 图一 实验内容: 可选择LL1分析法、算符优先分析法、LR分析法之一,实现如下表达式文法的语法分析器: (1)E→E+T | E-T | T (2)T→T*F | T/F | F (3)F→P^F | P (4)P→(E) | i 实验环境: Windows XP 实验分析: (1)定义部分:定义常量、变量、数据结构。 (2)初始化:设立LL(1)分析表、初始化变量空间(包括堆栈、结构体、数组、临时变量等); (3)控制部分:从键盘输入一个表达式符号串; (4)利用LL(1)分析算法进行表达式处理:根据LL(1)分析表对表达式符号串进行堆栈(或其他)操作,输出分 实验程序: #include {'r','r','s','r','r','r'}, {'r','r','r','r','r','r'}, {'r','r','r','r','r','r'} }; char snum[12][6]={//数字表 {5,1,1,4,2,1}, {3,6,5,3,2,0}, {2,2,7,2,2,2}, {4,4,4,4,4,4}, {5,1,1,4,2,1}, {6,6,6,6,6,6}, {5,1,1,4,2,1}, {5,1,1,4,2,1}, {3,6,5,3,11,4}, {1,1,7,1,1,1}, {3,3,3,3,3,3}, {5,5,5,5,5,5} }; int go2[12][3]={//goto表 {1,2,3}, {0,0,0}, {0,0,0}, {0,0,0}, {8,2,3}, {0,0,0}, {0,9,3}, {0,0,10}, {0,0,0}, {0,0,0}, {0,0,0}, {0,0,0} }; void action(int i,char *&a,char &how,int &num,char &A,int &b)//action函数[i,a] { int j; switch(*a) { case 'i': j=0;break; case '+': j=1;break; case '*': j=2;break; case '(': 编译原理课程设计报告 课题名称:编译原理课程设计 C-语言词法与语法分析器的实现 C-词法与语法分析器的实现 1.课程设计目标 (1)题目实用性 C-语言拥有一个完整语言的基本属性,通过编写C-语言的词法分析和语法分析,对于理解编译原理的相关理论和知识有很大的作用。通过编写C-语言词法和语法分析程序,能够对编译原理的相关知识:正则表达式、有限自动机、语法分析等有一个比较清晰的了解和掌握。(2)C-语言的词法说明 ①语言的关键字: else if int return void while 所有的关键字都是保留字,并且必须是小写。 ②专用符号: + - * / < <= > >= == != = ; , ( ) [ ] { } /* */ ③其他标记是ID和NUM,通过下列正则表达式定义: ID = letter letter* NUM = digit digit* letter = a|..|z|A|..|Z digit = 0|..|9 注:ID表示标识符,NUM表示数字,letter表示一个字母,digit表示一个数字。 小写和大写字母是有区别的。 ④空格由空白、换行符和制表符组成。空格通常被忽略。 ⑤注释用通常的c语言符号/ * . . . * /围起来。注释可以放在任何空白出现的位置(即注释不能放在标记)上,且可以超过一行。注释不能嵌套。 (3)程序设计目标 能够对一个程序正确的进行词法及语法分析。 2.分析与设计 (1)设计思想 a.词法分析 词法分析的实现主要利用有穷自动机理论。有穷自动机可用作描述在输入串中识别模式的过程,因此也能用作构造扫描程序。通过有穷自动机理论能够容易的设计出词法分析器。b.语法分析 语法分析采用递归下降分析。递归下降法是语法分析中最易懂的一种方法。它的主要原理是,对每个非终结符按其产生式结构构造相应语法分析子程序,其中终结符产生匹配命令,而非终结符则产生过程调用命令。因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。其中子程序的结构与产生式结构几乎是一致的。 (2)程序流程图 程序主流程图: 词法分析: 语法分析: #include"status_stack.h" #include"symbol_instr_stack.h" #include"lr.h" //打印LR分析器的工作过程 void print(status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p) { int i; out_stack(status_p); for(i=0;i<20-status_p->top;i++) printf(" "); out_stack1(symbol_p); for(i=0;i<20;i++) printf(" "); out_stack2(instr_p); printf("\n"); } //状态转换函数 int goto_char(status *status_p,symbol_instr *instr_p) { char x; int y,z; x = get_top(instr_p); y = get_top(status_p); z = get_index_char(x); return table[y][z]; } //移进--规约函数 void action(status *status_p,symbol_instr *symbol_p,symbol_instr *instr_p) { int i,j,x; char a; i = goto_char(status_p,instr_p); //规约出错 if(i == -1) printf("\n===============规约出错!================\n"); //规约成功 if(i == 12) printf("\n===============规约成功!================\n"); //移进动作 if(i>=0 && i<=11) { push(status_p,i); a = pop(instr_p); push(symbol_p,a); 《编译原理课程设计》课程报告题目 C语言词法分析器和C-语言语法分析器 学生 学生学号 指导教师 提交报告时间 2019 年 6 月 8 日 C语言词法分析器 1 实验目的及意义 1.熟悉C语言词法 2.掌握构造DFA的过程 3.掌握利用DFA实现C语言的词法分析器 4.理解编译器词法分析的工作原理 2 词法特点及正则表达式 2.1词法特点 2.1.1 保留字 AUTO, BREAK , CASE , CHAR , CONST , CONTINUE , DEFAULT , DO , DOUBLE , ELSE, ENUM , EXTERN , FLOAT , FOR , GOTO, IF , INT , LONG , REGISTER , RETURN, SHORT , SIGNED , SIZEOF , STATIC , STRUCT , SWITCH , TYPEDEF , UNION , UNSIGNED , VOID, VOLATILE , WHILE, 2.1.2 符号 + - * / ++ -- += -= *= < <= > >= == != = ; , ( ) [ ] { } /* */ : 2.2 正则表达式 whitespace = (newline|blank|tab|comment)+ digit=0|..|9 nat=digit+ signedNat=(+|-)?nat NUM=signedNat(“.”nat)? letter = a|..|z|A|..|Z ID = letter(letter|digit|“_”)+ CHAR = 'other+' STRING = “other+” 实验三语法分析的C语言实现 一、实验目的 加深对语法分析器工作过程的理解;能够采用一种编程语言实现简单的语法分析程序;能够使用自己编写的分析程序对简单的程序段进行语法分析。 二、实验要求 1、在实验一(用C语言实现词法分析的程序)的基础上,实现编写语法分析程序,语法 分析程序的实现可以采用任何一种编程工具。 2、对语法规则有明确的定义; 3、编写的分析程序能够对实验一的结果进行正确的语法分析; 4、对于遇到的语法错误,能够做出简单的错误处理,给出简单的错误提示,保证顺利 完成语法分析过程; 三、实验指导1(实现算术表达式的运算) (一)准备 1.阅读课本有关章节,参考P63的表6.3优先关系表。 2.初步编制程序。 3.准备一组测试数据。 (二)程序要求 1.程序输入/输出示例: 输入如下一段C语言源程序: 3+2*(5.5-5) 输出:输出运算的结果4.0。 2. 建议:实验一的词法分析结果保存到文件input.c,实验二直接从input.c读取一个token,将用到的文法规则输出并保存到文件output.c。(注:NUM由词法分析器返回) 3.可选功能:可以根据自身的情况完善语法分析程序的错误处理功能,如对遇到的语法错误给出准确的位置和错误类型提示。 三、实验指导2(用递归下降分析器实现语法分析) (一)准备 1.阅读课本有关章节,特别是P49的代码,明确语言的语法。 2.初步编制程序。 3.准备一组测试数据。 (二)程序要求 1.程序输入/输出示例: 输入如下一段C语言源程序(实现赋值语句或者if语句或者while语句,或者都实现):main() { a = 10*(b+2); if (a>b) a=b else a=c; while (a!=0) a=3+21*a; } 实验报告 姓名:张静学号:13031121 【实验名称】一种绘图语言的词法分析器 【实验目的】采用c语言完成词法分析器,练习使用。 【实验内容】 一、问题描述 设计一种简单的函数绘图语言的词法分析器,该绘图语言可以提供一条循环绘图语句,图形变换语句,注释语句,他的词法分析器部分是读取源程序——字符序列,并根据构词规则将其转换为记号流。它可以完成三个任务:(1)滤掉源程序中的注释和无用的成分(如空格,TAB等);(2)输出记号,供语法分析器使用;(3)识别非法输入,并将非法输入作为出错记号提供给语法分析器,以便进行出错处理。 二、问题分析 词法分析器的构造步骤:正规式——NFA——DFA——最小DFA ——编写程序——测试。 1、记号的设计 记号一般有两部分组成:极好的类别,记号的属性。根据 函数绘图语言的特点,可以将记号设计为如下的数据结构: Struct Token { Token_Type type;----------类别 char* lexeme;--------------属性,原是输入的字符串double value;----------属性,若记号是常数则是常数的值 double (*FuncPtr)(double);--属性,若记号是函数则是函数指针 }; 函数绘图语言的记号类别划分如下: Enum Token_Type { ORGIN, SCALE, ROT, IS, ------------保留字 TO, STEP, DRAW, FOR, FROM,---------保留字 T,--------------------------------参数 SEMICO, L_BRACKET, R_BRACKET, COMMA--分隔符 PLUS, MINUS, MUL, DIV, POWER,------运算符 FUNC,--------------------------函数 CONST_ID,-------------------常数 NONTOKEN,-----------------空记号 ERRTOKEN-------------------出错记号 }; 2、模式的正规式表示 函数绘图语言的此法可用下是正规式集合表示,其中的letter 和digit是辅助定义 描述词法的正规式 实验五LL(1)文法识别程序设计 一、实验目的 通过LL(1)文法识别程序的设计理解自顶向下的语法分析思想。 二、实验重难点 FIRST集合、FOLLOW集合、SELECT集合元素的求解,预测分析表的构造。 三、实验内容与要求 实验内容: 1.阅读并理解实验案例中LL(1)文法判别的程序实现; 2.参考实验案例,完成简单的LL(1)文法判别程序设计。 四、实验学时 4课时 五、实验设备与环境 C语言编译环境 六、实验案例 1.实验要求 参考教材93页预测分析方法,94页图5.11 预测分析程序框图,编写表达式文法的识别程序。要求对输入的LL(1)文法字符串,程序能自动判断所给字符串是否为所给文法的句子,并能给出分析过程。 表达式文法为: E→E+T|T T→T*F|F F→i|(E) 2.参考代码 为了更好的理解代码,建议将图5.11做如下标注: /* 程序名称:LL(1)语法分析程序*/ /* E->E+T|T */ /* T->T*F|F */ /* F->(E)|i */ /*目的: 对输入LL(1)文法字符串,本程序能自动判断所给字符串是否为所给文法的句子,并能给出分析过程。 /********************************************/ /* 程序相关说明*/ /* A=E' B=T' */ /* 预测分析表中列号、行号*/ /* 0=E 1=E' 2=T 3=T' 4=F */ /* 0=i 1=+ 2=* 3=( 4=) 5=# */ /************************************/ #include"iostream" #include "stdio.h" #include "malloc.h" #include "conio.h" /*定义链表这种数据类型参见: https://www.360docs.net/doc/b718949808.html,/link?url=_owQzf8PRZOt9H-5oXIReh4X0ClHo6zXtRdWrdSO5YBLpKl NvkCk0qWqvFFxjgO0KzueVwEQcv9aZtVKEEH8XWSQCeVTjXvy9lxLQ_mZXeS###*/ struct Lchar{ char char_ch; struct Lchar *next; }Lchar,*p,*h,*temp,*top,*base; /*p指向终结符线性链表的头结点,h指向动态建成的终结符线性链表节点,top和base分 别指向非终结符堆栈的顶和底*/ 郑州轻工业学院 编译原理课程设计总结报告 设计题目:词法分析器(语法分析器) 学生姓名: 系别: 专业: 班级: 学号: 指导教师: 20013年6 月2日 目录 一、设计题目 (3) 二、运行环境(软、硬件环境) (3) 三、算法设计的思想 (3) 四、算法流程图 (5) 五、算法设计分析 (5) 六、源代码 (6) 七、运行结果 (11) 八、收获及体会 (12) (一)设计题目 词法分析器 (二)运行环境 Visual C++.6.0 (三)算法设计的思想 各种单词符号对应的种别码: 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 1.主程序示意图: 主程序示意图如下;其中初值包括如下两个方面: (1)关键字表的初值。 关键字作为特殊标示符处理,把它们预先安排到一张表格中 (称为关键字表),当扫描程序识别出标识符时,查关键字表。 如果能查到匹配的单词,则该单词为关键字,否则为一般的标 识符。关键字表为一个字符串数组,其描述如下: Char*rwtab[6]={“begin”,”if”,”then”,”while”,”do”,”end”}; (2)程序需要用到的主要变量为syn,token和sum。 2.扫描子程序的算法思想 首先设置3个变量:(1)token用来存放构成单词符号的字符串;(2)sum 用来存放整型单词(3)syn用来存放单词符号的种别码。 (五)算法设计分析 算法的基本任务是从字符串表示的源程序中识别出具有独立意义的单词符号,其基本思想是根据扫描到单词符号的第一个字符的种类,拼出相应的单词符号。 其中初值包括如下两个方面:(一)关键字表的初值。关键字作为特殊标示符处理,把它们预先安排到一张表格中(称为关键字表),当扫描程序识别出标识符时,查关键字表。如果能查到匹配的单词,则该单词为关键字,否则为一般的标识符。关键字表为一个字符串数组,其描述如下:Char*rwtab[6]={“begin”,”if”,”then”,”while”,”do”,”end”}; (2)程序需要用到的主要变量为syn,token和sum。 2.扫描子程序的算法思想 编译原理C语言词法分析器 一、实验题目 编制并调试C词法分析程序。 a.txt源代码: ?main() { int sum=0 ,it=1;/* Variable declaration*/ if (sum==1) it++; else it=it+2; }? 设计其词法分析程序,能识别出所有的关键字、标识符、常数、运算符(包括复合运算符,如++)、界符;能过滤掉源程序中的注释、空格、制表符、换行符;并且能够对一些词法规则的错误进行必要的处理,如:标识符只能由字母、数字和下划线组成,且第一个字符必须为字母或下划线。实验要求:要给出所分析语言的词法说明,相应的状态转换图,单词的种别编码方案,词法分析程序的主要算法思想等。 二、实验目的 1、理解词法分析在编译程序中的作用; 2、掌握词法分析程序的实现方法和技术; 3、加深对有穷自动机模型的理解。 三、主要函数 四、设计 1.主函数void main ( ) 2. 初始化函数void load ( ) 3. 保留字及标识符判断函数void char_search(char *word) 4. 整数类型判断函数void inta_search(char *word) 5. 浮点类型判断函数void intb_search(char *word) 6. 字符串常量判断函数void cc_search(char *word) 7. 字符常量判断函数void c_search(char *word) 同4、5函数图 8.主扫描函数void scan ( ) 五、关键代码 #include C 语言词法分析器构造实验报告 02计算机(2) 2002374203 冯绍欣 一、题目要求: 完成一个C 语言的词法分析器的构造。此词法分析器能识别附值语句、循环语句、条件语句、并能处理注释。 二、设计方案: 这个词法分析器分析的主要关键字有:main, int, float, char, if, else, for, while, do, switch, case, break; default 。选择要分析的c 文件,首先对其去掉注释和与空格处理,再根据字符的不同类型分析。 1、全局数据结构: 字符数组 set[ ]:存放从文件中读到的所有字符; str[ ]:存放经过注释处理和预空格处理的字符; strtoken[ ]:存放当前分析的字符; 结构体 KEYTABLE :存放关键字及其标号; 全局字符变量 ch :当前读入字符; 全局整型变量 sr, to :数组str, strtoken 的指针。 2、以层次图形式描述模块的组成及调用关系 3、主要函数的设计要求(功能、参数、返回值): openfile :打开文件; GetChar :将下一个输入字符读到ch 中,搜索指示器前移一字符位置; GetBC :检查ch 中的字符是否为空白。若是,则调用GetChar 直至ch 中进入一个非空白字符; Main ( ) Openfile ( ) Analysis ( ) Reflesh() Process() Set32() GetChar() GetBC() Concat() Reserve() IsLetter() IsDigit() Retract() GetChar() #include<> #include<> #include<> /*******************************************/ 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*/ } [编译原理C语言词法分析器
c语言语法分析器详解
C语言编译器的设计与实现.
编译原理词法分析和语法分析报告 代码(C语言版)
编译原理--词法分析,语法分析,语义分析(C语言)
编译原理设计c语言的词法分析器
编译原理词法分析和语法分析报告+代码(C语言版)
编译原理课程设计 C语言编译器的实现
语法分析C语言程序
编译原理课程设计报告C语言词法与语法分析器的实现
语法分析代码2(LR分析器 C语言实现)
C语言词法分析器和C语言语法分析器编译原理课程设计报告书
实验三 语法分析的C语言实现
c语言实现语法分析器
实验5 LL(1)语法分析程序的设计与实现(C语言)教学文稿
C语言语法分析器
编译原理C语言词法分析器
C语言词法分析器构造实验报告(1)1
c语言语法分析器