回 帖 发 新 帖 刷新版面

主题:Lex与Yacc的结合

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

回复列表 (共1个回复)

沙发

Lex和Yacc充其量最多只能做到语法分析,只是编译程序的辅助工具而已。
并且他们是Unix下的分析工具,Windows版本的是flex和bison。
其实有很多这种类似的辅助工具.
我个人认为可能只是lex和yacc是比较早的,所以才广为人知而已。
现在在Windows环境下有很多相当好的IDE辅助开发工具。
象ParGen(支持C++),GoldenPar,ParGrammar等。
他们用起来都比lex和yacc要方便得多。
而且生成的C/C++代码也比lex&yacc要清晰。

我来回复

您尚未登录,请登录后再回复。点此登录或注册