繁体   English   中英

Bison中缀计算器总是评估为0

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM