blob: 96afafdef23f5ac7f57026114714ea557b3df214 [file] [log] [blame]
Erik Andersene49d5ec2000-02-08 19:58:47 +00001/* vi: set sw=4 ts=4: */
Eric Andersencc8ed391999-10-05 16:24:54 +00002#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 Andersen5e1189e2000-04-15 16:34:54 +000010static const char math_usage[] = "math expression ...\n\n"
11 "This is a Tiny RPN calculator that understands the\n"
12 "following operations: +, -, /, *, and, or, not, eor.\n"
13 "i.e. 'math 2 2 add' -> 4, and 'math 8 8 \\* 2 2 + /' -> 16\n";
Eric Andersencc8ed391999-10-05 16:24:54 +000014
Erik Andersene49d5ec2000-02-08 19:58:47 +000015static double stack[100];
16static unsigned int pointer;
Eric Andersencc8ed391999-10-05 16:24:54 +000017
Erik Andersene49d5ec2000-02-08 19:58:47 +000018static void push(double a)
Eric Andersencc8ed391999-10-05 16:24:54 +000019{
Erik Andersene49d5ec2000-02-08 19:58:47 +000020 if (pointer >= (sizeof(stack) / sizeof(*stack))) {
Eric Andersencc8ed391999-10-05 16:24:54 +000021 fprintf(stderr, "math: stack overflow\n");
22 exit(-1);
Erik Andersene49d5ec2000-02-08 19:58:47 +000023 } else
Eric Andersencc8ed391999-10-05 16:24:54 +000024 stack[pointer++] = a;
25}
26
Erik Andersene49d5ec2000-02-08 19:58:47 +000027static double pop()
Eric Andersencc8ed391999-10-05 16:24:54 +000028{
Erik Andersene49d5ec2000-02-08 19:58:47 +000029 if (pointer == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +000030 fprintf(stderr, "math: stack underflow\n");
31 exit(-1);
32 }
33 return stack[--pointer];
34}
35
Erik Andersene49d5ec2000-02-08 19:58:47 +000036static void add()
Eric Andersencc8ed391999-10-05 16:24:54 +000037{
38 push(pop() + pop());
39}
40
Erik Andersene49d5ec2000-02-08 19:58:47 +000041static void sub()
Eric Andersencc8ed391999-10-05 16:24:54 +000042{
Erik Andersene49d5ec2000-02-08 19:58:47 +000043 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000044
45 push(pop() - subtrahend);
46}
47
Erik Andersene49d5ec2000-02-08 19:58:47 +000048static void mul()
Eric Andersencc8ed391999-10-05 16:24:54 +000049{
50 push(pop() * pop());
51}
52
Erik Andersene49d5ec2000-02-08 19:58:47 +000053static void divide()
Eric Andersencc8ed391999-10-05 16:24:54 +000054{
Erik Andersene49d5ec2000-02-08 19:58:47 +000055 double divisor = pop();
56
Eric Andersencc8ed391999-10-05 16:24:54 +000057 push(pop() / divisor);
58}
59
Erik Andersene49d5ec2000-02-08 19:58:47 +000060static void and()
Eric Andersencc8ed391999-10-05 16:24:54 +000061{
Erik Andersene49d5ec2000-02-08 19:58:47 +000062 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000063}
64
Erik Andersene49d5ec2000-02-08 19:58:47 +000065static void or()
Eric Andersencc8ed391999-10-05 16:24:54 +000066{
Erik Andersene49d5ec2000-02-08 19:58:47 +000067 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000068}
69
Erik Andersene49d5ec2000-02-08 19:58:47 +000070static void eor()
Eric Andersencc8ed391999-10-05 16:24:54 +000071{
Erik Andersene49d5ec2000-02-08 19:58:47 +000072 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000073}
74
Erik Andersene49d5ec2000-02-08 19:58:47 +000075static void not()
Eric Andersencc8ed391999-10-05 16:24:54 +000076{
Erik Andersene49d5ec2000-02-08 19:58:47 +000077 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000078}
79
Erik Andersene49d5ec2000-02-08 19:58:47 +000080static void print()
Eric Andersencc8ed391999-10-05 16:24:54 +000081{
82 printf("%g\n", pop());
83}
84
85struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +000086 const char *name;
87 void (*function) ();
Eric Andersencc8ed391999-10-05 16:24:54 +000088};
89
Erik Andersene49d5ec2000-02-08 19:58:47 +000090static const struct op operators[] = {
Erik Andersen5e1189e2000-04-15 16:34:54 +000091 {"+", add},
92 {"-", sub},
93 {"*", mul},
94 {"/", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +000095 {"and", and},
Erik Andersene49d5ec2000-02-08 19:58:47 +000096 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +000097 {"not", not},
98 {"eor", eor},
Erik Andersene49d5ec2000-02-08 19:58:47 +000099 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +0000100};
101
Erik Andersene49d5ec2000-02-08 19:58:47 +0000102static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +0000103{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000104 char *endPointer = 0;
105 double d;
106 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000107
Erik Andersene49d5ec2000-02-08 19:58:47 +0000108 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000109 print();
110 return;
111 }
112
113 d = strtod(argument, &endPointer);
114
Erik Andersene49d5ec2000-02-08 19:58:47 +0000115 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000116 push(d);
117 return;
118 }
119
Erik Andersene49d5ec2000-02-08 19:58:47 +0000120 while (o->name != 0) {
121 if (strcmp(o->name, argument) == 0) {
122 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000123 return;
124 }
125 o++;
126 }
127 fprintf(stderr, "math: %s: syntax error.\n", argument);
128 exit(-1);
129}
130
Erik Andersene49d5ec2000-02-08 19:58:47 +0000131int math_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000132{
John Beppu53642b02000-04-16 10:55:27 +0000133 if (argc <= 1 || *argv[1]=='-')
Erik Andersen5e1189e2000-04-15 16:34:54 +0000134 usage(math_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000135 while (argc >= 2) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000136 stack_machine(argv[1]);
137 argv++;
138 argc--;
139 }
140 stack_machine(0);
Erik Andersen5e1189e2000-04-15 16:34:54 +0000141 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000142}