作为作业,我们有一个基本的计算器,该计算器只能执行+操作,并且我们必须实现更多功能。我们必须实现方括号运算符,符号运算符和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,您可以将其扩展为无数个参数。
你们有一个主意吗?
谢谢!
答案 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
文件中,您需要外部变量(我们将其称为var
)
extern int var
。
还为max
和min
添加一个redex规则,这些规则会将我们的变量设置为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,..
if,则将首先进行比较,然后将其相乘。
答案 1 :(得分:-1)
AIUI,您应该处理任意数量的最小/最大参数。这样做的标准方法是
arg_list: expr ',' expr ;
并返回一个列表(类似对象)。最小值/最大值的(子)规则然后根据返回的列表进行计算。arg_list
规则本身,通过使其递归使expr
规则处理1到n个条目。然后,最小/最大规则仍然必须根据列表进行计算,只需要假定任意长度> = 1,而不是长度== 2。