2013-03-24 47 views
3

我正在閱讀我在互聯網上找到的關於GNU Flex/Bison的書。這很酷。其中一個例子涉及編寫一箇中綴計算器。那很好。Bison中綴計算器始終評估爲0

的問題是,書中使用intYYSTYPE,這就造成明顯的問題時稱,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; 
} 

生成文件

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 

實施例R上的代碼的任何部分未

[email protected]:~/code/calculator$ ./calc 
-> 1 + 2 
0.000000 
-> ^C 
[email protected]:~/code/calculator$ 

反饋理解以及實際問題。乾杯!

回答

3

你是對的,它僅適用於師 - 奇怪的。我的天堂」沒有注意到,對我感到羞恥。 這裏是另一回事嘗試:

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 

預期。

+0

太棒了!謝謝你,它完美的作品。我不完全確定*爲什麼*它的功能完美,但我會研究這一點。 – 2013-03-24 18:22:21

+0

基本上,我只是創建了NUMBER標記,並且分析樹的節點返回了,這是一個雙精度值,如*%union *中所指定的那樣。可能還有其他方法可以做到這一點(我的yacc比較安靜);你可以搜索「野牛簡單計算器」,如果你想要更多的例子.. – 2013-03-24 19:44:38

+0

是的,我聚集了。我的意思是爲什麼原稿不起作用。不管怎麼說,還是要謝謝你。 :) – 2013-03-24 20:03:52

2
在calc.y

:添加第二個定義:

%{ 
#include <stdio.h> 

#define YYSTYPE float 
#define YYSTYPE_IS_DECLARED 
%} 

然後..

./calc 
-> 1/3 
0.333333 
+0

那麼這是清除了一件事。問題是,我仍然不能加/減/乘數!現在司工作,謝謝你。 – 2013-03-24 15:45:34

2

由於#define YYSTYPE未傳播至掃描儀,因此您的建議及其由@Michael進行的更正無效。 %{ %}塊僅用於野牛(對於生成的解析器),它不會在生成的頭中導出。閱讀有關%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。

現在,它如何「起作用」的分工?無意中,因爲float級和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,作爲@邁克爾建議。

+0

這就是爲什麼我應該閱讀完整手冊('ulp!)。非常感謝你,調試提示將非常有用,我可以明白爲什麼現在我出錯了。 – 2013-03-25 21:25:41