]> git.llucax.com Git - z.facultad/75.42/calculadora.git/blobdiff - parser_expression.c
Versión preliminar del programa del TP. Falta evaluar ecuaciones.
[z.facultad/75.42/calculadora.git] / parser_expression.c
index 588027c9cb83e141acb7d8284c111adcacfe3ad0..8ee6cc0030930d730acee4c662713298789e9bc5 100644 (file)
  *
  * 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 <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-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;
 }