編譯原理:詞法分析程序的設計與實現
- 2019 年 10 月 11 日
- 筆記
詞法分析程序(Lexical Analyzer)要求:
- 從左至右掃描構成源程序的字符流
- 識別出有詞法意義的單詞(Lexemes)
- 返回單詞記錄(單詞類別,單詞本身)
- 濾掉空格
- 跳過注釋
- 發現詞法錯誤
程序結構:
輸入:字符流(什麼輸入方式,什麼數據結構保存)
處理:
- 遍歷(什麼遍歷方式)
- 詞法規則
輸出:單詞流(什麼輸出形式)
- 二元組
單詞類別:
- 標識符(10)
- 無符號數(11)
- 保留字(一詞一碼)
- 運算符(一詞一碼)
- 界符(一詞一碼)
單詞符號 |
種別碼 |
單詞符號 |
種別碼 |
begin |
1 |
: |
17 |
if |
2 |
:= |
18 |
then |
3 |
< |
20 |
while |
4 |
<= |
21 |
do |
5 |
<> |
22 |
end |
6 |
> |
23 |
l(l|d)* |
10 |
>= |
24 |
dd* |
11 |
= |
25 |
+ |
13 |
; |
26 |
– |
14 |
( |
27 |
* |
15 |
) |
28 |
/ |
16 |
# |
0 |
程序詞法分析代碼:
#include <iostream> #include<stdio.h> #include<string.h> #include<stdlib.h> using namespace std; //關鍵字 string key[6]={"main","int","if","else","while","do"}; //關鍵字的種別碼 int keyNum[6]={1,2,3,4,5,6}; //運算符和界符 string symbol[17]={"<",">","!=",">=","<=","==",",",";","(",")","{","}","+","-","*","/","="}; //char symbol[12]={'<','>','!=','>=','<=','==',',',';','(',')','{','}'}; //運算符和界符的種別碼 int symbolNum[17]={7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; //存放文件取出的字符 string letter[1000]; //將字符轉換為單詞 string words[1000]; int length; //保存程序中字符的數目 int num; //判斷運算符和界符 int isSymbol(string s){ int i; for(i=0;i<17;i++){ if(s==symbol[i]) return symbolNum[i]; } return 0; } //判斷是否為數字 bool isNum(string s){ if(s>="0" && s<="9") return true; } //判斷是否為字母 bool isLetter(string s){ if(s>="a" && s<="z") return true; } //判斷是否為關鍵字,是返回種別碼 int isKeyWord(string s){ int i; for(i=0;i<6;i++){ if(s==key[i]) return keyNum[i]; } return 0; } //返回單個字符的類型 int typeword(string str){ if(str>="a" && str<="z") // 字母 return 1; if(str>="0" && str<="9") //數字 return 2; if(str==">"||str=="="||str=="<"||str=="!"||str==","||str==";"||str=="("||str==")"||str=="{"||str=="}" ||str=="+"||str=="-"||str=="*"||str=="/") //判斷運算符和界符 return 3; } string identifier(string s,int n){ int j=n+1; int flag=1; while(flag){ if(isNum(letter[j]) || isLetter(letter[j])){ s=(s+letter[j]).c_str(); if(isKeyWord(s)){ j++; num=j; return s; } j++; } else{ flag=0; } } num=j; return s; } string symbolStr(string s,int n){ int j=n+1; string str=letter[j]; if(str==">"||str=="="||str=="<"||str=="!") { s=(s+letter[j]).c_str(); j++; } num=j; return s; } string Number(string s,int n){ int j=n+1; int flag=1; while(flag){ if(isNum(letter[j])){ s=(s+letter[j]).c_str(); j++; } else{ flag=0; } } num=j; return s; } void print(string s,int n){ cout<<"("<<s<<","<<n<<")"<<endl; } //取單詞 void TakeWord(){ int k; for(num=0;num<length;){ string str1,str; str=letter[num]; k=typeword(str); switch(k){ case 1: str1=identifier(str,num); if(isKeyWord(str1)) print(str1,isKeyWord(str1)); else print(str1,0); break; case 2: str1=Number(str,num); print(str1,24); break; case 3: str1=symbolStr(str,num); print(str1,isSymbol(str1)); break; } } } int main(){ char w; int i,j; freopen("test.txt","r",stdin);//讀取本地文件 freopen("result.txt","w",stdout); //從控制台輸出,而不是文本輸出 length=0; while(cin>>w){ if(w!=' '){ letter[length]=w; length++; } //去掉程序中的空格 } TakeWord(); fclose(stdin);//關閉文件 fclose(stdout);//關閉文件 return 0; }
運行程序前準備一個分析文本test.txt內容如下:
int main() { int m,n; int num=0; n=10; if(n<0){ m=-n; } else{ m=n; } while(m!=0){ num=m*n; } }
執行程序會輸出如下結果:
(int,2) (main,1) ((,15) (),16) ({,17) (int,2) (m,0) (,,13) (n,0) (;,14) (int,2) (num,0) (=,23) (0,24) (;,14) (n,0) (=,23) (10,24) (;,14) (if,3) ((,15) (n,0) (<,7) (0,24) (),16) ({,17) (m,0) (=,23) (-,20) (n,0) (;,14) (},18) (else,4) ({,17) (m,0) (=,23) (n,0) (;,14) (},18) (while,5) ((,15) (m,0) (!=,9) (0,24) (),16) ({,17) (num,0) (=,23) (m,0) (*,21) (n,0) (;,14) (},18) (},18)