rpn.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. // Public Domain
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include <ctype.h>
  5. #include <string.h>
  6. #include "err.h"
  7. #include "rpn.h"
  8. #include "vec.h"
  9. int parse_arithmetic_string(char* src, char*** out, size_t* outlen) {
  10. VEC(char*) o;
  11. char* s = src;
  12. int l;
  13. VEC_INIT(&o);
  14. for(; *s; s++) {
  15. int c = *s;
  16. switch(c) {
  17. case ' ': continue;
  18. case '\n': continue;
  19. case '\r': continue;
  20. case '\t': continue;
  21. case '+':
  22. VEC_PUSH(&o, strdup("+"));
  23. break;
  24. case '*':
  25. if(s[1] == '*') {
  26. VEC_PUSH(&o, strdup("**"));
  27. s++;
  28. }
  29. else VEC_PUSH(&o, strdup("*"));
  30. break;
  31. case '/': VEC_PUSH(&o, strdup("/")); break;
  32. case '-':
  33. // TODO: check for negative signs
  34. VEC_PUSH(&o, strdup("-"));
  35. break;
  36. case '&': VEC_PUSH(&o, strdup("&")); break;
  37. case '^': VEC_PUSH(&o, strdup("^")); break;
  38. case '|': VEC_PUSH(&o, strdup("|")); break;
  39. case '~': VEC_PUSH(&o, strdup("~")); break;
  40. case '(': VEC_PUSH(&o, strdup("(")); break;
  41. case ')': VEC_PUSH(&o, strdup(")")); break;
  42. case '[': VEC_PUSH(&o, strdup("[")); break;
  43. case ']': VEC_PUSH(&o, strdup("]")); break;
  44. case '0':
  45. case '1':
  46. case '2':
  47. case '3':
  48. case '4':
  49. case '5':
  50. case '6':
  51. case '7':
  52. case '8':
  53. case '9':
  54. case '.':
  55. l = strspn(s, "0123456789.xbeE");
  56. VEC_PUSH(&o, strndup(s, l));
  57. s += l;
  58. break;
  59. default:
  60. continue;
  61. }
  62. }
  63. if(out) *out = o.data;
  64. if(outlen) *outlen = o.len;
  65. return 0;
  66. }
  67. static sti_op_prec_rule* shunting_classify(sti_op_prec_rule* rules, char* s) {
  68. sti_op_prec_rule* r = rules;
  69. for(; r->token; r++) {
  70. if(0 == strcmp(r->token, s)) return r;
  71. }
  72. return rules;
  73. }
  74. int infix_to_rpn(sti_op_prec_rule* rules, char** infix, char*** rpn, size_t* rpnlen) {
  75. VEC(sti_op_prec_rule) opstack;
  76. VEC(char*) out;
  77. VEC_INIT(&out);
  78. VEC_INIT(&opstack);
  79. char** n = infix;
  80. for(; *n; n++) {
  81. sti_op_prec_rule* r = shunting_classify(rules, *n);
  82. if(r == rules) {
  83. VEC_PUSH(&out, *n);
  84. continue;
  85. }
  86. if(r->assoc == STI_OP_OPEN_PAREN) {
  87. VEC_PUSH(&opstack, *r);
  88. continue;
  89. }
  90. if(r->assoc == STI_OP_CLOSE_PAREN) {
  91. while(VEC_LEN(&opstack) > 0) {
  92. sti_op_prec_rule top = VEC_TAIL(&opstack);
  93. if(top.assoc == STI_OP_OPEN_PAREN) {
  94. if(top.prec != r->prec) goto PAREN_MISMATCH;
  95. VEC_POP1(&opstack);
  96. goto END_PAREN;
  97. }
  98. sti_op_prec_rule o;
  99. VEC_POP(&opstack, o);
  100. VEC_PUSH(&out, o.token);
  101. }
  102. goto PAREN_MISMATCH;
  103. END_PAREN:
  104. continue;
  105. }
  106. // normal tokens
  107. while(VEC_LEN(&opstack) > 0) {
  108. sti_op_prec_rule top = VEC_TAIL(&opstack);
  109. if(top.assoc == STI_OP_OPEN_PAREN) break;
  110. if(top.prec < r->prec) break;
  111. if(top.prec == r->prec && r->assoc == STI_OP_ASSOC_LEFT) break;
  112. sti_op_prec_rule o;
  113. VEC_POP(&opstack, o);
  114. VEC_PUSH(&out, o.token);
  115. }
  116. VEC_PUSH(&opstack, ((sti_op_prec_rule){
  117. .token = *n,
  118. .prec = r->prec,
  119. .assoc = r->assoc,
  120. .arity = r->arity
  121. }));
  122. }
  123. // pop off the rest
  124. while(VEC_LEN(&opstack) > 0) {
  125. sti_op_prec_rule o;
  126. VEC_POP(&opstack, o);
  127. VEC_PUSH(&out, o.token);
  128. }
  129. VEC_FREE(&opstack);
  130. VEC_PUSH(&out, NULL);
  131. if(rpn) *rpn = out.data;
  132. if(rpnlen) *rpnlen = out.len - 1; // -1 because of the null pushed onto the end
  133. return 0;
  134. PAREN_MISMATCH:
  135. VEC_FREE(&opstack);
  136. VEC_FREE(&out);
  137. if(rpn) *rpn = NULL;
  138. if(rpnlen) *rpnlen = 0;
  139. return STI_ERR_PAREN_MISMATCH;
  140. }
  141. // the thinnest of checks
  142. static int string_is_number(char* s) {
  143. if(s[0] >= '0' && s[0] <= '9') return 1;
  144. else if(s[0] == '-' || s[0] == '+') {
  145. if(s[1] >= '0' && s[1] <= '9') return 1;
  146. else if(s[1] == '.') {
  147. if(s[2] >= '0' && s[2] <= '9') return 1;
  148. }
  149. }
  150. else if(s[0] == '.') {
  151. if(s[1] >= '0' && s[1] <= '9') return 1;
  152. }
  153. return 0;
  154. }
  155. #define oper(Z) { \
  156. VEC_POP(&stack, b); \
  157. VEC_POP(&stack, a); \
  158. Z; \
  159. VEC_PUSH(&stack, c); \
  160. break; }
  161. int64_t rpn_eval_int_str(char** rpn) {
  162. int64_t a, b, c;
  163. VEC(int64_t) stack;
  164. VEC_INIT(&stack);
  165. for(char** r = rpn; *r; r++) {
  166. if(string_is_number(*r)) {
  167. VEC_PUSH(&stack, strtol(*r, NULL, 10));
  168. continue;
  169. }
  170. switch(**r) {
  171. case '+': oper(c = a + b);
  172. case '-': oper(c = a - b);
  173. case '/': oper(c = a / b);
  174. case '%': oper(c = a % b);
  175. case '*':
  176. if((*r)[1] == '*') oper(c = a; for(int64_t n = labs(b); n > 1; n--) c *= a)
  177. else oper(c = a * b);
  178. case '&': oper(c = a & b);
  179. case '|': oper(c = a | b);
  180. case '^': oper(c = a ^ b);
  181. case '<':
  182. if((*r)[1] == '<') oper(c = a << b);
  183. break;
  184. case '>':
  185. if((*r)[1] == '>') oper(c = a << b);
  186. break;
  187. }
  188. }
  189. c = VEC_ITEM(&stack, 0);
  190. VEC_FREE(&stack);
  191. return c;
  192. }
  193. double rpn_eval_double_str(char** rpn) {
  194. double a, b, c;
  195. VEC(double) stack;
  196. VEC_INIT(&stack);
  197. for(char** r = rpn; *r; r++) {
  198. if(string_is_number(*r)) {
  199. VEC_PUSH(&stack, strtod(*r, NULL));
  200. continue;
  201. }
  202. switch(**r) {
  203. case '+': oper(c = a + b);
  204. case '-': oper(c = a - b);
  205. case '/': oper(c = a / b);
  206. case '*': oper(c = a * b);
  207. case '%': oper(c = fmod(a, b));
  208. default: return 0;
  209. }
  210. }
  211. c = VEC_ITEM(&stack, 0);
  212. VEC_FREE(&stack);
  213. return c;
  214. }
  215. /*
  216. int infix_to_rpn_incr(sti_op_prec_rule* rules, sti_shunting_context* ctx) {
  217. VEC_INIT(&ctx->stack);
  218. }
  219. */