/* tokeniser.c * geg, a GTK+ Equation Grapher * David Bryant 1998 */ #ifdef HAVE_CONFIG_H #include #endif /* HAVE_CONFIG_H */ #include #include #include "tokeniser.h" #include "localfunctions.h" #ifndef M_PI #define M_PI 3.14159265358979323846 #endif /* M_PI */ #ifndef M_E #define M_E 2.7182818284590452354 #endif /* M_E */ #define NUMBER(c) (((c) >= '0') && ((c) <= '9')) typedef struct { char *string; /* the identifier string in the equation */ gint type; /* eg NUM, FUN */ double value; /* used if it is a number or a constant */ Func func; /* the address of the unary function to call */ } token_db; static gint compare(token_db *a, gchar *b); /* these must be in descending order of string length */ static token_db tokens[] = { { "arcsin", FUN, 0, asin }, { "arccos", FUN, 0, acos }, { "arctan", FUN, 0, atan }, { "arccsc", FUN, 0, l_acsc }, { "arcsec", FUN, 0, l_asec }, { "arccot", FUN, 0, l_acot }, { "asin", FUN, 0, asin }, { "acos", FUN, 0, acos }, { "atan", FUN, 0, atan }, { "acsc", FUN, 0, l_acsc }, { "asec", FUN, 0, l_asec }, { "acot", FUN, 0, l_acot }, { "sinc", FUN, 0, l_sinc }, { "sinh", FUN, 0, sinh }, { "cosh", FUN, 0, cosh }, { "tanh", FUN, 0, tanh }, { "cbrt", FUN, 0, l_cbrt }, { "sqrt", FUN, 0, sqrt }, { "sin", FUN, 0, sin, }, { "cos", FUN, 0, cos, }, { "tan", FUN, 0, tan, }, { "csc", FUN, 0, l_csc, }, { "sec", FUN, 0, l_sec, }, { "cot", FUN, 0, l_cot, }, { "log", FUN, 0, log10 }, { "abs", FUN, 0, fabs }, { "ln", FUN, 0, log }, { "pi", NUM, M_PI, NULL }, { "u", FUN, 0, l_u }, { "e", NUM, M_E, NULL }, { "+", ADD, 0, NULL }, { "-", SUB, 0, NULL }, { "*", MUL, 0, NULL }, { "/", DIV, 0, NULL }, { "^", POW, 0, NULL }, { "[", LSB, 0, NULL }, { "]", RSB, 0, NULL }, { "{", LCB, 0, NULL }, { "}", RCB, 0, NULL }, { "(", LB, 0, NULL }, { ")", RB, 0, NULL }, { "x", X, 0, NULL }, { "", EOE, 0, NULL } }; /* compare, */ static gint compare(token_db *a, gchar *b) { if((*a->string == '\0') ^ (*b == '\0')) return(0); else return(!strncasecmp(a->string, b, strlen(a->string))); } /* make_token_list, this function builds a token list out of the equation */ token_list * make_token_list(gchar *equation) { gint i; token_list *list; list = (token_list *)g_new(token_list, 1); /* skip any whitespace */ while(*equation == ' ') equation++; /* check for the token in the token database */ for(i = 0; i < (sizeof(tokens) / sizeof(token_db)); i++) { if(compare(&tokens[i], equation)) { list->type = tokens[i].type; list->value = tokens[i].value; list->func = tokens[i].func; equation += strlen(tokens[i].string); if(list->type != EOE) list->next = make_token_list(equation); else list->next = NULL; return(list); } } /* if it wasn't in the token database, it's either a number, or the token */ /* can't be recognised and is therefore an error */ if(NUMBER(*equation)) { list->type = NUM; list->value = 0; while(NUMBER(*equation)) { list->value = list->value * 10 + *equation++ - '0'; } if(*equation == '.') { /* a real number */ equation++; i = 0; /* use i to count the decimal places */ while(NUMBER(*equation)) list->value += (*equation++ - '0') * pow(10, --i); } list->next = make_token_list(equation); return(list); } else { /* it's an error .. */ list->type = ERROR; list->value = 0; list->next = NULL; return(list); } } /* free_list, a recursive list freeing algorithm */ void free_list(token_list *list) { if(list->next != NULL) free_list(list->next); g_free(list); }