aboutsummaryrefslogtreecommitdiff
path: root/ch5
diff options
context:
space:
mode:
authorzlg <zlg@zlg.space>2013-09-24 08:33:37 -0500
committerzlg <zlg@zlg.space>2013-09-24 08:33:37 -0500
commitb4d63aa4acb84c9bb71f6b4cd62de0560a0b3f84 (patch)
tree0b2ba75bea8ec4df517facfbd48242dfa456f8fd /ch5
parentSolve Exercise 5-9: day of year functions with pointers (diff)
downloadknr-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.c107
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;
+ }
+}