GnuCash  4.11-137-g155922540d+
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 */
400 typedef 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 }
431 parser_env;
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 
449 static char allowed_operators[] = "+-*/()=:";
450 
451 parser_env_ptr
452 init_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 
488 void
489 exit_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 */
526 ParseError 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 */
535 var_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 */
545 unsigned
546 delete_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. */
583 char *
584 parse_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  pe->negate_numeric (val->value);
616  push (val, pe);
617  }
618  }
619 
620  if (pe->Token == EOS)
621  {
622  if ((pe->stack_cnt) && (retv = pop (pe)))
623  {
624  if (value != NULL)
625  *value = *retv;
626  pe->parse_str = NULL;
627  }
628  else
629  pe->error_code = STACK_UNDERFLOW;
630  }
631 
632  pe->stack_cnt = 0;
633  pe->unnamed_vars = NULL;
634 
635  return (char *) pe->parse_str;
636 } /* expression */
637 
638 /* pop value off value stack */
639 static var_store_ptr
640 pop (parser_env_ptr pe)
641 {
642  var_store_ptr val;
643 
644  if (pe->stack_cnt)
645  val = pe->stack[--(pe->stack_cnt)];
646  else
647  {
648  val = NULL;
649  pe->error_code = STACK_UNDERFLOW;
650  } /* endif */
651 
652  return val;
653 } /* pop */
654 
655 /* push value onto value stack */
656 static var_store_ptr
657 push (var_store_ptr push_value, parser_env_ptr pe)
658 {
659  if (pe->stack_cnt > pe->stack_size)
660  {
661  pe->stack_size += STACK_INIT;
662  pe->stack = g_realloc (pe->stack,
663  pe->stack_size * sizeof (var_store_ptr));
664  } /* endif */
665 
666  pe->stack[(pe->stack_cnt)++] = push_value;
667 
668  return push_value;
669 } /* push */
670 
671 /* get/set variable with specified name - nothing fancy just scan each
672  * variable in linked list checking for a string match return variable
673  * found if match create new variable if none found */
674 static var_store_ptr
675 get_named_var (parser_env_ptr pe)
676 {
677  var_store_ptr retp = NULL, bv;
678 
679  for (retp = pe->predefined_vars, bv = NULL; retp; retp = retp->next_var)
680  if (strcmp (retp->variable_name, pe->name) == 0)
681  break;
682 
683  if (!retp && pe->named_vars)
684  for (retp = pe->named_vars; retp; bv = retp, retp = retp->next_var)
685  if (strcmp (retp->variable_name, pe->name) == 0)
686  break;
687 
688  if (!retp)
689  {
690  retp = g_new0 (var_store, 1);
691  if (!pe->named_vars)
692  pe->named_vars = retp;
693  else
694  bv->next_var = retp;
695  retp->variable_name = g_strdup (pe->name);
696  retp->type = VST_NUMERIC;
697  retp->value =
698  pe->trans_numeric ("0", pe->radix_point, pe->group_char, NULL);
699  }
700 
701  return retp;
702 } /* get_var */
703 
704 /* get un-named temporary variable */
705 static var_store_ptr
706 get_unnamed_var (parser_env_ptr pe)
707 {
708  var_store_ptr retp = NULL;
709  unsigned cntr;
710 
711  for (cntr = 0; cntr < UNNAMED_VARS; cntr++)
712  if (pe->unnamed_vars[cntr].use_flag == UNUSED_VAR)
713  {
714  retp = &(pe->unnamed_vars[cntr]);
715  retp->variable_name = NULL;
716  retp->use_flag = USED_VAR;
717  retp->type = VST_NUMERIC;
718  if (retp->value)
719  {
720  pe->free_numeric (retp->value);
721  retp->value = NULL;
722  } /* endif */
723  break;
724  } /* endif */
725 
726  if (retp == NULL)
727  pe->error_code = PARSER_OUT_OF_MEMORY;
728 
729  return retp;
730 } /* get_unnamed_var */
731 
732 /* mark un-named temporary variable unused */
733 static void
734 free_var (var_store_ptr value, parser_env_ptr pe)
735 {
736  if (value == NULL)
737  return;
738 
739  /* first check that not a named variable */
740  if (value->variable_name != NULL)
741  return;
742 
743  value->use_flag = UNUSED_VAR;
744 
745  if (value->value)
746  {
747  pe->free_numeric (value->value);
748  value->value = NULL;
749  }
750 } /* free_var */
751 
752 static void
753 add_token (parser_env_ptr pe, char token)
754 {
755  pe->Token = token;
756  if ((token != EOS) || (*pe->token_tail != EOS))
757  {
758  *pe->token_tail = token;
759  pe->token_tail++;
760  }
761 }
762 
763 /* parse next token from string */
764 static void
765 next_token (parser_env_ptr pe)
766 {
767  char *nstr;
768  const char *str_parse = pe->parse_str;
769  void *number;
770 
771  while (isspace (*str_parse))
772  str_parse++;
773 
774  pe->asn_op = EOS;
775 
776  /* test for end of string */
777  if (!*str_parse)
778  {
779  add_token (pe, EOS);
780  }
781  /* test for possible operator */
782  else if (strchr (allowed_operators, *str_parse))
783  {
784  add_token (pe, *str_parse++);
785  if (*str_parse == ASN_OP)
786  {
787  /* BUG/FIXME: this seems to allow '(=' and ')=' [?], neither of which
788  * make sense. */
789  if (pe->Token != ASN_OP)
790  {
791  str_parse++;
792  pe->asn_op = pe->Token;
793  add_token (pe, ASN_OP);
794  }
795  else
796  pe->error_code = UNDEFINED_CHARACTER;
797  } /* endif */
798  }
799  /* test for string */
800  else if ( *str_parse == '"' )
801  {
802  nstr = pe->name;
803  /* skip over the '"'. */
804  str_parse++;
805  do
806  {
807  *nstr++ = *str_parse++;
808  }
809  while ( *str_parse != '"' );
810  *nstr = EOS;
811  str_parse++;
812  add_token( pe, STR_TOKEN );
813  }
814  /* test for name */
815  else if (isalpha (*str_parse)
816  || (*str_parse == '_'))
817  {
818  int funcFlag = 0;
819 
820  /* Check for variable or function */
821  /* If variable: add token. */
822  /* If function: parse args, build struct, add token. */
823  nstr = pe->name;
824  do
825  {
826  if ( *str_parse == '(' )
827  {
828  funcFlag = 1;
829  str_parse++;
830  break;
831  }
832  *nstr++ = *str_parse++;
833  }
834  while ((*str_parse == '_')
835  || (*str_parse == '(')
836  || isalpha (*str_parse)
837  || isdigit (*str_parse));
838 
839  *nstr = EOS;
840  if ( funcFlag )
841  {
842  add_token(pe, FN_TOKEN);
843  }
844  else
845  {
846  add_token(pe, VAR_TOKEN);
847  }
848 
849  }
850  /* test for numeric token */
851  else if ((number = pe->trans_numeric (str_parse, pe->radix_point,
852  pe->group_char, &nstr)))
853  {
854  add_token (pe, NUM_TOKEN);
855  pe->numeric_value = number;
856  str_parse = nstr;
857  }
858  /* unrecognized character - error */
859  else
860  {
861  add_token (pe, *str_parse);
862  pe->error_code = UNDEFINED_CHARACTER;
863  } /* endif */
864 
865  pe->parse_str = str_parse;
866 } /* next_token */
867 
868 /* evaluate assignment operators,
869  * =
870  * +=
871  * -=
872  * \=
873  * *=
874  */
875 /* FIXME: add non-numeric checking. */
876 static void
877 assignment_op (parser_env_ptr pe)
878 {
879  var_store_ptr vl; /* left value */
880  var_store_ptr vr; /* right value */
881  char ao;
882 
883  add_sub_op (pe);
884  if (pe->error_code)
885  return;
886 
887  while (pe->Token == ASN_OP)
888  {
889  vl = pop (pe);
890  if (pe->error_code)
891  return;
892 
893  ao = pe->asn_op;
894 
895  if (vl->variable_name)
896  {
897  next_token (pe);
898  if (pe->error_code)
899  {
900  free_var (vl, pe);
901  return;
902  }
903 
904  assignment_op (pe);
905  if (pe->error_code)
906  {
907  free_var (vl, pe);
908  return;
909  }
910 
911  vr = pop (pe);
912  if (pe->error_code)
913  {
914  free_var (vl, pe);
915  return;
916  }
917 
918  vl->assign_flag = ASSIGNED_TO;
919 
920  if (ao)
921  {
922  void *temp;
923 
924  temp = vl->value;
925  vl->value = pe->numeric_ops (ao, vl->value, vr->value);
926  pe->free_numeric (temp);
927  }
928  else if (vl != vr)
929  {
930  if (!vr->variable_name)
931  {
932  pe->free_numeric (vl->value);
933  vl->value = vr->value;
934  vr->value = NULL;
935  }
936  else
937  {
938  pe->numeric_ops (ASN_OP, vl->value, vr->value);
939  }
940 
941  free_var (vr, pe);
942  } /* endif */
943 
944  push (vl, pe);
945  }
946  else
947  {
948  add_token (pe, EOS); /* error !!!!!!!!!! */
949  pe->error_code = NOT_A_VARIABLE;
950  free_var (vl, pe);
951  } /* endif */
952  } /* endwhile */
953 } /* assignment_op */
954 
955 /* evaluate addition, subtraction operators */
956 /* FIXME: add non-numeric checking. */
957 static void
958 add_sub_op (parser_env_ptr pe)
959 {
960  var_store_ptr vl; /* left value */
961  var_store_ptr vr; /* right value */
962  var_store_ptr rslt; /* result */
963  char op;
964 
965  multiply_divide_op (pe);
966  if (pe->error_code)
967  return;
968 
969  while ((pe->Token == ADD_OP) || (pe->Token == SUB_OP))
970  {
971  op = pe->Token;
972 
973  vl = pop (pe);
974  if (pe->error_code)
975  return;
976 
977  next_token (pe);
978  if (pe->error_code)
979  {
980  free_var (vl, pe);
981  return;
982  }
983 
984  multiply_divide_op (pe);
985  if (pe->error_code)
986  {
987  free_var (vl, pe);
988  return;
989  }
990 
991  vr = pop (pe);
992  if (pe->error_code)
993  {
994  free_var (vl, pe);
995  return;
996  }
997 
998  rslt = get_unnamed_var (pe);
999  if (pe->error_code)
1000  {
1001  free_var (vl, pe);
1002  free_var (vr, pe);
1003  return;
1004  }
1005 
1006  rslt->value = pe->numeric_ops (op, vl->value, vr->value);
1007 
1008  free_var (vl, pe);
1009  free_var (vr, pe);
1010 
1011  push (rslt, pe);
1012  } /* endwhile */
1013 } /* add_sub_op */
1014 
1015 /* evaluate multiplication, division operators */
1016 /* FIXME: add non-numeric checking. */
1017 static void
1018 multiply_divide_op (parser_env_ptr pe)
1019 {
1020  var_store_ptr vl; /* left value */
1021  var_store_ptr vr; /* right value */
1022  var_store_ptr rslt; /* result */
1023  char op;
1024 
1025  primary_exp (pe);
1026  if (pe->error_code)
1027  return;
1028 
1029  while ((pe->Token == MUL_OP) || (pe->Token == DIV_OP))
1030  {
1031  op = pe->Token;
1032 
1033  vl = pop (pe);
1034  if (pe->error_code)
1035  return;
1036 
1037  next_token (pe);
1038  if (pe->error_code)
1039  {
1040  free_var (vl, pe);
1041  return;
1042  }
1043 
1044  primary_exp (pe);
1045  if (pe->error_code)
1046  {
1047  free_var (vl, pe);
1048  return;
1049  }
1050 
1051  vr = pop (pe);
1052  if (pe->error_code)
1053  {
1054  free_var (vl, pe);
1055  return;
1056  }
1057 
1058  rslt = get_unnamed_var (pe);
1059  if (pe->error_code)
1060  {
1061  free_var (vl, pe);
1062  free_var (vr, pe);
1063  return;
1064  }
1065 
1066  rslt->value = pe->numeric_ops (op, vl->value, vr->value);
1067 
1068  free_var (vl, pe);
1069  free_var (vr, pe);
1070 
1071  push (rslt, pe);
1072  } /* endwhile */
1073 } /* multiply_divide_op */
1074 
1080 static int
1081 check_expression_grammar_error(parser_env_ptr pe)
1082 {
1083  if (pe->Token == VAR_TOKEN
1084  || pe->Token == STR_TOKEN
1085  || pe->Token == NUM_TOKEN
1086  || pe->Token == FN_TOKEN)
1087  {
1088  add_token(pe, EOS);
1089  pe->error_code = EXPRESSION_ERROR;
1090  return TRUE;
1091  }
1092  return FALSE;
1093 }
1094 
1095 /* evaluate:
1096  * unary '+' and '-'
1097  * named variables
1098  * numerics
1099  * grouped expressions, "()"
1100  * functions [ <name>( [exp : exp : ... : exp] ) ]
1101  * strings
1102  */
1103 static void
1104 primary_exp (parser_env_ptr pe)
1105 {
1106  var_store_ptr rslt = NULL;
1107  char *ident = NULL;
1108  int funcArgCount;
1109  char LToken = pe->Token;
1110 
1111  /* If we are in a state where the non-stacked 'pe->name' is valuable, then
1112  * save it before we process the next token. */
1113  switch ( LToken )
1114  {
1115  case FN_TOKEN:
1116  case STR_TOKEN:
1117  ident = g_strdup( pe->name );
1118  break;
1119  }
1120 
1121  next_token (pe);
1122  if (pe->error_code)
1123  return;
1124 
1125  switch (LToken)
1126  {
1127  case '(':
1128  assignment_op (pe);
1129  if (pe->error_code)
1130  return;
1131 
1132  if (pe->Token == ')')
1133  {
1134  rslt = pop (pe);
1135  if (pe->error_code)
1136  return;
1137 
1138  next_token (pe);
1139  if (pe->error_code)
1140  return;
1141  }
1142  else
1143  {
1144  add_token (pe, EOS); /* error here */
1145  pe->error_code = UNBALANCED_PARENS;
1146  } /* endif */
1147 
1148  break;
1149 
1150  case ADD_OP:
1151  case SUB_OP:
1152  primary_exp (pe);
1153  if (pe->error_code)
1154  return;
1155 
1156  rslt = pop (pe);
1157  if (pe->error_code)
1158  return;
1159 
1160  if (LToken == SUB_OP)
1161  pe->negate_numeric (rslt->value);
1162 
1163  break;
1164 
1165  case NUM_TOKEN:
1166  rslt = get_unnamed_var (pe);
1167  if (pe->error_code)
1168  return;
1169 
1170  if (check_expression_grammar_error(pe))
1171  return;
1172 
1173  rslt->value = pe->numeric_value;
1174  pe->numeric_value = NULL;
1175  break;
1176 
1177  case FN_TOKEN:
1178  funcArgCount = 0;
1179 
1180  if (pe->Token && pe->Token != ')')
1181  {
1182  do
1183  {
1184  assignment_op(pe);
1185  if ( pe->error_code )
1186  return;
1187  funcArgCount++;
1188  if (!pe->Token || pe->Token == ')')
1189  {
1190  break;
1191  }
1192  next_token(pe);
1193  }
1194  while (pe->Token != ARG_TOKEN);
1195  }
1196 
1197  if ( pe->Token != ')' )
1198  {
1199  add_token( pe, EOS );
1200  pe->error_code = UNBALANCED_PARENS;
1201  }
1202 
1203  {
1204  int i;
1205  var_store_ptr val;
1206  void **argv;
1207 
1208  argv = g_new0( void*, funcArgCount );
1209  for ( i = 0; i < funcArgCount; i++ )
1210  {
1211  /* fill, in back-to-front order, the funcArgCount tokens we just
1212  * parsed out of the expression into a argument list to hand back
1213  * to the caller's func_op callback. */
1214  val = pop(pe);
1215  argv[funcArgCount - i - 1] = val;
1216  }
1217 
1218  rslt = get_unnamed_var(pe);
1219  rslt->value = (*pe->func_op)( ident, funcArgCount, argv );
1220 
1221  for ( i = 0; i < funcArgCount; i++ )
1222  {
1223  free_var( argv[i], pe );
1224  }
1225  g_free( argv );
1226  g_free( ident );
1227 
1228  if ( rslt->value == NULL )
1229  {
1230  pe->error_code = NOT_A_FUNC;
1231  add_token( pe, EOS );
1232  return;
1233  }
1234  }
1235 
1236  next_token(pe);
1237 
1238  if (check_expression_grammar_error(pe))
1239  return;
1240 
1241  break;
1242 
1243  case VAR_TOKEN:
1244  if (check_expression_grammar_error(pe))
1245  return;
1246 
1247  rslt = get_named_var (pe);
1248  break;
1249  case STR_TOKEN:
1250  if (!(pe->Token == ')'
1251  || pe->Token == ARG_TOKEN))
1252  {
1253  add_token(pe, EOS);
1254  pe->error_code = EXPRESSION_ERROR;
1255  return;
1256  }
1257 
1258  rslt = get_unnamed_var( pe );
1259  rslt->type = VST_STRING;
1260  rslt->value = ident;
1261  break;
1262  } /* endswitch */
1263 
1264  if (rslt != NULL)
1265  push (rslt, pe);
1266 
1267 } /* primary_exp */