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; }