X-Git-Url: https://git.llucax.com/z.facultad/75.42/calculadora.git/blobdiff_plain/7c3053f3f1930121b3ef87d1864f67069d28fe66..8f5992a5811ef292022a3ca3ac293c231e2b065b:/parser_expression.c diff --git a/parser_expression.c b/parser_expression.c index 588027c..8ee6cc0 100644 --- a/parser_expression.c +++ b/parser_expression.c @@ -11,102 +11,156 @@ * * Creado: dom sep 14 13:03:49 ART 2003 * - * $Id: parser_equation.c 50 2003-09-15 06:44:27Z luca $ + * $Id$ */ #include "bool.h" #include "parseerror.h" +#include "parser_common.h" +#include "variable.h" +#include "variable_list.h" #include "dllist.h" +#include "strutil.h" #include #include #include -bool is_space(char c) { - return (c == ' ') || (c == '\t'); -} - -bool is_number(char c) { - return ('0' <= c) && (c <= '9'); -} - -bool is_alpha(char c) { - return (c == '_') || (('a' <= c) && (c <= 'z')) || (('A' <= c) && (c <= 'Z')); -} - -bool is_alpha_num(c) { - return is_number(c) || is_alpha(c); -} - -size_t DLList_equation_print(DLList* l, FILE* fp) { - size_t cant = 0; - Equation* eq; - for (eq = DLList_begin(l); DLList_have_more(l); eq = DLList_next(l)) { - cant += Equation_print(eq, fp); - } - return cant; -} - -void DLList_equation_delete(DLList* l) { - if (l) { - while (!DLList_empty(l)) { - Equation_delete((Equation*)DLList_pop(l)); - } - } - DLList_delete(l); -} +#include "memdebug_debugger.h" #define PARSE_ERROR(str) ParseError_set_pos_message(error, str, i + 1, c) -bool parser_expression(const char* exp, size_t len, float* result, - ParseError* error) { - enum {SEARCH_VAR, VAR, SEARCH_EQUAL, EXP} state = SEARCH_VAR; - size_t var_start = 0; - size_t var_len = 0; +/** + * TODO: exp tiene que venir sin espacios. + * + * @bug Los números negativos hay que ponerlos entre paréntesis si hay algún + * operador de baja precedencia en el mismo nivel. + */ +bool parser_expression(const char* exp, size_t len, float* result, DLList* + var_list, ParseError* error) { + size_t level = 0; size_t i; char c; + char* exp_cuted; + char* err = NULL; + float result1; + float result2; + /* Si es vacío, devuelve cero. */ + if (!len) { + *result = 0.0; + return TRUE; + } /* Si es una expresión numérica, la devolvemos directamente. */ - *result = strntod(exp, len, &err); + if ((exp[0] == '(') && (exp[len-1] == ')')) { + /* Si está entre paréntesis, se los sacamos. */ + exp_cuted = strutil_copy_fragment(exp, 1, len - 2); + } else { + exp_cuted = strutil_copy_fragment(exp, 0, len); + } + /* No se pudo alocar la memoria. */ + if (!exp_cuted) { + ParseError_set_message(error, "No se pudo alocar memoria"); + return FALSE; + } + /* Trato de convertirlo a float. */ + *result = strtod(exp_cuted, &err); if (*err == '\0') { /* OK */ - return TRUE; /* La expresión es numérica (FIXME: puede ser numérica - entre paréntesis y esto falla). */ + free(exp_cuted); + return TRUE; } - /* No es una expresión numérica, busco operadores de alta precedencia. */ + /* No es un valor numérico, me fijo si está en la lista de variables. */ + if (DLList_variable_find(var_list, exp_cuted)) { + *result = ((Variable*)DLList_current(var_list))->value; + free(exp_cuted); + return TRUE; + } + free(exp_cuted); + /* No es una expresión numérica ni una variable, busco operadores de alta + * precedencia. */ for (i = 0; i < len; i++) { c = exp[i]; + /* Manejo los niveles de paréntesis. */ if ((c == '(')) { level++; } else if (c == ')') { level--; + /* Está en el nivel básico y hay un operador. */ } else if (((c == '+') || (c == '-')) && !level) { - /* FIXME: Es una operador => segundo operando. */ - if (!parser_expression(exp, i - 1, result1, error)) { + /* No hay segundo operando. */ + if (i == len - 1) { + ParseError_set_message(error, "Falta segundo operando"); return FALSE; } - /* FIXME: verificar que no este vacío el segundo operando. */ - if (!parser_expression(exp + i + 1, len - i - 1, result2, error)) { + /* Calcula la expresión del primer operando. */ + if (!parser_expression(exp, i, &result1, var_list, error)) { + /* Si hay error, devuelve FALSE (y "arrastra" el error. */ return FALSE; } - } else if (((c == '+') || (c == '-')) && !level) { - } else { /* es otra cosa => error */ - PARSE_ERROR("un espacio o una letra"); - return FALSE; + /* Calcula la expresión del segundo operando. */ + if (!parser_expression(exp + i + 1, len - i - 1, &result2, + var_list, error)) { + /* Si hay error, devuelve FALSE (y "arrastra" el error. */ + return FALSE; + } + *result = (c == '+') ? (result1 + result2) : (result1 - result2); + return TRUE; + } + } + /* No hay tampoco operadores de alta precendencia, busco operadores de baja + * precedencia. */ + for (i = 0; i < len; i++) { + c = exp[i]; + /* Manejo los niveles de paréntesis. */ + if ((c == '(')) { + level++; + } else if (c == ')') { + level--; + /* Está en el nivel básico y hay un operador. */ + } else if (((c == '*') || (c == '/')) && !level) { + /* No hay segundo operando. */ + if (i == len - 1) { + ParseError_set_message(error, "Falta segundo operando"); + return FALSE; + } + /* Calcula la expresión del primer operando. */ + if (!parser_expression(exp, i, &result1, var_list, error)) { + /* Si hay error, devuelve FALSE (y "arrastra" el error. */ + return FALSE; + } + /* Calcula la expresión del segundo operando. */ + if (!parser_expression(exp + i + 1, len - i - 1, &result2, + var_list, error)) { + /* Si hay error, devuelve FALSE (y "arrastra" el error. */ + return FALSE; + } + /* Si estamos dividiendo, chequeamos que el divisor no sea cero. */ + if (c == '/') { + /* Segundo operando es cero. */ + if (result2 == 0.0) { + ParseError_set_message(error, "División por cero"); + return FALSE; + } + *result = result1 / result2; + /* Si estamos multiplicando, no hay chequeos extra. */ + } else { + *result = result1 * result2; + } + return TRUE; } } - /* Error, no se llego a parsear todo bien. */ - error->pos = len; - switch (state) { - case SEARCH_VAR: - ParseError_set_message(error, - "No se encontró la definición de una variable"); - break; - case VAR: - case SEARCH_EQUAL: - ParseError_set_message(error, "No se encontró un igual"); - break; - case EXP: - ParseError_set_message(error, "No se encontró una expresión"); - break; + /* Si no tiene operadores ni valores numéricos ni es una variable, pero está + * entre paréntesis, pruebo de evaluar lo que está dentro de los paréntesis. + */ + if ((exp[0] == '(') && (exp[len-1] == ')')) { + if (!parser_expression(exp + 1, len - 2, result, var_list, error)) { + /* Si hay error, devuelve FALSE (y "arrastra" el error. */ + return FALSE; + } else { + return TRUE; + } } + /* Si no tiene operadores ni valores numéricos ni es una variable, es un + * error. */ + ParseError_set_message(error, "La expresión es incorrecta"); return FALSE; }