一、 實驗目的
編制一個讀單詞過程,從輸入的源程序中,識別出各個具有獨立意義的單詞,即基本保留字、標識符、常數、運算符、分隔符五大類。並依次輸出各個單詞的內部編碼及單詞符號自身值。
二、 實驗題目
如源程序為C語言。輸入如下一段:
main()
{
int a=-5,b=4,j;
if(a>=b)
j=a-b;
else j=b-a;
}
要求輸出如下:
(”main”,1,1)
(”(”,5)
(”)”,5)
(”{”,5)
(”int”,1,2)
(”a”,2)
(”=”,4)
(”-5”,3)
(”,”,5)
(”b”,2)
(”=”,4)
(”4”,3)
(”,”,5)
(”j”,2)
(”;”,5)
(”if”,1)
(”(”,5)
(”a”,2)
(”>=”,4)
(”b”,2)
(”)”,5)
(”j”,2)
(”=”,4)
(”a”,2)
(”-”,4)
(”b”,2)
(”;”,5)
(”else”,1)
(”j”,2)
(”=”,4)
(”b”,2)
(”-”,4)
(”a”,2)
(”;”,5)
(”}”,5)
三、 實驗理論依據
(一)識別各種單詞符號
1、 程序語言的單詞符號一般分為五種:
(1) 關鍵字(保留字/ 基本字)if 、while 、begin…
(2) 標識符:常量名、變量名…
(3) 常數:34 、56.78 、true 、‘a’ 、…
(4) 運算符:+ 、- 、* 、/ 、〈 、and 、or 、….
(5) 界限符:, ; ( ) { } /*…
2、 識別單詞:掌握單詞的構成規則很重要
(1) 標識符的識別:字母| 下划線+( 字母/ 數字/ 下划線)
(2) 關鍵字的識別:與標識符相同,最后查表
(3) 常數的識別
(4) 界符和算符的識別
3、 大多數程序設計語言的單詞符號都可以用轉換圖來識別,如圖1-1
圖1-1
4、 詞法分析器輸出的單詞符號常常表示為二元式:(單詞種別,單詞符號的屬性值)
(1) 單詞種別通常用整數編碼,如1 代表關鍵字,2 代表標識符等
(2) 關鍵字可視其全體為一種,也可以一字一種。采用一字一種得分法實際處理起來較為方便。
(3) 標識符一般統歸為一種
(4) 常數按類型(整、實、布爾等)分種
(5) 運算符可采用一符一種的方法。
(6) 界符一般一符一種的分法。
(二)超前搜索方法
1、 詞法分析時,常常會用到超前搜索方法。
如當前待分析字符串為“a>+” ,當前字符為“>” ,此時,分析器倒底是將其分析為大於關系運算符還是大於等於關系運算符呢?
顯然,只有知道下一個字符是什么才能下結論。於是分析器讀入下一個字符’+’ ,這時可知應將’>’ 解釋為大於運算符。但此時,超前讀了一個字符’+’ ,所以要回退一個字符,詞法分析器才能正常運行。又比如:‘+’ 分析為正號還是加法符號
(三)預處理
預處理工作包括對空白符、跳格符、回車符和換行符等編輯性字符的處理,及刪除注解等。由一個預處理子程序來完成。
參考代碼:
#include <stdio.h> #include <ctype.h> #include <malloc.h> #include <stdlib.h> #include <string.h> #define NULL 0 FILE *fp; char cbuffer; char *key[24]= {"main","int","if","else","for","while","do","return","break","continue","auto","double","struct", "long","switch","case","register","typedef","char","extern","union","const","short","null" };///t增加了關鍵字 int atype,id=4; int search(char searchchar[ ],int wordtype) /*判斷單詞是保留字還是標識符*/ { int i=0; int p; switch (wordtype) { case 1: for (i=0; i<=21; i++) { if (strcmp(key[i],searchchar)==0) { p=i+1; /*是保留字則p為非0且不重復的整數*/ break; } else p=0; /*不是保留字則用於返回的p=0*/ } return(p); } } char alphaprocess(char buffer) { int atype; /*保留字數組中的位置*/ int i=-1; char alphatp[20]; while ((isalpha(buffer))||(isdigit(buffer))||buffer=='_') { alphatp[++i]=buffer; buffer=fgetc(fp); } /*讀一個完整的單詞放入alphatp數組中*/ alphatp[i+1]='\0'; atype=search(alphatp,1);/*對此單詞調用search函數判斷類型*/ if(atype!=0) { printf("(%s, 1,%d)\n",alphatp,atype-1); id=1; } else { printf("(%s ,2)\n",alphatp); id=2; } return(buffer); } char digitprocess(char buffer) { int i=-1; char digittp[20]; while (isdigit(buffer)||((buffer=='.')&&i!=-1)) { digittp[++i]=buffer; buffer=fgetc(fp); } digittp[i+1]='\0'; printf("(%s ,3)\n",digittp); id=3; return(buffer); } char otherprocess(char buffer) { char ch[20]; ch[0]=buffer; ch[1]='\0'; if(ch[0]==','||ch[0]==';'||ch[0]=='{'||ch[0]=='}'||ch[0]=='('||ch[0]==')') { printf("(%s ,5)\n",ch); buffer=fgetc(fp); id=4; return(buffer); } if(ch[0]=='*'||ch[0]=='/') { buffer=fgetc(fp); ch[1]=buffer; if(ch[1]=='=') { ch[2]='\0'; printf("(%s ,4)\n",ch); buffer=fgetc(fp); id=4; return(buffer); } else { ch[1]='\0'; printf("(%s ,4)\n",ch); /// t*= /=也被判斷 } id=4; return(buffer); } if(ch[0]=='='||ch[0]=='!'||ch[0]=='<'||ch[0]=='>') { buffer=fgetc(fp); if(buffer=='=') { ch[1]=buffer; ch[2]='\0'; printf("(%s ,4)\n",ch); } else if(buffer =='>' || buffer =='<') { ch[1]=buffer; ch[2]='\0'; printf("(%s ,4)\n",ch); ///t >> <<判斷 } else { printf("(%s ,4)\n",ch); id=4; return(buffer); } buffer=fgetc(fp); id=4; return(buffer); } if(ch[0]=='+'||ch[0]=='-') { if(id==4) /*在當前符號以前是運算符,則此時為正負號*/ { buffer=fgetc(fp); ch[1]=buffer; ch[2]='\0'; printf("(%s ,3)\n",ch); id=3; buffer=fgetc(fp); return(buffer); } else if(ch[1] =='=')///*增加判斷 t+= -=*/ { ch[2]='\0'; printf("(%s ,4)\n",ch); } else if(ch[1] =='+' ||ch[1] =='-') { ch[2]='\0'; printf("(%s ,4)\n",ch);///*增加判斷 t++ --*/ } else { ch[1]='\0';///此時為加減運算符 printf("(%s ,4)\n",ch); id=4; return(buffer); } id=4; buffer=fgetc(fp); return(buffer); } } int main() { if ((fp=fopen("input.txt","r"))==NULL) /*只讀方式打開一個文件*/ printf("error"); else { cbuffer = fgetc(fp); /*fgetc( )函數:從磁盤文件讀取一個字符*/ while (cbuffer!=EOF) { if(cbuffer==' ' ||cbuffer=='\n') /*掠過空格和回車符*/ cbuffer=fgetc(fp); if(isalpha(cbuffer)) {cbuffer=alphaprocess(cbuffer);} else if (isdigit(cbuffer)) cbuffer=digitprocess(cbuffer); else {cbuffer=otherprocess(cbuffer);} } getchar(); } }