一、Ubuntu安裝flex
在ubutu上安裝 yacc的命令:
sudo apt-get install flex bison
yacc(Yet Another Compiler Compiler)
yacc是一個(gè)經(jīng)典的生成語法分析器的工具。yacc生成的編譯器主要是用C語言寫成的語法解析器(Parser),需要與詞法解析器Lex一起使用,再把兩部份產(chǎn)生出來的C程序一并編譯。-
flex:詞法分析器
flex是一個(gè)詞法分析器。用來將一個(gè).l文件生成一個(gè).c程序文件。即生成一個(gè)詞法分析器。然后讀取輸入,和正則表達(dá)式匹配,再執(zhí)行相應(yīng)的動(dòng)作,實(shí)現(xiàn)了程序的功能。我們可以發(fā)現(xiàn)flex實(shí)現(xiàn)在程序外部就可以接受輸入的功能。Flex是一個(gè)生成掃描器的工具,能夠識(shí)別文本中的詞法模式。Flex 讀入給定的輸入文件,如果沒有給定文件名的話,則從標(biāo)準(zhǔn)輸入讀取,從而獲得一個(gè)關(guān)于需要生成的掃描器的描述。此描述叫做規(guī)則,由正則表達(dá)式和 C代碼對(duì)組成。Flex 的輸出是一個(gè) C 代碼文件——lex.yy.c——其中定義了yylex() 函數(shù)。編譯輸出文件可以生成一個(gè)可執(zhí)行文件。當(dāng)運(yùn)行可執(zhí)行文件的時(shí)候,它分析輸入文件,為每一個(gè)正則表達(dá)式尋找匹配。當(dāng)發(fā)現(xiàn)一個(gè)匹配時(shí),它執(zhí)行與此正則表達(dá)式相關(guān)的C代碼。Flex 不是GNU工程,但是GNU為Flex 寫了手冊(cè)。
二、flex使用示例:實(shí)現(xiàn)Ubuntu中wc的功能
-
article.txt文件的內(nèi)容如下,
wc的功能就是統(tǒng)計(jì)該文件中的行數(shù)、單詞及字符個(gè)數(shù)。
wc統(tǒng)計(jì)結(jié)果
-
article.txt文件的內(nèi)容如下,
- 編寫countNum.l程序如下
%{
#define T_WORD 1
int numChars = 0, numWords = 0, numLines = 0; //初始化字符、單詞、行數(shù)
%}
WORD ([^ \t\n\r\a]+) //匹配單詞
%%
\n { numLines++; numChars++; } //匹配換行
{WORD} { numWords++; numChars += yyleng; return
T_WORD; }
<<EOF>> { return 0; } // 文件結(jié)束
. { numChars++; } //其他字符
%%
int main() {
int token_type;
while (token_type = yylex()) {
printf("WORD:\t%s\n", yytext);
}
printf("\nChars\tWords\tLines\n");
printf("%d\t%d\t%d\n", numChars, numWords, numLines);
return 0;
}
int yywrap() {
return 1;
}
- 3 執(zhí)行
flex countNum命令,生成一個(gè)lex.yy.c文件 - 4 執(zhí)行
g++ lex.yy.c countNum對(duì)lex.yy.c文件進(jìn)行編譯,生成countNum可執(zhí)行程序 - 5 運(yùn)行
./countNum < article.txt,把a(bǔ)rticle.txt輸入到countNum中,打印統(tǒng)計(jì)結(jié)果
統(tǒng)計(jì)結(jié)果
三、flex解析
yylex()是由flex創(chuàng)建的掃描程序的入口點(diǎn),調(diào)用yylex()啟動(dòng)或者重新開始掃描。Lex編寫的yylex()從名為yyin的FILE *文件指針中讀取字符。 如果未設(shè)置yyin,則默認(rèn)為標(biāo)準(zhǔn)輸入。 它輸出到y(tǒng)yout,如果未設(shè)置默認(rèn)為stdout。 還可以在yywrap()函數(shù)中修改yyin,該函數(shù)在文件末尾調(diào)用。 它允許打開另一個(gè)文件,并繼續(xù)解析。如果是這種情況,將其返回0。如果要結(jié)束此文件的解析,將其返回1。一般來說,每次調(diào)用yylex()都會(huì)返回一個(gè)表示標(biāo)記類型的整數(shù)值。
flex的結(jié)構(gòu)如下:
%{ /*declaration*/ %}
/* Definition */
%%
/* Rules */
%%
/* C Code */
一個(gè)*.l的文件里的結(jié)構(gòu)大概如上,用%%分隔開來。分為三個(gè)區(qū):
- 定義區(qū):包含一些簡(jiǎn)單的名字定義(name definitions)來簡(jiǎn)化詞法掃描器(scanner)的規(guī)則,并且還有起始條件(start condition)的定義。(上個(gè)例子比較簡(jiǎn)單,并未涉及定義區(qū))
- 規(guī)則區(qū):包含了一系列具有pattern-action形式的規(guī)則,并且模式 pattern 位于行首不能縮進(jìn),action 也應(yīng)該起始于同一行。(上例使用正則表達(dá)式給出)
- 用戶代碼區(qū):代碼將被原封不動(dòng)地拷貝到輸出文件中,并且這些代碼通常會(huì)被掃描器調(diào)用,當(dāng)然,該區(qū)是可選的,如果 Flex 源文件中不存在該區(qū),那么可以省略第二個(gè) " %%" 。
使用諸如Flex的詞法生成器的好處是使得程序員可以集中考慮詞法的特點(diǎn);而不是具體如何實(shí)現(xiàn)詞法分析。


