1
/* Copyright (c) 2004-2008 Sami Pietila
4
* Copyright (C) 2004-2008 Sami Pietila
2
5
* Copyright (c) 2008-2009 Robert Ancell
4
7
* This program is free software; you can redistribute it and/or modify
5
8
* it under the terms of the GNU General Public License as published by
6
9
* the Free Software Foundation; either version 2, or (at your option)
7
10
* any later version.
9
* This program is distributed in the hope that it will be useful, but
12
* This program is distributed in the hope that it will be useful, but
10
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
15
* General Public License for more details.
14
17
* You should have received a copy of the GNU General Public License
15
18
* along with this program; if not, write to the Free Software
16
19
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26
29
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);
42
32
get_variable(MPEquationParserState *state, const char *name, MPNumber *z)
46
36
if (strcmp(name, "e") == 0)
48
else if (strcmp(name, "i") == 0)
50
38
else if (strcmp(name, "π") == 0)
52
40
else if (state->options->get_variable)
61
49
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
51
if (strcmp(name, "e") == 0 || strcmp(name, "π") == 0)
67
54
if (state->options->set_variable)
68
55
state->options->set_variable(name, x, state->options->callback_data);
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;
123
lower_name = strdup(name);
124
for (c = lower_name; *c; c++)
127
/* FIXME: Make more generic */
128
if (strcmp(lower_name, "log") == 0 ||
129
(strncmp(lower_name, "log", 3) == 0 && sub_atoi(lower_name + 3) >= 0) ||
130
strcmp(lower_name, "ln") == 0 ||
131
strcmp(lower_name, "sqrt") == 0 ||
132
strcmp(lower_name, "abs") == 0 ||
133
strcmp(lower_name, "int") == 0 ||
134
strcmp(lower_name, "frac") == 0 ||
135
strcmp(lower_name, "sin") == 0 || strcmp(lower_name, "cos") == 0 || strcmp(lower_name, "tan") == 0 ||
136
strcmp(lower_name, "sin⁻¹") == 0 || strcmp(lower_name, "cos⁻¹") == 0 || strcmp(lower_name, "tan⁻¹") == 0 ||
137
strcmp(lower_name, "sinh") == 0 || strcmp(lower_name, "cosh") == 0 || strcmp(lower_name, "tanh") == 0 ||
138
strcmp(lower_name, "sinh⁻¹") == 0 || strcmp(lower_name, "cosh⁻¹") == 0 || strcmp(lower_name, "tanh⁻¹") == 0 ||
139
strcmp(lower_name, "asinh") == 0 || strcmp(lower_name, "acosh") == 0 || strcmp(lower_name, "atanh") == 0 ||
140
strcmp(lower_name, "ones") == 0 ||
141
strcmp(lower_name, "twos") == 0) {
147
if (state->options->function_is_defined)
148
return state->options->function_is_defined(name);
154
82
get_function(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z)
156
84
char *c, *lower_name;
159
87
lower_name = strdup(name);
160
88
for (c = lower_name; *c; c++)
165
93
if (strcmp(lower_name, "log") == 0)
166
94
mp_logarithm(10, x, z); // FIXME: Default to ln
167
95
else if (strncmp(lower_name, "log", 3) == 0) {
170
98
base = sub_atoi(lower_name + 3);
188
116
else if (strcmp(lower_name, "cos") == 0)
189
117
mp_cos(x, state->options->angle_units, z);
190
118
else if (strcmp(lower_name, "tan") == 0)
191
mp_tan(x, state->options->angle_units, z);
119
mp_tan(x, state->options->angle_units, z);
192
120
else if (strcmp(lower_name, "sin⁻¹") == 0 || strcmp(lower_name, "asin") == 0)
193
121
mp_asin(x, state->options->angle_units, z);
194
122
else if (strcmp(lower_name, "cos⁻¹") == 0 || strcmp(lower_name, "acos") == 0)
195
123
mp_acos(x, state->options->angle_units, z);
196
124
else if (strcmp(lower_name, "tan⁻¹") == 0 || strcmp(lower_name, "atan") == 0)
197
mp_atan(x, state->options->angle_units, z);
125
mp_atan(x, state->options->angle_units, z);
198
126
else if (strcmp(lower_name, "sinh") == 0)
200
128
else if (strcmp(lower_name, "cosh") == 0)
215
143
result = state->options->get_function(name, x, z, state->options->callback_data);
219
147
free(lower_name);
226
do_convert(const char *units[][2], const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
228
int x_index, z_index;
229
MPNumber x_factor, z_factor;
231
for (x_index = 0; units[x_index][0] != NULL && strcmp(units[x_index][0], x_units) != 0; x_index++);
232
if (units[x_index][0] == NULL)
234
for (z_index = 0; units[z_index][0] != NULL && strcmp(units[z_index][0], z_units) != 0; z_index++);
235
if (units[z_index][0] == NULL)
238
mp_set_from_string(units[x_index][1], &x_factor);
239
mp_set_from_string(units[z_index][1], &z_factor);
240
mp_multiply(x, &x_factor, z);
241
mp_divide(z, &z_factor, z);
248
convert(MPEquationParserState *state, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
250
const char *length_units[][2] = {
251
{"parsec", "30857000000000000"},
252
{"parsecs", "30857000000000000"},
253
{"pc", "30857000000000000"},
254
{"lightyear", "9460730472580800"},
255
{"lightyears", "9460730472580800"},
256
{"ly", "9460730472580800"},
257
{"au", "149597870691"},
259
{"mile", "1609.344"},
260
{"miles", "1609.344"},
262
{"kilometer", "1000"},
263
{"kilometers", "1000"},
266
{"cable", "219.456"},
267
{"cables", "219.456"},
269
{"fathom", "1.8288"},
270
{"fathoms", "1.8288"},
281
{"inches", "0.0254"},
282
{"centimeter", "0.01"},
283
{"centimeters", "0.01"},
286
{"millimeter", "0.001"},
287
{"millimeters", "0.001"},
289
{"micrometer", "0.000001"},
290
{"micrometers", "0.000001"},
292
{"nanometer", "0.000000001"},
293
{"nanometers", "0.000000001"},
297
const char *area_units[][2] = {
298
{"hectare", "10000"},
299
{"hectares", "10000"},
300
{"acre", "4046.8564224"},
301
{"acres", "4046.8564224"},
308
const char *volume_units[][2] = {
310
{"gallon", "3.785412"},
311
{"gallons", "3.785412"},
318
{"quart", "0.9463529"},
319
{"quarts", "0.9463529"},
321
{"pint", "0.4731765"},
322
{"pints", "0.4731765"},
324
{"millilitre", "0.001"},
325
{"millilitres", "0.001"},
326
{"milliliter", "0.001"},
327
{"milliliters", "0.001"},
334
const char *weight_units[][2] = {
339
{"kilogrammes", "1"},
342
{"pound", "0.45359237"},
343
{"pounds", "0.45359237"},
344
{"lb", "0.45359237"},
345
{"ounce", "0.002834952"},
346
{"ounces", "0.002834952"},
347
{"oz", "0.002834952"},
351
{"grammes", "0.001"},
356
const char *time_units[][2] = {
357
{"year", "31557600"},
358
{"years", "31557600"},
368
{"millisecond", "0.001"},
369
{"milliseconds", "0.001"},
371
{"microsecond", "0.000001"},
372
{"microseconds", "0.000001"},
377
if (do_convert(length_units, x, x_units, z_units, z) ||
378
do_convert(area_units, x, x_units, z_units, z) ||
379
do_convert(volume_units, x, x_units, z_units, z) ||
380
do_convert(weight_units, x, x_units, z_units, z) ||
381
do_convert(time_units, x, x_units, z_units, z))
384
if (state->options->convert)
385
return state->options->convert(x, x_units, z_units, z, state->options->callback_data);
392
mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token)
154
mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result)
395
157
MPEquationParserState state;
415
174
buffer = _mp_equation__scan_string(expression, yyscanner);
417
176
ret = _mp_equation_parse(yyscanner);
418
if (state.error_token != NULL && error_token != NULL) {
419
*error_token = state.error_token;
422
178
_mp_equation__delete_buffer(buffer, yyscanner);
423
179
_mp_equation_lex_destroy(yyscanner);
181
/* Failed to parse */
183
return -PARSER_ERR_INVALID;
425
185
/* Error during parsing */
427
187
return state.error;
429
189
if (mp_get_error())
430
return PARSER_ERR_MP;
432
/* Failed to parse */
434
return PARSER_ERR_INVALID;
190
return -PARSER_ERR_MP;
436
192
mp_set_from_mp(&state.ret, result);
438
return PARSER_ERR_NONE;
443
mp_error_code_to_string(MPErrorCode error_code)
447
case PARSER_ERR_NONE:
448
return "PARSER_ERR_NONE";
449
case PARSER_ERR_INVALID:
450
return "PARSER_ERR_INVALID";
451
case PARSER_ERR_OVERFLOW:
452
return "PARSER_ERR_OVERFLOW";
453
case PARSER_ERR_UNKNOWN_VARIABLE:
454
return "PARSER_ERR_UNKNOWN_VARIABLE";
455
case PARSER_ERR_UNKNOWN_FUNCTION:
456
return "PARSER_ERR_UNKNOWN_FUNCTION";
457
case PARSER_ERR_UNKNOWN_CONVERSION:
458
return "PARSER_ERR_UNKNOWN_CONVERSION";
460
return "PARSER_ERR_MP";
462
return "Unknown parser error";