Disable localized digits (Bug #644980)
[gcalctool.git] / src / mp-equation.c
blob505609f6498a2d1538bd2d07c925097d8e4fa61d
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)
7 * any later version.
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
17 * 02111-1307, USA.
20 #include <ctype.h>
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);
29 static int
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)
34 return 1;
35 if (state->options->variable_is_defined)
36 return state->options->variable_is_defined(name, state->options->callback_data);
37 return 0;
41 static int
42 get_variable(MPEquationParserState *state, const char *name, MPNumber *z)
44 int result = 1;
46 if (strcmp(name, "e") == 0)
47 mp_get_eulers(z);
48 else if (strcmp(name, "i") == 0)
49 mp_get_i(z);
50 else if (strcmp(name, "π") == 0)
51 mp_get_pi(z);
52 else if (state->options->get_variable)
53 result = state->options->get_variable(name, z, state->options->callback_data);
54 else
55 result = 0;
57 return result;
60 static void
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)
65 return; // FALSE
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
77 int
78 sub_atoi(const char *data)
80 int i, value = 0;
81 const char *digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL};
83 do {
84 for(i = 0; digits[i] != NULL && strncmp(data, digits[i], strlen(digits[i])) != 0; i++);
85 if(digits[i] == NULL)
86 return -1;
87 data += strlen(digits[i]);
88 value = value * 10 + i;
89 } while(*data != '\0');
91 return value;
94 int
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) {
101 sign = -1;
102 data += strlen("⁻");
105 do {
106 for(i = 0; digits[i] != NULL && strncmp(data, digits[i], strlen(digits[i])) != 0; i++);
107 if(digits[i] == NULL)
108 return 0;
109 value = value * 10 + i;
110 data += strlen(digits[i]);
111 } while(*data != '\0');
113 return sign * value;
117 static int
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++)
124 *c = tolower(*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) {
149 g_free (lower_name);
150 return 1;
152 g_free (lower_name);
154 if (state->options->function_is_defined)
155 return state->options->function_is_defined(name, state->options->callback_data);
156 return 0;
160 static int
161 get_function(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z)
163 char *c, *lower_name;
164 int result = 1;
166 lower_name = strdup(name);
167 for (c = lower_name; *c; c++)
168 *c = tolower(*c);
170 // FIXME: Re Im ?
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) {
175 int base;
177 base = sub_atoi(lower_name + 3);
178 if (base < 0)
179 result = 0;
180 else
181 mp_logarithm(base, x, z);
183 else if (strcmp(lower_name, "ln") == 0)
184 mp_ln(x, z);
185 else if (strcmp(lower_name, "sqrt") == 0) // √x
186 mp_sqrt(x, z);
187 else if (strcmp(lower_name, "abs") == 0) // |x|
188 mp_abs(x, z);
189 else if (strcmp(lower_name, "sgn") == 0)
190 mp_sgn(x, z);
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)
194 mp_conjugate(x, z);
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)
200 mp_floor(x, z);
201 else if (strcmp(lower_name, "ceil") == 0)
202 mp_ceiling(x, z);
203 else if (strcmp(lower_name, "round") == 0)
204 mp_round(x, z);
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)
222 mp_sinh(x, z);
223 else if (strcmp(lower_name, "cosh") == 0)
224 mp_cosh(x, z);
225 else if (strcmp(lower_name, "tanh") == 0)
226 mp_tanh(x, z);
227 else if (strcmp(lower_name, "sinh⁻¹") == 0 || strcmp(lower_name, "asinh") == 0)
228 mp_asinh(x, z);
229 else if (strcmp(lower_name, "cosh⁻¹") == 0 || strcmp(lower_name, "acosh") == 0)
230 mp_acosh(x, z);
231 else if (strcmp(lower_name, "tanh⁻¹") == 0 || strcmp(lower_name, "atanh") == 0)
232 mp_atanh(x, z);
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);
239 else
240 result = 0;
242 free(lower_name);
244 return result;
248 static int
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);
253 else
254 return 0;
258 MPErrorCode
259 mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token)
261 int ret;
262 MPEquationParserState state;
263 yyscan_t yyscanner;
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;
277 state.error = 0;
279 mp_clear_error();
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 */
293 if (state.error)
294 return state.error;
296 if (mp_get_error())
297 return PARSER_ERR_MP;
299 /* Failed to parse */
300 if (ret)
301 return PARSER_ERR_INVALID;
303 mp_set_from_mp(&state.ret, result);
305 return PARSER_ERR_NONE;
309 const char *
310 mp_error_code_to_string(MPErrorCode error_code)
312 switch(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";
326 case PARSER_ERR_MP:
327 return "PARSER_ERR_MP";
328 default:
329 return "Unknown parser error";
334 int _mp_equation_error(void *yylloc, MPEquationParserState *state, char *text)
336 return 0;