// ---------------------------------------------------------------------------- // Calculadora que utiliza Notacao Reversa Polonesa (RPN) // Criado por Wenderson Teixeira // // comandos suportados atualmente: // Drop ou D - retira valor da pilha // Dup - duplica ultimo valor da pilha // Swap ou S - troca os dois ultimos valores da pilha // Exit ou X - sai do programa // Abs - valor absoluto do ultimo numero da pilha // Sin - seno // Cos - cosseno // Tan - tangente // + - soma os dois ultimos valores // - - subtrai // * - multiplica // / - divide // -- - inverte o sinal // // Obs.: uma linha de comando pode conter um ou mais comandos, exemplo: // > 10 // > 10 2 + // > 4 3.1415269 * 180 / // // Modulo: Calc.cpp Ultima atualizacao: 19/06/99 // ---------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <alloc.h> #include <string.h> #include <conio.h> #include <math.h> #include <ctype.h> // Macro de comparacao de strings // retorna true se sao iguais e false caso contrario #define IsStrEqual(a, b) (strcmpi((a), (b)) == 0) // O tipo bool e as constantes true e false sao novos no C++, // entao se estiver compilando em C, ou versoes antigas do C++, // bool deve ser definido #if (__BORLANDC__ <= 0x460) || !defined(__cplusplus) typedef enum { false, true } bool; #endif // Estrutura da pilha typedef struct tag_Stack { double value; tag_Stack *next; } TStack; // Definicao da pilha TStack *stack = 0; // Funcao que testa se uma string possui apenas digitos validos p/ // um numero, e que esteja no formato [s][[#][.[#]]][#[e[s]#]] // por ex.: // 1, +1, -1, 1.1, 1e10, 1e-10, 1.e10, 1.1e10 - Validos // .1., 1e0.1, -+1, +, -, ., 1+1 - Invalidos bool IsNumber(char *str) { int c = 0; bool valid = false; // Verifica sinal if(str[c] == '-' || str[c] == '+') c++; // Verifica ponto decimal if(isdigit(str[c]) || str[c] == '.') { valid = true; // Se comecar com ponto decimal, deve haver pelo // menos digito, e nao pode terminar com ponto if(str[c] == '.') { c++; // Se nao possui digitos, esta errado if(isdigit(str[c])) { while(isdigit(str[c])) c++; // Nao pode haver outro ponto valid = str[c] != '.'; } else valid = false; } // Se parte inteira esta OK if(valid) { // Verifica digitos antes do ponto decimal while(isdigit(str[c])) c++; // Verifica ponto decimal if(str[c] == '.') c++; // Verificia digitos apos o ponto decimal while(isdigit(str[c])) c++; // Verifica 'e' p/ potencia de 10 if(tolower(str[c]) == 'e') { c++; // Deve existir digitos if(str[c] == '\0') valid = false; else { // Verifica sinal da pontencia de 10 if((str[c] == '-') || (str[c] == '+')) c++; // Deve haver digito apos o sinal if(str[c] == '\0') valid = false; else { while(isdigit(str[c])) c++; valid = str[c] == '\0'; } } } else valid = str[c] == '\0'; } } return valid; } // Salva na pilha void Push(double value) { TStack *s = (TStack *)malloc(sizeof(TStack)); s->value = value; s->next = stack; stack = s; } // Retira da pilha double Pop() { double value = 0; if(stack) { TStack *s = stack; value = stack->value; stack = stack->next; free(s); } return value; } // Devolve o tamanho da pilha int Length() { TStack *s = stack; int c = 0; while(s) { c++; s = s->next; } return c; } // Destroi a pilha void Destroy() { while(stack) Pop(); } // Mostra os valores na pilha void Show(TStack *s) { if(s) { Show(s->next); printf("%10.3lf\n", s->value); } } // Executa calculadora void Run() { bool done = false; int length; char str[256]; while(!done) { // Exibe lista de comandos printf("Stack calculator - Copyright (c) 1999 by Wenderson Teixiera\n\n"); printf("Commands\n" "Drop (D), Dup, Swap (S), Exit (X)\n" "Abs, Sin, Cos, Tan, +, -, *, /, --\n\n"); // Mostra a pilha Show(stack); // Espera ser digitado algum comando printf("\n> "); scanf("%s", str); clrscr(); // Se for numero, poe na pilha if(IsNumber(str)) Push(atof(str)); else { // Tentar processar como um comando length = Length(); if(IsStrEqual(str, "exit") || IsStrEqual(str, "x")) done = true; else if(length > 1 && (IsStrEqual(str, "swap") || IsStrEqual(str, "s"))) { double a = Pop(), b = Pop(); Push(a); Push(b); } else if(length) { if(IsStrEqual(str, "drop") || IsStrEqual(str, "d")) Pop(); else if(IsStrEqual(str, "dup")) { double a = Pop(); Push(a); Push(a); } else if(IsStrEqual(str, "abs")) Push(fabs(Pop())); else if(IsStrEqual(str, "sin")) Push(sin(Pop())); else if(IsStrEqual(str, "cos")) Push(cos(Pop())); else if(IsStrEqual(str, "tan")) Push(tan(Pop())); else if(IsStrEqual(str, "--")) Push(-Pop()); else if(strlen(str) == 1) { switch(str[0]) { case '+': if(length > 1) Push(Pop() + Pop()); break; case '-': Push(-Pop() + Pop()); break; case '*': if(length > 1) Push(Pop() * Pop()); break; case '/': if(length > 1) Push(1/Pop() * Pop()); break; } } } } } // Destroi a pilha Destroy(); } void main() { Run(); }