diff options
Diffstat (limited to 'dc.c')
-rw-r--r-- | dc.c | 194 |
1 files changed, 194 insertions, 0 deletions
@@ -0,0 +1,194 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | #include "internal.h" | ||
3 | #include <ctype.h> | ||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <unistd.h> | ||
7 | #include <math.h> | ||
8 | |||
9 | /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ | ||
10 | |||
11 | static const char dc_usage[] = "math expression ...\n" | ||
12 | #ifndef BB_FEATURE_TRIVIAL_HELP | ||
13 | "\nThis is a Tiny RPN calculator that understands the\n" | ||
14 | "following operations: +, -, /, *, and, or, not, eor.\n" | ||
15 | "i.e. 'math 2 2 add' -> 4, and 'math 8 8 \\* 2 2 + /' -> 16\n" | ||
16 | #endif | ||
17 | ; | ||
18 | |||
19 | static double stack[100]; | ||
20 | static unsigned int pointer; | ||
21 | |||
22 | static void push(double a) | ||
23 | { | ||
24 | if (pointer >= (sizeof(stack) / sizeof(*stack))) { | ||
25 | fprintf(stderr, "math: stack overflow\n"); | ||
26 | exit(-1); | ||
27 | } else | ||
28 | stack[pointer++] = a; | ||
29 | } | ||
30 | |||
31 | static double pop() | ||
32 | { | ||
33 | if (pointer == 0) { | ||
34 | fprintf(stderr, "math: stack underflow\n"); | ||
35 | exit(-1); | ||
36 | } | ||
37 | return stack[--pointer]; | ||
38 | } | ||
39 | |||
40 | static void add() | ||
41 | { | ||
42 | push(pop() + pop()); | ||
43 | } | ||
44 | |||
45 | static void sub() | ||
46 | { | ||
47 | double subtrahend = pop(); | ||
48 | |||
49 | push(pop() - subtrahend); | ||
50 | } | ||
51 | |||
52 | static void mul() | ||
53 | { | ||
54 | push(pop() * pop()); | ||
55 | } | ||
56 | |||
57 | static void divide() | ||
58 | { | ||
59 | double divisor = pop(); | ||
60 | |||
61 | push(pop() / divisor); | ||
62 | } | ||
63 | |||
64 | static void and() | ||
65 | { | ||
66 | push((unsigned int) pop() & (unsigned int) pop()); | ||
67 | } | ||
68 | |||
69 | static void or() | ||
70 | { | ||
71 | push((unsigned int) pop() | (unsigned int) pop()); | ||
72 | } | ||
73 | |||
74 | static void eor() | ||
75 | { | ||
76 | push((unsigned int) pop() ^ (unsigned int) pop()); | ||
77 | } | ||
78 | |||
79 | static void not() | ||
80 | { | ||
81 | push(~(unsigned int) pop()); | ||
82 | } | ||
83 | |||
84 | static void print() | ||
85 | { | ||
86 | printf("%g\n", pop()); | ||
87 | } | ||
88 | |||
89 | struct op { | ||
90 | const char *name; | ||
91 | void (*function) (); | ||
92 | }; | ||
93 | |||
94 | static const struct op operators[] = { | ||
95 | {"+", add}, | ||
96 | {"add", add}, | ||
97 | {"-", sub}, | ||
98 | {"sub", sub}, | ||
99 | {"*", mul}, | ||
100 | {"mul", mul}, | ||
101 | {"/", divide}, | ||
102 | {"div", divide}, | ||
103 | {"and", and}, | ||
104 | {"or", or}, | ||
105 | {"not", not}, | ||
106 | {"eor", eor}, | ||
107 | {0, 0} | ||
108 | }; | ||
109 | |||
110 | static void stack_machine(const char *argument) | ||
111 | { | ||
112 | char *endPointer = 0; | ||
113 | double d; | ||
114 | const struct op *o = operators; | ||
115 | |||
116 | if (argument == 0) { | ||
117 | print(); | ||
118 | return; | ||
119 | } | ||
120 | |||
121 | d = strtod(argument, &endPointer); | ||
122 | |||
123 | if (endPointer != argument) { | ||
124 | push(d); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | while (o->name != 0) { | ||
129 | if (strcmp(o->name, argument) == 0) { | ||
130 | (*(o->function)) (); | ||
131 | return; | ||
132 | } | ||
133 | o++; | ||
134 | } | ||
135 | fprintf(stderr, "math: %s: syntax error.\n", argument); | ||
136 | exit(-1); | ||
137 | } | ||
138 | |||
139 | /* return pointer to next token in buffer and set *buffer to one char | ||
140 | * past the end of the above mentioned token | ||
141 | */ | ||
142 | static char *get_token(char **buffer) | ||
143 | { | ||
144 | char *start = NULL; | ||
145 | char *current = *buffer; | ||
146 | |||
147 | while (isspace(*current)) { current++; } | ||
148 | if (*current != 0) { | ||
149 | start = current; | ||
150 | while (!isspace(*current) && current != 0) { current++; } | ||
151 | *buffer = current; | ||
152 | } | ||
153 | return start; | ||
154 | } | ||
155 | |||
156 | /* In Perl one might say, scalar m|\s*(\S+)\s*|g */ | ||
157 | static int number_of_tokens(char *buffer) | ||
158 | { | ||
159 | int i = 0; | ||
160 | char *b = buffer; | ||
161 | while (get_token(&b)) { i++; } | ||
162 | return i; | ||
163 | } | ||
164 | |||
165 | int dc_main(int argc, char **argv) | ||
166 | { | ||
167 | /* take stuff from stdin if no args are given */ | ||
168 | if (argc <= 1) { | ||
169 | int i, len; | ||
170 | char *line = NULL; | ||
171 | char *cursor = NULL; | ||
172 | char *token = NULL; | ||
173 | while ((line = cstring_lineFromFile(stdin))) { | ||
174 | cursor = line; | ||
175 | len = number_of_tokens(line); | ||
176 | for (i = 0; i < len; i++) { | ||
177 | token = get_token(&cursor); | ||
178 | *cursor++ = 0; | ||
179 | stack_machine(token); | ||
180 | } | ||
181 | free(line); | ||
182 | } | ||
183 | } else { | ||
184 | if (*argv[1]=='-') | ||
185 | usage(dc_usage); | ||
186 | while (argc >= 2) { | ||
187 | stack_machine(argv[1]); | ||
188 | argv++; | ||
189 | argc--; | ||
190 | } | ||
191 | } | ||
192 | stack_machine(0); | ||
193 | return( TRUE); | ||
194 | } | ||