LEX与YACC的结合使用

一个程序通常在每次返回一个标记时都要调用 yylex() 函数。只有在文件结束或者出现错误标记时才会终止。

一个由 Yacc 生成的解析器调用 yylex() 函数来获得标记。 yylex() 可以由 Lex 来生成或完全由自己来编写。 对于由 Lex 生成的 lexer 来说,要和 Yacc 结合使用,每当 Lex 中匹配一个模式时都必须返回一个标记。 因此 Lex 中匹配模式时的动作一般格式为:

{pattern} { /* do smthg*/ return TOKEN_NAME; }

于是 Yacc 就会获得返回的标记。当 Yacc 编译一个带有 -d 标记的 .y文件时,会生成一个头文件,它对每个标记都有 #define 的定义。 如果 Lex 和 Yacc 一起使用的话,头文件必须在相应的 Lex 文件 .lex中的 C 声明段中包括。

以整数的四则运算为例:

cal.y - 语法文件

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define YYSTYPE int
%}
 
%token DIGIT PLUS SUB MULT DIV LB RB ENTER

%left SUB PLUS
%left MULT DIV

%%
line    :    expr ENTER            {printf("%d\n", $1);}
        ;
expr    :    DIGIT                {$$ = $1;}
        |    expr PLUS expr        {$$ = $1+$3;}
        |    expr SUB expr        {$$ = $1-$3;}
        |    expr MULT expr        {$$ = $1*$3;}
        |    expr DIV expr        {$$ = $1/$3;}
        |    LB expr RB            {$$ = $2;}
        ;
%%

extern int yylex();
int yyparse();
int main(){
    return yyparse();
}
void yyerror(char const *s){
    fprintf(stderr, "%s\n", s);
}

lex.l - Lex的解析器文件

%{
        #include "cal.tab.h"
        #include <stdio.h>
        extern int yylval;
%}

digit    [0-9]+

%% 

{digit}        {yylval = atoi(yytext);    return DIGIT;}    
"+"            {return PLUS;}
"-"            {return SUB;}
"*"            {return MULT;}
"/"            {return DIV;}
"("            {return LB;}
")"            {return RB;}
\r            {return ENTER;}
\n            {return ENTER;}
%%


int yywrap(){
    return 1;
}
添加新评论