The C Programming Language

Chapter 5 - Pointers and Arrays 10

mmresult 2009. 3. 27. 14:08


Write the program expr , which evaluates a reverse Polish expression from the command line, where each operator or operand is a separate argument. For example,
expr 2 3 4 + *
 evaluates 2 X (3 + 4).

Solution by Lars Wirzenius

 Note: Lars uses EXIT_FAILURE on error. As far as I can tell, this is the only thing which makes this a Category 1, rather than Category 0, solution.


/*
 * Solution to exercise 5-10 in K&R2:
 *
 * Write the program expr, which evaluates a reverse Polish expression
 * from the command line, where each operator or operand is a separate
 * argument. For example,
 *
 *  expr 2 3 4 + *
 *
 * evaluates 2*(3+4).
 *
 * This is very similar to the program in 4.3 (and should ideally have been
 * a modification of that).
 *
 * Feel free to modify and copy freely.
 *
 * Lars Wirzenius <liw@iki.fi>
 */

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

#define STACK_SIZE 1024

double stack[STACK_SIZE];
int stack_height = 0;

void panic(const char *msg) {
 fprintf(stderr, "%s\n", msg);
 exit(EXIT_FAILURE);
}

void push(double value) {
 if (stack_height == STACK_SIZE)
  panic("stack is too high!");
 stack[stack_height] = value;
 ++stack_height;
}

double pop(void) {
 if (stack_height == 0)
  panic("stack is empty!");
 return stack[--stack_height];
}

int main(int argc, char **argv) {
 int i;
 double value;
 
 for (i = 1; i < argc; ++i) {
  switch (argv[i][0]) {
  case '\0':
   panic("empty command line argument");
   break;
  case '0':
  case '1':
  case '2':
  case '3':
  case '4':
  case '5':
  case '6':
  case '7':
  case '8':
  case '9':
   push(atof(argv[i]));
   break;
  case '+':
   push(pop() + pop());
   break;
  case '-':
   value = pop();
   push(pop() - value);
   break;
  case '*':
   push(pop() * pop());
   break;
  case '/':
   value = pop();
   push(pop() / value);
   break;
  default:
   panic("unknown operator");
   break;
  }
 }

 printf("%g\n", pop());
 return 0;
}

 

 Category 0 Solution by Alex Hoang

/* Allows for leading plus/minus as well as decimal numbers */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

#define NUMBER 0

void push(double f);

double pop(void);


main(int argc, char *argv[])
{
    int type;
    int c;
    double op1, op2, latest;
    while (--argc > 0)
    {
        *++argv;
        if (!isdigit(c = **argv) && strlen(*argv) == 1)
            type = c;
        else
            type = NUMBER;
        switch (type)
        {
            case NUMBER:
                push(atof(*argv));
                break;
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op2 = pop();
                push(pop() - op2);
                break;
            case '/':
                op2 = pop();
                if (op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero divisor\n");
                break;
            case '%':
                op2 = pop();
                if (op2 != 0.0)
                     push(fmod(pop(), op2));
                else
                    printf("error: zero divisor\n");
                break;
            case '^':
                op2 = pop();
                op1 = pop();
                if (op1 == 0.0 && op2 <= 0)
                    printf("if x = 0.0, y must be greater than 0\n");
                else
                    push(pow(op1, op2));
                break;
            case 'e':
                push(exp(pop()));
                break;
            case '~':
                push(sin(pop()));
                break;
            default:
                printf("error: unknown command: %c\n", type);
                break;
        }
    }
    latest = pop();
    printf("\t%.8g\n", latest);
    return 0;
}

#define MAXVAL 100

int sp = 0;
double val[MAXVAL];
/* maximum depth of val stack */
/* next free stack position */
/* value stack */
/* push: push f onto value stack */
void push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        printf("error: stack full, can't push %g\n", f);
}
/* pop: pop and return top value from stack */
double pop(void)
{
    if (sp > 0)
        return val[--sp];
    else {
        printf("error: stack empty\n");
        return 0.0;
    }
}

 


 menonsahab's
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define MAXVAL 100
int sp = 0;
double val[MAXVAL];

void push(double f)
{
 if(sp < MAXVAL)
  val[sp++] = f;
 else
  printf("error: stack full, can't push %g\n", f);
}

double pop(void)
{
 if(sp > 0)
  return val[--sp];
 else
 {
  printf("error: stack empty\n");
  return 0.0;
 }
}

int main(int argc, char *argv[])
{
 int i, c, op2;
 char *p;
 for(i = 1; i < argc; i++)
 {
  p = argv[i];
  printf("argv[%d] = %s\n", i, argv[i]);
  while(*p && isdigit(*p))
   p++;
  printf("*p = %d, %c\n", *p, *p);
  switch(*p)
  {
   case '\0':
    push(atoi(argv[i]));
    break;
   case '+':
    push(pop() + pop());
    break;
   case '-':
    op2 = pop();
    push(pop() - op2);
    break;
   case 'x':
    push(pop() * pop());
    break;
   case '/':
    op2 = pop();
    if(op2 != 0.0)
     push(pop() / op2);
    else
     printf("error: zero divisor\n");
    break;
  }
 }
 printf("Final result = %lf\n", pop());
 return 0;
}

/*
I noticed that the program was giving weird results when I was
using the multiplication symbol '*' as a command line input.
I couldn't figure out why that was happening so now I'm just
using the 'x' symbol to denote multiplication.
I even ran the other two solutions on this page but to no avail.
*/

/*
On running:
expr 2 3 4 + x
the output is:
Final result = 14.000000
*/