2 * Copyright (C) 2004-2008 Sami Pietila
3 * Copyright (C) 2008-2011 Robert Ancell.
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 2 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
14 #include "mp-equation-private.h"
15 #include "mp-equation-parser.h"
16 #include "mp-equation-lexer.h"
18 extern int _mp_equation_parse(yyscan_t yyscanner
);
22 variable_is_defined(MPEquationParserState
*state
, const char *name
)
24 /* FIXME: Make more generic */
25 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
27 if (state
->options
->variable_is_defined
)
28 return state
->options
->variable_is_defined(name
, state
->options
->callback_data
);
34 get_variable(MPEquationParserState
*state
, const char *name
, MPNumber
*z
)
38 if (strcmp(name
, "e") == 0)
40 else if (strcmp(name
, "i") == 0)
42 else if (strcmp(name
, "π") == 0)
44 else if (state
->options
->get_variable
)
45 result
= state
->options
->get_variable(name
, z
, state
->options
->callback_data
);
53 set_variable(MPEquationParserState
*state
, const char *name
, const MPNumber
*x
)
55 // Reserved words, e, π, mod, and, or, xor, not, abs, log, ln, sqrt, int, frac, sin, cos, ...
56 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
59 if (state
->options
->set_variable
)
60 state
->options
->set_variable(name
, x
, state
->options
->callback_data
);
63 // FIXME: Accept "2sin" not "2 sin", i.e. let the tokenizer collect the multiple
64 // Parser then distinguishes between "sin"="s*i*n" or "sin5" = "sin 5" = "sin(5)"
65 // i.e. numbers+letters = variable or function depending on following arg
66 // letters+numbers = numbers+letters+numbers = function
70 sub_atoi(const char *data
)
73 const char *digits
[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL
};
76 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
79 data
+= strlen(digits
[i
]);
80 value
= value
* 10 + i
;
81 } while(*data
!= '\0');
87 super_atoi(const char *data
)
89 int i
, sign
= 1, value
= 0;
90 const char *digits
[11] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL
};
92 if(strncmp(data
, "⁻", strlen("⁻")) == 0) {
98 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
101 value
= value
* 10 + i
;
102 data
+= strlen(digits
[i
]);
103 } while(*data
!= '\0');
110 function_is_defined(MPEquationParserState
*state
, const char *name
)
112 char *c
, *lower_name
;
114 lower_name
= strdup(name
);
115 for (c
= lower_name
; *c
; c
++)
118 /* FIXME: Make more generic */
119 if (strcmp(lower_name
, "log") == 0 ||
120 (strncmp(lower_name
, "log", 3) == 0 && sub_atoi(lower_name
+ 3) >= 0) ||
121 strcmp(lower_name
, "ln") == 0 ||
122 strcmp(lower_name
, "sqrt") == 0 ||
123 strcmp(lower_name
, "abs") == 0 ||
124 strcmp(lower_name
, "sgn") == 0 ||
125 strcmp(lower_name
, "arg") == 0 ||
126 strcmp(lower_name
, "conj") == 0 ||
127 strcmp(lower_name
, "int") == 0 ||
128 strcmp(lower_name
, "frac") == 0 ||
129 strcmp(lower_name
, "floor") == 0 ||
130 strcmp(lower_name
, "ceil") == 0 ||
131 strcmp(lower_name
, "round") == 0 ||
132 strcmp(lower_name
, "re") == 0 ||
133 strcmp(lower_name
, "im") == 0 ||
134 strcmp(lower_name
, "sin") == 0 || strcmp(lower_name
, "cos") == 0 || strcmp(lower_name
, "tan") == 0 ||
135 strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "tan⁻¹") == 0 ||
136 strcmp(lower_name
, "sinh") == 0 || strcmp(lower_name
, "cosh") == 0 || strcmp(lower_name
, "tanh") == 0 ||
137 strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "tanh⁻¹") == 0 ||
138 strcmp(lower_name
, "asinh") == 0 || strcmp(lower_name
, "acosh") == 0 || strcmp(lower_name
, "atanh") == 0 ||
139 strcmp(lower_name
, "ones") == 0 ||
140 strcmp(lower_name
, "twos") == 0) {
146 if (state
->options
->function_is_defined
)
147 return state
->options
->function_is_defined(name
, state
->options
->callback_data
);
153 get_function(MPEquationParserState
*state
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
155 char *c
, *lower_name
;
158 lower_name
= strdup(name
);
159 for (c
= lower_name
; *c
; c
++)
164 if (strcmp(lower_name
, "log") == 0)
165 mp_logarithm(10, x
, z
); // FIXME: Default to ln
166 else if (strncmp(lower_name
, "log", 3) == 0) {
169 base
= sub_atoi(lower_name
+ 3);
173 mp_logarithm(base
, x
, z
);
175 else if (strcmp(lower_name
, "ln") == 0)
177 else if (strcmp(lower_name
, "sqrt") == 0) // √x
179 else if (strcmp(lower_name
, "abs") == 0) // |x|
181 else if (strcmp(lower_name
, "sgn") == 0)
183 else if (strcmp(lower_name
, "arg") == 0)
184 mp_arg(x
, state
->options
->angle_units
, z
);
185 else if (strcmp(lower_name
, "conj") == 0)
187 else if (strcmp(lower_name
, "int") == 0)
188 mp_integer_component(x
, z
);
189 else if (strcmp(lower_name
, "frac") == 0)
190 mp_fractional_component(x
, z
);
191 else if (strcmp(lower_name
, "floor") == 0)
193 else if (strcmp(lower_name
, "ceil") == 0)
195 else if (strcmp(lower_name
, "round") == 0)
197 else if (strcmp(lower_name
, "re") == 0)
198 mp_real_component(x
, z
);
199 else if (strcmp(lower_name
, "im") == 0)
200 mp_imaginary_component(x
, z
);
201 else if (strcmp(lower_name
, "sin") == 0)
202 mp_sin(x
, state
->options
->angle_units
, z
);
203 else if (strcmp(lower_name
, "cos") == 0)
204 mp_cos(x
, state
->options
->angle_units
, z
);
205 else if (strcmp(lower_name
, "tan") == 0)
206 mp_tan(x
, state
->options
->angle_units
, z
);
207 else if (strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "asin") == 0)
208 mp_asin(x
, state
->options
->angle_units
, z
);
209 else if (strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "acos") == 0)
210 mp_acos(x
, state
->options
->angle_units
, z
);
211 else if (strcmp(lower_name
, "tan⁻¹") == 0 || strcmp(lower_name
, "atan") == 0)
212 mp_atan(x
, state
->options
->angle_units
, z
);
213 else if (strcmp(lower_name
, "sinh") == 0)
215 else if (strcmp(lower_name
, "cosh") == 0)
217 else if (strcmp(lower_name
, "tanh") == 0)
219 else if (strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "asinh") == 0)
221 else if (strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "acosh") == 0)
223 else if (strcmp(lower_name
, "tanh⁻¹") == 0 || strcmp(lower_name
, "atanh") == 0)
225 else if (strcmp(lower_name
, "ones") == 0)
226 mp_ones_complement(x
, state
->options
->wordlen
, z
);
227 else if (strcmp(lower_name
, "twos") == 0)
228 mp_twos_complement(x
, state
->options
->wordlen
, z
);
229 else if (state
->options
->get_function
)
230 result
= state
->options
->get_function(name
, x
, z
, state
->options
->callback_data
);
241 convert(MPEquationParserState
*state
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
243 if (state
->options
->convert
)
244 return state
->options
->convert(x
, x_units
, z_units
, z
, state
->options
->callback_data
);
251 mp_equation_parse(const char *expression
, MPEquationOptions
*options
, MPNumber
*result
, char **error_token
)
254 MPEquationParserState state
;
256 YY_BUFFER_STATE buffer
;
258 if (!(expression
&& result
) || strlen(expression
) == 0)
259 return PARSER_ERR_INVALID
;
261 memset(&state
, 0, sizeof(MPEquationParserState
));
262 state
.options
= options
;
263 state
.variable_is_defined
= variable_is_defined
;
264 state
.get_variable
= get_variable
;
265 state
.set_variable
= set_variable
;
266 state
.function_is_defined
= function_is_defined
;
267 state
.get_function
= get_function
;
268 state
.convert
= convert
;
273 _mp_equation_lex_init_extra(&state
, &yyscanner
);
274 buffer
= _mp_equation__scan_string(expression
, yyscanner
);
276 ret
= _mp_equation_parse(yyscanner
);
277 if (state
.error_token
!= NULL
&& error_token
!= NULL
) {
278 *error_token
= state
.error_token
;
281 _mp_equation__delete_buffer(buffer
, yyscanner
);
282 _mp_equation_lex_destroy(yyscanner
);
284 /* Error during parsing */
289 return PARSER_ERR_MP
;
291 /* Failed to parse */
293 return PARSER_ERR_INVALID
;
295 mp_set_from_mp(&state
.ret
, result
);
297 return PARSER_ERR_NONE
;
302 mp_error_code_to_string(MPErrorCode error_code
)
306 case PARSER_ERR_NONE
:
307 return "PARSER_ERR_NONE";
308 case PARSER_ERR_INVALID
:
309 return "PARSER_ERR_INVALID";
310 case PARSER_ERR_OVERFLOW
:
311 return "PARSER_ERR_OVERFLOW";
312 case PARSER_ERR_UNKNOWN_VARIABLE
:
313 return "PARSER_ERR_UNKNOWN_VARIABLE";
314 case PARSER_ERR_UNKNOWN_FUNCTION
:
315 return "PARSER_ERR_UNKNOWN_FUNCTION";
316 case PARSER_ERR_UNKNOWN_CONVERSION
:
317 return "PARSER_ERR_UNKNOWN_CONVERSION";
319 return "PARSER_ERR_MP";
321 return "Unknown parser error";
326 int _mp_equation_error(void *yylloc
, MPEquationParserState
*state
, char *text
)