Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 2 | #include "internal.h" |
| 3 | #include <stdio.h> |
| 4 | #include <stdlib.h> |
| 5 | #include <unistd.h> |
| 6 | #include <math.h> |
| 7 | |
| 8 | /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ |
| 9 | |
Erik Andersen | 7ab9c7e | 2000-05-12 19:41:47 +0000 | [diff] [blame] | 10 | static const char math_usage[] = "math expression ...\n" |
| 11 | #ifndef BB_FEATURE_TRIVIAL_HELP |
| 12 | "\nThis is a Tiny RPN calculator that understands the\n" |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 13 | "following operations: +, -, /, *, and, or, not, eor.\n" |
Erik Andersen | 7ab9c7e | 2000-05-12 19:41:47 +0000 | [diff] [blame] | 14 | "i.e. 'math 2 2 add' -> 4, and 'math 8 8 \\* 2 2 + /' -> 16\n" |
| 15 | #endif |
| 16 | ; |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 17 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 18 | static double stack[100]; |
| 19 | static unsigned int pointer; |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 20 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 21 | static void push(double a) |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 22 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 23 | if (pointer >= (sizeof(stack) / sizeof(*stack))) { |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 24 | fprintf(stderr, "math: stack overflow\n"); |
| 25 | exit(-1); |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 26 | } else |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 27 | stack[pointer++] = a; |
| 28 | } |
| 29 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 30 | static double pop() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 31 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 32 | if (pointer == 0) { |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 33 | fprintf(stderr, "math: stack underflow\n"); |
| 34 | exit(-1); |
| 35 | } |
| 36 | return stack[--pointer]; |
| 37 | } |
| 38 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 39 | static void add() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 40 | { |
| 41 | push(pop() + pop()); |
| 42 | } |
| 43 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 44 | static void sub() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 45 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 46 | double subtrahend = pop(); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 47 | |
| 48 | push(pop() - subtrahend); |
| 49 | } |
| 50 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 51 | static void mul() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 52 | { |
| 53 | push(pop() * pop()); |
| 54 | } |
| 55 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 56 | static void divide() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 57 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 58 | double divisor = pop(); |
| 59 | |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 60 | push(pop() / divisor); |
| 61 | } |
| 62 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 63 | static void and() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 64 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 65 | push((unsigned int) pop() & (unsigned int) pop()); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 66 | } |
| 67 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 68 | static void or() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 69 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 70 | push((unsigned int) pop() | (unsigned int) pop()); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 71 | } |
| 72 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 73 | static void eor() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 74 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 75 | push((unsigned int) pop() ^ (unsigned int) pop()); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 76 | } |
| 77 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 78 | static void not() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 79 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 80 | push(~(unsigned int) pop()); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 81 | } |
| 82 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 83 | static void print() |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 84 | { |
| 85 | printf("%g\n", pop()); |
| 86 | } |
| 87 | |
| 88 | struct op { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 89 | const char *name; |
| 90 | void (*function) (); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 91 | }; |
| 92 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 93 | static const struct op operators[] = { |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 94 | {"+", add}, |
| 95 | {"-", sub}, |
| 96 | {"*", mul}, |
| 97 | {"/", divide}, |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 98 | {"and", and}, |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 99 | {"or", or}, |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 100 | {"not", not}, |
| 101 | {"eor", eor}, |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 102 | {0, 0} |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 103 | }; |
| 104 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 105 | static void stack_machine(const char *argument) |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 106 | { |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 107 | char *endPointer = 0; |
| 108 | double d; |
| 109 | const struct op *o = operators; |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 110 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 111 | if (argument == 0) { |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 112 | print(); |
| 113 | return; |
| 114 | } |
| 115 | |
| 116 | d = strtod(argument, &endPointer); |
| 117 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 118 | if (endPointer != argument) { |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 119 | push(d); |
| 120 | return; |
| 121 | } |
| 122 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 123 | while (o->name != 0) { |
| 124 | if (strcmp(o->name, argument) == 0) { |
| 125 | (*(o->function)) (); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 126 | return; |
| 127 | } |
| 128 | o++; |
| 129 | } |
| 130 | fprintf(stderr, "math: %s: syntax error.\n", argument); |
| 131 | exit(-1); |
| 132 | } |
| 133 | |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 134 | int math_main(int argc, char **argv) |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 135 | { |
John Beppu | 53642b0 | 2000-04-16 10:55:27 +0000 | [diff] [blame] | 136 | if (argc <= 1 || *argv[1]=='-') |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 137 | usage(math_usage); |
Erik Andersen | e49d5ec | 2000-02-08 19:58:47 +0000 | [diff] [blame] | 138 | while (argc >= 2) { |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 139 | stack_machine(argv[1]); |
| 140 | argv++; |
| 141 | argc--; |
| 142 | } |
| 143 | stack_machine(0); |
Erik Andersen | 5e1189e | 2000-04-15 16:34:54 +0000 | [diff] [blame] | 144 | exit( TRUE); |
Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 145 | } |