]> git.llucax.com Git - z.facultad/75.42/calculadora.git/commitdiff
Se agrega una primera versión (sin debuggear) del parser de variables. Se separan...
authorLeandro Lucarella <llucax@gmail.com>
Tue, 16 Sep 2003 02:56:11 +0000 (02:56 +0000)
committerLeandro Lucarella <llucax@gmail.com>
Tue, 16 Sep 2003 02:56:11 +0000 (02:56 +0000)
Makefile
parser_variable.c [new file with mode: 0644]
parser_variable.h [new file with mode: 0644]
parser_variable_test.c [new file with mode: 0644]
strutil.c [new file with mode: 0644]
strutil.h [new file with mode: 0644]
variable.c [new file with mode: 0644]
variable.h [new file with mode: 0644]

index 831f9a7922b0e269356a85370d9d97934b0c174e..9b31f1509e81740485f672d5d21a3ccc0a6e54b8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ CFLAGS=-ansi -pedantic -Wall -g3 -DDEBUG
 CC=gcc-3.2
 
 # Pruebas.
-TESTS=dllist_test memdebug_test parser_equation_test
+TESTS=dllist_test memdebug_test parser_equation_test parser_variable_test
 # Programa a compilar.
 TARGETS=$(TESTS)
 
@@ -29,12 +29,16 @@ all: tp1
 tests: $(TESTS)
        ./dllist_test
        ./memdebug_test
+       ./parser_equation_test 'a = 40'
+       ./parser_variable_test 'a = 40'
 
 dllist_test: dllist.o
 
 memdebug_test: dllist.o meminfo.o memdebug.o
 
-parser_equation_test: dllist.o parseerror.o equation.o parser_equation.o meminfo.o memdebug.o
+parser_equation_test: dllist.o parseerror.o equation.o strutil.o parser_equation.o meminfo.o memdebug.o
+
+parser_variable_test: dllist.o parseerror.o variable.o strutil.o parser_variable.o meminfo.o memdebug.o
 
 tp1: $(TARGETS)
 
diff --git a/parser_variable.c b/parser_variable.c
new file mode 100644 (file)
index 0000000..ce19f9b
--- /dev/null
@@ -0,0 +1,250 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: dom sep 14 13:03:49 ART 2003
+ *
+ * $Id$
+ */
+
+#include "bool.h"
+#include "variable.h"
+#include "parser_variable.h"
+#include "parseerror.h"
+#include "dllist.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);
+}
+
+bool DLList_variable_find(DLList* l, Variable* var) {
+    Variable* v;
+    for (v = DLList_begin(l); DLList_have_more(l); v = DLList_next(l)) {
+        if (!strcmp(v->variable, var->variable)) {
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+size_t DLList_variable_print(DLList* l, FILE* fp) {
+    size_t cant = 0;
+    Variable* v;
+    for (v = DLList_begin(l); DLList_have_more(l); v = DLList_next(l)) {
+        cant += Variable_print(v, fp);
+    }
+    return cant;
+}
+
+void DLList_variable_delete(DLList* l) {
+    if (l) {
+        while (!DLList_empty(l)) {
+            Variable_delete((Variable*)DLList_pop(l));
+        }
+    }
+    DLList_delete(l);
+}
+
+#define PARSE_ERROR(str) ParseError_set_pos_message(error, str, i + 1, c)
+
+bool parser_variable(const char* line, size_t len, DLList* variable_list,
+        ParseError* error) {
+    enum {SEARCH_VAR, VAR, SEARCH_VAL, VAL, SEARCH_MIN, MIN, SEARCH_MAX, MAX}
+        state = SEARCH_VAR;
+    size_t var_start = 0;
+    size_t var_len   = 0;
+    size_t val_start = 0;
+    size_t val_len   = 0;
+    size_t min_start = 0;
+    size_t min_len   = 0;
+    size_t max_start = 0;
+    size_t max_len   = 0;
+    size_t i;
+    char c;
+    Variable* var;
+    for (i = 0; i < len; i++) {
+        c = line[i];
+        switch (state) {
+            case SEARCH_VAR: /* Busca el comienzo de una variable. */
+                if (!is_space(c)) {
+                    if (is_alpha(c)) {
+                        /* Es una letra => es el comienzo de la variable. */
+                        state = VAR;
+                        var_start = i;
+                    } else { /* es otra cosa => error */
+                        PARSE_ERROR("un espacio o una letra");
+                        return FALSE;
+                    }
+                }
+                /* Si es espacio, no hace nada, deja que siga. */
+                break;
+            case VAR: /* Se fija cual es el nombre de la variable. */
+                if (!is_alpha_num(c)) {
+                    if (is_space(c)) {
+                        /* Es un espacio, entonces hay que buscar un igual. */
+                        state = SEARCH_VAL;
+                        /* Calculo la longitud de la variable. */
+                        var_len = i - var_start;
+                    } else { /* es otra cosa */
+                        PARSE_ERROR(
+                                "un espacio, una letra, un número o un igual");
+                        return FALSE;
+                    }
+                }
+                /* Si es alfanumérico, no hace nada, deja que siga. */
+                break;
+            case SEARCH_VAL: /* Busca el valor. */
+                if (!is_space(c)) {
+                    /* Pasamos a interpretar el valor. */
+                    state = VAL;
+                    /* Pone el inicio del valor. */
+                    val_start = i;
+                }
+                /* Si es espacio, no hace nada, deja que siga. */
+                break;
+            case VAL: /* Se fija hasta donde va el valor actual. */
+                if (is_space(c)) { /* Si es un espacio, terminó el valor. */
+                    /* Buscamos otro valor. */
+                    state = SEARCH_MIN;
+                    /* Pone la longitud de este valor. */
+                    val_len = i - val_start;
+                }
+                /* Si es alfanumérico, no hace nada, deja que siga. */
+                break;
+            case SEARCH_MIN: /* Busca el mímino. */
+                if (!is_space(c)) {
+                    /* Pasamos a interpretar el mínimo. */
+                    state = MIN;
+                    /* Pone el inicio del mínimo. */
+                    min_start = i;
+                }
+                /* Si es espacio, no hace nada, deja que siga. */
+                break;
+            case MIN: /* Se fija hasta donde va el mínimo. */
+                if (is_space(c)) { /* Si es un espacio, terminó el mínimo. */
+                    /* Buscamos el máximo. */
+                    state = SEARCH_MAX;
+                    /* Pone la longitud del mínimo. */
+                    min_len = i - min_start;
+                }
+                /* Si es alfanumérico, no hace nada, deja que siga. */
+                break;
+            case SEARCH_MAX: /* Busca el máximo. */
+                if (!is_space(c)) {
+                    /* Pasamos al estado de máximo encontrado. */
+                    state = MAX;
+                    /* Pone el inicio del máximo. */
+                    max_start = i;
+                    /* Pone la longitud del máximo hasta el final (ya no hay más
+                     * valores a buscar). */
+                    max_len = i - len;
+                }
+                /* Si es espacio, no hace nada, deja que siga. */
+                break;
+        }
+        /* Si status es max, no se busca mas nada, terminamo el loop for. */
+        if (state == MAX) {
+            break;
+        }
+    }
+    /* Veo como terminó la interpretación. */
+    error->pos = len;
+    /* No se pudo interpretar una variable. */
+    if (state < VAL) {
+        switch (state) {
+            case SEARCH_VAR:
+                /* No tiene variable. */
+                ParseError_set_message(error,
+                        "No se encontró la definición de una variable");
+                return FALSE;
+            case VAR:
+            case SEARCH_VAL:
+                /* No tiene valor de la variable. */
+                ParseError_set_message(error,
+                        "No se encontró el valor de la variable");
+                return FALSE;
+        }
+    }
+    /* Al menos la variable con su valor ya la tenemos. */
+    var = Variable_new(line, var_start, var_len);
+    if (!var) {
+        ParseError_set_message(error, "No se pudo alocar memoria de variable");
+        return FALSE;
+    }
+    switch (state) {
+        case MAX:
+            /* Tiene máximo. */
+            if (!Variable_set_max(var, line, max_start, max_len)) {
+                /* No se pudo setear el máximo. */
+                Variable_delete(var);
+                ParseError_set_message(error,
+                        "No se pudo establecer el máximo");
+                return FALSE;
+            }
+            /* Continúo, tiene mínimo y valor también. */
+        case MIN:
+        case SEARCH_MAX:
+            /* Tiene míninimo. */
+            if (!Variable_set_min(var, line, min_start, min_len)) {
+                /* No se pudo setear el mínimo. */
+                Variable_delete(var);
+                ParseError_set_message(error,
+                        "No se pudo establecer el mínimo");
+                return FALSE;
+            }
+            /* Continúo, tiene valor también. */
+        case VAL:
+        case SEARCH_MIN:
+            /* Tiene solo valor. */
+            if (!Variable_set_value(var, line, val_start, val_len)) {
+                /* No se pudo setear el valor. */
+                Variable_delete(var);
+                ParseError_set_message(error,
+                        "No se pudo establecer el valor");
+                return FALSE;
+            }
+    }
+    /* Está todo ok, tengo la variable cargada, verifico max y min. */
+    if (!Variable_check_min_max(var)) {
+        Variable_delete(var);
+        ParseError_set_message(error,
+                "El mínimo es mayor que el máximo");
+        return FALSE;
+    }
+    /* Ahora sí, la puedo agregar a la lista de variables. */
+    if (DLList_variable_find(variable_list, var)) {
+        /* Si ya había uno, lo borro. */
+        DLList_remove_current(variable_list);
+    }
+    if (!DLList_push(variable_list, var)) {
+        ParseError_set_message(error,
+                "No se pudo agregar variable a la lista");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+#undef PARSE_ERROR /* Sólo queremos usarlo en este fragmento */
+
diff --git a/parser_variable.h b/parser_variable.h
new file mode 100644 (file)
index 0000000..91cf0fe
--- /dev/null
@@ -0,0 +1,32 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: lun sep 15 20:22:23 ART 2003
+ *
+ * $Id$
+ */
+
+#ifndef PARSER_VARIABLE_H
+#define PARSER_VARIABLE_H
+
+#include "bool.h"
+#include "parseerror.h"
+#include "dllist.h"
+#include <stdlib.h>
+
+size_t DLList_variable_print(DLList* l, FILE* fp);
+
+void DLList_variable_delete(DLList* l);
+
+bool parser_variable(const char* line, size_t len, DLList* variable_list,
+        ParseError* error);
+
+#endif /* PARSER_VARIABLE_H */
diff --git a/parser_variable_test.c b/parser_variable_test.c
new file mode 100644 (file)
index 0000000..c682d93
--- /dev/null
@@ -0,0 +1,77 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 18:24:31 ART 2003
+ *
+ * $Id$
+ */
+
+/**
+ * \file
+ *      Hace varios chequeos para probar si anda bien la función
+ *      parser_parser_variable().
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memdebug_debugger.h"
+#include "parser_variable.h"
+
+/**
+ * Programa para probar parser_variable().
+ *
+ * \return EXIT_SUCCESS si se realizó bien, EXIT_FAILURE si no.
+ */
+int main(int argc, char* argv[]) {
+    /* Declaración de variables. */
+    int i;
+    DLList* lista;
+    ParseError* error;
+
+    if (argc < 2) {
+        fprintf(stderr, "Debe pasar variables a evaluar como parámetros.\n");
+        fprintf(stderr, "Ejemplo: %s 'b = 50' 'a   = 1.7\n", argv[0]);
+        return EXIT_FAILURE;
+    }
+
+    lista = DLList_new();
+    if (!lista) {
+        fprintf(stderr, "No se pudo crear la lista.\n");
+        return EXIT_FAILURE;
+    }
+
+    error = ParseError_new();
+    if (!error) {
+        fprintf(stderr, "No se pudo crear el error.\n");
+        return EXIT_FAILURE;
+    }
+
+    for (i = 1; i < argc; i++) {
+        if (!parser_variable(argv[i], strlen(argv[i]), lista, error)) {
+            error->line = i;
+            ParseError_print(error, stderr);
+        }
+    }
+
+    DLList_variable_print(lista, stdout);
+
+    DLList_variable_delete(lista);
+
+    ParseError_delete(error);
+
+    /* Veo si pierdo memoria. */
+    memdebug_end();
+
+    return EXIT_SUCCESS;
+}
+
diff --git a/strutil.c b/strutil.c
new file mode 100644 (file)
index 0000000..48ec6f2
--- /dev/null
+++ b/strutil.c
@@ -0,0 +1,35 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: lun sep 15 18:12:35 ART 2003
+ *
+ * $Id$
+ */
+
+#include "strutil.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "memdebug_debugger.h"
+
+char* strutil_copy_fragment(const char* orig, size_t start, size_t len) {
+    /* Reservo el espacio (incluyendo el caracter nulo). */
+    char* new = malloc(sizeof(char) * (len + 1));
+    if (new) {
+        /* Copio el fragmento. */
+        strncpy(new, orig + start, len);
+        /* Termino la cadena. */
+        new[len] = '\0';
+    /* Si no pude reservar la memoria, devuelvo NULL. */
+    }
+    return new;
+}
+
diff --git a/strutil.h b/strutil.h
new file mode 100644 (file)
index 0000000..6da0a37
--- /dev/null
+++ b/strutil.h
@@ -0,0 +1,28 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: lun sep 15 18:14:36 ART 2003
+ *
+ * $Id$
+ */
+
+#ifndef STRUTIL_H
+#define STRUTIL_H
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/**
+ * Copia un fragmento de una cadena devolviendo el puntero a la copia.
+ */
+char* strutil_copy_fragment(const char* orig, size_t start, size_t len);
+
+#endif /* STRUTIL_H */
diff --git a/variable.c b/variable.c
new file mode 100644 (file)
index 0000000..74f403c
--- /dev/null
@@ -0,0 +1,134 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: lun sep 15 01:10:28 ART 2003
+ *
+ * $Id$
+ */
+
+#include "variable.h"
+#include "strutil.h"
+#include <stdlib.h>
+#include <string.h>
+
+#include "memdebug_debugger.h"
+
+Variable* Variable_new(const char* line, size_t var_start, size_t var_len) {
+    Variable* var = malloc(sizeof(Variable));
+    if (var) {
+        /* Copio el fragmento de la variable. */
+        var->variable = strutil_copy_fragment(line, var_start, var_len);
+        /* Si no hay más memoria, libero el resto y devuelvo NULL. */
+        if (!var->variable) {
+            free(var);
+            return NULL;
+        }
+        var->have_min = FALSE;
+        var->have_max = FALSE;
+    }
+    return var;
+}
+
+void Variable_delete(Variable* var) {
+    if (var) {
+        free(var->variable);
+    }
+    free(var);
+}
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_value(Variable* var, const char* line, size_t start,
+        size_t len) {
+    char* err = NULL;
+    char* str = strutil_copy_fragment(line, start, len);
+    if (!str) {
+        return FALSE;
+    }
+    var->value = strtod(str, &err);
+    /* Si el caracter donde apunta error no es 0 es porque hay error. */
+    if (*err != '\0') {
+        /* Libero memoria reservada. */
+        free(str);
+        return FALSE;
+    }
+    free(str);
+    return TRUE;
+}
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_min(Variable* var, const char* line, size_t start,
+        size_t len) {
+    char* err = NULL;
+    char* str = strutil_copy_fragment(line, start, len);
+    if (!str) {
+        return FALSE;
+    }
+    var->min = strtod(str, &err);
+    /* Si el caracter donde apunta error no es 0 es porque hay error. */
+    if (*err != '\0') {
+        /* Libero memoria reservada. */
+        free(str);
+        return FALSE;
+    }
+    free(str);
+    var->have_min = TRUE;
+    return TRUE;
+}
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_max(Variable* var, const char* line, size_t start,
+        size_t len) {
+    char* err = NULL;
+    char* str = strutil_copy_fragment(line, start, len);
+    if (!str) {
+        return FALSE;
+    }
+    var->max = strtod(str, &err);
+    /* Si el caracter donde apunta error no es 0 es porque hay error. */
+    if (*err != '\0') {
+        /* Libero memoria reservada. */
+        free(str);
+        return FALSE;
+    }
+    free(str);
+    var->have_max = TRUE;
+    return TRUE;
+}
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_check_min_max(Variable* var) {
+    return !var->have_min
+        || !var->have_max
+        || (var->min <= var->max);
+}
+
+size_t Variable_print(Variable* var, FILE* fp) {
+    size_t cant = 0;
+    cant += fprintf(fp, "%s = %f", var->variable, var->value);
+    if (var->have_min || var->have_max) {
+        cant += fprintf(fp, "(");
+    }
+    if (var->have_min) {
+        cant += fprintf(fp, "min = %f", var->min);
+    }
+    if (var->have_min && var->have_max) {
+        cant += fprintf(fp, ", ");
+    }
+    if (var->have_max) {
+        cant += fprintf(fp, "max = %f", var->max);
+    }
+    if (var->have_min || var->have_max) {
+        cant += fprintf(fp, ")");
+    }
+    cant += fprintf(fp, "\n");
+    return cant;
+}
+
diff --git a/variable.h b/variable.h
new file mode 100644 (file)
index 0000000..65785b2
--- /dev/null
@@ -0,0 +1,54 @@
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: lun sep 15 18:55:54 ART 2003
+ *
+ * $Id$
+ */
+
+#ifndef VARIABLE_H
+#define VARIABLE_H
+
+#include "bool.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct {
+    char* variable;
+    float value;
+    float min;
+    float max;
+    bool  have_min;
+    bool  have_max;
+} Variable;
+
+Variable* Variable_new(const char* line, size_t var_start, size_t var_len);
+
+void Variable_delete(Variable* var);
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_value(Variable* var, const char* line, size_t start,
+        size_t len);
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_min(Variable* var, const char* line, size_t start,
+        size_t len);
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_set_max(Variable* var, const char* line, size_t start,
+        size_t len);
+
+/* simplifico el manejo de errores, false si hubo error. */
+bool Variable_check_min_max(Variable* var);
+
+size_t Variable_print(Variable* var, FILE* fp);
+
+#endif /* VARIABLE_H */