1
2
3
4
5
6#include "libbb.h"
7#include <math.h>
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#if 0
33typedef unsigned data_t;
34#define DATA_FMT ""
35#elif 0
36typedef unsigned long data_t;
37#define DATA_FMT "l"
38#else
39typedef unsigned long long data_t;
40#define DATA_FMT "ll"
41#endif
42
43
44struct globals {
45 unsigned pointer;
46 unsigned base;
47 double stack[1];
48} FIX_ALIASING;
49enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) };
50#define G (*(struct globals*)&bb_common_bufsiz1)
51#define pointer (G.pointer )
52#define base (G.base )
53#define stack (G.stack )
54#define INIT_G() do { \
55 base = 10; \
56} while (0)
57
58
59static void check_under(void)
60{
61 if (pointer == 0)
62 bb_error_msg_and_die("stack underflow");
63}
64
65static void push(double a)
66{
67 if (pointer >= STACK_SIZE)
68 bb_error_msg_and_die("stack overflow");
69 stack[pointer++] = a;
70}
71
72static double pop(void)
73{
74 check_under();
75 return stack[--pointer];
76}
77
78static void add(void)
79{
80 push(pop() + pop());
81}
82
83static void sub(void)
84{
85 double subtrahend = pop();
86
87 push(pop() - subtrahend);
88}
89
90static void mul(void)
91{
92 push(pop() * pop());
93}
94
95#if ENABLE_FEATURE_DC_LIBM
96static void power(void)
97{
98 double topower = pop();
99
100 push(pow(pop(), topower));
101}
102#endif
103
104static void divide(void)
105{
106 double divisor = pop();
107
108 push(pop() / divisor);
109}
110
111static void mod(void)
112{
113 data_t d = pop();
114
115 push((data_t) pop() % d);
116}
117
118static void and(void)
119{
120 push((data_t) pop() & (data_t) pop());
121}
122
123static void or(void)
124{
125 push((data_t) pop() | (data_t) pop());
126}
127
128static void eor(void)
129{
130 push((data_t) pop() ^ (data_t) pop());
131}
132
133static void not(void)
134{
135 push(~(data_t) pop());
136}
137
138static void set_output_base(void)
139{
140 static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 };
141 unsigned b = (unsigned)pop();
142
143 base = *strchrnul(bases, b);
144 if (base == 0) {
145 bb_error_msg("error, base %u is not supported", b);
146 base = 10;
147 }
148}
149
150static void print_base(double print)
151{
152 data_t x, i;
153
154 x = (data_t) print;
155 if (base == 10) {
156 if (x == print)
157 printf("%"DATA_FMT"u\n", x);
158 else
159 printf("%g\n", print);
160 return;
161 }
162
163 switch (base) {
164 case 16:
165 printf("%"DATA_FMT"x\n", x);
166 break;
167 case 8:
168 printf("%"DATA_FMT"o\n", x);
169 break;
170 default:
171 i = MAXINT(data_t) - (MAXINT(data_t) >> 1);
172
173 do {
174 if (x & i)
175 break;
176 i >>= 1;
177 } while (i > 1);
178 do {
179 bb_putchar('1' - !(x & i));
180 i >>= 1;
181 } while (i);
182 bb_putchar('\n');
183 }
184}
185
186static void print_stack_no_pop(void)
187{
188 unsigned i = pointer;
189 while (i)
190 print_base(stack[--i]);
191}
192
193static void print_no_pop(void)
194{
195 check_under();
196 print_base(stack[pointer-1]);
197}
198
199struct op {
200 const char name[4];
201 void (*function) (void);
202};
203
204static const struct op operators[] = {
205#if ENABLE_FEATURE_DC_LIBM
206 {"**", power},
207 {"exp", power},
208 {"pow", power},
209#endif
210 {"%", mod},
211 {"mod", mod},
212 {"and", and},
213 {"or", or},
214 {"not", not},
215 {"eor", eor},
216 {"xor", eor},
217 {"+", add},
218 {"add", add},
219 {"-", sub},
220 {"sub", sub},
221 {"*", mul},
222 {"mul", mul},
223 {"/", divide},
224 {"div", divide},
225 {"p", print_no_pop},
226 {"f", print_stack_no_pop},
227 {"o", set_output_base},
228};
229
230
231static void stack_machine(const char *argument)
232{
233 char *end;
234 double number;
235 const struct op *o;
236
237 next:
238 number = strtod(argument, &end);
239 if (end != argument) {
240 argument = end;
241 push(number);
242 goto next;
243 }
244
245
246 argument = skip_whitespace(argument);
247
248 if (*argument == '\0')
249 return;
250
251 o = operators;
252 do {
253 char *after_name = is_prefixed_with(argument, o->name);
254 if (after_name) {
255 argument = after_name;
256 o->function();
257 goto next;
258 }
259 o++;
260 } while (o != operators + ARRAY_SIZE(operators));
261
262 bb_error_msg_and_die("syntax error at '%s'", argument);
263}
264
265int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
266int dc_main(int argc UNUSED_PARAM, char **argv)
267{
268 INIT_G();
269
270 argv++;
271 if (!argv[0]) {
272
273 char *line;
274 while ((line = xmalloc_fgetline(stdin)) != NULL) {
275 stack_machine(line);
276 free(line);
277 }
278 } else {
279 do {
280 stack_machine(*argv);
281 } while (*++argv);
282 }
283 return EXIT_SUCCESS;
284}
285