diff --git a/calculadora/calc b/calculadora/calc new file mode 100755 index 0000000000000000000000000000000000000000..8d7a4dac79d6762c834c6c3a97b70f9067d60434 Binary files /dev/null and b/calculadora/calc differ diff --git a/calculadora/calculadora.c b/calculadora/calculadora.c new file mode 100644 index 0000000000000000000000000000000000000000..02b4363baec33b9fb524e0df8ca2f67c73698906 --- /dev/null +++ b/calculadora/calculadora.c @@ -0,0 +1,243 @@ +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include "libpilha.h" + +typedef double 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, + valores maiores tem maior precedencia. */ +#define SOM 10.1 +#define SUB 10.2 +#define MUL 20.1 +#define DIV 20.2 + + +/* Identificador de '(' para ser empilhado na pilha de operadores */ +#define PAR 99.0 + + +/* Converte os caracteres que representam os operadores na entrada + para valores constantes que identificam os operadores. + Retorna 1 se o caracter c representa um operador valido e 0 caso + contrario. */ +int converte_operador(t_operador *op, char c) { + switch(c) { + case '+': *op = SOM; break; + case '-': *op = SUB; break; + case '*': *op = MUL; break; + case '/': *op = DIV; break; + default : return 0; + } + return 1; +} + + +/* 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) + return 1; + return 0; +} + + +/* Desempilha os dois valores no topo da pilha de valores, aplica o + operador sobre esses valores e empilha o resultado na pilha de + valores. */ +int opera(t_operador op, t_pilha *valores) { + double val_esq, val_dir; + + if(!desempilha(&val_dir, valores)) + return 0; + if(!desempilha(&val_esq, valores)) + return 0; + if(op == SOM) + return empilha(val_esq + val_dir, valores); + if(op == SUB) + return empilha(val_esq - val_dir, valores); + if(op == MUL) + return empilha(val_esq * val_dir, valores); + if(op == DIV && val_dir != 0.0) + return empilha(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); +} + + +/* Le da entrada padrao, usando fgets, um vetor de caracteres ate o \n. + Se o tamanho da entrada for maior que o vetor de leitura, aumenta + o tamanho do vetor e continua a leitura ate encontrar o \n. + Retorna um ponteiro para o vetor lido ou NULL caso ocorra algum erro + ne leitura ou ne alocação de memoria. */ +/* +char* le_entrada() { + char *ent, *ret_realloc, *ret_fgets; + int tam, pos; + + ent = NULL; + tam = 0; + pos = 0; + + do { + tam += TAM_ENTRADA; + ret_realloc = (char*) realloc(ent, sizeof(char) * tam); + if(!ret_realloc) { + free(ent); + return NULL; + } + ent = ret_realloc; + ent[tam - 1] = ' '; + ret_fgets = fgets(ent + pos, tam - pos, stdin); + pos = tam - 1; + } while(ret_fgets && ent[tam - 1] == '\0' && ent[tam - 2] != '\n'); + + if(!ret_fgets && tam == TAM_ENTRADA) { + free(ent); + return NULL; + } + + return ent; +} +*/ + + +/* Le da entrada padrao, usando fgets, um vetor de caracteres ate o \n. + Retorna um ponteiro para o vetor lido ou NULL caso ocorra algum erro + ne leitura ou na alocação de memoria. Se o tamanho da entrada for + maior que o vetor de leitura, retorna NULL. */ +char* le_entrada() { + char *ent, *ret_fgets; + int tam; + + tam = TAM_ENTRADA; + ent = (char*) malloc(sizeof(char) * tam); + if(!ent) + return NULL; + ent[tam - 1] = ' '; + ret_fgets = fgets(ent, tam, stdin); + if(!ret_fgets || (ent[tam - 1] == '\0' && ent[tam - 2] != '\n')) { + free(ent); + return NULL; + } + 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); + + entrada = le_entrada(); + if(!entrada) + erro_aborta("erro de leitura", 0); + + 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); + + destroi_pilha(pilha_valores); + destroi_pilha(pilha_operadores); + free(entrada); + + return 0; +} diff --git a/calculadora/libpilha.c b/calculadora/libpilha.c new file mode 100644 index 0000000000000000000000000000000000000000..9a4384276a3728ac24e2c819daf60be2b33b76b9 --- /dev/null +++ b/calculadora/libpilha.c @@ -0,0 +1,49 @@ +#include <stdlib.h> +#include "libpilha.h" + +t_pilha* cria_pilha(int n) { + t_pilha *p; + if ( !(p = malloc(sizeof(t_pilha) * n)) ) + return NULL; + + p->tam = n; + p->topo = -1; + + if ( !(p->v = malloc(sizeof(double) * n)) ) + return NULL; + return p; +} + +t_pilha* destroi_pilha(t_pilha *p) { + free(p->v); + free(p); + return NULL; +} + +int pilha_vazia(t_pilha *p) { + return p->topo == -1; +} + +int empilha(double x, t_pilha *p) { + if (p->topo == p->tam) + return 0; + p->topo++; + p->v[p->topo] = x; + + return 1; +} + +int desempilha(double *t, t_pilha *p) { + if (pilha_vazia(p)) + return 0; + *t = p->v[p->topo]; + p->topo--; + return 1; +} + +int topo(double *t, t_pilha *p) { + if (pilha_vazia(p)) + return 0; + *t = p->v[p->topo]; + return 1; +} diff --git a/calculadora/libpilha.h b/calculadora/libpilha.h new file mode 100644 index 0000000000000000000000000000000000000000..3eddf49979b0408d6af3501820e64e36c97d6a9b --- /dev/null +++ b/calculadora/libpilha.h @@ -0,0 +1,31 @@ +struct s_pilha { + int tam; + int topo; + double *v; +}; +typedef struct s_pilha t_pilha; + + +/* Cria uma pilha com espaço para n elementos do tipo double. + Retorna um ponteiro para a pilha ou NULL em caso de erro na + alocacao de memoria. */ +t_pilha* cria_pilha(int n); + +/* Desaloca a memoria usada pela pilha e retorna NULL */ +t_pilha* destroi_pilha(t_pilha *p); + +/* Retorna 1 se a pilha p esta vazia e 0 caso contrario. */ +int pilha_vazia(t_pilha *p); + +/* Empilha o double x na pilha p. Retorna 1 se a operacao foi + realizada com sucesso e 0 caso contrario. */ +int empilha(double x, t_pilha *p); + +/* Retorna em t o elemento do topo da pilha e o desempilha. A funcao + retorna 1 se a operacao foi bem sucedida e 0 caso contrario. */ +int desempilha(double *t, t_pilha *p); + +/* Retorna em t o elemento do topo da pilha, sem desempilhar. + A funcao retorna 1 se a operacao foi bem sucedida e 0 caso + contrario. */ +int topo(double *t, t_pilha *p); diff --git a/calculadora/makefile b/calculadora/makefile new file mode 100644 index 0000000000000000000000000000000000000000..0031aa354f97e35fbdaa2a9de557021582482f5f --- /dev/null +++ b/calculadora/makefile @@ -0,0 +1,14 @@ +CC = gcc +CFLAGS = -Wall -g -std=c90 + +calc: calculadora.o libpilha.o + $(CC) calculadora.o libpilha.o -o calc + +calculadora.o : libpilha.h calculadora.c + $(CC) $(CFLAGS) -c calculadora.c + +libpilha.o : libpilha.h libpilha.c + $(CC) $(CFLAGS) -c libpilha.c + +clean : + rm -f *.o