2 /* Copyright (c) 2004-2008 Sami Pietila
3 * Copyright (c) 2008-2009 Robert Ancell
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 #include "mp-equation-private.h"
28 #include "mp-equation-parser.h"
29 #include "mp-equation-lexer.h"
31 // fixme support x log x
32 // treat exp NAME exp as a function always and pass both arguments, i.e.
33 // can do mod using both and all others use $1 * NAME($3)
35 static void set_error
(yyscan_t yyscanner
, int error, const char *token
)
37 _mp_equation_get_extra
(yyscanner
)->error = error;
39 _mp_equation_get_extra
(yyscanner
)->error_token
= strdup
(token
);
42 static void set_result
(yyscan_t yyscanner
, const MPNumber
*x
)
44 mp_set_from_mp
(x
, &(_mp_equation_get_extra
(yyscanner
))->ret
);
48 utf8_next_char
(const char *c
)
51 while
((*c
& 0xC0) == 0x80)
56 static int get_variable
(yyscan_t yyscanner
, const char *name
, int power
, MPNumber
*z
)
60 /* If defined, then get the variable */
61 if
(_mp_equation_get_extra
(yyscanner
)->get_variable
(_mp_equation_get_extra
(yyscanner
), name
, z
)) {
62 mp_xpowy_integer
(z
, power
, z
);
66 /* If has more than one character then assume a multiplication of variables */
67 if
(utf8_next_char
(name
)[0] != '\0') {
69 char *buffer
= malloc
(sizeof
(char) * strlen
(name
));
73 mp_set_from_integer
(1, &value
);
74 for
(c
= name
; *c
!= '\0'; c
= next
) {
77 next
= utf8_next_char
(c
);
78 snprintf
(buffer
, next
- c
+ 1, "%s", c
);
80 if
(!_mp_equation_get_extra
(yyscanner
)->get_variable
(_mp_equation_get_extra
(yyscanner
), buffer
, &t
)) {
85 /* If last term do power */
87 mp_xpowy_integer
(&t
, power
, &t
);
89 mp_multiply
(&value
, &t
, &value
);
94 mp_set_from_mp
(&value
, z
);
98 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_VARIABLE
, name
);
103 static void set_variable
(yyscan_t yyscanner
, const char *name
, MPNumber
*x
)
105 _mp_equation_get_extra
(yyscanner
)->set_variable
(_mp_equation_get_extra
(yyscanner
), name
, x
);
108 static int get_function
(yyscan_t yyscanner
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
110 if
(!_mp_equation_get_extra
(yyscanner
)->get_function
(_mp_equation_get_extra
(yyscanner
), name
, x
, z
)) {
111 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, name
);
117 static void do_not
(yyscan_t yyscanner
, const MPNumber
*x
, MPNumber
*z
)
119 if
(!mp_is_overflow
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
)) {
120 set_error
(yyscanner
, PARSER_ERR_OVERFLOW
, NULL
);
122 mp_not
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
, z
);
125 static char *make_unit
(const char *name
, int power
)
131 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("²") + 1));
132 sprintf
(name2
, "%s²", name
);
134 else if
(power
== 3) {
135 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("³") + 1));
136 sprintf
(name2
, "%s³", name
);
139 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("?") + 1));
140 sprintf
(name2
, "%s?", name
);
146 static void do_conversion
(yyscan_t yyscanner
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
148 if
(!_mp_equation_get_extra
(yyscanner
)->convert
(_mp_equation_get_extra
(yyscanner
), x
, x_units
, z_units
, z
))
149 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_CONVERSION
, NULL
);
155 %name
-prefix
="_mp_equation_"
157 %parse
-param
{yyscan_t yyscanner
}
158 %lex
-param
{yyscan_t yyscanner
}
166 %left
<int_t
> tNUMBER
169 %left tAND tOR tXOR tXNOR
170 %left tMULTIPLY tDIVIDE tMOD MULTIPLICATION
172 %left tROOT tROOT3 tROOT4
173 %left
<name
> tVARIABLE tFUNCTION
174 %right
<integer
> tSUBNUM tSUPNUM tNSUPNUM
175 %left BOOLEAN_OPERATOR
181 %type
<int_t
> exp variable term
188 exp
{ set_result
(yyscanner
, &$1); }
189 | exp
'=' { set_result
(yyscanner
, &$1); }
190 | tVARIABLE
'=' exp
{set_variable
(yyscanner
, $1, &$3); set_result
(yyscanner
, &$3); }
191 | tNUMBER unit tIN unit
{ MPNumber t
; do_conversion
(yyscanner
, &$1, $2, $4, &t
); set_result
(yyscanner
, &t
); free
($2); free
($4); }
192 | unit tIN unit
{ MPNumber x
, t
; mp_set_from_integer
(1, &x
); do_conversion
(yyscanner
, &x
, $1, $3, &t
); set_result
(yyscanner
, &t
); free
($1); free
($3); }
197 | tVARIABLE tSUPNUM
{$$
= make_unit
($1, $2); free
($1);}
199 /* |x| gets confused and thinks = |x|(...||) */
202 '(' exp
')' {mp_set_from_mp
(&$2, &$$
);}
203 |
'|' exp
'|' {mp_abs
(&$2, &$$
);}
204 |
'|' tVARIABLE
'|' {get_variable
(yyscanner
, $2, 1, &$$
); mp_abs
(&$$
, &$$
); free
($2);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
205 |
'|' tNUMBER tVARIABLE
'|' {get_variable
(yyscanner
, $3, 1, &$$
); mp_multiply
(&$2, &$$
, &$$
); mp_abs
(&$$
, &$$
); free
($3);} /* FIXME: Shouldn't need this rule but doesn't parse without it... */
206 | exp
'^' exp
{mp_xpowy
(&$1, &$3, &$$
);}
207 | exp tSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
208 | exp tNSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
209 | exp
'!' {mp_factorial
(&$1, &$$
);}
210 | variable
{mp_set_from_mp
(&$1, &$$
);}
211 | tNUMBER variable %prec MULTIPLICATION
{mp_multiply
(&$1, &$2, &$$
);}
212 | tSUBTRACT exp %prec UNARY_MINUS
{mp_invert_sign
(&$2, &$$
);}
213 | tADD tNUMBER %prec UNARY_PLUS
{mp_set_from_mp
(&$2, &$$
);}
214 | exp tDIVIDE exp
{mp_divide
(&$1, &$3, &$$
);}
215 | exp tMOD exp
{mp_modulus_divide
(&$1, &$3, &$$
);}
216 | exp tMULTIPLY exp
{mp_multiply
(&$1, &$3, &$$
);}
217 | exp tADD exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, 100, &$3); mp_divide_integer
(&$3, 100, &$3); mp_multiply
(&$1, &$3, &$$
);}
218 | exp tSUBTRACT exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, -100, &$3); mp_divide_integer
(&$3, -100, &$3); mp_multiply
(&$1, &$3, &$$
);}
219 | exp tADD exp
{mp_add
(&$1, &$3, &$$
);}
220 | exp tSUBTRACT exp
{mp_subtract
(&$1, &$3, &$$
);}
221 | exp
'%' {mp_divide_integer
(&$1, 100, &$$
);}
222 | tNOT exp
{do_not
(yyscanner
, &$2, &$$
);}
223 | exp tAND exp %prec BOOLEAN_OPERATOR
{mp_and
(&$1, &$3, &$$
);}
224 | exp tOR exp %prec BOOLEAN_OPERATOR
{mp_or
(&$1, &$3, &$$
);}
225 | exp tXOR exp %prec BOOLEAN_OPERATOR
{mp_xor
(&$1, &$3, &$$
);}
226 | tNUMBER
{mp_set_from_mp
(&$1, &$$
);}
231 term
{mp_set_from_mp
(&$1, &$$
);}
232 | tFUNCTION exp
{if
(!get_function
(yyscanner
, $1, &$2, &$$
)) YYABORT; free
($1);}
233 | tFUNCTION tSUPNUM exp
{if
(!get_function
(yyscanner
, $1, &$3, &$$
)) YYABORT; mp_xpowy_integer
(&$$
, $2, &$$
); free
($1);}
234 | tVARIABLE exp
{set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, $1); free
($1); YYABORT;}
235 | tVARIABLE tSUPNUM exp
{set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, $1); free
($1); YYABORT;}
236 | tSUBNUM tROOT exp
{mp_root
(&$3, $1, &$$
);}
237 | tROOT exp
{mp_sqrt
(&$2, &$$
);}
238 | tROOT3 exp
{mp_root
(&$2, 3, &$$
);}
239 | tROOT4 exp
{mp_root
(&$2, 4, &$$
);}
243 tVARIABLE
{if
(!get_variable
(yyscanner
, $1, 1, &$$
)) YYABORT; free
($1);}
244 | tVARIABLE tSUPNUM
{if
(!get_variable
(yyscanner
, $1, $2, &$$
)) YYABORT; free
($1);}
245 | term term
{mp_multiply
(&$1, &$2, &$$
);}