dc.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  4. */
  5. /* config/applet/usage bits are in bc.c */
  6. //#include "libbb.h"
  7. //#include "common_bufsiz.h"
  8. #include <math.h>
  9. #if 0
  10. typedef unsigned data_t;
  11. #define DATA_FMT ""
  12. #elif 0
  13. typedef unsigned long data_t;
  14. #define DATA_FMT "l"
  15. #else
  16. typedef unsigned long long data_t;
  17. #define DATA_FMT "ll"
  18. #endif
  19. struct globals {
  20. unsigned pointer;
  21. unsigned base;
  22. double stack[1];
  23. } FIX_ALIASING;
  24. enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(double) };
  25. #define G (*(struct globals*)bb_common_bufsiz1)
  26. #define pointer (G.pointer )
  27. #define base (G.base )
  28. #define stack (G.stack )
  29. #define INIT_G() do { \
  30. setup_common_bufsiz(); \
  31. base = 10; \
  32. } while (0)
  33. static void check_under(void)
  34. {
  35. if (pointer == 0)
  36. bb_error_msg_and_die("stack underflow");
  37. }
  38. static void push(double a)
  39. {
  40. if (pointer >= STACK_SIZE)
  41. bb_error_msg_and_die("stack overflow");
  42. stack[pointer++] = a;
  43. }
  44. static double pop(void)
  45. {
  46. check_under();
  47. return stack[--pointer];
  48. }
  49. static void add(void)
  50. {
  51. push(pop() + pop());
  52. }
  53. static void sub(void)
  54. {
  55. double subtrahend = pop();
  56. push(pop() - subtrahend);
  57. }
  58. static void mul(void)
  59. {
  60. push(pop() * pop());
  61. }
  62. #if ENABLE_FEATURE_DC_LIBM
  63. static void power(void)
  64. {
  65. double topower = pop();
  66. push(pow(pop(), topower));
  67. }
  68. #endif
  69. static void divide(void)
  70. {
  71. double divisor = pop();
  72. push(pop() / divisor);
  73. }
  74. static void mod(void)
  75. {
  76. data_t d = pop();
  77. push((data_t) pop() % d);
  78. }
  79. static void and(void)
  80. {
  81. push((data_t) pop() & (data_t) pop());
  82. }
  83. static void or(void)
  84. {
  85. push((data_t) pop() | (data_t) pop());
  86. }
  87. static void eor(void)
  88. {
  89. push((data_t) pop() ^ (data_t) pop());
  90. }
  91. static void not(void)
  92. {
  93. push(~(data_t) pop());
  94. }
  95. static void set_output_base(void)
  96. {
  97. static const char bases[] ALIGN1 = { 2, 8, 10, 16, 0 };
  98. unsigned b = (unsigned)pop();
  99. base = *strchrnul(bases, b);
  100. if (base == 0) {
  101. bb_error_msg("error, base %u is not supported", b);
  102. base = 10;
  103. }
  104. }
  105. static void print_base(double print)
  106. {
  107. data_t x, i;
  108. x = (data_t) print;
  109. if (base == 10) {
  110. if (x == print) /* exactly representable as unsigned integer */
  111. printf("%"DATA_FMT"u\n", x);
  112. else
  113. printf("%g\n", print);
  114. return;
  115. }
  116. switch (base) {
  117. case 16:
  118. printf("%"DATA_FMT"x\n", x);
  119. break;
  120. case 8:
  121. printf("%"DATA_FMT"o\n", x);
  122. break;
  123. default: /* base 2 */
  124. i = MAXINT(data_t) - (MAXINT(data_t) >> 1);
  125. /* i is 100000...00000 */
  126. do {
  127. if (x & i)
  128. break;
  129. i >>= 1;
  130. } while (i > 1);
  131. do {
  132. bb_putchar('1' - !(x & i));
  133. i >>= 1;
  134. } while (i);
  135. bb_putchar('\n');
  136. }
  137. }
  138. static void print_stack_no_pop(void)
  139. {
  140. unsigned i = pointer;
  141. while (i)
  142. print_base(stack[--i]);
  143. }
  144. static void print_no_pop(void)
  145. {
  146. check_under();
  147. print_base(stack[pointer-1]);
  148. }
  149. struct op {
  150. const char name[4];
  151. void (*function) (void);
  152. };
  153. static const struct op operators[] = {
  154. #if ENABLE_FEATURE_DC_LIBM
  155. {"^", power},
  156. // {"exp", power},
  157. // {"pow", power},
  158. #endif
  159. {"%", mod},
  160. // {"mod", mod},
  161. // logic ops are not standard, remove?
  162. {"and", and},
  163. {"or", or},
  164. {"not", not},
  165. {"xor", eor},
  166. {"+", add},
  167. // {"add", add},
  168. {"-", sub},
  169. // {"sub", sub},
  170. {"*", mul},
  171. // {"mul", mul},
  172. {"/", divide},
  173. // {"div", divide},
  174. {"p", print_no_pop},
  175. {"f", print_stack_no_pop},
  176. {"o", set_output_base},
  177. };
  178. /* Feed the stack machine */
  179. static void stack_machine(const char *argument)
  180. {
  181. char *end;
  182. double number;
  183. const struct op *o;
  184. next:
  185. number = strtod(argument, &end);
  186. if (end != argument) {
  187. argument = end;
  188. push(number);
  189. goto next;
  190. }
  191. /* We might have matched a digit, eventually advance the argument */
  192. argument = skip_whitespace(argument);
  193. if (*argument == '\0')
  194. return;
  195. o = operators;
  196. do {
  197. char *after_name = is_prefixed_with(argument, o->name);
  198. if (after_name) {
  199. argument = after_name;
  200. o->function();
  201. goto next;
  202. }
  203. o++;
  204. } while (o != operators + ARRAY_SIZE(operators));
  205. bb_error_msg_and_die("syntax error at '%s'", argument);
  206. }
  207. static void process_file(FILE *fp)
  208. {
  209. char *line;
  210. while ((line = xmalloc_fgetline(fp)) != NULL) {
  211. stack_machine(line);
  212. free(line);
  213. }
  214. }
  215. int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  216. int dc_main(int argc UNUSED_PARAM, char **argv)
  217. {
  218. bool script = 0;
  219. INIT_G();
  220. /* Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs */
  221. for (;;) {
  222. int n = getopt(argc, argv, "e:f:");
  223. if (n <= 0)
  224. break;
  225. switch (n) {
  226. case 'e':
  227. script = 1;
  228. stack_machine(optarg);
  229. break;
  230. case 'f':
  231. script = 1;
  232. process_file(xfopen_for_read(optarg));
  233. break;
  234. default:
  235. bb_show_usage();
  236. }
  237. }
  238. argv += optind;
  239. if (*argv) {
  240. do
  241. process_file(xfopen_for_read(*argv++));
  242. while (*argv);
  243. } else if (!script) {
  244. /* Take stuff from stdin if no args are given */
  245. process_file(stdin);
  246. }
  247. return EXIT_SUCCESS;
  248. }