GnuCash 2.4.99
expression_parser.c
00001 /***************************************************************************
00002                           expression-parser.c  -  description
00003                              -------------------
00004     begin                : Wednesday June 21 2000
00005     email                : tboldt@attglobal.net
00006     Author               : Terry D. Boldt
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 /*
00019  *  Functions to parse arthmetic expressions
00020  *  6-21-2000
00021  */
00022 
00023 /* Modified to support functions - Summer, 2002 -- jsled@asynchronous.org */
00024 
00025 /* expression parser/evaluator use:
00026  *
00027  * Before describing the parser per se, I want to describe the
00028  * structures used to contain the results returned from the
00029  * parser. The structure is defined in "finvar.h":
00030  *
00031  * typedef struct var_store *var_store_ptr;
00032  *
00033  * typedef struct var_store {
00034  *     char *variable_name;
00035  *     char  use_flag;
00036  *     char  assign_flag;
00037  *     void          *value;
00038  *     var_strore_ptr next_var;
00039  * } var_store;
00040  *
00041  * The "use_flag" variable is for internal use of the parser and can
00042  * be ignored by the user. The "variable_name" variable possibly
00043  * points to a string containing the name of the value returned, a
00044  * "variable name". If NULL, then this is a temporary value. The
00045  * "value" variable points to a user defined structure containing the
00046  * numeric value of the variable.
00047  *
00048  * As well, variables now have a VarStoreType, to distinguish between numeric
00049  * and string values, as we want string arguments to functions.
00050  *
00051  * In designing and writing the parser, I decided early on that the
00052  * parser should be an "expression parser/evaluator" and that the
00053  * actual arithmetic was the responsibility of the caller/user.
00054  *
00055  * I decided that the parser should be totally independent of the
00056  * numeric representation used, and thus the exact details of how the
00057  * arithmetic was performed. To accomplish this, four functions are
00058  * supplied by the user/caller:
00059  *
00060  * 1: trans_numeric - this function translates the text string into a
00061  * numeric in the desired representation and returns a pointer to the
00062  * representation as a (void *) this function has four parameters
00063  * passed:
00064  *
00065  *                     1: digit_str -- the actual text string of the
00066  *                     numeric to be converted to the internal
00067  *                     representation
00068  *
00069  *                     2: radix_point -- the ASCII character used to
00070  *                     represent the radix point
00071  *
00072  *                     3: group character -- the ASCII character used
00073  *                     to separate and group digits to the left of the
00074  *                     radix
00075  *
00076  *                     4: rstr -- a pointer to a location in which to
00077  *                     return a pointer to the first character not
00078  *                     part of the numeric string translated If this
00079  *                     pointer is NULL, do not return a value. This
00080  *                     parameter is the same as the second parameter
00081  *                     of the standard C library functions "strtod" or
00082  *                     "strtol"
00083  *
00084  * 2: numeric_ops - this function does the actual arithmetic on two
00085  * numeric quantities in internal representation. It has three
00086  * parameters passed:
00087  *
00088  *                     1: op_sym -- the numeric operation to be
00089  *                     performed. The possible values are defined
00090  *                     in "finvar.h" and are:
00091  *
00092  *                                 ADD_OP - addition
00093  *                                 SUB_OP - subtraction
00094  *                                 DIV_OP - division
00095  *                                 MUL_OP - multiplication
00096  *                                 ASN_OP - assignment
00097  *
00098  *                     2: left_value - the left hand operand of the
00099  *                     binary operator
00100  *
00101  *                     3: right_value - the right hand operand of
00102  *                     the binary operator Note: left_value and
00103  *                     right_value are passed as (void *). This
00104  *                     function is responsible for casting to the
00105  *                     proper type to use.  Note: this function should
00106  *                     make no assumptions about overwriting or
00107  *                     re-using either left_value or right_value,
00108  *                     except for ASN_OP. Both values passed must be
00109  *                     left unchanged by any operation except ASN_OP.
00110  *                     This function is also responsible for
00111  *                     allocating/freeing memory as necessary to
00112  *                     perform the designated function and returning
00113  *                     the result.  I STRONGLY suggest that the result
00114  *                     be returned in dynamically allocated memory. If
00115  *                     static memory is used, the parser has no means
00116  *                     of copying the returned result or managing
00117  *                     static memory to prevent overwriting the result
00118  *                     and invalidating the result.
00119  *
00120  * 3: negate_numeric - this function negates the value passed (as a (void *))
00121  *
00122  * 4: free_numeric - this function is responsible for freeing memory
00123  * used by the internal numeric representation.
00124  *
00125  * 5: func_op - this function is repsonsible for handling function calls.
00126  *
00127  * I have included the file "numeric_ops.c" containing the above
00128  * functions for the usual "double" and "int" representation of
00129  * numerics. The functions perform integer or floating point
00130  * operations as appropriate for the string entered by the user. The
00131  * division operation is done in "double" since I do not think that
00132  * anybody really wants (9 / 2) to equal 4 instead of 4.5 for
00133  * financial operations. These functions use the structure defined in
00134  * finvar.h:
00135  *
00136  * typedef struct numeric *numeric_ptr;
00137  * typedef struct numeric {
00138  *     char  type;
00139  *     union {
00140  *         long int  int_value;
00141  *         double    dbl_value;
00142  *     } value;
00143  * } numeric;
00144  *
00145  * to contain all numeric values. The variable "type" in this
00146  * structure can have the values:
00147  *
00148  *     INT_TYPE
00149  *     DBL_TYPE
00150  *
00151  * which are defined in "finvar.h".
00152  *
00153  * All "named variables", variables defined by the user for storing
00154  * intermediate results for future reference/use, and temporary
00155  * variables used by the parser use the variable storage structure,
00156  * var_store, defined above. The result of parsing and evaluating the
00157  * string passed are returned in a variable storage structure
00158  * specified by the caller.
00159  *
00160  * If the returned variable value is not named, i.e., "variable_name
00161  * == NULL", then the user/caller is responsible for freeing the
00162  * memory used by the internal representation of the numeric value.
00163  * If, however, "variable_name != NULL", freeing the memory used by
00164  * the internal numeric representation will cause a segmentation fault
00165  * later, when the parser attempts to free the memory through a call
00166  * to "free_numeric". In addition, freeing the memory will probably
00167  * invalidate the numeric value contained therein and lead to
00168  * pernicuous results when the value is used.
00169  *
00170  * If "variable_name != NULL", the user/caller should never attempt to
00171  * free this memory, that is the sole responsibility of the parser.
00172  *
00173  * It may be that the calling function has certain "variables" that
00174  * need to be "pre-defined" for the user to manipulate.  In essence
00175  * the function "pre-defining" variables sets up a linked list of
00176  * variable storage structures with the proper "names" and numeric
00177  * values. The number of "pre-defined" variables and a pointer to the
00178  * structure array is passed to the parser in the initialization
00179  * call. After the parser is eventually exited, the calling function
00180  * is responsible for freeing any memory used by the "pre-defined"
00181  * variables and their final numeric representation.
00182  *
00183  * There may also be strings in the expression, by quoting them in '"'
00184  * characters.  These are intended to be passed literally into functions; the
00185  * result of using a string in a numeric operation is undefined.  Presently,
00186  * the expression-parser code does not check the variable types during
00187  * parsing or evaluation.
00188  *
00189  * A second design goal of the parser was that it should be callable
00190  * concurrently by multiple modules independently. That each module
00191  * should be capable of using differing "pre-defined" variables and
00192  * user defined variables and even internal numeric representations.
00193  * To that end the calling module must first initialize the parser
00194  * with a call to "init_parser".  This call creates the parser
00195  * internal structure for subsequent calls to the parser proper.  The
00196  * structure created and returned must then be passed to subsequent
00197  * calls to the parser.  When no further calls to the parser are to be
00198  * made, the module then calls "exit_parser" with the pointer returned
00199  * by "init_parser", so that the parser may release dynamically
00200  * allocated memory.
00201  *
00202  * The parser recognizes the following binary operators:
00203  *
00204  *      +
00205  *      -
00206  *      /
00207  *      *
00208  *      =
00209  *      +=
00210  *      -=
00211  *      /=
00212  *      *=
00213  *
00214  * In addition, the unary operators
00215  *
00216  *  +
00217  *  -
00218  *
00219  * are recognized. All numerics are initially recognized as positive
00220  * numbers. If negative, the unary '-' operator is applied. This saves
00221  * the logic of having to recogize strings as
00222  *
00223  *   -123
00224  *
00225  * The logic recognizes "-" and "123" separately. The '-' unary
00226  * operator is then applied to negate the numeric. This also has the
00227  * advanatge that the same logic can be used for
00228  *
00229  *  -123
00230  *  +123.45
00231  *  +uvar
00232  *  -uvar
00233  *
00234  *  In each case, the appropriate unary operator is applied to obtain
00235  *  the desired * result with no increase in the parsing logic. Thus
00236  *  keeping things as simple as possible.
00237  *
00238  * The parser also follows the C practice that the assignment
00239  * operators return a value. Thus, allowing multiple assignments and
00240  * assignment within expressions. The following expressions are all
00241  * valid:
00242  *
00243  *  nni = 123
00244  *  hnk = nni = 23.45
00245  *  jkl = 5 * (nj = 68.9)
00246  *
00247  * The first time variables are used in an expression, they are
00248  * initialized to zero, 0. Thus, even if the following variables have
00249  * not been assigned a value previously, the following expressions are
00250  * valid:
00251  *
00252  * nni *= 123
00253  *   above results in zero in nni
00254  * jk += 45.6
00255  *   above results in 45.6 in jk
00256  * 56.8 - tyh
00257  *   result of above is 56.8
00258  * tgh - 45.7
00259  *   above the same as
00260  * -45.7
00261  *
00262  * After parsing the above expressions the variables nni, jk, tyh and
00263  * tgh would all be defined.
00264  *
00265  * Functions are invoked with expressions of the format
00266  *
00267  *   [_a-zA-Z]( <argument_0> : <argument_1> : ... : <argument_n> )
00268  *
00269  * where each argument can itself be a sub-expression [arithmetic operation
00270  * or function call].
00271  *
00272  *
00273  * There are six parser functions needed to use the parser/evaluator:
00274  *
00275  * Note: in the last five functions, in the function paramter (void
00276  * *vp), "vp" is the pointer returned by the "init_parser" function.
00277  *
00278  * void *init_parser(var_store_ptr  predefined_vars,
00279  *                   gchar  *radix_point,
00280  *                   gchar  *group_char,
00281  *                   void          *trans_numeric(char  *digit_str,
00282  *                                                gchar *radix_point,
00283  *                                                gchar *group_char,
00284  *                                                char **rstr),
00285  *                   void          *numeric_ops(char  op_sym,
00286  *                                              void          *left_value,
00287  *                                              void          *right_value),
00288  *                   void          *negate_numeric(void *value),
00289  *                   void           free_numeric(void *numeric_value),
00290  *                   void          *func_op(const char *fname, int argc, void **argv));
00291  *
00292  *         This function is called by the module/function/whatever to
00293  *         initialize the parser. The parser returns a pointer to a
00294  *         structure that contains all relevant information for
00295  *         parsering strings. The pointer is returned as (void *)
00296  *         since all information is and should remain pertinent only
00297  *         to the parser. The calling function(s) should never rely on
00298  *         manipulating any information inside this structure
00299  *         directly, since it may and could change in the future.  --
00300  *         The first parameter is a pointer to a the first element in
00301  *         a linked list of "pre-defined" variables the caller wishes
00302  *         to use with subsequent calls to the parser.  -- The second
00303  *         parameter is the radix character to use in numeric strings
00304  *         in subsequent calls to the parser.  -- the third parameter
00305  *         is the optional character used for grouping digits to the
00306  *         left of the radix.  -- The fourth, fifth, sixth and seventh
00307  *         parameters are the functions I descibed above for the
00308  *         internal numeric representation desired by the calling
00309  *         function(s).
00310  *
00311  * void                     exit_parser(
00312  *                                      void *vp);
00313  *
00314  *         This function is called to exit the parser and free all
00315  *         dynamically allocated memory used by the parser for an
00316  *         internal stack and user defined variables.
00317  *
00318  * unsigned                 get_parse_error(
00319  *                                          void *vp);
00320  *
00321  *         If the parser is successful in complete parsing and
00322  *         evaluating the string passed to 'parse_string' below, that
00323  *         functions returns a NULL pointer. If, however, an error is
00324  *         encountered in parsing/evaluating the string, the
00325  *         'parse_string' function returns a pointer to the character
00326  *         which caused the error.  This call returns an unsigned
00327  *         integer designating the error encountered. The possible
00328  *         values are defined in the "finvar.h" file.
00329  *
00330  * var_store_ptr            parser_get_vars(
00331  *                                          void *vp)
00332  *
00333  *         This function returns a pointer to the first element of a
00334  *         linked list of variable storage structures containing the
00335  *         user defined named variables if any exist.  NULL is
00336  *         returned if none exist. The calling function should not
00337  *         alter the variable names.  The numeric values may be
00338  *         altered if the calling function author really knows what
00339  *         they are doing.
00340  *
00341  * unsigned                 delete_var(
00342  *                                     char *var_name,
00343  *                                     void *vp);
00344  *
00345  *         This function will delete the user defined named variable
00346  *         with a name identical to the name string passed in the
00347  *         first parameter. If no user defined variable exists with an
00348  *         identical name, zero, 0, is returned. If the delete
00349  *         operation is successful, one, 1, is returned.
00350  *
00351  * char           *parse_string(
00352  *                                       var_store_ptr value,
00353  *                                       char *string,
00354  *                                       void *vp);
00355  *
00356  *         This function parses the string passed in the second
00357  *         parameter and returns a pointer to the last character not
00358  *         recognized upon a parsing error. If no error occurred, NULL
00359  *         is returned. The first parameter is a pointer to a variable
00360  *         storage structure to contain the result of the
00361  *         parser/evaluator.
00362  *
00363  * Note: The parser/evaluator uses a simple recursive descent
00364  * parser. I decided on this type for the simple reason that for a
00365  * simple four function calculator a recursive descent parser is, in
00366  * my opinion, the easiest to construct. I also think that recursive
00367  * descent parsers are easier for the human to understand and thus
00368  * maintain.
00369  *
00370  * Also, the parser uses a stack which is dynamically allocated in
00371  * memory and can grow as needed.  I have not provided any mechanism
00372  * for shrinking the stack. The initial stack size is set at 50
00373  * slots. I really do not anticipate that under normal and even most
00374  * extreme cases, that it will ever approach that size in actual
00375  * use. Under "normal" operation, the stack will probably never exceed
00376  * 3 or 4 slots in size and 50 slots is probably an overkill for
00377  * normal use. However, since the stack is pointers and not entire
00378  * structures, a stack size of 50 slots is not that much memory and
00379  * can be tolerated by most users. Thus, a mechanism for shrinking the
00380  * stack will probably never be needed.
00381  */
00382 
00383 #include "config.h"
00384 #include <ctype.h>
00385 #include <stdio.h>
00386 #include <string.h>
00387 #include <stdlib.h>
00388 
00389 #include <glib.h>
00390 
00391 #include "qof.h"
00392 
00393 #define EXPRESSION_PARSER_STATICS
00394 #include "finvar.h"
00395 
00396 #define MAX_FUNC_ARG_LEN 255
00397 
00398 /* structure to hold parser environment - environment particular to
00399  * each caller */
00400 typedef struct parser_env
00401 {
00402     unsigned stack_cnt;
00403     unsigned stack_size;
00404     var_store_ptr *stack;
00405     var_store_ptr predefined_vars;
00406     var_store_ptr named_vars;
00407     var_store_ptr unnamed_vars;
00408 
00409     const char *parse_str;
00410     gchar *radix_point;
00411     gchar *group_char;
00412     char name[128];
00413 
00414     char Token;
00415     char asn_op;
00416 
00417     char *tokens;
00418     char *token_tail;
00419 
00420     ParseError error_code;
00421 
00422     void *numeric_value;
00423 
00424     void *(*trans_numeric) (const char *digit_str,
00425                             gchar *radix_point, gchar *group_char, char **rstr);
00426     void *(*numeric_ops) (char op_sym, void *left_value, void *right_value);
00427     void *(*negate_numeric) (void *value);
00428     void (*free_numeric) (void *numeric_value);
00429     void *(*func_op)( const char *fname, int argc, void **argv );
00430 }
00431 parser_env;
00432 
00433 #include "finproto.h"
00434 #include "fin_static_proto.h"
00435 #include "fin_spl_protos.h"
00436 
00437 #define FN_TOKEN 'F'
00438 #define ARG_TOKEN ':'
00439 #define VAR_TOKEN 'V'
00440 #define NUM_TOKEN 'I'
00441 #define STR_TOKEN '"'
00442 
00443 #define STACK_INIT 50
00444 
00445 #define UNNAMED_VARS 100
00446 
00447 #define NAMED_INCR 5
00448 
00449 static char allowed_operators[] = "+-*/()=:";
00450 
00451 parser_env_ptr
00452 init_parser (var_store_ptr predefined_vars,
00453              gchar *radix_point,
00454              gchar *group_char,
00455              void *trans_numeric (const char *digit_str,
00456                                   gchar *radix_point,
00457                                   gchar *group_char,
00458                                   char **rstr),
00459              void *numeric_ops (char op_sym,
00460                                 void *left_value,
00461                                 void *right_value),
00462              void *negate_numeric (void *value),
00463              void free_numeric (void *numeric_value),
00464              void *func_op( const char *fname,
00465                             int argc, void **argv ))
00466 {
00467     parser_env_ptr pe = g_new0 (parser_env, 1);
00468 
00469     pe->predefined_vars = predefined_vars;
00470 
00471     pe->stack = g_new0 (var_store_ptr, STACK_INIT);
00472     pe->stack_size = STACK_INIT;
00473 
00474     pe->radix_point = radix_point;
00475     pe->group_char = group_char;
00476 
00477     pe->numeric_value = NULL;
00478 
00479     pe->trans_numeric = trans_numeric;
00480     pe->numeric_ops = numeric_ops;
00481     pe->negate_numeric = negate_numeric;
00482     pe->free_numeric = free_numeric;
00483     pe->func_op = func_op;
00484 
00485     return pe;
00486 }                               /* init_parser */
00487 
00488 void
00489 exit_parser (parser_env_ptr pe)
00490 {
00491     var_store_ptr vars, bv;
00492 
00493     if (pe == NULL)
00494         return;
00495 
00496     for (vars = pe->named_vars; vars; vars = bv)
00497     {
00498         g_free (vars->variable_name);
00499         vars->variable_name = NULL;
00500 
00501         if (vars->value)
00502             pe->free_numeric (vars->value);
00503         vars->value = NULL;
00504 
00505         bv = vars->next_var;
00506         g_free (vars);
00507     }                           /* endfor */
00508 
00509     pe->named_vars = NULL;
00510 
00511     g_free (pe->stack);
00512     pe->stack = NULL;
00513 
00514     g_free (pe->tokens);
00515     pe->tokens = NULL;
00516     pe->token_tail = NULL;
00517 
00518     if (pe->numeric_value)
00519         pe->free_numeric (pe->numeric_value);
00520     pe->numeric_value = NULL;
00521 
00522     g_free (pe);
00523 }                               /* exit_parser */
00524 
00525 /* return parser error code */
00526 ParseError get_parse_error (parser_env_ptr pe)
00527 {
00528     if (pe == NULL)
00529         return PARSER_NO_ERROR;
00530 
00531     return pe->error_code;
00532 }                               /* get_parse_error */
00533 
00534 /* return linked list of named variables which have been defined */
00535 var_store_ptr parser_get_vars (parser_env_ptr pe)
00536 {
00537     if (pe == NULL)
00538         return NULL;
00539 
00540     return pe->named_vars;
00541 }                               /* get_vars */
00542 
00543 /* function to delete variable with specified name from named variables
00544  * if it exists. If it exists return TRUE, 1, else return FALSE, 0 */
00545 unsigned
00546 delete_var (char *var_name, parser_env_ptr pe)
00547 {
00548     unsigned ret = FALSE;
00549     var_store_ptr nv, tv;
00550 
00551     if (pe == NULL)
00552         return FALSE;
00553 
00554     for (nv = pe->named_vars, tv = NULL; nv; tv = nv, nv = nv->next_var)
00555     {
00556         if (strcmp (nv->variable_name, var_name) == 0)
00557         {
00558             if (tv)
00559                 tv->next_var = nv->next_var;
00560             else
00561                 pe->named_vars = nv->next_var;
00562 
00563             g_free (nv->variable_name);
00564             nv->variable_name = NULL;
00565 
00566             pe->free_numeric (nv->value);
00567             nv->value = NULL;
00568 
00569             g_free (nv);
00570 
00571             ret = TRUE;
00572             break;
00573         }                               /* endif */
00574     }                           /* endfor */
00575 
00576     return ret;
00577 }                               /* delete_var */
00578 
00579 /* parse string passed using parser environment passed return
00580  * evaluated value in numeric structure passed, return NULL if no
00581  * parse error. If parse error, return pointer to character at which
00582  * error occured. */
00583 char *
00584 parse_string (var_store_ptr value, const char *string, parser_env_ptr pe)
00585 {
00586     var_store_ptr retv;
00587     var_store unnamed_vars[UNNAMED_VARS];
00588 
00589     if (!pe || !string)
00590         return NULL;
00591 
00592     pe->unnamed_vars = unnamed_vars;
00593     memset (unnamed_vars, 0, UNNAMED_VARS * sizeof (var_store));
00594 
00595     pe->parse_str = string;
00596     pe->error_code = PARSER_NO_ERROR;
00597 
00598     g_free (pe->tokens);
00599     pe->tokens = g_new0(char, strlen (string) + 1);
00600     pe->token_tail = pe->tokens;
00601 
00602     next_token (pe);
00603 
00604     if (!pe->error_code)
00605         assignment_op (pe);
00606 
00607     if (!pe->error_code)
00608     {
00609         /* interpret (num) as -num */
00610         if (strcmp (pe->tokens, "(I)") == 0)
00611         {
00612             var_store_ptr val;
00613 
00614             val = pop (pe);
00615             pe->negate_numeric (val->value);
00616             push (val, pe);
00617         }
00618     }
00619 
00620     if (pe->Token == EOS)
00621     {
00622         if ((pe->stack_cnt) && (retv = pop (pe)))
00623         {
00624             if (value != NULL)
00625                 *value = *retv;
00626             pe->parse_str = NULL;
00627         }
00628         else
00629             pe->error_code = STACK_UNDERFLOW;
00630     }
00631 
00632     pe->stack_cnt = 0;
00633     pe->unnamed_vars = NULL;
00634 
00635     return (char *) pe->parse_str;
00636 }                               /* expression */
00637 
00638 /* pop value off value stack */
00639 static var_store_ptr
00640 pop (parser_env_ptr pe)
00641 {
00642     var_store_ptr val;
00643 
00644     if (pe->stack_cnt)
00645         val = pe->stack[--(pe->stack_cnt)];
00646     else
00647     {
00648         val = NULL;
00649         pe->error_code = STACK_UNDERFLOW;
00650     }                           /* endif */
00651 
00652     return val;
00653 }                               /* pop */
00654 
00655 /* push value onto value stack */
00656 static var_store_ptr
00657 push (var_store_ptr push_value, parser_env_ptr pe)
00658 {
00659     if (pe->stack_cnt > pe->stack_size)
00660     {
00661         pe->stack_size += STACK_INIT;
00662         pe->stack = g_realloc (pe->stack,
00663                                pe->stack_size * sizeof (var_store_ptr));
00664     }                           /* endif */
00665 
00666     pe->stack[(pe->stack_cnt)++] = push_value;
00667 
00668     return push_value;
00669 }                               /* push */
00670 
00671 /* get/set variable with specified name - nothing fancy just scan each
00672  * variable in linked list checking for a string match return variable
00673  * found if match create new variable if none found */
00674 static var_store_ptr
00675 get_named_var (parser_env_ptr pe)
00676 {
00677     var_store_ptr retp = NULL, bv;
00678 
00679     for (retp = pe->predefined_vars, bv = NULL; retp; retp = retp->next_var)
00680         if (strcmp (retp->variable_name, pe->name) == 0)
00681             break;
00682 
00683     if (!retp && pe->named_vars)
00684         for (retp = pe->named_vars; retp; bv = retp, retp = retp->next_var)
00685             if (strcmp (retp->variable_name, pe->name) == 0)
00686                 break;
00687 
00688     if (!retp)
00689     {
00690         retp = g_new0 (var_store, 1);
00691         if (!pe->named_vars)
00692             pe->named_vars = retp;
00693         else
00694             bv->next_var = retp;
00695         retp->variable_name = g_strdup (pe->name);
00696         retp->type = VST_NUMERIC;
00697         retp->value =
00698             pe->trans_numeric ("0", pe->radix_point, pe->group_char, NULL);
00699     }
00700 
00701     return retp;
00702 }                               /* get_var */
00703 
00704 /* get un-named temporary variable */
00705 static var_store_ptr
00706 get_unnamed_var (parser_env_ptr pe)
00707 {
00708     var_store_ptr retp = NULL;
00709     unsigned cntr;
00710 
00711     for (cntr = 0; cntr < UNNAMED_VARS; cntr++)
00712         if (pe->unnamed_vars[cntr].use_flag == UNUSED_VAR)
00713         {
00714             retp = &(pe->unnamed_vars[cntr]);
00715             retp->variable_name = NULL;
00716             retp->use_flag = USED_VAR;
00717             retp->type = VST_NUMERIC;
00718             if (retp->value)
00719             {
00720                 pe->free_numeric (retp->value);
00721                 retp->value = NULL;
00722             }                           /* endif */
00723             break;
00724         }                               /* endif */
00725 
00726     if (retp == NULL)
00727         pe->error_code = PARSER_OUT_OF_MEMORY;
00728 
00729     return retp;
00730 }                               /* get_unnamed_var */
00731 
00732 /* mark un-named temporary variable unused */
00733 static void
00734 free_var (var_store_ptr value, parser_env_ptr pe)
00735 {
00736     if (value == NULL)
00737         return;
00738 
00739     /* first check that not a named variable */
00740     if (value->variable_name != NULL)
00741         return;
00742 
00743     value->use_flag = UNUSED_VAR;
00744 
00745     if (value->value)
00746     {
00747         pe->free_numeric (value->value);
00748         value->value = NULL;
00749     }
00750 }                               /* free_var */
00751 
00752 static void
00753 add_token (parser_env_ptr pe, char token)
00754 {
00755     pe->Token = token;
00756     if ((token != EOS) || (*pe->token_tail != EOS))
00757     {
00758         *pe->token_tail = token;
00759         pe->token_tail++;
00760     }
00761 }
00762 
00763 /* parse next token from string */
00764 static void
00765 next_token (parser_env_ptr pe)
00766 {
00767     char *nstr;
00768     const char *str_parse = pe->parse_str;
00769     void *number;
00770 
00771     while (isspace (*str_parse))
00772         str_parse++;
00773 
00774     pe->asn_op = EOS;
00775 
00776     /* test for end of string */
00777     if (!*str_parse)
00778     {
00779         add_token (pe, EOS);
00780     }
00781     /* test for possible operator */
00782     else if (strchr (allowed_operators, *str_parse))
00783     {
00784         add_token (pe, *str_parse++);
00785         if (*str_parse == ASN_OP)
00786         {
00787             /* BUG/FIXME: this seems to allow '(=' and ')=' [?], neither of which
00788              * make sense. */
00789             if (pe->Token != ASN_OP)
00790             {
00791                 str_parse++;
00792                 pe->asn_op = pe->Token;
00793                 add_token (pe, ASN_OP);
00794             }
00795             else
00796                 pe->error_code = UNDEFINED_CHARACTER;
00797         }                               /* endif */
00798     }
00799     /* test for string */
00800     else if ( *str_parse == '"' )
00801     {
00802         nstr = pe->name;
00803         /* skip over the '"'. */
00804         str_parse++;
00805         do
00806         {
00807             *nstr++ = *str_parse++;
00808         }
00809         while ( *str_parse != '"' );
00810         *nstr = EOS;
00811         str_parse++;
00812         add_token( pe, STR_TOKEN );
00813     }
00814     /* test for name */
00815     else if (isalpha (*str_parse)
00816              || (*str_parse == '_'))
00817     {
00818         int funcFlag = 0;
00819 
00820         /* Check for variable or function */
00821         /* If variable: add token. */
00822         /* If function: parse args, build struct, add token. */
00823         nstr = pe->name;
00824         do
00825         {
00826             if ( *str_parse == '(' )
00827             {
00828                 funcFlag = 1;
00829                 str_parse++;
00830                 break;
00831             }
00832             *nstr++ = *str_parse++;
00833         }
00834         while ((*str_parse == '_')
00835                 || (*str_parse == '(')
00836                 || isalpha (*str_parse)
00837                 || isdigit (*str_parse));
00838 
00839         *nstr = EOS;
00840         if ( funcFlag )
00841         {
00842             add_token(pe, FN_TOKEN);
00843         }
00844         else
00845         {
00846             add_token(pe, VAR_TOKEN);
00847         }
00848 
00849     }
00850     /* test for numeric token */
00851     else if ((number = pe->trans_numeric (str_parse, pe->radix_point,
00852                                           pe->group_char, &nstr)))
00853     {
00854         add_token (pe, NUM_TOKEN);
00855         pe->numeric_value = number;
00856         str_parse = nstr;
00857     }
00858     /* unrecognized character - error */
00859     else
00860     {
00861         add_token (pe, *str_parse);
00862         pe->error_code = UNDEFINED_CHARACTER;
00863     }                           /* endif */
00864 
00865     pe->parse_str = str_parse;
00866 }                               /* next_token */
00867 
00868 /* evaluate assignment operators,
00869  * =
00870  * +=
00871  * -=
00872  * \=
00873  * *=
00874  */
00875 /* FIXME: add non-numeric checking. */
00876 static void
00877 assignment_op (parser_env_ptr pe)
00878 {
00879     var_store_ptr vl;           /* left value       */
00880     var_store_ptr vr;           /* right value      */
00881     char ao;
00882 
00883     add_sub_op (pe);
00884     if (pe->error_code)
00885         return;
00886 
00887     while (pe->Token == ASN_OP)
00888     {
00889         vl = pop (pe);
00890         if (pe->error_code)
00891             return;
00892 
00893         ao = pe->asn_op;
00894 
00895         if (vl->variable_name)
00896         {
00897             next_token (pe);
00898             if (pe->error_code)
00899             {
00900                 free_var (vl, pe);
00901                 return;
00902             }
00903 
00904             assignment_op (pe);
00905             if (pe->error_code)
00906             {
00907                 free_var (vl, pe);
00908                 return;
00909             }
00910 
00911             vr = pop (pe);
00912             if (pe->error_code)
00913             {
00914                 free_var (vl, pe);
00915                 return;
00916             }
00917 
00918             vl->assign_flag = ASSIGNED_TO;
00919 
00920             if (ao)
00921             {
00922                 void *temp;
00923 
00924                 temp = vl->value;
00925                 vl->value = pe->numeric_ops (ao, vl->value, vr->value);
00926                 pe->free_numeric (temp);
00927             }
00928             else if (vl != vr)
00929             {
00930                 if (!vr->variable_name)
00931                 {
00932                     pe->free_numeric (vl->value);
00933                     vl->value = vr->value;
00934                     vr->value = NULL;
00935                 }
00936                 else
00937                 {
00938                     pe->numeric_ops (ASN_OP, vl->value, vr->value);
00939                 }
00940 
00941                 free_var (vr, pe);
00942             }                           /* endif */
00943 
00944             push (vl, pe);
00945         }
00946         else
00947         {
00948             add_token (pe, EOS);        /* error !!!!!!!!!! */
00949             pe->error_code = NOT_A_VARIABLE;
00950             free_var (vl, pe);
00951         }                               /* endif */
00952     }                           /* endwhile */
00953 }                               /* assignment_op */
00954 
00955 /* evaluate addition, subtraction operators */
00956 /* FIXME: add non-numeric checking. */
00957 static void
00958 add_sub_op (parser_env_ptr pe)
00959 {
00960     var_store_ptr vl;   /* left value   */
00961     var_store_ptr vr;   /* right value  */
00962     var_store_ptr rslt;   /* result       */
00963     char op;
00964 
00965     multiply_divide_op (pe);
00966     if (pe->error_code)
00967         return;
00968 
00969     while ((pe->Token == ADD_OP) || (pe->Token == SUB_OP))
00970     {
00971         op = pe->Token;
00972 
00973         vl = pop (pe);
00974         if (pe->error_code)
00975             return;
00976 
00977         next_token (pe);
00978         if (pe->error_code)
00979         {
00980             free_var (vl, pe);
00981             return;
00982         }
00983 
00984         multiply_divide_op (pe);
00985         if (pe->error_code)
00986         {
00987             free_var (vl, pe);
00988             return;
00989         }
00990 
00991         vr = pop (pe);
00992         if (pe->error_code)
00993         {
00994             free_var (vl, pe);
00995             return;
00996         }
00997 
00998         rslt = get_unnamed_var (pe);
00999         if (pe->error_code)
01000         {
01001             free_var (vl, pe);
01002             free_var (vr, pe);
01003             return;
01004         }
01005 
01006         rslt->value = pe->numeric_ops (op, vl->value, vr->value);
01007 
01008         free_var (vl, pe);
01009         free_var (vr, pe);
01010 
01011         push (rslt, pe);
01012     }                           /* endwhile */
01013 }                               /* add_sub_op */
01014 
01015 /* evaluate multiplication, division operators */
01016 /* FIXME: add non-numeric checking. */
01017 static void
01018 multiply_divide_op (parser_env_ptr pe)
01019 {
01020     var_store_ptr vl;   /* left value   */
01021     var_store_ptr vr;   /* right value  */
01022     var_store_ptr rslt;   /* result       */
01023     char op;
01024 
01025     primary_exp (pe);
01026     if (pe->error_code)
01027         return;
01028 
01029     while ((pe->Token == MUL_OP) || (pe->Token == DIV_OP))
01030     {
01031         op = pe->Token;
01032 
01033         vl = pop (pe);
01034         if (pe->error_code)
01035             return;
01036 
01037         next_token (pe);
01038         if (pe->error_code)
01039         {
01040             free_var (vl, pe);
01041             return;
01042         }
01043 
01044         primary_exp (pe);
01045         if (pe->error_code)
01046         {
01047             free_var (vl, pe);
01048             return;
01049         }
01050 
01051         vr = pop (pe);
01052         if (pe->error_code)
01053         {
01054             free_var (vl, pe);
01055             return;
01056         }
01057 
01058         rslt = get_unnamed_var (pe);
01059         if (pe->error_code)
01060         {
01061             free_var (vl, pe);
01062             free_var (vr, pe);
01063             return;
01064         }
01065 
01066         rslt->value = pe->numeric_ops (op, vl->value, vr->value);
01067 
01068         free_var (vl, pe);
01069         free_var (vr, pe);
01070 
01071         push (rslt, pe);
01072     }                           /* endwhile */
01073 }                               /* multiply_divide_op */
01074 
01080 static int
01081 check_expression_grammar_error(parser_env_ptr pe)
01082 {
01083     if (pe->Token == VAR_TOKEN
01084             || pe->Token == STR_TOKEN
01085             || pe->Token == NUM_TOKEN
01086             || pe->Token == FN_TOKEN)
01087     {
01088         add_token(pe, EOS);
01089         pe->error_code = EXPRESSION_ERROR;
01090         return TRUE;
01091     }
01092     return FALSE;
01093 }
01094 
01095 /* evaluate:
01096  *  unary '+' and '-'
01097  *  named variables
01098  *  numerics
01099  *  grouped expressions, "()"
01100  *  functions [ <name>( [exp : exp : ... : exp] ) ]
01101  *  strings
01102  */
01103 static void
01104 primary_exp (parser_env_ptr pe)
01105 {
01106     var_store_ptr rslt = NULL;
01107     char *ident = NULL;
01108     int funcArgCount;
01109     char LToken = pe->Token;
01110 
01111     /* If we are in a state where the non-stacked 'pe->name' is valuable, then
01112      * save it before we process the next token. */
01113     switch ( LToken )
01114     {
01115     case FN_TOKEN:
01116     case STR_TOKEN:
01117         ident = g_strdup( pe->name );
01118         break;
01119     }
01120 
01121     next_token (pe);
01122     if (pe->error_code)
01123         return;
01124 
01125     switch (LToken)
01126     {
01127     case '(':
01128         assignment_op (pe);
01129         if (pe->error_code)
01130             return;
01131 
01132         if (pe->Token == ')')
01133         {
01134             rslt = pop (pe);
01135             if (pe->error_code)
01136                 return;
01137 
01138             next_token (pe);
01139             if (pe->error_code)
01140                 return;
01141         }
01142         else
01143         {
01144             add_token (pe, EOS);        /* error here */
01145             pe->error_code = UNBALANCED_PARENS;
01146         }                               /* endif */
01147 
01148         break;
01149 
01150     case ADD_OP:
01151     case SUB_OP:
01152         primary_exp (pe);
01153         if (pe->error_code)
01154             return;
01155 
01156         rslt = pop (pe);
01157         if (pe->error_code)
01158             return;
01159 
01160         if (LToken == SUB_OP)
01161             pe->negate_numeric (rslt->value);
01162 
01163         break;
01164 
01165     case NUM_TOKEN:
01166         rslt = get_unnamed_var (pe);
01167         if (pe->error_code)
01168             return;
01169 
01170         if (check_expression_grammar_error(pe))
01171             return;
01172 
01173         rslt->value = pe->numeric_value;
01174         pe->numeric_value = NULL;
01175         break;
01176 
01177     case FN_TOKEN:
01178         funcArgCount = 0;
01179 
01180         if (pe->Token && pe->Token != ')')
01181         {
01182             do
01183             {
01184                 assignment_op(pe);
01185                 if ( pe->error_code )
01186                     return;
01187                 funcArgCount++;
01188                 if (!pe->Token || pe->Token == ')')
01189                 {
01190                     break;
01191                 }
01192                 next_token(pe);
01193             }
01194             while (pe->Token != ARG_TOKEN);
01195         }
01196 
01197         if ( pe->Token != ')' )
01198         {
01199             add_token( pe, EOS );
01200             pe->error_code = UNBALANCED_PARENS;
01201         }
01202 
01203         {
01204             int i;
01205             var_store_ptr val;
01206             void **argv;
01207 
01208             argv = g_new0( void*, funcArgCount );
01209             for ( i = 0; i < funcArgCount; i++ )
01210             {
01211                 /* fill, in back-to-front order, the funcArgCount tokens we just
01212                  * parsed out of the expression into a argument list to hand back
01213                  * to the caller's func_op callback. */
01214                 val = pop(pe);
01215                 argv[funcArgCount - i - 1] = val;
01216             }
01217 
01218             rslt = get_unnamed_var(pe);
01219             rslt->value = (*pe->func_op)( ident, funcArgCount, argv );
01220 
01221             for ( i = 0; i < funcArgCount; i++ )
01222             {
01223                 free_var( argv[i], pe );
01224             }
01225             g_free( argv );
01226             g_free( ident );
01227 
01228             if ( rslt->value == NULL )
01229             {
01230                 pe->error_code = NOT_A_FUNC;
01231                 add_token( pe, EOS );
01232                 return;
01233             }
01234         }
01235 
01236         next_token(pe);
01237 
01238         if (check_expression_grammar_error(pe))
01239             return;
01240 
01241         break;
01242 
01243     case VAR_TOKEN:
01244         if (check_expression_grammar_error(pe))
01245             return;
01246 
01247         rslt = get_named_var (pe);
01248         break;
01249     case STR_TOKEN:
01250         if (!(pe->Token == ')'
01251                 || pe->Token == ARG_TOKEN))
01252         {
01253             add_token(pe, EOS);
01254             pe->error_code = EXPRESSION_ERROR;
01255             return;
01256         }
01257 
01258         rslt = get_unnamed_var( pe );
01259         rslt->type = VST_STRING;
01260         rslt->value = ident;
01261         break;
01262     }                           /* endswitch */
01263 
01264     if (rslt != NULL)
01265         push (rslt, pe);
01266 
01267 }                               /* primary_exp */
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines