C: Calculadora (simples) com notação polonesa reversa

Analisando as estatísticas do blog, percebi que uma grande parte das pesquisas que caem aqui são sobre “implementação notação polonesa reversa”. Por isso, decidi mostrar como fazer uma em C, usando a biblioteca termios.h que eu mostrei no artigo anterior.

Ela é bem simples, trabalha com ints apenas e com as quatro operações básicas: adição, subtração, multiplicação e divisão. Quem estiver atrás de algo mais usável (para Linux), eu recomendo uma chamada “galculator”.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#include <termios.h>

#define CTOI(x) (x-48)

void silent(struct termios *init_setting, struct termios *new_setting);
void verbose(struct termios *init_setting);
void push_stack(int number, int *stack);
void make_number(int *number, int new_digit);

unsigned char get_char(void);

int do_operation(int *number, int *stack, unsigned char operation);

int main(int argc, char *argv[])
{
    struct termios init_setting, new_setting;
    unsigned char pressed = '', last = '';
    int current_number = 0;

    int stack[3];

    stack[0] = 0;
    stack[1] = 0;
    stack[2] = 0;

    printf("Basic RPN Calculator. Press 'q' to quit.\n");
    silent(&init_setting, &new_setting);

    while(pressed != 'q')
    {
        last = pressed;
        pressed = get_char();

        switch(pressed)
        {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                verbose(&init_setting);
                write(fileno(stdin), &pressed, 1);

                if(last == '+' || last == '-' || last == '*' || last == '/')
                {
                    push_stack(current_number, stack);
                    current_number = CTOI(pressed);
                } else if(last == '\n')
                {
                    current_number = CTOI(pressed);
                } else {
                    make_number(&current_number, CTOI(pressed));
                }

                silent(&init_setting, &new_setting);
                break;

            case '\n':
                verbose(&init_setting);
                write(fileno(stdin), &pressed, 1);

                push_stack(current_number, stack);

                silent(&init_setting, &new_setting);
                break;

            case '+':
            case '-':
            case '*':
            case '/':
                verbose(&init_setting);

                printf("\n%c\t%d\n", pressed,
                        do_operation(&current_number, stack, pressed));

                silent(&init_setting, &new_setting);
                break;

            default:
                break;
        }

   }

    verbose(&init_setting);
    return(0);
}

void silent(struct termios *init_setting, struct termios *new_setting)
{
    tcgetattr(fileno(stdin), init_setting);
    new_setting = init_setting;

    new_setting->c_lflag &= ~(ICANON | ECHO | ISIG);

    new_setting->c_cc[VMIN] = 1;
    new_setting->c_cc[VTIME] = 0;

    tcsetattr(fileno(stdin), TCSADRAIN, new_setting);
}

void verbose(struct termios *init_setting)
{
    tcsetattr(fileno(stdin), TCSADRAIN, init_setting);
}

void push_stack(int number, int *stack)
{
    stack[2] = stack[1];
    stack[1] = stack[0];
    stack[0] = number;
}

void make_number(int *number, int new_digit)
{
    *number = (*number*10) + new_digit;
}

unsigned char get_char()
{
    unsigned char ch;

    read(fileno(stdin), &ch, sizeof(unsigned char));

    return ch;
}

int do_operation(int *number, int *stack, unsigned char operation)
{
    switch(operation)
    {
        case '+':
            *number = *number + stack[0];
            break;
        case '-':
            *number = stack[0] - *number;
            break;
        case '*':
            *number = *number * stack[0];
            break;
        case '/':
            *number = stack[0] / *number;
            break;
    }

    stack[0] = stack[1];
    stack[1] = stack[2];
    stack[2] = 0;

    return(*number);
}
Publicidade

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: