日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用状态图实现词法分析

發布時間:2024/4/17 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用状态图实现词法分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://blog.csdn.net/cn854/article/details/697242

實驗一:詞法分析程序

????????????????????????????????????????????????????????????????????????????????????????????? 03070020?曹寧

一.? 實驗目的

基本掌握計算機語言的詞法分析程序的開發方法。

二.? 實驗內容

編制一個能夠分析三種整數、標識符、主要運算符和主要關鍵字的詞法分析程序。

三.? 實驗環境

PC微機

DOS操作系統或 Windows操作系統

Turbo C 程序集成環境或 Visual C++程序集成環境

四.? 實驗內容

1.??? 根據以下的正規式,編制正規文法,畫出狀態圖;

標識符

letter(letter|digit)*

letter->A|B|…|Z|a|b|…|z

digit->0|1|2|3|4|…|9

十進制整數

0 | (1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*

八進制整數

0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)*

十六進制整數

0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)*

運算符和分隔符

+ ?- ?* ?/ ?>? <? =? (? ) ?

關鍵字

if? then? else? while? do ?

2.??? 根據狀態圖,設計詞法分析函數int nextToken(),完成以下功能:

1)?????????????從文件讀入數據,分析出一個單詞。

2)?????????????返回單詞種別(用整數表示),

3)?????????????返回單詞屬性(不同的屬性可以放在不同的全局變量中)。

3.??? 編寫測試程序,反復調用函數int nextToken(),輸出單詞種別和屬性。

五.? 實驗步驟

1.????? 根據狀態圖,設計詞法分析算法

標識符??????????

正規式?

id->letter(letter|digit)*

letter->A|B|…|Z|a|b|…|z

digit->0|1|2|3|4|…|9

正規文法

S->aB’|bB’|…|zB’|AB’|BB’|…|ZB’

B’->0B’|1B’|…|9B’

狀態圖

?????????????

八進制整數?????????????

正規式?

0(1|2|3|4|5|6|7)(0|1|2|3|4|5|6|7)*

正規文法

S->01B|02B|…|07B

B->0B|1B|…|7B|

十進制整數?????????????

正規式?

0 | (1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*

正規文法

S->0|1B|2B|…|9B

B->0B|1B|…|9B|

十六進制整數?????????????

正規式?

0x(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)(0|1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)*

正規文法

S->0(x|X)(1B’|2B’|…|9B’|aB’|bB’|…|fB’|AB’|…|FB’)

B’->0B’|1B’|…|7B’|

識別這三種數字的狀態圖

?????????????

運算符和分隔符

狀態圖

?

2.????? 采用C語言,設計函數scan( ),實現該算法

程序中的變量和函數聲明

//對外函數

extern void initLexer();//打開文件,初始化詞法分析器

extern int nextToken();//獲得一個token

//對外變量

extern int attr=-1;//是數值的時候存儲數值,是標識符時存儲在名字表中的位置

extern int lineNo=1;//顯示行數

extern char *keyWord[]={

??????? "if",

??????? "else",

??????? "then",

??????? "while",

??? ????"do"

};

//內部函數

static int fail();//換狀態圖

static char getAnChar();//在文件中讀取一個字符,指針下移一位

static void ungetAnChar();//在文件中指針回退一位

static void getNum(int type);//根據type,獲得十進制數值,存儲在attr

static int lookup(const char *s);//在符號表中查找ID

static int insert(const char *s);//返回再符號表中的下標位置

static int isKeyWord(char word[]);//判斷是否為關鍵字

//內部變量

static char lexBuf[100];//字符緩存,用來存儲當前分析的字

static int state=1, start=1;//當前狀態和狀態表的開始狀態

static int currentPos=0;//文件中當前指針的位置

static int tokenBeginning=0;//進入一個狀態表時指針位置,即換狀態表時的回退位置。

static FILE *fp;//被編譯的文件指針

static int smptableLength=0;//當前符號表的長度

?

int nextToken(){

?

??? int length=0;

??? char c;

??? int keyWordPos=0;//在關鍵字數組中的下標

?

??? state=1;start=1;

??? //存儲開始位置

??? tokenBeginning=currentPos;

??? //狀態圖的實現

??? while(1){

?

??????? switch(state){

??????? case 1:

??????????? c=getAnChar();

??????????? if(c==' '||c=='/t'||c=='/r'){

??????????????? tokenBeginning++;

??????????? }

??????????? else if(c=='/n'){

??????????????? lineNo++;

??????????????? tokenBeginning++;

??????????? }

??????????? else if(isalpha(c)){

??????????????? state=2;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else if(c==EOF) return FILEEND;

??????????? else state=fail();

??????????? break;

??????? case 2:

????????? ??c=getAnChar();

??????????? if(isdigit(c)||isalpha(c)){

??????????????? state=2;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else state=3;

??????????? break;

??????? case 3:

??????????? ungetAnChar();

??????????? lexBuf[length]='/0';

?? ?????????keyWordPos=isKeyWord(lexBuf);

??????????? if(keyWordPos!=-1){

??????????????? //是關鍵字

??????????????? return IF+keyWordPos;

??????????? }

??????????? //不是關鍵字

??????????? attr=insert(lexBuf);//把ID在名字表中的數組下標存儲在attr中

??????????? return ID;

??????? case 4:

??????????? c=getAnChar();

??????????? if(c=='0') state=5;

??????????? else if(c>='1' && c<='9'){

??????????????? state=12;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else state=fail();

??????????? break;

??????? case 5:

?????????? ?c=getAnChar();

??????????? if(c=='x') state=6;

??????????? else if(c>='1'&& c<='8'){

??????????????? state=10;

??????????????? lexBuf[length++]=c;

??????????? }

?

??????????? else state=13;

??????????? break;

??????? case 6:

??????????? c=getAnChar();

??? ????????if(c>='1' && c<='9' || c>='a'&& c<='f' || c>='A' && c<='B'){

??????????????? state=7;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else state=fail();

??????????? break;

??????? case 7:

??????????? c=getAnChar();

??????????? if(c>='1' && c<='9' || c>='a'&& c<='f' || c>='A' && c<='B'||c=='0'){

??????????????? state=7;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else state=8;

??????????? break;

??????? case 8:

??????????? ungetAnChar();

??????????? lexBuf[length]='/0';

??????????? getNum(INT16);//把數值存在attr中

??????????? return INT16;

??????? case 10:

??????????? c=getAnChar();

??????????? if(c>='0'&& c<='8'){

??????????????? state=10;

??????????????? lexBuf[length++]=c;

??????????? }

??????????? else state=11;

???????? ???break;

??????? case 11:

?? ?????????ungetAnChar();

??????????? lexBuf[length]='/0';

??????????? getNum(INT8);//把數值存在attr中

??????????? return INT8;

??????? case 12:

??????????? c=getAnChar();

??????????? if(c>='0' && c<='9'){

??????????????? state=12;

? ??????????????lexBuf[length++]=c;

??????????? }

??????????? else state=13;

??????????? break;

??????? case 13:

??????????? ungetAnChar();

??????????? lexBuf[length]='/0';

??????????? getNum(INT10);//把數值存在attr中

??????????? return INT10;

??????? case 14:

?? ?????????c=getAnChar();

??????????? if(c=='+') state=15;

??????????? else if(c=='-') state=16;

??????????? else if(c=='*') state=17;

??????????? else if(c=='/') state=18;

??????????? else if(c=='>') state=19;

??????????? else if(c=='<') state=20;

???????? ???else if(c=='=') state=21;

??????????? else if(c=='(') state=22;

??????????? else if(c==')') state=23;

??????????? else if(c==';') state=24;

??????????? else state=fail();

??????????? break;

??????? case 15:

??????????? return ADD;

??????? case 16:

???? ???????return SUB;

??????? case 17:

??????????? return MUL;

??????? case 18:

??????????? return DIV;

??????? case 19:

??????????? return GT;

??????? case 20:

??????????? return LT;

??????? case 21:

??????????? return EQ;

??????? case 22:

??????????? return LBR;

??????? case 23:

??????????? return RBR;

??????? case 24:

??????????? return SEM;

??????? }

??? }????

}

?

3.????? 編制測試程序(主函數main)。

void main(){

???? int token;

???? int oldLine=-1;

???? initLexer();??

?????

???? while(1){

???????? token=nextToken();

???? ????if(token==FILEEND) break;

???????? if(oldLine!=lineNo) {

???????????? printf("___________Line %d____________/n",lineNo);

???????????? oldLine=lineNo;

???????? }

????????

??????? if(token==ID){//標識符

??????????? printf("ID:%d,Pos:%d/n",token,attr);

??? ????}

??????? else {

??????????? switch(token){

??????????????? case INT16:case INT8:case INT10://數字

??????????????????? printf("%d/t/t%d/n",token,attr);

??????????????????? break;

??????????????? default: printf("%d/n",token);//關鍵字

??????????????? }

???? ???}

??????? token=nextToken();

???? }

}//*/

?

4.????? 調試程序:輸入一組單詞,檢查輸出結果

??? 1? 92+data>? 0x3f? 04? while

1x3 x3 x3 x44?? 00

以上都是一行的沒有出現什么問題,但是當對多行進行詞法分析時,總是出錯,通過打印讀到的字符發現有字符13ASCII),查資料才知是’/t’,把光標移到當前行的起始位置,我不知道為什么會有這個字符,添加濾掉這個字符的邏輯,才使詞法分析成功。

while (1) do num=10;

num=11;

if (1) then caoning=0x11;

if (1) than caoning=878;

?

5.????? 詞法分析程序的數據結構與算法

符號表的數據結構:采用的是結構數組

struct ENTYE{

?? char word[100];

?? float value;

};

int smptableLength=0;

struct ENTYE smptable[200];

在配以int lookup(const char *s)int insert(const char *s)對這個符號表操作。

/*查找s在符號表的位置,沒有返回-1*/

int lookup(const char *s){

??? int i;

??? for (i=0;i<smptableLength;i++){

??????? if (strcmp(smptable[i].word,s)==0) return i;

??? }

??? return -1;

}

/*返回s在符號表中的位置*/

int insert(const char *s){

?? int i=lookup(s);

?? if(i==-1){

??????? strcpy(smptable[smptableLength].word,s);

?????? //smptableLength++;

?????? return smptableLength++;

?? }

?? return i;

}

六.? 心得體會

這次詞法分析的實驗本身沒有什么難度,但是在做這實驗之前感覺沒譜,所以踏下心仔細的閱讀Aho的《編譯原理》中前三章,受到很大啟發,尤其是利用switch語句把狀態圖實現的技術,可謂一絕,這也是我學習詞法分析的最大的收獲。

在做語法分析的時候,對詞法分析進行了一些修改,學習了一下不同文件內的函數和變量的使用,在做詞法分析的時候架構沒有做好,比如哪些函數和變量作為內部的,哪些是提供外部使用的接口,比較混亂,也沒有進行大量測試,導致語法分析時受阻重重,最后停下語法分析的編程,對此詞法分析修改,使程序清晰易讀,并進行了大量的測試,再作語法分析時就容易多了。這也是個教訓,以后編程首先得考慮好,再一步一步來。就會省很多麻煩。

?

?

?

http://blog.chinaunix.net/uid-26750235-id-3088397.html

代碼下載: git clone git://git.code.sf.net/p/redy/code redy-code
這一章的內容有: 通過一個實例來說明狀態機合并的方法 狀態機合并算法 狀態鏈在合并中的優點

(1)簡介 在這一章里面,你會看到兩個簡單的狀態機: 一個為狀態機用于識別正則式 ? [0-7]+abf 所表于的語言,[0-7] 表于數字0-7中的任意一個,'+'表示重復一次或多次。 另一個狀態機用于識別正則式 [4-9]+acd所表于的語言。同樣[4-9]表示數字4-7中的任意一個。'+'表示重復一次或多次。
(2)狀態機1 根據正則式[0-7]+abf,繪出的狀態圖如下:

我們使用狀態鏈的算法來用程序來構造該狀態機,從狀態中可以看出,該狀態機總共有5個狀態,其中Abegin為開始狀態,A4為終態,由于每個狀態,都只在一個輸入類型下發生狀態轉移,所以每一個狀態,這里采用函數指釷的方法來判斷輸入類型。 在程序開頭,我們對于每一個狀態都進行申明,以使后面引用:
  • extern struct state Abegin;
  • extern struct state A1;
  • extern struct state A2;
  • extern struct state A3;
  • extern struct state A4;
  • 狀態Abegin在數據輸入字符0-7的情況下轉移到狀態A1,在其它輸入情況下讓狀態Abegin轉移到錯誤狀態lex_state_err。
  • int input_map_abegin(char c)
  • {
  • ????if(c>='0'&&c<='7')return 1;
  • ????else return 0;
  • }
  • struct state* Abegin_targets[]={&lex_state_err,&A1};
  • struct state Abegin={ "Abegin",2,1,0, input_map_abegin, Abegin_targets, 0,};
  • 狀態A1begin在輸入入字符0-7的情況下轉移到自身,當輸入為字符‘a’時轉移到A2,其它則轉移到狀態lex_state_err。
  • int input_map_a1(char c)
  • {
  • ????if(c=='a')return 1;
  • ????if(c>='0'&&c<='7')return 2;
  • ????else return 0;
  • }
  • struct state* A1_targets[]={&lex_state_err,&A2,&A1};
  • struct state A1={ "A1",2,1,0, input_map_a1, A1_targets, 0,};
  • 狀態A2,A3,A4構造方法和前面一樣,所以我就全部貼出。
  • int input_map_a2(char c)
  • {
  • ????if(c=='b')return 1;
  • ????else return 0;
  • }
  • struct state* A2_targets[]={&lex_state_err,&A3};
  • struct state A2={ "A2",2,1,0, input_map_a2, A2_targets, 0,};

  • int input_map_a3(char c)
  • {
  • ????if(c=='f')return 1;
  • ????else return 0;
  • }
  • struct state* A3_targets[]={&lex_state_err,&A4};
  • struct state A3={ "A3",2,1,0, input_map_a3, A3_targets, 0,};

  • int input_map_a4(char c)
  • {
  • ????return 0;
  • }
  • struct state* A4_targets[]={&lex_state_err};
  • struct state A4={ "[0-7]+abf",2,1,0, input_map_a4, A4_targets, 1,};
  • 這樣我們已經用狀態鏈的方法構造出了整個狀態機1的模型。把該模型帶入驅動程序,就可能對類似于011444abf ,2122abf,4abf,的字符串進行識別了。 狀態機1的程序可以在下載的文件夾下面的tutorial/lexical/merge1中找到,對程序進行編譯,運行可執行文件a1。` 下面我們來構造狀態機2 (3)狀態機2 根據正則式[4-9]+acd,繪出狀態圖:
    同樣我們也使用狀態鏈的方法來構造狀態機2,狀態機2總共有5個狀態,開始狀態為Bbegin,終態為B4,同構造狀態機1的方法一樣。我這里就直接貼出程序,不進行說明。 狀態申明:
  • extern struct state Bbegin;
  • extern struct state B1;
  • extern struct state B2;
  • extern struct state B3;
  • extern struct state B4;
  • 狀態機2的5個狀態:
  • int input_map_bbegin(char c)
  • {
  • ????if(c>='4'&&c<='9')return 1;
  • ????else return 0;
  • }

  • struct state* Bbegin_targets[]={&lex_state_err,&B1};
  • struct state Bbegin={ "Bbegin",2,1,0, input_map_bbegin, Bbegin_targets, 0,};


  • int input_map_b1(char c)
  • {
  • ????if(c=='a')return 1;
  • ????if(c>='4'&&c<='9')return 2;
  • ????else return 0;
  • }
  • struct state* B1_targets[]={&lex_state_err,&B2,&B1};
  • struct state B1={ "B1",2,1,0, input_map_b1, B1_targets, 0,};

  • int input_map_b2(char c)
  • {
  • ????if(c=='c')return 1;
  • ????else return 0;
  • }
  • struct state* B2_targets[]={&lex_state_err,&B3};
  • struct state B2={ "B2",2,1,0, input_map_b2, B2_targets, 0,};

  • int input_map_b3(char c)
  • {
  • ????if(c=='d')return 1;
  • ????else return 0;
  • }
  • struct state* B3_targets[]={&lex_state_err,&B4};
  • struct state B3={ "B3",2,1,0, input_map_b3, B3_targets, 0,};

  • int input_map_b4(char c)
  • {
  • ????return 0;
  • }
  • struct state* B4_targets[]={&lex_state_err};
  • struct state B4={ "[4-9]+acd",2,1,0, input_map_b4, B4_targets, 1,};
  • 現在我們就用狀態鏈的方法構造出狀態機2模型,同樣把該模型帶入驅動程序,這樣我們就可以識別例如:4578589acd , 87acd , 9978acd , 等類似的字符串。 狀態機2的程序可以在下載的文件夾下面的tutorial/lexical/merge1中找到,對程序進行編譯,運行可執行文件b1。

    (4)狀態機的合并

    現在我們要把兩個狀態機合并在一起,以便我們的程序同時能夠識別正則式[0-7]+abc所表示的語言和[4-9]+acd所表示的語言,合并狀態機的方法與自動機ENFA轉化為NFA的算法理論基本一樣。總共分為下面幾步:
    a)輸入類型分析 對于狀態機1來說,輸入類型有這么5種
  • 數字0到7  (D0_7)
  • 字符'a'   (S_a)
  • 字符'b'    (S_b)
  • 字符'f'   (S_f)
  • 除以上以外的所有字符  (Other)
  • 對于狀態機2來說,輸入類型有么5種
  • 數字4到9   (D4_9)
  • 字符'a'   (S_a)
  • 字符'c'    (S_c)
  • 字符'd'   (S_d)
  • 除以上以外的所有字符  (Other)
    把兩個狀態機的輸入類型進行合并得到下面9種輸入類型
  • 數字0到3  (D0_3)
  • 數字4到7  (D4_7)
  • 數字8到9  (D8_9)
  • 字符'a'   (D_a)
  • 字符‘b‘   (D_b)
  • 字符‘f’   (D_f)
  • 字符‘c’   (D_c)
  • 字符‘d‘   (D_d)
  • 除以上以外的所有字符   (other)
  • 其中類型D0_7包括:D0_3,D4_7;類型D4_9包括:D4_7,D8_9。
    b)合并第一步 狀態機1的開始狀態為Abegin,狀態機2的開始狀態為Bbegin,把兩個狀態合成一個狀態Cbegin,Abegin和Bbegin兩個狀態能發生的狀態轉移,Cbegin同樣能發生。
    這時狀態圖為: 其中黃色表示狀態機1,綠色表示狀態機2,黃色表示為新創建的狀態。
    因為Abegin,Bbegin能發生的狀態轉移,Cbegin都以發生,即 f(Abegin,D0_7)->A1 f(Begin,D4_9)->B1 所以推得出: f(Cbegin,D0_3)->A1 f(Cbegin,D4_7)->(A1,B1) f(Cbegin,D8_9)->B1 這里我們繪出一個狀態轉換表

    輸入\狀態

    D0_3

    D4_7

    D8_9

    S_a

    S_b

    S_c

    S_d

    S_f

    Other

    Cbegin

    (Abegin,Begin)

    A1

    A1,B1

    B1








    c)合并第二步
    假設狀態S在輸入類型I下的后繼狀態組合為C:
  • 如果C為空,則認為S在輸入類型I下不能發生狀態轉移
  • 如果C中只有一個后繼狀態,則在狀態圖引一條狀態轉移線從狀態S到C,并標記輸入類型為I
  • 如果C是由兩個或多個狀態組合在一起,而且這狀態組合在以前沒有出現過,則創建一個新的狀態N,新狀態N等價原狀成組合,從狀態圖引一條狀態轉移線從狀態S到N,并標記輸入類型為I
  • 如果C是由兩個或多個組合在一起,而該狀態組合已經出現過,則在狀態圖引一條轉移線從狀態S到該狀態組合的等價狀態。
  • 現在我們來看狀態機1與狀態機2的合并 因為
  • 狀態Cbegin在D0_3轉換為A1,A1為單一狀態,所以在狀態圖上引一條轉移線從Cbegin到A1,并標記輸入類型為D0_3
  • 狀態Cbeign在D8_9轉換為B1,B1為單一狀態,所以在狀態圖上引一條轉移線從Cbegin到B1,并標記輸入類型為D8_9
  • 狀態Cbegin在D4_7轉換為(A1,B1),(A1,B1)為狀態組合,并且前面沒有出現該狀態組合,所以創建一個新狀態C1,在狀態圖上引一條轉移線從Cbegin到C1,并標記輸入類型為D4_7。同時對C1進行標記,表示C1還未進行狀態轉移處理。
  • 此時狀態圖為:

    d)合并第三步
    在這一步中,找出標記一個標記過的狀態,進行狀態轉移處理,在一步時,我們只有狀態C1被標記過,狀態C1等價于(A1,B1)的組合,這時我們對狀態C1進行處理,并且取消對C1的標記。 因為 f(A1,D0_7)->A1 f(A1,S_a)->A2 f(B1,D4_9)->B1 f(B1,S_a)->B2 所以 f(C1,D0_3)->A1 f(C1,D4_7)-:>(A1,B1) f(C1,D8_9)->B1 f(C1,S_a)->(A2,B2) 根據上面的轉移公式,我們繼續繪畫狀態轉移表

    輸入\狀態

    D0_3

    D4_7

    D8_9

    S_a

    S_b

    S_c

    S_d

    S_f

    Other

    Cbegin

    (Abegin,Begin)

    A1

    A1,B1

    B1







    C1

    (A1,B1)

    A1

    A1,B1

    B1

    A2,B2







    根據上面的轉換,我們繼續繪制狀態圖
  • 由于C1在D0_3,D8_9分別轉移到狀態A1,B1。A1與B1分別都是單狀態,所以從C1引一條轉移線分別到A1與B1。
  • C1在D4_7轉換為(A1,B1),(A1,B1)為狀態組合,但是(A1,B1)在前面已經出現過了,就是狀態C1本身,所以引一條轉移線,從C1自己到自己。
  • C1在S_a的轉換到(A2,B2),(A2,B2)為狀態組合,以前也沒有出現過,所以創建一個等價于(A2,B2)的狀態C2,標記C2,并且從C1引一條到C2。

  • 此時狀態圖為:
    e)合并第四步 合并第四步,就是得重復第三步,直到沒有標記狀態為止,現在被標記的狀態只有C2,所以我們需要對C2進行處理,并且取消標記C2。按照第三步的方法來處理。 因為 f(A2,S_b)=A3 f(B2,S_c)=B3 所以 f(C2,S_b)=A3 f(C2,S_c)=B3 根據上面公式,這時轉移表為:

    輸入\狀態

    D0_3

    D4_7

    D8_9

    S_a

    S_b

    S_c

    S_d

    S_f

    Other

    Cbegin

    (Abegin,Begin)

    A1

    A1,B1

    B1







    C1

    (A1,B1)

    A1

    A1,B1

    B1

    A2,B2






    C2

    (A2,B2)





    A3

    B3





    繼續繪制我們的狀態轉換圖,因為狀態C2在S_b,S_c分別轉移到A3,B3。兩個都是單狀態,所以分別畫一條轉移線從C2到A3,B3。
    此時狀態圖為:
    到現在為些,已經沒有標記過的狀態了,所以狀態機1與狀態機2的合并也算完成了。

    (5)合并后的狀態機

    通過合并后的狀態圖,我們可以看到合并后,我們并不用修改狀態機1和狀態機2,只是增加了3個新的狀態,把兩個狀態機鏈接起來。這次合并總共增加了三個新的狀態,我們把這三個狀態加入我們的狀態鏈中去。 為了后面引用,我們先申明這三個狀態
  • extern struct state Cbegin;
  • extern struct state C1;
  • extern struct state C2;
  • 狀態Cbegin,在D0_3轉移到狀態A1, 在D4_7轉移到C1,在狀態D8_9轉移到B1。
  • int input_map_cbegin(char c)
  • {
  • ????if(c>='0'&&c<='3')return 1;
  • ????else if(c>='4'&&c<='7')return 2;
  • ????else if(c>='8'&&c<'9')return 3;
  • ????else return 0;
  • }

  • struct state* cbegin_targets[]={ &lex_state_err,&A1,&C1,&B1};
  • struct state Cbegin={"Cbegin",4,3,0,input_map_cbegin,cbegin_targets,0};

  • 狀態C1在D0_3轉移到狀態A1,在D4_7轉移到本身,在D8_9轉移到B1,在S_a轉移到C2
  • int input_map_c1(char c)
  • {
  • ????if(c>='0'&&c<='3')return 1;
  • ????else if(c>='4'&&c<='7')return 2;
  • ????else if(c>='8'&&c<'9')return 3;
  • ????else if(c=='a')return 4;
  • ????else return 0;
  • }
  • struct state* C1_targets[]={&lex_state_err,&A1,&C1,&B1,&C2};
  • struct state C1={"C1",5,4,0,input_map_c1,C1_targets,0};
  • 狀態C2在S_a轉移到狀態A3,在S_c轉移到狀態狀態B3
  • int input_map_c2(char c)
  • {
  • ????if(c=='b')return 1;
  • ????else if(c=='c')return 2;
  • ????else return 0;
  • }

  • struct state* C2_targets[]={&lex_state_err,&A3,&B3};
  • struct state C2={"C2",3,2,0,input_map_c2,C2_targets,0};

  • 這樣我們就以經完成合并后狀態機模型的狀態鏈,這時把開始狀態改為Cbegin,代入驅動程序,可以對正則式[0-7]+abf和正則式[4-9]+acd表示的語言進行綜合識別了 合并后的狀態機可以在下載的文件夾下面的tutorial/lexical/merge1中找到,對程序編譯,運行可執行文件merge 順便在這里也貼出一個運行后的圖給大家看看運行結果。
    (6)總結

    a)合并算法總結

    通過上面的實例大家應該對狀態機合并了解了。狀態機合并總共分為這么幾步: 1)分析兩個狀態機的輸入類型。 2)找到兩個狀態機的開始狀態,并且建立一個與組合狀態等價的新狀態Begin,標記新的狀態,這里等價意義為,組合狀態中任意一個狀態,在某種輸入類型下發生狀態轉移,與之等價的新狀態同樣也會在該輸入類型下發生狀態轉移 3)找出一個被標記過的狀態(命名為S)執行下面的步驟: a)找出狀態S在每一種輸入類型下的后繼狀態,等價于找出與之等價的組合狀態中的每一個在該輸入類型下發生的后繼狀態的組合。  b)對于后繼狀態來說,有下面3種情況: 如果狀態S在輸入類型A下的后繼狀態B只有一個,則畫一條從狀態S出發到后繼狀態B的轉移線,并在轉移線上標出輸入類型A。 如果狀態S在輸入類型A下的后繼狀態有兩個或多個,并且該狀態組合在以前沒有出現過,則創建一個與之等價的狀態C,并且標記C。隨后畫一條從狀態S出發到新狀態C的轉移線,并在轉移線上標出輸入類型A 如果狀態S在輸入類型A下的后繼狀態有兩個或多個,并且與狀態組合狀態B在以前已經出現過,則畫一條從從狀態S出發到狀態B的轉移線,并在轉移線上標出輸入類型A。 c)取消對狀態S的標記 4)重復第三步,直到沒有標記過的狀態。 5)把狀態Begin設置為該狀態機的開始狀態。 6)自動機合并完成。

    b)采用狀態鏈狀態機的優點

    從上面自動機合并的實例相信大家已經看到,當我們在合并兩個狀態機的時候,并沒有更改狀態1和狀態機2的任何結構,我們只是簡單的增加幾個狀態,把兩個狀態機連接在一起,來實現的狀態機的合并。這樣的好處在于當我們要開發的識別系統中存在不同的單詞類型時,我們可以分開來制作每一類單詞的狀態機,在合并的時候,我們不用去改變那些現有的自動機,只是簡單增加新的狀態,把它們連接到一起。這樣就可以把一個大的事情,分多個小的步驟來完成。
    在狀態中每一個狀態,不用去關心狀態機的整體結構。這是我們實現狀態機合并的關鍵。

    ?

    總結

    以上是生活随笔為你收集整理的利用状态图实现词法分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 天天操天天插天天干 | 青青在线免费观看 | 老熟妇高潮一区二区高清视频 | 亚洲熟女乱色一区二区三区 | 国产精品久久久久高潮 | 男女插鸡视频 | 久久性片 | 男女做受视频 | 国产在线97 | 96精品视频 | 午夜寂寞少妇 | 女生和男生一起插插插 | 国内毛片毛片毛片毛片 | 欧美日韩亚洲一区 | 精品久久久久久无码中文野结衣 | 青青在线| 日韩色 | 一区二区成人网 | 国产成人一区二区三区影院在线 | 天天综合天天做天天综合 | 国产日韩欧美在线观看视频 | 午夜日韩av| 久久成人在线视频 | 欧美精品在线免费 | 一级日批片 | 特黄三级又爽又粗又大 | 亚洲成人av电影网站 | 黄a毛片| 国产一区视频免费观看 | 强公把我次次高潮hd | 在线免费黄色 | 综合精品久久久 | 日韩精品二区在线观看 | 国产日韩中文字幕 | 久久午夜精品人妻一区二区三区 | 国产精品水嫩水嫩 | 老头把女人躁得呻吟 | 国产成人在线视频 | 91看片在线观看 | 欧美成人做爰猛烈床戏 | 中文字幕在线观看视频www | 天堂在线| 亚洲av乱码久久精品蜜桃 | 色香蕉网站 | 久久四色 | 13日本xxxxxⅹxxx20 | 亚洲素人在线 | 2024国产精品视频 | 桃色成人| 国产主播毛片 | 欧美性猛交xx乱大交 | 精品国产一区在线 | 久久r这里只有精品 | 国产69精品一区二区 | 国产亚洲性欧美日韩在线观看软件 | 久久精品成人一区二区三区蜜臀 | 76少妇精品导航 | 国产精品99久久免费黑人人妻 | 在线观看国产小视频 | 中文字幕无码av波多野吉衣 | 丁香婷婷一区二区三区 | 久久精品成人av | 亚洲乱论 | 住在隔壁的她动漫免费观看全集下载 | 国产精品视频免费看 | www.色多多 | 国产r级在线| 国产97超碰 | 美女免费黄色 | 亚洲一区a | 欧美特级黄 | 小泽玛利亚一区二区三区在线观看 | 悟空影视大全免费高清观看在线 | 亚洲国产精品成人无久久精品 | 成年免费在线观看 | 亚洲精品性视频 | 成人av社区| 国产色综合网 | 国产精品一区二区免费视频 | 免费污片软件 | 男人天堂2024 | 丁香婷婷色 | 亚洲精品在线91 | 人人综合网 | 黑帮大佬和我的365日第二部 | 蜜桃导航-精品导航 | 在线一区二区三区视频 | 免费成人电影在线观看 | 成人涩涩软件 | 九色视频在线观看 | 欧美熟妇精品一区二区蜜桃视频 | 成人av免费在线看 | 日韩精品亚洲精品 | 五月婷婷综合在线观看 | 欧美日韩小说 | 国产免费脚交足视频在线观看 | 国产成人二区 | 美女高潮网站 | 99热这里只有精品首页 |