You are not logged in.

#1 2009-09-21 22:43:58

Peasantoid
Member
Registered: 2009-04-26
Posts: 928
Website

Year-old RPN calculator

I was doing some cruft-cleaning when I discovered this in my project directory. As far as I can tell, it's a basic RPN calculator written in C++. The modification timestamp dates it back to about a year ago, at which point I was still dicking around with PHP under OS X. There are no comments and I apparently hadn't figured out the purpose of std::vector at the time. Enjoy! tongue

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <readline/readline.h>
#include <readline/history.h>
#include <stack>
using namespace std;

#define STR_MAXLEN 64
#define NUM_TOKENS 512

#define T_NONE 0
#define T_OPERAND 1
#define T_ADD 2
#define T_SUBTRACT 3
#define T_MULTIPLY 4
#define T_DIVIDE 5
#define T_POW 6
#define T_ROOT 7

struct token {
  int type;
  long double value;
};

#define IS_NUMERIC(n) ((n) == '0' || (n) == '1' || (n) == '2' || (n) == '3' || \
  (n) == '4' || (n) == '5' || (n) == '6' || (n) == '7' || (n) == '8' || \
  (n) == '9')

int main(int argc, char *argv[]) {
  stack<long double> values;
  token tokens[NUM_TOKENS];
  string input = "", value = "";
  char c, cstr[64] = "", *rl_input = (char *)NULL;
  int i, t;
  long double op1, op2;
  bool raised10;
  
  rl_bind_key('\t', rl_insert);
  while(true) {
    rl_input = readline(": ");
    if(rl_input == NULL) {
      cout << "\n";
      exit(0);
    }
    input.assign(rl_input);
    free(rl_input);
    rl_input = (char *)NULL;

    for(i = 0;
        i < NUM_TOKENS;
        i++) {
      tokens[i].type = T_NONE;
      tokens[i].value = 0.0;
    }
    for(i = 0, t = 0;
        i < input.length();
        i++) {
      c = input.at(i);
      switch(c) {
        case '+':
          tokens[t].type = T_ADD;
          t++;
          break;
        case '*':
          tokens[t].type = T_MULTIPLY;
          t++;
          break;
        case '/':
          tokens[t].type = T_DIVIDE;
          t++;
          break;
        case '^':
          tokens[t].type = T_POW;
          t++;
          break;
        case '?':
          tokens[t].type = T_ROOT;
          t++;
          break;
        case '(':
        case ')':
        case ',':
          break;
        default:
          if(IS_NUMERIC(c) || c == '-') {
            sprintf(cstr, "%c", c);
            raised10 = false;
            for(i++;
                i < input.length();
                i++) {
              if(input.at(i) == 'e') {
                raised10 = true;
              }
              if((!IS_NUMERIC(input.at(i)) && input.at(i) != '.' && input.at(i) != 'e' && input.at(i) != '-') || (input.at(i) == '-' && !raised10)) {
                i--;
                break;
              }
              sprintf(cstr, "%s%c", cstr, input.at(i));
            }
            if(cstr[0] == '-' && strlen(cstr) == 1) {
              tokens[t].type = T_SUBTRACT;
              t++;
            } else {
              tokens[t].type = T_OPERAND;
              tokens[t].value = strtold(cstr, NULL);
              t++;
            }
          } else if(c != ' ' && c != '\t' && c != '\n') {
            cout << "Unexpected character in input: " << c << "\n";
            goto loopcont;
          }
          break;
      }
    }
    
    for(t = 0;
        t < NUM_TOKENS && tokens[t].type != T_NONE;
        t++) {
      if(tokens[t].type == T_OPERAND) {
        values.push(tokens[t].value);
      } else {
        if(values.size() < 2) {
          cout << "Too few arguments provided (token " << t << ")\n";
          goto loopcont;
        }
        op2 = values.top();
        values.pop();
        op1 = values.top();
        values.pop();
        switch(tokens[t].type) {
          case T_ADD:
            values.push(op1 + op2);
            break;
          case T_SUBTRACT:
            values.push(op1 - op2);
            break;
          case T_MULTIPLY:
            values.push(op1 * op2);
            break;
          case T_DIVIDE:
            if(op2 == 0) {
              cout << "Division by zero\n";
              goto loopcont;
            }
            values.push(op1 / op2);
            break;
          case T_POW:
            values.push(pow(op1, op2));
            break;
          case T_ROOT:
            values.push(pow(op1, (1 / op2)));
            break;
        }
      }
      tokens[t].type = T_NONE;
      tokens[t].value = 0.0;
    }

    if(values.size()) {
      cout << values.top() << "\n";
    }
  
loopcont:
    if(input.length()) {
      add_history(input.c_str());
    }

    while(!values.empty()) {
      values.pop();
    }
  }
  
  return 0;
}

To compile:

g++ something.cpp -o something -l readline

Last edited by Peasantoid (2009-09-21 23:28:10)

Offline

#2 2009-09-21 23:24:41

linkmaster03
Member
Registered: 2008-12-27
Posts: 269

Re: Year-old RPN calculator

Cool! I was just reading about RPN today; I'll definitely have to learn it now. Thanks Peasantoid. smile

If anyone is having trouble compiling this:

g++ -lreadline file.cpp

Offline

#3 2009-09-21 23:27:28

Peasantoid
Member
Registered: 2009-04-26
Posts: 928
Website

Re: Year-old RPN calculator

linkmaster03 wrote:

Cool! I was just reading about RPN today; I'll definitely have to learn it now. Thanks Peasantoid. smile

Okay, you're welcome, but first you must promise to write better code than the above.

linkmaster03 wrote:

If anyone is having trouble compiling this:

g++ -lreadline file.cpp

Oh yes, I forgot about that. Added to OP.

Offline

Board footer

Powered by FluxBB