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]);
}
}
}
|