1 /* Copyright (C) 2006 Sergei Golubchik
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License version 2
5 as published by the Free Software Foundation
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
23 void yyerror (char const *);
25 char *yy_err
, *yy_str
;
27 int yy_nsum
, yy_ndiff
;
29 static double e_num
(Expr
*me
, Econtext
*ctx
) {
33 static double e_var
(Expr
*me
, Econtext
*ctx
) {
34 char c
, *s
, *e
; double v
;
35 if
(ctx
->pmatch
[me
->val.var
].rm_so
< 0) return
0;
36 s
=ctx
->str
+ctx
->pmatch
[me
->val.var
].rm_so
;
37 e
=ctx
->str
+ctx
->pmatch
[me
->val.var
].rm_eo
;
38 c
=*e
; *e
=0; v
=strtod
(s
, 0); *e
=c
;
42 static double e_if
(Expr
*me
, Econtext
*ctx
) {
43 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) ?
44 me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
) :
45 me
->val.arg
[2]->eval
(me
->val.arg
[2], ctx
) ;
48 static double e_lt
(Expr
*me
, Econtext
*ctx
) {
49 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) < me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
52 static double e_gt
(Expr
*me
, Econtext
*ctx
) {
53 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) > me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
56 static double e_add
(Expr
*me
, Econtext
*ctx
) {
57 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) + me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
60 static double e_sub
(Expr
*me
, Econtext
*ctx
) {
61 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) - me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
64 static double e_mul
(Expr
*me
, Econtext
*ctx
) {
65 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) * me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
68 static double e_div
(Expr
*me
, Econtext
*ctx
) {
69 return me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
) / me
->val.arg
[1]->eval
(me
->val.arg
[1], ctx
);
72 static double e_sum
(Expr
*me
, Econtext
*ctx
) {
73 int slot
=(long)me
->val.arg
[1];
74 return ctx
->sum_acc
[slot
]+=me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
);
77 static double e_diff
(Expr
*me
, Econtext
*ctx
) {
79 int slot
=(long)me
->val.arg
[1];
80 ctx
->diff_new
[slot
]=e
=me
->val.arg
[0]->eval
(me
->val.arg
[0], ctx
);
81 v
=e
-ctx
->diff_old
[slot
];
85 static Expr
*new_num
(double val
) {
86 Expr
*e
=malloc
(sizeof
(Expr
));
92 static Expr
*new_var
(int var
) {
93 Expr
*e
=malloc
(sizeof
(Expr
));
99 static Expr
*new_op
(Expr
*e1
, Expr
*e2
, double (*eval
)(Expr
*, Econtext
*))
101 Expr
*e
=calloc
(1, sizeof
(Expr
));
118 /* Bison declarations. */
130 %%
/* The grammar follows. */
132 input: expr
{ yy_expr
=$1; }
134 expr: NUM
{ $$
=new_num
($1); }
137 yyerror("too large register number");
142 | SUM
'(' expr
')' { $$
=new_op
($3, (Expr
*)(long)yy_nsum
++, e_sum
);}
143 | DIFF
'(' expr
')' { $$
=new_op
($3, (Expr
*)(long)yy_ndiff
++, e_diff
);}
144 | expr
'?' expr
':' expr
{ $$
=new_op
($1, $3, e_if
); $$
->val.arg
[2]=$5; }
145 | expr
'<' expr
{ $$
=new_op
($1, $3, e_lt
); }
146 | expr
'>' expr
{ $$
=new_op
($1, $3, e_gt
); }
147 | expr
'+' expr
{ $$
=new_op
($1, $3, e_add
); }
148 | expr
'-' expr
{ $$
=new_op
($1, $3, e_sub
); }
149 | expr
'*' expr
{ $$
=new_op
($1, $3, e_mul
); }
150 | expr
'/' expr
{ $$
=new_op
($1, $3, e_div
); }
151 |
'-' expr %prec NEG
{ $$
=new_op
(new_num
(0) ,$2, e_sub
); }
152 |
'+' expr %prec NEG
{ $$
=$2; }
153 |
'(' expr
')' { $$
=$2; }
160 #define prefix(S,CONST) !strncasecmp((S),CONST,sizeof(CONST)-1)
164 while
(isspace
(*yy_str
)) yy_str
++;
165 if
(isdigit
(*yy_str
)) {
166 yylval.val
=strtod
(yy_str
, &yy_str
);
169 if
(*yy_str
== '\\') {
170 if
(!isdigit
(*++yy_str
)) return
'\\';
171 yylval.var
=strtol
(yy_str
, &yy_str
, 10);
174 if
(prefix
(yy_str
, "sum")) {
178 if
(prefix
(yy_str
, "diff")) {
185 /* Called by yyparse on error. */
187 yyerror (char const *s
)