dc.c 3.8 KB

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