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 int get_inverse_function
(yyscan_t yyscanner
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
122 inv_name
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("⁻¹") + 1));
123 strcpy
(inv_name
, name
);
124 strcat
(inv_name
, "⁻¹");
125 result
= get_function
(yyscanner
, inv_name
, x
, z
);
131 static void do_not
(yyscan_t yyscanner
, const MPNumber
*x
, MPNumber
*z
)
133 if
(!mp_is_overflow
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
)) {
134 set_error
(yyscanner
, PARSER_ERR_OVERFLOW
, NULL
);
136 mp_not
(x
, _mp_equation_get_extra
(yyscanner
)->options
->wordlen
, z
);
139 static char *make_unit
(const char *name
, int power
)
145 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("²") + 1));
146 sprintf
(name2
, "%s²", name
);
148 else if
(power
== 3) {
149 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("³") + 1));
150 sprintf
(name2
, "%s³", name
);
153 name2
= malloc
(sizeof
(char) * (strlen
(name
) + strlen
("?") + 1));
154 sprintf
(name2
, "%s?", name
);
160 static void do_conversion
(yyscan_t yyscanner
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
162 if
(!_mp_equation_get_extra
(yyscanner
)->convert
(_mp_equation_get_extra
(yyscanner
), x
, x_units
, z_units
, z
))
163 set_error
(yyscanner
, PARSER_ERR_UNKNOWN_CONVERSION
, NULL
);
169 %name
-prefix
="_mp_equation_"
171 %parse
-param
{yyscan_t yyscanner
}
172 %lex
-param
{yyscan_t yyscanner
}
180 %left
<int_t
> tNUMBER
181 %left tLFLOOR tRFLOOR tLCEILING tRCEILING
184 %left tAND tOR tXOR tXNOR
185 %left tMULTIPLY tDIVIDE tMOD MULTIPLICATION
187 %left tROOT tROOT3 tROOT4
188 %left
<name
> tVARIABLE tFUNCTION
189 %right
<integer
> tSUBNUM tSUPNUM tNSUPNUM
190 %left BOOLEAN_OPERATOR
196 %type
<int_t
> exp variable term
203 exp
{ set_result
(yyscanner
, &$1); }
204 | exp
'=' { set_result
(yyscanner
, &$1); }
205 | tVARIABLE
'=' exp
{set_variable
(yyscanner
, $1, &$3); set_result
(yyscanner
, &$3); }
206 | tNUMBER unit tIN unit
{ MPNumber t
; do_conversion
(yyscanner
, &$1, $2, $4, &t
); set_result
(yyscanner
, &t
); free
($2); free
($4); }
207 | 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); }
212 | tVARIABLE tSUPNUM
{$$
= make_unit
($1, $2); free
($1);}
214 /* |x| gets confused and thinks = |x|(...||) */
217 '(' exp
')' {mp_set_from_mp
(&$2, &$$
);}
218 | exp
'(' exp
')' {mp_multiply
(&$1, &$3, &$$
);}
219 | tLFLOOR exp tRFLOOR
{mp_floor
(&$2, &$$
);}
220 | tLCEILING exp tRCEILING
{mp_ceiling
(&$2, &$$
);}
221 |
'[' exp
']' {mp_round
(&$2, &$$
);}
222 |
'{' exp
'}' {mp_fractional_part
(&$2, &$$
);}
223 |
'|' exp
'|' {mp_abs
(&$2, &$$
);}
224 | exp
'^' exp
{mp_xpowy
(&$1, &$3, &$$
);}
225 | exp tSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
226 | exp tNSUPNUM
{mp_xpowy_integer
(&$1, $2, &$$
);}
227 | exp
'!' {mp_factorial
(&$1, &$$
);}
228 | variable
{mp_set_from_mp
(&$1, &$$
);}
229 | tNUMBER variable %prec MULTIPLICATION
{mp_multiply
(&$1, &$2, &$$
);}
230 | tSUBTRACT exp %prec UNARY_MINUS
{mp_invert_sign
(&$2, &$$
);}
231 | tADD tNUMBER %prec UNARY_PLUS
{mp_set_from_mp
(&$2, &$$
);}
232 | exp tDIVIDE exp
{mp_divide
(&$1, &$3, &$$
);}
233 | exp tMOD exp
{mp_modulus_divide
(&$1, &$3, &$$
);}
234 | exp tMULTIPLY exp
{mp_multiply
(&$1, &$3, &$$
);}
235 | exp tADD exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, 100, &$3); mp_divide_integer
(&$3, 100, &$3); mp_multiply
(&$1, &$3, &$$
);}
236 | exp tSUBTRACT exp
'%' %prec PERCENTAGE
{mp_add_integer
(&$3, -100, &$3); mp_divide_integer
(&$3, -100, &$3); mp_multiply
(&$1, &$3, &$$
);}
237 | exp tADD exp
{mp_add
(&$1, &$3, &$$
);}
238 | exp tSUBTRACT exp
{mp_subtract
(&$1, &$3, &$$
);}
239 | exp
'%' {mp_divide_integer
(&$1, 100, &$$
);}
240 | tNOT exp
{do_not
(yyscanner
, &$2, &$$
);}
241 | exp tAND exp %prec BOOLEAN_OPERATOR
{mp_and
(&$1, &$3, &$$
);}
242 | exp tOR exp %prec BOOLEAN_OPERATOR
{mp_or
(&$1, &$3, &$$
);}
243 | exp tXOR exp %prec BOOLEAN_OPERATOR
{mp_xor
(&$1, &$3, &$$
);}
244 | tNUMBER
{mp_set_from_mp
(&$1, &$$
);}
249 term
{mp_set_from_mp
(&$1, &$$
);}
250 | tFUNCTION exp
{if
(!get_function
(yyscanner
, $1, &$2, &$$
)) YYABORT; free
($1);}
251 | tFUNCTION tSUPNUM exp
{if
(!get_function
(yyscanner
, $1, &$3, &$$
)) YYABORT; mp_xpowy_integer
(&$$
, $2, &$$
); free
($1);}
252 | tFUNCTION tNSUPNUM exp
{if
(!get_inverse_function
(yyscanner
, $1, &$3, &$$
)) YYABORT; mp_xpowy_integer
(&$$
, -$2, &$$
); free
($1);}
253 | tVARIABLE tSUPNUM exp
{set_error
(yyscanner
, PARSER_ERR_UNKNOWN_FUNCTION
, $1); free
($1); YYABORT;}
254 | tSUBNUM tROOT exp
{mp_root
(&$3, $1, &$$
);}
255 | tROOT exp
{mp_sqrt
(&$2, &$$
);}
256 | tROOT3 exp
{mp_root
(&$2, 3, &$$
);}
257 | tROOT4 exp
{mp_root
(&$2, 4, &$$
);}
261 tVARIABLE
{if
(!get_variable
(yyscanner
, $1, 1, &$$
)) YYABORT; free
($1);}
262 | tVARIABLE tSUPNUM
{if
(!get_variable
(yyscanner
, $1, $2, &$$
)) YYABORT; free
($1);}
263 | term term
{mp_multiply
(&$1, &$2, &$$
);}