GnuCash c935c2f+
Loading...
Searching...
No Matches
expression_parser.c
1/***************************************************************************
2 expression-parser.c - description
3 -------------------
4 begin : Wednesday June 21 2000
5 email : tboldt@attglobal.net
6 Author : Terry D. Boldt
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18/*
19 * Functions to parse arthmetic expressions
20 * 6-21-2000
21 */
22
23/* Modified to support functions - Summer, 2002 -- jsled@asynchronous.org */
24
25/* expression parser/evaluator use:
26 *
27 * Before describing the parser per se, I want to describe the
28 * structures used to contain the results returned from the
29 * parser. The structure is defined in "finvar.h":
30 *
31 * typedef struct var_store *var_store_ptr;
32 *
33 * typedef struct var_store {
34 * char *variable_name;
35 * char use_flag;
36 * char assign_flag;
37 * void *value;
38 * var_strore_ptr next_var;
39 * } var_store;
40 *
41 * The "use_flag" variable is for internal use of the parser and can
42 * be ignored by the user. The "variable_name" variable possibly
43 * points to a string containing the name of the value returned, a
44 * "variable name". If NULL, then this is a temporary value. The
45 * "value" variable points to a user defined structure containing the
46 * numeric value of the variable.
47 *
48 * As well, variables now have a VarStoreType, to distinguish between numeric
49 * and string values, as we want string arguments to functions.
50 *
51 * In designing and writing the parser, I decided early on that the
52 * parser should be an "expression parser/evaluator" and that the
53 * actual arithmetic was the responsibility of the caller/user.
54 *
55 * I decided that the parser should be totally independent of the
56 * numeric representation used, and thus the exact details of how the
57 * arithmetic was performed. To accomplish this, four functions are
58 * supplied by the user/caller:
59 *
60 * 1: trans_numeric - this function translates the text string into a
61 * numeric in the desired representation and returns a pointer to the
62 * representation as a (void *) this function has four parameters
63 * passed:
64 *
65 * 1: digit_str -- the actual text string of the
66 * numeric to be converted to the internal
67 * representation
68 *
69 * 2: radix_point -- the ASCII character used to
70 * represent the radix point
71 *
72 * 3: group character -- the ASCII character used
73 * to separate and group digits to the left of the
74 * radix
75 *
76 * 4: rstr -- a pointer to a location in which to
77 * return a pointer to the first character not
78 * part of the numeric string translated If this
79 * pointer is NULL, do not return a value. This
80 * parameter is the same as the second parameter
81 * of the standard C library functions "strtod" or
82 * "strtol"
83 *
84 * 2: numeric_ops - this function does the actual arithmetic on two
85 * numeric quantities in internal representation. It has three
86 * parameters passed:
87 *
88 * 1: op_sym -- the numeric operation to be
89 * performed. The possible values are defined
90 * in "finvar.h" and are:
91 *
92 * ADD_OP - addition
93 * SUB_OP - subtraction
94 * DIV_OP - division
95 * MUL_OP - multiplication
96 * ASN_OP - assignment
97 *
98 * 2: left_value - the left hand operand of the
99 * binary operator
100 *
101 * 3: right_value - the right hand operand of
102 * the binary operator Note: left_value and
103 * right_value are passed as (void *). This
104 * function is responsible for casting to the
105 * proper type to use. Note: this function should
106 * make no assumptions about overwriting or
107 * re-using either left_value or right_value,
108 * except for ASN_OP. Both values passed must be
109 * left unchanged by any operation except ASN_OP.
110 * This function is also responsible for
111 * allocating/freeing memory as necessary to
112 * perform the designated function and returning
113 * the result. I STRONGLY suggest that the result
114 * be returned in dynamically allocated memory. If
115 * static memory is used, the parser has no means
116 * of copying the returned result or managing
117 * static memory to prevent overwriting the result
118 * and invalidating the result.
119 *
120 * 3: negate_numeric - this function negates the value passed (as a (void *))
121 *
122 * 4: free_numeric - this function is responsible for freeing memory
123 * used by the internal numeric representation.
124 *
125 * 5: func_op - this function is responsible for handling function calls.
126 *
127 * I have included the file "numeric_ops.c" containing the above
128 * functions for the usual "double" and "int" representation of
129 * numerics. The functions perform integer or floating point
130 * operations as appropriate for the string entered by the user. The
131 * division operation is done in "double" since I do not think that
132 * anybody really wants (9 / 2) to equal 4 instead of 4.5 for
133 * financial operations. These functions use the structure defined in
134 * finvar.h:
135 *
136 * typedef struct numeric *numeric_ptr;
137 * typedef struct numeric {
138 * char type;
139 * union {
140 * long int int_value;
141 * double dbl_value;
142 * } value;
143 * } numeric;
144 *
145 * to contain all numeric values. The variable "type" in this
146 * structure can have the values:
147 *
148 * INT_TYPE
149 * DBL_TYPE
150 *
151 * which are defined in "finvar.h".
152 *
153 * All "named variables", variables defined by the user for storing
154 * intermediate results for future reference/use, and temporary
155 * variables used by the parser use the variable storage structure,
156 * var_store, defined above. The result of parsing and evaluating the
157 * string passed are returned in a variable storage structure
158 * specified by the caller.
159 *
160 * If the returned variable value is not named, i.e., "variable_name
161 * == NULL", then the user/caller is responsible for freeing the
162 * memory used by the internal representation of the numeric value.
163 * If, however, "variable_name != NULL", freeing the memory used by
164 * the internal numeric representation will cause a segmentation fault
165 * later, when the parser attempts to free the memory through a call
166 * to "free_numeric". In addition, freeing the memory will probably
167 * invalidate the numeric value contained therein and lead to
168 * pernicuous results when the value is used.
169 *
170 * If "variable_name != NULL", the user/caller should never attempt to
171 * free this memory, that is the sole responsibility of the parser.
172 *
173 * It may be that the calling function has certain "variables" that
174 * need to be "pre-defined" for the user to manipulate. In essence
175 * the function "pre-defining" variables sets up a linked list of
176 * variable storage structures with the proper "names" and numeric
177 * values. The number of "pre-defined" variables and a pointer to the
178 * structure array is passed to the parser in the initialization
179 * call. After the parser is eventually exited, the calling function
180 * is responsible for freeing any memory used by the "pre-defined"
181 * variables and their final numeric representation.
182 *
183 * There may also be strings in the expression, by quoting them in '"'
184 * characters. These are intended to be passed literally into functions; the
185 * result of using a string in a numeric operation is undefined. Presently,
186 * the expression-parser code does not check the variable types during
187 * parsing or evaluation.
188 *
189 * A second design goal of the parser was that it should be callable
190 * concurrently by multiple modules independently. That each module
191 * should be capable of using differing "pre-defined" variables and
192 * user defined variables and even internal numeric representations.
193 * To that end the calling module must first initialize the parser
194 * with a call to "init_parser". This call creates the parser
195 * internal structure for subsequent calls to the parser proper. The
196 * structure created and returned must then be passed to subsequent
197 * calls to the parser. When no further calls to the parser are to be
198 * made, the module then calls "exit_parser" with the pointer returned
199 * by "init_parser", so that the parser may release dynamically
200 * allocated memory.
201 *
202 * The parser recognizes the following binary operators:
203 *
204 * +
205 * -
206 * /
207 * *
208 * =
209 * +=
210 * -=
211 * /=
212 * *=
213 *
214 * In addition, the unary operators
215 *
216 * +
217 * -
218 *
219 * are recognized. All numerics are initially recognized as positive
220 * numbers. If negative, the unary '-' operator is applied. This saves
221 * the logic of having to recognize strings as
222 *
223 * -123
224 *
225 * The logic recognizes "-" and "123" separately. The '-' unary
226 * operator is then applied to negate the numeric. This also has the
227 * advantage that the same logic can be used for
228 *
229 * -123
230 * +123.45
231 * +uvar
232 * -uvar
233 *
234 * In each case, the appropriate unary operator is applied to obtain
235 * the desired * result with no increase in the parsing logic. Thus
236 * keeping things as simple as possible.
237 *
238 * The parser also follows the C practice that the assignment
239 * operators return a value. Thus, allowing multiple assignments and
240 * assignment within expressions. The following expressions are all
241 * valid:
242 *
243 * nni = 123
244 * hnk = nni = 23.45
245 * jkl = 5 * (nj = 68.9)
246 *
247 * The first time variables are used in an expression, they are
248 * initialized to zero, 0. Thus, even if the following variables have
249 * not been assigned a value previously, the following expressions are
250 * valid:
251 *
252 * nni *= 123
253 * above results in zero in nni
254 * jk += 45.6
255 * above results in 45.6 in jk
256 * 56.8 - tyh
257 * result of above is 56.8
258 * tgh - 45.7
259 * above the same as
260 * -45.7
261 *
262 * After parsing the above expressions the variables nni, jk, tyh and
263 * tgh would all be defined.
264 *
265 * Functions are invoked with expressions of the format
266 *
267 * [_a-zA-Z]( <argument_0> : <argument_1> : ... : <argument_n> )
268 *
269 * where each argument can itself be a sub-expression [arithmetic operation
270 * or function call].
271 *
272 *
273 * There are six parser functions needed to use the parser/evaluator:
274 *
275 * Note: in the last five functions, in the function parameter (void
276 * *vp), "vp" is the pointer returned by the "init_parser" function.
277 *
278 * void *init_parser(var_store_ptr predefined_vars,
279 * gchar *radix_point,
280 * gchar *group_char,
281 * void *trans_numeric(char *digit_str,
282 * gchar *radix_point,
283 * gchar *group_char,
284 * char **rstr),
285 * void *numeric_ops(char op_sym,
286 * void *left_value,
287 * void *right_value),
288 * void *negate_numeric(void *value),
289 * void free_numeric(void *numeric_value),
290 * void *func_op(const char *fname, int argc, void **argv));
291 *
292 * This function is called by the module/function/whatever to
293 * initialize the parser. The parser returns a pointer to a
294 * structure that contains all relevant information for
295 * parsing strings. The pointer is returned as (void *)
296 * since all information is and should remain pertinent only
297 * to the parser. The calling function(s) should never rely on
298 * manipulating any information inside this structure
299 * directly, since it may and could change in the future. --
300 * The first parameter is a pointer to the first element in
301 * a linked list of "pre-defined" variables the caller wishes
302 * to use with subsequent calls to the parser. -- The second
303 * parameter is the radix character to use in numeric strings
304 * in subsequent calls to the parser. -- the third parameter
305 * is the optional character used for grouping digits to the
306 * left of the radix. -- The fourth, fifth, sixth and seventh
307 * parameters are the functions I described above for the
308 * internal numeric representation desired by the calling
309 * function(s).
310 *
311 * void exit_parser(
312 * void *vp);
313 *
314 * This function is called to exit the parser and free all
315 * dynamically allocated memory used by the parser for an
316 * internal stack and user defined variables.
317 *
318 * unsigned get_parse_error(
319 * void *vp);
320 *
321 * If the parser is successful in complete parsing and
322 * evaluating the string passed to 'parse_string' below, that
323 * functions returns a NULL pointer. If, however, an error is
324 * encountered in parsing/evaluating the string, the
325 * 'parse_string' function returns a pointer to the character
326 * which caused the error. This call returns an unsigned
327 * integer designating the error encountered. The possible
328 * values are defined in the "finvar.h" file.
329 *
330 * var_store_ptr parser_get_vars(
331 * void *vp)
332 *
333 * This function returns a pointer to the first element of a
334 * linked list of variable storage structures containing the
335 * user defined named variables if any exist. NULL is
336 * returned if none exist. The calling function should not
337 * alter the variable names. The numeric values may be
338 * altered if the calling function author really knows what
339 * they are doing.
340 *
341 * unsigned delete_var(
342 * char *var_name,
343 * void *vp);
344 *
345 * This function will delete the user defined named variable
346 * with a name identical to the name string passed in the
347 * first parameter. If no user defined variable exists with an
348 * identical name, zero, 0, is returned. If the delete
349 * operation is successful, one, 1, is returned.
350 *
351 * char *parse_string(
352 * var_store_ptr value,
353 * char *string,
354 * void *vp);
355 *
356 * This function parses the string passed in the second
357 * parameter and returns a pointer to the last character not
358 * recognized upon a parsing error. If no error occurred, NULL
359 * is returned. The first parameter is a pointer to a variable
360 * storage structure to contain the result of the
361 * parser/evaluator.
362 *
363 * Note: The parser/evaluator uses a simple recursive descent
364 * parser. I decided on this type for the simple reason that for a
365 * simple four function calculator a recursive descent parser is, in
366 * my opinion, the easiest to construct. I also think that recursive
367 * descent parsers are easier for the human to understand and thus
368 * maintain.
369 *
370 * Also, the parser uses a stack which is dynamically allocated in
371 * memory and can grow as needed. I have not provided any mechanism
372 * for shrinking the stack. The initial stack size is set at 50
373 * slots. I really do not anticipate that under normal and even most
374 * extreme cases, that it will ever approach that size in actual
375 * use. Under "normal" operation, the stack will probably never exceed
376 * 3 or 4 slots in size and 50 slots is probably an overkill for
377 * normal use. However, since the stack is pointers and not entire
378 * structures, a stack size of 50 slots is not that much memory and
379 * can be tolerated by most users. Thus, a mechanism for shrinking the
380 * stack will probably never be needed.
381 */
382
383#include <config.h>
384#include <ctype.h>
385#include <stdio.h>
386#include <string.h>
387#include <stdlib.h>
388
389#include <glib.h>
390
391#include "qof.h"
392
393#define EXPRESSION_PARSER_STATICS
394#include "finvar.h"
395
396#define MAX_FUNC_ARG_LEN 255
397
398/* structure to hold parser environment - environment particular to
399 * each caller */
400typedef struct parser_env
401{
402 unsigned stack_cnt;
403 unsigned stack_size;
404 var_store_ptr *stack;
405 var_store_ptr predefined_vars;
406 var_store_ptr named_vars;
407 var_store_ptr unnamed_vars;
408
409 const char *parse_str;
410 gchar *radix_point;
411 gchar *group_char;
412 char name[128];
413
414 char Token;
415 char asn_op;
416
417 char *tokens;
418 char *token_tail;
419
420 ParseError error_code;
421
422 void *numeric_value;
423
424 void *(*trans_numeric) (const char *digit_str,
425 gchar *radix_point, gchar *group_char, char **rstr);
426 void *(*numeric_ops) (char op_sym, void *left_value, void *right_value);
427 void *(*negate_numeric) (void *value);
428 void (*free_numeric) (void *numeric_value);
429 void *(*func_op)( const char *fname, int argc, void **argv );
430}
432
433#include "finproto.h"
434#include "fin_static_proto.h"
435#include "fin_spl_protos.h"
436
437#define FN_TOKEN 'F'
438#define ARG_TOKEN ':'
439#define VAR_TOKEN 'V'
440#define NUM_TOKEN 'I'
441#define STR_TOKEN '"'
442
443#define STACK_INIT 50
444
445#define UNNAMED_VARS 100
446
447#define NAMED_INCR 5
448
449static char allowed_operators[] = "+-*/()=:";
450
451parser_env_ptr
452init_parser (var_store_ptr predefined_vars,
453 gchar *radix_point,
454 gchar *group_char,
455 void *trans_numeric (const char *digit_str,
456 gchar *radix_point,
457 gchar *group_char,
458 char **rstr),
459 void *numeric_ops (char op_sym,
460 void *left_value,
461 void *right_value),
462 void *negate_numeric (void *value),
463 void free_numeric (void *numeric_value),
464 void *func_op( const char *fname,
465 int argc, void **argv ))
466{
467 parser_env_ptr pe = g_new0 (parser_env, 1);
468
469 pe->predefined_vars = predefined_vars;
470
471 pe->stack = g_new0 (var_store_ptr, STACK_INIT);
472 pe->stack_size = STACK_INIT;
473
474 pe->radix_point = radix_point;
475 pe->group_char = group_char;
476
477 pe->numeric_value = NULL;
478
479 pe->trans_numeric = trans_numeric;
480 pe->numeric_ops = numeric_ops;
481 pe->negate_numeric = negate_numeric;
482 pe->free_numeric = free_numeric;
483 pe->func_op = func_op;
484
485 return pe;
486} /* init_parser */
487
488void
489exit_parser (parser_env_ptr pe)
490{
491 var_store_ptr vars, bv;
492
493 if (pe == NULL)
494 return;
495
496 for (vars = pe->named_vars; vars; vars = bv)
497 {
498 g_free (vars->variable_name);
499 vars->variable_name = NULL;
500
501 if (vars->value)
502 pe->free_numeric (vars->value);
503 vars->value = NULL;
504
505 bv = vars->next_var;
506 g_free (vars);
507 } /* endfor */
508
509 pe->named_vars = NULL;
510
511 g_free (pe->stack);
512 pe->stack = NULL;
513
514 g_free (pe->tokens);
515 pe->tokens = NULL;
516 pe->token_tail = NULL;
517
518 if (pe->numeric_value)
519 pe->free_numeric (pe->numeric_value);
520 pe->numeric_value = NULL;
521
522 g_free (pe);
523} /* exit_parser */
524
525/* return parser error code */
526ParseError get_parse_error (parser_env_ptr pe)
527{
528 if (pe == NULL)
529 return PARSER_NO_ERROR;
530
531 return pe->error_code;
532} /* get_parse_error */
533
534/* return linked list of named variables which have been defined */
535var_store_ptr parser_get_vars (parser_env_ptr pe)
536{
537 if (pe == NULL)
538 return NULL;
539
540 return pe->named_vars;
541} /* get_vars */
542
543/* function to delete variable with specified name from named variables
544 * if it exists. If it exists return TRUE, 1, else return FALSE, 0 */
545unsigned
546delete_var (char *var_name, parser_env_ptr pe)
547{
548 unsigned ret = FALSE;
549 var_store_ptr nv, tv;
550
551 if (pe == NULL)
552 return FALSE;
553
554 for (nv = pe->named_vars, tv = NULL; nv; tv = nv, nv = nv->next_var)
555 {
556 if (strcmp (nv->variable_name, var_name) == 0)
557 {
558 if (tv)
559 tv->next_var = nv->next_var;
560 else
561 pe->named_vars = nv->next_var;
562
563 g_free (nv->variable_name);
564 nv->variable_name = NULL;
565
566 pe->free_numeric (nv->value);
567 nv->value = NULL;
568
569 g_free (nv);
570
571 ret = TRUE;
572 break;
573 } /* endif */
574 } /* endfor */
575
576 return ret;
577} /* delete_var */
578
579/* parse string passed using parser environment passed return
580 * evaluated value in numeric structure passed, return NULL if no
581 * parse error. If parse error, return pointer to character at which
582 * error occurred. */
583char *
584parse_string (var_store_ptr value, const char *string, parser_env_ptr pe)
585{
586 var_store_ptr retv;
587 var_store unnamed_vars[UNNAMED_VARS];
588
589 if (!pe || !string)
590 return NULL;
591
592 pe->unnamed_vars = unnamed_vars;
593 memset (unnamed_vars, 0, UNNAMED_VARS * sizeof (var_store));
594
595 pe->parse_str = string;
596 pe->error_code = PARSER_NO_ERROR;
597
598 g_free (pe->tokens);
599 pe->tokens = g_new0(char, strlen (string) + 1);
600 pe->token_tail = pe->tokens;
601
602 next_token (pe);
603
604 if (!pe->error_code)
605 assignment_op (pe);
606
607 if (!pe->error_code)
608 {
609 /* interpret (num) as -num */
610 if (strcmp (pe->tokens, "(I)") == 0)
611 {
612 var_store_ptr val;
613
614 val = pop (pe);
615 if (val)
616 {
617 pe->negate_numeric (val->value);
618 push (val, pe);
619 }
620 }
621 }
622
623 if (pe->Token == EOS)
624 {
625 if ((pe->stack_cnt) && (retv = pop (pe)))
626 {
627 if (value != NULL)
628 *value = *retv;
629 pe->parse_str = NULL;
630 }
631 else
632 pe->error_code = STACK_UNDERFLOW;
633 }
634
635 pe->stack_cnt = 0;
636 pe->unnamed_vars = NULL;
637
638 return (char *) pe->parse_str;
639} /* expression */
640
641/* pop value off value stack */
642static var_store_ptr
643pop (parser_env_ptr pe)
644{
645 var_store_ptr val;
646
647 if (pe->stack_cnt)
648 val = pe->stack[--(pe->stack_cnt)];
649 else
650 {
651 val = NULL;
652 pe->error_code = STACK_UNDERFLOW;
653 } /* endif */
654
655 return val;
656} /* pop */
657
658/* push value onto value stack */
659static var_store_ptr
660push (var_store_ptr push_value, parser_env_ptr pe)
661{
662 if (pe->stack_cnt > pe->stack_size)
663 {
664 pe->stack_size += STACK_INIT;
665 pe->stack = g_realloc (pe->stack,
666 pe->stack_size * sizeof (var_store_ptr));
667 } /* endif */
668
669 pe->stack[(pe->stack_cnt)++] = push_value;
670
671 return push_value;
672} /* push */
673
674/* get/set variable with specified name - nothing fancy just scan each
675 * variable in linked list checking for a string match return variable
676 * found if match create new variable if none found */
677static var_store_ptr
678get_named_var (parser_env_ptr pe)
679{
680 var_store_ptr retp = NULL, bv;
681
682 for (retp = pe->predefined_vars, bv = NULL; retp; retp = retp->next_var)
683 if (strcmp (retp->variable_name, pe->name) == 0)
684 break;
685
686 if (!retp && pe->named_vars)
687 for (retp = pe->named_vars; retp; bv = retp, retp = retp->next_var)
688 if (strcmp (retp->variable_name, pe->name) == 0)
689 break;
690
691 if (!retp)
692 {
693 retp = g_new0 (var_store, 1);
694 if (!pe->named_vars)
695 pe->named_vars = retp;
696 else
697 bv->next_var = retp;
698 retp->variable_name = g_strdup (pe->name);
699 retp->type = VST_NUMERIC;
700 retp->value =
701 pe->trans_numeric ("0", pe->radix_point, pe->group_char, NULL);
702 }
703
704 return retp;
705} /* get_var */
706
707/* get un-named temporary variable */
708static var_store_ptr
709get_unnamed_var (parser_env_ptr pe)
710{
711 var_store_ptr retp = NULL;
712 unsigned cntr;
713
714 for (cntr = 0; cntr < UNNAMED_VARS; cntr++)
715 if (pe->unnamed_vars[cntr].use_flag == UNUSED_VAR)
716 {
717 retp = &(pe->unnamed_vars[cntr]);
718 retp->variable_name = NULL;
719 retp->use_flag = USED_VAR;
720 retp->type = VST_NUMERIC;
721 if (retp->value)
722 {
723 pe->free_numeric (retp->value);
724 retp->value = NULL;
725 } /* endif */
726 break;
727 } /* endif */
728
729 if (retp == NULL)
730 pe->error_code = PARSER_OUT_OF_MEMORY;
731
732 return retp;
733} /* get_unnamed_var */
734
735/* mark un-named temporary variable unused */
736static void
737free_var (var_store_ptr value, parser_env_ptr pe)
738{
739 if (value == NULL)
740 return;
741
742 /* first check that not a named variable */
743 if (value->variable_name != NULL)
744 return;
745
746 value->use_flag = UNUSED_VAR;
747
748 if (value->value)
749 {
750 pe->free_numeric (value->value);
751 value->value = NULL;
752 }
753} /* free_var */
754
755static void
756add_token (parser_env_ptr pe, char token)
757{
758 pe->Token = token;
759 if ((token != EOS) || (*pe->token_tail != EOS))
760 {
761 *pe->token_tail = token;
762 pe->token_tail++;
763 }
764}
765
766/* parse next token from string */
767static void
768next_token (parser_env_ptr pe)
769{
770 char *nstr;
771 const char *str_parse = pe->parse_str;
772 void *number;
773
774 while (isspace (*str_parse))
775 str_parse++;
776
777 pe->asn_op = EOS;
778
779 /* test for end of string */
780 if (!*str_parse)
781 {
782 add_token (pe, EOS);
783 }
784 /* test for possible operator */
785 else if (strchr (allowed_operators, *str_parse))
786 {
787 add_token (pe, *str_parse++);
788 if (*str_parse == ASN_OP)
789 {
790 /* BUG/FIXME: this seems to allow '(=' and ')=' [?], neither of which
791 * make sense. */
792 if (pe->Token != ASN_OP)
793 {
794 str_parse++;
795 pe->asn_op = pe->Token;
796 add_token (pe, ASN_OP);
797 }
798 else
799 pe->error_code = UNDEFINED_CHARACTER;
800 } /* endif */
801 }
802 /* test for string */
803 else if ( *str_parse == '"' )
804 {
805 nstr = pe->name;
806 /* skip over the '"'. */
807 str_parse++;
808 do
809 {
810 *nstr++ = *str_parse++;
811 }
812 while ( *str_parse != '"' );
813 *nstr = EOS;
814 str_parse++;
815 add_token( pe, STR_TOKEN );
816 }
817 /* test for name */
818 else if (isalpha (*str_parse)
819 || (*str_parse == '_'))
820 {
821 int funcFlag = 0;
822
823 /* Check for variable or function */
824 /* If variable: add token. */
825 /* If function: parse args, build struct, add token. */
826 nstr = pe->name;
827 do
828 {
829 if ( *str_parse == '(' )
830 {
831 funcFlag = 1;
832 str_parse++;
833 break;
834 }
835 *nstr++ = *str_parse++;
836 }
837 while ((*str_parse == '_')
838 || (*str_parse == '(')
839 || isalpha (*str_parse)
840 || isdigit (*str_parse));
841
842 *nstr = EOS;
843 if ( funcFlag )
844 {
845 add_token(pe, FN_TOKEN);
846 }
847 else
848 {
849 add_token(pe, VAR_TOKEN);
850 }
851
852 }
853 /* test for numeric token */
854 else if ((number = pe->trans_numeric (str_parse, pe->radix_point,
855 pe->group_char, &nstr)))
856 {
857 add_token (pe, NUM_TOKEN);
858 pe->numeric_value = number;
859 str_parse = nstr;
860 }
861 /* unrecognized character - error */
862 else
863 {
864 add_token (pe, *str_parse);
865 pe->error_code = UNDEFINED_CHARACTER;
866 } /* endif */
867
868 pe->parse_str = str_parse;
869} /* next_token */
870
871/* evaluate assignment operators,
872 * =
873 * +=
874 * -=
875 * \=
876 * *=
877 */
878/* FIXME: add non-numeric checking. */
879static void
880assignment_op (parser_env_ptr pe)
881{
882 var_store_ptr vl; /* left value */
883 var_store_ptr vr; /* right value */
884 char ao;
885
886 add_sub_op (pe);
887 if (pe->error_code)
888 return;
889
890 while (pe->Token == ASN_OP)
891 {
892 vl = pop (pe);
893 if (pe->error_code)
894 return;
895
896 ao = pe->asn_op;
897
898 if (vl->variable_name)
899 {
900 next_token (pe);
901 if (pe->error_code)
902 {
903 free_var (vl, pe);
904 return;
905 }
906
907 assignment_op (pe);
908 if (pe->error_code)
909 {
910 free_var (vl, pe);
911 return;
912 }
913
914 vr = pop (pe);
915 if (pe->error_code)
916 {
917 free_var (vl, pe);
918 return;
919 }
920
921 vl->assign_flag = ASSIGNED_TO;
922
923 if (ao)
924 {
925 void *temp;
926
927 temp = vl->value;
928 vl->value = pe->numeric_ops (ao, vl->value, vr->value);
929 pe->free_numeric (temp);
930 }
931 else if (vl != vr)
932 {
933 if (!vr->variable_name)
934 {
935 pe->free_numeric (vl->value);
936 vl->value = vr->value;
937 vr->value = NULL;
938 }
939 else
940 {
941 pe->numeric_ops (ASN_OP, vl->value, vr->value);
942 }
943
944 free_var (vr, pe);
945 } /* endif */
946
947 push (vl, pe);
948 }
949 else
950 {
951 add_token (pe, EOS); /* error !!!!!!!!!! */
952 pe->error_code = NOT_A_VARIABLE;
953 free_var (vl, pe);
954 } /* endif */
955 } /* endwhile */
956} /* assignment_op */
957
958/* evaluate addition, subtraction operators */
959/* FIXME: add non-numeric checking. */
960static void
961add_sub_op (parser_env_ptr pe)
962{
963 var_store_ptr vl; /* left value */
964 var_store_ptr vr; /* right value */
965 var_store_ptr rslt; /* result */
966 char op;
967
968 multiply_divide_op (pe);
969 if (pe->error_code)
970 return;
971
972 while ((pe->Token == ADD_OP) || (pe->Token == SUB_OP))
973 {
974 op = pe->Token;
975
976 vl = pop (pe);
977 if (pe->error_code)
978 return;
979
980 next_token (pe);
981 if (pe->error_code)
982 {
983 free_var (vl, pe);
984 return;
985 }
986
987 multiply_divide_op (pe);
988 if (pe->error_code)
989 {
990 free_var (vl, pe);
991 return;
992 }
993
994 vr = pop (pe);
995 if (pe->error_code)
996 {
997 free_var (vl, pe);
998 return;
999 }
1000
1001 rslt = get_unnamed_var (pe);
1002 if (pe->error_code)
1003 {
1004 free_var (vl, pe);
1005 free_var (vr, pe);
1006 return;
1007 }
1008
1009 rslt->value = pe->numeric_ops (op, vl->value, vr->value);
1010
1011 free_var (vl, pe);
1012 free_var (vr, pe);
1013
1014 push (rslt, pe);
1015 } /* endwhile */
1016} /* add_sub_op */
1017
1018/* evaluate multiplication, division operators */
1019/* FIXME: add non-numeric checking. */
1020static void
1021multiply_divide_op (parser_env_ptr pe)
1022{
1023 var_store_ptr vl; /* left value */
1024 var_store_ptr vr; /* right value */
1025 var_store_ptr rslt; /* result */
1026 char op;
1027
1028 primary_exp (pe);
1029 if (pe->error_code)
1030 return;
1031
1032 while ((pe->Token == MUL_OP) || (pe->Token == DIV_OP))
1033 {
1034 op = pe->Token;
1035
1036 vl = pop (pe);
1037 if (pe->error_code)
1038 return;
1039
1040 next_token (pe);
1041 if (pe->error_code)
1042 {
1043 free_var (vl, pe);
1044 return;
1045 }
1046
1047 primary_exp (pe);
1048 if (pe->error_code)
1049 {
1050 free_var (vl, pe);
1051 return;
1052 }
1053
1054 vr = pop (pe);
1055 if (pe->error_code)
1056 {
1057 free_var (vl, pe);
1058 return;
1059 }
1060
1061 rslt = get_unnamed_var (pe);
1062 if (pe->error_code)
1063 {
1064 free_var (vl, pe);
1065 free_var (vr, pe);
1066 return;
1067 }
1068
1069 rslt->value = pe->numeric_ops (op, vl->value, vr->value);
1070
1071 free_var (vl, pe);
1072 free_var (vr, pe);
1073
1074 push (rslt, pe);
1075 } /* endwhile */
1076} /* multiply_divide_op */
1077
1083static int
1084check_expression_grammar_error(parser_env_ptr pe)
1085{
1086 if (pe->Token == VAR_TOKEN
1087 || pe->Token == STR_TOKEN
1088 || pe->Token == NUM_TOKEN
1089 || pe->Token == FN_TOKEN)
1090 {
1091 add_token(pe, EOS);
1092 pe->error_code = EXPRESSION_ERROR;
1093 return TRUE;
1094 }
1095 return FALSE;
1096}
1097
1098/* evaluate:
1099 * unary '+' and '-'
1100 * named variables
1101 * numerics
1102 * grouped expressions, "()"
1103 * functions [ <name>( [exp : exp : ... : exp] ) ]
1104 * strings
1105 */
1106static void
1107primary_exp (parser_env_ptr pe)
1108{
1109 var_store_ptr rslt = NULL;
1110 char *ident = NULL;
1111 int funcArgCount;
1112 char LToken = pe->Token;
1113
1114 /* If we are in a state where the non-stacked 'pe->name' is valuable, then
1115 * save it before we process the next token. */
1116 switch ( LToken )
1117 {
1118 case FN_TOKEN:
1119 case STR_TOKEN:
1120 ident = g_strdup( pe->name );
1121 break;
1122 }
1123
1124 next_token (pe);
1125 if (pe->error_code)
1126 return;
1127
1128 switch (LToken)
1129 {
1130 case '(':
1131 assignment_op (pe);
1132 if (pe->error_code)
1133 return;
1134
1135 if (pe->Token == ')')
1136 {
1137 rslt = pop (pe);
1138 if (pe->error_code)
1139 return;
1140
1141 next_token (pe);
1142 if (pe->error_code)
1143 return;
1144 }
1145 else
1146 {
1147 add_token (pe, EOS); /* error here */
1148 pe->error_code = UNBALANCED_PARENS;
1149 } /* endif */
1150
1151 break;
1152
1153 case ADD_OP:
1154 case SUB_OP:
1155 primary_exp (pe);
1156 if (pe->error_code)
1157 return;
1158
1159 rslt = pop (pe);
1160 if (pe->error_code)
1161 return;
1162
1163 if (LToken == SUB_OP)
1164 pe->negate_numeric (rslt->value);
1165
1166 break;
1167
1168 case NUM_TOKEN:
1169 rslt = get_unnamed_var (pe);
1170 if (pe->error_code)
1171 return;
1172
1173 if (check_expression_grammar_error(pe))
1174 return;
1175
1176 rslt->value = pe->numeric_value;
1177 pe->numeric_value = NULL;
1178 break;
1179
1180 case FN_TOKEN:
1181 funcArgCount = 0;
1182
1183 if (pe->Token && pe->Token != ')')
1184 {
1185 do
1186 {
1187 assignment_op(pe);
1188 if ( pe->error_code )
1189 return;
1190 funcArgCount++;
1191 if (!pe->Token || pe->Token == ')')
1192 {
1193 break;
1194 }
1195 next_token(pe);
1196 }
1197 while (pe->Token != ARG_TOKEN);
1198 }
1199
1200 if ( pe->Token != ')' )
1201 {
1202 add_token( pe, EOS );
1203 pe->error_code = UNBALANCED_PARENS;
1204 }
1205
1206 {
1207 int i;
1208 var_store_ptr val;
1209 void **argv;
1210
1211 argv = g_new0( void*, funcArgCount );
1212 for ( i = 0; i < funcArgCount; i++ )
1213 {
1214 /* fill, in back-to-front order, the funcArgCount tokens we just
1215 * parsed out of the expression into a argument list to hand back
1216 * to the caller's func_op callback. */
1217 val = pop(pe);
1218 argv[funcArgCount - i - 1] = val;
1219 }
1220
1221 rslt = get_unnamed_var(pe);
1222 rslt->value = (*pe->func_op)( ident, funcArgCount, argv );
1223
1224 for ( i = 0; i < funcArgCount; i++ )
1225 {
1226 free_var( argv[i], pe );
1227 }
1228 g_free( argv );
1229 g_free( ident );
1230
1231 if ( rslt->value == NULL )
1232 {
1233 pe->error_code = NOT_A_FUNC;
1234 add_token( pe, EOS );
1235 return;
1236 }
1237 }
1238
1239 next_token(pe);
1240
1241 if (check_expression_grammar_error(pe))
1242 return;
1243
1244 break;
1245
1246 case VAR_TOKEN:
1247 if (check_expression_grammar_error(pe))
1248 return;
1249
1250 rslt = get_named_var (pe);
1251 break;
1252 case STR_TOKEN:
1253 if (!(pe->Token == ')'
1254 || pe->Token == ARG_TOKEN))
1255 {
1256 add_token(pe, EOS);
1257 pe->error_code = EXPRESSION_ERROR;
1258 return;
1259 }
1260
1261 rslt = get_unnamed_var( pe );
1262 rslt->type = VST_STRING;
1263 rslt->value = ident;
1264 break;
1265 } /* endswitch */
1266
1267 if (rslt != NULL)
1268 push (rslt, pe);
1269
1270} /* primary_exp */