Lex與Yacc的結合 用Lex與Yacc結合起來使用可以很方便的產生一個新語言的編譯器,不過現在很多國內的圖書裡面對它們的介紹是分開的,單獨的介紹也是比較含糊,不是很清晰。把他們如何結合的介紹更是少的可憐。我用他們做了一個能識別整型數值的加、減、乘、除的編譯器。把我的心得寫在下面,供大家參考。
首先,我就不介紹Lex的文法規則了,因為在一些書上這些是重點介紹的內容,我先把Lex的來源程式寫在下面,然後講解。 %{ #define NUMBER 257 #define PLUS 258 #define SUB 259 #define CHEN 260 #define DIV 261 #define LKUO 262 #define YKUO 263 #include <stdio.h> #include <stdlib.h> extern int yylval; %} number [0-9]+ %% {number} {yylval=atoi(yytext);printf("%s",yytext);return NUMBER;} "+" {printf("%s",yytext);return PLUS;} "-" {printf("%s",yytext);return SUB;} "*" {printf("%s",yytext);return CHEN;} "/" {printf("%s",yytext);return DIV;} "(" {printf("%s",yytext);return LKUO;} ")" {printf("%s",yytext);return YKUO;} %% 其中 #define NUMBER 257 #define PLUS 258 #define SUB 259 #define CHEN 260 #define DIV 261 #define LKUO 262 #define YKUO 263 是在Yacc中使用的記號,該記號必須先在YACC中定義,然後,在LEX中使用,YACC告訴LEX需要使用的符號,使用YACC –d 檔案.y來產生一個yytab.h的檔案,在該檔案中內容就是上面的一系列#define 。。。。 extern int yylval; 告訴LEX要引用外部的變數yylval。 %% {number} {yylval=atoi(yytext);printf("%s",yytext);return NUMBER;} "+" {printf("%s",yytext);return PLUS;} "-" {printf("%s",yytext);return SUB;} "*" {printf("%s",yytext);return CHEN;} "/" {printf("%s",yytext);return DIV;} "(" {printf("%s",yytext);return LKUO;} ")" {printf("%s",yytext);return YKUO;} %% 這一部分就不解釋了。 下面是*.y檔案了 %{ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define YYSTYPE int %} %token NUMBER %token PLUS %token SUB %token PLUS %token CHEN %token DIV %token LKUO %token YKUO %left PLUS SUB %left CHEN DIV %% com: exp {printf("=%d/n",$1);}; exp: exp PLUS fac {$$=$1+$3;} |exp SUB fac {$$=$1-$3;} |fac{$$=$1;}; fac:fac CHEN term {$$=$1*$3;} |fac DIV term {$$=$1/$3;} |term {$$=$1;}; term:LKUO exp YKUO {$$=$1;} | NUMBER {$$=$1;}; %% extern int yylex(); int yyparse(); main() { return yyparse(); } yyerror() {printf("sytax error");} 其中#define YYSTYPE int是定義記錄記號的值棧的類型為int,當然你也可以定義其他的類型。 我們命名第一個檔案為sample.l,用命令pclex sample.l 處理,產生sample.c檔案。 然後我們命名第二個檔案為sample1.y,用命令pcyacc -v -d sample1.y 產生sample1.c、yytab.h、yy.lrt(YACC的分析表檔案)。 用vc++或者tc編譯一個工程,這個工程包含這兩個檔案*.c檔案,其中在tc中編譯這個工程的時候,sample1.c為primary file(該選項在tc中的compile項中設定),產生一個可執行檔檔案。如niu1.exe,然後編輯一個niu.txt檔案,niu.txt檔案就是需要識別的數學運算式。如下面的例子: niu.txt 內容如下 5-2+3*22/2+2-3 用niu1<niu.txt執行結果如: 比如niu.txt的內容如下: 用一個錯誤的文法試試 如果niu.txt的內容如下: 5-3+2+ / 4*2+4 紅色代表文法有錯誤的地方運行結果如下 我以sytax error代表語法錯誤。 該編譯器還有許多不完善的地方,不過它已經勾勒出了,LEX與YACC結合使用的一個架構,如果你感興趣的話,可以逐步的完善它。
|