25.06
2020
Recentemente orientei um participante da lista ccppbrasil com um exercício que ele estava tentando fazer. E dentre as soluções que eu sugeri tinha a opção dele criar uma calculadora RPN utilizando C. Pra quem não sabe como funciona uma calculadora RPN (Notação Polonesa Reversa), pode dar uma olhada neste link.
Na verdade o rapaz queria fazer parse de álgebra direta, eu orientei fazer uma RPN com uma pilha de 2 variáveis, x e y. E agora eu desenvolvi a solução e decidi disponibilizar. Vamos a primeira opção:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char input[128] = "";
int x = 0, y = 0;
do {
int ct = 0;
printf("> ");
scanf("%s", input);
/* is digit? */
for (ct = strlen(input); ct--; )
if (!isdigit(input[ct]))
break;
if (ct < 0) {
y = x;
x = atoi(input);
} else {
if (strlen(input) > 1) {
printf("\tInvalid operator: %s\n", input);
continue;
}
switch (input[0]) {
case '+': x = y + x; break;
case '-': x = y - x; break;
case '*': x = y * x; break;
case '/': x = y / x; break;
case 'q': printf ("\tquit\n"); exit(0);
default: printf("\tInvalid operator: %s\n", input); continue;
}
}
printf("\t%d\n", x);
} while (input[0] != '\x0');
exit(0);
}
Uma solução bem simples, utilizando conceitos básicos. Fica um desafio, fazer uma pilha de N elementos, ao invés de somente x e y. Outra opção é aceitar números negativos, ou de ponto flutuante.
Note a construção não ortodoxa do for para determinar se a entrada é numérica ou não. Para maiores informações veja neste post. Quando ct for negativo indica que o for percorreu todos os caracteres da string sem passar pelo break, ou seja, é exclusivamente numérico. Quando ct não for negativo indica que em algum momento o loop saiu através do break, signifiando que não é numérico.
Para a conversão para int eu usei a função atoi (ascii to int), é a forma mais simples de fazer parser de strings numéricas.
Quem quiser testar o código pode usar o arquivo disponibilizado no github.
Comentários
Muito bom meu caro!
Posso dizer que você contribuiu muito para o meu conhecimento na linguagem. Agora vou ter que reservar um tempo para estudar esse código hehe.
Obrigado!
Marcelo aqui. (o rapaz que queria fazer parse de álgebra direta rs..)
Ele pode fazer a “algebra direta” também se quiser, só que em dois passos: primeiro transformando a expressão em formato infixo para o pósfixo (não é um algoritmo muito complicado), e depois resolvendo a expressão pósfixa com este algoritmo acima. Agora, se ele quiser resolver “algebra direta” mesmo (sem este passo intermediário) aí complica. Acredito que nem seja possível, a não ser que ele use uma algebra limitada definindo um nível máximo de recursão.