Skip to content

Instantly share code, notes, and snippets.

@guipn
Last active December 14, 2015 17:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save guipn/5122682 to your computer and use it in GitHub Desktop.
Save guipn/5122682 to your computer and use it in GitHub Desktop.
A monolithic, simple RPN calculator with a decent structure.
/* 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