Расчет мин / макс с более чем двумя параметрами - PullRequest
3 голосов
/ 16 мая 2019

В качестве домашней работы мы получили базовый калькулятор, который может выполнять только + операции, и нам нужно реализовать больше функций.Нам пришлось реализовать оператор скобок, операторы знака и функции min max.Одна из последних задач - расширить функцию min / max для вычисления минимума / максимума, используя только два параметра, и это та задача, в которой я сейчас застрял.

Мой текущий файл lex calc.l:

%{
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, как должно, и ожидаемый способ, которым он должен работать (мин 6, 7, 3) и верните 3, и вы можете потратить его на бесконечное количество параметров.

Есть ли у кого-нибудь из вас идея?

Спасибо!

Ответы [ 2 ]

1 голос
/ 17 мая 2019

Вам нужно 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 вам нужна внешняя переменная (назовем ее var) extern int var.

Добавьте также правило переопределения для max и min, которое установит нашу переменную в 1 или 0:

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

Где 1 - MAX, а MIN - 0.

Это делается в файле .l, потому что мы хотим установить var, прежде чем я сделаю операции.

Если вы сделаете это в файле .y, после операций будет установлен var.

Добавьте переменную в ваш файл *.y тоже (int var =0).

В .y файле вы MAX и MIN должны быть %tokens.Кроме того, добавьте , с %right на первое / второе место (вместо , можно использовать COMMA).В противном случае, если у вас есть ..4,5*5,.., то сначала сравните, а затем умножьте его.

0 голосов
/ 16 мая 2019

AIUI вы должны обработать произвольное количество аргументов до мин / макс. Стандартный способ сделать это будет

  • сначала переместите список аргументов в отдельное правило, например, arg_list: expr ',' expr ; и заставить его возвращать список (-подобный объект). (Sub) правила для min / max затем рассчитываются по этому возвращенному списку.
  • Во-вторых, заставьте это правило arg_list обрабатывать от 1 до n записей, сделав его рекурсивным, аналогично самому правилу expr. Тогда правила min / max все равно должны вычисляться по списку, просто нужно принять произвольную длину> = 1 вместо длины == 2.
...