青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見(jiàn)諒!~
隨筆 - 1469, 文章 - 0, 評(píng)論 - 661, 引用 - 0
數(shù)據(jù)加載中……

使用 Flex 和 Bison 更好地進(jìn)行錯(cuò)誤處理

  盡管使用 Flex Bison 生成程序非常簡(jiǎn)單,但是要讓這些程序產(chǎn)生用戶友好的語(yǔ)法和語(yǔ)義錯(cuò)誤消息卻很困難。本文將介紹 Flex Bison 的錯(cuò)誤處理特性,并展示如何使用它們,然后詳細(xì)介紹它們的一些缺陷。

 

  簡(jiǎn)介

 

  正如 UNIX? 開發(fā)人員所了解的那樣,Flex Bison 的功能非常強(qiáng)大,非常適合開發(fā)詞法和語(yǔ)法解析器,尤其是語(yǔ)言編譯器和解釋器。如果我們不熟悉它們所實(shí)現(xiàn)的工具 —— 分別是 Lex Yacc —— 可以參考一下本文 參考資料一節(jié)中有關(guān) Flex Bison 文檔的鏈接,以及其他介紹這兩個(gè)程序的文章。

 

  本文介紹了更高級(jí)的一些主題:用來(lái)在編譯器和解釋器中更好地實(shí)現(xiàn)錯(cuò)誤處理能力的特性和技術(shù)。為了展示這些技術(shù),我使用了一個(gè)示例程序 ccalc,它基于 Bison 手冊(cè)中的計(jì)算機(jī)實(shí)現(xiàn)了一個(gè)增強(qiáng)的計(jì)算器。我們可以從本文后面下載 一節(jié)下載 ccalc 和相關(guān)文件。

 

  增強(qiáng)包括使用了很多變量。在 ccalc 中,變量是通過(guò)在初始化中首次使用時(shí)定義的,例如 a = 3。如果變量是在初始化之前使用的,那就會(huì)產(chǎn)生語(yǔ)義錯(cuò)誤,使用值為 0 來(lái)創(chuàng)建這個(gè)變量,并打印一條消息。

 

  示例源文件

 

  示例源代碼中包括 7 個(gè)文件:

 

ccalc.c:主程序,以及一些進(jìn)行輸入、輸出和錯(cuò)誤處理的函數(shù)

ccalc.h:包括了對(duì)所有模塊的定義

cmath.c:數(shù)學(xué)函數(shù)

parse.yBison 使用的輸入文法

lex.lFlex 的輸入

makefile:簡(jiǎn)單的 makefile

defs.txt:示例輸入文件

  這個(gè)程序接收兩個(gè)參數(shù):

 

-debug:產(chǎn)生調(diào)試輸出

filename:輸入文件名;默認(rèn)值為 defs.txt

  Bison 使用的設(shè)置

 

  為了處理變量名和實(shí)際值,Bison 的語(yǔ)義類型必須進(jìn)行增強(qiáng):

 

  清單 1. 更好的 Bison 語(yǔ)義類型

 

/* generate include-file with symbols and types */

%defines

/* a more advanced semantic type */

%union {

 double   value;

 char    *string;

}

 

  有些文法規(guī)則可以產(chǎn)生特定的語(yǔ)義類型,這需要像清單 2 中一樣對(duì) Bison 進(jìn)行聲明。要獲得一個(gè)可移植性更好的 Bison 文法版本,我們需要重新定義 +-*/() 符號(hào)。下面這個(gè)例子沒(méi)有使用左括號(hào) (,而是使用了結(jié)束符符號(hào) LBRACE,這是由詞法分析提供的。另外,操作符的優(yōu)先順序也必須進(jìn)行聲明。

 

  對(duì)于 Flex 來(lái)說(shuō),所生成的代碼通常都依賴于平臺(tái)所使用的代碼頁(yè)(codepage)。盡管我們可以使用其他代碼頁(yè),但是必須要對(duì)輸入進(jìn)行轉(zhuǎn)換。因此與 Bison 代碼不同,Flex 代碼尚不能進(jìn)行移植。

 

  清單 2. Bison 聲明

 

/* terminal symbols */

%token <string>  IDENTIFIER

%token <value>  VALUE

%type <value>   expression

/* operator-precedence

* top-0: -

*   1: * /

*   2: + -

*/

%left ADD SUB

%left MULT DIV

%left NEG

%start program

 

  這段文法與 Bison 手冊(cè)非常類似,不同之處在于它使用了名字作為終端符號(hào)和標(biāo)識(shí)符的簡(jiǎn)寫形式。標(biāo)識(shí)符是在賦值語(yǔ)句中進(jìn)行定義和初始化的,并且可以在任何允許使用的地方使用。清單 3 給出了一個(gè)示例文法:

 

  清單 3. 示例 Bison 文法

 

program

  : statement SEMICOLON program

  | statement SEMICOLON

  | statement error SEMICOLON program

  ;

statement

  : IDENTIFIER ASSIGN expression

  | expression

  ;

expression

  : LBRACE expression RBRACE

  | SUB expression %prec NEG

  | expression ADD expression

  | expression SUB expression

  | expression MULT expression

  | expression DIV expression

  | VALUE

  | IDENTIFIER

  ;

 

  program 的第三個(gè)輸出讓這個(gè)分析程序可以獲得錯(cuò)誤,從中搜索分號(hào),然后繼續(xù)執(zhí)行(通常錯(cuò)誤對(duì)于解析器來(lái)說(shuō)都是非常嚴(yán)重的)。

 

  為了讓這個(gè)例子更加有趣,規(guī)則體中的真正數(shù)學(xué)函數(shù)都是以單獨(dú)函數(shù)的形式實(shí)現(xiàn)的。在進(jìn)行高級(jí)文法分析時(shí),我們要盡量保證規(guī)則簡(jiǎn)短,并使用函數(shù)來(lái)實(shí)現(xiàn)一些不會(huì)直接處理解析的過(guò)程:

 

  清單 4. 使用單獨(dú)的函數(shù)來(lái)實(shí)現(xiàn)數(shù)學(xué)規(guī)則

 

| expression DIV expression

 {

  $$ = ReduceDiv($1, $3);

 }

 

  最后,函數(shù) yyerror() 必須要進(jìn)行定義。這個(gè)函數(shù)是在所生成的解析器檢測(cè)到語(yǔ)法錯(cuò)誤時(shí)調(diào)用的,它又會(huì)調(diào)用一個(gè)小函數(shù) PrintError(),后者會(huì)打印增強(qiáng)的錯(cuò)誤消息。詳細(xì)內(nèi)容請(qǐng)參看源代碼。

 

  Flex 的設(shè)置

 

  Flex 所生成的詞法分析器必須要根據(jù)語(yǔ)義類型提供終止符號(hào)。清單 5 定義了空格、實(shí)際值、標(biāo)識(shí)符和符號(hào)所使用的語(yǔ)法。

 

  清單 5. 示例 Flex 規(guī)則

 

[   

]+ {

  /* eat up whitespace */

  }

{DIGIT}+ {

  yylval.value = atof(yytext);

  return VALUE;

  }

{DIGIT}+"."{DIGIT}*    {

  yylval.value = atof(yytext);

  return VALUE;

  }

{DIGIT}+[eE]["+""-"]?{DIGIT}*    {

  yylval.value = atof(yytext);

  return VALUE;

  }

{DIGIT}+"."{DIGIT}*[eE]["+""-"]?{DIGIT}*    {

  yylval.value = atof(yytext);

  return VALUE;

  }

{ID}    {

  yylval.string = malloc(strlen(yytext)+1);

  strcpy(yylval.string, yytext);

  return IDENTIFIER;

  }

"+"    { return ADD; }

"-"    { return SUB; }

"*"    { return MULT; }

"/"    { return DIV; }

"("    { return LBRACE; }

")"    { return RBRACE; }

";"    { return SEMICOLON; }

"="    { return ASSIGN; }

 

  為了幫助調(diào)試,我們?cè)诔绦蜻\(yùn)行的末尾把所有已知的變量及其當(dāng)前內(nèi)容都打印了出來(lái)。

 

  使用普通錯(cuò)誤消息的例子

 

  使用下面的輸入(其中稍微進(jìn)行了排版)來(lái)編譯并運(yùn)行這個(gè)示例解析器程序 ccalc

 

  清單 6. 數(shù)學(xué)解析器的示例輸入

 

a = 3;

3 aa = a * 4;

b = aa / ( a - 3 );

 

  輸出結(jié)果如下所示:

 

  清單 7. 數(shù)學(xué)解析器的示例輸出

 

Error 'syntax error'

Error: reference to unknown variable 'aa'

division by zero!

final content of variables

  Name------------------ Value----------

  'a          ' 3

  'b          ' 3

  'aa         ' 0

 

  這個(gè)輸出結(jié)果并非非常有用,因?yàn)樗](méi)有顯示問(wèn)題到底在什么地方。這在下一節(jié)中會(huì)進(jìn)行介紹。

 

  擴(kuò)展 Bison 可以更好地處理錯(cuò)誤消息

 

  Bison 的最主要的特性在 Bison 手冊(cè)中隱藏的很深,就是它可以通過(guò)使用 YYERROR_VERBOSE 宏在產(chǎn)生語(yǔ)法錯(cuò)誤的情況下生成更有意義的錯(cuò)誤消息。

 

  普通的 'syntax error' 消息如下:

 

  Error 'syntax error, unexpected IDENTIFIER, expecting SEMICOLON'

 

  這條消息對(duì)于調(diào)試更為合適。

 

  更好的輸入函數(shù)

 

  使用原來(lái)的錯(cuò)誤消息,很難判斷語(yǔ)義的錯(cuò)誤。當(dāng)然,這個(gè)例子非常容易修復(fù),因?yàn)槲覀兞⒓淳涂梢哉页鲇绣e(cuò)誤的那一行。在更加復(fù)雜的語(yǔ)法和對(duì)應(yīng)輸入中,這可能并不簡(jiǎn)單。讓我們編寫一個(gè)輸入函數(shù)來(lái)從文件中讀取相應(yīng)的行。

 

  Flex 具有一個(gè)非常有用的宏 YY_INPUT,它負(fù)責(zé)為符號(hào)解釋讀入數(shù)據(jù)。我們可以在 YY_INPUT 宏中添加一個(gè)對(duì) GetNextChar() 函數(shù)的調(diào)用,后者從文件中讀取數(shù)據(jù),并保留了下一個(gè)要讀取的字符的位置信息。GetNextChar() 使用了一個(gè)緩沖區(qū)來(lái)存放一行輸入。這兩個(gè)變量保存了當(dāng)前行號(hào)和該行中下一個(gè)字符的位置:

 

  清單 8. 更好的 Flex YY_INPUT

 

#define YY_INPUT(buf,result,max_size) {

  result = GetNextChar(buf, max_size);

  if ( result <= 0 )

   result = YY_NULL;

  }

 

  使用這個(gè)增強(qiáng)的錯(cuò)誤打印函數(shù) PrintError()(在前面討論過(guò),它可以很好地顯示有問(wèn)題的輸入行,完整的 PrintError() 源代碼請(qǐng)參看 示例源代碼),我們就具有了一個(gè)用戶友好的消息,它顯示了下一個(gè)字符的位置:

 

  清單 9. 更好的 Flex 錯(cuò)誤:字符位置

 

    |....+....:....+....:....+....:....+....:....+....:....+

   1 |a = 3;

   2 |3 aa = a * 4;

...... !.....^

Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON

   3 |b = aa / ( a - 3 );

...... !.......^

Error: reference to unknown variable 'aa'

...... !.................^

Error: division by zero!

 

  這個(gè)示例函數(shù)可以從其他函數(shù)(例如 ReduceDiv())中進(jìn)行調(diào)用,從而打印語(yǔ)義錯(cuò)誤,例如 division by zero unknown identifiers

 

  如果我們希望標(biāo)記一下最后使用的符號(hào),就可以對(duì) Flex 規(guī)則進(jìn)行擴(kuò)展,并修改錯(cuò)誤的打印。函數(shù) BeginToken() PrintError()(二者都可以在示例源代碼中找到)是關(guān)鍵:BeginToken() 是由每條規(guī)則進(jìn)行調(diào)用的,這樣它就可以記住每個(gè)符號(hào)的開始和結(jié)束,每次打印錯(cuò)誤時(shí)都會(huì)調(diào)用 PrintError()。這樣,我們就可以生成一條有用的消息了,例如:

 

  清單 10. 更好的 Flex 錯(cuò)誤:表示確切的符號(hào)位置

 

   2 |3 aa = a * 4;

...... !..^^............

Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON

 

  缺點(diǎn)

 

  所生成的詞法解析器可能會(huì)在檢測(cè)到某個(gè)符號(hào)之前讀入多個(gè)字符。因此,這個(gè)過(guò)程不可能精確地顯示確切的位置。它最終取決于為 Flex 所提供的規(guī)則。規(guī)則越復(fù)雜,位置的精確程度就越低。這個(gè)例子中的規(guī)則可以由 Flex 通過(guò)提前查找一個(gè)字符來(lái)進(jìn)行處理,這會(huì)讓位置的預(yù)測(cè)更加精確。

 

  Bison 的定位機(jī)制

 

  下面讓我們來(lái)看一下 division by zero 這個(gè)錯(cuò)誤。最后一次符號(hào)讀取(結(jié)束括號(hào))并不是這個(gè)錯(cuò)誤的根源。表達(dá)式 (a-3) 的值就是 0。對(duì)于更好的錯(cuò)誤消息來(lái)說(shuō),我們需要知道表達(dá)式的位置。要實(shí)現(xiàn)這種功能,我們可以在 YYLTYPE 類型的全局變量 yylloc 中提供這個(gè)符號(hào)的確切位置。使用宏 YYLLOC_DEFAULT(請(qǐng)參看 Bison 文檔 中默認(rèn)的定義),Bison 可以計(jì)算出某個(gè)表達(dá)式的位置。

 

  記住,只有當(dāng)您在文法中使用位置時(shí)才會(huì)定義類型。這是一個(gè)常見(jiàn)的錯(cuò)誤。

 

  默認(rèn)的位置類型 YYLTYPE 如清單 11 所示。我們可以對(duì)這個(gè)類型重新進(jìn)行定義,使其包括更多信息,例如 Flex 所讀取的文件名。

 

  清單 11. 默認(rèn)位置類型 YYLTYPE

 

typedef struct YYLTYPE

{

 int first_line;

 int first_column;

 int last_line;

 int last_column;

} YYLTYPE;

 

  在上一節(jié)中,我們看到了 BeginToken() 函數(shù),它是在新符號(hào)開始時(shí)調(diào)用的。此時(shí)就應(yīng)該存儲(chǔ)這個(gè)位置了。在我們的例子中,一個(gè)符號(hào)不能跨越多行,因此 first_line last_line 是相同的,它們都保存了當(dāng)前的行號(hào)。其他屬性有符號(hào)的起點(diǎn)(first_column)和終點(diǎn)(last_column),這是通過(guò)符號(hào)的起點(diǎn)和長(zhǎng)度計(jì)算出來(lái)的。

 

  要使用這個(gè)位置,我們必須對(duì)規(guī)則處理函數(shù)進(jìn)行處理,如清單 12 所示。符號(hào) $3 的位置是通過(guò) @3 進(jìn)行引用的。為了防止拷貝這個(gè)規(guī)則中的整個(gè)結(jié)構(gòu),我們生成了一個(gè)指針 &@3。這看起來(lái)可能有點(diǎn)奇怪,但卻是正確的。

 

  清單 12. 記住規(guī)則中的位置

 

| expression DIV expression

 {

  $$ = ReduceDiv($1, $3, &@3);

 }

 

  在處理函數(shù)中,我們獲得了一個(gè)指向保存了位置信息的 YYLTYPE 結(jié)構(gòu)的指針,這樣可以生成一條很好的錯(cuò)誤消息。

 

  清單 13. ReduceDiv 中使用保存的位置

 

extern

double ReduceDiv(double a, double b, YYLTYPE *bloc) {

 if ( b == 0 ) {

  PrintError("division by zero! Line %d:c%d to %d:c%d",

            bloc->first_line, bloc->first_column,

            bloc->last_line, bloc->last_column);

  return MAXFLOAT;

 }

 return a / b;

}

 

  現(xiàn)在錯(cuò)誤消息可以幫助我們來(lái)定位問(wèn)題了。除零操作錯(cuò)誤在第 3 行的第 10 列到 18 列之間。

 

  清單 14. 更好的 ReduceDiv() 錯(cuò)誤消息

 

    |....+....:....+....:....+....:....+....:....+....:....+

   1 |a = 3;

   2 |3 aa = a * 4;

...... !..^^...........

Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON

   3 |b = aa / ( a - 3 );

...... !....^^...............

Error: reference to unknown variable 'aa'

...... !.................^..

Error: division by zero! Line 3:10 to 3:18

final content of variables

  Name------------------ Value----------

  'a          ' 3

  'b          ' 3.40282e+38

  'aa         ' 0

 

 

  結(jié)束語(yǔ)

 

  Flex Bison 是用來(lái)解析文法的一對(duì)功能強(qiáng)大的組合。通過(guò)使用本文中介紹的技巧,我們可以構(gòu)建更好的解釋器,它們可以生成像您自己喜歡的編譯器中一樣的有用的、容易理解的錯(cuò)誤消息。

 

 

posted on 2008-11-22 22:29 肥仔 閱讀(1238) 評(píng)論(0)  編輯 收藏 引用 所屬分類: LEX & YACC

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美www在线| 欧美日韩妖精视频| 91久久亚洲| 欧美黄色小视频| 欧美成人精品不卡视频在线观看| 久久国产精彩视频| 久久综合中文字幕| 亚洲国产精品久久久久婷婷老年 | 国产一区二区三区免费在线观看| 国产日韩一区二区三区| 在线电影院国产精品| 亚洲精品午夜| 亚洲天堂网在线观看| 美女啪啪无遮挡免费久久网站| 久久国内精品视频| 欧美成人一品| 亚洲一区二区三区777| 久久久午夜精品| 欧美日韩国产欧| 国内成人精品2018免费看| 99国内精品久久久久久久软件| 亚洲自拍三区| 亚洲风情亚aⅴ在线发布| 亚洲自拍偷拍麻豆| 欧美精品激情在线| 在线观看日韩av| 亚洲欧美韩国| 亚洲国产精品女人久久久| 欧美一区激情| 欧美日韩视频专区在线播放| 一区二区三区在线免费观看| 亚洲欧美电影在线观看| 欧美二区视频| 欧美在线高清| 国产精品毛片在线看| 日韩一级在线| 欧美黄色日本| 久久免费国产精品1| 国产日韩久久| 香蕉久久夜色精品国产使用方法| 亚洲国产欧美日韩精品| 久久久午夜精品| 精品91视频| 久久精品中文字幕一区二区三区| 这里是久久伊人| 欧美日韩亚洲一区在线观看| 99精品热视频| 91久久久久久久久久久久久| 久久久一区二区三区| 国产一区二区0| 欧美在线日韩在线| 亚洲在线播放| 国产区精品视频| 欧美影院在线播放| 亚洲男人影院| 国产一区二区精品| 久久福利一区| 欧美亚洲在线播放| 国模精品娜娜一二三区| 久久久久青草大香线综合精品| 午夜国产欧美理论在线播放 | 欧美日韩亚洲天堂| 在线视频一区二区| 一区二区精品在线观看| 国产精品扒开腿做爽爽爽软件| 亚洲一区二区动漫| 亚洲欧美国产视频| 国产欧美日韩精品丝袜高跟鞋| 欧美综合国产| 久久久久久穴| 久久精品91| 亚洲美女区一区| 国产精品白丝jk黑袜喷水| 欧美一级精品大片| 久久久精品网| 亚洲裸体视频| 午夜国产不卡在线观看视频| 激情五月综合色婷婷一区二区| 欧美二区乱c少妇| 欧美激情免费观看| 亚洲欧美日韩在线高清直播| 欧美在线免费| 亚洲精品美女| 亚洲欧美日韩综合aⅴ视频| 在线观看福利一区| 一本一本久久| 在线观看欧美| 亚洲一级二级在线| 在线国产亚洲欧美| 日韩视频第一页| 狠狠综合久久| av不卡在线观看| 亚洲国产黄色片| 亚洲一区尤物| 亚洲精品日韩在线观看| 亚洲欧美国产视频| 亚洲作爱视频| 久久久综合网| 欧美一级大片在线观看| 男女精品网站| 久久精品国产99国产精品| 欧美电影美腿模特1979在线看 | 午夜在线不卡| 欧美黄色免费| 久久综合一区二区| 欧美性大战久久久久久久| 麻豆成人小视频| 国产精品自拍小视频| 亚洲精品久久在线| 亚洲第一久久影院| 久久大综合网| 欧美一级二区| 国产精品狠色婷| 91久久精品国产91性色| 亚洲国产一区二区三区高清| 欧美亚洲日本一区| 午夜亚洲一区| 国产精品女主播一区二区三区| 亚洲高清久久| 亚洲国产日韩欧美| 久久午夜精品| 久久综合给合久久狠狠色| 国产精品午夜在线| 亚洲国产影院| 久久久国产精品一区| 久久精品视频一| 国产美女搞久久| 亚洲欧美日韩天堂一区二区| 亚洲免费视频一区二区| 欧美日韩三级| 中日韩在线视频| 亚洲欧美日韩第一区| 国产精品美女久久| 亚洲一区二区三区在线| 亚洲欧美影音先锋| 亚洲一二三区精品| 国产精品看片你懂得| 日韩视频永久免费观看| 一区二区三区鲁丝不卡| 欧美日韩免费一区二区三区| 亚洲精品欧美激情| 亚洲最黄网站| 国产精品xxxxx| 亚洲欧美日韩精品综合在线观看| 亚洲欧美日韩精品久久久| 国产精品嫩草99a| 午夜精品视频在线| 久久久久久自在自线| 伊人激情综合| 欧美成人精品高清在线播放| 亚洲精品乱码| 亚洲免费在线观看视频| 国产欧美一区二区三区久久人妖| 久久精品久久99精品久久| 欧美激情免费在线| 亚洲午夜av| 国产午夜精品久久久久久免费视| 久久精品欧美日韩精品| 欧美激情一区二区三区全黄| 亚洲天堂av在线免费| 国产日韩欧美一区二区三区在线观看| 欧美一区二区在线观看| 亚洲国产欧美不卡在线观看| 亚洲一区视频在线观看视频| 国产一区二区三区黄| 欧美高清一区| 欧美亚洲视频在线观看| 最新中文字幕一区二区三区| 欧美一区二区三区啪啪| 亚洲国产网站| 国产日韩欧美一二三区| 欧美成人精品一区二区三区| 亚洲婷婷在线| 亚洲国产成人精品视频| 欧美在线一级va免费观看| 亚洲精品一区在线| 国产亚洲亚洲| 欧美视频在线一区二区三区| 久久综合久色欧美综合狠狠| 亚洲性线免费观看视频成熟| 欧美激情欧美狂野欧美精品| 欧美影院成人| 亚洲一区二区三区激情| 亚洲国产乱码最新视频| 国产日韩视频一区二区三区| 欧美精品亚洲| 欧美一级大片在线观看| 亚洲精品久久久久久一区二区| 国产欧美日韩中文字幕在线| 欧美精选午夜久久久乱码6080| 久久国产精品久久久久久电车| 99国内精品久久久久久久软件| 免费毛片一区二区三区久久久| 欧美一级黄色录像| 亚洲一区二区三区四区中文| 亚洲韩国精品一区| 精品成人在线观看| 国产综合欧美在线看| 国产精品夜色7777狼人| 欧美性淫爽ww久久久久无|