Created
May 10, 2022 13:22
-
-
Save Colouratura/f381a7d41f70c7a7c5fbce4c0dc348dc to your computer and use it in GitHub Desktop.
A simple RPN calculator in C
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
#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