Calc with bison and flex 不工作负操作
Calc with bison and flex doesn't work operation negative
我对这个 Bison 程序有疑问。我不知道为什么重用不起作用。对于负数的操作,我只使用同一行来获取第一个数字并进行更多操作。我刚把第一个数字改成了负数。
calc.y
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
void yyerror(const char* s);
%}
%union {
int ival;
float fval;
}
%token<ival> T_INT
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE
%type<ival> expression
%type<fval> mixed_expression
%start calculation
%%
calculation:
| calculation line
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { printf("\tResult: %f\n", );}
| expression T_NEWLINE { printf("\tResult: %i\n", ); }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| T_MINUS T_FLOAT { $$ = -; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
| T_MINUS mixed_expression T_RIGHT { $$ = -; }
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
| T_MINUS T_INT { $$ = -; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
calclex.l
%option noyywrap
%{
#include <stdio.h>
#define YY_DECL int yylex()
#include "calc.tab.h"
%}
%%
[ \t] ; // ignore all whitespace
[0-9]+\.[0-9]+ {yylval.fval = atof(yytext); return T_FLOAT;}
[0-9]+ {yylval.ival = atoi(yytext); return T_INT;}
\n {return T_NEWLINE;}
"+" {return T_PLUS;}
"-" {return T_MINUS;}
"*" {return T_MULTIPLY;}
"/" {return T_DIVIDE;}
"(" {return T_LEFT;}
")" {return T_RIGHT;}
"exit" {return T_QUIT;}
"quit" {return T_QUIT;}
%%
正如我评论中所说,这个问题叫做"unary minus",它描述了区分正常减法运算a - b
和否定运算0 - a
的麻烦,如果缩写为-a
。常见的解决方案是添加一些代码,使减号根据位置充当两个不同的运算符。在 Bison 中,它通过为不存在的符号(此处 NEG
)实现优先级并将该优先级绑定到大小写 -a
.
来完成
您需要在代码中执行两次,一次用于 T_FLOAT
,第二次用于 T_INT
。我还删除了一行毫无意义的内容,至少对我来说是这样。
calc.y
:
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
void yyerror(const char* s);
%}
%union {
int ival;
float fval;
}
%token<ival> T_INT
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE
%precedence NEG /* unary minus */
%type<ival> expression
%type<fval> mixed_expression
%start calculation
%%
calculation:
| calculation line
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { printf("\tResult: %f\n", );}
| expression T_NEWLINE { printf("\tResult: %i\n", ); }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| T_MINUS mixed_expression %prec NEG { $$ = -; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
/* | T_MINUS mixed_expression T_RIGHT { $$ = -; } */
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
| T_MINUS expression %prec NEG { $$ = -; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
文件calclex.l
可以保持不变(虽然浮点数有点复杂)。
我对这个 Bison 程序有疑问。我不知道为什么重用不起作用。对于负数的操作,我只使用同一行来获取第一个数字并进行更多操作。我刚把第一个数字改成了负数。
calc.y
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
void yyerror(const char* s);
%}
%union {
int ival;
float fval;
}
%token<ival> T_INT
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE
%type<ival> expression
%type<fval> mixed_expression
%start calculation
%%
calculation:
| calculation line
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { printf("\tResult: %f\n", );}
| expression T_NEWLINE { printf("\tResult: %i\n", ); }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| T_MINUS T_FLOAT { $$ = -; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
| T_MINUS mixed_expression T_RIGHT { $$ = -; }
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
| T_MINUS T_INT { $$ = -; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
calclex.l
%option noyywrap
%{
#include <stdio.h>
#define YY_DECL int yylex()
#include "calc.tab.h"
%}
%%
[ \t] ; // ignore all whitespace
[0-9]+\.[0-9]+ {yylval.fval = atof(yytext); return T_FLOAT;}
[0-9]+ {yylval.ival = atoi(yytext); return T_INT;}
\n {return T_NEWLINE;}
"+" {return T_PLUS;}
"-" {return T_MINUS;}
"*" {return T_MULTIPLY;}
"/" {return T_DIVIDE;}
"(" {return T_LEFT;}
")" {return T_RIGHT;}
"exit" {return T_QUIT;}
"quit" {return T_QUIT;}
%%
正如我评论中所说,这个问题叫做"unary minus",它描述了区分正常减法运算a - b
和否定运算0 - a
的麻烦,如果缩写为-a
。常见的解决方案是添加一些代码,使减号根据位置充当两个不同的运算符。在 Bison 中,它通过为不存在的符号(此处 NEG
)实现优先级并将该优先级绑定到大小写 -a
.
您需要在代码中执行两次,一次用于 T_FLOAT
,第二次用于 T_INT
。我还删除了一行毫无意义的内容,至少对我来说是这样。
calc.y
:
%{
#include <stdio.h>
#include <stdlib.h>
extern int yylex();
extern int yyparse();
extern FILE* yyin;
void yyerror(const char* s);
%}
%union {
int ival;
float fval;
}
%token<ival> T_INT
%token<fval> T_FLOAT
%token T_PLUS T_MINUS T_MULTIPLY T_DIVIDE T_LEFT T_RIGHT
%token T_NEWLINE T_QUIT
%left T_PLUS T_MINUS
%left T_MULTIPLY T_DIVIDE
%precedence NEG /* unary minus */
%type<ival> expression
%type<fval> mixed_expression
%start calculation
%%
calculation:
| calculation line
;
line: T_NEWLINE
| mixed_expression T_NEWLINE { printf("\tResult: %f\n", );}
| expression T_NEWLINE { printf("\tResult: %i\n", ); }
| T_QUIT T_NEWLINE { printf("bye!\n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = ; }
| T_MINUS mixed_expression %prec NEG { $$ = -; }
| mixed_expression T_PLUS mixed_expression { $$ = + ; }
| mixed_expression T_MINUS mixed_expression { $$ = - ; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = * ; }
| mixed_expression T_DIVIDE mixed_expression { $$ = / ; }
| T_LEFT mixed_expression T_RIGHT { $$ = ; }
/* | T_MINUS mixed_expression T_RIGHT { $$ = -; } */
| expression T_PLUS mixed_expression { $$ = + ; }
| expression T_MINUS mixed_expression { $$ = - ; }
| expression T_MULTIPLY mixed_expression { $$ = * ; }
| expression T_DIVIDE mixed_expression { $$ = / ; }
| mixed_expression T_PLUS expression { $$ = + ; }
| mixed_expression T_MINUS expression { $$ = - ; }
| mixed_expression T_MULTIPLY expression { $$ = * ; }
| mixed_expression T_DIVIDE expression { $$ = / ; }
| expression T_DIVIDE expression { $$ = / (float); }
;
expression: T_INT { $$ = ; }
| expression T_PLUS expression { $$ = + ; }
| expression T_MINUS expression { $$ = - ; }
| expression T_MULTIPLY expression { $$ = * ; }
| T_LEFT expression T_RIGHT { $$ = ; }
| T_MINUS expression %prec NEG { $$ = -; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %s\n", s);
exit(1);
}
文件calclex.l
可以保持不变(虽然浮点数有点复杂)。