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结合使用的一个框架,如果你感兴趣的话,可以逐步的完善它。
|