1 /* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
3 * Taller de Programación (75.42).
6 * Programa calculadora.
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/).
12 * Creado: dom sep 14 13:03:49 ART 2003
18 #include "parseerror.h"
19 #include "parser_common.h"
21 #include "variable_list.h"
28 #include "memdebug_debugger.h"
30 #define PARSE_ERROR(str) ParseError_set_pos_message(error, str, i + 1, c)
33 * TODO: exp tiene que venir sin espacios.
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.
38 bool parser_expression(const char* exp, size_t len, float* result, DLList*
39 var_list, ParseError* error) {
47 /* Si es vacío, devuelve cero. */
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);
57 exp_cuted = strutil_copy_fragment(exp, 0, len);
59 /* No se pudo alocar la memoria. */
61 ParseError_set_message(error, "No se pudo alocar memoria");
64 /* Trato de convertirlo a float. */
65 *result = strtod(exp_cuted, &err);
66 if (*err == '\0') { /* OK */
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;
77 /* No es una expresión numérica ni una variable, busco operadores de alta
79 for (i = 0; i < len; i++) {
81 /* Manejo los niveles de paréntesis. */
84 } else if (c == ')') {
86 /* Está en el nivel básico y hay un operador. */
87 } else if (((c == '+') || (c == '-')) && !level) {
88 /* No hay segundo operando. */
90 ParseError_set_message(error, "Falta segundo operando");
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. */
98 /* Calcula la expresión del segundo operando. */
99 if (!parser_expression(exp + i + 1, len - i - 1, &result2,
101 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
104 *result = (c == '+') ? (result1 + result2) : (result1 - result2);
108 /* No hay tampoco operadores de alta precendencia, busco operadores de baja
110 for (i = 0; i < len; i++) {
112 /* Manejo los niveles de paréntesis. */
115 } else if (c == ')') {
117 /* Está en el nivel básico y hay un operador. */
118 } else if (((c == '*') || (c == '/')) && !level) {
119 /* No hay segundo operando. */
121 ParseError_set_message(error, "Falta segundo operando");
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. */
129 /* Calcula la expresión del segundo operando. */
130 if (!parser_expression(exp + i + 1, len - i - 1, &result2,
132 /* Si hay error, devuelve FALSE (y "arrastra" el error. */
135 /* Si estamos dividiendo, chequeamos que el divisor no sea cero. */
137 /* Segundo operando es cero. */
138 if (result2 == 0.0) {
139 ParseError_set_message(error, "División por cero");
142 *result = result1 / result2;
143 /* Si estamos multiplicando, no hay chequeos extra. */
145 *result = result1 * result2;
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.
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. */
161 /* Si no tiene operadores ni valores numéricos ni es una variable, es un
163 ParseError_set_message(error, "La expresión es incorrecta");
167 #undef PARSE_ERROR /* Sólo queremos usarlo en este fragmento */