]> git.llucax.com Git - z.facultad/75.42/calculadora.git/blob - parser_expression.c
Últimos retoques.
[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 bool parser_expression(const char* exp, size_t len, float* result, DLList*
31         var_list, ParseError* error) {
32     size_t level = 0;
33     size_t i;
34     char c;
35     char* exp_cuted;
36     char* err = NULL;
37     float result1;
38     float result2;
39     /* Si es vacío, devuelve cero. */
40     if (!len) {
41         *result = 0.0;
42         return TRUE;
43     }
44     /* Si es una expresión numérica, la devolvemos directamente. */
45     if ((exp[0] == '(') && (exp[len-1] == ')')) {
46         /* Si está entre paréntesis, se los sacamos. */
47         exp_cuted = strutil_copy_fragment(exp, 1, len - 2);
48     } else {
49         exp_cuted = strutil_copy_fragment(exp, 0, len);
50     }
51     /* No se pudo alocar la memoria. */
52     if (!exp_cuted) {
53         ParseError_set_message(error, "No se pudo alocar memoria");
54         return FALSE;
55     }
56     /* Trato de convertirlo a float. */
57     *result = strtod(exp_cuted, &err);
58     if (*err == '\0') { /* OK */
59         free(exp_cuted);
60         return TRUE;
61     }
62     /* No es un valor numérico, me fijo si está en la lista de variables. */
63     if (DLList_variable_find(var_list, exp_cuted)) {
64         *result = ((Variable*)DLList_current(var_list))->value;
65         free(exp_cuted);
66         return TRUE;
67     }
68     free(exp_cuted);
69     /* No es una expresión numérica ni una variable, busco operadores de alta
70      * precedencia. */
71     for (i = 0; i < len; i++) {
72         c = exp[i];
73         /* Manejo los niveles de paréntesis. */
74         if ((c == '(')) {
75             level++;
76         } else if (c == ')') {
77             level--;
78         /* Está en el nivel básico y hay un operador. */
79         } else if (((c == '+') || (c == '-')) && !level) {
80             /* No hay segundo operando. */
81             if (i == len - 1) {
82                 ParseError_set_message(error, "Falta segundo operando");
83                 return FALSE;
84             }
85             /* Calcula la expresión del primer operando. */
86             if (!parser_expression(exp, i, &result1, var_list, error)) {
87                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
88                 return FALSE;
89             }
90             /* Calcula la expresión del segundo operando. */
91             if (!parser_expression(exp + i + 1, len - i - 1, &result2,
92                         var_list, error)) {
93                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
94                 return FALSE;
95             }
96             *result = (c == '+') ? (result1 + result2) : (result1 - result2);
97             return TRUE;
98         }
99     }
100     /* No hay tampoco operadores de alta precendencia, busco operadores de baja
101      * precedencia. */
102     for (i = 0; i < len; i++) {
103         c = exp[i];
104         /* Manejo los niveles de paréntesis. */
105         if ((c == '(')) {
106             level++;
107         } else if (c == ')') {
108             level--;
109         /* Está en el nivel básico y hay un operador. */
110         } else if (((c == '*') || (c == '/')) && !level) {
111             /* No hay segundo operando. */
112             if (i == len - 1) {
113                 ParseError_set_message(error, "Falta segundo operando");
114                 return FALSE;
115             }
116             /* Calcula la expresión del primer operando. */
117             if (!parser_expression(exp, i, &result1, var_list, error)) {
118                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
119                 return FALSE;
120             }
121             /* Calcula la expresión del segundo operando. */
122             if (!parser_expression(exp + i + 1, len - i - 1, &result2,
123                         var_list, error)) {
124                 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
125                 return FALSE;
126             }
127             /* Si estamos dividiendo, chequeamos que el divisor no sea cero. */
128             if (c == '/') {
129                 /* Segundo operando es cero. */
130                 if (result2 == 0.0) {
131                     ParseError_set_message(error, "División por cero");
132                     return FALSE;
133                 }
134                 *result = result1 / result2;
135             /* Si estamos multiplicando, no hay chequeos extra. */
136             } else {
137                 *result = result1 * result2;
138             }
139             return TRUE;
140         }
141     }
142     /* Si no tiene operadores ni valores numéricos ni es una variable, pero está
143      * entre paréntesis, pruebo de evaluar lo que está dentro de los paréntesis.
144      */
145     if ((exp[0] == '(') && (exp[len-1] == ')')) {
146         if (!parser_expression(exp + 1, len - 2, result, var_list, error)) {
147             /* Si hay error, devuelve FALSE (y "arrastra" el error. */
148             return FALSE;
149         } else {
150             return TRUE;
151         }
152     }
153     /* Si no tiene operadores ni valores numéricos ni es una variable, es un
154      * error. */
155     ParseError_set_message(error, "La expresión es incorrecta");
156     return FALSE;
157 }
158