Skip to content
Snippets Groups Projects
Commit 0b742219 authored by Pedro Folloni Pesserl's avatar Pedro Folloni Pesserl
Browse files

add exponentiation, memory storage and multiple line calculations

parent 003a0edc
Branches
No related tags found
No related merge requests found
File deleted
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <math.h>
#include "libpilha.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_ENTRADA 256
#define TAM_PILHA 1024 #define TAM_PILHA 1024
/* Constantes com valores para identificar os operadores. O valor /* 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. */ valores maiores tem maior precedencia. */
#define SOM 10.1 #define SOM 101
#define SUB 10.2 #define SUB 102
#define MUL 20.1 #define MUL 201
#define DIV 20.2 #define DIV 202
#define EXP 300
/* Identificador de '(' para ser empilhado na pilha de operadores */ /* 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 /* Converte os caracteres que representam os operadores na entrada
...@@ -32,6 +36,7 @@ int converte_operador(t_operador *op, char c) { ...@@ -32,6 +36,7 @@ int converte_operador(t_operador *op, char c) {
case '-': *op = SUB; break; case '-': *op = SUB; break;
case '*': *op = MUL; break; case '*': *op = MUL; break;
case '/': *op = DIV; break; case '/': *op = DIV; break;
case '^': *op = EXP; break;
default : return 0; default : return 0;
} }
return 1; return 1;
...@@ -41,7 +46,7 @@ int converte_operador(t_operador *op, char c) { ...@@ -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 1 se o operador op1 tem precedencia sobre o operador op2.
Retorna 0 caso contrario. */ Retorna 0 caso contrario. */
int precede(t_operador op1, t_operador op2) { int precede(t_operador op1, t_operador op2) {
if((op1 - op2) >= 1.0) if((op1 - op2) > 1)
return 1; return 1;
return 0; return 0;
} }
...@@ -65,15 +70,18 @@ int opera(t_operador op, t_pilha *valores) { ...@@ -65,15 +70,18 @@ int opera(t_operador op, t_pilha *valores) {
return empilha(val_esq * val_dir, valores); return empilha(val_esq * val_dir, valores);
if(op == DIV && val_dir != 0.0) 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; return 0;
} }
/* Imprime na saida de erro (stderr) a mensagem de erro e a linha e /* Imprime na saida de erro (stderr) a mensagem de erro e a linha e
a coluna da entrada onde o erro foi detectado. */ a coluna da entrada onde o erro foi detectado. */
void erro_aborta(char *msg, int col) { void erro(char *msg, int col, int *flag_erro) {
fprintf(stderr, "ERRO: %s (coluna %d)\n", msg, col); fprintf(stderr, "ERRO: %s (coluna %d)\n", msg, col);
exit(1); *flag_erro = 1;
} }
...@@ -135,32 +143,42 @@ char* le_entrada() { ...@@ -135,32 +143,42 @@ char* le_entrada() {
return ent; return ent;
} }
int main() { int main() {
t_pilha *pilha_valores, *pilha_operadores; t_pilha *pilha_valores, *pilha_operadores;
t_operador operador, op_topo; t_operador operador, op_topo;
double operando, resultado; double operando, resultado, memoria = 0.0;
char *entrada, *c, *prox; char *entrada, *c, *prox;
int flag_erro = 0;
entrada = le_entrada();
if(!entrada) {
erro("erro de leitura", 0, &flag_erro);
return 1;
}
c = entrada;
/* 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); pilha_valores = cria_pilha(TAM_PILHA);
if(!pilha_valores) if(!pilha_valores) {
erro_aborta("erro ao criar pilha de valores", 0); erro("erro ao criar pilha de valores", 0, &flag_erro);
return 1;
}
pilha_operadores = cria_pilha(TAM_PILHA); pilha_operadores = cria_pilha(TAM_PILHA);
if(!pilha_operadores) if(!pilha_operadores) {
erro_aborta("erro ao criar pilha de operadores", 0); erro("erro ao criar pilha de operadores", 0, &flag_erro);
return 1;
}
entrada = le_entrada(); while(*c != 'q' && *c != '\n' && !flag_erro) {
if(!entrada) /* Percorre o ponteiro c pela entrada até achar um q, o final da linha ou um erro. */
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 */ /* Caso 1: separadores */
if(*c == ' ' || *c == '\t') if(*c == ' ' || *c == '\t')
/* Se for sepador, passa para o proximo caracter. */ /* Se for separador, passa para o proximo caracter. */
c++; c++;
/* Caso 2: operando */ /* Caso 2: operando */
...@@ -168,9 +186,10 @@ int main() { ...@@ -168,9 +186,10 @@ int main() {
/* Se for [1..9] le um valor e empilha na pilha de valores. */ /* Se for [1..9] le um valor e empilha na pilha de valores. */
operando = strtod(c, &prox); operando = strtod(c, &prox);
if(c == prox) if(c == prox)
erro_aborta("operando incorreto", c - entrada + 1); erro("operando incorreto", c - entrada + 1, &flag_erro);
if(!empilha(operando, pilha_valores)) else if(!empilha(operando, pilha_valores))
erro_aborta("pilha de valores cheia", c - entrada + 1); erro("pilha de valores cheia", c - entrada + 1, &flag_erro);
else
c = prox; c = prox;
} }
...@@ -178,7 +197,8 @@ int main() { ...@@ -178,7 +197,8 @@ int main() {
else if(*c == '(') { else if(*c == '(') {
/* Se for abre parenteses, empilha PAR na pilha de operadores. */ /* Se for abre parenteses, empilha PAR na pilha de operadores. */
if(!empilha(PAR, pilha_operadores)) if(!empilha(PAR, pilha_operadores))
erro_aborta("pilha de operadores cheia", c - entrada + 1); erro("pilha de operadores cheia", c - entrada + 1, &flag_erro);
else
c++; c++;
} }
...@@ -186,14 +206,15 @@ int main() { ...@@ -186,14 +206,15 @@ int main() {
else if(*c == ')') { else if(*c == ')') {
/* Se for fecha parenteses, processa a pilha de operadores até /* Se for fecha parenteses, processa a pilha de operadores até
encontar um PAR. */ encontar um PAR. */
while(topo(&op_topo, pilha_operadores) && op_topo != PAR) { while(topo(&op_topo, pilha_operadores) && op_topo != PAR && !flag_erro) {
desempilha(&op_topo, pilha_operadores); desempilha(&op_topo, pilha_operadores);
if(!opera(op_topo, pilha_valores)) if(!opera(op_topo, pilha_valores))
erro_aborta("formato incorreto", c - entrada + 1); erro("formato incorreto", c - entrada + 1, &flag_erro);
} }
if(pilha_vazia(pilha_operadores) || if(pilha_vazia(pilha_operadores) ||
(desempilha(&op_topo, pilha_operadores) && op_topo != PAR)) (desempilha(&op_topo, pilha_operadores) && op_topo != PAR))
erro_aborta("formato incorreto", c - entrada + 1); erro("formato incorreto", c - entrada + 1, &flag_erro);
else
c++; c++;
} }
...@@ -203,41 +224,74 @@ int main() { ...@@ -203,41 +224,74 @@ int main() {
ao topo da pilha de operadores. */ ao topo da pilha de operadores. */
while(topo(&op_topo, pilha_operadores) && while(topo(&op_topo, pilha_operadores) &&
op_topo != PAR && op_topo != PAR &&
precede(op_topo, operador)) { precede(op_topo, operador) &&
!flag_erro) {
/* Enquando o topo da pilha tiver precedencia, desempilha e /* Enquando o topo da pilha tiver precedencia, desempilha e
processa o operador do topo da pilha. */ processa o operador do topo da pilha. */
desempilha(&op_topo, pilha_operadores); desempilha(&op_topo, pilha_operadores);
if(!opera(op_topo, pilha_valores)) if(!opera(op_topo, pilha_valores))
erro_aborta("formato incorreto", c - entrada + 1); erro("formato incorreto", c - entrada + 1, &flag_erro);
} }
if(!empilha(operador, pilha_operadores)) if(!empilha(operador, pilha_operadores))
/* Empilha o novo operador na pilha de operadores. */ /* Empilha o novo operador na pilha de operadores. */
erro_aborta("pilha de operadores cheia", c - entrada + 1); 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++; c++;
} }
/* Caso 6: caracter invalido na entrada */ /* Caso 7: caracter invalido na entrada */
else else
erro_aborta("caracter desconhecido", c - entrada + 1); erro("caracter desconhecido", c - entrada + 1, &flag_erro);
} }
/* Nesse ponto o processamento da entrada terminou e pode ser o caso da /* Sai da leitura se encontrar um q em qualquer posição da entrada */
pilha de operadores nao estar vazia. */ if(*c == 'q') break;
while(desempilha(&op_topo, pilha_operadores)) {
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. */ /* Processa os operadores que restaram na pilha. */
if(!opera(op_topo, pilha_valores)) if(!opera(op_topo, pilha_valores))
erro_aborta("formato incorreto", c - entrada + 1); erro("formato incorreto", c - entrada + 1, &flag_erro);
} }
/* Após o processamento, o resultado final da expressao esta no topo da /* Após o processamento, o resultado final da expressao esta no topo da
pilha de valores. */ pilha de valores. */
if(!flag_erro) {
if(!desempilha(&resultado, pilha_valores)) if(!desempilha(&resultado, pilha_valores))
erro_aborta("formato incorreto", c - entrada + 1); erro("formato incorreto", c - entrada + 1, &flag_erro);
else {
memoria = resultado;
printf("%.16g\n", resultado); printf("%.16g\n", resultado);
}
}
}
/* Libera a entrada e lê uma nova entrada. */
destroi_pilha(pilha_valores); destroi_pilha(pilha_valores);
destroi_pilha(pilha_operadores); destroi_pilha(pilha_operadores);
free(entrada); free(entrada);
entrada = le_entrada();
if(!entrada)
erro("erro de leitura", 0, &flag_erro);
c = entrada;
flag_erro = 0;
}
free(entrada);
return 0; return 0;
} }
...@@ -2,13 +2,13 @@ CC = gcc ...@@ -2,13 +2,13 @@ CC = gcc
CFLAGS = -Wall -g -std=c90 CFLAGS = -Wall -g -std=c90
calc: calculadora.o libpilha.o 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 calculadora.o : libpilha.h calculadora.c
$(CC) $(CFLAGS) -c calculadora.c $(CC) $(CFLAGS) -c calculadora.c -lm
libpilha.o : libpilha.h libpilha.c libpilha.o : libpilha.h libpilha.c
$(CC) $(CFLAGS) -c libpilha.c $(CC) $(CFLAGS) -c libpilha.c
clean : clean :
rm -f *.o rm -f *.o calc
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment