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
18 variable_is_defined(ParserState
*state
, const char *name
)
20 /* FIXME: Make more generic */
21 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
23 if (state
->options
->variable_is_defined
)
24 return state
->options
->variable_is_defined(name
, state
->options
->callback_data
);
30 get_variable(ParserState
*state
, const char *name
, MPNumber
*z
)
34 if (strcmp(name
, "e") == 0)
36 else if (strcmp(name
, "i") == 0)
38 else if (strcmp(name
, "π") == 0)
40 else if (state
->options
->get_variable
)
41 result
= state
->options
->get_variable(name
, z
, state
->options
->callback_data
);
49 set_variable(ParserState
*state
, const char *name
, const MPNumber
*x
)
51 // Reserved words, e, π, mod, and, or, xor, not, abs, log, ln, sqrt, int, frac, sin, cos, ...
52 if (strcmp(name
, "e") == 0 || strcmp(name
, "i") == 0 || strcmp(name
, "π") == 0)
55 if (state
->options
->set_variable
)
56 state
->options
->set_variable(name
, x
, state
->options
->callback_data
);
59 // FIXME: Accept "2sin" not "2 sin", i.e. let the tokenizer collect the multiple
60 // Parser then distinguishes between "sin"="s*i*n" or "sin5" = "sin 5" = "sin(5)"
61 // i.e. numbers+letters = variable or function depending on following arg
62 // letters+numbers = numbers+letters+numbers = function
66 sub_atoi(const char *data
)
69 const char *digits
[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL
};
72 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
75 data
+= strlen(digits
[i
]);
76 value
= value
* 10 + i
;
77 } while(*data
!= '\0');
83 super_atoi(const char *data
)
85 int i
, sign
= 1, value
= 0;
86 const char *digits
[11] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL
};
88 if(strncmp(data
, "⁻", strlen("⁻")) == 0) {
94 for(i
= 0; digits
[i
] != NULL
&& strncmp(data
, digits
[i
], strlen(digits
[i
])) != 0; i
++);
97 value
= value
* 10 + i
;
98 data
+= strlen(digits
[i
]);
99 } while(*data
!= '\0');
106 function_is_defined(ParserState
*state
, const char *name
)
108 char *c
, *lower_name
;
110 lower_name
= strdup(name
);
111 for (c
= lower_name
; *c
; c
++)
114 /* FIXME: Make more generic */
115 if (strcmp(lower_name
, "log") == 0 ||
116 (strncmp(lower_name
, "log", 3) == 0 && sub_atoi(lower_name
+ 3) >= 0) ||
117 strcmp(lower_name
, "ln") == 0 ||
118 strcmp(lower_name
, "sqrt") == 0 ||
119 strcmp(lower_name
, "abs") == 0 ||
120 strcmp(lower_name
, "sgn") == 0 ||
121 strcmp(lower_name
, "arg") == 0 ||
122 strcmp(lower_name
, "conj") == 0 ||
123 strcmp(lower_name
, "int") == 0 ||
124 strcmp(lower_name
, "frac") == 0 ||
125 strcmp(lower_name
, "floor") == 0 ||
126 strcmp(lower_name
, "ceil") == 0 ||
127 strcmp(lower_name
, "round") == 0 ||
128 strcmp(lower_name
, "re") == 0 ||
129 strcmp(lower_name
, "im") == 0 ||
130 strcmp(lower_name
, "sin") == 0 || strcmp(lower_name
, "cos") == 0 || strcmp(lower_name
, "tan") == 0 ||
131 strcmp(lower_name
, "asin") == 0 || strcmp(lower_name
, "acos") == 0 || strcmp(lower_name
, "atan") == 0 ||
132 strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "tan⁻¹") == 0 ||
133 strcmp(lower_name
, "sinh") == 0 || strcmp(lower_name
, "cosh") == 0 || strcmp(lower_name
, "tanh") == 0 ||
134 strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "tanh⁻¹") == 0 ||
135 strcmp(lower_name
, "asinh") == 0 || strcmp(lower_name
, "acosh") == 0 || strcmp(lower_name
, "atanh") == 0 ||
136 strcmp(lower_name
, "ones") == 0 ||
137 strcmp(lower_name
, "twos") == 0) {
143 if (state
->options
->function_is_defined
)
144 return state
->options
->function_is_defined(name
, state
->options
->callback_data
);
150 get_function(ParserState
*state
, const char *name
, const MPNumber
*x
, MPNumber
*z
)
152 char *c
, *lower_name
;
155 lower_name
= strdup(name
);
156 for (c
= lower_name
; *c
; c
++)
161 if (strcmp(lower_name
, "log") == 0)
162 mp_logarithm(10, x
, z
); // FIXME: Default to ln
163 else if (strncmp(lower_name
, "log", 3) == 0) {
166 base
= sub_atoi(lower_name
+ 3);
170 mp_logarithm(base
, x
, z
);
172 else if (strcmp(lower_name
, "ln") == 0)
174 else if (strcmp(lower_name
, "sqrt") == 0) // √x
176 else if (strcmp(lower_name
, "abs") == 0) // |x|
178 else if (strcmp(lower_name
, "sgn") == 0)
180 else if (strcmp(lower_name
, "arg") == 0)
181 mp_arg(x
, state
->options
->angle_units
, z
);
182 else if (strcmp(lower_name
, "conj") == 0)
184 else if (strcmp(lower_name
, "int") == 0)
185 mp_integer_component(x
, z
);
186 else if (strcmp(lower_name
, "frac") == 0)
187 mp_fractional_component(x
, z
);
188 else if (strcmp(lower_name
, "floor") == 0)
190 else if (strcmp(lower_name
, "ceil") == 0)
192 else if (strcmp(lower_name
, "round") == 0)
194 else if (strcmp(lower_name
, "re") == 0)
195 mp_real_component(x
, z
);
196 else if (strcmp(lower_name
, "im") == 0)
197 mp_imaginary_component(x
, z
);
198 else if (strcmp(lower_name
, "sin") == 0)
199 mp_sin(x
, state
->options
->angle_units
, z
);
200 else if (strcmp(lower_name
, "cos") == 0)
201 mp_cos(x
, state
->options
->angle_units
, z
);
202 else if (strcmp(lower_name
, "tan") == 0)
203 mp_tan(x
, state
->options
->angle_units
, z
);
204 else if (strcmp(lower_name
, "sin⁻¹") == 0 || strcmp(lower_name
, "asin") == 0)
205 mp_asin(x
, state
->options
->angle_units
, z
);
206 else if (strcmp(lower_name
, "cos⁻¹") == 0 || strcmp(lower_name
, "acos") == 0)
207 mp_acos(x
, state
->options
->angle_units
, z
);
208 else if (strcmp(lower_name
, "tan⁻¹") == 0 || strcmp(lower_name
, "atan") == 0)
209 mp_atan(x
, state
->options
->angle_units
, z
);
210 else if (strcmp(lower_name
, "sinh") == 0)
212 else if (strcmp(lower_name
, "cosh") == 0)
214 else if (strcmp(lower_name
, "tanh") == 0)
216 else if (strcmp(lower_name
, "sinh⁻¹") == 0 || strcmp(lower_name
, "asinh") == 0)
218 else if (strcmp(lower_name
, "cosh⁻¹") == 0 || strcmp(lower_name
, "acosh") == 0)
220 else if (strcmp(lower_name
, "tanh⁻¹") == 0 || strcmp(lower_name
, "atanh") == 0)
222 else if (strcmp(lower_name
, "ones") == 0)
223 mp_ones_complement(x
, state
->options
->wordlen
, z
);
224 else if (strcmp(lower_name
, "twos") == 0)
225 mp_twos_complement(x
, state
->options
->wordlen
, z
);
226 else if (state
->options
->get_function
)
227 result
= state
->options
->get_function(name
, x
, z
, state
->options
->callback_data
);
238 convert(ParserState
*state
, const MPNumber
*x
, const char *x_units
, const char *z_units
, MPNumber
*z
)
240 if (state
->options
->convert
)
241 return state
->options
->convert(x
, x_units
, z_units
, z
, state
->options
->callback_data
);
248 mp_equation_parse(const char *expression
, MPEquationOptions
*options
, MPNumber
*result
, char **error_token
)
253 state
= p_create_parser (expression
, options
);
255 if (!(expression
&& result
) || strlen(expression
) == 0)
256 return PARSER_ERR_INVALID
;
258 state
->variable_is_defined
= variable_is_defined
;
259 state
->get_variable
= get_variable
;
260 state
->set_variable
= set_variable
;
261 state
->function_is_defined
= function_is_defined
;
262 state
->get_function
= get_function
;
263 state
->convert
= convert
;
266 ret
= p_parse (state
);
267 if (state
->error_token
!= NULL
&& error_token
!= NULL
) {
268 *error_token
= state
->error_token
;
270 /* Error during parsing */
273 p_destroy_parser (state
);
277 if (mp_get_error()) {
278 p_destroy_parser (state
);
279 return PARSER_ERR_MP
;
282 /* Failed to parse */
284 p_destroy_parser (state
);
285 return PARSER_ERR_INVALID
;
287 mp_set_from_mp(&state
->ret
, result
);
288 p_destroy_parser (state
);
289 return PARSER_ERR_NONE
;
294 mp_error_code_to_string(MPErrorCode error_code
)
298 case PARSER_ERR_NONE
:
299 return "PARSER_ERR_NONE";
300 case PARSER_ERR_INVALID
:
301 return "PARSER_ERR_INVALID";
302 case PARSER_ERR_OVERFLOW
:
303 return "PARSER_ERR_OVERFLOW";
304 case PARSER_ERR_UNKNOWN_VARIABLE
:
305 return "PARSER_ERR_UNKNOWN_VARIABLE";
306 case PARSER_ERR_UNKNOWN_FUNCTION
:
307 return "PARSER_ERR_UNKNOWN_FUNCTION";
308 case PARSER_ERR_UNKNOWN_CONVERSION
:
309 return "PARSER_ERR_UNKNOWN_CONVERSION";
311 return "PARSER_ERR_MP";
313 return "Unknown parser error";