GnuCash  5.6-150-g038405b370+
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  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 */
642 static var_store_ptr
643 pop (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 */
659 static var_store_ptr
660 push (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 */
677 static var_store_ptr
678 get_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 */
708 static var_store_ptr
709 get_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 */
736 static void
737 free_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 
755 static void
756 add_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 */
767 static void
768 next_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. */
879 static void
880 assignment_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. */
960 static void
961 add_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. */
1020 static void
1021 multiply_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 
1083 static int
1084 check_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  */
1106 static void
1107 primary_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 */