3 * Copyright (C) 2004-2008 Sami Pietila
4 * Copyright (C) 2008-2011 Robert Ancell
6 * This program is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 2 of the License, or (at your option) any later
9 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
19 #include "mp-equation-private.h"
20 #include "mp-equation-parser.h"
21 #include "mp-equation-lexer.h"
23 // fixme support x log x
24 // treat exp NAME exp as a function always and pass both arguments, i.e.
25 // can do mod using both and all others use $1 * NAME($3)
27 static void set_error
(yyscan_t yyscanner
, int error, const char *token
)
29 _mp_equation_get_extra
(yyscanner
)->error = error;
31 _mp_equation_get_extra
(yyscanner
)->error_token
= strdup
(token
);
34 static void set_result
(yyscan_t yyscanner
, const MPNumber
*x
)
36 mp_set_from_mp
(x
, &(_mp_equation_get_extra
(yyscanner
))->ret
);
40 utf8_next_char
(const char *c
)
43 while
((*c
& 0xC0) == 0x80)
48 static int get_variable
(yyscan_t yyscanner
, const char *name
, int power
, MPNumber
*z
)
52 /* If defined, then get the variable */
53 if
(_mp_equation_get_extra
(yyscanner
)->get_variable
(_mp_equation_get_extra
(yyscanner
), name
, z
)) {
54 mp_xpowy_integer
(z
, power
, z
);
58 /* If has more than one character then assume a multiplication of variables */
59 if
(utf8_next_char
(name
)[0] != '\0') {
61 char *buffer
= malloc
(sizeof
(char) * strlen
(name
));
65 mp_set_from_integer
(1, &value
);
66 for
(c
= name
; *c
!= '\0'; c
= next
) {
69 next
= utf8_next_char
(c
);
70 snprintf
(buffer
, next
- c
+ 1, "%s", c
);
72 if
(!_mp_equation_get_extra
(yyscanner
)->get_variable
(_mp_equation_get_extra
(yyscanner
), buffer
, &t
)) {
77 /* If last term do power */
79 mp_xpowy_integer
(&t
, power
, &t
);
81 mp_multiply
(&value
, &t
, &value
);
86 mp_set_from_mp
(&value
, z
);
90 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_VARIABLE
, name
);
95 static void set_variable
(yyscan_t yyscanner
, const char *name
, MPNumber
*x
)
97 _mp_equation_get_extra
(yyscanner
)->set_variable
(_mp_equation_get_extra
(yyscanner
), name
, x
);
100 static int get_function
(yyscan_t yyscanner
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
102 if
(!_mp_equation_get_extra
(yyscanner
)->get_function
(_mp_equation_get_extra
(yyscanner
), name
, x
, z
)) {
103 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, name
);
109 static int get_inverse_function
(yyscan_t yyscanner
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
114 inv_name
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("⁻¹") + 1));
115 strcpy
(inv_name
, name
);
116 strcat
(inv_name
, "⁻¹");
117 result
= get_function
(yyscanner
, inv_name
, x
, z
);
123 static void do_not
(yyscan_t yyscanner
, const MPNumber
*x
, MPNumber
*z
)
125 if
(!mp_is_overflow
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
)) {
126 set_error
(yyscanner
, PARSER_ERR_OVERFLOW
, NULL
);
128 mp_not
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
, z
);
131 static char *make_unit
(const char *name
, int power
)
137 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("²") + 1));
138 sprintf
(name2
, "%s²", name
);
140 else if
(power
== 3) {
141 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("³") + 1));
142 sprintf
(name2
, "%s³", name
);
145 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("?") + 1));
146 sprintf
(name2
, "%s?", name
);
152 static void do_conversion
(yyscan_t yyscanner
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
154 if
(!_mp_equation_get_extra
(yyscanner
)->convert
(_mp_equation_get_extra
(yyscanner
), x
, x_units
, z_units
, z
))
155 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_CONVERSION
, NULL
);
161 %name
-prefix
="_mp_equation_"
163 %parse
-param
{yyscan_t yyscanner
}
164 %lex
-param
{yyscan_t yyscanner
}
172 %left
<int_t
> tNUMBER
173 %left tLFLOOR tRFLOOR tLCEILING tRCEILING
176 %left tAND tOR tXOR tXNOR
177 %left tMULTIPLY MULTIPLICATION
180 %left tROOT tROOT3 tROOT4
181 %left
<name
> tVARIABLE tFUNCTION
182 %right
<integer
> tSUBNUM tSUPNUM tNSUPNUM
183 %left BOOLEAN_OPERATOR
189 %type
<int_t
> exp variable term
196 exp
{ set_result
(yyscanner
, &$1); }
197 | exp
'=' { set_result
(yyscanner
, &$1); }
198 | tVARIABLE
'=' exp
{set_variable
(yyscanner
, $1, &$3); set_result
(yyscanner
, &$3); }
199 | tNUMBER unit tIN unit
{ MPNumber t
; do_conversion
(yyscanner
, &$1, $2, $4, &t
); set_result
(yyscanner
, &t
); free
($2); free
($4); }
200 | 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); }
205 | tVARIABLE tSUPNUM
{$$
= make_unit
($1, $2); free
($1);}
207 /* |x| gets confused and thinks = |x|(...||) */
210 '(' exp
')' {mp_set_from_mp
(&$2, &$$
);}
211 | exp tDIVIDE exp
'(' exp
')' {mp_divide
(&$1, &$3, &$$
); mp_multiply
(&$5, &$$
, &$$
);}
212 | exp tMOD exp
'(' exp
')' {mp_modulus_divide
(&$1, &$3, &$$
); mp_multiply
(&$5, &$$
, &$$
);}
213 | exp
'(' exp
')' {mp_multiply
(&$1, &$3, &$$
);}
214 | tLFLOOR exp tRFLOOR
{mp_floor
(&$2, &$$
);}
215 | tLCEILING exp tRCEILING
{mp_ceiling
(&$2, &$$
);}
216 |
'[' exp
']' {mp_round
(&$2, &$$
);}
217 |
'{' exp
'}' {mp_fractional_part
(&$2, &$$
);}
218 |
'|' exp
'|' {mp_abs
(&$2, &$$
);}
219 | exp
'^' exp
{mp_xpowy
(&$1, &$3, &$$
);}
220 | exp tSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
221 | exp tNSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
222 | exp
'!' {mp_factorial
(&$1, &$$
);}
223 | variable
{mp_set_from_mp
(&$1, &$$
);}
224 | tNUMBER variable %prec MULTIPLICATION
{mp_multiply
(&$1, &$2, &$$
);}
225 | tSUBTRACT exp %prec UNARY_MINUS
{mp_invert_sign
(&$2, &$$
);}
226 | tADD tNUMBER %prec UNARY_PLUS
{mp_set_from_mp
(&$2, &$$
);}
227 | exp tDIVIDE exp
{mp_divide
(&$1, &$3, &$$
);}
228 | exp tMOD exp
{mp_modulus_divide
(&$1, &$3, &$$
);}
229 | exp tMULTIPLY exp
{mp_multiply
(&$1, &$3, &$$
);}
230 | exp tADD exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, 100, &$3); mp_divide_integer
(&$3, 100, &$3); mp_multiply
(&$1, &$3, &$$
);}
231 | exp tSUBTRACT exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, -100, &$3); mp_divide_integer
(&$3, -100, &$3); mp_multiply
(&$1, &$3, &$$
);}
232 | exp tADD exp
{mp_add
(&$1, &$3, &$$
);}
233 | exp tSUBTRACT exp
{mp_subtract
(&$1, &$3, &$$
);}
234 | exp
'%' {mp_divide_integer
(&$1, 100, &$$
);}
235 | tNOT exp
{do_not
(yyscanner
, &$2, &$$
);}
236 | exp tAND exp %prec BOOLEAN_OPERATOR
{mp_and
(&$1, &$3, &$$
);}
237 | exp tOR exp %prec BOOLEAN_OPERATOR
{mp_or
(&$1, &$3, &$$
);}
238 | exp tXOR exp %prec BOOLEAN_OPERATOR
{mp_xor
(&$1, &$3, &$$
);}
239 | tNUMBER
{mp_set_from_mp
(&$1, &$$
);}
244 term
{mp_set_from_mp
(&$1, &$$
);}
245 | tFUNCTION exp
{if
(!get_function
(yyscanner
, $1, &$2, &$$
)) YYABORT; free
($1);}
246 | tFUNCTION tSUPNUM exp
{if
(!get_function
(yyscanner
, $1, &$3, &$$
)) YYABORT; mp_xpowy_integer
(&$$
, $2, &$$
); free
($1);}
247 | tFUNCTION tNSUPNUM exp
{if
(!get_inverse_function
(yyscanner
, $1, &$3, &$$
)) YYABORT; mp_xpowy_integer
(&$$
, -$2, &$$
); free
($1);}
248 | tVARIABLE tSUPNUM exp
{set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, $1); free
($1); YYABORT;}
249 | tSUBNUM tROOT exp
{mp_root
(&$3, $1, &$$
);}
250 | tROOT exp
{mp_sqrt
(&$2, &$$
);}
251 | tROOT3 exp
{mp_root
(&$2, 3, &$$
);}
252 | tROOT4 exp
{mp_root
(&$2, 4, &$$
);}
256 tVARIABLE
{if
(!get_variable
(yyscanner
, $1, 1, &$$
)) YYABORT; free
($1);}
257 | tVARIABLE tSUPNUM
{if
(!get_variable
(yyscanner
, $1, $2, &$$
)) YYABORT; free
($1);}
258 | term term
{mp_multiply
(&$1, &$2, &$$
);}