flex學習筆記

flex學習筆記
一、flex的安裝和使用(系統Ubuntu14.04)
$ sudo apt-get install flex
二、編譯
flex代碼的源文件每每是以.l爲後綴名的。 
.l文件經過如下命令編譯(以文件名爲scanner.l爲例):
$ flex scanner.l
編譯後在源代碼相同目錄下會生成一個lex.yy.c,這就是生成的可以執行上述scanner.l功能的c語言代碼。使用gcc編譯便可生成詞法分析程序1:
$ gcc lex.yy.c -o scanner
而後將須要分析的文件(以input.txt爲例)做爲參數傳遞給scanner執行分析:
$ ./scanner input.txt
flex語法格式
詞法規範定義文件給出了單詞構成規則。詞法文件在習慣上用字母l(即L的小寫)來做爲後綴。Flex文件由三個部分組成。或者說三個段。三個段之間用兩個%%分隔。正則表達式

定義段(definitions)函數

%%學習

規則段(rules)flex

%%spa

用戶代碼段(user code)code

定義段                                                                                                                                                                         
定義段包含着一些簡單名字的定義(name definitions),旨在簡化掃描器的規範。定義名字的方法以下:get

name definitioninput

名字能夠由字母或下劃線開頭,後跟零個或多個字母、數字、下劃線、或短橫線。名字的定義則從其後的第一個非空白字符(non-white-space)開始直到行尾。下面是一個例子,定義了一個名字DIGIT,其定義就是指一個數字,以下所示:it

DIGIT [0-9]io

當在後面引用這個名字時,用一對花括號({})括住該名字便可。它會被展開成一對圓括號括住的該名字的定義,即:

{name} 展開成 (definition)

例如:

{DIGIT}+"."{DIGIT}*

就等價於:

([0-9])+"."([0-9])*

定義段中還能夠加入啓動條件(start conditions)的聲明。顧名思義,啓動條件就如同C語言中的條件編譯同樣,根據指定的啓動條件去激活一條規則,並用這條規則去匹配讀入的字符。關於啓動條件,後面還有更詳細的介紹。
規則段                                                                                                                                                                            
規則由模式(pattern)和動做(action)兩個部分組成。模式就是一個正則表達式,FLEX加入了一些本身的擴展。而動做通常就是一些C語句。模式指出了一個單詞是如何構成的,當分析出一個符合該規則的單詞時,就執行相應的動做。

模式必定要位於一行的開頭處,不能有縮進。而動做的開頭必定要與模式在同一行。當動做是用一對花括號{}括起來時,能夠將左花括號放在與規則相同的行,而其他部分則能夠從下一行開始。
用戶代碼段                                                                                                                                                                      
全部用戶代碼都被原樣拷貝到文件lex.yy.c中。在這裏能夠定義一些輔助函數或代碼,供掃描器yylex()調用,或者調用掃描器(通常來講就是main()了)。這一部分是無關緊要的。若是沒有的話,Flex文件中第二個%%是能夠省略的。

在定義段或者規則段中,任何一行有縮進的文本或者包含在一對%{和%}之間的文本,都被原樣拷貝到最後生成的C代碼文件中(固然%{和%}會被移走)。在書寫時%{和%}都必須在一行的開始處,不能縮進。

在規則段中,第一條規則以前的任何未縮進的文本或者在%{和%}之間的文本,能夠用來爲掃描器聲明一些本地變量和代碼。一旦進入掃描器的代碼,這些代碼就會被執行。規則段內其餘的縮進的文本或者%{和%}之間的文本仍是被原樣拷貝輸出,可是他們的含義是還沒有有明肯定義,極可能引發編譯時(compile-time)錯誤(這一特性是爲了與POSIX兼容而提供的)。

在定義段中,沒有縮進的註釋也會被原樣拷貝到最後生成的C代碼文件中,例如以/*開始的一行註釋,直到遇到*/,這中間的文本會被原樣拷貝輸出
一個簡單的掃描器實例                                                                                                                                                      
%{
#include "stdio.h"
#include "stdlib.h"
%}

INT_DEX [1-9][0-9]*|[0]
INT_HEX [0][Xx]([1-9][0-9]*|[0])
INT_OCT [0][0-7]
FLOAT [0-9]*[.][0-9]+([eE][+-]?[0-9]*|[0])?f?
SEMI [;]
COMMA [,]
ASSIGNOP [=]
RELOP [>]|[<]|[>][=]|[<][=]|[=][=]|[!][=](^[=])
PLUS [+]
MINUS [-]
STAR [*]
DIV [/]
AND [&][&]
OR [|][|]
DOT [.]
NOT [!]
TYPE int|float
LP \(
RP \)
LB \[
RB \]
LC \{
RC \}
STRUCT struct
RETURN return
IF if
ELSE else 
WHILE while
SPACE [ \n\t]
ID [a-zA-Z_][a-zA-Z_0-9]*
/*end of definition*/

%%
{SEMI} {
    printf("get semmi : %s\n", yytext);

}

{COMMA} {
    printf("get comma : %s\n", yytext);
}
{ASSIGNOP} {
    printf("get assignop : %s\n", yytext);
}

{INT_DEX} |
{INT_HEX} |
{INT_OCT} {
    printf("get an integer: %s\n", yytext);
}

{FLOAT} {
    printf("get a float: %s\n", yytext);
}

{PLUS} | 
{MINUS} |
{DIV} |
{STAR} {
    printf("get an operator: %s\n", yytext);
}

{RELOP} {
    printf("get a relop: %s\n", yytext);
}

{AND} |
{OR} |
{NOT} {
    printf("get a logic operator: %s\n", yytext);
}

{DOT} {
    printf("get a dot: %s\n", yytext);
}
{STRUCT} |
{RETURN} |
{IF} |
{ELSE} |
{WHILE} {
    printf("get keyword: %s\n", yytext);
}

{TYPE} {
    printf("get type: %s\n", yytext);
}

{LP} |
{RP} |
{LB} |
{RB} |
{LC} |
{RC} {
    printf("get brackets : %s\n", yytext);
}

{SPACE} |
. {
/*ABANDON THESE CHARACTORS*/
}

{ID} {
    printf("get an ID: %s\n", yytext);
}
%%

int yywrap() {
  return 1;
}

int main(int argc, char** argv) {    if (argc > 1) {        if (!(yyin = fopen(argv[1], "r"))) {               perror(argv[1]);            return 1;        }    }    while (yylex());    return 0; }

相關文章
相關標籤/搜索