Flex和Bison似乎不匹配

时间:2014-12-19 14:27:41

标签: bison flex-lexer

我正在尝试构建一个简单的计算器,就像在键入算术表达式并按Enter键来解析表达式并计算结果一样。

以下代码适用于(只是野牛),朋友给了我:

%{                
   #include<stdio.h>                                                                   
   #include <math.h>                                                       
   #define YYSTYPE double

   extern int line_number;                                                            
   int line_number=0;                                                                     
void yyerror(char *err)
{
   printf("Error: %s\n", err);
}
%}                                                                                   

%token NUMBER        /* define token type for numbers */
%token PLUS
%token MINUS
%token MULT
%token DIV
%token NEWLINE
%token LPAR
%token RPAR

%%     /* Bison grammar rules */
input   : /* empty production to allow an empty input */
        | line input  
        ;
line    : expr NEWLINE   { printf("Result is %f\n", $1); }
expr    : expr PLUS term   { $$ = $1 + $3; }
        | expr MINUS term   { $$ = $1 - $3; }
        | term            { $$ = $1; }
        ;
term    : term MULT factor { $$ = $1 * $3; }
        | term DIV factor { $$ = $1 / $3; }
        | factor          { $$ = $1; }
        ;
factor  : LPAR expr RPAR    { $$ = $2; }
        | NUMBER          { $$ = $1; }
        ;
;                                                                                    
%%                                                                                   

int yylex( void ) {
    int c = getchar();      /* read from stdin */
    if (c < 0) return 0;        /* end of the input*/
    while ( c == ' ' || c == '\t' ) c = getchar( );
    if ( isdigit(c) || c == '.' ) {
    ungetc(c, stdin);    /* put c back into input */
    scanf_s ("%lf", &yylval); /* get value using scanf */
    return NUMBER;       /* return the token type */
    }
    if(c=='+')
        return PLUS;
    if(c=='-')
        return MINUS;
    if(c=='*')
        return MULT;
    if(c=='/')
        return DIV;
    if(c=='\n')
        return NEWLINE;
    if(c=='(')
        return LPAR;
    if(c==')')
        return RPAR;
    return c; /* anything else... return char itself */
}

main ()                                                                              
{
  yyparse ();
}

现在,当我尝试将其拆分为两个文件时,它只调用main函数并且似乎接受输入但屏幕上没有显示任何内容:

calc.l:

%{
#include "calc.tab.h"
#include "stdlib.h"
#define YYSTYPE double
%}
%option noyywrap
%option never-interactive

NUM  [0-9]*\.?[0-9]+
white [ \r\t]+ 

%%
{white} { }
{NUM}  {yylval=atof(yytext);return NUM;}
"+"    {return PLUS;}
"-"    {return MINUS;}
"/"    {return DIV;}
"*"    {return MUL;}
"("    {return LP;}
")"    {return RP;}
"\n"   {return NL;}
%%

calc.y:

%{
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define YYSTYPE double

%}

%token NUM
%token PLUS
%token MINUS
%token MUL
%token DIV
%token LP
%token RP
%token NL

%%

Input   :
    | Line Input
    ;

Line    : Exp NL        { printf("Result = %f\n", $1); }


Exp : Exp PLUS Term     { $$ = $1 + $3; }
    | Exp MINUS Term    { $$ = $1 - $3; }
    | Term          { $$ = $1; }
    ;

Term    : Term MUL Fact     { $$ = $1 * $3; }
    | Term DIV Fact     { $$ = $1 / $3; }
    | Fact          { $$ = $1; }
    ;

Fact    : LP Exp RP         { $$ = $2; }
    | NUM           { $$ = $1; }
    ;

%%
int yyerror(char *err)
{
   printf("Error: %s\n", err);
}

int main()
{
    printf("Hello\n");
    yyparse();
}

我使用以下命令编译并运行 bison -d calc.y && flex calc.l && gcc -o calculator calc.tab.c lex.yy.c -lfl && ./calculator

这是一个示例输出(5 + 5是我的输入,没有显示结果):

Hello
5+5

我哪里出错了?

1 个答案:

答案 0 :(得分:2)

这里有两个问题。

首先,您指定:

%option never-interactive

一旦这样做,您就不应期望能够以交互方式使用该程序。 never-interactive实际上是一个承诺,即程序不会以交互方式使用,它允许flex生成稍微更有效的代码来缓冲输入而不是逐个字符地读取。因此,在输入大量表达式或通过输入文件结束标记终止程序之前,您将看不到任何输出。

第二个问题是你不能在YYSTYPE中尽早定义calc.l

%{
#include "calc.tab.h"
#include "stdlib.h"
#define YYSTYPE double
%}

yylvalcalc.tab.h中声明为YYSTYPE yylval;;如果YYSTYPE未定义为宏(当包含calc.tab.h时),则为int的typedef&#39; d,其效果为yylval flex生成的C文件中的int。但是,在bison生成的C文件中,yylval被声明为double。这是未定义的行为,gcc不会检测到,因为两个翻译单元是独立编译的,链接器对类型没有任何了解。

该错误的后果是打印的结果不正确。 (它很可能被打印为0.0,但由于它是未定义的行为,因此任何结果都是可能的。)

因此,您需要将#define放在#include

之前
%{
#define YYSTYPE double
#include <stdlib.h>
#include <unistd.h>
#include "calc.tab.h"
%}