diff --git a/calculadora/calc b/calculadora/calc deleted file mode 100755 index 8d7a4dac79d6762c834c6c3a97b70f9067d60434..0000000000000000000000000000000000000000 Binary files a/calculadora/calc and /dev/null differ diff --git a/calculadora/calculadora.c b/calculadora/calculadora.c index 02b4363baec33b9fb524e0df8ca2f67c73698906..efd209c79d3acbcaffd92b13e88484ec7630da64 100644 --- a/calculadora/calculadora.c +++ b/calculadora/calculadora.c @@ -1,25 +1,29 @@ #include <stdlib.h> #include <stdio.h> #include <ctype.h> +#include <math.h> #include "libpilha.h" -typedef double t_operador; +/* Definindo o valor do operador como um inteiro, prevenimos + erros de aritmética com ponto flutuante. */ +typedef int t_operador; #define TAM_ENTRADA 256 #define TAM_PILHA 1024 /* Constantes com valores para identificar os operadores. O valor - antes do ponto flutuante difine a precedencia entre os operadores, + antes da casa da unidade define a precedencia entre os operadores, valores maiores tem maior precedencia. */ -#define SOM 10.1 -#define SUB 10.2 -#define MUL 20.1 -#define DIV 20.2 +#define SOM 101 +#define SUB 102 +#define MUL 201 +#define DIV 202 +#define EXP 300 /* Identificador de '(' para ser empilhado na pilha de operadores */ -#define PAR 99.0 +#define PAR 990 /* Converte os caracteres que representam os operadores na entrada @@ -32,6 +36,7 @@ int converte_operador(t_operador *op, char c) { case '-': *op = SUB; break; case '*': *op = MUL; break; case '/': *op = DIV; break; + case '^': *op = EXP; break; default : return 0; } return 1; @@ -41,7 +46,7 @@ int converte_operador(t_operador *op, char c) { /* Retorna 1 se o operador op1 tem precedencia sobre o operador op2. Retorna 0 caso contrario. */ int precede(t_operador op1, t_operador op2) { - if((op1 - op2) >= 1.0) + if((op1 - op2) > 1) return 1; return 0; } @@ -54,26 +59,29 @@ int opera(t_operador op, t_pilha *valores) { double val_esq, val_dir; if(!desempilha(&val_dir, valores)) - return 0; + return 0; if(!desempilha(&val_esq, valores)) - return 0; + return 0; if(op == SOM) - return empilha(val_esq + val_dir, valores); + return empilha(val_esq + val_dir, valores); if(op == SUB) - return empilha(val_esq - val_dir, valores); + return empilha(val_esq - val_dir, valores); if(op == MUL) - return empilha(val_esq * val_dir, valores); + return empilha(val_esq * val_dir, valores); if(op == DIV && val_dir != 0.0) - return empilha(val_esq / val_dir, valores); + return empilha(val_esq / val_dir, valores); + if(op == EXP) + return empilha(pow(val_esq, val_dir), valores); + return 0; } /* Imprime na saida de erro (stderr) a mensagem de erro e a linha e a coluna da entrada onde o erro foi detectado. */ -void erro_aborta(char *msg, int col) { - fprintf(stderr, "ERRO: %s (coluna %d)\n", msg, col); - exit(1); +void erro(char *msg, int col, int *flag_erro) { + fprintf(stderr, "ERRO: %s (coluna %d)\n", msg, col); + *flag_erro = 1; } @@ -135,109 +143,155 @@ char* le_entrada() { return ent; } - int main() { t_pilha *pilha_valores, *pilha_operadores; t_operador operador, op_topo; - double operando, resultado; - char *entrada, *c, *prox; - - pilha_valores = cria_pilha(TAM_PILHA); - if(!pilha_valores) - erro_aborta("erro ao criar pilha de valores", 0); - - pilha_operadores = cria_pilha(TAM_PILHA); - if(!pilha_operadores) - erro_aborta("erro ao criar pilha de operadores", 0); + double operando, resultado, memoria = 0.0; + char *entrada, *c, *prox; + int flag_erro = 0; entrada = le_entrada(); - if(!entrada) - erro_aborta("erro de leitura", 0); + if(!entrada) { + erro("erro de leitura", 0, &flag_erro); + return 1; + } c = entrada; - while(*c != '\n') { - /* Percorre o ponteiro c pela entrada ate o final de linha. */ - - /* Caso 1: separadores */ - if(*c == ' ' || *c == '\t') - /* Se for sepador, passa para o proximo caracter. */ - c++; - - /* Caso 2: operando */ - else if(isdigit(*c)) { - /* Se for [1..9] le um valor e empilha na pilha de valores. */ - operando = strtod(c, &prox); - if(c == prox) - erro_aborta("operando incorreto", c - entrada + 1); - if(!empilha(operando, pilha_valores)) - erro_aborta("pilha de valores cheia", c - entrada + 1); - c = prox; - } - - /* Caso 3: abre parenteses */ - else if(*c == '(') { - /* Se for abre parenteses, empilha PAR na pilha de operadores. */ - if(!empilha(PAR, pilha_operadores)) - erro_aborta("pilha de operadores cheia", c - entrada + 1); - c++; - } - - /* Caso 4: fecha parenteses */ - else if(*c == ')') { - /* Se for fecha parenteses, processa a pilha de operadores até - encontar um PAR. */ - while(topo(&op_topo, pilha_operadores) && op_topo != PAR) { - desempilha(&op_topo, pilha_operadores); - if(!opera(op_topo, pilha_valores)) - erro_aborta("formato incorreto", c - entrada + 1); - } - if(pilha_vazia(pilha_operadores) || - (desempilha(&op_topo, pilha_operadores) && op_topo != PAR)) - erro_aborta("formato incorreto", c - entrada + 1); - c++; - } - - /* Caso 5: operador */ - else if(converte_operador(&operador, *c)) { - /* Se for um operador valido, verifica a precedencia em relacao - ao topo da pilha de operadores. */ - while(topo(&op_topo, pilha_operadores) && - op_topo != PAR && - precede(op_topo, operador)) { - /* Enquando o topo da pilha tiver precedencia, desempilha e - processa o operador do topo da pilha. */ - desempilha(&op_topo, pilha_operadores); - if(!opera(op_topo, pilha_valores)) - erro_aborta("formato incorreto", c - entrada + 1); - } - if(!empilha(operador, pilha_operadores)) - /* Empilha o novo operador na pilha de operadores. */ - erro_aborta("pilha de operadores cheia", c - entrada + 1); - c++; - } - - /* Caso 6: caracter invalido na entrada */ - else - erro_aborta("caracter desconhecido", c - entrada + 1); - } - - /* Nesse ponto o processamento da entrada terminou e pode ser o caso da - pilha de operadores nao estar vazia. */ - while(desempilha(&op_topo, pilha_operadores)) { - /* Processa os operadores que restaram na pilha. */ - if(!opera(op_topo, pilha_valores)) - erro_aborta("formato incorreto", c - entrada + 1); - } - - /* Após o processamento, o resultado final da expressao esta no topo da - pilha de valores. */ - if(!desempilha(&resultado, pilha_valores)) - erro_aborta("formato incorreto", c - entrada + 1); - printf("%.16g\n", resultado); + /* Loop principal, le valores e realiza operacoes ate ler uma linha + que contém "q" na primeira posição */ + while(*c != 'q') { + + pilha_valores = cria_pilha(TAM_PILHA); + if(!pilha_valores) { + erro("erro ao criar pilha de valores", 0, &flag_erro); + return 1; + } + + pilha_operadores = cria_pilha(TAM_PILHA); + if(!pilha_operadores) { + erro("erro ao criar pilha de operadores", 0, &flag_erro); + return 1; + } + + while(*c != 'q' && *c != '\n' && !flag_erro) { + /* Percorre o ponteiro c pela entrada até achar um q, o final da linha ou um erro. */ + + /* Caso 1: separadores */ + if(*c == ' ' || *c == '\t') + /* Se for separador, passa para o proximo caracter. */ + c++; + + /* Caso 2: operando */ + else if(isdigit(*c)) { + /* Se for [1..9] le um valor e empilha na pilha de valores. */ + operando = strtod(c, &prox); + if(c == prox) + erro("operando incorreto", c - entrada + 1, &flag_erro); + else if(!empilha(operando, pilha_valores)) + erro("pilha de valores cheia", c - entrada + 1, &flag_erro); + else + c = prox; + } + + /* Caso 3: abre parenteses */ + else if(*c == '(') { + /* Se for abre parenteses, empilha PAR na pilha de operadores. */ + if(!empilha(PAR, pilha_operadores)) + erro("pilha de operadores cheia", c - entrada + 1, &flag_erro); + else + c++; + } + + /* Caso 4: fecha parenteses */ + else if(*c == ')') { + /* Se for fecha parenteses, processa a pilha de operadores até + encontar um PAR. */ + while(topo(&op_topo, pilha_operadores) && op_topo != PAR && !flag_erro) { + desempilha(&op_topo, pilha_operadores); + if(!opera(op_topo, pilha_valores)) + erro("formato incorreto", c - entrada + 1, &flag_erro); + } + if(pilha_vazia(pilha_operadores) || + (desempilha(&op_topo, pilha_operadores) && op_topo != PAR)) + erro("formato incorreto", c - entrada + 1, &flag_erro); + else + c++; + } + + /* Caso 5: operador */ + else if(converte_operador(&operador, *c)) { + /* Se for um operador valido, verifica a precedencia em relacao + ao topo da pilha de operadores. */ + while(topo(&op_topo, pilha_operadores) && + op_topo != PAR && + precede(op_topo, operador) && + !flag_erro) { + /* Enquando o topo da pilha tiver precedencia, desempilha e + processa o operador do topo da pilha. */ + desempilha(&op_topo, pilha_operadores); + if(!opera(op_topo, pilha_valores)) + erro("formato incorreto", c - entrada + 1, &flag_erro); + } + if(!empilha(operador, pilha_operadores)) + /* Empilha o novo operador na pilha de operadores. */ + erro("pilha de operadores cheia", c - entrada + 1, &flag_erro); + else + c++; + } + + /* Caso 6: memória */ + else if(*c == 'm') { + /* Se for m, empilha o valor guardado na memória na pilha de valores */ + if(!empilha(memoria, pilha_valores)) + erro("pilha de valores cheia", c - entrada + 1, &flag_erro); + else + c++; + } + + /* Caso 7: caracter invalido na entrada */ + else + erro("caracter desconhecido", c - entrada + 1, &flag_erro); + } + + /* Sai da leitura se encontrar um q em qualquer posição da entrada */ + if(*c == 'q') break; + + if(!flag_erro) { + /* Nesse ponto o processamento da entrada terminou (por enquanto sem erros) + e pode ser o caso da pilha de operadores nao estar vazia. */ + while(desempilha(&op_topo, pilha_operadores) && !flag_erro) { + /* Processa os operadores que restaram na pilha. */ + if(!opera(op_topo, pilha_valores)) + erro("formato incorreto", c - entrada + 1, &flag_erro); + } + + /* Após o processamento, o resultado final da expressao esta no topo da + pilha de valores. */ + if(!flag_erro) { + if(!desempilha(&resultado, pilha_valores)) + erro("formato incorreto", c - entrada + 1, &flag_erro); + else { + memoria = resultado; + printf("%.16g\n", resultado); + } + } + } + /* Libera a entrada e lê uma nova entrada. */ + + destroi_pilha(pilha_valores); + destroi_pilha(pilha_operadores); + free(entrada); + + entrada = le_entrada(); + if(!entrada) + erro("erro de leitura", 0, &flag_erro); + + c = entrada; + + flag_erro = 0; + } - destroi_pilha(pilha_valores); - destroi_pilha(pilha_operadores); - free(entrada); + free(entrada); return 0; } diff --git a/calculadora/makefile b/calculadora/makefile index 0031aa354f97e35fbdaa2a9de557021582482f5f..282c19f67f776299bb8925f79910be0cc21515f5 100644 --- a/calculadora/makefile +++ b/calculadora/makefile @@ -2,13 +2,13 @@ CC = gcc CFLAGS = -Wall -g -std=c90 calc: calculadora.o libpilha.o - $(CC) calculadora.o libpilha.o -o calc + $(CC) calculadora.o libpilha.o -o calc -lm calculadora.o : libpilha.h calculadora.c - $(CC) $(CFLAGS) -c calculadora.c + $(CC) $(CFLAGS) -c calculadora.c -lm libpilha.o : libpilha.h libpilha.c $(CC) $(CFLAGS) -c libpilha.c clean : - rm -f *.o + rm -f *.o calc