Lex和yacc工具介紹

2021-08-27 01:22:19 字數 3671 閱讀 2002

在編譯過程中,詞法分析和語法分析是兩個重要階段。lex和yacc是unix環境下非常著名的兩個工具,可以生成分別完成詞法分析和語法分析功能 的c**。在學習編譯原理過程中,可以善加利用這兩個工具,加深對兩個階段的理解。在平時的工作中,這兩個工具也會起到重要的作用。 lex是lexical compiler的縮寫,主要功能是生成乙個詞法分析器(scanner)的c原始碼。描述詞法分析器的檔案,經過lex編譯後,生成乙個lex.yy.c 的檔案,然後由c編譯器編譯生成乙個詞法分析器。詞法分析器,簡單來說,其任務就是將輸入的各種符號,轉化成相應的識別符號(token),轉化後的識別符號 很容被後續階段處理。

先讓我們來看乙個簡單的例子:

int num_lines = 0, num_chars = 0;

%% \n

. %%

main()

然後編譯,輸入乙個文字試試:

$ flex sample1.l$ mv lex.yy.c sample1.c$ gcc sample1.c -o sample1 -ll$ ./sample1

#include "y.tab.h"

typedef char * yystype;

char * yylval;

% }

正規表示式宣告如下

/* regular definitions */

delim [ \t\n]

ws +

letter [a-za-z]

digit [0-9]

id ()*

number +(\.+)?(e[+\-]?+}?

這段正規表示式描述識別數(number)、識別符號(id)的"規則"。過一會我們再細說正規表示式。

規則段是由正規表示式和相應的動作組成的。

p1

p2

…… pn

值得注意的是,lex 依次嘗試每乙個規則,盡可能地匹配最長的輸入流。如果有一些內容根本不匹配任何規則,那麼 lex 將只是把它拷貝到標準輸出。比如

%% a

aa

aaaa

%% 編譯後執行一下,

$ ./sample3

aaaaaaa

i love you

可以看出lex的確按照最長的規則匹配。

程式段部分放一些掃瞄器的其它模組,比如一些動作執行時需要的模組。也可以在另乙個程式檔案中編寫,最後再鏈結到一起。 生成c**後,需用c的編譯器編譯。連線時需要指定鏈結庫。gcc的連線引數為 -ll。

[編輯]正規表示式

正規表示式(regular expression)可以描述有窮狀態自動機(finite automata)接受的語言,也就是定義乙個可以接受的串的集合。限於篇幅,我們就不展開關於這方面的話題了。有興趣的請參考[4]。 這裡只介紹一下lex中用到的正規表示式的一些規則。

轉義字元(也稱操作符):

" \ [ ] ^ - ? . * + | ( ) $ / % 這些符號有特殊含義,不能用來匹配自身。如果需要匹配的話,可以通過引號(")或者轉義符號(\)來指示。比如

c"++" c\+\+都可以匹配c++。

非轉義字元:所有除了轉義字元之外的字元都是非轉義字元。乙個非轉義字元可以匹配自身。比如

integer匹配文字中出現的integer。

萬用字元:萬用字元就是.(dot),可以匹配任何乙個字元。

字符集:用一對指定的字元構成乙個字符集。比如[abc]表示乙個字符集,可以匹配a、b、c中的任意乙個字元。使用 可以指定範圍。比如[a-z]表示可以匹配所有小寫字母的字符集。

重複:

* 任意次重複+ 至少一次的重複,相當於xx*? 零次或者一次選擇和分組:|符號表示選擇,二者則一;括號表示分組,括號內的組合被看作是乙個原子。比如(ab|cd)匹配ab或者cd。

簡單來說,yacc(yet another compiler-compiler)就是編譯器的編譯器。yacc是乙個通用的工具,能夠根據使用者指定的規則,生成乙個詞法分析程式。yacc能識別 lalr(1)且無歧義的文法,它的輸入是詞法分析器的輸出。我們知道,生成詞法分析器是lex分內的事,因此lex和yacc常常珠聯璧合。

先讓我們看一下yacc檔案的格式。和前面介紹的lex的格式類似:

declarations(宣告)

%%rules(規則)%%

programs(**)

俗話說"沒有規矩,不成方圓"。 規則段描述規則,自然是重中之重了。規則段的結構是如下,

a : body ;

a表示非終結符名,body表示產生式和動作。產生式包括非終結符和終結符,終結符用''引用。一些轉義字元,比如'\r','\n'等,和c裡面 的表示是一樣的。動作(action)則是在輸入被當前規則識別出來時而執行的。動作實際上就是c的**,寫在中。為了溝通詞法分析器和動作,yacc引入了形式變數,以$開頭。如果希望獲得詞法分析器和前面的動作返回的值,我們可以使用$1,$2,…。$i表 示一條規則右側第i個單元的值。比如有這樣的一條規則,

a : b c d ;c的返回值為$2,d為$3。依此類推。

程式段放一些其它的程式,也可以省略,連%%都可以不要。

連線時需要指定連線庫,gcc的引數為-ly。

[編輯]舉例

讓我們看乙個典型的例子,它實現乙個簡單的計算器: %

%start list

%token digit letter

%left '|'

%left '&'

%left '+' '-'

%left '*' '/' '%'

%left uminus /* supplies precedence for unary minus */

%% /* beginning of rules section

*/list :

/* empty */

| list stat '\n'

| list error '\n'

; stat : expr

| letter '=' expr

; expr : '(' expr ')'

| expr '+' expr

| expr '-' expr

| expr '*' expr

| expr '/' expr

| expr '%' expr

| expr '&' expr

| expr '|' expr

| '-' expr %prec uminus

| letter

| number ; number : digit | number digit ; %% /* start of programs */ yylex() /* c is now nonblank */ if( islower( c ) ) if( isdigit( c ) ) return( c ); } 編譯、執行:

$bison example.y

$gcc example.tab.c ly -o example

$./example

20+30*50=1520

小結 lex是詞法分析器的生成工具,yacc是文法分析器的生成工具。lex的描述規則採用正規表示式,關於正規表示式的詳細討論,參見文獻[1]; yacc的描述規則採用無歧異文法。在gnu中有相應lex和yacc工具:flex和bison,與lex和 yacc相容。

C語言的lex和yacc工具說明

一,lex工具 lex工具是一種詞法分析程式生成器,它可以根據詞法規則說明書的要求來生成單詞識別程式,由該程式識別出輸入文字中的各個單詞。1 lex程式的結構 定義部分 規則部分 使用者子程式部分 其中規則部分是必須的,定義和使用者子程式部分是任選的。1 定義部分 定義部分起始於 符號,其間可以是包...

lex和yacc格式入門

lex和yacc格式入門 lex檔案 hi oi n tchau bye n int main void int yywrap void yacc檔案 token hi bye program hi bye hi hi bye bye int yyerror char msg 會發現它們的結構都很相...

初步學習lex和yacc

因為是非計算機本科,所以沒有學編譯原理,進來想補補課,於是買了本 自製程式語言 裡面介紹了lex和yacc工具,於是裝起來試了下。原來用工具來解析字串還是挺方便的,以前知道正則以後,就覺得這東西很好,現在有了lex和yacc,把正則能做的事情又放大了,能夠做更豐富的事情。例如,寫乙個簡單的把字串裡的...