Page 118

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).

#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
#define MAX_OP_LEN 16

void push(float val);
float pop(void);
enum op_type { NUMBER, CHARACTER, INVALID };
enum op_type get_op_type(char *buf);

int main(int argc, char *argv[])
{
	while (--argc > 0) {
		switch (get_op_type(*++argv)) {
		case NUMBER:
			push(atof(*argv));
			break;
		case CHARACTER:
			switch (**argv) {
			case '+':
				push(pop() + pop());
				break;
			case '-':
				push(pop() - pop());
				break;
			case '*':
				push(pop() * pop());
				break;
			case '/':
				push(pop() / pop());
				break;
			}
			break;
		default:
			printf("Invalid argument '%s'", *argv);
			break;
		}
	}
	printf("%f\n", pop());
}

enum op_type get_op_type(char *buf)
{
	bool is_num =
		isdigit(*buf) || (*buf == '-' || *buf == '+' || *buf == '.') &&
					 isdigit(*(buf + 1));

	if (is_num) {
		for (; isdigit(*buf); buf++)
			;

		if (*buf == '\0') {
			return NUMBER;
		} else {
			return INVALID;
		}
	}

	if (*(buf + 1) != '\0') {
		return INVALID;
	}

	return CHARACTER;
}

#define MAX_BUF 16
static float buf[MAX_BUF];
static unsigned idx = 0;

void push(float val)
{
	if (idx < MAX_BUF) {
		buf[idx++] = val;
	} else {
		printf("error: buffer full\n");
	}
}

float pop(void)
{
	if (idx > 0) {
		return buf[--idx];
	} else {
		printf("error: buffer empty\n");
		return 0.0;
	}
}