• <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
            數據加載中……

            yacc / lex 在linux 下 使用指南

                Lex 和 Yacc 是 Unix 和Linux 下詞法和語法的分析,解析工具,有了這兩個工具,你可以自己制作想要的編譯器,也可以重新制作已有程序語言的解析器。需要注意的是linux下的這兩個工具生成的程序源碼只能是C和C++語言,當然現在早已有類似可以生成Java源碼的語法分析器,如較常用的JavaCC(Java Compiler Compiler),相關內容可以去網上搜索。Lex和Yacc已被移植到windows下,現在常用的工具有Parser Generator。本文只介紹Linux 下Lex和Yacc的使用方法。


            Lex介紹

            Lex 通過對.lex或.l文件定義的格式生成一個C語言源碼文件,通過編譯這個源碼,就生成了.lex文件或.l文件定義的編譯器。.lex或.l文件的格式分三段:

            1.全局變量聲明部分
            2.詞法規則部分
            3.函數定義部分

            以下是一個簡單的例子:lex_example.l文件

            %{            //全局聲明部分
            /*林木100 linux
            www.linmu100.com
            */
            #include <stdio.h>  

            extern char *yytext;
            extern FILE *yyin;
            int sem_count = 0;

            %}

            //規則定義部分,
            %%
            [a-zA-Z][a-zA-Z0-9]*    {printf("WORD[%s] ", yytext);}
            [a-zA-Z0-9\/.-]+        printf("FILENAME ");
            \"                      printf("QUOTE ");
            \{                      printf("OBRACE ");
            \}                      printf("EBRACE ");
            ;                       {sem_count++; printf("SEMICOLON ");}
            \n                      printf("\n");
            [ \t]+                  /* ignore whitespace */;
            %%

            //以下為函數定義部分
            int main(int avgs, char *avgr[]) 
            {
                yyin = fopen(avgr[1], "r");
                if (!yyin)
                {
                    return 0;
                }
                yylex();
                printf("sem_count : %d\n", sem_count);
                fclose(yyin);

                return 1;
            }

            Lex 常用格式如下表,常規表達式:

            字符

            含義

            A-Z, 0-9, a-z

            構成了部分模式的字符和數字。

            .

            匹配任意字符,除了 \n。

            -

            用來指定范圍。例如:A-Z 指從 A 到 Z 之間的所有字符。

            [ ]

            一個字符集合。匹配括號內的任意 字符。如果第一個字符是 ^ 那么它表示否定模式。例如: [abC] 匹配 a, b, 和 C中的任何一個。

            *

            匹配0個或者多個上述的模式。

            +

            匹配1個或者多個上述模式。

            ?

            匹配0個或1個上述模式。

            $

            作為模式的最后一個字符匹配一行的結尾。

            { }

            指出一個模式可能出現的次數。 例如: A{1,3} 表示 A 可能出現1次或3次。

            \

            用來轉義元字符。同樣用來覆蓋字符在此表中定義的特殊意義,只取字符的本意。

            ^

            否定。

            |

            表達式間的邏輯或。

            "<一些符號>"

            字符的字面含義。元字符具有。

            /

            向前匹配。如果在匹配的模版中的“/”后跟有后續表達式,只匹配模版中“/”前面的部分。如:如果輸入 A01,那么在模版 A0/1 中的 A0 是匹配的。

            ( )

            將一系列常規表達式分組。


            常規表達式舉例

            常規表達式

            含義

            joke[rs]

            匹配 jokes 或 joker。

            A{1,2}shis+

            匹配 AAshis, Ashis, AAshi, Ashi。

            (A[b-e])+

            匹配在 A 出現位置后跟隨的從 b 到 e 的所有字符中的 0 個或 1個。



            使用lex掃描上述舉例文件 lex_example.l:
            lex lex_example.l
            缺省會生成lex.yy.c文件,然后用gcc編譯這個文件,注意要有-ll選項:
            gcc lex.yy.c -o analyse -ll
            這樣就生成了一個簡單的詞法分析器analyse,假設有文件demo,其內容如下所示:
            firstword;
            secondword;
            thirdword

            fourthword{
            fifthword
            }
            輸入命令:
            ./analyse demo
            會有如下顯示:
            WORD[firstword] SEMICOLON 
            WORD[secondword] SEMICOLON 
            WORD[thirdword] 

            WORD[fourthword] OBRACE 
            WORD[fifthword] 
            EBRACE 
            sem_count : 2

            實際上,對于上述lex_example.l文件,函數定義部分可以完全省略,因為lex會自動為你生成main函數。這時仍然按上述方法生成analyse,輸入命令:
            ./analse < demo
            結果如下:
            WORD[firstword] SEMICOLON 
            WORD[secondword] SEMICOLON 
            WORD[thirdword] 

            WORD[fourthword] OBRACE 
            WORD[fifthword] 
            EBRACE 


            在上述lex_example.l文件中我們還使用了兩個變量:
            extern char *yytext;
            extern FILE *yyin;
            這兩個變量是lex提供的外部借口,用戶可以根據自己需要自己更改,lex提供了以下接口:

            Lex 變量

            yyin

            FILE* 類型。 它指向 lexer 正在解析的當前文件。

            yyout

            FILE* 類型。 它指向記錄 lexer 輸出的位置。 缺省情況下,yyin 和 yyout 都指向標準輸入和輸出。

            yytext

            匹配模式的文本存儲在這一變量中(char*)。

            yyleng

            給出匹配模式的長度。

            yylineno

            提供當前的行數信息。(lexer不一定支持。)

            Lex 函數

            yylex()

            這一函數開始分析。 它由 Lex 自動生成。

            yywrap()

            這 一函數在文件(或輸入)的末尾調用。如果函數的返回值是1,就停止解析。 因此它可以用來解析多個文件。代碼可以寫在第三段,這就能夠解析多個文件。 方法是使用 yyin 文件指針(見上表)指向不同的文件,直到所有的文件都被解析。最后,yywrap() 可以返回 1 來表示解析的結束。

            yyless(int n)

            這一函數可以用來送回除了前憂? 個字符外的所有讀出標記。

            yymore()

            這一函數告訴 Lexer 將下一個標記附加到當前標記后。

            以下是一個計算字符個數的.l文件內容,有興趣的朋友可以編譯試試
            %{ 
            /*
            林木100 linux
            www.linmu100.com
            */
            int wc = 0;        /* word count */ 
            %} 
             
            %% 
            [a-zA-Z]+    { wc++; } 
            \n|.        { /* gobble up */ } 
            %% 
            int main(void) 

                int n = yylex(); 
                return n; 

             
            int yywrap(void) 

                printf("word count: %d\n", wc); 
                return 1; 
            }

            yacc介紹

            Yacc 是 Yet Another Compiler Compiler的縮寫。 Yacc 的 GNU 版叫做 Bison。它是一種語法解析工具。它用巴科斯范式(BNF, Backus Naur Form)來書寫。按照慣例,Yacc 文件有 .y 后綴。
            實際上,yacc才是真正分析語法的核心,.y文件格式和.l文件一樣分三段,但每一段的意義有所不同:
            1.全局變量聲明,終結符號(終端符號)聲明
            2.語法定義
            3.函數定義

            以下是一個簡單的yacc_example.y文件,定義了一個簡單的計算器:
            %{ 
            //全局變量聲明 
            #include <ctype.h> 
            #include <stdio.h> 
            #define YYSTYPE double /*double type for YACC stack; for yylval*/ 
             
            /*林木100 www.linmu100.com */ 
             
            void yyerror(const char *str) 

                fprintf(stderr, "error:%s\n", str ); 

            %} 
            //終結符聲明 
            %token NUMBER 
             
            %% 
            lines    : lines expr '\n'            { printf("%g\n", $2); } 
                    | lines '\n' 
                    | /* e */ 
                    | error '\n'                { yyerror("reenter last line:"); /*yyerrok(); */} 
                    ; 
             
            expr    : expr '+' term                { $$ = $1 + $3; } 
                    | expr '-' term                { $$ = $1 - $3; } 
                    | term 
                    ; 
             
            term    : term '*' factor            { $$ = $1 * $3; } 
                    | term '/' factor            { $$ = $1 / $3; } 
                    | factor 
                    ; 
             
            factor    : '(' expr ')'                { $$ = $2; } 
                    | '(' expr error            { $$ = $2; yyerror("missing ')'"); /*yyerrok(); */} 
                    | '-' factor                { $$ = -$2; } 
                    | NUMBER 
                    ; 
             
            %% 
            //以上部分為語法定義,以下部分為函數定義 
            int main(void) 

                return yyparse(); 

             
            int yylex(void) 

                int c; 
                while ((c = getchar()) == ' '); 
                if (c == '.' || isdigit(c)) { 
                    ungetc(c, stdin); 
                    scanf("%lf", &yylval); 
                    return NUMBER; 
                } 
                return c; 


            使用yacc掃描這個文件:
            yacc yacc_example.y
            缺省會生成一個y.tab.c文件,然后用gcc編譯這個文件,注意要有選項 -ll 或 -ly:
            gcc y.tab.c -o analyse -ll
            運行./analyse:結果如下圖所示:
            clip_image001

            現在對照yacc_example.y文件講解一下.y文件的規則:
            1.在全局變量聲明部分,聲明了一個接口函數yyerror,這個函數是用來在出錯時調用的。這一段主要是聲明一些變量,數據結構,函數用。
            2.%token NUMBER則聲明了一個終端符(終結符),這個符號是由Lex返回的,會在yacc語法規則中用到。
            3.語法規則部分則聲明了語法:
                3.1語法規則對外只有一個接口,這一點要注意,初學者常常會犯語法對外有多個接口的錯誤。
                3.2無論是lex文件還是yacc文件都要注意最大可能性的詞法和語法規則要放在沖突規則的前面,這樣保證了最大可能規則會被最先匹配,比如lex文件中:
                   temperator      return T1;
                   temp             return T2;
                    在yacc文件中,例子如下
                        command:
                            NUMBER CHAR
                            |   NUMBER
                           ;

            對于.y文件還要注意全局語法,以及遞歸的調用。

            初學者對于yacc文件規則可能會較為生疏,關鍵還要多做一些練習。


            Lex 和 Yacc 的結合

            lex和yacc結合時需要注意的是
            lex文件頭要引用yacc生成的頭文件:"y.tab.h"

            以下是一個lex和yacc結合的實例:
            lex_yacc_exp.l文件:
            %{
            /*林木100
            www.linmu100.com
            */
            #include <stdio.h>
            #include <string.h>
            #include "y.tab.h"
            extern char *yytext;
            %}
            %%
            [0-9]+                  yylval.number=atoi(yytext); return NUMBER;
            heater            return TOKHEATER;
            heat                    return TOKHEAT;
            on|off                  yylval.number=!strcmp(yytext,"on"); return STATE;
            target                  return TOKTARGET;
            temperature             return TOKTEMPERATURE;
            [a-z0-9]+        yylval.string=strdup(yytext);return WORD;
            \n                      /* ignore end of line */;
            [ \t]+                  /* ignore whitespace */;
            %%

            lex_yacc_exp.y文件:
            %{
            /*林木100
            www.linmu100.com
            */
            #include <stdio.h>
            #include <string.h>

            void yyerror(const char *str)
            {
                fprintf(stderr,"error: %s\n",str);
            }

            int yywrap()
            {
                return 1;
            }

            main()
            {
                yyparse();
            }

            char *heater="xl's test";

            %}

            %token TOKHEATER TOKHEAT TOKTARGET TOKTEMPERATURE

            %union 
            {
                int number;
                char *string;
            }

            %token <number> STATE
            %token <number> NUMBER
            %token <string> WORD

            %%

            commands:
                | commands command
                ;


            command:
                heat_switch | target_set | heater_select

            heat_switch:
                TOKHEAT STATE 
                {
                    if($2)
                        printf("\tHeater '%s' turned on\n", heater);
                    else
                        printf("\tHeat '%s' turned off\n", heater);
                }
                ;

            target_set:
                TOKTARGET TOKTEMPERATURE NUMBER
                {
                    printf("\tHeater '%s' temperature set to %d\n",heater, $3);
                }
                ;

            heater_select:
                TOKHEATER WORD
                {
                    printf("\tSelected heater '%s'\n",$2);
                    heater=$2;
                }
                ;

            輸入以下命令,分別生成lex.yy.c,y.tab.c,y.tab.h三個文件:
            lex lex_yacc_exp.l
            yacc -d lex_yacc_exp.y
            gcc lex.yy.c y.tab.c -o analyse -ll

            創建一個語法用例demo,內容如下:
            heat on
            target temperature 99
            heater asdfsieiwef99adsf

            輸入./analyse <demo分析demo文件,會得到以下結果:
            clip_image002 


            結語:
            Lex 和 Yacc 是很強大的工具,這里只簡單介紹了一些入門知識。
            The Lex & Yacc Page 中有很多有趣的歷史參考,以及 非常好的 lex 和 yacc 文檔。 

            參考文檔:
            http://www.ibm.com/developerworks/cn/linux/l-lexyac.html
            http://blog.csdn.net/ThinkinginLinux/archive/2005/03/19/323379.aspx

            /
            /*-----Lex & Yacc ----www.linmu100.com ----*/
            /
            /*-----linux工具,Lex & Yacc,基本操作----*/
            /
            /*-----linux配置,UNIX,開源軟件,linux技術,makefile----*/
            /
            /*----------------------@xiaolin--------------------*/
            /

             

            posted on 2008-09-19 18:01 肥仔 閱讀(2029) 評論(0)  編輯 收藏 引用 所屬分類: LEX & YACC

            久久久综合香蕉尹人综合网| 久久综合亚洲色HEZYO社区 | 精品国产VA久久久久久久冰| 亚洲性久久久影院| 亚洲色大成网站www久久九| 三上悠亚久久精品| 一本一道久久综合狠狠老 | 国产成人精品久久| 99久久国产综合精品麻豆| 中文字幕亚洲综合久久2| 噜噜噜色噜噜噜久久| 99久久免费国产特黄| 日本精品一区二区久久久| 国产成人久久精品激情| 最新久久免费视频| 国产ww久久久久久久久久| 77777亚洲午夜久久多喷| 精品久久人人爽天天玩人人妻| 久久伊人色| 久久综合九色综合欧美狠狠| 国产69精品久久久久APP下载| 久久综合久久自在自线精品自 | 日韩AV无码久久一区二区| 精品久久久久久| 无码日韩人妻精品久久蜜桃| 香蕉久久夜色精品国产尤物| 久久中文娱乐网| 久久国产高清字幕中文| 久久亚洲精品无码AV红樱桃| 少妇久久久久久被弄到高潮 | 精品一二三区久久aaa片| 亚洲国产精久久久久久久| 久久精品九九亚洲精品| 怡红院日本一道日本久久 | 国内精品久久久久久久97牛牛| 久久人人爽人人爽人人片AV东京热| 国产精品一区二区久久不卡| 99精品久久精品一区二区| 麻豆av久久av盛宴av| 久久综合亚洲色一区二区三区| 一级做a爰片久久毛片毛片|