]> git.llucax.com Git - z.facultad/75.42/calculadora.git/blob - parser_expression.c
Se mejora el informe.
[z.facultad/75.42/calculadora.git] / parser_expression.c
1 /* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
2  *
3  * Taller de Programación (75.42).
4  *
5  * Ejercicio Número 2:
6  * Programa calculadora.
7  *
8  * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
9  * Puede copiar, modificar y distribuir este programa bajo los términos de
10  * la licencia GPL (http://www.gnu.org/).
11  *
12  * Creado: dom sep 14 13:03:49 ART 2003
13  *
14  * $Id$
15  */
16
17 #include "bool.h"
18 #include "parseerror.h"
19 #include "parser_common.h"
20 #include "variable.h"
21 #include "variable_list.h"
22 #include "dllist.h"
23 #include "strutil.h"
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "memdebug_debugger.h"
29
30 #define PARSE_ERROR(str) ParseError_set_pos_message(error, str, i + 1, c)
31
32 /**
33  * TODO: exp tiene que venir sin espacios.
34  * 
35  * @bug Los números negativos hay que ponerlos entre paréntesis si hay algún
36  *      operador de baja precedencia en el mismo nivel.
37  */
38 bool parser_expression(const char* exp, size_t len, float* result, DLList*
39         var_list, ParseError* error) {
40     size_t level = 0;
41     size_t i;
42     char c;
43     char* exp_cuted;
44     char* err = NULL;
45     float result1;
46     float result2;
47     /* Si es vacío, devuelve cero. */
48     if (!len) {
49         *result = 0.0;
50         return TRUE;
51     }
52     /* Si es una expresión numérica, la devolvemos directamente. */
53     if ((exp[0] == '(') && (exp[len-1] == ')')) {
54         /* Si está entre paréntesis, se los sacamos. */
55         exp_cuted = strutil_copy_fragment(exp, 1, len - 2);
56     } else {
57         exp_cuted = strutil_copy_fragment(exp, 0, len);
58     }
59     /* No se pudo alocar la memoria. */
60     if (!exp_cuted) {
61         ParseError_set_message(error, "No se pudo alocar memoria");
62         return FALSE;
63     }
64     /* Trato de convertirlo a float. */
65     *result = strtod(exp_cuted, &err);
66     if (*err == '\0') { /* OK */
67         free(exp_cuted);
68         return TRUE;
69     }
70     /* No es un valor numérico, me fijo si está en la lista de variables. */
71     if (DLList_variable_find(var_list, exp_cuted)) {
72         *result = ((Variable*)DLList_current(var_list))->value;
73         free(exp_cuted);
74         return TRUE;
75     }
76     free(exp_cuted);
77     /* No es una expresión numérica ni una variable, busco operadores de alta
78      * precedencia. */
79     for (i = 0; i < len; i++) {
80         c = exp[i];
81         /* Manejo los niveles de paréntesis. */
82         if ((c == '(')) {
83             level++;
84         } else if (c == ')') {
85             level--;
86         /* Está en el nivel básico y hay un operador. */
87         } else if (((c == '+') || (c == '-')) && !level) {
88             /* No hay segundo operando. */
89             if (i == len - 1) {
90                 ParseError_set_message(error, "Falta segundo operando");
91                 return FALSE;
92             }
93             /* Calcula la expresión del primer operando. */
94             if (!parser_expression(exp, i, &result1, var_list, error)) {
95                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
96                 return FALSE;
97             }
98             /* Calcula la expresión del segundo operando. */
99             if (!parser_expression(exp + i + 1, len - i - 1, &result2,
100                         var_list, error)) {
101                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
102                 return FALSE;
103             }
104             *result = (c == '+') ? (result1 + result2) : (result1 - result2);
105             return TRUE;
106         }
107     }
108     /* No hay tampoco operadores de alta precendencia, busco operadores de baja
109      * precedencia. */
110     for (i = 0; i < len; i++) {
111         c = exp[i];
112         /* Manejo los niveles de paréntesis. */
113         if ((c == '(')) {
114             level++;
115         } else if (c == ')') {
116             level--;
117         /* Está en el nivel básico y hay un operador. */
118         } else if (((c == '*') || (c == '/')) && !level) {
119             /* No hay segundo operando. */
120             if (i == len - 1) {
121                 ParseError_set_message(error, "Falta segundo operando");
122                 return FALSE;
123             }
124             /* Calcula la expresión del primer operando. */
125             if (!parser_expression(exp, i, &result1, var_list, error)) {
126                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
127                 return FALSE;
128             }
129             /* Calcula la expresión del segundo operando. */
130             if (!parser_expression(exp + i + 1, len - i - 1, &result2,
131                         var_list, error)) {
132                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
133                 return FALSE;
134             }
135             /* Si estamos dividiendo, chequeamos que el divisor no sea cero. */
136             if (c == '/') {
137                 /* Segundo operando es cero. */
138                 if (result2 == 0.0) {
139                     ParseError_set_message(error, "División por cero");
140                     return FALSE;
141                 }
142                 *result = result1 / result2;
143             /* Si estamos multiplicando, no hay chequeos extra. */
144             } else {
145                 *result = result1 * result2;
146             }
147             return TRUE;
148         }
149     }
150     /* Si no tiene operadores ni valores numéricos ni es una variable, pero está
151      * entre paréntesis, pruebo de evaluar lo que está dentro de los paréntesis.
152      */
153     if ((exp[0] == '(') && (exp[len-1] == ')')) {
154         if (!parser_expression(exp + 1, len - 2, result, var_list, error)) {
155             /* Si hay error, devuelve FALSE (y "arrastra" el error. */
156             return FALSE;
157         } else {
158             return TRUE;
159         }
160     }
161     /* Si no tiene operadores ni valores numéricos ni es una variable, es un
162      * error. */
163     ParseError_set_message(error, "La expresión es incorrecta");
164     return FALSE;
165 }
166
167 #undef PARSE_ERROR /* Sólo queremos usarlo en este fragmento */
168