// ----------------------------------------------------------------------------
// 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();
}