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

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            flex詳解

            flex
             
            此篇不會講述規則表達式,自從.net流行之后,大量的原本只是在unix才使用的規則表達式現在廣泛使用在各種系統中。略.

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

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

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

            4).REJECT:  相當于拒絕此匹配,讓系統重新找下一個匹配。
            "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(): 讀取輸入流下一個字符

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


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

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

            4. flex的緩沖管理:
                flex
            本質上都是對緩沖輸入流進行yylex詞法分析. 緩沖是個結構體,每個緩沖有個緩沖輸入流指針,指向當前位置,各個被切換的緩沖互不相干擾,而相關yyin,yyrestart,yy_create_buffer,yy_scan_string系列函數都是操縱flex底層緩沖的.
                flex
            緩沖是一個結構體:   
            我們以下面的詞法規則為例子:(來自flex官方網站的注解)
                 /* 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
            就是一個緩沖。該lex文法使用到了<incl>,這個是狀態,見4節的flex的狀態管理.目前只需要知道它是個狀態即可.incl狀態下才進行[ \t]*的規則匹配.
                <<EOF>>
            見上面的描述,指某個輸入流到了末尾則到了這個狀態.

                BEGIN(INITIAL)類似于BEGIN(0),表示狀態從開頭解析(0表示不帶狀態的解析,也就說規則前沒有<>這個標記的狀態.


               
            上面的文法可以知道:
                a.
            在遇到include之后,跳到incl狀態。
                b.
            incl狀態中,跳過空白的字符,得到文件名(include file),先把當前的flexBuffer保存到數組棧,然后打開新的文件,并把flex的當前輸入流切換到剛打開的新文件的輸入流.
                c.
            切換到INITIAL狀態(沒有<>在規則前的默認的狀態)
                d.
            這里用到了幾個宏或者函數: yy_switch_to_buffer, yy_create_buffer,YY_CURRENT_BUFFER,yy_delete_buffer.
               
            這些函數看名字就應該知道其作用了。 
                   
            4. flex
            的狀態(Start conditions).
               
            上面的緩沖管理已經涉及到狀態管理了。flex的狀態管理相當于普通詞法的擴展。通過flex的狀態,大大擴充了詞法分析本身的功能。
               
            比如:
                 a.    <STRING>[^"]*        { /* eat up the string body ... */
                             ...
                             }
                
            表示在STRING狀態下才進行   [^"]*匹配。
                 b.      <INITIAL,STRING,QUOTE>\.        { /* handle an escape ... */
                             ...
                             }
                
            表示在INITIAL,STRING,QUOTE才匹配。\.  
                 flex
            的狀態怎么使用呢?
                 a.
            首先定義:%開頭(flex的申明本質上所有的都是以%開頭)定義,2: %s,%x,其中%s = %x+INITIAL,也就說是%s的狀態為%x定義的+INITIAL狀態
                 b.
            在規則域中,使用<狀態>規則,比如 comment是個狀態,則有 <comment>.\,其中.\是個lex規則文法,comment則就是一個狀態了.
                 c.
            有幾個特殊內置的狀態。INITIAL,*.比如: <*>規則,則表示這個規則在任何狀態下有效. <INITIAL>是個默認狀態。
                 d.
            某個規則可以支持多個狀態,使用隔開。比如<INITIAL,STRING,QUOTE>規則.如果和<<EOF>>重用一個規則的話,則是<quote><<EOF>>
                 e.flex
            還提供了一套相關函數:
                 yy_push_state, yy_pop_state, yy_top_state, BEGIN()    
                
            可以說有了狀態的支持,flex的功能更加強大了,簡單的文法分析甚至可以不借助于yacc/bison來做了。
                
               
            一個完整的例子:
                 %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++
            的支持
               
            編譯時,使用flex -+ 文件,就可以得到.cc的文件,而且flex也會生成C++相關類,對應的類和方法有:
                FlexLexer:
            成員方法有:
                    a. yylex(), YYText(), YYLeng(),lineno(), set_debug(),debug(),
                    b.
            構造函數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 肥仔 閱讀(8137) 評論(2)  編輯 收藏 引用 所屬分類: LEX & YACC

            評論

            # re: flex詳解  回復  更多評論   

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

            # re: flex詳解  回復  更多評論   

            從各種意義上來看flex不僅僅是type 3 grammar,
            http://www.uggeinkaufenboots.com/
            2010-10-26 17:09 | ugg boots buy
            久久久久久A亚洲欧洲AV冫| 伊人久久精品线影院| 国产精品亚洲美女久久久| 久久久久久久综合日本| 亚洲国产成人久久精品影视| 91精品国产91久久久久福利| 欧美性大战久久久久久| 久久香蕉国产线看观看精品yw| 国产精品久久久久乳精品爆| 999久久久国产精品| 久久亚洲视频| 超级碰久久免费公开视频| 国产巨作麻豆欧美亚洲综合久久| 色综合久久天天综合| 亚洲AV日韩AV天堂久久| 久久精品亚洲福利| 伊人久久大香线蕉精品不卡| 曰曰摸天天摸人人看久久久| 国产精品热久久毛片| 久久精品国产亚洲αv忘忧草| 91精品国产91久久久久久| 久久se精品一区二区影院| 韩国无遮挡三级久久| 久久久久久毛片免费播放| 久久精品中文无码资源站| 2020久久精品国产免费| 国产精品欧美久久久久无广告| 一本色道久久综合狠狠躁篇| 久久综合给合久久国产免费| 超级碰久久免费公开视频| 18禁黄久久久AAA片| 狠狠色丁香婷婷久久综合| 91精品国产综合久久婷婷| 久久天天日天天操综合伊人av| 久久综合给合久久狠狠狠97色69| 国产高潮国产高潮久久久91 | 欧美噜噜久久久XXX| 久久免费国产精品| 日本道色综合久久影院| 亚洲愉拍99热成人精品热久久| 99久久无色码中文字幕人妻|