我对这个野牛程序有问题。我不知道为什么重用不起作用。对于负数的操作,我只是使用相同的行来获取第一个数字并使用更多操作进行操作。我只是将第一个数字更改为负数。
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: %fn", $1);}
| expression T_NEWLINE { printf("tResult: %in", $1); }
| T_QUIT T_NEWLINE { printf("bye!n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = $1; }
| T_MINUS T_FLOAT { $$ = -$2; }
| mixed_expression T_PLUS mixed_expression { $$ = $1 + $3; }
| mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| T_LEFT mixed_expression T_RIGHT { $$ = $2; }
| T_MINUS mixed_expression T_RIGHT { $$ = -$2; }
| expression T_PLUS mixed_expression { $$ = $1 + $3; }
| expression T_MINUS mixed_expression { $$ = $1 - $3; }
| expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| mixed_expression T_PLUS expression { $$ = $1 + $3; }
| mixed_expression T_MINUS expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE expression { $$ = $1 / $3; }
| expression T_DIVIDE expression { $$ = $1 / (float)$3; }
;
expression: T_INT { $$ = $1; }
| expression T_PLUS expression { $$ = $1 + $3; }
| expression T_MINUS expression { $$ = $1 - $3; }
| expression T_MULTIPLY expression { $$ = $1 * $3; }
| T_LEFT expression T_RIGHT { $$ = $2; }
| T_MINUS T_INT { $$ = -$2; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %sn", 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;}
%%
正如我在评论中所说,这个问题被称为"一元减号",它描述了将正常的减法运算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: %fn", $1);}
| expression T_NEWLINE { printf("tResult: %in", $1); }
| T_QUIT T_NEWLINE { printf("bye!n"); exit(0); }
;
mixed_expression: T_FLOAT { $$ = $1; }
| T_MINUS mixed_expression %prec NEG { $$ = -$2; }
| mixed_expression T_PLUS mixed_expression { $$ = $1 + $3; }
| mixed_expression T_MINUS mixed_expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| T_LEFT mixed_expression T_RIGHT { $$ = $2; }
/* | T_MINUS mixed_expression T_RIGHT { $$ = -$2; } */
| expression T_PLUS mixed_expression { $$ = $1 + $3; }
| expression T_MINUS mixed_expression { $$ = $1 - $3; }
| expression T_MULTIPLY mixed_expression { $$ = $1 * $3; }
| expression T_DIVIDE mixed_expression { $$ = $1 / $3; }
| mixed_expression T_PLUS expression { $$ = $1 + $3; }
| mixed_expression T_MINUS expression { $$ = $1 - $3; }
| mixed_expression T_MULTIPLY expression { $$ = $1 * $3; }
| mixed_expression T_DIVIDE expression { $$ = $1 / $3; }
| expression T_DIVIDE expression { $$ = $1 / (float)$3; }
;
expression: T_INT { $$ = $1; }
| expression T_PLUS expression { $$ = $1 + $3; }
| expression T_MINUS expression { $$ = $1 - $3; }
| expression T_MULTIPLY expression { $$ = $1 * $3; }
| T_LEFT expression T_RIGHT { $$ = $2; }
| T_MINUS expression %prec NEG { $$ = -$2; }
;
%%
int main() {
yyin = stdin;
do {
yyparse();
} while(!feof(yyin));
return 0;
}
void yyerror(const char* s) {
fprintf(stderr, "Parse error: %sn", s);
exit(1);
}
文件calclex.l
可以保持不变(尽管浮点数有点复杂(。