• <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>

            woaidongmao

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

            flex詳解

            flex
             
            此篇不會(huì)講述規(guī)則表達(dá)式,自從.net流行之后,大量的原本只是在unix才使用的規(guī)則表達(dá)式現(xiàn)在廣泛使用在各種系統(tǒng)中。略.

            1.內(nèi)置變量
              yy_create_buffer:
            見后面的緩沖管理
              yy_delete_buffer:
            見后面的緩沖管理
              yy_flex_debug:
            見后面的緩沖管理
              yy_init_buffer:
            見后面的緩沖管理
              yy_flush_buffer:
            見后面的緩沖管理
              yy_load_buffer_state:
            見后面的緩沖管理
              yy_switch_to_buffer:
            見后面的緩沖管理
             
              yyin:
            輸入緩沖流的文件指針,可以被替換以實(shí)現(xiàn)解析某個(gè)自定義的文件
              yyleng:
            當(dāng)前匹配字串的長度
              yylex:
            解析函數(shù),接口
              yylineno:
            當(dāng)前匹配的文件行號(hào)
              yyout:  
            輸出流的指針
              yyrestart:
            手動(dòng)調(diào)用yyrestart.會(huì)重啟解析
                        yyrestart( yyin );
            一般是打開某個(gè)文件之后,yyrestart(yyin)再解析.
              yytext
            : 當(dāng)前匹配的字串
              yywrap
            : 解析一個(gè)文件完畢之后,會(huì)調(diào)用yywrap:返回1表示結(jié)束,0表示繼續(xù)(此時(shí)最好重新打開yyin或者重置yyin)

            2. 幾個(gè)重要函數(shù):
            1). yymore(): yymore()
            的含義是,當(dāng)當(dāng)前匹配的字串之后,想把后面配置的字串附加到這個(gè)字串后面,組成新的token返回.
             
            比如:
                        %%
                      mega-    ECHO; yymore();
                      kludge   ECHO;
             
            如果:“mega-kludge" the following will write "mega-mega-kludge" to the output
             
            為什么呢? 首先遇到 mega-,接著被more了一下,因此就會(huì)把kludga附加到mega-后面,而后面的kludge的動(dòng)作又是打印,因此會(huì)打印出:mega-mega-kludge

            2). yyless(): yyless()的含義是:當(dāng)當(dāng)前的匹配之后,我想只返回前面幾個(gè)字符,并且把后面回退到輸入
             
            比如:
                      %%
                      foobar    ECHO; yyless(3);
                      [a-z]+    ECHO;
                    input "foobar" the following will write out     "foobarbar":
              
            為什么呢? foobar輸入之后,匹配foobar,ECHO打印出來,接著yyless(3),則輸入流變?yōu)?span lang="EN-US">bar
            (yytextfoo).接著再匹配,于是匹配    [a-z]+,因此再次打印出bar.
              
            3).BEGIN: flex
            下一個(gè)起始解析狀態(tài)。見第3節(jié),flex的狀態(tài).

            4).REJECT:  相當(dāng)于拒絕此匹配,讓系統(tǒng)重新找下一個(gè)匹配。
            "abcd", it
                 will write "abcdabcaba" to the output:

                      %%
                      a        |
                      ab       |
                      abc      |
                      abcd     ECHO; REJECT;
                      .|\n     /* eat up any unmatched character */  
                    
            5).unput(c):
            c重新放到輸入流。

            6).input(): 讀取輸入流下一個(gè)字符

            7).yyrestart(): 該函數(shù)迫使yylex重新解析。yyrestart有個(gè)函數(shù)指針流,可以再打開之后,重新使用yyrestart().


            3.
            解析源管理:
                1).
            默認(rèn)是從yyin獲取,而yyin則是stdout,也可以是其它文件。
                    if ( ! yyin )
                     yyin = stdin;
                   
                    if ( ! yyout )
                     yyout = stdout;
               
                2).
            如果你打開了一個(gè)文件,并把yyin指向此文件,則從該文件中讀取.比如:
               
            main中:
                 FILE* fp = NULL;
                 fp = fopen("hell.txt", "r");
                 yyin = fp;
                
            之后再使用 yylex()
               
            flexhell.txt中讀取信息并解析.
               
                3).
            從字符串中解析
                   
            先使用下列函數(shù),轉(zhuǎn)化緩沖,之后再使用 yylex()
                   a. yy_scan_string(char*).
            使用了yy_scan_string(char*)之后,flex會(huì)把char*放到yy的輸入緩沖中(會(huì)調(diào)用到yy_switch_to_buffer.)
                   b. yy_scan_bytes(const char *base, int len);
                   c. yy_scan_buffer(char *base, yy_size_t size)
                  
            這幾個(gè)函數(shù)內(nèi)部都使用的是緩沖切換的創(chuàng)建等函數(shù),見后面的章節(jié).

                4).利用EOF內(nèi)置規(guī)則,重新打開多個(gè)文件輸入:  
               
            比如:
                 <<EOF>>  {
                      if ( *++filelist )
                          yyin = fopen( *filelist, "r" );
                      else
                         yyterminate();
                      }
                5).
            多緩沖問題:
                    a.
            此問題可以按上面的 <<EOF>>或者 yywrap解決。
                    b.
            另外一種形式,比如:#include <iostream>或者類似于這種,這種形式的話,則不能使用yywrap<<EOF>>來解決了。
                      
            這就需要用到在flex動(dòng)作中手動(dòng)切換緩沖。flex對(duì)每個(gè)緩沖有個(gè)緩沖輸入流指針,指向當(dāng)前位置,各個(gè)被切換的緩沖互不相干擾,這恰好很好地解決了文件包含另外一個(gè)文件,而子文件也許要yylex的這種場(chǎng)合.
                      
            這就需要使用到flex底層的緩沖管理了.見下節(jié)
               

            4. flex的緩沖管理:
                flex
            本質(zhì)上都是對(duì)緩沖輸入流進(jìn)行yylex詞法分析. 緩沖是個(gè)結(jié)構(gòu)體,每個(gè)緩沖有個(gè)緩沖輸入流指針,指向當(dāng)前位置,各個(gè)被切換的緩沖互不相干擾,而相關(guān)yyin,yyrestart,yy_create_buffer,yy_scan_string系列函數(shù)都是操縱flex底層緩沖的.
                flex
            緩沖是一個(gè)結(jié)構(gòu)體:   
            我們以下面的詞法規(guī)則為例子:(來自flex官方網(wǎng)站的注解)
                 /* the "incl" state is used for picking up the name
                  * of an include file
                  */
                 %x incl
                
                 %{
                 #define MAX_INCLUDE_DEPTH 10
                 YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
                 int include_stack_ptr = 0;
                 %}
                
                 %%
                 include             BEGIN(incl);
                
                 [a-z]+              ECHO;
                 [^a-z\n]*\n?        ECHO;
                
                 <incl>[ \t]*      /* eat the whitespace */
                 <incl>[^ \t\n]+   { /* got the include file name */
                         if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
                             {
                             fprintf( stderr, "Includes nested too deeply" );
                             exit( 1 );
                             }
                
                         include_stack[include_stack_ptr++] =
                             YY_CURRENT_BUFFER;
                
                         yyin = fopen( yytext, "r" );
                
                         if ( ! yyin )
                             error( ... );
                
                         yy_switch_to_buffer(
                             yy_create_buffer( yyin, YY_BUF_SIZE ) );
                
                         BEGIN(INITIAL);
                         }
                
                 <<EOF>> {
                         if ( --include_stack_ptr < 0 )
                             {
                             yyterminate();
                             }
                
                         else
                             {
                             yy_delete_buffer( YY_CURRENT_BUFFER );
                             yy_switch_to_buffer(
                                  include_stack[include_stack_ptr] );
                             }
                         }   
                YY_BUFFER_STATE
            就是一個(gè)緩沖。該lex文法使用到了<incl>,這個(gè)是狀態(tài),見4節(jié)的flex的狀態(tài)管理.目前只需要知道它是個(gè)狀態(tài)即可.incl狀態(tài)下才進(jìn)行[ \t]*的規(guī)則匹配.
                <<EOF>>
            見上面的描述,指某個(gè)輸入流到了末尾則到了這個(gè)狀態(tài).

                BEGIN(INITIAL)類似于BEGIN(0),表示狀態(tài)從開頭解析(0表示不帶狀態(tài)的解析,也就說規(guī)則前沒有<>這個(gè)標(biāo)記的狀態(tài).


               
            上面的文法可以知道:
                a.
            在遇到include之后,跳到incl狀態(tài)。
                b.
            incl狀態(tài)中,跳過空白的字符,得到文件名(include file),先把當(dāng)前的flexBuffer保存到數(shù)組棧,然后打開新的文件,并把flex的當(dāng)前輸入流切換到剛打開的新文件的輸入流.
                c.
            切換到INITIAL狀態(tài)(沒有<>在規(guī)則前的默認(rèn)的狀態(tài))
                d.
            這里用到了幾個(gè)宏或者函數(shù): yy_switch_to_buffer, yy_create_bufferYY_CURRENT_BUFFERyy_delete_buffer.
               
            這些函數(shù)看名字就應(yīng)該知道其作用了。 
                   
            4. flex
            的狀態(tài)(Start conditions).
               
            上面的緩沖管理已經(jīng)涉及到狀態(tài)管理了。flex的狀態(tài)管理相當(dāng)于普通詞法的擴(kuò)展。通過flex的狀態(tài),大大擴(kuò)充了詞法分析本身的功能。
               
            比如:
                 a.    <STRING>[^"]*        { /* eat up the string body ... */
                             ...
                             }
                
            表示在STRING狀態(tài)下才進(jìn)行   [^"]*匹配。
                 b.      <INITIAL,STRING,QUOTE>\.        { /* handle an escape ... */
                             ...
                             }
                
            表示在INITIAL,STRING,QUOTE才匹配。\.  
                 flex
            的狀態(tài)怎么使用呢?
                 a.
            首先定義:%開頭(flex的申明本質(zhì)上所有的都是以%開頭)定義,2: %s,%x,其中%s = %x+INITIAL,也就說是%s的狀態(tài)為%x定義的+INITIAL狀態(tài)
                 b.
            在規(guī)則域中,使用<狀態(tài)>規(guī)則,比如 comment是個(gè)狀態(tài),則有 <comment>.\,其中.\是個(gè)lex規(guī)則文法,comment則就是一個(gè)狀態(tài)了.
                 c.
            有幾個(gè)特殊內(nèi)置的狀態(tài)。INITIAL,*.比如: <*>規(guī)則,則表示這個(gè)規(guī)則在任何狀態(tài)下有效. <INITIAL>是個(gè)默認(rèn)狀態(tài)。
                 d.
            某個(gè)規(guī)則可以支持多個(gè)狀態(tài),使用隔開。比如<INITIAL,STRING,QUOTE>規(guī)則.如果和<<EOF>>重用一個(gè)規(guī)則的話,則是<quote><<EOF>>
                 e.flex
            還提供了一套相關(guān)函數(shù):
                 yy_push_state, yy_pop_state, yy_top_state, BEGIN()    
                
            可以說有了狀態(tài)的支持,flex的功能更加強(qiáng)大了,簡(jiǎn)單的文法分析甚至可以不借助于yacc/bison來做了。
                
               
            一個(gè)完整的例子:
                 %x str
                
                 %%
                         char string_buf[MAX_STR_CONST];
                         char *string_buf_ptr;
                
                 \"      string_buf_ptr = string_buf; BEGIN(str);
                
                 <str>\"        { /* saw closing quote - all done */
                         BEGIN(INITIAL);
                         *string_buf_ptr = '\0';
                         /* return string constant token type and
                          * value to parser
                          */
                         }
                
                 <str>\n        {
                         /* error - unterminated string constant */
                         /* generate error message */
                         }
                
                 <str>\\[0-7]{1,3} {
                         /* octal escape sequence */
                         int result;
                
                         (void) sscanf( yytext + 1, "%o", &result );
                
                         if ( result > 0xff )
                                 /* error, constant is out-of-bounds */
                
                         *string_buf_ptr++ = result;
                         }
                
                 <str>\\[0-9]+ {
                         /* generate error - bad escape sequence; something
                          * like '\48' or '\0777777'
                          */
                         }
                
                 <str>\\n  *string_buf_ptr++ = '\n';
                 <str>\\t  *string_buf_ptr++ = '\t';
                 <str>\\r  *string_buf_ptr++ = '\r';
                 <str>\\b  *string_buf_ptr++ = '\b';
                 <str>\\f  *string_buf_ptr++ = '\f';
                
                 <str>\\(.|\n)  *string_buf_ptr++ = yytext[1];
                
                 <str>[^\\\n\"]+        {
                         char *yptr = yytext;
                
                         while ( *yptr )
                                 *string_buf_ptr++ = *yptr++;
                         }
               
               
            5. flex C++
            的支持
               
            編譯時(shí),使用flex -+ 文件,就可以得到.cc的文件,而且flex也會(huì)生成C++相關(guān)類,對(duì)應(yīng)的類和方法有:
                FlexLexer:
            成員方法有:
                    a. yylex(), YYText(), YYLeng(),lineno(), set_debug(),debug(),
                    b.
            構(gòu)造函數(shù)yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
                    c.
            緩沖:switch_streams(istream* new_in = 0, ostream* new_out = 0),yylex( istream* new_in = 0, ostream* new_out = 0 )
                   
                   
            等等。
              
            例子:
                     // An example of using the flex C++ scanner class.
                
                 %{
                 int mylineno = 0;
                 %}
                
                 string  \"[^\n"]+\"
                
                 ws      [ \t]+
                
                 alpha   [A-Za-z]
                 dig     [0-9]
                 name    ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
                 num1    [-+]?{dig}+\.?([eE][-+]?{dig}+)?
                 num2    [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
                 number  {num1}|{num2}
                
                 %%
                
                 {ws}    /* skip blanks and tabs */
                
                 "/*"    {
                         int c;
                
                         while((c = yyinput()) != 0)
                             {
                             if(c == '\n')
                                 ++mylineno;
                
                             else if(c == '*')
                                 {
                                 if((c = yyinput()) == '/')
                                     break;
                                 else
                                     unput(c);
                                 }
                             }
                         }
                
                 {number}  cout << "number " << YYText() << '\n';
                
                 \n        mylineno++;
                
                 {name}    cout << "name " << YYText() << '\n';
                
                 {string}  cout << "string " << YYText() << '\n';
                
                 %%
                
                 Version 2.5               December 1994                      
                
                 int main( int /* argc */, char** /* argv */ )
                     {
                     FlexLexer* lexer = new yyFlexLexer;
                     while(lexer->yylex() != 0)
                         ;
                     return 0;
                     }    

            posted on 2008-11-23 00:54 肥仔 閱讀(8166) 評(píng)論(2)  編輯 收藏 引用 所屬分類: LEX & YACC

            評(píng)論

            # re: flex詳解  回復(fù)  更多評(píng)論   

            flex也就是幫你詞法之后將剩下的事情全部丟給你了。因?yàn)椤笆O碌氖虑椤庇玫氖荂/C++,所以從各種意義上來看flex不僅僅是type 3 grammar,但是這是借助其他工具完成的,譬如說C/C++。
            2008-11-23 16:31 | 陳梓瀚(vczh)

            # re: flex詳解  回復(fù)  更多評(píng)論   

            從各種意義上來看flex不僅僅是type 3 grammar,
            http://www.uggeinkaufenboots.com/
            2010-10-26 17:09 | ugg boots buy
            久久精品嫩草影院| 久久精品国产亚洲AV香蕉| 久久久久久久久久久免费精品| 国产免费久久精品99久久| 国产成人香蕉久久久久| 久久人人爽人人爽人人片AV麻豆 | 久久国产精品一区| 久久婷婷色香五月综合激情| 国产午夜免费高清久久影院| 欧美精品一区二区久久| 99久久久精品免费观看国产 | 久久www免费人成看国产片| 久久久久这里只有精品| 久久久久久久久波多野高潮| 香蕉久久一区二区不卡无毒影院| 久久AⅤ人妻少妇嫩草影院| 久久夜色精品国产噜噜亚洲AV| 国产精品欧美亚洲韩国日本久久| 久久精品成人欧美大片| 成人午夜精品久久久久久久小说| 久久久国产打桩机| 99久久国产免费福利| 久久国产精品99国产精| 伊人色综合久久天天人守人婷 | 久久综合噜噜激激的五月天| 久久久久99这里有精品10| 国内精品久久久久久久亚洲 | 国产亚洲精午夜久久久久久| 欧美精品一区二区精品久久| 99久久精品午夜一区二区| 亚洲av伊人久久综合密臀性色| 亚洲国产精品无码久久久久久曰| 久久精品国产99久久香蕉| 久久精品视频网| 久久综合九色综合97_久久久| 狠狠色婷婷综合天天久久丁香 | 新狼窝色AV性久久久久久| 婷婷久久香蕉五月综合加勒比| 一本色道久久综合亚洲精品| 亚洲va久久久噜噜噜久久狠狠| 久久精品国产网红主播|