简体   繁体   English

带有野牛和弹性的Calc无法正常运行

[英]Calc with bison and flex doesn't work operation negative

I have a problem with this Bison program. 我的Bison程序有问题。 I don't know why Reuse does not work. 我不知道为什么重用不起作用。 For the operation with the negative numbers, I just use the same line for the get the first number and to operate with more operations. 对于带有负数的运算,我只使用同一行来获取第一个数字并进行更多运算。 I just changed the first number to negative. 我只是将第一个数字更改为负数。

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", $1);}
    | expression T_NEWLINE { printf("\tResult: %i\n", $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: %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;}

%%

As said in my comment, the problem is called "unary minus" and it describes the trouble of distinguishing the normal subtraction operation a - b from the negation operation 0 - a if it is abbreviated to -a . 如我的评论中所述,该问题称为“一元减”,它描述了将普通减法运算a - b与否定运算0 - a区别开来的麻烦(如果缩写为-a The common solution is to add a bit of code to make the minus-symbol act as two different operators depending on position. 常见的解决方案是添加一些代码,以使减号根据位置充当两个不同的运算符。 It is done in Bison by implementing a precedence for a non-existing symbol (here NEG ) and bind that precedence to the case -a . 在Bison中,通过为不存在的符号(在此为NEG )实现优先级并将该优先级绑定到case -a

You need to do it twice in your code, once for T_FLOAT and the second time for T_INT . 您需要在代码中执行两次,一次用于T_FLOAT ,第二次用于T_INT I also deleted one line that made no sense, at least for me. 我还删除了一条毫无意义的行,至少对我而言。

calc.y : 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", $1);}
    | expression T_NEWLINE       { printf("\tResult: %i\n", $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: %s\n", s);
    exit(1);
}

The file calclex.l can be left unchanged (although a floating point number is a bit more complicated). 可以将文件calclex.l保留不变(尽管浮点数会更复杂)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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