/* * The Spar Library - modular math parser * Copyright (C) 2000,2001 Davide Angelocola * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ #include #include #include #include #include #include #include #include /* * The Token Type */ typedef enum { TOKEN_TYPE_ALPHA, /* token is a function or variable name */ TOKEN_TYPE_DELIM, /* token is a delimitator */ TOKEN_TYPE_NUMBER /* token is a number */ } token_type_t; /* * Token infos * type specifys the token type * token is a identifier (sl_conf.h) */ token_type_t type; sl_identifier (token); /* * Expression to evaluate */ char *expression; /* * Used with throw_error * return to the level0 function is any error occurs */ extern jmp_buf jb; /* * Internal functions * declared as 'static' */ static void next_token (void); static bool __is_a_identifier (const char[]); static int level0 (const char[], double *, bool *); static bool level1 (double *); static void level2 (double *); static void level3 (double *); static void level4 (double *); static void level5 (double *); static void level6 (double *); sl_error sl_parser_evaluate (const char *str) { int rc; bool assign; double result; memset (token, 0, SL_IDENTIFIER_LENGHT); rc = level0 (str, &result, &assign); switch (rc) { case SL_SUCCESS: { switch (assign) { case true: break; case false: { sl_write_value_with_label (str, result); break; } default: sl_writeln ("%s: %s: %u: bug: assign undefined", __FILE__, __FUNCTION__, __LINE__); break; } return SL_SUCCESS; } case SL_ERROR: return SL_ERROR; default: sl_writeln ("%s: %s: %u: bug: rc undefined", __FILE__, __FUNCTION__, __LINE__); } return SL_ERROR; } double sl_parser_evaluate_to_double (const char *str) { bool assign; double result; memset (token, 0, SL_IDENTIFIER_LENGHT); (void) level0 (str, &result, &assign); return result; } static int level0 (const char ete[], double *result, bool * assg) { /* * if any parser error occurcs jump here * using the function throw_error with * SL_ERROR_PARSER */ if (setjmp (jb)) return SL_ERROR; expression = (char *) ete; *result = ZERO; next_token (); if ((strlen (token)) > 0) *assg = level1 (result); /* * No errors, the string is correct */ return SL_SUCCESS; } static bool level1 (double *r) { sl_identifier (t); if (type == TOKEN_TYPE_ALPHA) if (*expression == '=') { strcpy (t, token); next_token (); next_token (); level2 (r); if (sl_variable_set (t, *r) == SL_SUCCESS) sl_writeln ("Variable '%s' added.", t); return true; } level2 (r); return false; } static void level2 (double *r) { double t = ZERO; char o; level3 (r); while ((o = *token) == '+' || o == '-') { next_token (); level3 (&t); switch (o) { case '+': *r = *r + t; break; case '-': *r = *r - t; break; } } return; } static void level3 (double *r) { double t = ZERO; char o; level4 (r); while ((o = *token) == '*' || o == '/' || o == '%') { next_token (); level4 (&t); switch (o) { case '*': *r = *r * t; break; case '/': if (SL_IS_ZERO (t)) sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_DIVZERO, "'%s'", token); *r = *r / t; break; case '%': { if (SL_IS_ZERO (t)) sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_DIVZERO, "'%s'", token); *r = sl_mod (*r, t); break; } } } return; } static void level4 (double *r) { double t = ZERO; level5 (r); if (*token == '^') { next_token (); level5 (&t); *r = sl_pow (*r, t); } return; } static void level5 (double *r) { char o = '0'; if (*token == '+' || *token == '-') { o = *token; next_token (); } level6 (r); if (o == '-') *r = *r * (-1); return; } static void level6 (double *r) { if (*token == '(') { next_token (); if (*token == ')') sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_NOARG, "'%s'", token); level1 (r); if (*token != ')') sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_UNBALAN, "'%s'", token); next_token (); } else { if (type == TOKEN_TYPE_NUMBER) { sl_string_to_double (token, r); next_token (); } else if (type == TOKEN_TYPE_ALPHA) { if (*expression == '(') { int fnc_code = sl_function_check (token); if (fnc_code != SL_SYMBOL_NOT_FOUND) { sl_function_args_t argc = 0; double argv[3]; const char *name = sl_function_get_name (fnc_code); next_token (); do { next_token (); switch (*token) { case ')': argv[argc] = 0; break; case ',': argv[argc] = 0; break; default: break; } if (*token == ')' || *token == ',') argv[argc] = 0; level1 (&argv[argc]); argc += 1; } while (argc < 3 && *token == ','); while ((*token) != ')') { if (*token == '(') sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_UNBALAN, "'%s'", token); next_token (); if (*token != ')') sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_UNBALAN, "'%s'", token); } if (argc != (sl_function_get_argc (fnc_code))) sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_NUMARGS, "'%s'", name); *r = sl_function_run (name, argv); next_token (); return; } else sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_BADFUNC, "'%s'", token); } else { double t; if (sl_variable_get (token, &t) == SL_SUCCESS) goto success; else if (sl_constant_get (token, &t) == SL_SUCCESS) goto success; else goto error; error: sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_UNKNOWN, "'%s'", token); success: *r = t; next_token (); return; } } else sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_SYNTAX, "'%s'", token); } return; } static void next_token (void) { char *t; register int iden_len = 0; type = 0; t = token; while (sl_isblank (*expression) == 1) expression++; if (sl_isdelim (*expression) == 1) { type = TOKEN_TYPE_DELIM; *t++ = *expression++; } else if (sl_isnumber (*expression)) { type = TOKEN_TYPE_NUMBER; while (sl_isnumber (*expression) || (*expression == 'E') || (*expression == 'e') || (*expression == '-') || (*expression == '+')) { *t++ = *expression++; // if (sl_isnumber (*expression)) // sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_SYNTAX, expression); } } else if (sl_isalpha (*expression)) { type = TOKEN_TYPE_ALPHA; while (sl_isalpha (*expression) == 1 || sl_isnumber (*expression) == 1) { iden_len += 1; if (iden_len >= SL_IDENTIFIER_LENGHT) sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_IDENF, "'%s'", token); *t++ = *expression++; } if (__is_a_identifier (t) == 0) sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_SYNTAX, "'%s'", t); } else if (*expression != '\0') { *t++ = *expression++; *t = '\0'; sl_error_throw (SL_ERROR_CLASS_PARSER, SL_ERROR_SYNTAX, "'%s'", token); } *t = '\0'; while (sl_isblank (*expression) == 1) expression++; return; } bool __is_a_identifier (const char iden[]) { return !(sl_isnumber (iden[0])); }