[英]Bison infix calculator always evaluates as 0
我正在读一本我在互联网上发现的关于GNU Flex / Bison的书。 这很酷。 其中一个例子涉及编写中缀计算器。 这很好。
问题是,本书使用int
作为YYSTYPE
,这会产生明显的问题,比如将1除以2.所以我决定修改程序以使用float
。 到现在为止还挺好。 该程序(源代码如下)编译得很好,但无论计算结果如何, 总是给出0的答案 。 我也不知道如何调试它,因为它显然是生成代码。
calc.l
%{
#include "parser.h"
%}
%%
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
[0-9]+ {
yylval = atof(yytext);
return NUMBER;
}
\n { return EOL; }
[ \t] { ; }
. { yyerror("Unknown symbol"); }
%%
calc.y
%{
#include <stdio.h>
#define YYSTYPE float
%}
%token NUMBER
%token ADD SUB MUL DIV
%token EOL
%%
/* List of expressions */
calclist:
| calclist AS_result EOL { printf("%f\n-> ", $2); }
;
/* Add/subtract result. Evaluated after multiply/divide result */
AS_result: MD_result
| AS_result ADD MD_result { $$ = $1 + $3; }
| AS_result SUB MD_result { $$ = $1 - $3; }
;
/* Multiply/divide result. Evaluated first. */
MD_result: NUMBER
| MD_result MUL NUMBER { $$ = $1 * $3; }
| MD_result DIV NUMBER { $$ = $1 / $3; }
;
%%
int yyerror(char *msg)
{
printf("Error: '%s'\n", msg);
return 0;
}
int main(int argc, char **argv)
{
printf("-> ");
yyparse();
return 0;
}
Makefile文件
make: calc.l calc.y
bison -Wall -o parser.c --defines=parser.h calc.y
flex -o scanner.c calc.l
cc -ggdb -o calc scanner.c parser.c -lfl
clean:
rm -f parser.c parser.h scanner.c calc.c calc
示例运行
michael@michael-desktop:~/code/calculator$ ./calc
-> 1 + 2
0.000000
-> ^C
michael@michael-desktop:~/code/calculator$
感谢代码的任何部分的反馈以及实际问题。 干杯!
你是对的,它只适用于分裂 - 奇怪......我没有注意到,对我感到羞耻。 这是另一件要尝试的事情:
calc.y:
%{
#include <stdio.h>
%}
%union { double d; }
%token <d> NUMBER
%token ADD SUB MUL DIV
%token EOL
%type <d> MD_result AS_result
%%
calc.l:更改行“yylval = atof(yytext);” 有:
yylval.d = atof(yytext);
现在它说:
-> 1+2
3.000000
-> 2*3
6.000000
-> 4-5
-1.000000
-> 6/4
1.500000
正如所料。
在calc.y中:添加第二个定义:
%{
#include <stdio.h>
#define YYSTYPE float
#define YYSTYPE_IS_DECLARED
%}
然后..
./calc
-> 1/3
0.333333
您的提议及其由@Michael进行的更正不起作用,因为#define YYSTYPE
未传播到扫描仪。 %{ %}
块仅用于bison(对于生成的解析器),它不会在生成的标头中导出。 阅读有关%code
的文档,了解需要完成的工作: http : //www.gnu.org/software/bison/manual/bison.html#g_t_0025code-Summary 。 在您的情况下, %code requires
是合适的:
%code requires
{
# include <stdio.h>
# define YYSTYPE float
# define YYSTYPE_IS_DECLARED
}
在为解析器配备调试操作后,很容易看出出现了什么问题:
%debug
%printer { fprintf(yyoutput, "%f", $$); } <>
和
int main(int argc, char **argv)
{
printf("-> ");
yydebug = !!getenv("YYDEBUG");
yyparse();
return 0;
}
你会看到的:
Reading a token: -> 1+2
Next token is token NUMBER (0.000000)
Shifting token NUMBER (0.000000)
Entering state 3
Reducing stack by rule 6 (line 28):
$1 = token NUMBER (0.000000)
-> $$ = nterm MD_result (0.000000)
Stack now 0 1
Entering state 5
Reading a token: Next token is token ADD (0.000000)
Reducing stack by rule 3 (line 22):
$1 = nterm MD_result (0.000000)
-> $$ = nterm AS_result (0.000000)
Stack now 0 1
Entering state 4
Next token is token ADD (0.000000)
Shifting token ADD (0.000000)
Entering state 6
Reading a token: Next token is token NUMBER (0.000000)
Shifting token NUMBER (0.000000)
Entering state 3
Reducing stack by rule 6 (line 28):
$1 = token NUMBER (0.000000)
-> $$ = nterm MD_result (0.000000)
Stack now 0 1 4 6
Entering state 11
Reading a token: Next token is token EOL (0.000000)
Reducing stack by rule 4 (line 23):
$1 = nterm AS_result (0.000000)
$2 = token ADD (0.000000)
$3 = nterm MD_result (0.000000)
-> $$ = nterm AS_result (0.000000)
这表明当我输入“1 + 2”时,实际上到处都看到0.00000。
现在,它如何“分裂”? 不小心,因为浮点除法和int除法在位级非常相似。 玩具有以下程序重复错误:将变量填充为整数,但将它们用作浮点数。
#include <stdio.h>
union YYSTYPE
{
int ival;
float fval;
};
#define TRY(L, O, R) \
do { \
union YYSTYPE lhs, rhs, res; \
lhs.ival = L; \
rhs.ival = R; \
res.fval = lhs.fval O rhs.fval; \
fprintf (stdout, "d. %d %s %d => %f\n", \
lhs.ival, #O, rhs.ival, res.fval); \
fprintf (stdout, "x. %x %s %x => %x\n", \
lhs.ival, #O, rhs.ival, res.ival); \
} while (0)
int main()
{
TRY(1, /, 2);
TRY(1, *, 2);
TRY(1, -, 2);
TRY(1, +, 2);
return 0;
}
但是,当然,正确的答案不是使用#define YYSTYPE
,这种方法太粗糙,而是使用%union
,正如@Michael建议的那样。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.