編譯原理實驗-詞法分析器

1、 實驗目的

設計、編制、調試一個詞法分析程序,對單詞進行識別和編碼,加深對詞法分析原理的理解。ios

2、實驗內容

1.選定語言,編輯任意的源程序保存在文件中;git

2.對文件中的代碼預處理,刪除製表符、回車符、換行符、註釋、多餘的空格並將預處理後的代碼保存在文件中;ide

3.掃描處理後的源程序,分離各個單詞符號,顯示分離的單詞類型。函數

3、實驗思路

       對於實驗內容1,選擇編寫c語言的源程序存放在code.txt中,設計一個c語言的詞法分析器,主要包含三部分,一部分是預處理函數,第二部分是掃描判斷單詞類型的函數,第三部分是主函數,調用其它函數;編碼

       對於實驗內容2,主要實如今預處理函數processor()中,使用文檔操做函數打開源程序文件(code.txt),去除兩種類型(「//」,「/*…*/」)的註釋、多餘的空格合併爲一個、換行符、回車符等,而後將處理後的保存在另外一個新的文件(afterdel.txt)中,最後關閉文檔。spa

       對於實驗內容3,打開處理後的文件,而後調用掃描函數,從文件裏讀取一個單詞調用判斷單詞類型的函數與以前創建的符號表進行對比判斷,最後格式化輸出。設計

4、編碼設計

代碼參考了兩篇博主的,作了部分改動,添加了預處理函數等指針

  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 }

 

 

 

 

5、實驗結果

1.下面是編寫的一段源程序,命名爲code.txt調試

 

 

 

 

 

 

 

 

 

 

2.通過程序執行後,在項目目錄下生成了一個新的名爲afterdel.txt文件code

 

3.afterdel.txt文件內容以下,通過預處理後去除了多於內容

 

4.下面是程序詞法分析後獲得的結果

 

 

 

 

 

 

6、實驗總結

       該詞法分析器功能基本具有,可以實現預約要求,本次實驗讓我瞭解如何設計編制並調試詞法分析程序,加深了我對詞法分析器原理的理解。詞法分析是編譯的第一階段。詞法分析器的主要任務是讀入源程序的輸入字符,將它們組成詞素,生成並輸出一個詞法單元序列,這個詞法單元序列被輸出到語法分析器進行語法分析。另外,因爲詞法分析器在編譯器中負責讀取源程序,所以除了識別詞素以外,它還會完成一些其餘任務,好比過濾掉源程序中的註釋和空白,將編譯器生成的錯誤消息與源程序的位置關聯起來等。

相關文章
相關標籤/搜索