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可以保持不变(虽然浮点数有点复杂)。