Umgekehrt polnische Notation

Dieses Programm ist ein Taschenrechner mit umgekehrt polnischer Notation.

/*
 * UPN - a reverse polish calculator
 * Copyright (C) 2005 Nicolas Bellm
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * gcc -lm -std=c99 upn.c
 *
 */

#include <stdio.h>
#include <math.h>
#include <error.h>

#define SIZE 255

double stack[SIZE];
double *p;

int push(double d, double *r)
{
  if (p < &stack[SIZE])
  {
    *p = *r = d;
    p++;
    return 0;
  }
  else
  {
    error(0, 0, "Stack-Überlauf");
    return 1;
  }  
}

int pop(double *r)
{
  if (p > &stack[0])
  {
    p--;
    *r = *p;
    return 0;
  }
  else
  {
    error(0, 0, "Stack-Unterlauf");
    return 1;
  }
}

double add(double d1, double d2)
{
  return d1 + d2;
}

double sub(double d1, double d2)
{
  return d1 - d2;
}

double mul(double d1, double d2)
{
  return d1 * d2;
}

double div(double d1, double d2)
{
  return d1 / d2;
}

double root(double d1, double d2)
{
  return pow(d2, 1/d1);
}

int calc(double f(double, double))
{
  double d1, d2;
  if (pop(&d2) || pop(&d1))
  {
    return 1;
  }
  d1 = f(d1, d2);
  if (!isnormal(d1))
  {
    error(0, 0, "Ergebnis ist keine Zahl!");
    return 1;
  }
  
  push(d1, &d1);
  printf("%lf\n",d1);

  return 0;
}

int cal(double f(double))
{
  double d;
  if (pop(&d))
  {
    return 1;
  }
  d = f(d);
  if (!isnormal(d))
  {
    error(0, 0, "Ergebnis ist keine Zahl!");
    return 1;
  }
  
  push(d, &d);
  printf("%lf\n",d);

  return 0;
}

int main()
{
  double d;
  char buf[SIZE];

  p = &stack[0];

  while(1)
  {
    printf(">");
    fgets(buf, SIZE, stdin);
    if (buf && buf[0] != '\n' && sscanf(buf, "%lf", &d))
    {
      push(d, &d);
    }
    else
    {
      switch(buf[0])
      {
        case '+':
          calc(add);
          break;
        case '-':
          calc(sub);
          break;
        case '*':
          calc(mul);
          break;
        case '/':
          calc(div);
          break;
        case '^':
          calc(pow);
          break;
        case 's':
          cal(sqrt);
          break;
        case 'c':
          cal(cbrt);
          break;
        case 'r':
          calc(root);
          break;
        case 'x':
          return 0;
        default:
          error (0, 0, "Fehlerhafte Eingabe");
          break;
      }
    }
  }
}