1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 /* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */
17 enum { STACK_SIZE
= (COMMON_BUFSIZE
- offsetof(struct globals
, stack
)) / sizeof(double) };
18 #define G (*(struct globals*)&bb_common_bufsiz1)
19 #define pointer (G.pointer )
20 #define base (G.base )
21 #define stack (G.stack )
22 #define INIT_G() do { \
27 static void push(double a
)
29 if (pointer
>= STACK_SIZE
)
30 bb_error_msg_and_die("stack overflow");
34 static double pop(void)
37 bb_error_msg_and_die("stack underflow");
38 return stack
[--pointer
];
48 double subtrahend
= pop();
50 push(pop() - subtrahend
);
58 #if ENABLE_FEATURE_DC_LIBM
59 static void power(void)
61 double topower
= pop();
63 push(pow(pop(), topower
));
67 static void divide(void)
69 double divisor
= pop();
71 push(pop() / divisor
);
78 push((unsigned) pop() % d
);
83 push((unsigned) pop() & (unsigned) pop());
88 push((unsigned) pop() | (unsigned) pop());
93 push((unsigned) pop() ^ (unsigned) pop());
98 push(~(unsigned) pop());
101 static void set_output_base(void)
103 static const char bases
[] ALIGN1
= { 2, 8, 10, 16, 0 };
104 unsigned b
= (unsigned)pop();
106 base
= *strchrnul(bases
, b
);
108 bb_error_msg("error, base %u is not supported", b
);
113 static void print_base(double print
)
118 printf("%g\n", print
);
130 default: /* base 2 */
131 i
= (unsigned)INT_MAX
+ 1;
137 bb_putchar('1' - !(x
& i
));
144 static void print_stack_no_pop(void)
146 unsigned i
= pointer
;
148 print_base(stack
[--i
]);
151 static void print_no_pop(void)
153 print_base(stack
[pointer
-1]);
158 void (*function
) (void);
161 static const struct op operators
[] = {
170 #if ENABLE_FEATURE_DC_LIBM
183 {"f", print_stack_no_pop
},
184 {"o", set_output_base
},
185 { /* zero filled */ }
188 static void stack_machine(const char *argument
)
192 const struct op
*o
= operators
;
197 d
= strtod(argument
, &endPointer
);
199 if (endPointer
!= argument
) {
205 if (strcmp(o
->name
, argument
) == 0) {
211 bb_error_msg_and_die("%s: syntax error", argument
);
214 /* return pointer to next token in buffer and set *buffer to one char
215 * past the end of the above mentioned token
217 static char *get_token(char **buffer
)
219 char *current
= skip_whitespace(*buffer
);
220 if (*current
!= '\0') {
221 *buffer
= skip_non_whitespace(current
);
227 int dc_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
228 int dc_main(int argc UNUSED_PARAM
, char **argv
)
234 /* take stuff from stdin if no args are given */
238 while ((line
= xmalloc_fgetline(stdin
)) != NULL
) {
241 token
= get_token(&cursor
);
244 stack_machine(token
);
249 if (argv
[0][0] == '-')
252 stack_machine(*argv
);