Skip to content

Instantly share code, notes, and snippets.

@Colouratura
Created May 10, 2022 13:22
Show Gist options
  • Save Colouratura/f381a7d41f70c7a7c5fbce4c0dc348dc to your computer and use it in GitHub Desktop.
Save Colouratura/f381a7d41f70c7a7c5fbce4c0dc348dc to your computer and use it in GitHub Desktop.
A simple RPN calculator in C
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>
struct stack {
size_t size;
double *buff;
};
void repl();
bool process_input(char *line, size_t line_len, struct stack *stack);
void print_stack(struct stack *stack);
void print_help();
bool is_numeric(char *line, size_t line_len);
void push_double(char *line, size_t line_len, struct stack *stack);
void stack_push(double n, struct stack *stack);
double stack_pop(struct stack *stack);
void add(struct stack *stack);
void sub(struct stack *stack);
void mul(struct stack *stack);
void ddiv(struct stack *stack);
void rem(struct stack *stack);
int main(int argc, char **argv) {
printf("cal (v0.0.1) - press q to exit or h for help.\n");
repl();
return 0;
}
void repl() {
bool run = true;
char *line = NULL;
size_t line_len = 0;
ssize_t read_bytes = 0;
struct stack *stack = malloc(sizeof(struct stack));;
stack->size = 4;
stack->buff = malloc(sizeof(double) * stack->size);
while (run) {
printf("> ");
read_bytes = getline(&line, &line_len, stdin);
if (read_bytes > 0) {
// trim newline before processing
line[strlen(line) - 1] = '\0';
line_len = strlen(line);
run = process_input(line, line_len, stack);
}
}
}
bool process_input(char *line, size_t line_len, struct stack *stack) {
char fc = line[0];
switch (fc) {
case 'q':
return false;
break;
case 'p':
print_stack(stack);
break;
case 'h':
print_help();
break;
case '+':
add(stack);
break;
case '-':
sub(stack);
break;
case '*':
mul(stack);
break;
case '/':
ddiv(stack);
break;
case '%':
rem(stack);
break;
default:
if (is_numeric(line, line_len)) {
push_double(line, line_len, stack);
} else {
printf("!\n");
}
break;
}
return true;
}
void print_stack(struct stack *stack) {
// print in reverse order
for (int i = stack->size - 1; i >= 0; i--) {
printf("[%d] = %.4f\n", i, stack->buff[i]);
}
}
void print_help() {
printf("\tq - Quit the calculator.\n");
printf("\th - Display this message.\n");
printf("\tp - Display the values on the stack.\n");
}
bool is_numeric(char *line, size_t line_len) {
const char allowed[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
const char decimal = '.';
// check for multiple decimals
int dec_count = 0;
for (int i = 0; i < line_len; i++) {
if (line[i] == decimal) {
dec_count++;
}
}
// only valid if there is 1 or none decimal
if (dec_count > 1) {
return false;
}
// check numeric
for (int i = 0; i < line_len; i++) {
bool is_num = false;
for (int j = 0; j < 10; j++) {
if (line[i] == allowed[j] || line[i] == decimal) {
is_num = true;
break;
}
}
// contains an invalid character
if (!is_num) {
return false;
}
}
return true;
}
void push_double(char *line, size_t line_len, struct stack *stack) {
char *eptr;
double result;
result = strtod(line, &eptr);
stack_push(result, stack);
}
void stack_push(double n, struct stack *stack) {
// to do: make this dynamic to stack size
stack->buff[3] = stack->buff[2];
stack->buff[2] = stack->buff[1];
stack->buff[1] = stack->buff[0];
stack->buff[0] = n;
}
double stack_pop(struct stack * stack) {
// to do: make this dynamic to stack size
double t = stack->buff[0];
stack->buff[0] = stack->buff[1];
stack->buff[1] = stack->buff[2];
stack->buff[2] = stack->buff[3];
stack->buff[3] = 0.0f;
return t;
}
void add(struct stack *stack) {
double b = stack_pop(stack);
double a = stack_pop(stack);
double res = a + b;
stack_push(res, stack);
printf("%.4f\n", res);
}
void sub(struct stack *stack) {
double b = stack_pop(stack);
double a = stack_pop(stack);
double res = a - b;
stack_push(res, stack);
printf("%.4f\n", res);
}
void mul(struct stack *stack) {
double b = stack_pop(stack);
double a = stack_pop(stack);
double res = a * b;
stack_push(res, stack);
printf("%.4f\n", res);
}
void ddiv(struct stack *stack) {
double b = stack_pop(stack);
double a = stack_pop(stack);
if (a == 0 || b == 0) {
printf("Error: cannot divide by 0!\n");
stack_push(b, stack);
stack_push(a, stack);
return;
}
double res = a / b;
stack_push(res, stack);
printf("%.4f\n", res);
}
void rem(struct stack *stack) {
double b = stack_pop(stack);
double a = stack_pop(stack);
if (a == 0 || b == 0) {
printf("Error: cannot take the remainder of 0!\n");
stack_push(a, stack);
stack_push(b, stack);
return;
}
double res = remainder(a, b);
stack_push(res, stack);
printf("%.4f\n", res);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment