It's a stack calculator for the unwise. Public Domain.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

546 lines
12KB

  1. /* ns.c - Number Stack */
  2. #define NS_PRINTLINE_FORMAT NS_PRINT_FORMAT "\n"
  3. /* Easy access functions */
  4. #define NS_PEEK(s) s->num[s->top]
  5. #define NS_PEEKN(s,n) s->num[s->top + n]
  6. #define NS_PEEKDOT(s) s.num[s.top]
  7. /* Handling of the stack max size and expanding */
  8. #define NS_EXPAND(s,n) n >= s->max ? !ns_expand(s,n) : 1
  9. #define NS_EXPANDDOT(s,n) n >= s.max ? !ns_expand(&s,n) : 1
  10. #define NS_LTMAX(s,n) s->top + n >= s->max ? !ns_expand(s,s->max+n) : 1
  11. #define NS_LTMAXDOT(s,n) s.top + n >= s.max ? !ns_expand(&s,s.max+n) : 1
  12. /* Debugging and Stack Output */
  13. #define NS_DIV0(fail) do { fprintf(stderr, PROGN ": divide by zero\n"); return fail; } while (0)
  14. #define NS_REG_UNDERFLOW(fail, c) do { fprintf(stderr, PROGN ": stack register '%c' (%04d) is empty\n", (char) c, c); return fail; } while (0)
  15. #ifndef DC_COMPLY
  16. #define NS_OVERFLOW(fail) do { fprintf(stderr, PROGN ": overflow\n"); return fail; } while (0)
  17. #define NS_UNDERFLOW(fail) do { fprintf(stderr, PROGN ": underflow\n"); return fail; } while (0)
  18. #define NS_REG_OOB(fail, c) fprintf(stderr, PROGN ": register '%c' (%04d) is out of bounds\n", (char) c, c)
  19. #else
  20. #define NS_OVERFLOW(fail) do { fprintf(stderr, PROGN ": at top of stack\n"); return fail; } while (0)
  21. #define NS_UNDERFLOW(fail) do { fprintf(stderr, PROGN ": stack empty\n"); return fail; } while (0)
  22. #define NS_REG_OOB(fail, c) __builtin_unreachable()
  23. #endif /* !DC_COMPLY */
  24. #define PERROR_RETURN(str,ret) do { perror(str); return ret; } while (1)
  25. #define NS_RETURN(ret) do { perror(PROGN); return ret; } while (1)
  26. /* #define NS_EXPAND(s,n) \ */
  27. /* if (s->top + n >= s->max) \ */
  28. /* { ns_expand(s,s->max+n); } */
  29. #define NS_OP(fn, op) \
  30. DC_EXPORT int \
  31. fn(ns_t * s) \
  32. { \
  33. if (s->top > 0) \
  34. { \
  35. --s->top; \
  36. op(NS_PEEK(s), \
  37. NS_PEEK(s), NS_PEEKN(s,1)); \
  38. return 0; \
  39. } \
  40. else \
  41. { NS_UNDERFLOW(1); } \
  42. }
  43. #define NS_OP_ONE(fn, op) \
  44. DC_EXPORT int \
  45. fn(ns_t * s) \
  46. { \
  47. if (s->top > -1) \
  48. { \
  49. op(NS_PEEK(s), \
  50. NS_PEEK(s)); \
  51. return 0; \
  52. } \
  53. else \
  54. { NS_UNDERFLOW(1); } \
  55. }
  56. #define NS_OP_DIV(fn, op) \
  57. DC_EXPORT int fn(ns_t * s) \
  58. { \
  59. if (s->top > 0) \
  60. { \
  61. if (!(mpf_cmp_ui(NS_PEEK(s), 0) || \
  62. mpf_cmp_ui(NS_PEEKN(s,-1), 0))) \
  63. { NS_DIV0(2); } \
  64. else \
  65. { \
  66. --s->top; \
  67. op(NS_PEEK(s), \
  68. NS_PEEK(s), NS_PEEKN(s,1)); \
  69. return 0; \
  70. } \
  71. } \
  72. else \
  73. { NS_UNDERFLOW(1); } \
  74. }
  75. typedef struct
  76. {
  77. ssize_t max;
  78. ssize_t top;
  79. mpf_t * num;
  80. } ns_t; /* number stack */
  81. DC_EXPORT_VAR mp_bitcnt_t g_prec = NS_DEFAULT_PREC;
  82. DC_EXPORT_VAR int g_iradix = 10;
  83. DC_EXPORT_VAR int g_oradix = 10;
  84. /* Data handling */
  85. DC_EXPORT void
  86. ns_free(ns_t * s)
  87. {
  88. ssize_t i;
  89. /* fprintf(stderr, "%p: Freeing %ld blocks\n", (void *) s, s->max); */
  90. for (i = 0; i < s->max; ++i)
  91. {
  92. mpf_clear(s->num[i]);
  93. }
  94. free(s->num);
  95. /* free(s); */
  96. }
  97. /* Growth */
  98. DC_EXPORT int
  99. ns_expand(ns_t * s, ssize_t newmax)
  100. {
  101. /* fprintf(stderr, "%p: Expanding to %ld blocks\n", (void *) s, newmax); */
  102. s->num = realloc(s->num, newmax * sizeof(mpf_t));
  103. if (!s->num)
  104. { NS_RETURN(1); }
  105. else
  106. {
  107. ssize_t i;
  108. for (i = s->max; i < newmax; ++i)
  109. { mpf_init(s->num[i]); }
  110. s->max = newmax;
  111. return 0;
  112. }
  113. }
  114. /* Stack */
  115. #define NS_PUSH(fn, op, type) \
  116. DC_EXPORT int \
  117. fn(ns_t * s, type val) \
  118. { \
  119. if (NS_LTMAX(s,1)) \
  120. { \
  121. ++s->top; \
  122. op(NS_PEEK(s), val); \
  123. return 0; \
  124. } \
  125. NS_OVERFLOW(1); \
  126. }
  127. NS_PUSH(ns_push, mpf_set, mpf_t)
  128. NS_PUSH(ns_push_ui, mpf_set_ui, unsigned int)
  129. DC_EXPORT mpf_t *
  130. ns_pop(ns_t * s)
  131. {
  132. if (s->top > -1)
  133. { return &s->num[s->top--]; }
  134. else
  135. { return NULL; }
  136. }
  137. DC_EXPORT inline int
  138. ns_dup(ns_t * s)
  139. {
  140. if (NS_LTMAX(s,1))
  141. { return ns_push(s, NS_PEEK(s)); }
  142. return 1;
  143. }
  144. DC_EXPORT inline void
  145. ns_clear(ns_t * s)
  146. { s->top = -1; }
  147. DC_EXPORT inline int
  148. ns_reverse(ns_t * s)
  149. {
  150. if (s->top > 0)
  151. {
  152. mpf_swap(NS_PEEK(s), NS_PEEKN(s,-1));
  153. return 0;
  154. }
  155. else
  156. { return 1; }
  157. }
  158. /* nrotate = x - 1
  159. top - n swapped with peek -x */
  160. DC_EXPORT int
  161. ns_nrotate(ns_t * s)
  162. {
  163. mpf_t * val = ns_pop(s);
  164. if (!val)
  165. { NS_UNDERFLOW(1); }
  166. else
  167. {
  168. signed long v = mpf_get_si(*val);
  169. long i = -v;
  170. const long l = -v;
  171. while (++i < v)
  172. {
  173. mpf_swap(NS_PEEKN(s,i), NS_PEEKN(s,l));
  174. }
  175. }
  176. return 0;
  177. }
  178. /* Registers */
  179. ns_t g_reg[NS_REG_MAX];
  180. void
  181. ns_reg_init(void)
  182. {
  183. size_t i;
  184. for (i = 0; i < NS_REG_MAX; ++i)
  185. {
  186. g_reg[i].top = -1;
  187. g_reg[i].max = 0;
  188. }
  189. }
  190. void
  191. ns_reg_free(void)
  192. {
  193. size_t i;
  194. for (i = 0; i < NS_REG_MAX; ++i)
  195. { ns_free(&g_reg[i]); }
  196. }
  197. DC_EXPORT int
  198. ns_reg_set(ns_t * s, int c)
  199. {
  200. mpf_t * val = ns_pop(s);
  201. if (!val)
  202. { NS_REG_UNDERFLOW(1, c); }
  203. if (g_reg[c].top > -1)
  204. { mpf_set(NS_PEEKDOT(g_reg[c]), *val); }
  205. else
  206. { ns_push(&g_reg[c], *val); }
  207. return 0;
  208. }
  209. DC_EXPORT int
  210. ns_reg_get(ns_t * s, int c)
  211. {
  212. mpf_t * val = ns_pop(&g_reg[c]);
  213. if (!val)
  214. { NS_REG_UNDERFLOW(1, c); }
  215. if (NS_LTMAX(s,1))
  216. { ns_push(s, *val); }
  217. return 0;
  218. }
  219. DC_EXPORT int
  220. ns_reg_push(ns_t * s, int c)
  221. {
  222. mpf_t * val = ns_pop(s);
  223. if (!val)
  224. { NS_REG_UNDERFLOW(1, c); }
  225. if (NS_LTMAXDOT(g_reg[c],1))
  226. { ns_push(&g_reg[c], *val); }
  227. return 0;
  228. }
  229. DC_EXPORT int
  230. ns_reg_pop(ns_t * s, int c)
  231. {
  232. mpf_t * val = ns_pop(&g_reg[c]);
  233. if (!val)
  234. { NS_REG_UNDERFLOW(1, c); }
  235. if (NS_LTMAX(s,1))
  236. { ns_push(s, *val); }
  237. return 0;
  238. }
  239. DC_EXPORT int
  240. ns_reg_push_index(ns_t * s, int c)
  241. {
  242. mpf_t * val, * ip;
  243. ip = ns_pop(s);
  244. val = ns_pop(s);
  245. if (!ip || !val)
  246. { NS_REG_UNDERFLOW(1, c); }
  247. else
  248. {
  249. ssize_t i = mpf_get_si(*ip);
  250. if (NS_EXPANDDOT(g_reg[c],i+1))
  251. {
  252. mpf_set(g_reg[c].num[i], *val);
  253. return 0;
  254. }
  255. else return 1;
  256. }
  257. }
  258. DC_EXPORT int
  259. ns_reg_pop_index(ns_t * s, int c)
  260. {
  261. mpf_t * ip = ns_pop(s);
  262. if (!ip)
  263. { NS_REG_UNDERFLOW(1, c); }
  264. else
  265. {
  266. ssize_t i;
  267. i = mpf_get_ui(*ip);
  268. if (NS_LTMAX(s,1) && NS_EXPANDDOT(g_reg[c],i+1))
  269. {
  270. ns_push(s, g_reg[c].num[i]);
  271. return 0;
  272. }
  273. else return 1;
  274. }
  275. }
  276. /* Printing */
  277. DC_EXPORT void
  278. ns_printline_all(ns_t * s)
  279. {
  280. ssize_t i;
  281. #ifdef FOR_HUMANS
  282. for (i = 0; i <= s->top; ++i)
  283. #else
  284. for (i = s->top; i >= 0; --i)
  285. #endif /* FOR_HUMANS */
  286. { gmp_printf(NS_FORMAT, s->num[i]); }
  287. }
  288. DC_EXPORT inline void
  289. ns_printline_peek(ns_t * s)
  290. {
  291. if (s->top > -1)
  292. { gmp_printf(NS_FORMAT, NS_PEEK(s)); }
  293. }
  294. DC_EXPORT inline int
  295. ns_print_peek(ns_t * s)
  296. {
  297. if (s->top > -1)
  298. {
  299. gmp_printf(NS_FORMAT, NS_PEEK(s));
  300. return 0;
  301. }
  302. else
  303. { return 1; }
  304. }
  305. #undef PRINT
  306. /* Numbers */
  307. DC_EXPORT inline int
  308. ns_isnum(char c)
  309. {
  310. switch (c)
  311. {
  312. case '.':
  313. case '0': case '1': case '2': case '3': case '4':
  314. case '5': case '6': case '7': case '8': case '9':
  315. case 'A': case 'B': case 'C': case 'D': case 'E':
  316. case 'F':
  317. return 1;
  318. default:
  319. return 0;
  320. }
  321. }
  322. DC_EXPORT size_t
  323. ns_getnum(ns_t * s, char * eval, size_t len, int base)
  324. {
  325. size_t i = 0;
  326. char t;
  327. while (ns_isnum(eval[i]) && i < len) { ++i; }
  328. if (!i)
  329. { return 0; }
  330. if (NS_LTMAX(s,1))
  331. {
  332. ++s->top;
  333. t = eval[i];
  334. eval[i] = '\0';
  335. mpf_set_str(NS_PEEK(s), eval, base);
  336. eval[i] = t;
  337. return i-1;
  338. }
  339. else
  340. { NS_OVERFLOW(0); }
  341. }
  342. /* Digits */
  343. #if 0
  344. DC_EXPORT int
  345. ns_digit_last(ns_t * s)
  346. {
  347. return 1;
  348. }
  349. DC_EXPORT int
  350. ns_digit(ns_t * s)
  351. {
  352. return 1;
  353. }
  354. #endif /* 0 */
  355. /* Arithmetic */
  356. /* handles negative numbers and is multi-precision on both operands unlike mpf_exp_ui */
  357. DC_EXPORT int
  358. ns_exp(ns_t * s)
  359. {
  360. if (s->top > 0)
  361. {
  362. if (!(mpf_cmp_ui(NS_PEEK(s), 0) ||
  363. mpf_cmp_ui(s->num[s->top-1], 0)))
  364. { fprintf(stderr, "dc: divide by 0\n"); return 2; }
  365. else
  366. {
  367. mpf_t i;
  368. mpf_t mpf;
  369. if (mpf_cmp_ui(NS_PEEK(s), 0) == 0)
  370. { mpf_set_ui(NS_PEEK(s), 1); return 0; }
  371. --s->top;
  372. mpf_inits(i, mpf, NULL);
  373. mpf_set(mpf, NS_PEEK(s));
  374. mpf_set(i, s->num[s->top + 1]);
  375. mpf_ceil(i, i);
  376. mpf_sub_ui(i, i, 1);
  377. if (mpf_cmp_ui(i, 0) > 0)
  378. {
  379. for (; mpf_cmp_ui(i, 0); mpf_sub_ui(i, i, 1))
  380. { mpf_mul(NS_PEEK(s), NS_PEEK(s), mpf); }
  381. }
  382. else
  383. {
  384. for (; mpf_cmp_ui(i, 0); mpf_add_ui(i, i, 1))
  385. { mpf_div(NS_PEEK(s), NS_PEEK(s), mpf); }
  386. }
  387. mpf_clears(i, mpf, NULL);
  388. return 0;
  389. }
  390. }
  391. NS_UNDERFLOW(1);
  392. }
  393. NS_OP(ns_add, mpf_add)
  394. NS_OP(ns_sub, mpf_sub)
  395. NS_OP(ns_mul, mpf_mul)
  396. NS_OP_ONE(ns_abs, mpf_abs)
  397. NS_OP_ONE(ns_sqrt, mpf_sqrt)
  398. NS_OP_ONE(ns_floor, mpf_floor)
  399. NS_OP_ONE(ns_ceil, mpf_ceil)
  400. NS_OP_DIV(ns_div, mpf_div)
  401. /* Params */
  402. DC_EXPORT int
  403. ns_pop_prec(ns_t * s)
  404. {
  405. ssize_t i, f;
  406. mpf_t * mpf = ns_pop(s);
  407. if (!mpf)
  408. { NS_UNDERFLOW(1); }
  409. else
  410. {
  411. size_t prec = mpf_get_ui(*mpf);
  412. /* fprintf(stderr, "new prec: %ld\n", prec); */
  413. g_prec = prec;
  414. for (i = 0; i < s->max; ++i)
  415. { mpf_set_prec(s->num[i], prec); }
  416. for (f = NS_REG_OFF; f < NS_REG_MAX; ++f)
  417. {
  418. for (i = 0; i < g_reg[f].max; ++i)
  419. { mpf_set_prec(g_reg[f].num[i], prec); }
  420. }
  421. return 0;
  422. }
  423. }
  424. DC_EXPORT int
  425. ns_push_prec(ns_t * s)
  426. { return ns_push_ui(s, g_prec); }
  427. DC_EXPORT int
  428. ns_pop_iradix(ns_t * s)
  429. {
  430. mpf_t * mpf = ns_pop(s);
  431. if (!mpf)
  432. { NS_UNDERFLOW(1); }
  433. else
  434. {
  435. int x = (int) mpf_get_ui(*mpf);
  436. if (2 < x && x < INT_MAX - 1)
  437. { fprintf(stderr, PROGN ": input base must be a number between 2 and %d (inclusive)\n", INT_MAX - 1); }
  438. return 0;
  439. }
  440. }
  441. DC_EXPORT int
  442. ns_push_iradix(ns_t * s)
  443. { return ns_push_ui(s, g_iradix); }
  444. DC_EXPORT int
  445. ns_pop_oradix(ns_t * s)
  446. {
  447. mpf_t * mpf = ns_pop(s);
  448. if (!mpf)
  449. { NS_UNDERFLOW(1); }
  450. else
  451. {
  452. g_oradix = (int) mpf_get_ui(*mpf);
  453. return 0;
  454. }
  455. }
  456. DC_EXPORT int
  457. ns_push_oradix(ns_t * s)
  458. { return ns_push_ui(s, g_oradix); }
  459. /* Test Functions */
  460. #if 0
  461. /* It probably shouldn't return -1 but I'm not worried about this function */
  462. DC_EXPORT int
  463. ns_ndup(ns_t * s)
  464. {
  465. int ret = 0;
  466. mpf_t dupn;
  467. if (!ns_pop(s))
  468. { NS_UNDERFLOW(-1); }
  469. for (mpf_set(dupn, NS_PEEKN(s,1));
  470. !ret &&
  471. mpf_cmp_ui(dupn,1);
  472. mpf_sub_ui(dupn,dupn,1))
  473. { ret = ns_dup(s); }
  474. return ret;
  475. }
  476. #endif /* 0 */
  477. /* Definition Cleanup */
  478. /* #undef NS_OP */
  479. /* #undef NS_OP_ONE */
  480. /* #undef NS_OP_DIV */
  481. /* #undef NS_OVERFLOW */
  482. /* #undef NS_UNDERFLOW */
  483. /* #undef NS_REG_UNDERFLOW */
  484. /* #undef NS_DIV0 */