diff options
-rw-r--r-- | cmds.c | 52 | ||||
-rw-r--r-- | cmds.h | 2 | ||||
-rw-r--r-- | main.c | 100 |
3 files changed, 92 insertions, 62 deletions
diff --git a/cmds.c b/cmds.c index 30772fb..da5720b 100644 --- a/cmds.c +++ b/cmds.c @@ -67,7 +67,42 @@ stack fcos(stack stack) { return stack; } +stack fadd(stack stack) { + PREV = LAST + PREV; + REDUCE; + return stack; +} + +stack fsub(stack stack) { + PREV = PREV - LAST; + REDUCE; + return stack; +} + +stack fmul(stack stack) { + PREV = PREV*LAST; + REDUCE; + return stack; +} + +stack fdiv(stack stack) { + PREV = PREV / LAST; + REDUCE; + return stack; +} + +stack fpow(stack stack) { + PREV = pow(PREV, LAST); + REDUCE; + return stack; +} + command CMD_LIST[] = { + {"*", &fmul, "multiply last two numbers", 2}, + {"+", &fadd, "add last two numbers", 2}, + {"-", &fsub, "substract last two numbers", 2}, + {"/", &fdiv, "divide last two numbers", 2}, + {"^", &fpow, "power last two numbers", 2}, {"ceil", &fceil, "truncate to the next integer", 1}, {"cos", &fcos, "calculate the cosine", 1}, {"e", &fe, "return number e", 0}, @@ -100,17 +135,22 @@ void init_state(state *s) { s->sorted = CMD_LIST; } -void exec(char *buf, state *s) { +/* +exec tries to find a function name matching the one provided in buf. If it +fails to find one, it returns -2. If it finds one, but number of arguments in +the stack is less than the specified limit, it returns the number of arguments +needed. If it succeeds, it returns -1, in order not to conflict with the integer +returned when an incorrect number of arguments have been passed. +*/ +int exec(char *buf, state *s) { command *c = bsearch(&buf, s->sorted, s->numel, sizeof(s->sorted[0]), search); if (c == NULL) { - fprintf(s->defout, "error: function '%s' not found\n", buf); - return; + return -2; // not found } if (c->required_args > s->stk.count) { - fprintf(s->defout,"this function requires %d arguments\n", c->required_args); - return; + return c->required_args; // return number of required arguments } fprintf(s->defout, "executing function: %s\n", c->name); s->stk = c->exec(s->stk); - + return -1; // no error } diff --git a/cmds.h b/cmds.h index 78a1c13..5951148 100644 --- a/cmds.h +++ b/cmds.h @@ -6,6 +6,6 @@ extern command CMD_LIST[]; void init_state(state *s); -void exec(char *buf, state *s); +int exec(char *buf, state *s); #endif diff --git a/main.c b/main.c index 2b79001..09fc6ab 100644 --- a/main.c +++ b/main.c @@ -1,12 +1,13 @@ -#include <math.h> -#include <stdio.h> +#include "cmds.h" #include "state.h" #include "util.h" -#include <stdlib.h> -#include <string.h> -#include "cmds.h" +#include <ctype.h> #include <err.h> #include <errno.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #define BUF_SIZE 50 @@ -27,76 +28,65 @@ int main() { s.command_count = 0; init_state(&s); + fprintf(s.defout, "welcome to rpncalc! type 'list' to see a list of " + "commands, or 'quit' to leave.\n"); - fprintf(s.defout,"welcome to rpncalc! type 'list' to see a list of commands, or 'quit' to leave.\n"); - - /* start reading from defbuf */ char buf[BUF_SIZE]; - while(1){ + while (1) { + int execval = 0; + /* prompt the user for input */ fprintf(s.defout, s.prompt, s.command_count, s.last_op); s.last_op = 0; char *endptr = NULL; + /* get input */ char *check = fgets(buf, BUF_SIZE, s.defbuf); - if (check == NULL) exit(0); + if (check == NULL) + exit(0); + /* strip newline */ buf[strcspn(buf, "\n")] = 0; + /* parse input as a number */ double interpreted = strtod(buf, &endptr); if (errno == ERANGE) { - fprintf(s.defout,"sorry, this number is too big\n"); + fprintf(s.defout, "sorry, this number is too big\n"); continue; } - if (interpreted == (double)0 && endptr == buf) { /* strtod returned the char it could not read */ - TYPE t = discriminate(buf); - if (t == OPERATOR ) { - if (s.stk.count <= 1) { - fprintf(s.defout, "not enough arguments\n"); - continue; - } - char operator = buf[0]; - if (operator == '+') { - s.stk.val[s.stk.count-2] = s.stk.val[s.stk.count-1]+s.stk.val[s.stk.count-2]; - s.stk.val[s.stk.count--] = 0; /* lower count by 1 */ - s.last_op = '+'; - } else if (operator == '-') { - s.stk.val[s.stk.count-2] = s.stk.val[s.stk.count-2]-s.stk.val[s.stk.count-1]; - s.stk.val[s.stk.count--] = 0; /* lower count by 1 */ - s.last_op = '-'; - } else if (operator == '*') { - s.stk.val[s.stk.count-2] = s.stk.val[s.stk.count-2]*s.stk.val[s.stk.count-1]; - s.stk.val[s.stk.count--] = 0; /* lower count by 1 */ - s.last_op = '*'; - } else if (operator == '/') { - s.stk.val[s.stk.count-2] = s.stk.val[s.stk.count-2]/s.stk.val[s.stk.count-1]; - s.stk.val[s.stk.count--] = 0; /* lower count by 1 */ - s.last_op = '/'; - } else if (operator == '^') { - s.stk.val[s.stk.count-2] = pow(s.stk.val[s.stk.count-2],s.stk.val[s.stk.count-1]); - s.stk.val[s.stk.count--] = 0; /* lower count by 1 */ - s.last_op = '^'; - } else; - } else if (t == FUNCTION) { - /* check for special commands, else pass to exec() */ - if (strcmp(buf, "quit") == 0) { - fprintf(s.defout, "quitting, bye!\n"); - exit(0); - } else if (strcmp(buf, "list") == 0) { - for (int i = 0; i < s.numel; i++) { - fprintf(s.defout, "[%s]\t->\t%s\n", s.sorted[i].name, s.sorted[i].description); - } - continue; - } else exec(buf, &s); + /* special functions, quit and list, that do not interact with the stack directly */ + if (strcmp(buf, "quit") == 0) { + fprintf(s.defout, "quitting, bye!\n"); + exit(0); + } else if (strcmp(buf, "list") == 0) { + for (int i = 0; i < s.numel; i++) { + fprintf(s.defout, "[%s]\t->\t%s\n", s.sorted[i].name, + s.sorted[i].description); + } + continue; + } else if ((execval = exec(buf, &s)) == -1 || execval > 0) { /* try to execute a known function. + if we fail, we either catch an + incorrect number of arguments + error, or we pass it to the next + else clause.*/ + if (execval > 0) { + fprintf(s.defout, "this function requires %d arguments\n", execval); + continue; } } else { /* we found a number */ - if (s.stk.count == STACK_SIZE - 1) { - fprintf(s.defout, "exceeded stack size %d\n", STACK_SIZE); + /* test if provided input could not be parsed by strtod, in this case we are not against + a number, so error out */ + if (endptr == buf) { + fprintf(s.defout, "function %s not found\n", buf); continue; } + if (s.stk.count == STACK_SIZE - 1) { + fprintf(s.defout, "exceeded stack size %d\n", STACK_SIZE); + continue; + } s.stk.val[s.stk.count++] = interpreted; } - + /* add one to the command count, and print the updated stack */ s.command_count++; for (int i = 0; i < s.stk.count; i++) { - fprintf(s.defout,"%d → %f\n",i, s.stk.val[i]); + fprintf(s.defout, "%d → %f\n", i, s.stk.val[i]); } } } |