|
GnuCash 2.4.99
|
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 */
1.7.4