使用两个以上的参数计算最小值/最大值

时间:2019-05-16 08:07:01

标签: calculator yacc lex

作为作业,我们有一个基本的计算器,该计算器只能执行+操作,并且我们必须实现更多功能。我们必须实现方括号运算符,符号运算符和min max函数。最后的任务之一是扩展min / max函数以使用仅两个以上的参数来计算min / max,这就是我目前所处的任务。

我当前的calc.l lex文件:

%{
extern int yylval;
extern int sym[];
extern int yyerror(char *s);
#include "y.tab.h"
%}

%%

[a-z]   {
           yylval = *yytext - 'a';
           return VARIABLE;
        }

[0-9]+  {
           yylval = atoi(yytext);
           return INTEGER;
        }

[(),]   { return *yytext; }

":="    return ASSIGN;
"+"     return PLUS;
"-"     return MINUS;
"/"     return DIVIDE;
"%"     return MODULO;
"*"     return TIMES;
"<"     return SMAS;
"<="    return SMGAS;
"=="    return IS;
"!="    return NOTIS;
">="    return BGGAS;
">"     return BGAS;

"min"   return MIN;
"max"   return MAX;

"\n"    return NEWLINE;

[ \t]   ;

.       yyerror("Invalid character");

%%

int yywrap() {
 return 1;
}

我当前的calc.y yacc文件:

%{
#include <stdio.h>
int sym[26];
int yylex();
int yyerror(char *s);
%}

%token VARIABLE ASSIGN INTEGER NEWLINE
%left PLUS
%left TIMES
%left MINUS
%left DIVIDE
%left MODULO
%left UMINUS
%left UPLUS
%left SMAS SMGAS IS NOTIS BGAS BGGAS
%left MIN MAX

%%

program: program statement
       |
       ;

statement: expr NEWLINE
             { printf("%d\n", $1); }
         | VARIABLE ASSIGN expr NEWLINE
             { sym[$1] = $3; }
         ;

expr: INTEGER            { $$ = $1; }
      | VARIABLE         { $$ = sym[$1]; }
      | expr PLUS expr   { $$ = $1 + $3; }
      | expr TIMES expr  { $$ = $1 * $3; }
      | expr MINUS expr  { $$ = $1 - $3; }
      | expr DIVIDE expr { $$ = $1 / $3; }
      | expr MODULO expr { $$ = $1 % $3; }
      | '(' expr ')'     { $$ = $2;      }

      | MINUS expr %prec UMINUS { $$ = -$2; }
      | PLUS expr %prec UPLUS { $$ = $2; }

      | expr SMAS  expr   { $$ = $1 < $3;  }
      | expr SMGAS expr   { $$ = $1 <= $3; }
      | expr IS    expr   { $$ = $1 == $3; }
      | expr NOTIS expr   { $$ = $1 != $3; }
      | expr BGGAS expr   { $$ = $1 >= $3; }
      | expr BGAS  expr   { $$ = $1 > $3;  }

      | MIN '(' expr ',' expr ')' { if ($3 < $5){ $$ = $3; } else if ($3 > $5){ $$ = $5; }; }
      | MAX '(' expr ',' expr ')' { if ($3 > $5){ $$ = $3; } else if ($3 < $5){ $$ = $5; }; }

      ;

%%

int yyerror(char *s) {
  fprintf(stderr, "%s\n", s);
  return 0;
}

int main() {
  yyparse();
  return 0;
}

我认为一种解决方案是在min / max函数中用分隔每个值,然后将其计算出来,然后将其返回给min / max函数,但是我不确定如何实现它。我能想到的唯一解决方案是相当复杂的。既然项目不应该那么复杂,我想我缺少一种简单的方法来实现它。

min(5,6)按应返回5,其预期工作方式为(min 6,7,3)并返回3,您可以将其扩展为无数个参数。

你们有一个主意吗?

谢谢!

2 个答案:

答案 0 :(得分:1)

您需要max(x,y)max(x,y,z,q..)

一个可能的解决方案是(... x,z ...)可重复,因此您将不需要几个规则。注意var,它用来确定我们需要什么操作。

expr ',' expr { if(var==1){$$=$1>$3?$1:$3;}else{$$=$1<$3?$1:$3;}; }
'(' expr ')' { $$ = $2;}
MAX  expr    { $$ = $2;}
MAX  expr    { $$ = $2;}

在您的*.l文件中,您需要外部变量(我们将其称为varextern int var

还为maxmin添加一个redex规则,这些规则会将我们的变量设置为1或0:

min { op =0;}
max { op =1;}

其中1是MAX,而MIN是0。

这是在.l文件中完成的,因为我们要在进行操作之前首先设置var

如果在.y文件中进行操作,则var将在操作后设置。

也将变量添加到*.y文件中(int var =0)

.y文件中,您MAXMIN应该是%tokens。另外,将,%right放在第一位/第二位(您可以使用COMMA代替,)。否则,如果您有..4,5*5,.. if,则将首先进行比较,然后将其相乘。

答案 1 :(得分:-1)

AIUI,您应该处理任意数量的最小/最大参数。这样做的标准方法是

  • 首先将参数列表移到单独的规则中,例如arg_list: expr ',' expr ;并返回一个列表(类似对象)。最小值/最大值的(子)规则然后根据返回的列表进行计算。
  • 第二,类似于arg_list规则本身,通过使其递归使expr规则处理1到n个条目。然后,最小/最大规则仍然必须根据列表进行计算,只需要假定任意长度> = 1,而不是长度== 2。