It's a stack calculator for the unwise. Public Domain.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
Ce dépôt est archivé. Vous pouvez voir les fichiers et le cloner, mais vous ne pouvez pas pousser ni ouvrir de ticket/demande d'ajout.

546 lignes
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 */