summaryrefslogtreecommitdiff
path: root/math.c
diff options
context:
space:
mode:
Diffstat (limited to 'math.c')
-rw-r--r--math.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/math.c b/math.c
new file mode 100644
index 0000000..5c1560a
--- /dev/null
+++ b/math.c
@@ -0,0 +1,149 @@
+#include "internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
+
+const char math_usage[] = "math expression ...";
+
+static double stack[100];
+static unsigned int pointer;
+
+static void
+push(double a)
+{
+ if ( pointer >= (sizeof(stack) / sizeof(*stack)) ) {
+ fprintf(stderr, "math: stack overflow\n");
+ exit(-1);
+ }
+ else
+ stack[pointer++] = a;
+}
+
+static double
+pop()
+{
+ if ( pointer == 0 ) {
+ fprintf(stderr, "math: stack underflow\n");
+ exit(-1);
+ }
+ return stack[--pointer];
+}
+
+static void
+add()
+{
+ push(pop() + pop());
+}
+
+static void
+sub()
+{
+ double subtrahend = pop();
+
+ push(pop() - subtrahend);
+}
+
+static void
+mul()
+{
+ push(pop() * pop());
+}
+
+static void
+divide()
+{
+ double divisor = pop();
+ push(pop() / divisor);
+}
+
+static void
+and()
+{
+ push((unsigned int)pop() & (unsigned int)pop());
+}
+
+static void
+or()
+{
+ push((unsigned int)pop() | (unsigned int)pop());
+}
+
+static void
+eor()
+{
+ push((unsigned int)pop() ^ (unsigned int)pop());
+}
+
+static void
+not()
+{
+ push(~(unsigned int)pop());
+}
+
+static void
+print()
+{
+ printf("%g\n", pop());
+}
+
+struct op {
+ const char * name;
+ void (*function)();
+};
+
+static const struct op operators[] = {
+ { "add", add },
+ { "and", and },
+ { "div", divide },
+ { "eor", eor },
+ { "mul", mul },
+ { "not", not },
+ { "or", or },
+ { "sub", sub },
+ { 0, 0 }
+};
+
+static void
+stack_machine(const char * argument)
+{
+ char * endPointer = 0;
+ double d;
+ const struct op * o = operators;
+
+ if ( argument == 0 ) {
+ print();
+ return;
+ }
+
+ d = strtod(argument, &endPointer);
+
+ if ( endPointer != argument ) {
+ push(d);
+ return;
+ }
+
+ while ( o->name != 0 ) {
+ if ( strcmp(o->name, argument) == 0 ) {
+ (*(o->function))();
+ return;
+ }
+ o++;
+ }
+ fprintf(stderr, "math: %s: syntax error.\n", argument);
+ exit(-1);
+}
+
+int
+math_main(struct FileInfo * i, int argc, char * * argv)
+{
+ while ( argc >= 2 ) {
+ stack_machine(argv[1]);
+ argv++;
+ argc--;
+ }
+ stack_machine(0);
+ return 0;
+}