1 /* Copyright (c) 2004-2008 Sami Pietila
2 * Copyright (c) 2008-2009 Robert Ancell
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22 #include "mp-equation-private.h"
23 #include "mp-equation-parser.h"
24 #include "mp-equation-lexer.h"
26 extern int _mp_equation_parse(yyscan_t yyscanner
);
30 variable_is_defined(MPEquationParserState
*state
, const char *name
)
32 /* FIXME: Make more generic */
33 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
35 if (state
->options
->variable_is_defined
)
36 return state
->options
->variable_is_defined(name
, state
->options
->callback_data
);
42 get_variable(MPEquationParserState
*state
, const char *name
, MPNumber
*z
)
46 if (strcmp(name
, "e") == 0)
48 else if (strcmp(name
, "i") == 0)
50 else if (strcmp(name
, "π") == 0)
52 else if (state
->options
->get_variable
)
53 result
= state
->options
->get_variable(name
, z
, state
->options
->callback_data
);
61 set_variable(MPEquationParserState
*state
, const char *name
, const MPNumber
*x
)
63 // Reserved words, e, π, mod, and, or, xor, not, abs, log, ln, sqrt, int, frac, sin, cos, ...
64 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
67 if (state
->options
->set_variable
)
68 state
->options
->set_variable(name
, x
, state
->options
->callback_data
);
71 // FIXME: Accept "2sin" not "2 sin", i.e. let the tokenizer collect the multiple
72 // Parser then distinguishes between "sin"="s*i*n" or "sin5" = "sin 5" = "sin(5)"
73 // i.e. numbers+letters = variable or function depending on following arg
74 // letters+numbers = numbers+letters+numbers = function
78 sub_atoi(const char *data
)
81 const char *digits
[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL
};
84 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
87 data
+= strlen(digits
[i
]);
88 value
= value
* 10 + i
;
89 } while(*data
!= '\0');
95 super_atoi(const char *data
)
97 int i
, sign
= 1, value
= 0;
98 const char *digits
[11] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL
};
100 if(strncmp(data
, "⁻", strlen("⁻")) == 0) {
106 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
107 if(digits
[i
] == NULL
)
109 value
= value
* 10 + i
;
110 data
+= strlen(digits
[i
]);
111 } while(*data
!= '\0');
118 function_is_defined(MPEquationParserState
*state
, const char *name
)
120 char *c
, *lower_name
;
122 lower_name
= strdup(name
);
123 for (c
= lower_name
; *c
; c
++)
126 /* FIXME: Make more generic */
127 if (strcmp(lower_name
, "log") == 0 ||
128 (strncmp(lower_name
, "log", 3) == 0 && sub_atoi(lower_name
+ 3) >= 0) ||
129 strcmp(lower_name
, "ln") == 0 ||
130 strcmp(lower_name
, "sqrt") == 0 ||
131 strcmp(lower_name
, "abs") == 0 ||
132 strcmp(lower_name
, "sgn") == 0 ||
133 strcmp(lower_name
, "arg") == 0 ||
134 strcmp(lower_name
, "conj") == 0 ||
135 strcmp(lower_name
, "int") == 0 ||
136 strcmp(lower_name
, "frac") == 0 ||
137 strcmp(lower_name
, "floor") == 0 ||
138 strcmp(lower_name
, "ceil") == 0 ||
139 strcmp(lower_name
, "round") == 0 ||
140 strcmp(lower_name
, "re") == 0 ||
141 strcmp(lower_name
, "im") == 0 ||
142 strcmp(lower_name
, "sin") == 0 || strcmp(lower_name
, "cos") == 0 || strcmp(lower_name
, "tan") == 0 ||
143 strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "tan⁻¹") == 0 ||
144 strcmp(lower_name
, "sinh") == 0 || strcmp(lower_name
, "cosh") == 0 || strcmp(lower_name
, "tanh") == 0 ||
145 strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "tanh⁻¹") == 0 ||
146 strcmp(lower_name
, "asinh") == 0 || strcmp(lower_name
, "acosh") == 0 || strcmp(lower_name
, "atanh") == 0 ||
147 strcmp(lower_name
, "ones") == 0 ||
148 strcmp(lower_name
, "twos") == 0) {
154 if (state
->options
->function_is_defined
)
155 return state
->options
->function_is_defined(name
, state
->options
->callback_data
);
161 get_function(MPEquationParserState
*state
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
163 char *c
, *lower_name
;
166 lower_name
= strdup(name
);
167 for (c
= lower_name
; *c
; c
++)
172 if (strcmp(lower_name
, "log") == 0)
173 mp_logarithm(10, x
, z
); // FIXME: Default to ln
174 else if (strncmp(lower_name
, "log", 3) == 0) {
177 base
= sub_atoi(lower_name
+ 3);
181 mp_logarithm(base
, x
, z
);
183 else if (strcmp(lower_name
, "ln") == 0)
185 else if (strcmp(lower_name
, "sqrt") == 0) // √x
187 else if (strcmp(lower_name
, "abs") == 0) // |x|
189 else if (strcmp(lower_name
, "sgn") == 0)
191 else if (strcmp(lower_name
, "arg") == 0)
192 mp_arg(x
, state
->options
->angle_units
, z
);
193 else if (strcmp(lower_name
, "conj") == 0)
195 else if (strcmp(lower_name
, "int") == 0)
196 mp_integer_component(x
, z
);
197 else if (strcmp(lower_name
, "frac") == 0)
198 mp_fractional_component(x
, z
);
199 else if (strcmp(lower_name
, "floor") == 0)
201 else if (strcmp(lower_name
, "ceil") == 0)
203 else if (strcmp(lower_name
, "round") == 0)
205 else if (strcmp(lower_name
, "re") == 0)
206 mp_real_component(x
, z
);
207 else if (strcmp(lower_name
, "im") == 0)
208 mp_imaginary_component(x
, z
);
209 else if (strcmp(lower_name
, "sin") == 0)
210 mp_sin(x
, state
->options
->angle_units
, z
);
211 else if (strcmp(lower_name
, "cos") == 0)
212 mp_cos(x
, state
->options
->angle_units
, z
);
213 else if (strcmp(lower_name
, "tan") == 0)
214 mp_tan(x
, state
->options
->angle_units
, z
);
215 else if (strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "asin") == 0)
216 mp_asin(x
, state
->options
->angle_units
, z
);
217 else if (strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "acos") == 0)
218 mp_acos(x
, state
->options
->angle_units
, z
);
219 else if (strcmp(lower_name
, "tan⁻¹") == 0 || strcmp(lower_name
, "atan") == 0)
220 mp_atan(x
, state
->options
->angle_units
, z
);
221 else if (strcmp(lower_name
, "sinh") == 0)
223 else if (strcmp(lower_name
, "cosh") == 0)
225 else if (strcmp(lower_name
, "tanh") == 0)
227 else if (strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "asinh") == 0)
229 else if (strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "acosh") == 0)
231 else if (strcmp(lower_name
, "tanh⁻¹") == 0 || strcmp(lower_name
, "atanh") == 0)
233 else if (strcmp(lower_name
, "ones") == 0)
234 mp_ones_complement(x
, state
->options
->wordlen
, z
);
235 else if (strcmp(lower_name
, "twos") == 0)
236 mp_twos_complement(x
, state
->options
->wordlen
, z
);
237 else if (state
->options
->get_function
)
238 result
= state
->options
->get_function(name
, x
, z
, state
->options
->callback_data
);
249 convert(MPEquationParserState
*state
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
251 if (state
->options
->convert
)
252 return state
->options
->convert(x
, x_units
, z_units
, z
, state
->options
->callback_data
);
259 mp_equation_parse(const char *expression
, MPEquationOptions
*options
, MPNumber
*result
, char **error_token
)
262 MPEquationParserState state
;
264 YY_BUFFER_STATE buffer
;
266 if (!(expression
&& result
) || strlen(expression
) == 0)
267 return PARSER_ERR_INVALID
;
269 memset(&state
, 0, sizeof(MPEquationParserState
));
270 state
.options
= options
;
271 state
.variable_is_defined
= variable_is_defined
;
272 state
.get_variable
= get_variable
;
273 state
.set_variable
= set_variable
;
274 state
.function_is_defined
= function_is_defined
;
275 state
.get_function
= get_function
;
276 state
.convert
= convert
;
281 _mp_equation_lex_init_extra(&state
, &yyscanner
);
282 buffer
= _mp_equation__scan_string(expression
, yyscanner
);
284 ret
= _mp_equation_parse(yyscanner
);
285 if (state
.error_token
!= NULL
&& error_token
!= NULL
) {
286 *error_token
= state
.error_token
;
289 _mp_equation__delete_buffer(buffer
, yyscanner
);
290 _mp_equation_lex_destroy(yyscanner
);
292 /* Error during parsing */
297 return PARSER_ERR_MP
;
299 /* Failed to parse */
301 return PARSER_ERR_INVALID
;
303 mp_set_from_mp(&state
.ret
, result
);
305 return PARSER_ERR_NONE
;
310 mp_error_code_to_string(MPErrorCode error_code
)
314 case PARSER_ERR_NONE
:
315 return "PARSER_ERR_NONE";
316 case PARSER_ERR_INVALID
:
317 return "PARSER_ERR_INVALID";
318 case PARSER_ERR_OVERFLOW
:
319 return "PARSER_ERR_OVERFLOW";
320 case PARSER_ERR_UNKNOWN_VARIABLE
:
321 return "PARSER_ERR_UNKNOWN_VARIABLE";
322 case PARSER_ERR_UNKNOWN_FUNCTION
:
323 return "PARSER_ERR_UNKNOWN_FUNCTION";
324 case PARSER_ERR_UNKNOWN_CONVERSION
:
325 return "PARSER_ERR_UNKNOWN_CONVERSION";
327 return "PARSER_ERR_MP";
329 return "Unknown parser error";
334 int _mp_equation_error(void *yylloc
, MPEquationParserState
*state
, char *text
)