编译原理实验一

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

实验内容:
实现标准C语言词法分析器
实验目的:
1.掌握程序设计语言词法分析的设计方法;
2.掌握DFA的设计与使用方法;
3.掌握正规式到有限自动机的构造方法;
实验要求:
1.单词种别编码要求
基本字(关键字)、运算符、界符:一符一种;
标识符(变量名):统一为一种;
常量():按类型编码;
2.词法分析工作过程中建立符号表、常量表,并以文本文件形式输出;
3.词法分析的最后结果以文本文件形式输出;
4.完成对所设计词法分析器的功能测试,并给出测试数据和实验结果;
5.为增加程序可读性,请在程序中进行适当注释说明;
6.整理上机步骤,总结经验和体会;
7.认真完成并按时提交实验报告。

二、设计方案:
这个词法分析器分析的主要关键字有:main, int, float, char, if, else, for, while, do, switch, case, break; default……。

选择要分析的c文件,首先对其去掉注释和与空格处理,再根据字符的不同类型分析。

1、全局数据结构:
*key[ ]:关键字表
全局文件指针*fr,*fw, *temp1,*temp2用于文件的读写。

2、以层次图模块的组成及调用关系
3、主要函数的设计要求(功能、参数、返回值):
isKey:判断ch中的字符是否为关键字;
isLer 和isNum:布尔函数过程,分别判断ch中的字符是否为字母和数字;
isBoudany():布尔函数过程,分别判断ch组成的字符否为边界符号;
check:词法分析;
clock:时间函数,计算程序运行所需的时间
main:主函数。

4、状态转换图:
字符a包括:= , & , | , + , --
字符b包括:-- , < , > , | , *
字符c包括:, , : , ( , ) , { , } , [ , ] , ! ,# , % , ” , / , * , + , -- , > , <, .
# include<stdio.h>
# include <string.h>
# include <stdlib.h>
# include <time.h>
# include <ctype.h>
FILE *fr,*fw,*temp1,*temp2;
char *key0[]={"main","printf","scanf","else","if","auto","double", "int","struct","break","long","switch","case","enum","register","typedef", "char","extern","return","union","const","float","short","unsigned","continue","for", "signed","void","default","goto","sizeof","volatile","do","while","static"};
/*关键字表*/
char *key1[]={"\"","\\","(",")","[","]","{","}",",",";","'"};
/*边界符表*/
int isLet(char c)//判断是否是字母
{
if(c>='a'&& c<='z'||c>='A'&&c<='Z')
return 1;
else
return 0;
}
int isNum(char c)//判断是否是数字
{
if (c>='0'&&c<='9')
return 1;
else
return 0;
}
int isKey(char *word)
{
int m,i;
for(i=0;i<36;i++)
{
if((m=strcmp(word,key0[i]))==0)
{
if(i==0)
return 2;
else
return 1;
}
}
return 0;
}
int isBoudany(char c)
{
if(c=='\\')
return 2;
else
if(c=='('||c==')'||c=='{'||c=='}'||c=='['||c==']'||c==','||c==';'||c=='\''||c=='\"'||c=='\"') return 1;
else
return 0;
}
void check(FILE *fr)
{
char word[30];
while(!feof(fr))
{
memset(word,0,sizeof(word));
char ch,temp;
ch=fgetc(fr); //获取字符,指针fr并自动指向下一个字符
int i,c;
if(ch=='#')//预处理
{
//temp=fgetc(fr);
while(ch!='>')
ch=fgetc(fr);
ch=fgetc(fr);
fprintf(fw,"*****************************************跳过头文件和文件宏定义\n");
}
else
if (ch=='/')//跳过注释/**/类型
{
ch=fgetc(fr);
if (ch=='/')//跳过注释//类型
{
while(ch!='\n')
ch=fgetc(fr);
fprintf(fw,"*********************************************************跳过注释\n");
}
else
if (ch=='*')
{
ch=fgetc(fr);
temp=fgetc(fr);
do
{
ch=fgetc(fr);
temp=fgetc(fr);
}
while (ch!='*'||temp!='/');
fprintf(fw,"******************************************************跳过注释\n");
ch=fgetc(fr);
}
}
else
if(isLet(ch))
{
word[0]=ch;
ch=fgetc(fr);
i=1;
while(isNum(ch)||isLet(ch))//判断该字符是否是字母或数字
{
word[i]=ch;
i++;
ch=fgetc(fr);
}
word[i]='\0'; //'\0' 代表字符结束(空格)
fseek(fr,-1,1);
c=isKey(word); //判断是否是关键字
if(c==0) //不是关键字
{
fprintf(temp1,"%s ",word);
fprintf(fw,"字符%s是:标识符,种别编码为:%d\n",word,2);
}
else
{
if(ch!='"')//判断是否是定义的字符
{
if(c==2)
fprintf(fw,"字符%s是:
***************************************************主函数,种别编码
为:%d\n",word,0);//主函数
else
fprintf(fw,"字符%s是:关键字,种别编码
为:%d\n",word,1);//关键字
}
else
{
fprintf(fw,"字符%s是:定义的字符常量,种别编码为:%d\n\n",word,32);
}
}
}
else
//开始判断的字符不是字母
if(isNum(ch))
{ //判断是否是数字
word[0]=ch;
ch=fgetc(fr);
i=1;
while(isNum(ch))
{
word[i]=ch;
i++;
ch=fgetc(fr);
}
word[i]='\0';
fseek(fr,-1,1); //回退
fprintf(fw,"字符%s是:常量,种别编码为:%d\n",word,3);
}
else
{
c=isBoudany(ch);
//开始判
断的字符不是字母也不是数字
//边界符
if(c)
{
if(c==2)//判断是否是转义字符
{
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
word[2]='\0';
fprintf(fw,"字符%s是:转义字符,种别编码为:%d\n",word,4);
}
else
if(c==1)
{
fprintf(fw,"字符%c是:界符,种别编码为:%d\n",ch,5);
fprintf(temp2,"%c ",ch);
}
}
else
switch(ch)
{
case'+':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='='){
word[2]='\0';
fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,6);//运算符"+="
}
else
if(ch=='+')
{
word[2]='\0';
fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,7); //判断结果为"++"
}
else {
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,8); //判断结果为"+"
}
break;
case'-':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='='){
word[2]='\0';
fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,9); }
else
if(ch=='-'){
word[2]='\0';
fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,10); //判断结果为"--"
}
else {
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,11); //判断结果为"-"
}
break;
case'*':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch!='=')
{
if(isNum(ch))
{
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,12);//判断结果为"*"
}
else
{ //判断是否
是指针
i=2;
ch=fgetc(fr);
while(isLet(ch))
{
word[i]=ch;
ch=fgetc(fr);
i++;
}
fprintf(fw,"字符%s:是指针定义运算符,种别编码
为:%d\n",word,13);
}
}
else
{
word[2]='\0';
fprintf(fw,"字符%s:是运算符,种别编码为:%d\n",word,14);//判断结果为"*="
}
break;
case'/':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch!='=')
{
if(isNum(ch))
{
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,15);//判断结果为"/"
}
}
else {
word[2]='\0';
fprintf(fw,"字符%s:是运算符,,种别编码为:%d\n",word,16);//判断结果为"/="
}
break;
case'!':
case'?':
case':':
case'.':
case'=':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch!='='){
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c:是运算符,种别编码为:%d\n",ch,17);
}
else {word[2]='\0';
fprintf(fw,"字符%s:是运算符,种别编码为:%d\n",word,18);
break;
case'|':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='|'){
word[2]='\0';
fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,19); //判断结果为运算符"||"
}
else {
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,20); //判断结果为"|"
}
break;
case'%':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='=')
{
word[2]='\0';
fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,21);
}
else
if(isLet(ch))
{
word[2]='\0';
fprintf(fw,"字符%s是输出类型标识符,种别编码
为:%d\n",word,22);
}
else
{
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是取余运算符,种别编码为:%d\n",ch,23);
}
break;
case'&':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='&'){
word[2]='\0';
fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,24); //判断结果为运算符"&&"
}
else {
fseek(fr,-2,1);
ch=getc(fr);
fprintf(fw,"字符%c是:运算符,种别编码为:%d\n",ch,25); //判断结果为"&"
}
break;
case'<':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='='){
word[2]='\0';
fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,26); //判断结果为运算符"<="
}
else
if(ch=='<'){
word[2]='\0';
fprintf(fw,"字符%s是:运算符,种别编码为:%d\n",word,27); //判断结果为运算符"<<"
}
else
{
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是:运算符,种别编码为:%d\n",ch,28); //判断结果为"<"
}
break;
case'>':
word[0]=ch;
ch=fgetc(fr);
word[1]=ch;
if(ch=='=') {
word[2]='\0';
fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,29);
}
else
if(ch=='>'){
word[2]='\0';
fprintf(fw,"字符%s是运算符,种别编码为:%d\n",word,30);
}
else {
fseek(fr,-2,1);
ch=fgetc(fr);
fprintf(fw,"字符%c是运算符,种别编码为:%d\n",ch,31);
}
break;
default: break;
}
}
fprintf(fw,"\n");
}
}
int main()
{
clock_t start,end;
char cr;
char str_in[25],str_out[25],str_out1[25],str_out2[25];
double duration;
start=clock();
printf("请输入文件的读取路径(包含文件的后缀名):\n");
scanf("%s",str_in);
fr=fopen(str_in,"r");
while(fr==NULL)
{
printf("文件路径输入错误!请重新输入:\n");
scanf("%s",str_in);
fr=fopen(str_in,"r");
}
printf("文件读入成功!内容显示如下:\n");
printf("**************************************************\n");
cr=fgetc(fr);
while (cr!=EOF) {
putchar(cr);
cr=fgetc(fr);
}
printf("\n");
printf("**************************************************\n");
printf("请输入文件的最终结果的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out);
printf("请输入文件的常量表的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out1);
printf("请输入文件的符号表的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out2);
while(str_in==str_out||str_in==str_out1||str_in==str_out2)
{
if(str_out==str_in){printf("请输入文件的最终结果的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out);
}else
if(str_in==str_out1){
printf("请输入文件的常量表的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out1);
}else
if(str_in==str_out2){
printf("请输入文件的符号表的写入路径(包含文件的后缀名):\n");
scanf("%s",str_out2);
}
}
fw=fopen(str_out,"w");
temp1=fopen(str_out1,"w");
temp2=fopen(str_out2,"w");
while(fw==NULL||temp1==NULL||temp2==NULL)
{
printf("文件写入路径错误,请重新输入:\n");
if(fw==NULL)
{
scanf("%s",str_out);
fw=fopen(str_out,"w");
}
else
if(temp1=NULL)
{
scanf("%s",str_out1);
temp1=fopen(str_out1,"w");
}
else
if (temp2=NULL) {
scanf("%s",str_out2);
temp2=fopen(str_out2,"w");
}
}
fprintf(temp1,"文件中依次出现的标识符\n");
fprintf(temp2,"文件中依次出现的符号\n");
fr=fopen(str_in,"r");
check(fr);
printf("文件写入成功!编译结果已写入指定文件区域!请注意查看...........\n\n");
fclose(fw);
fclose(temp1);
fclose(temp2);
fclose(fr);
printf("\n");
end=clock();
duration=(double)(end-start)/CLOCKS_PER_SEC * 1000;
printf("该词法分析程序共运行约%lf ms\n", duration);
return 0;
}
测试结果:
这个程序主要参考书上关于词法分析器的假设,完成了关于c语言词法分析的所有的功能。

在设计过程中仍有遇到很多困难,。

尽管如此,分析考虑还不全面,如符号不匹配问题,这些情况将在在语法和语义分析时进行完善。

相关文档
最新文档