使用两个以上的参数计算 min/max
Calculating min/max with more than two parameters
作为家庭作业,我们得到了一个只能做+运算的基本计算器,我们必须实现更多的功能。我们必须实现括号运算符、符号运算符和最小最大函数。最后一项任务是扩展 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", ); }
| VARIABLE ASSIGN expr NEWLINE
{ sym[] = ; }
;
expr: INTEGER { $$ = ; }
| VARIABLE { $$ = sym[]; }
| expr PLUS expr { $$ = + ; }
| expr TIMES expr { $$ = * ; }
| expr MINUS expr { $$ = - ; }
| expr DIVIDE expr { $$ = / ; }
| expr MODULO expr { $$ = % ; }
| '(' expr ')' { $$ = ; }
| MINUS expr %prec UMINUS { $$ = -; }
| PLUS expr %prec UPLUS { $$ = ; }
| expr SMAS expr { $$ = < ; }
| expr SMGAS expr { $$ = <= ; }
| expr IS expr { $$ = == ; }
| expr NOTIS expr { $$ = != ; }
| expr BGGAS expr { $$ = >= ; }
| expr BGAS expr { $$ = > ; }
| MIN '(' expr ',' expr ')' { if ( < ){ $$ = ; } else if ( > ){ $$ = ; }; }
| MAX '(' expr ',' expr ')' { if ( > ){ $$ = ; } else if ( < ){ $$ = ; }; }
;
%%
int yyerror(char *s) {
fprintf(stderr, "%s\n", s);
return 0;
}
int main() {
yyparse();
return 0;
}
我认为一种解决方案是在 min/max 函数中用 , 分隔每个值并计算它,然后将其返回给 min/max 函数,但我不确定如何实施它。我能想到的唯一解决方案相当复杂。由于项目不应该那么复杂,我想我缺少一种简单的方法。
min(5, 6) returns 5 它应该是这样的,它应该如何工作的预期方式是 (min 6, 7, 3) 和 return 3 你可以扩展它有无数个参数。
你们有什么想法吗?
谢谢!
AIUI 你应该处理 min/max 的任意数量的参数。这样做的标准方法是
- 首先将参数列表移动到单独的规则中,例如
arg_list: expr ',' expr ;
并使 return 成为一个列表(类对象)。 min/max 的(子)规则然后根据 returned 列表进行计算。
- 其次,通过使
arg_list
规则递归处理 1 到 n 个条目,类似于 expr
规则本身。 min/max 规则仍然需要根据列表进行计算,只需假设任意长度 >= 1,而不是长度 == 2。
您需要 max(x,y)
和 max(x,y,z,q..)
。
一个可能的解决方案是 (... x , z ...) 可重复的,因此您将需要很少的规则。注意var
,它是用来判断我们需要什么操作的。
expr ',' expr { if(var==1){$$=>?:;}else{$$=<?:;}; }
'(' expr ')' { $$ = ;}
MAX expr { $$ = ;}
MAX expr { $$ = ;}
在你的 *.l
文件中你需要外部变量(我们称之为 var
)
extern int var
。
还为 max
和 min
添加一个 redex 规则,这会将我们的变量设置为 1 或 0:
min { op =0;}
max { op =1;}
其中 1 是最大值,最小值是 0。
这是在 .l
文件中完成的,因为我们想在进行操作之前先设置 var
。
如果在.y
文件中进行操作,var
将在操作后设置。
也将变量添加到您的 *.y
文件 (int var =0)
。
在 .y
文件中,您 MAX
和 MIN
应该是 %tokens
。另外,在 first/second 位置添加 ,
和 %right
(您可以使用 COMMA
而不是 ,
)。否则如果你有 ..4,5*5,..
if 将首先比较然后乘以它。
作为家庭作业,我们得到了一个只能做+运算的基本计算器,我们必须实现更多的功能。我们必须实现括号运算符、符号运算符和最小最大函数。最后一项任务是扩展 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", ); }
| VARIABLE ASSIGN expr NEWLINE
{ sym[] = ; }
;
expr: INTEGER { $$ = ; }
| VARIABLE { $$ = sym[]; }
| expr PLUS expr { $$ = + ; }
| expr TIMES expr { $$ = * ; }
| expr MINUS expr { $$ = - ; }
| expr DIVIDE expr { $$ = / ; }
| expr MODULO expr { $$ = % ; }
| '(' expr ')' { $$ = ; }
| MINUS expr %prec UMINUS { $$ = -; }
| PLUS expr %prec UPLUS { $$ = ; }
| expr SMAS expr { $$ = < ; }
| expr SMGAS expr { $$ = <= ; }
| expr IS expr { $$ = == ; }
| expr NOTIS expr { $$ = != ; }
| expr BGGAS expr { $$ = >= ; }
| expr BGAS expr { $$ = > ; }
| MIN '(' expr ',' expr ')' { if ( < ){ $$ = ; } else if ( > ){ $$ = ; }; }
| MAX '(' expr ',' expr ')' { if ( > ){ $$ = ; } else if ( < ){ $$ = ; }; }
;
%%
int yyerror(char *s) {
fprintf(stderr, "%s\n", s);
return 0;
}
int main() {
yyparse();
return 0;
}
我认为一种解决方案是在 min/max 函数中用 , 分隔每个值并计算它,然后将其返回给 min/max 函数,但我不确定如何实施它。我能想到的唯一解决方案相当复杂。由于项目不应该那么复杂,我想我缺少一种简单的方法。
min(5, 6) returns 5 它应该是这样的,它应该如何工作的预期方式是 (min 6, 7, 3) 和 return 3 你可以扩展它有无数个参数。
你们有什么想法吗?
谢谢!
AIUI 你应该处理 min/max 的任意数量的参数。这样做的标准方法是
- 首先将参数列表移动到单独的规则中,例如
arg_list: expr ',' expr ;
并使 return 成为一个列表(类对象)。 min/max 的(子)规则然后根据 returned 列表进行计算。 - 其次,通过使
arg_list
规则递归处理 1 到 n 个条目,类似于expr
规则本身。 min/max 规则仍然需要根据列表进行计算,只需假设任意长度 >= 1,而不是长度 == 2。
您需要 max(x,y)
和 max(x,y,z,q..)
。
一个可能的解决方案是 (... x , z ...) 可重复的,因此您将需要很少的规则。注意var
,它是用来判断我们需要什么操作的。
expr ',' expr { if(var==1){$$=>?:;}else{$$=<?:;}; }
'(' expr ')' { $$ = ;}
MAX expr { $$ = ;}
MAX expr { $$ = ;}
在你的 *.l
文件中你需要外部变量(我们称之为 var
)
extern int var
。
还为 max
和 min
添加一个 redex 规则,这会将我们的变量设置为 1 或 0:
min { op =0;}
max { op =1;}
其中 1 是最大值,最小值是 0。
这是在 .l
文件中完成的,因为我们想在进行操作之前先设置 var
。
如果在.y
文件中进行操作,var
将在操作后设置。
也将变量添加到您的 *.y
文件 (int var =0)
。
在 .y
文件中,您 MAX
和 MIN
应该是 %tokens
。另外,在 first/second 位置添加 ,
和 %right
(您可以使用 COMMA
而不是 ,
)。否则如果你有 ..4,5*5,..
if 将首先比较然后乘以它。