Skip to main content
Became Hot Network Question
Tweeted twitter.com/StackCodeReview/status/1571197310679252996
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
Source Link

K&R Exercise 5-10. reverse Polish calculator

I have been learning C with K&R Book 2nd Ed. And well, so far I've gotten to chapter five, and I've been dealing with pointers/command line arguments.

I came up with the following solution for the exercise (Chapter 5, Ex-5.10):

Exercise 5-10. 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).

I would like to know how to improve it.:

/*-
 *  Exercise 5-10. 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).
 *
 *  By jr.chavez
 *
 *  NOTE:
 *      To receive the expected output with the following example:
 *          2 3 4 + *
 *      '\' must be used (e.g., 2 3 4 + \* instead of *)
 */
#include <stdio.h>
#include <stdlib.h> /* for atof() */
#include <string.h> /* for strlen() */
#include <ctype.h>  /* for isdigit() */

#define NUMBER  '0'     /* signal that a number was found */
#define MAXVAL  100     /* next free stack position */

static int sp = 0;      /* next free stack position */
static double val[MAXVAL];  /* value stack */

void push(double);
double pop(void);

/* reverse Polish calculator */
int
main(int argc, char *argv[])
{
    int type, c;
    double op2;
    
    while (--argc > 0) {
        {
            char *p = *++argv;
            type = (!isdigit(c = *p) && strlen(p) == 1) ? c : 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
                fprintf(stderr, "error: zero divisor\n");
            break;
        default:
            fprintf(stderr, "error: unkown command %s\n", *argv);
            argc = 1;
            break;
        }
    }
    printf("\t%.8g\n", pop()); 
    return 0;
}


/* push: push f onto value stack */
void
push(double f)
{
    if (sp < MAXVAL)
        val[sp++] = f;
    else
        fprintf(stderr, "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 {
        fprintf(stderr, "error: empty stack\n");
        return 0.0;
    }
}

input:

./bin/main 2 3 4 + \*

output:

14

Note: I decided not to add options like sin, cos, exp, and pow.