我正在尝试构建一个简单的计算器,就像在键入算术表达式并按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
我哪里出错了?
答案 0 :(得分:2)
这里有两个问题。
首先,您指定:
%option never-interactive
一旦这样做,您就不应期望能够以交互方式使用该程序。 never-interactive
实际上是一个承诺,即程序不会以交互方式使用,它允许flex
生成稍微更有效的代码来缓冲输入而不是逐个字符地读取。因此,在输入大量表达式或通过输入文件结束标记终止程序之前,您将看不到任何输出。
第二个问题是你不能在YYSTYPE
中尽早定义calc.l
:
%{
#include "calc.tab.h"
#include "stdlib.h"
#define YYSTYPE double
%}
yylval
在calc.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"
%}