From 0f0090fd999b6194842cbff05ee4f93d69c43000 Mon Sep 17 00:00:00 2001 From: Leandro Lucarella Date: Tue, 16 Sep 2003 02:56:11 +0000 Subject: [PATCH] =?utf8?q?Se=20agrega=20una=20primera=20versi=C3=B3n=20(si?= =?utf8?q?n=20debuggear)=20del=20parser=20de=20variables.=20Se=20separan?= =?utf8?q?=20algunas=20cosas.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- Makefile | 8 +- parser_variable.c | 250 +++++++++++++++++++++++++++++++++++++++++ parser_variable.h | 32 ++++++ parser_variable_test.c | 77 +++++++++++++ strutil.c | 35 ++++++ strutil.h | 28 +++++ variable.c | 134 ++++++++++++++++++++++ variable.h | 54 +++++++++ 8 files changed, 616 insertions(+), 2 deletions(-) create mode 100644 parser_variable.c create mode 100644 parser_variable.h create mode 100644 parser_variable_test.c create mode 100644 strutil.c create mode 100644 strutil.h create mode 100644 variable.c create mode 100644 variable.h diff --git a/Makefile b/Makefile index 831f9a7..9b31f15 100644 --- 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 index 0000000..ce19f9b --- /dev/null +++ b/parser_variable.c @@ -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 + * 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 +#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); +} + +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 index 0000000..91cf0fe --- /dev/null +++ b/parser_variable.h @@ -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 + * 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 + +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 index 0000000..c682d93 --- /dev/null +++ b/parser_variable_test.c @@ -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 + * 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 +#include +#include + +#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 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 + * 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 +#include + +#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 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 + * 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 +#include + +/** + * 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 index 0000000..74f403c --- /dev/null +++ b/variable.c @@ -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 + * 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 +#include + +#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 index 0000000..65785b2 --- /dev/null +++ b/variable.h @@ -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 + * 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 +#include + +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 */ -- 2.43.0