编译原理实验-词法分析器 - 打怪升级ing

时间:2024-01-24 22:13:18

编译原理实验-词法分析器

一、 实验目的

设计、编制、调试一个词法分析程序,对单词进行识别和编码,加深对词法分析原理的理解。

二、实验内容

1.选定语言,编辑任意的源程序保存在文件中;

2.对文件中的代码预处理,删除制表符、回车符、换行符、注释、多余的空格并将预处理后的代码保存在文件中;

3.扫描处理后的源程序,分离各个单词符号,显示分离的单词类型。

三、实验思路

       对于实验内容1,选择编写c语言的源程序存放在code.txt中,设计一个c语言的词法分析器,主要包含三部分,一部分是预处理函数,第二部分是扫描判断单词类型的函数,第三部分是主函数,调用其它函数;

       对于实验内容2,主要实现在预处理函数processor()中,使用文档操作函数打开源程序文件(code.txt),去除两种类型(“//”,“/*…*/”)的注释、多余的空格合并为一个、换行符、回车符等,然后将处理后的保存在另一个新的文件(afterdel.txt)中,最后关闭文档。

       对于实验内容3,打开处理后的文件,然后调用扫描函数,从文件里读取一个单词调用判断单词类型的函数与之前建立的符号表进行对比判断,最后格式化输出。

四、编码设计

代码参考了两篇博主的,做了部分改动,添加了预处理函数等

  1 #include<iostream>
  2 #include<fstream>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<string>
  6 #include<cstdlib>
  7  
  8 using namespace std;
  9  
 10 int aa;// fseek的时候用来接着的
 11 string  word="";
 12 string  reserved_word[20];//保留
 13 char buffer;//每次读进来的一个字符
 14 int num=0;//每个单词中当前字符的位置
 15 int line=1; //行数
 16 int row=1; //列数,就是每行的第几个
 17 bool flag; //文件是否结束了
 18 int flag2;//单词的类型
 19  
 20 
 21 //预处理函数
 22 int processor(){//预处理函数
 23 FILE *p;
 24  int  falg = 0,len,i=0,j=0;
 25  char str[1000],str1[1000],c;
 26  if((p=fopen("code.txt","rt"))==NULL){
 27   printf("无法打开要编译的源程序");
 28   return  0;
 29  }
 30  else{
 31   //fgets(str,1000,p);
 32   while((c=getc(p))!=EOF){
 33    str[i++] = c; 
 34   }
 35   fclose(p);
 36   str[i] = \'\0\';
 37   for(i=0;i<strlen(str);i++){
 38    if(str[i]==\'/\'&&str[i+1]==\'/\'){
 39     while(str[i++]!=\'\n\'){}
 40    }//单行注释
 41    else if(str[i]==\'/\'&&str[i+1]==\'*\'){
 42     while(!(str[i]==\'*\'&&str[i+1]==\'/\')){i++;}
 43     i+=2;
 44    }//多行注释
 45    else if(str[i]==\' \'&&str[i+1]==\' \'){
 46     while(str[i]==\' \'){i++;}
 47     i--;
 48     if(str1[j-1]!=\' \')
 49        str1[j++]=\' \';
 50    }//多个空格,去除空格
 51    else if(str[i]==\'\n\') {
 52     if(str1[j-1]!=\' \')
 53        str1[j++]=\' \';
 54    }//换行处理,
 55    else if(str[i]==9){
 56     while(str[i]==9){
 57      i++;
 58     }
 59     if(str1[j-1]!=\' \')
 60      str1[j++]=\' \';
 61     i--;
 62    }//tab键处理
 63    else str1[j++] = str[i];//其他字符处理
 64   }
 65   str1[j] = \'\0\';
 66   if((p = fopen("afterdel.txt","w"))==NULL){
 67    printf("can not find it!");
 68    return 0;
 69   }
 70   else{
 71    if(fputs(str1,p)!=0){
 72     printf("预处理失败!");
 73    }
 74    else printf("预处理成功!");
 75   }
 76   fclose(p);
 77  }
 78  return 0;
 79  }
 80 
 81  //设置保留字
 82 void set_reserve()
 83 {
 84     reserved_word[1]="return";
 85     reserved_word[2]="def";
 86     reserved_word[3]="if";
 87     reserved_word[4]="else";
 88     reserved_word[5]="while";
 89     reserved_word[6]="return";
 90     reserved_word[7]="char";
 91     reserved_word[8]="for";
 92     reserved_word[9]="and";
 93     reserved_word[10]="or";
 94     reserved_word[11]="int";
 95     reserved_word[12]="bool";
 96 }
 97  
 98 //看这个字是不是字母
 99 bool judge_word(char x)
100 {
101     if(x>=\'a\' && x<=\'z\' || x>=\'A\' && x<=\'Z\' ){
102         return true;
103     }
104     else return false;
105 }
106  
107 //看这个字是不是数字
108 bool judge_number(char x)
109 {
110     if(x>=\'0\' && x<=\'9\'){
111         return true;
112     }
113     else return false;
114 }
115  
116 //看这个字符是不是界符
117 bool judge_jiefu(char x)
118 {
119     if(x==\'(\'||x==\')\'||x==\',\'||x==\';\'||x==\'{\'||x==\'}\'){
120         return true;
121     }
122     else return false;
123 }
124  
125  
126 //加减乘
127 bool judge_yunsuanfu1(char x)
128 {
129     if(x==\'+\'||x==\'-\'||x==\'*\')
130     {
131         return true;
132     }
133     else return false;
134 }
135  
136 //等于 赋值,大于小于 大于等于,小于等于,大于小于
137 bool judge_yunsuannfu2(char x)
138 {
139     if(x==\'=\'|| x==\'>\'||x==\'<\'||x==\'&\'||x==\'||\'){
140         return true;
141     }
142     else return false;
143 }
144  
145  
146 //这个最大的函数的总体作用是从文件里读一个单词
147 int scan(FILE *fp)
148 {
149     buffer=fgetc(fp);//读取一个字符
150     if(feof(fp)){//检测结束符
151         flag=0;return 0;
152     }
153     else if(buffer==\' \')
154     {
155         row++;
156         return 0;
157     }
158     else if(buffer==\'\n\')
159     {
160         row=1;
161         return 0;
162     }
163     //如果是字母开头或\'_\' 看关键字还是普通单词
164     else if(judge_word(buffer) || buffer==\'_\')
165     {
166         word+=buffer;
167         row++;
168         while((buffer=fgetc(fp)) && (judge_word(buffer) || judge_number(buffer) || buffer==\'_\'))
169         {
170             word+=buffer;
171             row++;
172         }
173         if(feof(fp)){
174                 flag=0;
175                 return 1;
176         }
177         for(int i=1;i<=12;i++){
178             if(word==reserved_word[i]){
179                 aa=fseek(fp,-1,SEEK_CUR);//如果执行成功,stream将指向以fromwhere为基准,偏移offset(指针偏移量)个字节的位置,函数返回0。
180                 return 3;
181             }
182         }
183         aa=fseek(fp,-1,SEEK_CUR);
184         return 1;
185     }
186  
187     //开始是加减乘 一定是类型4
188     else if(judge_yunsuanfu1(buffer))
189     {
190         word+=buffer;
191         row++;
192         return 4;
193     }
194  
195     //开始是数字就一定是数字
196     else if(judge_number(buffer))
197     {
198         word+=buffer;
199         row++;
200         while((buffer=fgetc(fp)) && judge_number(buffer))
201         {
202             word+=buffer;
203             row++;
204         }
205         if(feof(fp)){
206             flag=0;
207             return 2;
208         }
209         aa=fseek(fp,-1,SEEK_CUR);
210         return 2;
211     }
212  
213     //检验界符
214     else if(judge_jiefu(buffer))
215     {
216         word+=buffer;
217         row++;
218         return 6;
219     }
220  
221     //检验 <=、  >=、  <>、  == =、 <、>
222     else if(judge_yunsuannfu2(buffer))
223     {
224         row++;
225         word+=buffer;
226         if(buffer==\'<\')   //为了检验题目中的<> <=
227         {
228             buffer=fgetc(fp);
229             if(buffer==\'>\' || buffer==\'=\')
230             {
231                 word+=buffer;
232                 row++;
233                 return 5;
234             }
235         }
236         //检验  >= ==
237         else{
238             buffer=fgetc(fp);
239             if(buffer==\'=\')
240             {
241                 word+=buffer;
242                 row++;
243                 return 5;
244             }
245         }
246         if(feof(fp)){
247                 flag=0;
248         }
249         aa=fseek(fp,-1,SEEK_CUR);
250         return 4;
251     }
252  
253     //首字符是/ 有可能是除号 也有可能是注释
254     else if(buffer==\'/\')
255     {
256         row++;
257         word+=buffer;
258         buffer=fgetc(fp);
259         aa=fseek(fp,-1,SEEK_CUR);
260             return 4;
261     }
262  
263     else {
264         word+=buffer;
265         row++;
266         return -1;
267     }
268 }
269  
270 int main()
271 {
272     set_reserve();//设置保留字
273     processor();
274     cout<<"open "<<"afterdel.txt"<<endl;
275     flag=1;
276     FILE *fp;
277     if(!(fp=fopen("afterdel.txt","r")))
278     {
279         cout<<"not found the file or other error "<<endl;
280         flag=0;
281     }
282  
283     while(flag==1)
284     {
285         //flag2 返回的类型
286         flag2=scan(fp);//反复调用函数提取单词
287  
288         if(flag2==1)
289         {
290             cout<<"type:1 identifier      "<<word<<endl;
291             if(word.length()>20)
292             cout<<"ERROR Identifier length cannot exceed 20 characters"<<endl;
293             word.erase(word.begin(),word.end());
294         }
295         else if(flag2==3)
296         {
297             cout<<"type:3 reserved word   "<<word<<endl;
298             word.erase(word.begin(),word.end());
299         }
300         else if(flag2==4)
301         {
302             cout<<"type:4 unary_operator  "<<word<<endl;
303             word.erase(word.begin(),word.end());
304         }
305         else if(flag2==2)
306         {
307             cout<<"type:2 positive number "<<word<<endl;
308             //if(word[0]==\'0\')
309             //cout<<"ERROR: The first digit cannot be 0!"<<endl;
310             word.erase(word.begin(),word.end());
311         }
312         else if(flag2==6)
313         {
314             cout<<"type:6 Separator       "<<word<<endl;
315             word.erase(word.begin(),word.end());
316         }
317         else if(flag2==5)
318         {
319             cout<<"type:5 double_operator "<<word<<endl;
320             word.erase(word.begin(),word.end());
321         }
322         //非法字符
323         else if(flag2==-1)
324         {
325            cout<<"Illegal character      "<<word<<endl;
326            word.erase(word.begin(),word.end());
327         }
328     }
329  
330         int a=fclose(fp);
331         cout<<"press e to close"<<endl;
332         char end;
333         while(cin>>end && end!=\'e\'){
334             cout<<"只有e可以关闭"<<endl;
335         }
336     return 0;
337 }

 

 

 

 

五、实验结果

1.下面是编写的一段源程序,命名为code.txt

 

 

 

 

 

 

 

 

 

 

2.经过程序执行后,在项目目录下生成了一个新的名为afterdel.txt文件

 

3.afterdel.txt文件内容如下,经过预处理后去除了多于内容

 

4.下面是程序词法分析后得到的结果

 

 

 

 

 

 

六、实验总结

       该词法分析器功能基本具备,能够实现预定要求,本次实验让我了解如何设计编制并调试词法分析程序,加深了我对词法分析器原理的理解。词法分析是编译的第一阶段。词法分析器的主要任务是读入源程序的输入字符,将它们组成词素,生成并输出一个词法单元序列,这个词法单元序列被输出到语法分析器进行语法分析。另外,由于词法分析器在编译器中负责读取源程序,因此除了识别词素之外,它还会完成一些其他任务,比如过滤掉源程序中的注释和空白,将编译器生成的错误消息与源程序的位置关联起来等。