Last active
December 14, 2015 17:29
-
-
Save guipn/5122682 to your computer and use it in GitHub Desktop.
A monolithic, simple RPN calculator with a decent structure.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* An extensible RPN calculator. | |
* gcc -std=c99 -Wall -Wextra -pedantic rpn.c -o rpn | |
* | |
* example: ./rpn 10 20 / 2 "*" -> 1.00 | |
*/ | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <string.h> | |
static void groan(const char *what) | |
{ | |
fprintf(stderr, "\n RPN Error: %s\n", what); | |
exit(EXIT_FAILURE); | |
} | |
struct stack | |
{ | |
int i, size; | |
double *values; | |
}; | |
static double pop(struct stack *st) | |
{ | |
if (st->i < 0) | |
{ | |
groan("Stack underflow."); | |
} | |
st->i--; | |
return st->values[st->i + 1]; | |
} | |
static double push(struct stack *st, double value) | |
{ | |
if (st->i == st->size) | |
{ | |
groan("Stack overflow."); | |
} | |
st->i++; | |
st->values[st->i] = value; | |
return value; | |
} | |
static struct stack *make(size_t size) | |
{ | |
struct stack *s = malloc(sizeof *s); | |
if (!s) | |
{ | |
groan("Could not allocate a new stack."); | |
} | |
s->values = malloc(size * sizeof *s->values); | |
if (!s->values) | |
{ | |
free(s); | |
groan("No space left for the stack's values."); | |
} | |
s->i = -1; | |
s->size = size; | |
return s; | |
} | |
static void kill(struct stack *s) | |
{ | |
free(s->values); | |
free(s); | |
} | |
struct op | |
{ | |
char *name; | |
double (*apply)(struct stack *); | |
}; | |
struct op fetch(struct op *operations, size_t size, const char *name) | |
{ | |
for (size_t i = 0; i < size; i++) | |
{ | |
size_t op_name_len = strlen(operations[i].name), | |
target_len = strlen(name), | |
min = (op_name_len > target_len) ? target_len : op_name_len; | |
if (strncmp(name, operations[i].name, min) == 0) | |
{ | |
return operations[i]; | |
} | |
} | |
groan("Bad operator."); | |
return (struct op) { "Unknown", NULL }; | |
} | |
static double add(struct stack *st) | |
{ | |
return pop(st) + pop(st); | |
} | |
static double subtract(struct stack *st) | |
{ | |
double one = pop(st), | |
other = pop(st); | |
return other - one; | |
} | |
static double multiply(struct stack *st) | |
{ | |
return pop(st) * pop(st); | |
} | |
static double divide(struct stack *st) | |
{ | |
double one = pop(st), | |
other = pop(st); | |
return other / one; | |
} | |
static double sum(struct stack *st) | |
{ | |
double result = 0.0; | |
do | |
{ | |
result += pop(st); | |
} while (st->i != -1); | |
return result; | |
} | |
static void print_stack(struct stack *st) | |
{ | |
while (st->i) | |
{ | |
printf("\n%.2F", pop(st)); | |
} | |
printf("\n%.2F\n\n", pop(st)); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
if (argc < 2) | |
{ | |
groan("I need arguments."); | |
} | |
struct stack *calc = make(argc); | |
struct op operations[] = { | |
{ "+", add }, | |
{ "-", subtract }, | |
{ "*", multiply }, | |
{ "/", divide }, | |
{ "sum", sum } | |
}; | |
size_t op_arr_size = sizeof operations / sizeof *operations; | |
for (int i = 1; i < calc->size; i++) | |
{ | |
char *endptr = argv[i]; | |
double try = strtod(argv[i], &endptr); | |
if (endptr == argv[i]) | |
{ | |
struct op operation = fetch(operations, op_arr_size, argv[i]); | |
push(calc, operation.apply(calc)); | |
} | |
else | |
{ | |
push(calc, try); | |
} | |
} | |
print_stack(calc); | |
kill(calc); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment