dc.c 3.8 KB

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