diff options
author | zlg <zlg@zlg.space> | 2013-09-24 08:33:37 -0500 |
---|---|---|
committer | zlg <zlg@zlg.space> | 2013-09-24 08:33:37 -0500 |
commit | b4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84 (patch) | |
tree | 0b2ba75bea8ec4df517facfbd48242dfa456f8fd /ch5 | |
parent | Solve Exercise 5-9: day of year functions with pointers (diff) | |
download | knr-b4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84.tar.gz knr-b4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84.tar.bz2 knr-b4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84.tar.xz knr-b4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84.zip |
Solve Exercise 5-10: expr
Diffstat (limited to 'ch5')
-rw-r--r-- | ch5/5-10_expr.c | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/ch5/5-10_expr.c b/ch5/5-10_expr.c new file mode 100644 index 0000000..08b143a --- /dev/null +++ b/ch5/5-10_expr.c @@ -0,0 +1,107 @@ +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +/* The C Programming Language: 2nd Edition + * + * Exercise 5-10: Write the program expr, which evaluates a reverse Polish + * expression from the command line, where each operator or operand is a + * separate argument. For example: + * + * expr 2 3 4 + * + * + * evaluates 2 × (3+4). + */ + +#define STACKSIZE 100 +#define NUMBER '0' + +double stack[STACKSIZE]; +double *stp = stack; // stack pointer + +void push(double); +double pop(void); + +/* This solution only offers basic arithmetic as proof of concept. See + * Chapter 4's exercises on how to extend this to a fully featured + * calculator. Note that for most shells, you'll need to escape the + * multiplication symbol (*) or it will expand to every file in the current + * directory; NOT what you want in this situation. :) + * + * So if you want 6 × 8 for example, you'll need to type `6 8 \*` + */ +int main(int argc, char *argv[]) { + int argp; // current argument position + double op2; + for (argp = 1; argp < argc; argp++) { + printf("checking arg: %s\n", argv[argp]); + int argtype = opt_type(argv[argp]); + switch(argtype) { + case '*': + push(pop() * pop()); + break; + case '+': + push(pop() + pop()); + break; + case '-': + op2 = pop(); + push(pop() - op2); + break; + case '/': + op2 = pop(); + if (op2 != 0.0) { + push(pop() / op2); + } else { + printf("error: divide by zero\n"); + } + break; + case NUMBER: + printf("it's a number\n"); + push(atof(argv[argp])); + break; + } + printf("%s\n", argv[argp]); + } + printf("%f\n", pop()); +} + +void push(double num) { + if (stp >= stack + STACKSIZE) { + printf("Cannot push: stack full.\n"); + return; + } + printf("add %f to stack.\n", num); + *(++stp) = num; +} + +double pop(void) { + if (stp == stack) { + printf("Cannot pop: stack empty.\n"); + return 0.0; + } + return *(stp--); +} + +int opt_type(char op[]) { + int i = 0; + switch(op[i]) { + case '*': + return '*'; + case '+': + return '+'; + case '/': + return '/'; + case '-': + if (op[i+1] == '\0') { + return '-'; + } + break; + } + + while (isdigit(op[i])) { + i++; + } + if (op[i] == '\0') { + return NUMBER; + } +} |