As a Homework we got a basic calculator which can only do + operations and we have to implement more functions. We had to implement the bracket operator, sign operators and min max functions. One of the last tasks is to expand the min/max function to calculate min/max with more than only two parameters and thats the task where I'm currently stuck.
My current calc.l lex file:
%{
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;
}
My current calc.y yacc file:
%{
#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;
}
I think one solution would be to seperate each value with an , in the min/max function and calculate it and then give it back to the min/max function, but I'm not sure how to implement it. The only solution I could think of is rather complex. Since the project shouldn't be that complex I think I'm missing an easy way to do it.
min(5, 6) returns 5 as it should, and the expected way how it should work is (min 6, 7, 3) and return 3 and you can expend it to an infinite number of parameters.
Does any of you have an Idea?
Thanks!
You need max(x,y)
and max(x,y,z,q..)
.
One possible solution is (... x , z ...) repeatable so you will need few rules for that. Note var
, it is use to determine what operation we need.
expr ',' expr { if(var==1){$$=$1>$3?$1:$3;}else{$$=$1<$3?$1:$3;}; }
'(' expr ')' { $$ = $2;}
MAX expr { $$ = $2;}
MAX expr { $$ = $2;}
In your *.l
file you need external variable (let's call it var
)
extern int var
.
Add also a redex rule for max
and min
, which will set our variable to 1 or 0:
min { op =0;}
max { op =1;}
Where 1 is MAX and MIN is 0.
This is done in .l
file because we want to set the var
first before me make the operations.
If you do it in .y
file, the var
will be set after the operations.
Add the variable to your *.y
file too (int var =0)
.
In .y
file you MAX
and MIN
should be %tokens
. Plus, add ,
with %right
on first/second place (you can use COMMA
instead ,
). Otherwise if you have ..4,5*5,..
if will first compare and then it will multiply it.