詞法分析實驗
一、實驗目的
編制一個詞法分析程序
二、實驗內容和要求
1.輸入:源程序字符串
2.輸出:二元組(種別,單詞本身)
單詞與種別碼
三、實驗方法、步驟及結果測試
(一).原理分析及流程圖
1.原理分析
存儲結構:此詞法分析程序,我采用的主要存儲結構有鏈隊列和指針數組。鏈隊列用於存 儲輸入的原程序,之所以考慮用鏈隊列,是因為鏈隊列是需要時才申請空間的,更重要的原因 是鏈隊列是先進先出的,這符合我要編寫的詞法分析程序,而數組是在定義時就要設置好它的 容量,系統會為其分配一個固定容量的存儲空間,數組一旦創建后,它的容量就不能更改,所 以它很容易造成數組越界而導致程序終止,數組容量過大就會浪費存儲空間,會影響程序的運 行速度。此程序指針數組是用於存儲關鍵字、符、算符、界符等已知其需要多大存儲空間的字 符,而且程序上涉及的種別碼可以通過獲取數組下標得到。
主要算法:先將源程序用鏈隊列存儲起來,然后逐一從鏈隊列中取出單個字符分析,具體 實 現,看下面的流程圖
關鍵函數的實現:
void InitQueue() //初始化一個帶節點的空隊列
void Printf() //輸出原程序
int search(char searchstr[],int wordtype)//符號匹配 返回種別碼
void Analyze() //詞法程序分析
2.流程圖
2.主要程序段及其解釋:
1 void Analyze() 2 { 3 char str; 4 char letter[20]; //存放字母的數組 5 char num[20]; //存放數字的字符數組 6 char other[20]; //存放其他字符的數組 7 int i; 8 do //循環獲取字符分析 9 { 10 Q.front=Q.front->next; //獲取單個字符 11 str=Q.front->ch; //出隊列 12 if (isalpha(str)!=0) //如果是字符 13 { 14 i=-1; 15 while (isalnum(str)!=0) //判斷下一個字符是否是字母 16 { 17 letter[++i]=str; //將字母存放到字符數組 18 Q.front=Q.front->next; //出隊列 19 str=Q.front->ch; //獲取下一個字符 20 } 21 letter[i+1]='\0'; //字符串的結束 22 if (search(letter,1)!=-1) // 調用int search(char searchstr[],int wordtype)函數,判斷該字符串是否能和指針數組中的字符串匹配 23 { 24 printf("( %d,%s )\n",search(letter,1),letter);//輸出種別碼和單詞本身 25 26 } 27 else 28 { 29 printf("( %d,%s )\n",71,letter); //輸出種別碼和單詞本身 30 } 31 } 32 else 33 { 34 if (isdigit(str)!=0) //判斷是否為數字 35 { 36 i=-1; 37 while (isdigit(str)!=0) //判斷下一個字符是否為數字 38 { 39 num[++i]=str; //將數字存放到數字字符數組里去 40 Q.front=Q.front->next; //出隊列 41 str=Q.front->ch; //獲取下一個字符 42 } 43 if(isalpha(str)!=0) //數字后面是字符 44 { 45 while(isspace(str)==0) 46 { 47 num[++i]=str; 48 Q.front=Q.front->next; //出隊列 49 str=Q.front->ch; //獲取下一個字符 50 51 } 52 num[i+1]='\0'; //字符串的結束 53 printf("錯誤!非法標識符:%s\n",num); 54 55 } 56 num[i+1]='\0'; 57 printf("( %d,%s )\n",72,num); 58 } 59 else 60 { 61 i=-1; 62 if (isspace(str)!=0) //判斷是否為空格 63 { 64 Q.front=Q.front->next; //出隊列,即跳過空格 65 str=Q.front->ch; //獲取下一個字符 66 67 } 68 while ((isspace(str)==0)&&(isalnum(str)==0)) 69 { 70 other[++i]=str; 71 Q.front=Q.front->next; 72 str=Q.front->ch; 73 74 75 } 76 other[i+1]='\0'; 77 if (search(other,2)!=-1) 78 printf("( %d,%s )\n",search(other,2),other); //輸出種別碼和單詞本身 79 else if (search(other,3)!=-1) 80 printf("( %d,%s )\n",search(other,3),other); //輸出種別碼和單詞本身 81 else if (search(other,4)!=-1) 82 printf("( %d,%s )\n",search(other,4),other); //輸出種別碼和單詞本身 83 else if (search(other,5)!=-1) 84 printf("( %d,%s )\n",search(other,5),other); //輸出種別碼和單詞本身 85 else if (search(other,6)!=-1) 86 printf("( %s,注釋符號 )\n",other); //輸出種別碼和單詞本身 87 else if (search(other,7)!=-1) 88 printf("( %d,%s )\n",search(other,7),other); //輸出種別碼和單詞本身 89 else 90 printf("錯誤!非法字符:%s\n",other); 91 } 92 } 93 }while(Q.front!=Q.rear); 94 printf("詞法分析結束,謝謝使用!\n"); 95 }
3. 運行結果及分析
四、 實驗總結
難點一:. 想將字符串存進數組中去,覺得這樣獲取種別碼比較簡單,但是用沒有加指針的數組會報錯
解決方法:用一個指針數組存儲就可以解決這一問題。
難點二:如果將所有的字符和數字都存儲在同一指針數組,那樣指針數組看起來太長,且分析時也比較浪費時間,每次都要從頭開始匹配
解決方法:按類型將字符串和字符分別放在不同的指針數組中,獲取種別碼時要加上前一個數組的長度。
難點三:.輸入原程序后,對原程序的分析時,要判斷各種字符和數字,判斷條件太多,代碼長且難看懂,很容易把自己繞暈。
解決方法:調用#include<ctype.h>庫函數里的字符類型判斷的函數,這樣可以使代碼簡潔易懂。