1. 程式人生 > >編譯原理實驗---詞法分析

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

轉自 

一、實驗概述

1.1、實驗要求

      選擇計算機高階語言之一-----C語言,運用恰當的此法分析技術線路,設計和實現其對應的詞法分析器。

建議:程式語言,選擇《計算機程式設計》課程所採用的語言。

提示:技術線路選擇如下兩種之一:

正則式→NFA→DFA→minDFA→程式設計

         或正則文法→NFA→DFA→minDFA→程式設計。

     要求:分析器輸出結果存入到磁碟檔案中,具有出錯處理功能。

1.2、實驗目的

1)加深對編譯原理及其構造詞法分析器的原理和技術理解與應用,進一步提高學生程式設計能力;

2)培養、提高學生分析問題、解決問題的綜合能力;

3)整理資料,撰寫規範的實驗報告;

二、系統分析

2.1、系統需求

  根據C語言語法,待分析的詞可以分為如下幾類:

(1)    關鍵字

如if, else, whlile, int 等。

(2)    標示符

開頭只能為字母,後面可以接數字或者字母,用來表示各種名字,如變數名、常量名和過程名等

(3)    常數

各種型別的常數,如整型(1, 30),浮點型(2.16),字串型(”AHD”),字元型(’A’)

(4)    運算子與界符

如+,  *, <= , 逗號等。

2.2、系統功能

       讀入一個C語言源程式(經過預處理的),對每一個單詞輸出一些三元組的集合。

2.3、系統實現步驟

按照如下順序構造詞法分析器:

(1) 設計出各類單詞的正規式,畫出有限狀態自動機。

(2) 將各類單詞的正規式轉換成相應的NFA M,並將其合併成一個NFA M`

(3) 將NFA M`轉換成對應的DFA M``

(4) 將DFA M``最小化為DFA M```

(5) 根據DFA M```用C語言設計出相應的詞法分析器。

三、系統設計

3.1、有限狀態自動機設計

     狀態機說明:由於單詞的構成較為複雜,所以再設計時,邊的變遷不再是一個字元,而是一個函式。若當前輸入串滿足該函式,則當前狀態可以變遷到該邊連線的下一狀態。

根據終態可以看出自動機可以分離的狀態有:

INT

整數

FLOAT

浮點數

CHAR

字元型

CHARS

字串型

IDENT

識別符號(包括關鍵字)

SYMBOL

符號

其中,關鍵字的分離在輔助程式中進行。

3.2、單詞符號對應的種別碼

種別碼

單詞符號及說明

種別碼

單詞符號及說明

0

INT(整數)

30

>=

1

FLOAT(浮點數)

31

<=

2

CHAR(字元型)

32

3

CHAR(字串型)

33

4

IDENT(識別符號)

34

==

5

if

35

=

6

else

36

!=

7

int

37

++

8

char

38

+=

9

float

39

+

10

double

40

/

11

long

41

-

12

short

42

\

13

return

43

;

14

while

44

(

15

break

45

)

16

46

{

17

47

}

18

48

[

19

49

]

20

50

:

21

51

->

22

52

?

23

53

,

24

54

.

25

55

*

26

56

27

57

28

58

29

59

3.3、基本資料結構及程式碼設計

      程式碼是用C++完成的。為狀態機定義了兩個基本的結構體,分別為STATE和LIST。其中STATE是LIST的友元,STATE表示的是狀態機中的一個狀態,包括error和start等狀態。LIST的例項是依附於一個STATE的例項存在的,他表示一條邊,邊的值是一個函式指標,該邊指向一個滿足該函式的另一狀態。

      另外用到了STL庫中的MAP模板,定義為map<string,string>type用以存放關鍵字及其對應的種別碼。

      程式的輸出為三元組的集合,其中三元組定義為<單詞名, 單詞含義 ,種別碼>。如一個識別符號abc的三元組為<abc, IDENT , 4> 。若某個單詞錯誤,則會輸出 error: name。 輸出的最後會顯示共識別了多少單詞,並發現多少錯誤。

四、系統實現

4.1 系統執行

l    在命令列裡直接輸入待翻譯的檔案和輸出的檔名。如果沒有給引數,預設為輸入”input.txt”,輸出”output.txt”。

l    輸出的結果。

4.2 系統結果

 input.txt

其中,第六行為錯誤行。

int main()

{

   freopen("input.txt","r",stdin);

    char input[255],*s = input;

    int t = 1;

    floatp = 12.4;

    int 0a = 2;

    init();

    while(gets(s))

    {

       curn = 0;

       printf("Line %d:\n",t++);

       while((*s)!= 0)  

       {

          while((*s) == ' ') s++;  

          curn = 0;

          curtype = 0;

          print(s,start->start(s));

          s += curn;

       }

    }

    return 0;

}

 output.txt

********Line 1*********:

<int, int, 7>

<main, IDENT, 3>

<(, (, 34>

<), ), 35>

********Line 2*********:

<{, {, 36>

********Line 3*********:

<freopen, IDENT, 3>

<(, (, 34>

<"input.txt",CHARS, 2>

<,, ,, 43>

<"r", CHARS, 2>

<,, ,, 43>

<stdin, IDENT, 3>

<), ), 35>

<;, ;, 33>

********Line 4*********:

<char, char, 8>

<input, IDENT, 3>

<[, [, 38>

<255, INT, 0>

<], ], 39>

<,, ,, 43>

<*, *, 45>

<s, IDENT, 3>

<=, =, 25>

<input, IDENT, 3>

<;, ;, 33>

********Line 5*********:

<int, int, 7>

<t, IDENT, 3>

<=, =, 25>

<1, INT, 0>

<;, ;, 33>

********Line 6*********:

<float, float, 9>

<p, IDENT, 3>

<=, =, 25>

<12.4, FLOAT, 1>

<;, ;, 33>

********Line 7*********:

<int, int, 7>

error: 0a

<=, =, 25>

<2, INT, 0>

<;, ;, 33>

********Line 8*********:

********Line 9*********:

<init, IDENT, 3>

<(, (, 34>

<), ), 35>

<;, ;, 33>

********Line 10*********:

********Line 11*********:

<while, while, 14>

<(, (, 34>

<gets, IDENT, 3>

<(, (, 34>

<s, IDENT, 3>

<), ), 35>

<), ), 35>

********Line 12*********:

<{, {, 36>

********Line 13*********:

<curn, IDENT, 3>

<=, =, 25>

<0, INT, 0>

<;, ;, 33>

********Line 14*********:

<printf, IDENT, 3>

<(, (, 34>

<"Line %d:\n",CHARS, 2>

<,, ,, 43>

<t, IDENT, 3>

<++, ++, 27>

<), ), 35>

<;, ;, 33>

********Line 15*********:

<while, while, 14>

<(, (, 34>

<(, (, 34>

<*, *, 45>

<s, IDENT, 3>

<), ), 35>

<!=, !=, 26>

<0, INT, 0>

<), ), 35>

********Line 16*********:

<{, {, 36>

********Line 17*********:

<while, while, 14>

<(, (, 34>

<(, (, 34>

<*, *, 45>

<s, IDENT, 3>

<), ), 35>

<==, ==, 24>

<' ', CHAR, 2>

<), ), 35>

<s, IDENT, 3>

<++, ++, 27>

<;, ;, 33>

********Line 18*********:

<curn, IDENT, 3>

<=, =, 25>

<0, INT, 0>

<;, ;, 33>

********Line 19*********:

<curtype, IDENT, 3>

<=, =, 25>

<0, INT, 0>

<;, ;, 33>

********Line 20*********:

<print, IDENT, 3>

<(, (, 34>

<s, IDENT, 3>

<,, ,, 43>

<start, IDENT, 3>

<-, -, 31>

<>, >, 23>

<start, IDENT, 3>

<(, (, 34>

<s, IDENT, 3>

<), ), 35>

<), ), 35>

<;, ;, 33>

********Line 21*********:

<s, IDENT, 3>

<+=, +=, 28>

<curn, IDENT, 3>

<;, ;, 33>

********Line 22*********:

<}, }, 37>

********Line 23*********:

<}, }, 37>

********Line 24*********:

********Line 25*********:

<return, return, 13>

<0, INT, 0>

<;, ;, 33>

********Line 26*********:

<}, }, 37>

*******************************

1       error!

116 Word Have Been Found Out!

原始碼:

[cpp] view plain copy print?
  1. #include <iostream>
  2. #include <string.h>
  3. #include <map>
  4. #include <stdio.h>
  5. #define num_before_symbol 20
  6. usingnamespace std;  
  7. bool isNum(char *a);  
  8. bool isWord(char *a);  
  9. bool isSymbol(char *a);  
  10. bool isNULL(char *a);  
  11. map<string,string>type;  
  12. char symbol[][10] = {">=","<=","<",">","==","=","!=","++","+=","+","/","-","\\",";","(",")","{","}",  
  13.                      "[","]",":","->","?",",",".","*","\0"};  
  14. int curn = 0;  
  15. int curtype = 0;  
  16. int nerror = 0;  
  17. class STATE;  
  18. class LIST;  
  19. class STATE  
  20. {  
  21.     LIST *list;  
  22.     static STATE *error;  
  23.  public:  
  24.     staticint count;  
  25.     int type;  
  26.     char *name;  
  27.     void enlist(bool (*fun)(char *),STATE *out);  
  28.     const STATE *next(char *in)const;  
  29.     const STATE *start(char *)const;  
  30.     STATE(char *name);  
  31.     ~STATE();  
  32. };  
  33. class LIST{  
  34.   LIST *next;  
  35.   bool (*fun)(char *);  
  36.   STATE *output;  
  37.   LIST(bool (*fun)(char *),STATE *out);  
  38.   ~LIST();  
  39.   friendclass STATE;  
  40. };  
  41. STATE *STATE::error = 0;  
  42. int STATE::count = 0;  
  43. LIST::LIST(bool (*fun)(char *),STATE *out)  
  44. {  
  45.     this->next = NULL;  
  46.     this->fun = fun;  
  47.     this->output = out;  
  48. }  
  49. LIST::~LIST()   //怎麼delete????
  50. {  
  51.     if(this->next!=NULL)  
  52.         deletethis->next;  
  53. }  
  54. const STATE *STATE::next(char *in)const
  55. {  
  56.     LIST *p = list;  
  57.     //if(this == error) return error;
  58.     while(p!=NULL)  
  59.     {  
  60.         if(p->fun(in))  
  61.           return p->output;  
  62.         else
  63.           p = p->next;  
  64.     }  
  65.     return error;  
  66. }  
  67. const STATE *STATE::start(char *s)const
  68. {  
  69.     const STATE *p;  
  70.     if(list == NULL)  
  71.     {  
  72.         if(this != error)  
  73.            count++;  
  74.         else
  75.         {  
  76.             while(isWord(s))  
  77.               curn++;  
  78.         }  
  79.         returnthis;  
  80.     }  
  81.     p = this->next(s);  
  82.     if(p == error)  
  83.       return error;          //error是否要加字首
  84.     return p->start(s+1);  
  85. }  
  86. STATE::STATE(char *name)  
  87. {  
  88.     if(name == 0)  
  89.     {  
  90.        error = this;  
  91.        this->type = 1;  
  92.        return;  
  93.     }  
  94.     if(strcmp(name,"SYMBOL"))  
  95.       this->type = 0;  
  96.     else
  97.       this->type = 1;  
  98.     this->name = newchar[strlen(name)]; //strlen+1
  99.     strcpy(this->name,name);  
  100.     this->list = NULL;  
  101. }  
  102. STATE::~STATE()  
  103. {  
  104.     if(list)  
  105.     {  
  106.       delete list;  
  107.       list = 0;  
  108.     }  
  109.     if(name)  
  110.     {  
  111.         delete name;  
  112.         name = 0;  
  113.     }  
  114. }  
  115. void STATE::enlist(bool (*fun)(char *),STATE *out)  
  116. {  
  117.     LIST *p = new LIST(fun,out);  
  118.     LIST *cur = this->list;  
  119.     if(cur == NULL)  
  120.      this->list = p;  
  121.     else
  122.     {  
  123.        while(cur->next!=NULL)  
  124.           cur = cur->next;  
  125.        cur->next = p;  
  126.     }  
  127. }  
  128. bool mystrcmp(char *a,char *s)  
  129. {  
  130.    int i = 0;  
  131.    while(s[i]!='\0')  
  132.    {  
  133.       if(a[i]!=s[i])  
  134.         returnfalse;  
  135.       i++;  
  136.    }  
  137.    returntrue;  
  138. }  
  139. bool isNum(char *a)  
  140. {  
  141.    if(a[0]<='9' && a[0]>='0')  
  142.    {  
  143.        curn++;  
  144.        returntrue;  
  145.    }  
  146.    returnfalse;  
  147. }  
  148. bool isDot(char *a)  
  149. {  
  150.     if(a[0] == '.')  
  151.     {  
  152.        curn++;  
  153.        returntrue;  
  154.     }  
  155.     returnfalse;  
  156. }  
  157. bool isWord(char *a)  
  158. {  
  159.    if((a[0]<='Z' && a[0]>='A') || (a[0]>='a' && a[0]<='z'))  
  160.     {  
  161.        curn++;  
  162.        returntrue;  
  163.     }  
  164.     returnfalse;  
  165. }  
  166. bool isNotNumOrWord(char *a)  
  167. {  
  168.    if((!(a[0]<='9' && a[0]>='0')) && !isWord(a))  
  169.    {  
  170.        returntrue;  
  171.    }  
  172.    curn--;  
  173.    returnfalse;  
  174. }  
  175. bool isSymbol(char *a)  
  176. {  
  177.     int i = 0;  
  178.     while(strcmp(symbol[i],"\0"))  
  179.     {  
  180.        if(mystrcmp(a,symbol[i]))  
  181.        {  
  182.          curtype = i;  
  183.          curn = strlen(symbol[i]);  
  184.          break;  
  185.        }  
  186.        i++;  
  187.     }  
  188. }  
  189. bool isDQuotation(char *a)  
  190. {  
  191.    if(a[0] == '"')  
  192.    {  
  193.        curn++;  
  194.        returntrue;  
  195.    }  
  196.    returnfalse;  
  197. }  
  198. bool isNotDQuotation(char *a)  
  199. {  
  200.    if(a[0] != '"')  
  201.    {  
  202.        curn++;  
  203.        returntrue;  
  204.    }  
  205.    returnfalse;  
  206. }  
  207. bool isNotSQuotation(char *a)  
  208. {  
  209.    if(a[0]!='\'')  
  210.    {  
  211.        curn++;  
  212.        returntrue;  
  213.    }  
  214.    returnfalse;  
  215. }  
  216. bool isSQuotation(char *a)  
  217. {  
  218.    if(*(a-1)!='\\' && (*a)== '\'')  
  219.    {  
  220.        curn++;  
  221.        returntrue;  
  222.    }  
  223.    returnfalse;  
  224. }  
  225. STATE *start = new STATE("start");  
  226. STATE *s1 = new STATE("s1");  
  227. STATE *s2 = new STATE("s2");  
  228. STATE *s3 = new STATE("s3");  
  229. STATE *s4 = new STATE("s4");  
  230. STATE *s5 = new STATE("s5");  
  231. STATE *s6 = new STATE("s6");  
  232. STATE *INT = new STATE("INT");  
  233. STATE *FLOAT = new STATE("FLOAT");  
  234. STATE *IDENT = new STATE("IDENT");  
  235. STATE *SYMBOL = new STATE("SYMBOL");  
  236. STATE *CHAR = new STATE("CHAR");  
  237. STATE *CHARS = new STATE("CHARS");  
  238. STATE error(0);  
  239. void init()  
  240. {  
  241.     start->enlist(isNum,s1);  
  242.     start->enlist(isWord,s3);  
  243.     start->enlist(isSymbol,SYMBOL);  
  244.     start->enlist(isDQuotation,s4);  
  245.     start->enlist(isSQuotation,s5);  
  246.     s1->enlist(isNum,s1);  
  247.     s1->enlist(isDot,s2);  
  248.     s1->enlist(isNotNumOrWord,INT);  
  249.     s1->enlist(isWord,&error);   //需要將錯誤部分剩下的跳過,對error型別進行標識。
  250.     s2->enlist(isNum,s2);  
  251.     s2->enlist(isNotNumOrWord,FLOAT);  
  252.     s2->enlist(isWord,&error);  
  253.     s3->enlist(isWord,s3);  
  254.     s3->enlist(isNum,s3);  
  255.     s3->enlist(isNotNumOrWord,IDENT);  
  256.     s4->enlist(isNotDQuotation,s4);  //if is """ will get wrong answer
  257.     s4->enlist(isDQuotation,CHARS);  
  258.     s5->enlist(isNotSQuotation,s6);  
  259.     s5->enlist(isSQuotation,&error);  
  260.     s6->enlist(isSQuotation,CHAR);  
  261.     type["INT"] = "0";  
  262.     type["FLOAT"] = "1";  
  263.     type["CHAR"] = "2";  
  264.     type["CHARS"] = "2";  
  265.     type["IDENT"] = "3";  
  266.     type["if"] = "5";  
  267.     type["else"] = "6";  
  268.     type["int"] = "7";  
  269.     type["char"] = "8";  
  270.     type["float"] = "9";  
  271.     type["double"] = "10";  
  272.     type["long"] = "11";  
  273.     type["short"] = "12";  
  274.     type["return"] = "13";  
  275.     type["while"] = "14";  
  276.     type["break"] = "15";  
  277.     //引號算什麼??
  278. }  
  279. void print(char *s,const STATE *p)  
  280. {  
  281.     int i = 0;  
  282.     char temp[255];  
  283.     for(i = 0;i<curn;i++)  
  284.       temp[i] = s[i];  
  285.     temp[i] = '\0';  
  286.     if(p->name == 0)  
  287.     {  
  288.       printf("error: %s\n",temp);  
  289.       nerror++;  
  290.       return;  
  291.     }  
  292.     printf("<");  
  293.     for(i = 0;i<curn;i++)  
  294.       printf("%c",*(s+i));  
  295.     if(curtype == 0)  
  296.     {  
  297.        if(type.find(temp) == type.end())  
  298.           cout<<", "<<p->name<<", "<<type[p->name]<<">"<<endl;  
  299.        else
  300.          cout<<", "<<temp<<", "<<type[temp]<<">"<<endl;  
  301.     }  
  302.     else
  303.       printf(", %s, %d>\n",symbol[curtype],num_before_symbol+curtype);  
  304. }  
  305. int main(int argv,char *argc[])  
  306. {  
  307.     char temp[2][255];  
  308.     if(argv<2)  
  309.         strcpy(temp[0],"input.txt");  
  310.     else
  311.         strcpy(temp[0],argc[1]);  
  312.     if(argv<3)  
  313.         strcpy(temp[1],"output.txt");  
  314.     else
  315.         strcpy(temp[1],argc[2]);  
  316.     freopen((constchar*)temp[0],"r",stdin);  
  317.     freopen((constchar*)temp[1],"w",stdout);  
  318.     char input[255],*s = input;  
  319.     int t = 1;  
  320.     init();  
  321.     while(gets(s))  
  322.     {  
  323.        curn = 0;  
  324.        printf("********Line %d*********:\n",t++);  
  325.        if(t == 18)  
  326.          t = 18;  
  327.        while((*s)!='\0')    //n is last edit
  328.        {  
  329.           while((*s) == ' ') s++;   //濾掉空格
  330.           curn = 0;  
  331.           curtype = 0;  
  332.           print(s,start->start(s));  
  333.           s += curn;  
  334.           while((*s) == ' ') s++;   //濾掉空格
  335.        }  
  336.        s = input;  
  337.        printf("\n");  
  338.     }  
  339.     printf("*******************************\n%d error!\n%d Word Have Been Found Out!\n",nerror,STATE::count);  
  340.     return 0;  
  341. }