blob: 18af3534aadaaa28f9bb9e6d5104be0ff9c474ee [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 Andersen7ab9c7e2000-05-12 19:41:47 +000010static 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 Andersen5e1189e2000-04-15 16:34:54 +000013 "following operations: +, -, /, *, and, or, not, eor.\n"
Erik Andersen7ab9c7e2000-05-12 19:41:47 +000014 "i.e. 'math 2 2 add' -> 4, and 'math 8 8 \\* 2 2 + /' -> 16\n"
15#endif
16 ;
Eric Andersencc8ed391999-10-05 16:24:54 +000017
Erik Andersene49d5ec2000-02-08 19:58:47 +000018static double stack[100];
19static unsigned int pointer;
Eric Andersencc8ed391999-10-05 16:24:54 +000020
Erik Andersene49d5ec2000-02-08 19:58:47 +000021static void push(double a)
Eric Andersencc8ed391999-10-05 16:24:54 +000022{
Erik Andersene49d5ec2000-02-08 19:58:47 +000023 if (pointer >= (sizeof(stack) / sizeof(*stack))) {
Eric Andersencc8ed391999-10-05 16:24:54 +000024 fprintf(stderr, "math: stack overflow\n");
25 exit(-1);
Erik Andersene49d5ec2000-02-08 19:58:47 +000026 } else
Eric Andersencc8ed391999-10-05 16:24:54 +000027 stack[pointer++] = a;
28}
29
Erik Andersene49d5ec2000-02-08 19:58:47 +000030static double pop()
Eric Andersencc8ed391999-10-05 16:24:54 +000031{
Erik Andersene49d5ec2000-02-08 19:58:47 +000032 if (pointer == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +000033 fprintf(stderr, "math: stack underflow\n");
34 exit(-1);
35 }
36 return stack[--pointer];
37}
38
Erik Andersene49d5ec2000-02-08 19:58:47 +000039static void add()
Eric Andersencc8ed391999-10-05 16:24:54 +000040{
41 push(pop() + pop());
42}
43
Erik Andersene49d5ec2000-02-08 19:58:47 +000044static void sub()
Eric Andersencc8ed391999-10-05 16:24:54 +000045{
Erik Andersene49d5ec2000-02-08 19:58:47 +000046 double subtrahend = pop();
Eric Andersencc8ed391999-10-05 16:24:54 +000047
48 push(pop() - subtrahend);
49}
50
Erik Andersene49d5ec2000-02-08 19:58:47 +000051static void mul()
Eric Andersencc8ed391999-10-05 16:24:54 +000052{
53 push(pop() * pop());
54}
55
Erik Andersene49d5ec2000-02-08 19:58:47 +000056static void divide()
Eric Andersencc8ed391999-10-05 16:24:54 +000057{
Erik Andersene49d5ec2000-02-08 19:58:47 +000058 double divisor = pop();
59
Eric Andersencc8ed391999-10-05 16:24:54 +000060 push(pop() / divisor);
61}
62
Erik Andersene49d5ec2000-02-08 19:58:47 +000063static void and()
Eric Andersencc8ed391999-10-05 16:24:54 +000064{
Erik Andersene49d5ec2000-02-08 19:58:47 +000065 push((unsigned int) pop() & (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000066}
67
Erik Andersene49d5ec2000-02-08 19:58:47 +000068static void or()
Eric Andersencc8ed391999-10-05 16:24:54 +000069{
Erik Andersene49d5ec2000-02-08 19:58:47 +000070 push((unsigned int) pop() | (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000071}
72
Erik Andersene49d5ec2000-02-08 19:58:47 +000073static void eor()
Eric Andersencc8ed391999-10-05 16:24:54 +000074{
Erik Andersene49d5ec2000-02-08 19:58:47 +000075 push((unsigned int) pop() ^ (unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000076}
77
Erik Andersene49d5ec2000-02-08 19:58:47 +000078static void not()
Eric Andersencc8ed391999-10-05 16:24:54 +000079{
Erik Andersene49d5ec2000-02-08 19:58:47 +000080 push(~(unsigned int) pop());
Eric Andersencc8ed391999-10-05 16:24:54 +000081}
82
Erik Andersene49d5ec2000-02-08 19:58:47 +000083static void print()
Eric Andersencc8ed391999-10-05 16:24:54 +000084{
85 printf("%g\n", pop());
86}
87
88struct op {
Erik Andersene49d5ec2000-02-08 19:58:47 +000089 const char *name;
90 void (*function) ();
Eric Andersencc8ed391999-10-05 16:24:54 +000091};
92
Erik Andersene49d5ec2000-02-08 19:58:47 +000093static const struct op operators[] = {
Erik Andersen5e1189e2000-04-15 16:34:54 +000094 {"+", add},
95 {"-", sub},
96 {"*", mul},
97 {"/", divide},
Erik Andersene49d5ec2000-02-08 19:58:47 +000098 {"and", and},
Erik Andersene49d5ec2000-02-08 19:58:47 +000099 {"or", or},
Erik Andersen5e1189e2000-04-15 16:34:54 +0000100 {"not", not},
101 {"eor", eor},
Erik Andersene49d5ec2000-02-08 19:58:47 +0000102 {0, 0}
Eric Andersencc8ed391999-10-05 16:24:54 +0000103};
104
Erik Andersene49d5ec2000-02-08 19:58:47 +0000105static void stack_machine(const char *argument)
Eric Andersencc8ed391999-10-05 16:24:54 +0000106{
Erik Andersene49d5ec2000-02-08 19:58:47 +0000107 char *endPointer = 0;
108 double d;
109 const struct op *o = operators;
Eric Andersencc8ed391999-10-05 16:24:54 +0000110
Erik Andersene49d5ec2000-02-08 19:58:47 +0000111 if (argument == 0) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000112 print();
113 return;
114 }
115
116 d = strtod(argument, &endPointer);
117
Erik Andersene49d5ec2000-02-08 19:58:47 +0000118 if (endPointer != argument) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000119 push(d);
120 return;
121 }
122
Erik Andersene49d5ec2000-02-08 19:58:47 +0000123 while (o->name != 0) {
124 if (strcmp(o->name, argument) == 0) {
125 (*(o->function)) ();
Eric Andersencc8ed391999-10-05 16:24:54 +0000126 return;
127 }
128 o++;
129 }
130 fprintf(stderr, "math: %s: syntax error.\n", argument);
131 exit(-1);
132}
133
Erik Andersene49d5ec2000-02-08 19:58:47 +0000134int math_main(int argc, char **argv)
Eric Andersencc8ed391999-10-05 16:24:54 +0000135{
John Beppu53642b02000-04-16 10:55:27 +0000136 if (argc <= 1 || *argv[1]=='-')
Erik Andersen5e1189e2000-04-15 16:34:54 +0000137 usage(math_usage);
Erik Andersene49d5ec2000-02-08 19:58:47 +0000138 while (argc >= 2) {
Eric Andersencc8ed391999-10-05 16:24:54 +0000139 stack_machine(argv[1]);
140 argv++;
141 argc--;
142 }
143 stack_machine(0);
Erik Andersen5e1189e2000-04-15 16:34:54 +0000144 exit( TRUE);
Eric Andersencc8ed391999-10-05 16:24:54 +0000145}