~ubuntu-branches/ubuntu/lucid/gcalctool/lucid-updates

« back to all changes in this revision

Viewing changes to src/mp-equation.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2010-04-07 19:41:56 UTC
  • mfrom: (1.3.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20100407194156-hgj8g002ffce2de0
Tags: 5.30.0.is.5.28.2-0ubuntu1
Downgrade to 5.28.2 as the new version does not support number bases
as well.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*  Copyright (c) 2004-2008 Sami Pietila
 
1
 
 
2
/*  $Header$
 
3
 *
 
4
 *  Copyright (C) 2004-2008 Sami Pietila
2
5
 *  Copyright (c) 2008-2009 Robert Ancell
3
6
 *
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.
8
 
 *
9
 
 *  This program is distributed in the hope that it will be useful, but
 
11
 *           
 
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.
13
 
 *
 
16
 *           
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
25
28
 
26
29
extern int _mp_equation_parse(yyscan_t yyscanner);
27
30
 
28
 
 
29
 
static int
30
 
variable_is_defined(MPEquationParserState *state, const char *name)
31
 
{
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);
37
 
    return 0;
38
 
}
39
 
 
40
 
 
41
31
static int
42
32
get_variable(MPEquationParserState *state, const char *name, MPNumber *z)
43
33
{
44
34
    int result = 1;
45
 
 
 
35
    
46
36
    if (strcmp(name, "e") == 0)
47
37
        mp_get_eulers(z);
48
 
    else if (strcmp(name, "i") == 0)
49
 
        mp_get_i(z);
50
38
    else if (strcmp(name, "π") == 0)
51
39
        mp_get_pi(z);
52
40
    else if (state->options->get_variable)
60
48
static void
61
49
set_variable(MPEquationParserState *state, const char *name, const MPNumber *x)
62
50
{
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)
65
52
        return; // FALSE
66
 
 
 
53
    
67
54
    if (state->options->set_variable)
68
55
        state->options->set_variable(name, x, state->options->callback_data);
69
56
}
74
61
// letters+numbers = numbers+letters+numbers = function
75
62
 
76
63
 
77
 
int
78
 
sub_atoi(const char *data)
 
64
static int sub_atoi(const char *data)
79
65
{
80
66
    int i, value = 0;
81
67
    const char *digits[] = {"₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉", NULL};
82
 
 
 
68
    
83
69
    do {
84
70
        for(i = 0; digits[i] != NULL && strncmp(data, digits[i], strlen(digits[i])) != 0; i++);
85
71
        if(digits[i] == NULL)
91
77
    return value;
92
78
}
93
79
 
94
 
int
95
 
super_atoi(const char *data)
96
 
{
97
 
   int i, sign = 1, value = 0;
98
 
   const char *digits[11] = {"⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹", NULL};
99
 
 
100
 
   if(strncmp(data, "⁻", strlen("⁻")) == 0) {
101
 
      sign = -1;
102
 
      data += strlen("⁻");
103
 
   }
104
 
 
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');
112
 
 
113
 
   return sign * value;
114
 
}
115
 
 
116
 
 
117
 
static int
118
 
function_is_defined(MPEquationParserState *state, const char *name)
119
 
{
120
 
    char *c, *lower_name;
121
 
    int result = 1;
122
 
 
123
 
    lower_name = strdup(name);
124
 
    for (c = lower_name; *c; c++)
125
 
        *c = tolower(*c);
126
 
 
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) {
142
 
        g_free (lower_name);
143
 
        return 1;
144
 
    }
145
 
    g_free (lower_name);
146
 
 
147
 
    if (state->options->function_is_defined)
148
 
        return state->options->function_is_defined(name);
149
 
    return 0;
150
 
}
151
 
 
152
80
 
153
81
static int
154
82
get_function(MPEquationParserState *state, const char *name, const MPNumber *x, MPNumber *z)
155
83
{
156
84
    char *c, *lower_name;
157
85
    int result = 1;
158
 
 
 
86
    
159
87
    lower_name = strdup(name);
160
88
    for (c = lower_name; *c; c++)
161
89
        *c = tolower(*c);
162
 
 
 
90
    
163
91
    // FIXME: Re Im ?
164
92
 
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) {
168
96
        int base;
169
 
 
 
97
        
170
98
        base = sub_atoi(lower_name + 3);
171
99
        if (base < 0)
172
100
            result = 0;
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)
199
127
        mp_sinh(x, z);
200
128
    else if (strcmp(lower_name, "cosh") == 0)
215
143
        result = state->options->get_function(name, x, z, state->options->callback_data);
216
144
    else
217
145
        result = 0;
218
 
 
 
146
    
219
147
    free(lower_name);
220
 
 
 
148
    
221
149
    return result;
222
150
}
223
151
 
224
152
 
225
 
static int
226
 
do_convert(const char *units[][2], const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
227
 
{
228
 
    int x_index, z_index;
229
 
    MPNumber x_factor, z_factor;
230
 
    
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)
233
 
        return 0;
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)
236
 
        return 0;
237
 
 
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);
242
 
 
243
 
    return 1;
244
 
}
245
 
 
246
 
 
247
 
static int
248
 
convert(MPEquationParserState *state, const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z)
249
 
{
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"},
258
 
        {"nm",                   "1852000"},
259
 
        {"mile",                    "1609.344"},
260
 
        {"miles",                   "1609.344"},
261
 
        {"mi",                      "1609.344"},
262
 
        {"kilometer",               "1000"},
263
 
        {"kilometers",              "1000"},
264
 
        {"km",                      "1000"},
265
 
        {"kms",                     "1000"},
266
 
        {"cable",                    "219.456"},
267
 
        {"cables",                   "219.456"},
268
 
        {"cb",                       "219.456"},
269
 
        {"fathom",                     "1.8288"},
270
 
        {"fathoms",                    "1.8288"},
271
 
        {"ftm",                        "1.8288"},
272
 
        {"meter",                      "1"},
273
 
        {"meters",                     "1"},
274
 
        {"m",                          "1"},
275
 
        {"yard",                       "0.9144"},
276
 
        {"yd",                         "0.9144"},
277
 
        {"foot",                       "0.3048"},
278
 
        {"feet",                       "0.3048"},
279
 
        {"ft",                         "0.3048"},
280
 
        {"inch",                       "0.0254"},
281
 
        {"inches",                     "0.0254"},
282
 
        {"centimeter",                 "0.01"},
283
 
        {"centimeters",                "0.01"},
284
 
        {"cm",                         "0.01"},
285
 
        {"cms",                        "0.01"},
286
 
        {"millimeter",                 "0.001"},
287
 
        {"millimeters",                "0.001"},
288
 
        {"mm",                         "0.001"},
289
 
        {"micrometer",                 "0.000001"},
290
 
        {"micrometers",                "0.000001"},
291
 
        {"um",                         "0.000001"},
292
 
        {"nanometer",                  "0.000000001"},
293
 
        {"nanometers",                 "0.000000001"},
294
 
        {NULL, NULL}
295
 
    };
296
 
 
297
 
    const char *area_units[][2] = {
298
 
        {"hectare",         "10000"},
299
 
        {"hectares",        "10000"},
300
 
        {"acre",             "4046.8564224"},
301
 
        {"acres",            "4046.8564224"},
302
 
        {"m²",                  "1"},
303
 
        {"cm²",                 "0.001"},
304
 
        {"mm²",                 "0.000001"},
305
 
        {NULL, NULL}
306
 
    };
307
 
 
308
 
    const char *volume_units[][2] = {
309
 
        {"m³",               "1000"},
310
 
        {"gallon",              "3.785412"},
311
 
        {"gallons",             "3.785412"},
312
 
        {"gal",                 "3.785412"},
313
 
        {"litre",               "1"},
314
 
        {"litres",              "1"},
315
 
        {"liter",               "1"},
316
 
        {"liters",              "1"},
317
 
        {"L",                   "1"},
318
 
        {"quart",               "0.9463529"},
319
 
        {"quarts",              "0.9463529"},
320
 
        {"qt",                  "0.9463529"},
321
 
        {"pint",                "0.4731765"},
322
 
        {"pints",               "0.4731765"},
323
 
        {"pt",                  "0.4731765"},
324
 
        {"millilitre",          "0.001"},
325
 
        {"millilitres",         "0.001"},
326
 
        {"milliliter",          "0.001"},
327
 
        {"milliliters",         "0.001"},
328
 
        {"mL",                  "0.001"},
329
 
        {"cm³",                 "0.001"},
330
 
        {"mm³",                 "0.000001"},
331
 
        {NULL, NULL}
332
 
    };
333
 
 
334
 
    const char *weight_units[][2] = {
335
 
        {"tonne",            "1000"},
336
 
        {"tonnes",           "1000"},
337
 
        {"kilograms",           "1"},
338
 
        {"kilogramme",          "1"},
339
 
        {"kilogrammes",         "1"},
340
 
        {"kg",                  "1"},
341
 
        {"kgs",                 "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"},
348
 
        {"gram",                "0.001"},
349
 
        {"grams",               "0.001"},
350
 
        {"gramme",              "0.001"},
351
 
        {"grammes",             "0.001"},
352
 
        {"g",                   "0.001"},
353
 
        {NULL, NULL}
354
 
    };
355
 
    
356
 
    const char *time_units[][2] = {
357
 
        {"year",         "31557600"},
358
 
        {"years",        "31557600"},
359
 
        {"day",             "86400"},
360
 
        {"days",            "86400"},
361
 
        {"hour",             "3600"},
362
 
        {"hours",            "3600"},
363
 
        {"minute",             "60"},
364
 
        {"minutes",            "60"},
365
 
        {"second",              "1"},
366
 
        {"seconds",             "1"},
367
 
        {"s",                   "1"},
368
 
        {"millisecond",         "0.001"},
369
 
        {"milliseconds",        "0.001"},
370
 
        {"ms",                  "0.001"},
371
 
        {"microsecond",         "0.000001"},
372
 
        {"microseconds",        "0.000001"},
373
 
        {"us",                  "0.000001"},
374
 
        {NULL, NULL}
375
 
    };
376
 
 
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))
382
 
        return 1;
383
 
 
384
 
    if (state->options->convert)
385
 
        return state->options->convert(x, x_units, z_units, z, state->options->callback_data);
386
 
  
387
 
    return 0;
388
 
}
389
 
 
390
 
 
391
 
MPErrorCode
392
 
mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token)
 
153
int
 
154
mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result)
393
155
{
394
156
    int ret;
395
157
    MPEquationParserState state;
397
159
    YY_BUFFER_STATE buffer;
398
160
 
399
161
    if (!(expression && result) || strlen(expression) == 0)
400
 
        return PARSER_ERR_INVALID;
 
162
        return -EINVAL;
401
163
 
402
164
    memset(&state, 0, sizeof(MPEquationParserState));
403
165
    state.options = options;
404
 
    state.variable_is_defined = variable_is_defined;
405
166
    state.get_variable = get_variable;
406
167
    state.set_variable = set_variable;
407
 
    state.function_is_defined = function_is_defined;
408
168
    state.get_function = get_function;
409
 
    state.convert = convert;
410
169
    state.error = 0;
411
170
 
412
171
    mp_clear_error();
415
174
    buffer = _mp_equation__scan_string(expression, yyscanner);
416
175
 
417
176
    ret = _mp_equation_parse(yyscanner);
418
 
    if (state.error_token != NULL && error_token != NULL) {
419
 
        *error_token = state.error_token;
420
 
    }
421
177
 
422
178
    _mp_equation__delete_buffer(buffer, yyscanner);
423
179
    _mp_equation_lex_destroy(yyscanner);
424
180
 
 
181
    /* Failed to parse */
 
182
    if (ret)
 
183
        return -PARSER_ERR_INVALID;
 
184
        
425
185
    /* Error during parsing */
426
186
    if (state.error)
427
187
        return state.error;
428
188
 
429
189
    if (mp_get_error())
430
 
        return PARSER_ERR_MP;
431
 
 
432
 
    /* Failed to parse */
433
 
    if (ret)
434
 
        return PARSER_ERR_INVALID;
 
190
        return -PARSER_ERR_MP;
435
191
 
436
192
    mp_set_from_mp(&state.ret, result);
437
193
 
438
 
    return PARSER_ERR_NONE;
439
 
}
440
 
 
441
 
 
442
 
const char *
443
 
mp_error_code_to_string(MPErrorCode error_code)
444
 
{
445
 
    switch(error_code)
446
 
    {
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";
459
 
    case PARSER_ERR_MP:
460
 
        return "PARSER_ERR_MP";
461
 
    default:
462
 
        return "Unknown parser error";
463
 
    }
 
194
    return 0;
464
195
}
465
196
 
466
197