Advertisement
Guest User

[Patch] Add bc to busybox

a guest
Oct 29th, 2018
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 188.18 KB | None | 0 0
  1. From 61c3eaeaf5fa3d525b1911f7dc37829a049de354 Mon Sep 17 00:00:00 2001
  2. From: Gavin Howard <yzena.tech@gmail.com>
  3. Date: Mon, 29 Oct 2018 09:46:57 -0600
  4. Subject: [PATCH] Add bc and a complete dc
  5.  
  6. ---
  7. miscutils/bc.c | 7581 ++++++++++++++++++++++++++++++++++++++++++++++++
  8.  1 file changed, 7581 insertions(+)
  9.  create mode 100644 miscutils/bc.c
  10.  
  11. diff --git a/miscutils/bc.c b/miscutils/bc.c
  12. new file mode 100644
  13. index 000000000..a1a8814ea
  14. --- /dev/null
  15. +++ b/miscutils/bc.c
  16. @@ -0,0 +1,7581 @@
  17. +/* vi: set sw=4 ts=4: */
  18. +/*
  19. + * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  20. + * Copyright (c) 2018 Gavin D. Howard and contributors.
  21. + * Automatically generated from https://github.com/gavinhoward/bc
  22. + */
  23. +//config:config BC
  24. +//config:  bool "bc (46.77 kb; 55.93 kb when combined with dc)"
  25. +//config:  default n
  26. +//config:  help
  27. +//config:  bc is a command-line, arbitrary-precision calculator with a Turing-complete
  28. +//config:  language. See the GNU bc manual (https://www.gnu.org/software/bc/manual/bc.html)
  29. +//config:  and bc spec (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
  30. +//config:  for details.
  31. +//config:
  32. +//config:  This bc has four differences to the GNU bc:
  33. +//config:
  34. +//config:    1) The period (.) can also be used as a shortcut for "last", as in the BSD bc.
  35. +//config:    2) Arrays are copied before being passed as arguments to functions. This
  36. +//config:       behavior is required by the bc spec.
  37. +//config:    3) Arrays can be passed to the builtin "length" function to get the number of
  38. +//config:       elements currently in the array. The following example prints "1":
  39. +//config:
  40. +//config:         a[0] = 0
  41. +//config:         length(a[])
  42. +//config:
  43. +//config:    4) The precedence of the boolean "not" operator (!) is equal to that of the
  44. +//config:       unary minus (-), or negation, operator. This still allows POSIX-compliant
  45. +//config:       scripts to work while somewhat preserving expected behavior (versus C) and
  46. +//config:       making parsing easier.
  47. +//config:
  48. +//config:  Options:
  49. +//config:
  50. +//config:    -e expr  --expression=expr
  51. +//config:                           run "expr" and quit. If multiple expressions or files
  52. +//config:                           (see below) are given, they are all run.
  53. +//config:    -f  file  --file=file  run the bc code in "file" and exit. See above as well.
  54. +//config:    -h  --help             print this usage message and exit
  55. +//config:    -i  --interactive      force interactive mode
  56. +//config:    -l  --mathlib          use predefined math routines:
  57. +//config:
  58. +//config:                             s(expr)  =  sine of expr in radians
  59. +//config:                             c(expr)  =  cosine of expr in radians
  60. +//config:                             a(expr)  =  arctangent of expr, returning radians
  61. +//config:                             l(expr)  =  natural log of expr
  62. +//config:                             e(expr)  =  raises e to the power of expr
  63. +//config:                             j(n, x)  =  Bessel function of integer order n of x
  64. +//config:
  65. +//config:    -q  --quiet            don't print version and copyright
  66. +//config:    -s  --standard         error if any non-POSIX extensions are used
  67. +//config:    -w  --warn             warn if any non-POSIX extensions are used
  68. +//config:    -v  --version          print version information and copyright and exit
  69. +//config:
  70. +//config:config DC
  71. +//config:  bool "dc (35.90 kb; 55.93 kb when combined with bc)"
  72. +//config:  default n
  73. +//config:  help
  74. +//config:  dc is a reverse-polish notation command-line calculator which supports unlimited
  75. +//config:  precision arithmetic. See the FreeBSD man page
  76. +//config:  (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
  77. +//config:  (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html) for details.
  78. +//config:
  79. +//config:  This dc has a few differences from the two above:
  80. +//config:
  81. +//config:    1) When printing a byte stream (command "P"), this bc follows what the FreeBSD
  82. +//config:       dc does.
  83. +//config:    2) This dc implements the GNU extensions for divmod ("~") and modular
  84. +//config:       exponentiation ("|").
  85. +//config:    3) This dc implements all FreeBSD extensions, except for "J" and "M".
  86. +//config:    4) Like the FreeBSD dc, this dc supports extended registers. However, it is
  87. +//config:       implemented differently. When it encounters whitespace where a register
  88. +//config:       should be, it skips the whitespace. If the character following is not
  89. +//config:       a lowercase letter, an error is issued. Otherwise, the register name is
  90. +//config:       parsed by the following regex:
  91. +//config:
  92. +//config:         [a-z][a-z0-9_]*
  93. +//config:
  94. +//config:       This generally means that register names will be surrounded by parentheses.
  95. +//config:
  96. +//config:       Examples:
  97. +//config:
  98. +//config:         l idx s temp L index S temp2 < do_thing
  99. +//config:
  100. +//config:       Also note that, like the FreeBSD dc, extended registers are not allowed
  101. +//config:       unless the "-x" option is given.
  102. +//config:
  103. +//config:  Options:
  104. +//config:
  105. +//config:    -e expr  --expression=expr  run "expr" and quit. If multiple expressions or
  106. +//config:                                files (see below) are given, they are all run.
  107. +//config:    -f  file  --file=file       run the bc code in "file" and exit. See above.
  108. +//config:    -h  --help                  print this usage message and exit.
  109. +//config:    -V  --version               print version and copyright and exit.
  110. +//config:    -x  --extended-register     enable extended register mode.
  111. +
  112. +//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
  113. +//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
  114. +
  115. +//kbuild:lib-$(CONFIG_BC) += bc.o
  116. +//kbuild:lib-$(CONFIG_DC) += bc.o
  117. +
  118. +//usage:#define bc_trivial_usage
  119. +//usage:       "EXPRESSION...\n"
  120. +//usage:       "function_definition\n"
  121. +//usage:
  122. +//usage:#define bc_full_usage "\n\n"
  123. +//usage:       "See www.gnu.org/software/bc/manual/bc.html\n"
  124. +//usage:
  125. +//usage:#define bc_example_usage
  126. +//usage:       "3 + 4.129\n"
  127. +//usage:       "1903 - 2893\n"
  128. +//usage:       "-129 * 213.28935\n"
  129. +//usage:       "12 / -1932\n"
  130. +//usage:       "12 % 12\n"
  131. +//usage:       "34 ^ 189\n"
  132. +//usage:       "scale = 13\n"
  133. +//usage:       "ibase = 2\n"
  134. +//usage:       "obase = A\n"
  135. +//usage:
  136. +//usage:#define dc_trivial_usage
  137. +//usage:       "EXPRESSION..."
  138. +//usage:
  139. +//usage:#define dc_full_usage "\n\n"
  140. +//usage:       "Tiny RPN calculator. Operations:\n"
  141. +//usage:       "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, modular exponentiation,\n"
  142. +//usage:       "p - print top of the stack (without popping),\n"
  143. +//usage:       "f - print entire stack,\n"
  144. +//usage:       "k - pop the value and set the precision.\n"
  145. +//usage:       "i - pop the value and set input radix.\n"
  146. +//usage:       "o - pop the value and set output radix.\n"
  147. +//usage:       "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
  148. +//usage:
  149. +//usage:#define dc_example_usage
  150. +//usage:       "$ dc 2 2 + p\n"
  151. +//usage:       "4\n"
  152. +//usage:       "$ dc 8 8 \\* 2 2 + / p\n"
  153. +//usage:       "16\n"
  154. +//usage:       "$ dc 0 1 and p\n"
  155. +//usage:       "0\n"
  156. +//usage:       "$ dc 0 1 or p\n"
  157. +//usage:       "1\n"
  158. +//usage:       "$ echo 72 9 div 8 mul p | dc\n"
  159. +//usage:       "64\n"
  160. +
  161. +#include <ctype.h>
  162. +#include <errno.h>
  163. +#include <stdbool.h>
  164. +#include <stddef.h>
  165. +#include <stdint.h>
  166. +#include <stdio.h>
  167. +#include <stdlib.h>
  168. +#include <string.h>
  169. +
  170. +#include <fcntl.h>
  171. +#include <limits.h>
  172. +#include <signal.h>
  173. +#include <unistd.h>
  174. +#include <sys/stat.h>
  175. +#include <sys/types.h>
  176. +
  177. +#include <getopt.h>
  178. +
  179. +typedef enum BcStatus {
  180. +
  181. +   BC_STATUS_SUCCESS,
  182. +
  183. +   BC_STATUS_ALLOC_ERR,
  184. +   BC_STATUS_IO_ERR,
  185. +   BC_STATUS_BIN_FILE,
  186. +   BC_STATUS_PATH_IS_DIR,
  187. +
  188. +   BC_STATUS_LEX_BAD_CHAR,
  189. +   BC_STATUS_LEX_NO_STRING_END,
  190. +   BC_STATUS_LEX_NO_COMMENT_END,
  191. +   BC_STATUS_LEX_EOF,
  192. +#ifdef CONFIG_DC
  193. +   BC_STATUS_LEX_EXTENDED_REG,
  194. +#endif // CONFIG_DC
  195. +
  196. +   BC_STATUS_PARSE_BAD_TOKEN,
  197. +   BC_STATUS_PARSE_BAD_EXP,
  198. +   BC_STATUS_PARSE_EMPTY_EXP,
  199. +   BC_STATUS_PARSE_BAD_PRINT,
  200. +   BC_STATUS_PARSE_BAD_FUNC,
  201. +   BC_STATUS_PARSE_BAD_ASSIGN,
  202. +   BC_STATUS_PARSE_NO_AUTO,
  203. +   BC_STATUS_PARSE_DUPLICATE_LOCAL,
  204. +   BC_STATUS_PARSE_NO_BLOCK_END,
  205. +
  206. +   BC_STATUS_MATH_NEGATIVE,
  207. +   BC_STATUS_MATH_NON_INTEGER,
  208. +   BC_STATUS_MATH_OVERFLOW,
  209. +   BC_STATUS_MATH_DIVIDE_BY_ZERO,
  210. +   BC_STATUS_MATH_BAD_STRING,
  211. +
  212. +   BC_STATUS_EXEC_FILE_ERR,
  213. +   BC_STATUS_EXEC_MISMATCHED_PARAMS,
  214. +   BC_STATUS_EXEC_UNDEFINED_FUNC,
  215. +   BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
  216. +   BC_STATUS_EXEC_SIGACTION_FAIL,
  217. +   BC_STATUS_EXEC_NUM_LEN,
  218. +   BC_STATUS_EXEC_NAME_LEN,
  219. +   BC_STATUS_EXEC_STRING_LEN,
  220. +   BC_STATUS_EXEC_ARRAY_LEN,
  221. +   BC_STATUS_EXEC_BAD_IBASE,
  222. +   BC_STATUS_EXEC_BAD_SCALE,
  223. +   BC_STATUS_EXEC_BAD_READ_EXPR,
  224. +   BC_STATUS_EXEC_REC_READ,
  225. +   BC_STATUS_EXEC_BAD_TYPE,
  226. +   BC_STATUS_EXEC_BAD_OBASE,
  227. +   BC_STATUS_EXEC_SIGNAL,
  228. +   BC_STATUS_EXEC_STACK,
  229. +
  230. +   BC_STATUS_VEC_OUT_OF_BOUNDS,
  231. +   BC_STATUS_VEC_ITEM_EXISTS,
  232. +
  233. +#ifdef CONFIG_BC
  234. +   BC_STATUS_POSIX_NAME_LEN,
  235. +   BC_STATUS_POSIX_COMMENT,
  236. +   BC_STATUS_POSIX_BAD_KW,
  237. +   BC_STATUS_POSIX_DOT,
  238. +   BC_STATUS_POSIX_RET_PARENS,
  239. +   BC_STATUS_POSIX_BOOL_OPS,
  240. +   BC_STATUS_POSIX_REL_POS,
  241. +   BC_STATUS_POSIX_MULTIPLE_REL,
  242. +   BC_STATUS_POSIX_FOR_INIT,
  243. +   BC_STATUS_POSIX_FOR_COND,
  244. +   BC_STATUS_POSIX_FOR_END,
  245. +   BC_STATUS_POSIX_BRACE,
  246. +#endif // CONFIG_BC
  247. +
  248. +   BC_STATUS_QUIT,
  249. +   BC_STATUS_LIMITS,
  250. +
  251. +   BC_STATUS_INVALID_OPTION,
  252. +
  253. +} BcStatus;
  254. +
  255. +#define BC_ERR_IDX_VM (0)
  256. +#define BC_ERR_IDX_LEX (1)
  257. +#define BC_ERR_IDX_PARSE (2)
  258. +#define BC_ERR_IDX_MATH (3)
  259. +#define BC_ERR_IDX_EXEC (4)
  260. +#define BC_ERR_IDX_VEC (5)
  261. +#ifdef CONFIG_BC
  262. +#define BC_ERR_IDX_POSIX (6)
  263. +#endif // CONFIG_BC
  264. +
  265. +#define BC_VEC_INVALID_IDX ((size_t) -1)
  266. +#define BC_VEC_START_CAP (1<<5)
  267. +
  268. +typedef void (*BcVecFree)(void*);
  269. +typedef int (*BcVecCmp)(const void*, const void*);
  270. +
  271. +typedef struct BcVec {
  272. +
  273. +   char *v;
  274. +   size_t len;
  275. +   size_t cap;
  276. +   size_t size;
  277. +
  278. +   BcVecFree dtor;
  279. +
  280. +} BcVec;
  281. +
  282. +BcStatus bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor);
  283. +BcStatus bc_vec_expand(BcVec *v, size_t req);
  284. +
  285. +void bc_vec_npop(BcVec *v, size_t n);
  286. +
  287. +BcStatus bc_vec_push(BcVec *v, const void *data);
  288. +BcStatus bc_vec_pushByte(BcVec *v, uint8_t data);
  289. +BcStatus bc_vec_string(BcVec *v, size_t len, const char *str);
  290. +BcStatus bc_vec_concat(BcVec *v, const char *str);
  291. +
  292. +void* bc_vec_item(const BcVec *v, size_t idx);
  293. +void* bc_vec_item_rev(const BcVec *v, size_t idx);
  294. +
  295. +void bc_vec_free(void *vec);
  296. +
  297. +#define bc_vec_pop(v) (bc_vec_npop((v), 1))
  298. +#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
  299. +
  300. +BcStatus bc_map_insert(BcVec* v, const void *data, size_t *i);
  301. +size_t bc_map_index(const BcVec *v, const void *ptr);
  302. +
  303. +#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
  304. +#define bc_map_item(v, idx) (bc_vec_item((v), (idx)))
  305. +
  306. +BcStatus bc_args(int argc, char *argv[], unsigned int* flags,
  307. +                 BcVec* exprs, BcVec* files);
  308. +
  309. +BcStatus bc_read_line(BcVec* vec, const char *prompt);
  310. +BcStatus bc_read_file(const char *path, char **buf);
  311. +
  312. +#define BC_IO_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
  313. +
  314. +typedef signed char BcDig;
  315. +
  316. +typedef struct BcNum {
  317. +
  318. +  BcDig *restrict num;
  319. +  size_t rdx;
  320. +  size_t len;
  321. +  size_t cap;
  322. +  bool neg;
  323. +
  324. +} BcNum;
  325. +
  326. +#define BC_NUM_MIN_BASE ((unsigned long) 2)
  327. +#define BC_NUM_MAX_IBASE ((unsigned long) 16)
  328. +#define BC_NUM_DEF_SIZE (16)
  329. +#define BC_NUM_PRINT_WIDTH (69)
  330. +
  331. +#ifndef BC_NUM_KARATSUBA_LEN
  332. +#define BC_NUM_KARATSUBA_LEN (32)
  333. +#elif BC_NUM_KARATSUBA_LEN < 2
  334. +#error BC_NUM_KARATSUBA_LEN must be at least 2
  335. +#endif // BC_NUM_KARATSUBA_LEN
  336. +
  337. +#define BC_NUM_NEG(n, neg) ((((ssize_t) (n)) ^ -((ssize_t) (neg))) + (neg))
  338. +#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
  339. +#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
  340. +#define BC_NUM_AREQ(a, b) \
  341. +   (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
  342. +#define BC_NUM_MREQ(a, b, scale) \
  343. +   (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
  344. +
  345. +typedef BcStatus (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t);
  346. +typedef BcStatus (*BcNumDigitOp)(size_t, size_t, bool, size_t*, size_t);
  347. +
  348. +BcStatus bc_num_init(BcNum *n, size_t request);
  349. +BcStatus bc_num_expand(BcNum *n, size_t req);
  350. +BcStatus bc_num_copy(BcNum *d, BcNum *s);
  351. +void bc_num_free(void *num);
  352. +
  353. +BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
  354. +BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
  355. +
  356. +void bc_num_truncate(BcNum *n, size_t places);
  357. +ssize_t bc_num_cmp(BcNum *a, BcNum *b);
  358. +
  359. +BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  360. +BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  361. +BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  362. +BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  363. +BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  364. +BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
  365. +BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
  366. +BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale);
  367. +
  368. +#ifdef CONFIG_DC
  369. +BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d);
  370. +#endif // CONFIG_DC
  371. +
  372. +void bc_num_zero(BcNum *n);
  373. +void bc_num_one(BcNum *n);
  374. +void bc_num_ten(BcNum *n);
  375. +
  376. +BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, size_t base_t);
  377. +BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
  378. +                      size_t *nchars, size_t line_len);
  379. +BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len);
  380. +
  381. +typedef enum BcInst {
  382. +
  383. +   BC_INST_INC_PRE,
  384. +   BC_INST_DEC_PRE,
  385. +   BC_INST_INC_POST,
  386. +   BC_INST_DEC_POST,
  387. +
  388. +   BC_INST_NEG,
  389. +
  390. +   BC_INST_POWER,
  391. +   BC_INST_MULTIPLY,
  392. +   BC_INST_DIVIDE,
  393. +   BC_INST_MODULUS,
  394. +   BC_INST_PLUS,
  395. +   BC_INST_MINUS,
  396. +
  397. +   BC_INST_REL_EQ,
  398. +   BC_INST_REL_LE,
  399. +   BC_INST_REL_GE,
  400. +   BC_INST_REL_NE,
  401. +   BC_INST_REL_LT,
  402. +   BC_INST_REL_GT,
  403. +
  404. +   BC_INST_BOOL_NOT,
  405. +   BC_INST_BOOL_OR,
  406. +   BC_INST_BOOL_AND,
  407. +
  408. +   BC_INST_ASSIGN_POWER,
  409. +   BC_INST_ASSIGN_MULTIPLY,
  410. +   BC_INST_ASSIGN_DIVIDE,
  411. +   BC_INST_ASSIGN_MODULUS,
  412. +   BC_INST_ASSIGN_PLUS,
  413. +   BC_INST_ASSIGN_MINUS,
  414. +   BC_INST_ASSIGN,
  415. +
  416. +   BC_INST_NUM,
  417. +   BC_INST_VAR,
  418. +   BC_INST_ARRAY_ELEM,
  419. +   BC_INST_ARRAY,
  420. +
  421. +   BC_INST_CALL,
  422. +
  423. +   BC_INST_SCALE_FUNC,
  424. +   BC_INST_IBASE,
  425. +   BC_INST_SCALE,
  426. +   BC_INST_LAST,
  427. +   BC_INST_LENGTH,
  428. +   BC_INST_READ,
  429. +   BC_INST_OBASE,
  430. +   BC_INST_SQRT,
  431. +
  432. +   BC_INST_PRINT,
  433. +   BC_INST_PRINT_POP,
  434. +   BC_INST_STR,
  435. +   BC_INST_PRINT_STR,
  436. +
  437. +   BC_INST_JUMP,
  438. +   BC_INST_JUMP_ZERO,
  439. +
  440. +   BC_INST_POP,
  441. +
  442. +   BC_INST_RET,
  443. +   BC_INST_RET0,
  444. +   BC_INST_POP_EXEC,
  445. +
  446. +   BC_INST_HALT,
  447. +
  448. +#ifdef CONFIG_DC
  449. +   BC_INST_MODEXP,
  450. +   BC_INST_DIVMOD,
  451. +
  452. +   BC_INST_EXECUTE,
  453. +   BC_INST_EXEC_COND,
  454. +
  455. +   BC_INST_ASCIIFY,
  456. +   BC_INST_PRINT_STREAM,
  457. +
  458. +   BC_INST_PRINT_STACK,
  459. +   BC_INST_CLEAR_STACK,
  460. +   BC_INST_STACK_LEN,
  461. +   BC_INST_DUPLICATE,
  462. +   BC_INST_SWAP,
  463. +
  464. +   BC_INST_LOAD,
  465. +   BC_INST_PUSH_VAR,
  466. +   BC_INST_PUSH_TO_VAR,
  467. +
  468. +   BC_INST_QUIT,
  469. +   BC_INST_NQUIT,
  470. +
  471. +   BC_INST_INVALID = -1,
  472. +#endif // CONFIG_DC
  473. +
  474. +} BcInst;
  475. +
  476. +typedef struct BcId {
  477. +
  478. +   char *name;
  479. +   size_t idx;
  480. +
  481. +} BcId;
  482. +
  483. +typedef struct BcFunc {
  484. +
  485. +   BcVec code;
  486. +   BcVec labels;
  487. +   size_t nparams;
  488. +   BcVec autos;
  489. +
  490. +} BcFunc;
  491. +
  492. +typedef enum BcResultType {
  493. +
  494. +   BC_RESULT_TEMP,
  495. +
  496. +   BC_RESULT_VAR,
  497. +   BC_RESULT_ARRAY_ELEM,
  498. +   BC_RESULT_ARRAY,
  499. +
  500. +   BC_RESULT_STR,
  501. +
  502. +   BC_RESULT_IBASE,
  503. +   BC_RESULT_SCALE,
  504. +   BC_RESULT_LAST,
  505. +
  506. +   // These are between to calculate ibase, obase, and last from instructions.
  507. +   BC_RESULT_CONSTANT,
  508. +   BC_RESULT_ONE,
  509. +
  510. +   BC_RESULT_OBASE,
  511. +
  512. +} BcResultType;
  513. +
  514. +typedef union BcResultData {
  515. +
  516. +   BcNum n;
  517. +   BcVec v;
  518. +   BcId id;
  519. +
  520. +} BcResultData;
  521. +
  522. +typedef struct BcResult {
  523. +
  524. +   BcResultType t;
  525. +   BcResultData d;
  526. +
  527. +} BcResult;
  528. +
  529. +typedef struct BcInstPtr {
  530. +
  531. +   size_t func;
  532. +   size_t idx;
  533. +   size_t len;
  534. +
  535. +} BcInstPtr;
  536. +
  537. +BcStatus bc_func_init(BcFunc *f);
  538. +BcStatus bc_func_insert(BcFunc *f, char *name, bool var);
  539. +void bc_func_free(void *func);
  540. +
  541. +BcStatus bc_array_init(BcVec *a, bool nums);
  542. +BcStatus bc_array_copy(BcVec *d, const BcVec *s);
  543. +
  544. +BcStatus bc_array_expand(BcVec *a, size_t len);
  545. +
  546. +void bc_string_free(void *string);
  547. +void bc_id_free(void *id);
  548. +BcStatus bc_result_copy(BcResult *d, BcResult *src);
  549. +void bc_result_free(void *result);
  550. +
  551. +int bc_id_cmp(const void *e1, const void *e2);
  552. +
  553. +// BC_LEX_NEG is not used in lexing; it is only for parsing.
  554. +typedef enum BcLexType {
  555. +
  556. +   BC_LEX_EOF,
  557. +   BC_LEX_INVALID,
  558. +
  559. +   BC_LEX_OP_INC,
  560. +   BC_LEX_OP_DEC,
  561. +
  562. +   BC_LEX_NEG,
  563. +
  564. +   BC_LEX_OP_POWER,
  565. +   BC_LEX_OP_MULTIPLY,
  566. +   BC_LEX_OP_DIVIDE,
  567. +   BC_LEX_OP_MODULUS,
  568. +   BC_LEX_OP_PLUS,
  569. +   BC_LEX_OP_MINUS,
  570. +
  571. +   BC_LEX_OP_REL_EQ,
  572. +   BC_LEX_OP_REL_LE,
  573. +   BC_LEX_OP_REL_GE,
  574. +   BC_LEX_OP_REL_NE,
  575. +   BC_LEX_OP_REL_LT,
  576. +   BC_LEX_OP_REL_GT,
  577. +
  578. +   BC_LEX_OP_BOOL_NOT,
  579. +   BC_LEX_OP_BOOL_OR,
  580. +   BC_LEX_OP_BOOL_AND,
  581. +
  582. +   BC_LEX_OP_ASSIGN_POWER,
  583. +   BC_LEX_OP_ASSIGN_MULTIPLY,
  584. +   BC_LEX_OP_ASSIGN_DIVIDE,
  585. +   BC_LEX_OP_ASSIGN_MODULUS,
  586. +   BC_LEX_OP_ASSIGN_PLUS,
  587. +   BC_LEX_OP_ASSIGN_MINUS,
  588. +   BC_LEX_OP_ASSIGN,
  589. +
  590. +   BC_LEX_NLINE,
  591. +
  592. +   BC_LEX_WHITESPACE,
  593. +
  594. +   BC_LEX_LPAREN,
  595. +   BC_LEX_RPAREN,
  596. +
  597. +   BC_LEX_LBRACKET,
  598. +   BC_LEX_COMMA,
  599. +   BC_LEX_RBRACKET,
  600. +
  601. +   BC_LEX_LBRACE,
  602. +   BC_LEX_SCOLON,
  603. +   BC_LEX_RBRACE,
  604. +
  605. +   BC_LEX_STR,
  606. +   BC_LEX_NAME,
  607. +   BC_LEX_NUMBER,
  608. +
  609. +   BC_LEX_KEY_AUTO,
  610. +   BC_LEX_KEY_BREAK,
  611. +   BC_LEX_KEY_CONTINUE,
  612. +   BC_LEX_KEY_DEFINE,
  613. +   BC_LEX_KEY_ELSE,
  614. +   BC_LEX_KEY_FOR,
  615. +   BC_LEX_KEY_HALT,
  616. +   BC_LEX_KEY_IBASE,
  617. +   BC_LEX_KEY_IF,
  618. +   BC_LEX_KEY_LAST,
  619. +   BC_LEX_KEY_LENGTH,
  620. +   BC_LEX_KEY_LIMITS,
  621. +   BC_LEX_KEY_OBASE,
  622. +   BC_LEX_KEY_PRINT,
  623. +   BC_LEX_KEY_QUIT,
  624. +   BC_LEX_KEY_READ,
  625. +   BC_LEX_KEY_RETURN,
  626. +   BC_LEX_KEY_SCALE,
  627. +   BC_LEX_KEY_SQRT,
  628. +   BC_LEX_KEY_WHILE,
  629. +
  630. +#ifdef CONFIG_DC
  631. +   BC_LEX_EQ_NO_REG,
  632. +   BC_LEX_OP_MODEXP,
  633. +   BC_LEX_OP_DIVMOD,
  634. +
  635. +   BC_LEX_COLON,
  636. +   BC_LEX_ELSE,
  637. +   BC_LEX_EXECUTE,
  638. +   BC_LEX_PRINT_STACK,
  639. +   BC_LEX_CLEAR_STACK,
  640. +   BC_LEX_STACK_LEVEL,
  641. +   BC_LEX_DUPLICATE,
  642. +   BC_LEX_SWAP,
  643. +   BC_LEX_POP,
  644. +
  645. +   BC_LEX_ASCIIFY,
  646. +   BC_LEX_PRINT_STREAM,
  647. +
  648. +   BC_LEX_STORE_IBASE,
  649. +   BC_LEX_STORE_SCALE,
  650. +   BC_LEX_LOAD,
  651. +   BC_LEX_LOAD_POP,
  652. +   BC_LEX_STORE_PUSH,
  653. +   BC_LEX_STORE_OBASE,
  654. +   BC_LEX_PRINT_POP,
  655. +   BC_LEX_NQUIT,
  656. +   BC_LEX_SCALE_FACTOR,
  657. +#endif // CONFIG_DC
  658. +
  659. +} BcLexType;
  660. +
  661. +struct BcLex;
  662. +typedef BcStatus (*BcLexNext)(struct BcLex*);
  663. +
  664. +typedef struct BcLex {
  665. +
  666. +   const char *buffer;
  667. +   size_t idx;
  668. +   size_t line;
  669. +   const char *f;
  670. +   size_t len;
  671. +   bool newline;
  672. +
  673. +   struct {
  674. +       BcLexType t;
  675. +       BcLexType last;
  676. +       BcVec v;
  677. +   } t;
  678. +
  679. +   BcLexNext next;
  680. +
  681. +} BcLex;
  682. +
  683. +BcStatus bc_lex_init(BcLex *l, BcLexNext next);
  684. +void bc_lex_free(BcLex *l);
  685. +void bc_lex_file(BcLex *l, const char *file);
  686. +BcStatus bc_lex_text(BcLex *l, const char *text);
  687. +BcStatus bc_lex_next(BcLex *l);
  688. +
  689. +void bc_lex_lineComment(BcLex *l);
  690. +void bc_lex_whitespace(BcLex *l);
  691. +BcStatus bc_lex_number(BcLex *l, char start);
  692. +BcStatus bc_lex_name(BcLex *l);
  693. +
  694. +#define BC_PARSE_STREND ((char) UCHAR_MAX)
  695. +
  696. +#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (uint8_t) (i)))
  697. +#define bc_parse_updateFunc(p, f) \
  698. +   ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
  699. +
  700. +#define BC_PARSE_REL (1<<0)
  701. +#define BC_PARSE_PRINT (1<<1)
  702. +#define BC_PARSE_NOCALL (1<<2)
  703. +#define BC_PARSE_NOREAD (1<<3)
  704. +#define BC_PARSE_ARRAY (1<<4)
  705. +
  706. +#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t*) bc_vec_top(&(parse)->flags))
  707. +#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
  708. +
  709. +#define BC_PARSE_FLAG_FUNC_INNER (1<<0)
  710. +#define BC_PARSE_FUNC_INNER(parse) \
  711. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
  712. +
  713. +#define BC_PARSE_FLAG_FUNC (1<<1)
  714. +#define BC_PARSE_FUNC(parse) \
  715. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
  716. +
  717. +#define BC_PARSE_FLAG_BODY (1<<2)
  718. +#define BC_PARSE_BODY(parse) \
  719. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
  720. +
  721. +#define BC_PARSE_FLAG_LOOP (1<<3)
  722. +#define BC_PARSE_LOOP(parse) \
  723. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
  724. +
  725. +#define BC_PARSE_FLAG_LOOP_INNER (1<<4)
  726. +#define BC_PARSE_LOOP_INNER(parse) \
  727. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
  728. +
  729. +#define BC_PARSE_FLAG_IF (1<<5)
  730. +#define BC_PARSE_IF(parse) \
  731. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
  732. +
  733. +#define BC_PARSE_FLAG_ELSE (1<<6)
  734. +#define BC_PARSE_ELSE(parse) \
  735. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
  736. +
  737. +#define BC_PARSE_FLAG_IF_END (1<<7)
  738. +#define BC_PARSE_IF_END(parse) \
  739. +   (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
  740. +
  741. +#define BC_PARSE_CAN_EXEC(parse) \
  742. +   (!(BC_PARSE_TOP_FLAG(parse) & (BC_PARSE_FLAG_FUNC_INNER |  \
  743. +                                  BC_PARSE_FLAG_FUNC |        \
  744. +                                  BC_PARSE_FLAG_BODY |        \
  745. +                                  BC_PARSE_FLAG_LOOP |        \
  746. +                                  BC_PARSE_FLAG_LOOP_INNER |  \
  747. +                                  BC_PARSE_FLAG_IF |          \
  748. +                                  BC_PARSE_FLAG_ELSE |        \
  749. +                                  BC_PARSE_FLAG_IF_END)))
  750. +
  751. +typedef struct BcOp {
  752. +
  753. +   uint8_t prec;
  754. +   bool left;
  755. +
  756. +} BcOp;
  757. +
  758. +typedef struct BcParseNext {
  759. +
  760. +   uint32_t len;
  761. +   BcLexType tokens[3];
  762. +
  763. +} BcParseNext;
  764. +
  765. +#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
  766. +#define BC_PARSE_NEXT(a, ...) { .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }
  767. +
  768. +struct BcParse;
  769. +
  770. +struct BcProgram;
  771. +
  772. +typedef BcStatus (*BcParseInit)(struct BcParse*, struct BcProgram*, size_t);
  773. +typedef BcStatus (*BcParseParse)(struct BcParse*);
  774. +typedef BcStatus (*BcParseExpr)(struct BcParse*, uint8_t);
  775. +
  776. +typedef struct BcParse {
  777. +
  778. +   BcParseParse parse;
  779. +
  780. +   BcLex l;
  781. +
  782. +   BcVec flags;
  783. +
  784. +   BcVec exits;
  785. +   BcVec conds;
  786. +
  787. +   BcVec ops;
  788. +
  789. +   struct BcProgram *prog;
  790. +   BcFunc *func;
  791. +   size_t fidx;
  792. +
  793. +   size_t nbraces;
  794. +   bool auto_part;
  795. +
  796. +} BcParse;
  797. +
  798. +BcStatus bc_parse_create(BcParse *p, struct BcProgram *prog, size_t func,
  799. +                         BcParseParse parse, BcLexNext next);
  800. +void bc_parse_free(BcParse *p);
  801. +BcStatus bc_parse_reset(BcParse *p, BcStatus s);
  802. +
  803. +BcStatus bc_parse_addFunc(BcParse *p, char *name, size_t *idx);
  804. +BcStatus bc_parse_pushName(BcParse* p, char *name);
  805. +BcStatus bc_parse_pushIndex(BcParse* p, size_t idx);
  806. +BcStatus bc_parse_number(BcParse *p, BcInst *prev, size_t* nexs);
  807. +BcStatus bc_parse_text(BcParse *p, const char *text);
  808. +
  809. +#ifdef CONFIG_BC
  810. +
  811. +#endif // CONFIG_BC
  812. +
  813. +#ifdef CONFIG_BC
  814. +
  815. +BcStatus bc_main(int argc, char *argv[]);
  816. +
  817. +typedef struct BcLexKeyword {
  818. +
  819. +   const char name[9];
  820. +   const char len;
  821. +   const bool posix;
  822. +
  823. +} BcLexKeyword;
  824. +
  825. +#define BC_LEX_KW_ENTRY(a, b, c) { .name = a, .len = (b), .posix = (c) }
  826. +
  827. +BcStatus bc_lex_token(BcLex *l);
  828. +
  829. +#define BC_PARSE_LEAF(p, rparen) \
  830. +   (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
  831. +   (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
  832. +
  833. +// We can calculate the conversion between tokens and exprs by subtracting the
  834. +// position of the first operator in the lex enum and adding the position of the
  835. +// first in the expr enum. Note: This only works for binary operators.
  836. +#define BC_PARSE_TOKEN_INST(t) ((char) ((t) - BC_LEX_NEG + BC_INST_NEG))
  837. +
  838. +BcStatus bc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
  839. +BcStatus bc_parse_expression(BcParse *p, uint8_t flags);
  840. +
  841. +BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
  842. +
  843. +#endif // CONFIG_BC
  844. +
  845. +#ifdef CONFIG_DC
  846. +
  847. +#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
  848. +
  849. +BcStatus dc_main(int argc, char *argv[]);
  850. +
  851. +BcStatus dc_lex_token(BcLex *l);
  852. +
  853. +BcStatus dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
  854. +BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
  855. +
  856. +#endif // CONFIG_DC
  857. +
  858. +typedef struct BcProgram {
  859. +
  860. +   size_t len;
  861. +
  862. +   size_t scale;
  863. +
  864. +   BcNum ib;
  865. +   size_t ib_t;
  866. +   BcNum ob;
  867. +   size_t ob_t;
  868. +
  869. +   BcNum hexb;
  870. +
  871. +#ifdef CONFIG_DC
  872. +   BcNum strmb;
  873. +#endif // CONFIG_DC
  874. +
  875. +   BcVec results;
  876. +   BcVec stack;
  877. +
  878. +   BcVec fns;
  879. +   BcVec fn_map;
  880. +
  881. +   BcVec vars;
  882. +   BcVec var_map;
  883. +
  884. +   BcVec arrs;
  885. +   BcVec arr_map;
  886. +
  887. +   BcVec strs;
  888. +   BcVec consts;
  889. +
  890. +   const char *file;
  891. +
  892. +   BcNum last;
  893. +   BcNum zero;
  894. +   BcNum one;
  895. +
  896. +   size_t nchars;
  897. +
  898. +   BcParseInit parse_init;
  899. +   BcParseExpr parse_expr;
  900. +
  901. +} BcProgram;
  902. +
  903. +#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
  904. +
  905. +#define BC_PROG_MAIN (0)
  906. +#define BC_PROG_READ (1)
  907. +
  908. +#ifdef CONFIG_DC
  909. +#define BC_PROG_REQ_FUNCS (2)
  910. +#endif // CONFIG_DC
  911. +
  912. +#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
  913. +#define BC_PROG_NUM(r, n) \
  914. +   ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
  915. +
  916. +typedef unsigned long (*BcProgramBuiltIn)(BcNum*);
  917. +
  918. +BcStatus bc_program_init(BcProgram *p, size_t line_len,
  919. +                         BcParseInit init, BcParseExpr expr);
  920. +void bc_program_free(BcProgram *program);
  921. +
  922. +BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
  923. +BcStatus bc_program_reset(BcProgram *p, BcStatus s);
  924. +BcStatus bc_program_exec(BcProgram *p);
  925. +
  926. +#if !defined(CONFIG_BC) && !defined(CONFIG_DC)
  927. +#error Must define CONFIG_BC, CONFIG_DC, or both
  928. +#endif
  929. +
  930. +#define VERSION_STR(V) #V
  931. +#define VERSION_STR2(V) VERSION_STR(V)
  932. +#define BC_VERSION VERSION_STR2(VERSION)
  933. +
  934. +#define BC_FLAG_X (1<<0)
  935. +#define BC_FLAG_W (1<<1)
  936. +#define BC_FLAG_S (1<<2)
  937. +#define BC_FLAG_Q (1<<3)
  938. +#define BC_FLAG_L (1<<4)
  939. +#define BC_FLAG_I (1<<5)
  940. +
  941. +#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
  942. +#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
  943. +
  944. +#define BC_MAX_OBASE ((unsigned long) 999)
  945. +#define BC_MAX_DIM ((unsigned long) INT_MAX)
  946. +#define BC_MAX_SCALE ((unsigned long) UINT_MAX)
  947. +#define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
  948. +#define BC_MAX_NAME BC_MAX_STRING
  949. +#define BC_MAX_NUM BC_MAX_STRING
  950. +#define BC_MAX_EXP ((unsigned long) LONG_MAX)
  951. +#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
  952. +
  953. +typedef struct BcVmExe {
  954. +
  955. +   BcParseInit init;
  956. +   BcParseExpr exp;
  957. +
  958. +   char sbgn;
  959. +   char send;
  960. +
  961. +} BcVmExe;
  962. +
  963. +typedef struct BcVm {
  964. +
  965. +   BcParse prs;
  966. +   BcProgram prog;
  967. +
  968. +   unsigned int flags;
  969. +
  970. +   BcVec files;
  971. +   BcVec exprs;
  972. +
  973. +   char *env_args;
  974. +
  975. +   BcVmExe exe;
  976. +
  977. +} BcVm;
  978. +
  979. +typedef struct BcGlobals {
  980. +
  981. +   unsigned long sig;
  982. +   unsigned long sigc;
  983. +   unsigned long signe;
  984. +   long sig_other;
  985. +
  986. +   long tty;
  987. +   long ttyin;
  988. +#ifdef CONFIG_BC
  989. +   long posix;
  990. +   long warn;
  991. +#endif // CONFIG_BC
  992. +#ifdef CONFIG_DC
  993. +   long exreg;
  994. +#endif // CONFIG_DC
  995. +
  996. +   const char *name;
  997. +   const char *sig_msg;
  998. +   // Busybox exclude start.
  999. +   const char *help;
  1000. +   // Busybox exclude end.
  1001. +   bool bc;
  1002. +
  1003. +} BcGlobals;
  1004. +
  1005. +#ifdef CONFIG_BC
  1006. +BcStatus bc_vm_posixError(BcStatus s, const char *file,
  1007. +                          size_t line, const char *msg);
  1008. +#endif // CONFIG_BC
  1009. +
  1010. +BcStatus bc_vm_info(const char* const help);
  1011. +BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe, const char *env_len);
  1012. +
  1013. +#ifdef CONFIG_BC
  1014. +
  1015. +#endif // CONFIG_BC
  1016. +
  1017. +#ifdef CONFIG_DC
  1018. +
  1019. +#endif // CONFIG_DC
  1020. +
  1021. +BcGlobals bcg;
  1022. +
  1023. +#ifdef CONFIG_BC
  1024. +
  1025. +const char bc_name[] = "bc";
  1026. +
  1027. +const char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
  1028. +#endif // CONFIG_BC
  1029. +
  1030. +#ifdef CONFIG_DC
  1031. +const char dc_name[] = "dc";
  1032. +const char dc_sig_msg[] = "\ninterrupt (type \"q\" to exit)\n";
  1033. +#endif // CONFIG_DC
  1034. +
  1035. +const char bc_copyright[] =
  1036. +   "Copyright (c) 2018 Gavin D. Howard and contributors\n"
  1037. +   "Report bugs at: https://github.com/gavinhoward/bc\n\n"
  1038. +   "This is free software with ABSOLUTELY NO WARRANTY.\n";
  1039. +
  1040. +const char* const bc_args_env_name = "BC_ENV_ARGS";
  1041. +
  1042. +const char bc_err_fmt[] = "\n%s error: %s\n";
  1043. +const char bc_warn_fmt[] = "\n%s warning: %s\n";
  1044. +const char bc_err_line[] = ":%zu\n\n";
  1045. +
  1046. +const char *bc_errs[] = {
  1047. +   "VM",
  1048. +   "Lex",
  1049. +   "Parse",
  1050. +   "Math",
  1051. +   "Runtime",
  1052. +   "Vector",
  1053. +#ifdef CONFIG_BC
  1054. +   "POSIX",
  1055. +#endif // CONFIG_BC
  1056. +};
  1057. +
  1058. +const uint8_t bc_err_ids[] = {
  1059. +   BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
  1060. +   BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
  1061. +#ifdef CONFIG_DC
  1062. +   BC_ERR_IDX_LEX,
  1063. +#endif // CONFIG_DC
  1064. +   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
  1065. +   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
  1066. +   BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
  1067. +   BC_ERR_IDX_MATH,
  1068. +#ifdef CONFIG_DC
  1069. +   BC_ERR_IDX_MATH,
  1070. +#endif // CONFIG_DC
  1071. +   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
  1072. +   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
  1073. +   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
  1074. +   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
  1075. +   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
  1076. +   BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
  1077. +#ifdef CONFIG_BC
  1078. +   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
  1079. +   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
  1080. +   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
  1081. +#endif // CONFIG_BC
  1082. +   BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
  1083. +};
  1084. +
  1085. +const char *bc_err_msgs[] = {
  1086. +
  1087. +   NULL,
  1088. +   "memory allocation error",
  1089. +   "I/O error",
  1090. +   "file is not text:",
  1091. +   "path is a directory:",
  1092. +
  1093. +   "bad character",
  1094. +   "string end could not be found",
  1095. +   "comment end could not be found",
  1096. +   "end of file",
  1097. +#ifdef CONFIG_DC
  1098. +   "extended register",
  1099. +#endif // CONFIG_DC
  1100. +
  1101. +   "bad token",
  1102. +   "bad expression",
  1103. +   "empty expression",
  1104. +   "bad print statement",
  1105. +   "bad function definition",
  1106. +   "bad assignment: left side must be scale, ibase, "
  1107. +       "obase, last, var, or array element",
  1108. +   "no auto variable found",
  1109. +   "function parameter or auto var has the same name as another",
  1110. +   "block end could not be found",
  1111. +
  1112. +   "negative number",
  1113. +   "non integer number",
  1114. +   "overflow",
  1115. +   "divide by zero",
  1116. +   "bad number string",
  1117. +
  1118. +   "could not open file:",
  1119. +   "mismatched parameters",
  1120. +   "undefined function",
  1121. +   "file is not executable:",
  1122. +   "could not install signal handler",
  1123. +   "number too long: must be [1, BC_NUM_MAX]",
  1124. +   "name too long: must be [1, BC_NAME_MAX]",
  1125. +   "string too long: must be [1, BC_STRING_MAX]",
  1126. +   "array too long; must be [1, BC_DIM_MAX]",
  1127. +   "bad ibase; must be [2, 16]",
  1128. +   "bad scale; must be [0, BC_SCALE_MAX]",
  1129. +   "bad read() expression",
  1130. +   "read() call inside of a read() call",
  1131. +   "variable is wrong type",
  1132. +   "bad obase; must be [2, BC_BASE_MAX]",
  1133. +   "signal caught and not handled",
  1134. +   "stack has too few elements",
  1135. +
  1136. +   "index is out of bounds",
  1137. +   "item already exists",
  1138. +
  1139. +#ifdef CONFIG_BC
  1140. +   "POSIX only allows one character names; the following is bad:",
  1141. +   "POSIX does not allow '#' script comments",
  1142. +   "POSIX does not allow the following keyword:",
  1143. +   "POSIX does not allow a period ('.') as a shortcut for the last result",
  1144. +   "POSIX requires parentheses around return expressions",
  1145. +   "POSIX does not allow boolean operators; the following is bad:",
  1146. +   "POSIX does not allow comparison operators outside if or loops",
  1147. +   "POSIX requires exactly one comparison operator per condition",
  1148. +   "POSIX does not allow an empty init expression in a for loop",
  1149. +   "POSIX does not allow an empty condition expression in a for loop",
  1150. +   "POSIX does not allow an empty update expression in a for loop",
  1151. +   "POSIX requires the left brace be on the same line as the function header",
  1152. +#endif // CONFIG_BC
  1153. +
  1154. +};
  1155. +
  1156. +const char bc_func_main[] = "(main)";
  1157. +const char bc_func_read[] = "(read)";
  1158. +
  1159. +#ifdef CONFIG_BC
  1160. +const BcLexKeyword bc_lex_kws[20] = {
  1161. +   BC_LEX_KW_ENTRY("auto", 4, true),
  1162. +   BC_LEX_KW_ENTRY("break", 5, true),
  1163. +   BC_LEX_KW_ENTRY("continue", 8, false),
  1164. +   BC_LEX_KW_ENTRY("define", 6, true),
  1165. +   BC_LEX_KW_ENTRY("else", 4, false),
  1166. +   BC_LEX_KW_ENTRY("for", 3, true),
  1167. +   BC_LEX_KW_ENTRY("halt", 4, false),
  1168. +   BC_LEX_KW_ENTRY("ibase", 5, true),
  1169. +   BC_LEX_KW_ENTRY("if", 2, true),
  1170. +   BC_LEX_KW_ENTRY("last", 4, false),
  1171. +   BC_LEX_KW_ENTRY("length", 6, true),
  1172. +   BC_LEX_KW_ENTRY("limits", 6, false),
  1173. +   BC_LEX_KW_ENTRY("obase", 5, true),
  1174. +   BC_LEX_KW_ENTRY("print", 5, false),
  1175. +   BC_LEX_KW_ENTRY("quit", 4, true),
  1176. +   BC_LEX_KW_ENTRY("read", 4, false),
  1177. +   BC_LEX_KW_ENTRY("return", 6, true),
  1178. +   BC_LEX_KW_ENTRY("scale", 5, true),
  1179. +   BC_LEX_KW_ENTRY("sqrt", 4, true),
  1180. +   BC_LEX_KW_ENTRY("while", 5, true),
  1181. +};
  1182. +
  1183. +// This is an array that corresponds to token types. An entry is
  1184. +// true if the token is valid in an expression, false otherwise.
  1185. +const bool bc_parse_exprs[] = {
  1186. +   false, false, true, true, true, true, true, true, true, true, true, true,
  1187. +   true, true, true, true, true, true, true, true, true, true, true, true,
  1188. +   true, true, true, false, false, true, true, false, false, false, false,
  1189. +   false, false, false, true, true, false, false, false, false, false, false,
  1190. +   false, true, false, true, true, true, true, false, false, true, false, true,
  1191. +   true, false,
  1192. +};
  1193. +
  1194. +// This is an array of data for operators that correspond to token types.
  1195. +const BcOp bc_parse_ops[] = {
  1196. +   { 0, false }, { 0, false },
  1197. +   { 1, false },
  1198. +   { 2, false },
  1199. +   { 3, true }, { 3, true }, { 3, true },
  1200. +   { 4, true }, { 4, true },
  1201. +   { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
  1202. +   { 1, false },
  1203. +   { 7, true }, { 7, true },
  1204. +   { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
  1205. +   { 5, false }, { 5, false },
  1206. +};
  1207. +
  1208. +// These identify what tokens can come after expressions in certain cases.
  1209. +const BcParseNext bc_parse_next_expr =
  1210. +   BC_PARSE_NEXT(3, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE);
  1211. +const BcParseNext bc_parse_next_param =
  1212. +   BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
  1213. +const BcParseNext bc_parse_next_print =
  1214. +   BC_PARSE_NEXT(3, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON);
  1215. +const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
  1216. +const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
  1217. +const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
  1218. +const BcParseNext bc_parse_next_read = BC_PARSE_NEXT(1, BC_LEX_NLINE);
  1219. +#endif // CONFIG_BC
  1220. +
  1221. +#ifdef CONFIG_DC
  1222. +const BcLexType dc_lex_regs[] = {
  1223. +   BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
  1224. +   BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
  1225. +   BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
  1226. +   BC_LEX_STORE_PUSH,
  1227. +};
  1228. +
  1229. +const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
  1230. +
  1231. +const BcLexType dc_lex_tokens[] = {
  1232. +   BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
  1233. +   BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
  1234. +   BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
  1235. +   BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
  1236. +   BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
  1237. +   BC_LEX_INVALID, BC_LEX_INVALID,
  1238. +   BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
  1239. +   BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
  1240. +   BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
  1241. +   BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
  1242. +   BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
  1243. +   BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
  1244. +   BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
  1245. +   BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
  1246. +   BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
  1247. +   BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
  1248. +   BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
  1249. +   BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
  1250. +   BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
  1251. +   BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
  1252. +   BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
  1253. +   BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
  1254. +   BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
  1255. +   BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
  1256. +   BC_LEX_INVALID
  1257. +};
  1258. +
  1259. +const BcInst dc_parse_insts[] = {
  1260. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
  1261. +   BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
  1262. +   BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
  1263. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1264. +   BC_INST_INVALID, BC_INST_INVALID,
  1265. +   BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
  1266. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1267. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1268. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
  1269. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
  1270. +   BC_INST_INVALID, BC_INST_INVALID,
  1271. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1272. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1273. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
  1274. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
  1275. +   BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
  1276. +   BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
  1277. +   BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
  1278. +   BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
  1279. +   BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
  1280. +   BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
  1281. +   BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
  1282. +   BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
  1283. +};
  1284. +#endif // CONFIG_DC
  1285. +
  1286. +const char bc_num_hex_digits[] = "0123456789ABCDEF";
  1287. +
  1288. +const BcNumBinaryOp bc_program_ops[] = {
  1289. +   bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
  1290. +};
  1291. +
  1292. +const char bc_program_exprs_name[] = "<exprs>";
  1293. +
  1294. +const char bc_program_stdin_name[] = "<stdin>";
  1295. +const char bc_program_ready_msg[] = "ready for more input\n";
  1296. +#ifdef CONFIG_BC
  1297. +const char *bc_lib_name = "gen/lib.bc";
  1298. +
  1299. +const char bc_lib[] = {
  1300. +  115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
  1301. +  10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
  1302. +  44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
  1303. +  40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
  1304. +  61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
  1305. +  97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
  1306. +  120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
  1307. +  101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
  1308. +  9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
  1309. +  61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
  1310. +  118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
  1311. +  40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
  1312. +  9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
  1313. +  110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
  1314. +  100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
  1315. +  44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
  1316. +  105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
  1317. +  49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
  1318. +  9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
  1319. +  10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
  1320. +  120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
  1321. +  41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
  1322. +  42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
  1323. +  40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
  1324. +  102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
  1325. +  61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
  1326. +  112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
  1327. +  116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
  1328. +  120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
  1329. +  10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
  1330. +  97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
  1331. +  49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
  1332. +  10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
  1333. +  52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
  1334. +  120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
  1335. +  9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
  1336. +  43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
  1337. +  114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
  1338. +  61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
  1339. +  49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
  1340. +  110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
  1341. +  98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
  1342. +  9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
  1343. +  120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
  1344. +  101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
  1345. +  40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
  1346. +  116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
  1347. +  61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
  1348. +  9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
  1349. +  40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
  1350. +  55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
  1351. +  52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
  1352. +  54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
  1353. +  9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
  1354. +  54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
  1355. +  57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
  1356. +  50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
  1357. +  56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
  1358. +  10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
  1359. +  9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
  1360. +  104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
  1361. +  120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
  1362. +  10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
  1363. +  33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
  1364. +  10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
  1365. +  115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
  1366. +  41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
  1367. +  116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
  1368. +  115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
  1369. +  99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
  1370. +  9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
  1371. +  10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
  1372. +  97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
  1373. +  110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
  1374. +  52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
  1375. +  97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
  1376. +  61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
  1377. +  41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
  1378. +  97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
  1379. +  117,114,110,40,97,42,114,47,49,41,10,125,10,0
  1380. +};
  1381. +#endif // CONFIG_BC
  1382. +
  1383. +static BcStatus bc_vec_grow(BcVec *v, size_t n) {
  1384. +
  1385. +   char *ptr;
  1386. +   size_t cap = v->cap * 2;
  1387. +
  1388. +   while (cap < v->len + n) cap *= 2;
  1389. +   if (!(ptr = realloc(v->v, v->size * cap))) return BC_STATUS_ALLOC_ERR;
  1390. +
  1391. +   v->v = ptr;
  1392. +   v->cap = cap;
  1393. +
  1394. +   return BC_STATUS_SUCCESS;
  1395. +}
  1396. +
  1397. +BcStatus bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor) {
  1398. +
  1399. +   v->size = esize;
  1400. +   v->cap = BC_VEC_START_CAP;
  1401. +   v->len = 0;
  1402. +   v->dtor = dtor;
  1403. +
  1404. +   if (!(v->v = malloc(esize * BC_VEC_START_CAP))) return BC_STATUS_ALLOC_ERR;
  1405. +
  1406. +   return BC_STATUS_SUCCESS;
  1407. +}
  1408. +
  1409. +BcStatus bc_vec_expand(BcVec *v, size_t req) {
  1410. +
  1411. +   char *ptr;
  1412. +
  1413. +   if (v->cap >= req) return BC_STATUS_SUCCESS;
  1414. +   if (!(ptr = realloc(v->v, v->size * req))) return BC_STATUS_ALLOC_ERR;
  1415. +
  1416. +   v->v = ptr;
  1417. +   v->cap = req;
  1418. +
  1419. +   return BC_STATUS_SUCCESS;
  1420. +}
  1421. +
  1422. +void bc_vec_npop(BcVec *v, size_t n) {
  1423. +   if (!v->dtor) v->len -= n;
  1424. +   else {
  1425. +       size_t len = v->len - n;
  1426. +       while (v->len > len) v->dtor(v->v + (v->size * --v->len));
  1427. +   }
  1428. +}
  1429. +
  1430. +BcStatus bc_vec_push(BcVec *v, const void *data) {
  1431. +
  1432. +   BcStatus s;
  1433. +
  1434. +   if (v->len + 1 > v->cap && (s = bc_vec_grow(v, 1))) return s;
  1435. +
  1436. +   memmove(v->v + (v->size * v->len), data, v->size);
  1437. +   v->len += 1;
  1438. +
  1439. +   return BC_STATUS_SUCCESS;
  1440. +}
  1441. +
  1442. +BcStatus bc_vec_pushByte(BcVec *v, uint8_t data) {
  1443. +   return bc_vec_push(v, &data);
  1444. +}
  1445. +
  1446. +static BcStatus bc_vec_pushAt(BcVec *v, const void *data, size_t idx) {
  1447. +
  1448. +   BcStatus s;
  1449. +   char *ptr;
  1450. +
  1451. +   if (idx == v->len) return bc_vec_push(v, data);
  1452. +   if (v->len == v->cap && (s = bc_vec_grow(v, 1))) return s;
  1453. +
  1454. +   ptr = v->v + v->size * idx;
  1455. +
  1456. +   memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
  1457. +   memmove(ptr, data, v->size);
  1458. +
  1459. +   return BC_STATUS_SUCCESS;
  1460. +}
  1461. +
  1462. +BcStatus bc_vec_string(BcVec *v, size_t len, const char *str) {
  1463. +
  1464. +   BcStatus s;
  1465. +
  1466. +   bc_vec_npop(v, v->len);
  1467. +   if ((s = bc_vec_expand(v, len + 1))) return s;
  1468. +   memcpy(v->v, str, len);
  1469. +
  1470. +   v->len = len;
  1471. +
  1472. +   return bc_vec_pushByte(v, '\0');
  1473. +}
  1474. +
  1475. +BcStatus bc_vec_concat(BcVec *v, const char *str) {
  1476. +
  1477. +   BcStatus s;
  1478. +   size_t len;
  1479. +
  1480. +   if (!v->len && (s = bc_vec_pushByte(v, '\0'))) return s;
  1481. +
  1482. +   len = v->len + strlen(str);
  1483. +
  1484. +   if (v->cap < len && (s = bc_vec_grow(v, len - v->len))) return s;
  1485. +   strcat(v->v, str);
  1486. +
  1487. +   v->len = len;
  1488. +
  1489. +   return BC_STATUS_SUCCESS;
  1490. +}
  1491. +
  1492. +void* bc_vec_item(const BcVec *v, size_t idx) {
  1493. +   return v->v + v->size * idx;
  1494. +}
  1495. +
  1496. +void* bc_vec_item_rev(const BcVec *v, size_t idx) {
  1497. +   return v->v + v->size * (v->len - idx - 1);
  1498. +}
  1499. +
  1500. +void bc_vec_free(void *vec) {
  1501. +   BcVec *v = (BcVec*) vec;
  1502. +   bc_vec_npop(v, v->len);
  1503. +   free(v->v);
  1504. +}
  1505. +
  1506. +static size_t bc_veco_find(const BcVec *v, const void *ptr) {
  1507. +
  1508. +   size_t low = 0, high = v->len;
  1509. +
  1510. +   while (low < high) {
  1511. +
  1512. +       size_t mid = (low + high) / 2;
  1513. +       uint8_t *item = bc_vec_item(v, mid);
  1514. +       int result = bc_id_cmp(ptr, item);
  1515. +
  1516. +       if (!result) return mid;
  1517. +       else if (result < 0) high = mid;
  1518. +       else low = mid + 1;
  1519. +   }
  1520. +
  1521. +   return low;
  1522. +}
  1523. +
  1524. +BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i) {
  1525. +
  1526. +   BcStatus s;
  1527. +
  1528. +   if ((*i = bc_veco_find(v, ptr)) > v->len) s = BC_STATUS_VEC_OUT_OF_BOUNDS;
  1529. +   else if (*i == v->len) s = bc_vec_push(v, ptr);
  1530. +   else if (!bc_id_cmp(ptr, bc_vec_item(v, *i))) s = BC_STATUS_VEC_ITEM_EXISTS;
  1531. +   else s = bc_vec_pushAt(v, ptr, *i);
  1532. +
  1533. +   return s;
  1534. +}
  1535. +
  1536. +size_t bc_map_index(const BcVec* v, const void *ptr) {
  1537. +   size_t i = bc_veco_find(v, ptr);
  1538. +   if (i >= v->len) return BC_VEC_INVALID_IDX;
  1539. +   return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
  1540. +}
  1541. +
  1542. +static const struct option bc_args_lopt[] = {
  1543. +
  1544. +   { "expression", required_argument, NULL, 'e' },
  1545. +   { "file", required_argument, NULL, 'f' },
  1546. +   { "help", no_argument, NULL, 'h' },
  1547. +   { "interactive", no_argument, NULL, 'i' },
  1548. +   { "mathlib", no_argument, NULL, 'l' },
  1549. +   { "quiet", no_argument, NULL, 'q' },
  1550. +   { "standard", no_argument, NULL, 's' },
  1551. +   { "version", no_argument, NULL, 'v' },
  1552. +   { "warn", no_argument, NULL, 'w' },
  1553. +   { "extended-register", no_argument, NULL, 'x' },
  1554. +   { 0, 0, 0, 0 },
  1555. +
  1556. +};
  1557. +
  1558. +static const char* const bc_args_opt = "e:f:hilqsvVwx";
  1559. +
  1560. +static BcStatus bc_args_exprs(BcVec *exprs, const char *str) {
  1561. +   BcStatus s;
  1562. +   if ((s = bc_vec_concat(exprs, str))) return s;
  1563. +   return bc_vec_concat(exprs, "\n");
  1564. +}
  1565. +
  1566. +static BcStatus bc_args_file(BcVec *exprs, const char *file) {
  1567. +
  1568. +   BcStatus s;
  1569. +   char *buf;
  1570. +
  1571. +   if ((s = bc_read_file(file, &buf))) return s;
  1572. +   s = bc_args_exprs(exprs, buf);
  1573. +
  1574. +   free(buf);
  1575. +
  1576. +   return s;
  1577. +}
  1578. +
  1579. +BcStatus bc_args(int argc, char *argv[], unsigned int *flags,
  1580. +                 BcVec *exprs, BcVec *files)
  1581. +{
  1582. +   BcStatus s = BC_STATUS_SUCCESS;
  1583. +   int c, i, idx;
  1584. +   bool do_exit = false;
  1585. +
  1586. +   idx = c = optind = 0;
  1587. +
  1588. +   while ((c = getopt_long(argc, argv, bc_args_opt, bc_args_lopt, &idx)) != -1)
  1589. +   {
  1590. +       switch (c) {
  1591. +
  1592. +           case 0:
  1593. +           {
  1594. +               // This is the case when a long option is found.
  1595. +               break;
  1596. +           }
  1597. +
  1598. +           case 'e':
  1599. +           {
  1600. +               if ((s = bc_args_exprs(exprs, optarg))) return s;
  1601. +               break;
  1602. +           }
  1603. +
  1604. +           case 'f':
  1605. +           {
  1606. +               if ((s = bc_args_file(exprs, optarg))) return s;
  1607. +               break;
  1608. +           }
  1609. +
  1610. +           case 'h':
  1611. +           {
  1612. +               if ((s = bc_vm_info(bcg.help))) return s;
  1613. +               do_exit = true;
  1614. +               break;
  1615. +           }
  1616. +
  1617. +#ifdef CONFIG_BC
  1618. +           case 'i':
  1619. +           {
  1620. +               if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
  1621. +               (*flags) |= BC_FLAG_I;
  1622. +               break;
  1623. +           }
  1624. +
  1625. +           case 'l':
  1626. +           {
  1627. +               if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
  1628. +               (*flags) |= BC_FLAG_L;
  1629. +               break;
  1630. +           }
  1631. +
  1632. +           case 'q':
  1633. +           {
  1634. +               if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
  1635. +               (*flags) |= BC_FLAG_Q;
  1636. +               break;
  1637. +           }
  1638. +
  1639. +           case 's':
  1640. +           {
  1641. +               if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
  1642. +               (*flags) |= BC_FLAG_S;
  1643. +               break;
  1644. +           }
  1645. +
  1646. +           case 'w':
  1647. +           {
  1648. +               if (!bcg.bc) return BC_STATUS_INVALID_OPTION;
  1649. +               (*flags) |= BC_FLAG_W;
  1650. +               break;
  1651. +           }
  1652. +#endif // CONFIG_BC
  1653. +
  1654. +           case 'V':
  1655. +           case 'v':
  1656. +           {
  1657. +               if ((s = bc_vm_info(NULL))) return s;
  1658. +               do_exit = true;
  1659. +               break;
  1660. +           }
  1661. +
  1662. +#ifdef CONFIG_DC
  1663. +           case 'x':
  1664. +           {
  1665. +               if (bcg.bc) return BC_STATUS_INVALID_OPTION;
  1666. +               (*flags) |= BC_FLAG_X;
  1667. +               break;
  1668. +           }
  1669. +#endif // CONFIG_DC
  1670. +
  1671. +           // Getopt printed an error message, but we should exit.
  1672. +           case '?':
  1673. +           default:
  1674. +           {
  1675. +               return BC_STATUS_INVALID_OPTION;
  1676. +           }
  1677. +       }
  1678. +   }
  1679. +
  1680. +   if (do_exit) exit((int) s);
  1681. +   if (exprs->len > 1 || !bcg.bc) (*flags) |= BC_FLAG_Q;
  1682. +   if (argv[optind] && strcmp(argv[optind], "--") == 0) ++optind;
  1683. +
  1684. +   for (i = optind; !s && i < argc; ++i) s = bc_vec_push(files, argv + i);
  1685. +
  1686. +   return s;
  1687. +}
  1688. +
  1689. +BcStatus bc_read_line(BcVec *vec, const char* prompt) {
  1690. +
  1691. +   BcStatus s;
  1692. +   int i;
  1693. +   signed char c = 0;
  1694. +
  1695. +   if (bcg.ttyin && (fputs(prompt, stderr) == EOF || fflush(stderr) == EOF))
  1696. +       return BC_STATUS_IO_ERR;
  1697. +
  1698. +   bc_vec_npop(vec, vec->len);
  1699. +
  1700. +   while (c != '\n') {
  1701. +
  1702. +       if ((i = fgetc(stdin)) == EOF) {
  1703. +
  1704. +           if (errno != EINTR) return BC_STATUS_IO_ERR;
  1705. +
  1706. +           bcg.sigc = bcg.sig;
  1707. +           bcg.signe = 0;
  1708. +
  1709. +           if (bcg.ttyin && (fputs(bc_program_ready_msg, stderr) == EOF ||
  1710. +                             fputs(prompt, stderr) == EOF ||
  1711. +                             fflush(stderr) == EOF))
  1712. +           {
  1713. +               return BC_STATUS_IO_ERR;
  1714. +           }
  1715. +
  1716. +           continue;
  1717. +       }
  1718. +
  1719. +       if (i > UCHAR_MAX) return BC_STATUS_LEX_BAD_CHAR;
  1720. +
  1721. +       c = (char) i;
  1722. +       if (BC_IO_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
  1723. +       if ((s = bc_vec_push(vec, &c))) return s;
  1724. +   }
  1725. +
  1726. +   return bc_vec_pushByte(vec, '\0');
  1727. +}
  1728. +
  1729. +BcStatus bc_read_file(const char *path, char **buf) {
  1730. +
  1731. +   BcStatus s = BC_STATUS_IO_ERR;
  1732. +   FILE *f;
  1733. +   size_t size, read;
  1734. +   long res;
  1735. +   struct stat pstat;
  1736. +
  1737. +   if (!(f = fopen(path, "r"))) return BC_STATUS_EXEC_FILE_ERR;
  1738. +
  1739. +   if (fstat(fileno(f), &pstat) == -1) goto malloc_err;
  1740. +
  1741. +   if (S_ISDIR(pstat.st_mode)) {
  1742. +       s = BC_STATUS_PATH_IS_DIR;
  1743. +       goto malloc_err;
  1744. +   }
  1745. +
  1746. +   if (fseek(f, 0, SEEK_END) == -1) goto malloc_err;
  1747. +   if ((res = ftell(f)) < 0) goto malloc_err;
  1748. +   if (fseek(f, 0, SEEK_SET) == -1) goto malloc_err;
  1749. +
  1750. +   if (!(*buf = malloc((size = (size_t) res) + 1))) {
  1751. +       s = BC_STATUS_ALLOC_ERR;
  1752. +       goto malloc_err;
  1753. +   }
  1754. +
  1755. +   if ((read = fread(*buf, 1, size, f)) != size) goto read_err;
  1756. +
  1757. +   (*buf)[size] = '\0';
  1758. +   s = BC_STATUS_BIN_FILE;
  1759. +
  1760. +   for (read = 0; read < size; ++read) {
  1761. +       if (BC_IO_BIN_CHAR((*buf)[read])) goto read_err;
  1762. +   }
  1763. +
  1764. +   fclose(f);
  1765. +
  1766. +   return BC_STATUS_SUCCESS;
  1767. +
  1768. +read_err:
  1769. +   free(*buf);
  1770. +malloc_err:
  1771. +   fclose(f);
  1772. +   return s;
  1773. +}
  1774. +
  1775. +static void bc_num_setToZero(BcNum *n, size_t scale) {
  1776. +   n->neg = (n->len = 0);
  1777. +   n->rdx = scale;
  1778. +}
  1779. +
  1780. +void bc_num_zero(BcNum *n) {
  1781. +   bc_num_setToZero(n, 0);
  1782. +}
  1783. +
  1784. +void bc_num_one(BcNum *n) {
  1785. +   bc_num_setToZero(n, 0);
  1786. +   n->len = 1;
  1787. +   n->num[0] = 1;
  1788. +}
  1789. +
  1790. +void bc_num_ten(BcNum *n) {
  1791. +   bc_num_setToZero(n, 0);
  1792. +   n->len = 2;
  1793. +   n->num[0] = 0;
  1794. +   n->num[1] = 1;
  1795. +}
  1796. +
  1797. +static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
  1798. +                                 size_t len)
  1799. +{
  1800. +   size_t i, j;
  1801. +   for (i = 0; !bcg.signe && i < len; ++i) {
  1802. +       for (a[i] -= b[i], j = 0; !bcg.signe && a[i + j] < 0;) {
  1803. +           a[i + j++] += 10;
  1804. +           a[i + j] -= 1;
  1805. +       }
  1806. +   }
  1807. +   return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
  1808. +}
  1809. +
  1810. +static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
  1811. +{
  1812. +   size_t i;
  1813. +   int c = 0;
  1814. +   for (i = len - 1; !bcg.signe && i < len && !(c = a[i] - b[i]); --i);
  1815. +   return BC_NUM_NEG(i + 1, c < 0);
  1816. +}
  1817. +
  1818. +ssize_t bc_num_cmp(BcNum *a, BcNum *b) {
  1819. +
  1820. +   size_t i, min, a_int, b_int, diff;
  1821. +   BcDig *max_num, *min_num;
  1822. +   bool a_max, neg = false;
  1823. +   ssize_t cmp;
  1824. +
  1825. +   if (a == b) return 0;
  1826. +   else if (!a->len) return BC_NUM_NEG(!!b->len, !b->neg);
  1827. +   else if (!b->len) return BC_NUM_NEG(1, a->neg);
  1828. +   else if (a->neg) {
  1829. +       if (b->neg) neg = true;
  1830. +       else return -1;
  1831. +   }
  1832. +   else if (b->neg) return 1;
  1833. +
  1834. +   a_int = BC_NUM_INT(a);
  1835. +   b_int = BC_NUM_INT(b);
  1836. +
  1837. +   if ((a_int -= b_int)) return (ssize_t) a_int;
  1838. +
  1839. +   if ((a_max = (a->rdx > b->rdx))) {
  1840. +       min = b->rdx;
  1841. +       diff = a->rdx - b->rdx;
  1842. +       max_num = a->num + diff;
  1843. +       min_num = b->num;
  1844. +   }
  1845. +   else {
  1846. +       min = a->rdx;
  1847. +       diff = b->rdx - a->rdx;
  1848. +       max_num = b->num + diff;
  1849. +       min_num = a->num;
  1850. +   }
  1851. +
  1852. +   if ((cmp = bc_num_compare(max_num, min_num, b_int + min)))
  1853. +       return BC_NUM_NEG(cmp, (!a_max) != neg);
  1854. +
  1855. +   for (max_num -= diff, i = diff - 1; !bcg.signe && i < diff; --i) {
  1856. +       if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
  1857. +   }
  1858. +
  1859. +   return 0;
  1860. +}
  1861. +
  1862. +void bc_num_truncate(BcNum *n, size_t places) {
  1863. +
  1864. +   if (!places) return;
  1865. +
  1866. +   n->rdx -= places;
  1867. +
  1868. +   if (n->len) {
  1869. +       n->len -= places;
  1870. +       memmove(n->num, n->num + places, n->len * sizeof(BcDig));
  1871. +   }
  1872. +}
  1873. +
  1874. +static BcStatus bc_num_extend(BcNum *n, size_t places) {
  1875. +
  1876. +   BcStatus s;
  1877. +   size_t len = n->len + places;
  1878. +
  1879. +   if (!places) return BC_STATUS_SUCCESS;
  1880. +   if (n->cap < len && (s = bc_num_expand(n, len))) return s;
  1881. +
  1882. +   memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
  1883. +   memset(n->num, 0, sizeof(BcDig) * places);
  1884. +
  1885. +   n->len += places;
  1886. +   n->rdx += places;
  1887. +
  1888. +   return BC_STATUS_SUCCESS;
  1889. +}
  1890. +
  1891. +static void bc_num_clean(BcNum *n) {
  1892. +   while (n->len > 0 && !n->num[n->len - 1]) --n->len;
  1893. +   if (!n->len) n->neg = false;
  1894. +   else if (n->len < n->rdx) n->len = n->rdx;
  1895. +}
  1896. +
  1897. +static BcStatus bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2) {
  1898. +
  1899. +   BcStatus s = BC_STATUS_SUCCESS;
  1900. +
  1901. +   if (n->rdx < scale) s = bc_num_extend(n, scale - n->rdx);
  1902. +   else bc_num_truncate(n, n->rdx - scale);
  1903. +
  1904. +   bc_num_clean(n);
  1905. +   if (n->len) n->neg = !neg1 != !neg2;
  1906. +
  1907. +   return s;
  1908. +}
  1909. +
  1910. +static BcStatus bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
  1911. +                             BcNum *restrict b)
  1912. +{
  1913. +   BcStatus s = BC_STATUS_SUCCESS;
  1914. +
  1915. +   if (idx < n->len) {
  1916. +
  1917. +       b->len = n->len - idx;
  1918. +       a->len = idx;
  1919. +       a->rdx = b->rdx = 0;
  1920. +
  1921. +       memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
  1922. +       memcpy(a->num, n->num, idx * sizeof(BcDig));
  1923. +   }
  1924. +   else {
  1925. +       bc_num_zero(b);
  1926. +       s = bc_num_copy(a, n);
  1927. +   }
  1928. +
  1929. +   bc_num_clean(a);
  1930. +   bc_num_clean(b);
  1931. +
  1932. +   return s;
  1933. +}
  1934. +
  1935. +static BcStatus bc_num_shift(BcNum *n, size_t places) {
  1936. +
  1937. +   BcStatus s = BC_STATUS_SUCCESS;
  1938. +
  1939. +   if (!places || !n->len) return BC_STATUS_SUCCESS;
  1940. +   if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
  1941. +
  1942. +   if (n->rdx >= places) n->rdx -= places;
  1943. +   else {
  1944. +       s = bc_num_extend(n, places - n->rdx);
  1945. +       n->rdx = 0;
  1946. +   }
  1947. +
  1948. +   bc_num_clean(n);
  1949. +
  1950. +   return s;
  1951. +}
  1952. +
  1953. +static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) {
  1954. +
  1955. +   BcNum one;
  1956. +   BcDig num[2];
  1957. +
  1958. +   one.cap = 2;
  1959. +   one.num = num;
  1960. +   bc_num_one(&one);
  1961. +
  1962. +   return bc_num_div(&one, a, b, scale);
  1963. +}
  1964. +
  1965. +static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) {
  1966. +
  1967. +   BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
  1968. +   size_t i, max, min_rdx, min_int, diff, a_int, b_int;
  1969. +   int carry, in;
  1970. +
  1971. +   // Because this function doesn't need to use scale (per the bc spec),
  1972. +   // I am hijacking it to say whether it's doing an add or a subtract.
  1973. +
  1974. +   if (!a->len) {
  1975. +       BcStatus s = bc_num_copy(c, b);
  1976. +       if (sub && c->len) c->neg = !c->neg;
  1977. +       return s;
  1978. +   }
  1979. +   else if (!b->len) return bc_num_copy(c, a);
  1980. +
  1981. +   c->neg = a->neg;
  1982. +   c->rdx = BC_MAX(a->rdx, b->rdx);
  1983. +   min_rdx = BC_MIN(a->rdx, b->rdx);
  1984. +   c->len = 0;
  1985. +
  1986. +   if (a->rdx > b->rdx) {
  1987. +       diff = a->rdx - b->rdx;
  1988. +       ptr = a->num;
  1989. +       ptr_a = a->num + diff;
  1990. +       ptr_b = b->num;
  1991. +   }
  1992. +   else {
  1993. +       diff = b->rdx - a->rdx;
  1994. +       ptr = b->num;
  1995. +       ptr_a = a->num;
  1996. +       ptr_b = b->num + diff;
  1997. +   }
  1998. +
  1999. +   for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
  2000. +
  2001. +   ptr_c += diff;
  2002. +
  2003. +   if ((a_int = BC_NUM_INT(a)) > (b_int = BC_NUM_INT(b))) {
  2004. +       min_int = b_int;
  2005. +       max = a_int;
  2006. +       ptr = ptr_a;
  2007. +   }
  2008. +   else {
  2009. +       min_int = a_int;
  2010. +       max = b_int;
  2011. +       ptr = ptr_b;
  2012. +   }
  2013. +
  2014. +   for (carry = 0, i = 0; !bcg.signe && i < min_rdx + min_int; ++i, ++c->len) {
  2015. +       in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
  2016. +       carry = in / 10;
  2017. +       ptr_c[i] = (BcDig) (in % 10);
  2018. +   }
  2019. +
  2020. +   for (; !bcg.signe && i < max + min_rdx; ++i, ++c->len) {
  2021. +       in = ((int) ptr[i]) + carry;
  2022. +       carry = in / 10;
  2023. +       ptr_c[i] = (BcDig) (in % 10);
  2024. +   }
  2025. +
  2026. +   if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
  2027. +
  2028. +   if (carry) c->num[c->len++] = (BcDig) carry;
  2029. +
  2030. +   return BC_STATUS_SUCCESS;
  2031. +}
  2032. +
  2033. +static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub) {
  2034. +
  2035. +   BcStatus s;
  2036. +   ssize_t cmp;
  2037. +   BcNum *minuend, *subtrahend;
  2038. +   size_t start;
  2039. +   bool aneg, bneg, neg;
  2040. +
  2041. +   // Because this function doesn't need to use scale (per the bc spec),
  2042. +   // I am hijacking it to say whether it's doing an add or a subtract.
  2043. +
  2044. +   if (!a->len) {
  2045. +       s = bc_num_copy(c, b);
  2046. +       if (sub && c->len) c->neg = !c->neg;
  2047. +       return s;
  2048. +   }
  2049. +   else if (!b->len) return bc_num_copy(c, a);
  2050. +
  2051. +   aneg = a->neg;
  2052. +   bneg = b->neg;
  2053. +   a->neg = b->neg = false;
  2054. +
  2055. +   cmp = bc_num_cmp(a, b);
  2056. +
  2057. +   a->neg = aneg;
  2058. +   b->neg = bneg;
  2059. +
  2060. +   if (!cmp) {
  2061. +       bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
  2062. +       return BC_STATUS_SUCCESS;
  2063. +   }
  2064. +   else if (cmp > 0) {
  2065. +       neg = a->neg;
  2066. +       minuend = a;
  2067. +       subtrahend = b;
  2068. +   }
  2069. +   else {
  2070. +       neg = b->neg;
  2071. +       if (sub) neg = !neg;
  2072. +       minuend = b;
  2073. +       subtrahend = a;
  2074. +   }
  2075. +
  2076. +   if ((s = bc_num_copy(c, minuend))) return s;
  2077. +   c->neg = neg;
  2078. +
  2079. +   if (c->rdx < subtrahend->rdx) {
  2080. +       if ((s = bc_num_extend(c, subtrahend->rdx - c->rdx))) return s;
  2081. +       start = 0;
  2082. +   }
  2083. +   else start = c->rdx - subtrahend->rdx;
  2084. +
  2085. +   s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
  2086. +
  2087. +   bc_num_clean(c);
  2088. +
  2089. +   return s;
  2090. +}
  2091. +
  2092. +static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
  2093. +                         BcNum *restrict c)
  2094. +{
  2095. +   BcStatus s;
  2096. +   int carry;
  2097. +   size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
  2098. +   BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
  2099. +   bool aone = BC_NUM_ONE(a);
  2100. +
  2101. +   if (!a->len || !b->len) {
  2102. +       bc_num_zero(c);
  2103. +       return BC_STATUS_SUCCESS;
  2104. +   }
  2105. +   else if (aone || BC_NUM_ONE(b)) return bc_num_copy(c, aone ? b : a);
  2106. +
  2107. +   if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
  2108. +       a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
  2109. +   {
  2110. +       if ((s = bc_num_expand(c, a->len + b->len + 1))) return s;
  2111. +
  2112. +       memset(c->num, 0, sizeof(BcDig) * c->cap);
  2113. +       c->len = carry = len = 0;
  2114. +
  2115. +       for (i = 0; !bcg.signe && i < b->len; ++i) {
  2116. +
  2117. +           for (j = 0; !bcg.signe && j < a->len; ++j) {
  2118. +               int in = (int) c->num[i + j];
  2119. +               in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
  2120. +               carry = in / 10;
  2121. +               c->num[i + j] = (BcDig) (in % 10);
  2122. +           }
  2123. +
  2124. +           if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
  2125. +
  2126. +           c->num[i + j] += (BcDig) carry;
  2127. +           len = BC_MAX(len, i + j + !!carry);
  2128. +           carry = 0;
  2129. +       }
  2130. +
  2131. +       c->len = len;
  2132. +
  2133. +       return bcg.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
  2134. +   }
  2135. +
  2136. +   if ((s = bc_num_init(&l1, max))) return s;
  2137. +   if ((s = bc_num_init(&h1, max))) goto high1_err;
  2138. +   if ((s = bc_num_init(&l2, max))) goto low2_err;
  2139. +   if ((s = bc_num_init(&h2, max))) goto high2_err;
  2140. +   if ((s = bc_num_init(&m1, max))) goto mix1_err;
  2141. +   if ((s = bc_num_init(&m2, max))) goto mix2_err;
  2142. +   if ((s = bc_num_init(&z0, max))) goto z0_err;
  2143. +   if ((s = bc_num_init(&z1, max))) goto z1_err;
  2144. +   if ((s = bc_num_init(&z2, max))) goto z2_err;
  2145. +   if ((s = bc_num_init(&temp, max + max))) goto temp_err;
  2146. +
  2147. +   if ((s = bc_num_split(a, max2, &l1, &h1))) goto err;
  2148. +   if ((s = bc_num_split(b, max2, &l2, &h2))) goto err;
  2149. +
  2150. +   if ((s = bc_num_add(&h1, &l1, &m1, 0))) goto err;
  2151. +   if ((s = bc_num_add(&h2, &l2, &m2, 0))) goto err;
  2152. +
  2153. +   if ((s = bc_num_k(&h1, &h2, &z0))) goto err;
  2154. +   if ((s = bc_num_k(&m1, &m2, &z1))) goto err;
  2155. +   if ((s = bc_num_k(&l1, &l2, &z2))) goto err;
  2156. +
  2157. +   if ((s = bc_num_sub(&z1, &z0, &temp, 0))) goto err;
  2158. +   if ((s = bc_num_sub(&temp, &z2, &z1, 0))) goto err;
  2159. +
  2160. +   if ((s = bc_num_shift(&z0, max2 * 2))) goto err;
  2161. +   if ((s = bc_num_shift(&z1, max2))) goto err;
  2162. +   if ((s = bc_num_add(&z0, &z1, &temp, 0))) goto err;
  2163. +   s = bc_num_add(&temp, &z2, c, 0);
  2164. +
  2165. +err:
  2166. +   bc_num_free(&temp);
  2167. +temp_err:
  2168. +   bc_num_free(&z2);
  2169. +z2_err:
  2170. +   bc_num_free(&z1);
  2171. +z1_err:
  2172. +   bc_num_free(&z0);
  2173. +z0_err:
  2174. +   bc_num_free(&m2);
  2175. +mix2_err:
  2176. +   bc_num_free(&m1);
  2177. +mix1_err:
  2178. +   bc_num_free(&h2);
  2179. +high2_err:
  2180. +   bc_num_free(&l2);
  2181. +low2_err:
  2182. +   bc_num_free(&h1);
  2183. +high1_err:
  2184. +   bc_num_free(&l1);
  2185. +   return s;
  2186. +}
  2187. +
  2188. +static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
  2189. +
  2190. +   BcStatus s;
  2191. +   BcNum cpa, cpb;
  2192. +   size_t maxrdx = BC_MAX(a->rdx, b->rdx);
  2193. +
  2194. +   scale = BC_MAX(scale, a->rdx);
  2195. +   scale = BC_MAX(scale, b->rdx);
  2196. +   scale = BC_MIN(a->rdx + b->rdx, scale);
  2197. +   maxrdx = BC_MAX(maxrdx, scale);
  2198. +
  2199. +   if ((s = bc_num_init(&cpa, a->len))) return s;
  2200. +   if ((s = bc_num_init(&cpb, b->len))) goto b_err;
  2201. +
  2202. +   if ((s = bc_num_copy(&cpa, a))) goto err;
  2203. +   if ((s = bc_num_copy(&cpb, b))) goto err;
  2204. +   cpa.neg = cpb.neg = false;
  2205. +   if ((s = bc_num_shift(&cpa, maxrdx))) goto err;
  2206. +   if ((s = bc_num_shift(&cpb, maxrdx))) goto err;
  2207. +
  2208. +   if ((s = bc_num_k(&cpa, &cpb, c))) goto err;
  2209. +
  2210. +   if ((s = bc_num_expand(c, c->len + (maxrdx += scale)))) goto err;
  2211. +   if (c->len < maxrdx) {
  2212. +       memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
  2213. +       c->len += maxrdx;
  2214. +   }
  2215. +
  2216. +   c->rdx = maxrdx;
  2217. +   s = bc_num_retireMul(c, scale, a->neg, b->neg);
  2218. +
  2219. +err:
  2220. +   bc_num_free(&cpb);
  2221. +b_err:
  2222. +   bc_num_free(&cpa);
  2223. +   return s;
  2224. +}
  2225. +
  2226. +static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
  2227. +
  2228. +   BcStatus s;
  2229. +   BcDig *n, *bptr, q;
  2230. +   size_t len, end, i;
  2231. +   BcNum cp;
  2232. +
  2233. +   if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
  2234. +   else if (!a->len) {
  2235. +       bc_num_setToZero(c, scale);
  2236. +       return BC_STATUS_SUCCESS;
  2237. +   }
  2238. +   else if (BC_NUM_ONE(b)) {
  2239. +       if ((s = bc_num_copy(c, a))) return s;
  2240. +       return bc_num_retireMul(c, scale, a->neg, b->neg);
  2241. +   }
  2242. +
  2243. +   if ((s = bc_num_init(&cp, BC_NUM_MREQ(a, b, scale)))) return s;
  2244. +   if ((s = bc_num_copy(&cp, a))) goto err;
  2245. +
  2246. +   if ((len = b->len) > cp.len) {
  2247. +       if ((s = bc_num_expand(&cp, len + 2))) goto err;
  2248. +       if ((s = bc_num_extend(&cp, len - cp.len))) goto err;
  2249. +   }
  2250. +
  2251. +   if (b->rdx > cp.rdx && (s = bc_num_extend(&cp, b->rdx - cp.rdx))) goto err;
  2252. +   cp.rdx -= b->rdx;
  2253. +   if (scale > cp.rdx && (s = bc_num_extend(&cp, scale - cp.rdx))) goto err;
  2254. +
  2255. +   if (b->rdx == b->len) {
  2256. +
  2257. +       bool zero = true;
  2258. +       for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
  2259. +
  2260. +       len -= i - 1;
  2261. +   }
  2262. +
  2263. +   if (cp.cap == cp.len && (s = bc_num_expand(&cp, cp.len + 1))) goto err;
  2264. +
  2265. +   // We want an extra zero in front to make things simpler.
  2266. +   cp.num[cp.len++] = 0;
  2267. +   end = cp.len - len;
  2268. +
  2269. +   if ((s = bc_num_expand(c, cp.len))) goto err;
  2270. +
  2271. +   bc_num_zero(c);
  2272. +   memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
  2273. +   c->rdx = cp.rdx;
  2274. +   c->len = cp.len;
  2275. +   bptr = b->num;
  2276. +
  2277. +   for (i = end - 1; !bcg.signe  && !s && i < end; --i) {
  2278. +
  2279. +       n = cp.num + i;
  2280. +
  2281. +       for (q = 0; (!s && n[len]) || bc_num_compare(n, bptr, len) >= 0; ++q)
  2282. +           s = bc_num_subArrays(n, bptr, len);
  2283. +
  2284. +       c->num[i] = q;
  2285. +   }
  2286. +
  2287. +   if (!s) s = bc_num_retireMul(c, scale, a->neg, b->neg);
  2288. +
  2289. +err:
  2290. +   bc_num_free(&cp);
  2291. +   return s;
  2292. +}
  2293. +
  2294. +static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
  2295. +                         BcNum *restrict d, size_t scale, size_t ts)
  2296. +{
  2297. +   BcStatus s;
  2298. +   BcNum temp;
  2299. +   bool neg;
  2300. +
  2301. +   if (!b->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
  2302. +
  2303. +   if (!a->len) {
  2304. +       bc_num_setToZero(d, ts);
  2305. +       return BC_STATUS_SUCCESS;
  2306. +   }
  2307. +
  2308. +   if ((s = bc_num_init(&temp, d->cap))) return s;
  2309. +
  2310. +   if ((s = bc_num_d(a, b, c, scale))) goto err;
  2311. +
  2312. +   if (scale) scale = ts;
  2313. +
  2314. +   if ((s = bc_num_m(c, b, &temp, scale))) goto err;
  2315. +   if ((s = bc_num_sub(a, &temp, d, scale))) goto err;
  2316. +
  2317. +   if (ts > d->rdx && d->len && (s = bc_num_extend(d, ts - d->rdx))) goto err;
  2318. +
  2319. +   neg = d->neg;
  2320. +   s = bc_num_retireMul(d, ts, a->neg, b->neg);
  2321. +   d->neg = neg;
  2322. +
  2323. +err:
  2324. +   bc_num_free(&temp);
  2325. +   return s;
  2326. +}
  2327. +
  2328. +static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
  2329. +{
  2330. +   BcStatus s;
  2331. +   BcNum c1;
  2332. +   size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
  2333. +
  2334. +   if ((s = bc_num_init(&c1, len))) return s;
  2335. +
  2336. +   s = bc_num_r(a, b, &c1, c, scale, ts);
  2337. +
  2338. +   bc_num_free(&c1);
  2339. +
  2340. +   return s;
  2341. +}
  2342. +
  2343. +static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale) {
  2344. +
  2345. +   BcStatus s;
  2346. +   BcNum copy;
  2347. +   unsigned long pow;
  2348. +   size_t i, powrdx, resrdx;
  2349. +   bool neg, zero;
  2350. +
  2351. +   if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
  2352. +
  2353. +   if (!b->len) {
  2354. +       bc_num_one(c);
  2355. +       return BC_STATUS_SUCCESS;
  2356. +   }
  2357. +   else if (!a->len) {
  2358. +       bc_num_setToZero(c, scale);
  2359. +       return BC_STATUS_SUCCESS;
  2360. +   }
  2361. +   else if (BC_NUM_ONE(b)) {
  2362. +
  2363. +       if (!b->neg) s = bc_num_copy(c, a);
  2364. +       else s = bc_num_inv(a, c, scale);
  2365. +
  2366. +       return s;
  2367. +   }
  2368. +
  2369. +   neg = b->neg;
  2370. +   b->neg = false;
  2371. +
  2372. +   if ((s = bc_num_ulong(b, &pow))) return s;
  2373. +   if ((s = bc_num_init(&copy, a->len))) return s;
  2374. +   if ((s = bc_num_copy(&copy, a))) goto err;
  2375. +
  2376. +   if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
  2377. +
  2378. +   b->neg = neg;
  2379. +
  2380. +   for (powrdx = a->rdx; !bcg.signe && !(pow & 1); pow >>= 1) {
  2381. +       powrdx <<= 1;
  2382. +       if ((s = bc_num_mul(&copy, &copy, &copy, powrdx))) goto err;
  2383. +   }
  2384. +
  2385. +   if ((s = bc_num_copy(c, &copy))) goto err;
  2386. +   if (bcg.signe) {
  2387. +       s = BC_STATUS_EXEC_SIGNAL;
  2388. +       goto err;
  2389. +   }
  2390. +
  2391. +   for (resrdx = powrdx, pow >>= 1; !bcg.signe && pow != 0; pow >>= 1) {
  2392. +       if ((s = bc_num_mul(&copy, &copy, &copy, (powrdx <<= 1)))) goto err;
  2393. +       if (pow & 1) {
  2394. +           resrdx += powrdx;
  2395. +           if ((s = bc_num_mul(c, &copy, c, resrdx))) goto err;
  2396. +       }
  2397. +   }
  2398. +
  2399. +   if (neg && (s = bc_num_inv(c, c, scale))) goto err;
  2400. +   if (bcg.signe) {
  2401. +       s = BC_STATUS_EXEC_SIGNAL;
  2402. +       goto err;
  2403. +   }
  2404. +
  2405. +   if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
  2406. +
  2407. +   for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
  2408. +   if (zero) bc_num_setToZero(c, scale);
  2409. +
  2410. +err:
  2411. +   bc_num_free(&copy);
  2412. +   return s;
  2413. +}
  2414. +
  2415. +static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
  2416. +                              BcNumBinaryOp op, size_t req)
  2417. +{
  2418. +   BcStatus s;
  2419. +   BcNum num2, *ptr_a, *ptr_b;
  2420. +   bool init = false;
  2421. +
  2422. +   if ((init = (c == a))) {
  2423. +       ptr_a = &num2;
  2424. +       memcpy(ptr_a, c, sizeof(BcNum));
  2425. +   }
  2426. +   else ptr_a = a;
  2427. +
  2428. +   if (c == b) {
  2429. +
  2430. +       ptr_b = &num2;
  2431. +
  2432. +       if (c != a) {
  2433. +           memcpy(ptr_b, c, sizeof(BcNum));
  2434. +           init = true;
  2435. +       }
  2436. +   }
  2437. +   else ptr_b = b;
  2438. +
  2439. +   if (init) s = bc_num_init(c, req);
  2440. +   else s = bc_num_expand(c, req);
  2441. +
  2442. +   if (!s) s = op(ptr_a, ptr_b, c, scale);
  2443. +
  2444. +   if (init) bc_num_free(&num2);
  2445. +   return s;
  2446. +}
  2447. +
  2448. +static bool bc_num_strValid(const char *val, size_t base) {
  2449. +
  2450. +   BcDig b;
  2451. +   bool small, radix = false;
  2452. +   size_t i, len = strlen(val);
  2453. +
  2454. +   if (!len) return true;
  2455. +
  2456. +   small = base <= 10;
  2457. +   b = (BcDig) (small ? base + '0' : base - 10 + 'A');
  2458. +
  2459. +   for (i = 0; i < len; ++i) {
  2460. +
  2461. +       BcDig c = val[i];
  2462. +
  2463. +       if (c == '.') {
  2464. +
  2465. +           if (radix) return false;
  2466. +
  2467. +           radix = true;
  2468. +           continue;
  2469. +       }
  2470. +
  2471. +       if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
  2472. +           return false;
  2473. +   }
  2474. +
  2475. +   return true;
  2476. +}
  2477. +
  2478. +static BcStatus bc_num_parseDecimal(BcNum *n, const char *val) {
  2479. +
  2480. +   BcStatus s;
  2481. +   size_t len, i;
  2482. +   const char *ptr;
  2483. +   bool zero = true;
  2484. +
  2485. +   for (i = 0; val[i] == '0'; ++i);
  2486. +
  2487. +   val += i;
  2488. +   len = strlen(val);
  2489. +   bc_num_zero(n);
  2490. +
  2491. +   if (len) {
  2492. +       for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
  2493. +       if ((s = bc_num_expand(n, len))) return s;
  2494. +   }
  2495. +
  2496. +   ptr = strchr(val, '.');
  2497. +
  2498. +   // Explicitly test for NULL here to produce either a 0 or 1.
  2499. +   n->rdx = (size_t) ((ptr != NULL) * ((val + len) - (ptr + 1)));
  2500. +
  2501. +   if (zero) return BC_STATUS_SUCCESS;
  2502. +
  2503. +   for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
  2504. +       n->num[n->len] = val[i] - '0';
  2505. +
  2506. +   return BC_STATUS_SUCCESS;
  2507. +}
  2508. +
  2509. +static BcStatus bc_num_parseBase(BcNum *n, const char *val, BcNum *base) {
  2510. +
  2511. +   BcStatus s;
  2512. +   BcNum temp, mult, result;
  2513. +   BcDig c = '\0';
  2514. +   bool zero = true;
  2515. +   unsigned long v;
  2516. +   size_t i, digits, len = strlen(val);
  2517. +
  2518. +   bc_num_zero(n);
  2519. +
  2520. +   for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
  2521. +   if (zero) return BC_STATUS_SUCCESS;
  2522. +
  2523. +   if ((s = bc_num_init(&temp, BC_NUM_DEF_SIZE))) return s;
  2524. +   if ((s = bc_num_init(&mult, BC_NUM_DEF_SIZE))) goto mult_err;
  2525. +
  2526. +   for (i = 0; i < len && (c = val[i]) != '.'; ++i) {
  2527. +
  2528. +       v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
  2529. +
  2530. +       if ((s = bc_num_m(n, base, &mult, 0))) goto int_err;
  2531. +       if ((s = bc_num_ulong2num(&temp, v))) goto int_err;
  2532. +       if ((s = bc_num_add(&mult, &temp, n, 0))) goto int_err;
  2533. +   }
  2534. +
  2535. +   if (i == len && !(c = val[i])) goto int_err;
  2536. +   if ((s = bc_num_init(&result, base->len))) goto int_err;
  2537. +
  2538. +   bc_num_zero(&result);
  2539. +   bc_num_one(&mult);
  2540. +
  2541. +   for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) {
  2542. +
  2543. +       v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
  2544. +
  2545. +       if ((s = bc_num_mul(&result, base, &result, 0))) goto err;
  2546. +       if ((s = bc_num_ulong2num(&temp, v))) goto err;
  2547. +       if ((s = bc_num_add(&result, &temp, &result, 0))) goto err;
  2548. +       if ((s = bc_num_mul(&mult, base, &mult, 0))) goto err;
  2549. +   }
  2550. +
  2551. +   if ((s = bc_num_div(&result, &mult, &result, digits))) goto err;
  2552. +   if ((s = bc_num_add(n, &result, n, digits))) goto err;
  2553. +
  2554. +   if (n->len) {
  2555. +       if (n->rdx < digits && n->len) s = bc_num_extend(n, digits - n->rdx);
  2556. +   }
  2557. +   else bc_num_zero(n);
  2558. +
  2559. +err:
  2560. +   bc_num_free(&result);
  2561. +int_err:
  2562. +   bc_num_free(&mult);
  2563. +mult_err:
  2564. +   bc_num_free(&temp);
  2565. +   return s;
  2566. +}
  2567. +
  2568. +static BcStatus bc_num_printNewline(size_t *nchars, size_t line_len) {
  2569. +   if (*nchars == line_len - 1) {
  2570. +       if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
  2571. +       if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
  2572. +       *nchars = 0;
  2573. +   }
  2574. +   return BC_STATUS_SUCCESS;
  2575. +}
  2576. +
  2577. +#ifdef CONFIG_DC
  2578. +static BcStatus bc_num_printChar(size_t num, size_t width, bool radix,
  2579. +                                 size_t *nchars, size_t line_len)
  2580. +{
  2581. +   (void) radix, (void) line_len;
  2582. +   if (putchar((char) num) == EOF) return BC_STATUS_IO_ERR;
  2583. +   *nchars = *nchars + width;
  2584. +   return BC_STATUS_SUCCESS;
  2585. +}
  2586. +#endif // CONFIG_DC
  2587. +
  2588. +static BcStatus bc_num_printDigits(size_t num, size_t width, bool radix,
  2589. +                                   size_t *nchars, size_t line_len)
  2590. +{
  2591. +   BcStatus s;
  2592. +   size_t exp, pow, div;
  2593. +
  2594. +   if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2595. +   if (putchar(radix ? '.' : ' ') == EOF) return BC_STATUS_IO_ERR;
  2596. +   ++(*nchars);
  2597. +
  2598. +   if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2599. +   for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10);
  2600. +
  2601. +   for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
  2602. +       if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2603. +       div = num / pow;
  2604. +       num -= div * pow;
  2605. +       if (putchar(((char) div) + '0') == EOF) return BC_STATUS_IO_ERR;
  2606. +   }
  2607. +
  2608. +   return BC_STATUS_SUCCESS;
  2609. +}
  2610. +
  2611. +static BcStatus bc_num_printHex(size_t num, size_t width, bool radix,
  2612. +                                size_t *nchars, size_t line_len)
  2613. +{
  2614. +   BcStatus s;
  2615. +
  2616. +   if (radix) {
  2617. +       if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2618. +       if (putchar('.') == EOF) return BC_STATUS_IO_ERR;
  2619. +       *nchars += 1;
  2620. +   }
  2621. +
  2622. +   if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2623. +   if (putchar(bc_num_hex_digits[num]) == EOF) return BC_STATUS_IO_ERR;
  2624. +   *nchars = *nchars + width;
  2625. +
  2626. +   return BC_STATUS_SUCCESS;
  2627. +}
  2628. +
  2629. +static BcStatus bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len) {
  2630. +
  2631. +   BcStatus s = BC_STATUS_SUCCESS;
  2632. +   size_t i, rdx = n->rdx - 1;
  2633. +
  2634. +   if (n->neg && putchar('-') == EOF) return BC_STATUS_IO_ERR;
  2635. +   (*nchars) += n->neg;
  2636. +
  2637. +   for (i = n->len - 1; !s && i < n->len; --i)
  2638. +       s = bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
  2639. +
  2640. +   return s;
  2641. +}
  2642. +
  2643. +static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
  2644. +                                size_t *nchars, size_t len, BcNumDigitOp print)
  2645. +{
  2646. +   BcStatus s;
  2647. +   BcVec stack;
  2648. +   BcNum intp, fracp, digit, frac_len;
  2649. +   unsigned long dig, *ptr;
  2650. +   size_t i;
  2651. +   bool radix;
  2652. +
  2653. +   if (!n->len) return print(0, width, false, nchars, len);
  2654. +
  2655. +   if ((s = bc_vec_init(&stack, sizeof(long), NULL))) return s;
  2656. +   if ((s = bc_num_init(&intp, n->len))) goto int_err;
  2657. +   if ((s = bc_num_init(&fracp, n->rdx))) goto frac_err;
  2658. +   if ((s = bc_num_init(&digit, width))) goto digit_err;
  2659. +   if ((s = bc_num_init(&frac_len, BC_NUM_INT(n)))) goto frac_len_err;
  2660. +   if ((s = bc_num_copy(&intp, n))) goto err;
  2661. +   bc_num_one(&frac_len);
  2662. +
  2663. +   bc_num_truncate(&intp, intp.rdx);
  2664. +   if ((s = bc_num_sub(n, &intp, &fracp, 0))) goto err;
  2665. +
  2666. +   while (intp.len) {
  2667. +       if ((s = bc_num_divmod(&intp, base, &intp, &digit, 0))) goto err;
  2668. +       if ((s = bc_num_ulong(&digit, &dig))) goto err;
  2669. +       if ((s = bc_vec_push(&stack, &dig))) goto err;
  2670. +   }
  2671. +
  2672. +   for (i = 0; i < stack.len; ++i) {
  2673. +       ptr = bc_vec_item_rev(&stack, i);
  2674. +       if ((s = print(*ptr, width, false, nchars, len))) goto err;
  2675. +   }
  2676. +
  2677. +   if (!n->rdx) goto err;
  2678. +
  2679. +   for (radix = true; frac_len.len <= n->rdx; radix = false) {
  2680. +       if ((s = bc_num_mul(&fracp, base, &fracp, n->rdx))) goto err;
  2681. +       if ((s = bc_num_ulong(&fracp, &dig))) goto err;
  2682. +       if ((s = bc_num_ulong2num(&intp, dig))) goto err;
  2683. +       if ((s = bc_num_sub(&fracp, &intp, &fracp, 0))) goto err;
  2684. +       if ((s = print(dig, width, radix, nchars, len))) goto err;
  2685. +       if ((s = bc_num_mul(&frac_len, base, &frac_len, 0))) goto err;
  2686. +   }
  2687. +
  2688. +err:
  2689. +   bc_num_free(&frac_len);
  2690. +frac_len_err:
  2691. +   bc_num_free(&digit);
  2692. +digit_err:
  2693. +   bc_num_free(&fracp);
  2694. +frac_err:
  2695. +   bc_num_free(&intp);
  2696. +int_err:
  2697. +   bc_vec_free(&stack);
  2698. +   return s;
  2699. +}
  2700. +
  2701. +static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
  2702. +                                 size_t *nchars, size_t line_len)
  2703. +{
  2704. +   BcStatus s;
  2705. +   size_t width, i;
  2706. +   BcNumDigitOp print;
  2707. +   bool neg = n->neg;
  2708. +
  2709. +   if (neg && putchar('-') == EOF) return BC_STATUS_IO_ERR;
  2710. +   (*nchars) += neg;
  2711. +
  2712. +   n->neg = false;
  2713. +
  2714. +   if (base_t <= BC_NUM_MAX_IBASE) {
  2715. +       width = 1;
  2716. +       print = bc_num_printHex;
  2717. +   }
  2718. +   else {
  2719. +       for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
  2720. +       print = bc_num_printDigits;
  2721. +   }
  2722. +
  2723. +   s = bc_num_printNum(n, base, width, nchars, line_len, print);
  2724. +   n->neg = neg;
  2725. +
  2726. +   return s;
  2727. +}
  2728. +
  2729. +#ifdef CONFIG_DC
  2730. +BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len) {
  2731. +   return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
  2732. +}
  2733. +#endif // CONFIG_DC
  2734. +
  2735. +BcStatus bc_num_init(BcNum *n, size_t request) {
  2736. +
  2737. +   request = request >= BC_NUM_DEF_SIZE ? request : BC_NUM_DEF_SIZE;
  2738. +   memset(n, 0, sizeof(BcNum));
  2739. +   if (!(n->num = malloc(request))) return BC_STATUS_ALLOC_ERR;
  2740. +
  2741. +   n->cap = request;
  2742. +
  2743. +   return BC_STATUS_SUCCESS;
  2744. +}
  2745. +
  2746. +BcStatus bc_num_expand(BcNum *n, size_t req) {
  2747. +
  2748. +   BcDig *temp;
  2749. +
  2750. +   req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
  2751. +
  2752. +   if (req <= n->cap) return BC_STATUS_SUCCESS;
  2753. +   if (!(temp = realloc(n->num, req))) return BC_STATUS_ALLOC_ERR;
  2754. +
  2755. +   n->num = temp;
  2756. +   n->cap = req;
  2757. +
  2758. +   return BC_STATUS_SUCCESS;
  2759. +}
  2760. +
  2761. +void bc_num_free(void *num) {
  2762. +   BcNum *n = (BcNum*) num;
  2763. +   free(n->num);
  2764. +}
  2765. +
  2766. +BcStatus bc_num_copy(BcNum *d, BcNum *s) {
  2767. +
  2768. +   BcStatus status;
  2769. +
  2770. +   if (d == s) return BC_STATUS_SUCCESS;
  2771. +   if ((status = bc_num_expand(d, s->cap))) return status;
  2772. +
  2773. +   d->len = s->len;
  2774. +   d->neg = s->neg;
  2775. +   d->rdx = s->rdx;
  2776. +
  2777. +   memcpy(d->num, s->num, sizeof(BcDig) * d->len);
  2778. +
  2779. +   return status;
  2780. +}
  2781. +
  2782. +BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base, size_t base_t) {
  2783. +
  2784. +   BcStatus s;
  2785. +
  2786. +   if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
  2787. +
  2788. +   if (base_t == 10) s = bc_num_parseDecimal(n, val);
  2789. +   else s = bc_num_parseBase(n, val, base);
  2790. +
  2791. +   return s;
  2792. +}
  2793. +
  2794. +BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
  2795. +                      size_t *nchars, size_t line_len)
  2796. +{
  2797. +   BcStatus s;
  2798. +
  2799. +   if ((s = bc_num_printNewline(nchars, line_len))) return s;
  2800. +
  2801. +   if (!n->len) {
  2802. +       if (putchar('0') == EOF) return BC_STATUS_IO_ERR;
  2803. +       ++(*nchars);
  2804. +   }
  2805. +   else if (base_t == 10) s = bc_num_printDecimal(n, nchars, line_len);
  2806. +   else s = bc_num_printBase(n, base, base_t, nchars, line_len);
  2807. +
  2808. +   if (s) return s;
  2809. +
  2810. +   if (newline) {
  2811. +       if (putchar('\n') == EOF) return BC_STATUS_IO_ERR;
  2812. +       *nchars = 0;
  2813. +   }
  2814. +
  2815. +   return s;
  2816. +}
  2817. +
  2818. +BcStatus bc_num_ulong(BcNum *n, unsigned long *result) {
  2819. +
  2820. +   size_t i;
  2821. +   unsigned long pow;
  2822. +
  2823. +   if (n->neg) return BC_STATUS_MATH_NEGATIVE;
  2824. +
  2825. +   for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
  2826. +
  2827. +       unsigned long prev = *result, powprev = pow;
  2828. +
  2829. +       *result += ((unsigned long) n->num[i]) * pow;
  2830. +       pow *= 10;
  2831. +
  2832. +       if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
  2833. +   }
  2834. +
  2835. +   return BC_STATUS_SUCCESS;
  2836. +}
  2837. +
  2838. +BcStatus bc_num_ulong2num(BcNum *n, unsigned long val) {
  2839. +
  2840. +   BcStatus s;
  2841. +   size_t len;
  2842. +   BcDig *ptr;
  2843. +   unsigned long i;
  2844. +
  2845. +   bc_num_zero(n);
  2846. +
  2847. +   if (!val) return BC_STATUS_SUCCESS;
  2848. +
  2849. +   for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len)
  2850. +   if ((s = bc_num_expand(n, len))) return s;
  2851. +   for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
  2852. +
  2853. +   return BC_STATUS_SUCCESS;
  2854. +}
  2855. +
  2856. +BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2857. +   BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
  2858. +   (void) scale;
  2859. +   return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
  2860. +}
  2861. +
  2862. +BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2863. +   BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
  2864. +   (void) scale;
  2865. +   return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
  2866. +}
  2867. +
  2868. +BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2869. +   size_t req = BC_NUM_MREQ(a, b, scale);
  2870. +   return bc_num_binary(a, b, c, scale, bc_num_m, req);
  2871. +}
  2872. +
  2873. +BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2874. +   size_t req = BC_NUM_MREQ(a, b, scale);
  2875. +   return bc_num_binary(a, b, c, scale, bc_num_d, req);
  2876. +}
  2877. +
  2878. +BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2879. +   size_t req = BC_NUM_MREQ(a, b, scale);
  2880. +   return bc_num_binary(a, b, c, scale, bc_num_rem, req);
  2881. +}
  2882. +
  2883. +BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
  2884. +   return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
  2885. +}
  2886. +
  2887. +BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale) {
  2888. +
  2889. +   BcStatus s;
  2890. +   BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
  2891. +   size_t pow, len, digits, digits1, resrdx, req, times = 0;
  2892. +   ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
  2893. +
  2894. +   req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a)+ 1) >> 1) + 1;
  2895. +
  2896. +   if ((s = bc_num_expand(b, req))) goto init_err;
  2897. +
  2898. +   if (!a->len) {
  2899. +       bc_num_setToZero(b, scale);
  2900. +       goto init_err;
  2901. +   }
  2902. +   else if (a->neg) {
  2903. +       s = BC_STATUS_MATH_NEGATIVE;
  2904. +       goto init_err;
  2905. +   }
  2906. +   else if (BC_NUM_ONE(a)) {
  2907. +       bc_num_one(b);
  2908. +       s = bc_num_extend(b, scale);
  2909. +       goto init_err;
  2910. +   }
  2911. +
  2912. +   len = a->len;
  2913. +
  2914. +   scale = BC_MAX(scale, a->rdx) + 1;
  2915. +
  2916. +   if ((s = bc_num_init(&num1, len))) goto init_err;
  2917. +   if ((s = bc_num_init(&num2, num1.len))) goto num2_err;
  2918. +   if ((s = bc_num_init(&half, BC_NUM_DEF_SIZE))) goto two_err;
  2919. +
  2920. +   bc_num_one(&half);
  2921. +   half.num[0] = 5;
  2922. +   half.rdx = 1;
  2923. +
  2924. +   len += scale;
  2925. +
  2926. +   if ((s = bc_num_init(&f, len))) goto f_err;
  2927. +   if ((s = bc_num_init(&fprime, len + scale))) goto fprime_err;
  2928. +
  2929. +   x0 = &num1;
  2930. +   x1 = &num2;
  2931. +
  2932. +   bc_num_one(x0);
  2933. +
  2934. +   if ((pow = BC_NUM_INT(a))) {
  2935. +
  2936. +       if (pow & 1) x0->num[0] = 2;
  2937. +       else x0->num[0] = 6;
  2938. +
  2939. +       pow -= 2 - (pow & 1);
  2940. +
  2941. +       if ((s = bc_num_extend(x0, pow))) goto err;
  2942. +
  2943. +       // Make sure to move the radix back.
  2944. +       x0->rdx -= pow;
  2945. +   }
  2946. +
  2947. +   x0->rdx = digits = digits1 = 0;
  2948. +   resrdx = scale + 2;
  2949. +   len = BC_NUM_INT(x0) + resrdx - 1;
  2950. +
  2951. +   while (!bcg.signe && (cmp || digits < len)) {
  2952. +
  2953. +       if ((s = bc_num_d(a, x0, &f, resrdx))) goto err;
  2954. +       if ((s = bc_num_add(x0, &f, &fprime, resrdx))) goto err;
  2955. +       if ((s = bc_num_m(&fprime, &half, x1, resrdx))) goto err;
  2956. +
  2957. +       cmp = bc_num_cmp(x1, x0);
  2958. +       digits = x1->len - (unsigned long long) llabs(cmp);
  2959. +
  2960. +       if (cmp == cmp2 && digits == digits1) times += 1;
  2961. +       else times = 0;
  2962. +
  2963. +       resrdx += times > 4;
  2964. +
  2965. +       cmp2 = cmp1;
  2966. +       cmp1 = cmp;
  2967. +       digits1 = digits;
  2968. +
  2969. +       temp = x0;
  2970. +       x0 = x1;
  2971. +       x1 = temp;
  2972. +   }
  2973. +
  2974. +   if (bcg.signe) {
  2975. +       s = BC_STATUS_EXEC_SIGNAL;
  2976. +       goto err;
  2977. +   }
  2978. +
  2979. +   if ((s = bc_num_copy(b, x0))) goto err;
  2980. +
  2981. +   if (b->rdx > --scale) bc_num_truncate(b, b->rdx - scale);
  2982. +
  2983. +err:
  2984. +   bc_num_free(&fprime);
  2985. +fprime_err:
  2986. +   bc_num_free(&f);
  2987. +f_err:
  2988. +   bc_num_free(&half);
  2989. +two_err:
  2990. +   bc_num_free(&num2);
  2991. +num2_err:
  2992. +   bc_num_free(&num1);
  2993. +init_err:
  2994. +   return s;
  2995. +}
  2996. +
  2997. +BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) {
  2998. +
  2999. +   BcStatus s;
  3000. +   BcNum num2, *ptr_a;
  3001. +   bool init;
  3002. +   size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
  3003. +
  3004. +   if ((init = (c == a))) {
  3005. +       memcpy(&num2, c, sizeof(BcNum));
  3006. +       ptr_a = &num2;
  3007. +   }
  3008. +   else ptr_a = a;
  3009. +
  3010. +   if (init) s = bc_num_init(c, len);
  3011. +   else s = bc_num_expand(d, ptr_a->len);
  3012. +
  3013. +   if (s) return s;
  3014. +
  3015. +   s = bc_num_r(ptr_a, b, c, d, scale, ts);
  3016. +
  3017. +   if (init) bc_num_free(&num2);
  3018. +
  3019. +   return s;
  3020. +}
  3021. +
  3022. +#ifdef CONFIG_DC
  3023. +BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d) {
  3024. +
  3025. +   BcStatus s;
  3026. +   BcNum base, exp, two, temp;
  3027. +
  3028. +   if ((s = bc_num_expand(d, c->len))) return s;
  3029. +
  3030. +   if (!c->len) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
  3031. +   if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
  3032. +   if (b->neg) return BC_STATUS_MATH_NEGATIVE;
  3033. +
  3034. +   if ((s = bc_num_init(&base, c->len))) return s;
  3035. +   if ((s = bc_num_init(&exp, b->len))) goto exp_err;
  3036. +   if ((s = bc_num_init(&two, BC_NUM_DEF_SIZE))) goto two_err;
  3037. +   if ((s = bc_num_init(&temp, b->len))) goto temp_err;
  3038. +
  3039. +   bc_num_one(&two);
  3040. +   two.num[0] = 2;
  3041. +   bc_num_one(d);
  3042. +
  3043. +   if ((s = bc_num_rem(a, c, &base, 0))) goto err;
  3044. +   if ((s = bc_num_copy(&exp, b))) goto err;
  3045. +
  3046. +   while (exp.len) {
  3047. +
  3048. +       if ((s = bc_num_divmod(&exp, &two, &exp, &temp, 0))) goto err;
  3049. +
  3050. +       if (BC_NUM_ONE(&temp)) {
  3051. +           if ((s = bc_num_m(d, &base, &temp, 0))) goto err;
  3052. +           if ((s = bc_num_rem(&temp, c, d, 0))) goto err;
  3053. +       }
  3054. +
  3055. +       if ((s = bc_num_m(&base, &base, &temp, 0))) goto err;
  3056. +       if ((s = bc_num_rem(&temp, c, &base, 0))) goto err;
  3057. +   }
  3058. +
  3059. +err:
  3060. +   bc_num_free(&temp);
  3061. +temp_err:
  3062. +   bc_num_free(&two);
  3063. +two_err:
  3064. +   bc_num_free(&exp);
  3065. +exp_err:
  3066. +   bc_num_free(&base);
  3067. +   return s;
  3068. +}
  3069. +#endif // CONFIG_DC
  3070. +
  3071. +int bc_id_cmp(const void *e1, const void *e2) {
  3072. +   return strcmp(((const BcId*) e1)->name, ((const BcId*) e2)->name);
  3073. +}
  3074. +
  3075. +void bc_id_free(void *id) {
  3076. +   free(((BcId*) id)->name);
  3077. +}
  3078. +
  3079. +BcStatus bc_func_insert(BcFunc *f, char *name, bool var) {
  3080. +
  3081. +   BcId a;
  3082. +   size_t i;
  3083. +
  3084. +   for (i = 0; i < f->autos.len; ++i) {
  3085. +       if (!strcmp(name, ((BcId*) bc_vec_item(&f->autos, i))->name))
  3086. +           return BC_STATUS_PARSE_DUPLICATE_LOCAL;
  3087. +   }
  3088. +
  3089. +   a.idx = var;
  3090. +   a.name = name;
  3091. +
  3092. +   return bc_vec_push(&f->autos, &a);
  3093. +}
  3094. +
  3095. +BcStatus bc_func_init(BcFunc *f) {
  3096. +
  3097. +   BcStatus s;
  3098. +
  3099. +   if ((s = bc_vec_init(&f->code, sizeof(char), NULL))) return s;
  3100. +   if ((s = bc_vec_init(&f->autos, sizeof(BcId), bc_id_free))) goto err;
  3101. +   if ((s = bc_vec_init(&f->labels, sizeof(size_t), NULL))) goto label_err;
  3102. +
  3103. +   f->nparams = 0;
  3104. +
  3105. +   return BC_STATUS_SUCCESS;
  3106. +
  3107. +label_err:
  3108. +   bc_vec_free(&f->autos);
  3109. +err:
  3110. +   bc_vec_free(&f->code);
  3111. +   return s;
  3112. +}
  3113. +
  3114. +void bc_func_free(void *func) {
  3115. +   BcFunc *f = (BcFunc*) func;
  3116. +   bc_vec_free(&f->code);
  3117. +   bc_vec_free(&f->autos);
  3118. +   bc_vec_free(&f->labels);
  3119. +}
  3120. +
  3121. +BcStatus bc_array_init(BcVec *a, bool nums) {
  3122. +
  3123. +   BcStatus s;
  3124. +
  3125. +   if (nums) s = bc_vec_init(a, sizeof(BcNum), bc_num_free);
  3126. +   else s = bc_vec_init(a, sizeof(BcVec), bc_vec_free);
  3127. +
  3128. +   if (s) return s;
  3129. +
  3130. +   if ((s = bc_array_expand(a, 1))) goto err;
  3131. +
  3132. +   return s;
  3133. +
  3134. +err:
  3135. +   bc_vec_free(a);
  3136. +   return s;
  3137. +}
  3138. +
  3139. +BcStatus bc_array_copy(BcVec *d, const BcVec *s) {
  3140. +
  3141. +   BcStatus status;
  3142. +   size_t i;
  3143. +
  3144. +   bc_vec_npop(d, d->len);
  3145. +   if ((status = bc_vec_expand(d, s->cap))) return status;
  3146. +   d->len = s->len;
  3147. +
  3148. +   for (i = 0; !status && i < s->len; ++i) {
  3149. +       BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
  3150. +       if ((status = bc_num_init(dnum, snum->len))) return status;
  3151. +       if ((status = bc_num_copy(dnum, snum))) bc_num_free(dnum);
  3152. +   }
  3153. +
  3154. +   return status;
  3155. +}
  3156. +
  3157. +BcStatus bc_array_expand(BcVec *a, size_t len) {
  3158. +
  3159. +   BcStatus s = BC_STATUS_SUCCESS;
  3160. +   BcResultData data;
  3161. +
  3162. +   if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
  3163. +       while (!s && len > a->len) {
  3164. +           if ((s = bc_num_init(&data.n, BC_NUM_DEF_SIZE))) return s;
  3165. +           if ((s = bc_vec_push(a, &data.n))) bc_num_free(&data.n);
  3166. +       }
  3167. +   }
  3168. +   else {
  3169. +       while (!s && len > a->len) {
  3170. +           if ((s = bc_array_init(&data.v, true))) return s;
  3171. +           if ((s = bc_vec_push(a, &data.v))) bc_vec_free(&data.v);
  3172. +       }
  3173. +   }
  3174. +
  3175. +   return s;
  3176. +}
  3177. +
  3178. +void bc_string_free(void *string) {
  3179. +   free(*((char**) string));
  3180. +}
  3181. +
  3182. +#ifdef CONFIG_DC
  3183. +BcStatus bc_result_copy(BcResult *d, BcResult *src) {
  3184. +
  3185. +   BcStatus s = BC_STATUS_SUCCESS;
  3186. +
  3187. +   switch ((d->t = src->t)) {
  3188. +
  3189. +       case BC_RESULT_TEMP:
  3190. +       case BC_RESULT_IBASE:
  3191. +       case BC_RESULT_SCALE:
  3192. +       case BC_RESULT_OBASE:
  3193. +       {
  3194. +           if ((s = bc_num_init(&d->d.n, src->d.n.len))) return s;
  3195. +           s = bc_num_copy(&d->d.n, &src->d.n);
  3196. +           break;
  3197. +       }
  3198. +
  3199. +       case BC_RESULT_VAR:
  3200. +       case BC_RESULT_ARRAY:
  3201. +       case BC_RESULT_ARRAY_ELEM:
  3202. +       {
  3203. +           if ((d->d.id.name = strdup(src->d.id.name))) s = BC_STATUS_SUCCESS;
  3204. +           else s = BC_STATUS_ALLOC_ERR;
  3205. +           break;
  3206. +       }
  3207. +
  3208. +       case BC_RESULT_CONSTANT:
  3209. +       case BC_RESULT_LAST:
  3210. +       case BC_RESULT_ONE:
  3211. +       case BC_RESULT_STR:
  3212. +       {
  3213. +           memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
  3214. +           break;
  3215. +       }
  3216. +   }
  3217. +
  3218. +   return s;
  3219. +}
  3220. +#endif // CONFIG_DC
  3221. +
  3222. +void bc_result_free(void *result) {
  3223. +
  3224. +   BcResult *r = (BcResult*) result;
  3225. +
  3226. +   switch (r->t) {
  3227. +
  3228. +       case BC_RESULT_TEMP:
  3229. +       case BC_RESULT_IBASE:
  3230. +       case BC_RESULT_SCALE:
  3231. +       case BC_RESULT_OBASE:
  3232. +       {
  3233. +           bc_num_free(&r->d.n);
  3234. +           break;
  3235. +       }
  3236. +
  3237. +       case BC_RESULT_VAR:
  3238. +       case BC_RESULT_ARRAY:
  3239. +       case BC_RESULT_ARRAY_ELEM:
  3240. +       {
  3241. +           free(r->d.id.name);
  3242. +           break;
  3243. +       }
  3244. +
  3245. +       default:
  3246. +       {
  3247. +           // Do nothing.
  3248. +           break;
  3249. +       }
  3250. +   }
  3251. +}
  3252. +
  3253. +void bc_lex_lineComment(BcLex *l) {
  3254. +   l->t.t = BC_LEX_WHITESPACE;
  3255. +   while (l->idx < l->len && l->buffer[l->idx++] != '\n');
  3256. +   --l->idx;
  3257. +}
  3258. +
  3259. +void bc_lex_whitespace(BcLex *l) {
  3260. +   char c;
  3261. +   l->t.t = BC_LEX_WHITESPACE;
  3262. +   for (; (c = l->buffer[l->idx]) != '\n' && isspace(c); ++l->idx);
  3263. +}
  3264. +
  3265. +BcStatus bc_lex_number(BcLex *l, char start) {
  3266. +
  3267. +   BcStatus s;
  3268. +   const char *buf = l->buffer + l->idx;
  3269. +   size_t len, hits = 0, bslashes = 0, i = 0, j;
  3270. +   char c = buf[i];
  3271. +   bool last_pt, pt = start == '.';
  3272. +
  3273. +   last_pt = pt;
  3274. +   l->t.t = BC_LEX_NUMBER;
  3275. +
  3276. +   while (c && (isdigit(c) || (c >= 'A' && c <= 'F') ||
  3277. +                (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
  3278. +   {
  3279. +       if (c != '\\') {
  3280. +           last_pt = c == '.';
  3281. +           pt = pt || last_pt;
  3282. +       }
  3283. +       else {
  3284. +           ++i;
  3285. +           bslashes += 1;
  3286. +       }
  3287. +
  3288. +       c = buf[++i];
  3289. +   }
  3290. +
  3291. +   len = i + 1 * !last_pt - bslashes * 2;
  3292. +   if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
  3293. +
  3294. +   bc_vec_npop(&l->t.v, l->t.v.len);
  3295. +   if ((s = bc_vec_expand(&l->t.v, len + 1))) return s;
  3296. +   if ((s = bc_vec_push(&l->t.v, &start))) return s;
  3297. +
  3298. +   for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
  3299. +
  3300. +       c = buf[j];
  3301. +
  3302. +       // If we have hit a backslash, skip it. We don't have
  3303. +       // to check for a newline because it's guaranteed.
  3304. +       if (hits < bslashes && c == '\\') {
  3305. +           ++hits;
  3306. +           ++j;
  3307. +           continue;
  3308. +       }
  3309. +
  3310. +       if ((s = bc_vec_push(&l->t.v, &c))) return s;
  3311. +   }
  3312. +
  3313. +   if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s;
  3314. +   l->idx += i;
  3315. +
  3316. +   return BC_STATUS_SUCCESS;
  3317. +}
  3318. +
  3319. +BcStatus bc_lex_name(BcLex *l) {
  3320. +
  3321. +   BcStatus s;
  3322. +   size_t i = 0;
  3323. +   const char *buf = l->buffer + l->idx - 1;
  3324. +   char c = buf[i];
  3325. +
  3326. +   l->t.t = BC_LEX_NAME;
  3327. +
  3328. +   while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
  3329. +
  3330. +   if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
  3331. +   if ((s = bc_vec_string(&l->t.v, i, buf))) return s;
  3332. +
  3333. +   // Increment the index. We minus 1 because it has already been incremented.
  3334. +   l->idx += i - 1;
  3335. +
  3336. +   return BC_STATUS_SUCCESS;
  3337. +}
  3338. +
  3339. +BcStatus bc_lex_init(BcLex *l, BcLexNext next) {
  3340. +   l->next = next;
  3341. +   return bc_vec_init(&l->t.v, sizeof(uint8_t), NULL);
  3342. +}
  3343. +
  3344. +void bc_lex_free(BcLex *l) {
  3345. +   bc_vec_free(&l->t.v);
  3346. +}
  3347. +
  3348. +void bc_lex_file(BcLex *l, const char *file) {
  3349. +   l->line = 1;
  3350. +   l->newline = false;
  3351. +   l->f = file;
  3352. +}
  3353. +
  3354. +BcStatus bc_lex_next(BcLex *l) {
  3355. +
  3356. +   BcStatus s;
  3357. +
  3358. +   if ((l->t.last = l->t.t) == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
  3359. +
  3360. +   l->line += l->newline;
  3361. +   l->t.t = BC_LEX_EOF;
  3362. +
  3363. +   if ((l->newline = (l->idx == l->len))) return BC_STATUS_SUCCESS;
  3364. +
  3365. +   // Loop until failure or we don't have whitespace. This
  3366. +   // is so the parser doesn't get inundated with whitespace.
  3367. +   while (!(s = l->next(l)) && l->t.t == BC_LEX_WHITESPACE);
  3368. +
  3369. +   return s;
  3370. +}
  3371. +
  3372. +BcStatus bc_lex_text(BcLex *l, const char *text) {
  3373. +   l->buffer = text;
  3374. +   l->idx = 0;
  3375. +   l->len = strlen(text);
  3376. +   l->t.t = l->t.last = BC_LEX_INVALID;
  3377. +   return bc_lex_next(l);
  3378. +}
  3379. +
  3380. +#ifdef CONFIG_BC
  3381. +static BcStatus bc_lex_identifier(BcLex *l) {
  3382. +
  3383. +   BcStatus s;
  3384. +   size_t i;
  3385. +   const char *buf = l->buffer + l->idx - 1;
  3386. +
  3387. +   for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
  3388. +
  3389. +       unsigned long len = (unsigned long) bc_lex_kws[i].len;
  3390. +
  3391. +       if (!strncmp(buf, bc_lex_kws[i].name, len)) {
  3392. +
  3393. +           l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
  3394. +
  3395. +           if (!bc_lex_kws[i].posix &&
  3396. +               (s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f,
  3397. +                                     l->line, bc_lex_kws[i].name)))
  3398. +           {
  3399. +               return s;
  3400. +           }
  3401. +
  3402. +           // We minus 1 because the index has already been incremented.
  3403. +           l->idx += len - 1;
  3404. +           return BC_STATUS_SUCCESS;
  3405. +       }
  3406. +   }
  3407. +
  3408. +   if ((s = bc_lex_name(l))) return s;
  3409. +
  3410. +   if (l->t.v.len - 1 > 1)
  3411. +       s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
  3412. +
  3413. +   return s;
  3414. +}
  3415. +
  3416. +static BcStatus bc_lex_string(BcLex *l) {
  3417. +
  3418. +   BcStatus s;
  3419. +   size_t len, nls = 0, i = l->idx;
  3420. +   char c;
  3421. +
  3422. +   l->t.t = BC_LEX_STR;
  3423. +
  3424. +   for (; (c = l->buffer[i]) && c != '"'; ++i) nls += (c == '\n');
  3425. +
  3426. +   if (c == '\0') {
  3427. +       l->idx = i;
  3428. +       return BC_STATUS_LEX_NO_STRING_END;
  3429. +   }
  3430. +
  3431. +   if ((len = i - l->idx) > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
  3432. +   if ((s = bc_vec_string(&l->t.v, len, l->buffer + l->idx))) return s;
  3433. +
  3434. +   l->idx = i + 1;
  3435. +   l->line += nls;
  3436. +
  3437. +   return BC_STATUS_SUCCESS;
  3438. +}
  3439. +
  3440. +static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) {
  3441. +   if (l->buffer[l->idx] == '=') {
  3442. +       ++l->idx;
  3443. +       l->t.t = with;
  3444. +   }
  3445. +   else l->t.t = without;
  3446. +}
  3447. +
  3448. +static BcStatus bc_lex_comment(BcLex *l) {
  3449. +
  3450. +   size_t i, nls = 0;
  3451. +   const char *buf = l->buffer;
  3452. +   bool end = false;
  3453. +   char c;
  3454. +
  3455. +   l->t.t = BC_LEX_WHITESPACE;
  3456. +
  3457. +   for (i = ++l->idx; !end; i += !end) {
  3458. +
  3459. +       for (; (c = buf[i]) != '*' && c != '\0'; ++i) nls += (c == '\n');
  3460. +
  3461. +       if (c == '\0' || buf[i + 1] == '\0') {
  3462. +           l->idx = i;
  3463. +           return BC_STATUS_LEX_NO_COMMENT_END;
  3464. +       }
  3465. +
  3466. +       end = buf[i + 1] == '/';
  3467. +   }
  3468. +
  3469. +   l->idx = i + 2;
  3470. +   l->line += nls;
  3471. +
  3472. +   return BC_STATUS_SUCCESS;
  3473. +}
  3474. +
  3475. +BcStatus bc_lex_token(BcLex *l) {
  3476. +
  3477. +   BcStatus s = BC_STATUS_SUCCESS;
  3478. +   char c, c2;
  3479. +
  3480. +   // This is the workhorse of the lexer.
  3481. +   switch ((c = l->buffer[l->idx++])) {
  3482. +
  3483. +       case '\0':
  3484. +       case '\n':
  3485. +       {
  3486. +           l->newline = true;
  3487. +           l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
  3488. +           break;
  3489. +       }
  3490. +
  3491. +       case '\t':
  3492. +       case '\v':
  3493. +       case '\f':
  3494. +       case '\r':
  3495. +       case ' ':
  3496. +       {
  3497. +           bc_lex_whitespace(l);
  3498. +           break;
  3499. +       }
  3500. +
  3501. +       case '!':
  3502. +       {
  3503. +           bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
  3504. +
  3505. +           if (l->t.t == BC_LEX_OP_BOOL_NOT &&
  3506. +               (s = bc_vm_posixError(BC_STATUS_POSIX_BOOL_OPS,
  3507. +                                     l->f, l->line, "!")))
  3508. +           {
  3509. +               return s;
  3510. +           }
  3511. +
  3512. +           break;
  3513. +       }
  3514. +
  3515. +       case '"':
  3516. +       {
  3517. +           s = bc_lex_string(l);
  3518. +           break;
  3519. +       }
  3520. +
  3521. +       case '#':
  3522. +       {
  3523. +           if ((s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT,
  3524. +                                     l->f, l->line, NULL)))
  3525. +           {
  3526. +               return s;
  3527. +           }
  3528. +
  3529. +           bc_lex_lineComment(l);
  3530. +
  3531. +           break;
  3532. +       }
  3533. +
  3534. +       case '%':
  3535. +       {
  3536. +           bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
  3537. +           break;
  3538. +       }
  3539. +
  3540. +       case '&':
  3541. +       {
  3542. +           if ((c2 = l->buffer[l->idx]) == '&') {
  3543. +
  3544. +               if ((s = bc_vm_posixError(BC_STATUS_POSIX_BOOL_OPS,
  3545. +                                         l->f, l->line, "&&")))
  3546. +               {
  3547. +                   return s;
  3548. +               }
  3549. +
  3550. +               ++l->idx;
  3551. +               l->t.t = BC_LEX_OP_BOOL_AND;
  3552. +           }
  3553. +           else {
  3554. +               l->t.t = BC_LEX_INVALID;
  3555. +               s = BC_STATUS_LEX_BAD_CHAR;
  3556. +           }
  3557. +
  3558. +           break;
  3559. +       }
  3560. +
  3561. +       case '(':
  3562. +       case ')':
  3563. +       {
  3564. +           l->t.t = (BcLexType) (c - '(' + BC_LEX_LPAREN);
  3565. +           break;
  3566. +       }
  3567. +
  3568. +       case '*':
  3569. +       {
  3570. +           bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
  3571. +           break;
  3572. +       }
  3573. +
  3574. +       case '+':
  3575. +       {
  3576. +           if ((c2 = l->buffer[l->idx]) == '+') {
  3577. +               ++l->idx;
  3578. +               l->t.t = BC_LEX_OP_INC;
  3579. +           }
  3580. +           else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
  3581. +           break;
  3582. +       }
  3583. +
  3584. +       case ',':
  3585. +       {
  3586. +           l->t.t = BC_LEX_COMMA;
  3587. +           break;
  3588. +       }
  3589. +
  3590. +       case '-':
  3591. +       {
  3592. +           if ((c2 = l->buffer[l->idx]) == '-') {
  3593. +               ++l->idx;
  3594. +               l->t.t = BC_LEX_OP_DEC;
  3595. +           }
  3596. +           else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
  3597. +           break;
  3598. +       }
  3599. +
  3600. +       case '.':
  3601. +       {
  3602. +           if (isdigit(l->buffer[l->idx])) s = bc_lex_number(l, c);
  3603. +           else {
  3604. +               l->t.t = BC_LEX_KEY_LAST;
  3605. +               s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
  3606. +           }
  3607. +           break;
  3608. +       }
  3609. +
  3610. +       case '/':
  3611. +       {
  3612. +           if ((c2 = l->buffer[l->idx]) =='*') s = bc_lex_comment(l);
  3613. +           else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
  3614. +           break;
  3615. +       }
  3616. +
  3617. +       case '0':
  3618. +       case '1':
  3619. +       case '2':
  3620. +       case '3':
  3621. +       case '4':
  3622. +       case '5':
  3623. +       case '6':
  3624. +       case '7':
  3625. +       case '8':
  3626. +       case '9':
  3627. +       case 'A':
  3628. +       case 'B':
  3629. +       case 'C':
  3630. +       case 'D':
  3631. +       case 'E':
  3632. +       case 'F':
  3633. +       {
  3634. +           s = bc_lex_number(l, c);
  3635. +           break;
  3636. +       }
  3637. +
  3638. +       case ';':
  3639. +       {
  3640. +           l->t.t = BC_LEX_SCOLON;
  3641. +           break;
  3642. +       }
  3643. +
  3644. +       case '<':
  3645. +       {
  3646. +           bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
  3647. +           break;
  3648. +       }
  3649. +
  3650. +       case '=':
  3651. +       {
  3652. +           bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
  3653. +           break;
  3654. +       }
  3655. +
  3656. +       case '>':
  3657. +       {
  3658. +           bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
  3659. +           break;
  3660. +       }
  3661. +
  3662. +       case '[':
  3663. +       case ']':
  3664. +       {
  3665. +           l->t.t = (BcLexType) (c - '[' + BC_LEX_LBRACKET);
  3666. +           break;
  3667. +       }
  3668. +
  3669. +       case '\\':
  3670. +       {
  3671. +           if (l->buffer[l->idx] == '\n') {
  3672. +               l->t.t = BC_LEX_WHITESPACE;
  3673. +               ++l->idx;
  3674. +           }
  3675. +           else s = BC_STATUS_LEX_BAD_CHAR;
  3676. +           break;
  3677. +       }
  3678. +
  3679. +       case '^':
  3680. +       {
  3681. +           bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
  3682. +           break;
  3683. +       }
  3684. +
  3685. +       case 'a':
  3686. +       case 'b':
  3687. +       case 'c':
  3688. +       case 'd':
  3689. +       case 'e':
  3690. +       case 'f':
  3691. +       case 'g':
  3692. +       case 'h':
  3693. +       case 'i':
  3694. +       case 'j':
  3695. +       case 'k':
  3696. +       case 'l':
  3697. +       case 'm':
  3698. +       case 'n':
  3699. +       case 'o':
  3700. +       case 'p':
  3701. +       case 'q':
  3702. +       case 'r':
  3703. +       case 's':
  3704. +       case 't':
  3705. +       case 'u':
  3706. +       case 'v':
  3707. +       case 'w':
  3708. +       case 'x':
  3709. +       case 'y':
  3710. +       case 'z':
  3711. +       {
  3712. +           s = bc_lex_identifier(l);
  3713. +           break;
  3714. +       }
  3715. +
  3716. +       case '{':
  3717. +       case '}':
  3718. +       {
  3719. +           l->t.t = (BcLexType) (c - '{' + BC_LEX_LBRACE);
  3720. +           break;
  3721. +       }
  3722. +
  3723. +       case '|':
  3724. +       {
  3725. +           if ((c2 = l->buffer[l->idx]) == '|') {
  3726. +
  3727. +               if ((s = bc_vm_posixError(BC_STATUS_POSIX_BOOL_OPS,
  3728. +                                         l->f, l->line, "||")))
  3729. +               {
  3730. +                   return s;
  3731. +               }
  3732. +
  3733. +               ++l->idx;
  3734. +               l->t.t = BC_LEX_OP_BOOL_OR;
  3735. +           }
  3736. +           else {
  3737. +               l->t.t = BC_LEX_INVALID;
  3738. +               s = BC_STATUS_LEX_BAD_CHAR;
  3739. +           }
  3740. +
  3741. +           break;
  3742. +       }
  3743. +
  3744. +       default:
  3745. +       {
  3746. +           l->t.t = BC_LEX_INVALID;
  3747. +           s = BC_STATUS_LEX_BAD_CHAR;
  3748. +           break;
  3749. +       }
  3750. +   }
  3751. +
  3752. +   return s;
  3753. +}
  3754. +#endif // CONFIG_BC
  3755. +
  3756. +#ifdef CONFIG_DC
  3757. +static BcStatus dc_lex_register(BcLex *l) {
  3758. +
  3759. +   BcStatus s;
  3760. +
  3761. +   if (isspace(l->buffer[l->idx - 1])) {
  3762. +       bc_lex_whitespace(l);
  3763. +       ++l->idx;
  3764. +       if (!bcg.exreg) s = BC_STATUS_LEX_EXTENDED_REG;
  3765. +       else s = bc_lex_name(l);
  3766. +   }
  3767. +   else {
  3768. +       bc_vec_npop(&l->t.v, l->t.v.len);
  3769. +       if ((s = bc_vec_pushByte(&l->t.v, l->buffer[l->idx - 1]))) return s;
  3770. +       s = bc_vec_pushByte(&l->t.v, '\0');
  3771. +       l->t.t = BC_LEX_NAME;
  3772. +   }
  3773. +
  3774. +   return s;
  3775. +}
  3776. +
  3777. +static BcStatus dc_lex_string(BcLex *l) {
  3778. +
  3779. +   BcStatus s;
  3780. +   size_t depth = 1, nls = 0, i = l->idx;
  3781. +   char c;
  3782. +
  3783. +   l->t.t = BC_LEX_STR;
  3784. +   bc_vec_npop(&l->t.v, l->t.v.len);
  3785. +
  3786. +   for (; (c = l->buffer[i]) && depth; ++i) {
  3787. +
  3788. +       depth += (c == '[' && (i == l->idx || l->buffer[i - 1] != '\\'));
  3789. +       depth -= (c == ']' && (i == l->idx || l->buffer[i - 1] != '\\'));
  3790. +       nls += (c == '\n');
  3791. +
  3792. +       if (depth && (s = bc_vec_push(&l->t.v, &c))) return s;
  3793. +   }
  3794. +
  3795. +   if (c == '\0') {
  3796. +       l->idx = i;
  3797. +       return BC_STATUS_LEX_NO_STRING_END;
  3798. +   }
  3799. +
  3800. +   if ((s = bc_vec_pushByte(&l->t.v, '\0'))) return s;
  3801. +   if (i - l->idx > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
  3802. +
  3803. +   l->idx = i;
  3804. +   l->line += nls;
  3805. +
  3806. +   return BC_STATUS_SUCCESS;
  3807. +}
  3808. +
  3809. +BcStatus dc_lex_token(BcLex *l) {
  3810. +
  3811. +   BcStatus s = BC_STATUS_SUCCESS;
  3812. +   char c = l->buffer[l->idx++], c2;
  3813. +   size_t i;
  3814. +
  3815. +   for (i = 0; i < dc_lex_regs_len; ++i) {
  3816. +       if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
  3817. +   }
  3818. +
  3819. +   if (c >= '%' && c <= '~' &&
  3820. +       (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
  3821. +   {
  3822. +       return s;
  3823. +   }
  3824. +
  3825. +   // This is the workhorse of the lexer.
  3826. +   switch (c) {
  3827. +
  3828. +       case '\0':
  3829. +       {
  3830. +           l->t.t = BC_LEX_EOF;
  3831. +           break;
  3832. +       }
  3833. +
  3834. +       case '\n':
  3835. +       case '\t':
  3836. +       case '\v':
  3837. +       case '\f':
  3838. +       case '\r':
  3839. +       case ' ':
  3840. +       {
  3841. +           l->newline = (c == '\n');
  3842. +           bc_lex_whitespace(l);
  3843. +           break;
  3844. +       }
  3845. +
  3846. +       case '!':
  3847. +       {
  3848. +           c2 = l->buffer[l->idx];
  3849. +
  3850. +           if (c2 == '=') l->t.t = BC_LEX_OP_REL_NE;
  3851. +           else if (c2 == '<') l->t.t = BC_LEX_OP_REL_LE;
  3852. +           else if (c2 == '>') l->t.t = BC_LEX_OP_REL_GE;
  3853. +           else return BC_STATUS_LEX_BAD_CHAR;
  3854. +
  3855. +           ++l->idx;
  3856. +           break;
  3857. +       }
  3858. +
  3859. +       case '#':
  3860. +       {
  3861. +           bc_lex_lineComment(l);
  3862. +           break;
  3863. +       }
  3864. +
  3865. +       case '.':
  3866. +       {
  3867. +           if (isdigit(l->buffer[l->idx])) s = bc_lex_number(l, c);
  3868. +           else s = BC_STATUS_LEX_BAD_CHAR;
  3869. +           break;
  3870. +       }
  3871. +
  3872. +       case '0':
  3873. +       case '1':
  3874. +       case '2':
  3875. +       case '3':
  3876. +       case '4':
  3877. +       case '5':
  3878. +       case '6':
  3879. +       case '7':
  3880. +       case '8':
  3881. +       case '9':
  3882. +       case 'A':
  3883. +       case 'B':
  3884. +       case 'C':
  3885. +       case 'D':
  3886. +       case 'E':
  3887. +       case 'F':
  3888. +       {
  3889. +           s = bc_lex_number(l, c);
  3890. +           break;
  3891. +       }
  3892. +
  3893. +       case '[':
  3894. +       {
  3895. +           s = dc_lex_string(l);
  3896. +           break;
  3897. +       }
  3898. +
  3899. +       default:
  3900. +       {
  3901. +           l->t.t = BC_LEX_INVALID;
  3902. +           s = BC_STATUS_LEX_BAD_CHAR;
  3903. +           break;
  3904. +       }
  3905. +   }
  3906. +
  3907. +   return s;
  3908. +}
  3909. +#endif // CONFIG_DC
  3910. +
  3911. +BcStatus bc_parse_addFunc(BcParse *p, char *name, size_t *idx) {
  3912. +   BcStatus s = bc_program_addFunc(p->prog, name, idx);
  3913. +   p->func = bc_vec_item(&p->prog->fns, p->fidx);
  3914. +   return s;
  3915. +}
  3916. +
  3917. +BcStatus bc_parse_pushName(BcParse *p, char *name) {
  3918. +
  3919. +   BcStatus s = BC_STATUS_SUCCESS;
  3920. +   size_t i = 0, len = strlen(name);
  3921. +
  3922. +   for (; !s && i < len; ++i) s = bc_parse_push(p, (char) name[i]);
  3923. +   if (s || (s = bc_parse_push(p, BC_PARSE_STREND))) return s;
  3924. +
  3925. +   free(name);
  3926. +
  3927. +   return s;
  3928. +}
  3929. +
  3930. +BcStatus bc_parse_pushIndex(BcParse *p, size_t idx) {
  3931. +
  3932. +   BcStatus s;
  3933. +   unsigned char amt, i, nums[sizeof(size_t)];
  3934. +
  3935. +   for (amt = 0; idx; ++amt) {
  3936. +       nums[amt] = (char) idx;
  3937. +       idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
  3938. +   }
  3939. +
  3940. +   if ((s = bc_parse_push(p, amt))) return s;
  3941. +   for (i = 0; !s && i < amt; ++i) s = bc_parse_push(p, nums[i]);
  3942. +
  3943. +   return s;
  3944. +}
  3945. +
  3946. +BcStatus bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs) {
  3947. +
  3948. +   BcStatus s;
  3949. +   char *num;
  3950. +   size_t idx = p->prog->consts.len;
  3951. +
  3952. +   if (!(num = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  3953. +
  3954. +   if ((s = bc_vec_push(&p->prog->consts, &num))) {
  3955. +       free(num);
  3956. +       return s;
  3957. +   }
  3958. +
  3959. +   if ((s = bc_parse_push(p, BC_INST_NUM))) return s;
  3960. +   if ((s = bc_parse_pushIndex(p, idx))) return s;
  3961. +
  3962. +   ++(*nexs);
  3963. +   (*prev) = BC_INST_NUM;
  3964. +
  3965. +   return s;
  3966. +}
  3967. +
  3968. +BcStatus bc_parse_text(BcParse *p, const char *text) {
  3969. +
  3970. +   BcStatus s;
  3971. +
  3972. +   p->func = bc_vec_item(&p->prog->fns, p->fidx);
  3973. +
  3974. +   if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
  3975. +       p->l.t.t = BC_LEX_INVALID;
  3976. +       if ((s = p->parse(p))) return s;
  3977. +       if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
  3978. +   }
  3979. +
  3980. +   return bc_lex_text(&p->l, text);
  3981. +}
  3982. +
  3983. +BcStatus bc_parse_reset(BcParse *p, BcStatus s) {
  3984. +
  3985. +   if (p->fidx != BC_PROG_MAIN) {
  3986. +
  3987. +       p->func->nparams = 0;
  3988. +       bc_vec_npop(&p->func->code, p->func->code.len);
  3989. +       bc_vec_npop(&p->func->autos, p->func->autos.len);
  3990. +       bc_vec_npop(&p->func->labels, p->func->labels.len);
  3991. +
  3992. +       bc_parse_updateFunc(p, BC_PROG_MAIN);
  3993. +   }
  3994. +
  3995. +   p->l.idx = p->l.len;
  3996. +   p->l.t.t = BC_LEX_EOF;
  3997. +   p->auto_part = (p->nbraces = 0);
  3998. +
  3999. +   bc_vec_npop(&p->flags, p->flags.len - 1);
  4000. +   bc_vec_npop(&p->exits, p->exits.len);
  4001. +   bc_vec_npop(&p->conds, p->conds.len);
  4002. +   bc_vec_npop(&p->ops, p->ops.len);
  4003. +
  4004. +   return bc_program_reset(p->prog, s);
  4005. +}
  4006. +
  4007. +void bc_parse_free(BcParse *p) {
  4008. +   bc_vec_free(&p->flags);
  4009. +   bc_vec_free(&p->exits);
  4010. +   bc_vec_free(&p->conds);
  4011. +   bc_vec_free(&p->ops);
  4012. +   bc_lex_free(&p->l);
  4013. +}
  4014. +
  4015. +BcStatus bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
  4016. +                         BcParseParse parse, BcLexNext next)
  4017. +{
  4018. +   BcStatus s;
  4019. +
  4020. +   memset(p, 0, sizeof(BcParse));
  4021. +
  4022. +   if ((s = bc_lex_init(&p->l, next))) return s;
  4023. +   if ((s = bc_vec_init(&p->flags, sizeof(uint8_t), NULL))) goto err;
  4024. +   if ((s = bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL))) goto err;
  4025. +   if ((s = bc_vec_init(&p->conds, sizeof(size_t), NULL))) goto err;
  4026. +   if ((s = bc_vec_pushByte(&p->flags, 0))) goto err;
  4027. +   if ((s = bc_vec_init(&p->ops, sizeof(BcLexType), NULL))) goto err;
  4028. +
  4029. +   p->parse = parse;
  4030. +   p->prog = prog;
  4031. +   p->auto_part = (p->nbraces = 0);
  4032. +   bc_parse_updateFunc(p, func);
  4033. +
  4034. +   return s;
  4035. +
  4036. +err:
  4037. +   bc_parse_free(p);
  4038. +   return s;
  4039. +}
  4040. +
  4041. +#ifdef CONFIG_BC
  4042. +static BcStatus bc_parse_else(BcParse *p);
  4043. +static BcStatus bc_parse_stmt(BcParse *p);
  4044. +
  4045. +static BcStatus bc_parse_operator(BcParse *p, BcVec *ops, BcLexType type,
  4046. +                                  size_t start, size_t *nexprs, bool next)
  4047. +{
  4048. +   BcStatus s;
  4049. +   BcLexType t;
  4050. +   uint8_t l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
  4051. +   bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
  4052. +
  4053. +   while (ops->len > start &&
  4054. +          (t = *((BcLexType*) bc_vec_top(ops))) != BC_LEX_LPAREN &&
  4055. +          ((l = bc_parse_ops[t - BC_LEX_OP_INC].prec) < r || (l == r && left)))
  4056. +   {
  4057. +       if ((s = bc_parse_push(p, BC_PARSE_TOKEN_INST(t)))) return s;
  4058. +       bc_vec_pop(ops);
  4059. +       *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
  4060. +   }
  4061. +
  4062. +   if ((s = bc_vec_push(ops, &type))) return s;
  4063. +   if (next) s = bc_lex_next(&p->l);
  4064. +
  4065. +   return s;
  4066. +}
  4067. +
  4068. +static BcStatus bc_parse_rightParen(BcParse *p, BcVec *ops, size_t *nexs) {
  4069. +
  4070. +   BcStatus s;
  4071. +   BcLexType top;
  4072. +
  4073. +   if (!ops->len) return BC_STATUS_PARSE_BAD_EXP;
  4074. +
  4075. +   while ((top = *((BcLexType*) bc_vec_top(ops))) != BC_LEX_LPAREN) {
  4076. +
  4077. +       if ((s = bc_parse_push(p, BC_PARSE_TOKEN_INST(top)))) return s;
  4078. +
  4079. +       bc_vec_pop(ops);
  4080. +       *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
  4081. +
  4082. +       if (!ops->len) return BC_STATUS_PARSE_BAD_EXP;
  4083. +   }
  4084. +
  4085. +   bc_vec_pop(ops);
  4086. +
  4087. +   return bc_lex_next(&p->l);
  4088. +}
  4089. +
  4090. +static BcStatus bc_parse_params(BcParse *p, uint8_t flags) {
  4091. +
  4092. +   BcStatus s;
  4093. +   bool comma = false;
  4094. +   size_t nparams;
  4095. +
  4096. +   if ((s = bc_lex_next(&p->l))) return s;
  4097. +
  4098. +   for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
  4099. +
  4100. +       flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
  4101. +       if ((s = bc_parse_expr(p, flags, bc_parse_next_param))) return s;
  4102. +
  4103. +       comma = p->l.t.t == BC_LEX_COMMA;
  4104. +       if (comma && (s = bc_lex_next(&p->l))) return s;
  4105. +   }
  4106. +
  4107. +   if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
  4108. +   if ((s = bc_parse_push(p, BC_INST_CALL))) return s;
  4109. +
  4110. +   return bc_parse_pushIndex(p, nparams);
  4111. +}
  4112. +
  4113. +static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) {
  4114. +
  4115. +   BcStatus s;
  4116. +   BcId entry, *entry_ptr;
  4117. +   size_t idx;
  4118. +
  4119. +   entry.name = name;
  4120. +
  4121. +    if ((s = bc_parse_params(p, flags))) goto err;
  4122. +
  4123. +   if (p->l.t.t != BC_LEX_RPAREN) {
  4124. +       s = BC_STATUS_PARSE_BAD_TOKEN;
  4125. +       goto err;
  4126. +   }
  4127. +
  4128. +   idx = bc_map_index(&p->prog->fn_map, &entry);
  4129. +
  4130. +   if (idx == BC_VEC_INVALID_IDX) {
  4131. +
  4132. +       if ((s = bc_parse_addFunc(p, name, &idx))) return s;
  4133. +
  4134. +       name = NULL;
  4135. +       idx = bc_map_index(&p->prog->fn_map, &entry);
  4136. +   }
  4137. +   else free(name);
  4138. +
  4139. +   entry_ptr = bc_map_item(&p->prog->fn_map, idx);
  4140. +   if ((s = bc_parse_pushIndex(p, entry_ptr->idx))) return s;
  4141. +
  4142. +   return bc_lex_next(&p->l);
  4143. +
  4144. +err:
  4145. +   free(name);
  4146. +   return s;
  4147. +}
  4148. +
  4149. +static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) {
  4150. +
  4151. +   BcStatus s;
  4152. +   char *name;
  4153. +
  4154. +   if (!(name = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  4155. +   if ((s = bc_lex_next(&p->l))) goto err;
  4156. +
  4157. +   if (p->l.t.t == BC_LEX_LBRACKET) {
  4158. +
  4159. +       if ((s = bc_lex_next(&p->l))) goto err;
  4160. +
  4161. +       if (p->l.t.t == BC_LEX_RBRACKET) {
  4162. +
  4163. +           if (!(flags & BC_PARSE_ARRAY)) {
  4164. +               s = BC_STATUS_PARSE_BAD_EXP;
  4165. +               goto err;
  4166. +           }
  4167. +
  4168. +           *type = BC_INST_ARRAY;
  4169. +       }
  4170. +       else {
  4171. +
  4172. +           *type = BC_INST_ARRAY_ELEM;
  4173. +
  4174. +           flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
  4175. +           if ((s = bc_parse_expr(p, flags, bc_parse_next_elem))) goto err;
  4176. +       }
  4177. +
  4178. +       if ((s = bc_lex_next(&p->l))) goto err;
  4179. +       if ((s = bc_parse_push(p, (char) *type))) goto err;
  4180. +       s = bc_parse_pushName(p, name);
  4181. +   }
  4182. +   else if (p->l.t.t == BC_LEX_LPAREN) {
  4183. +
  4184. +       if (flags & BC_PARSE_NOCALL) {
  4185. +           s = BC_STATUS_PARSE_BAD_TOKEN;
  4186. +           goto err;
  4187. +       }
  4188. +
  4189. +       *type = BC_INST_CALL;
  4190. +       s = bc_parse_call(p, name, flags);
  4191. +   }
  4192. +   else {
  4193. +       *type = BC_INST_VAR;
  4194. +       if ((s = bc_parse_push(p, BC_INST_VAR))) goto err;
  4195. +       s = bc_parse_pushName(p, name);
  4196. +   }
  4197. +
  4198. +   return s;
  4199. +
  4200. +err:
  4201. +   free(name);
  4202. +   return s;
  4203. +}
  4204. +
  4205. +static BcStatus bc_parse_read(BcParse *p) {
  4206. +
  4207. +   BcStatus s;
  4208. +
  4209. +   if ((s = bc_lex_next(&p->l))) return s;
  4210. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4211. +
  4212. +   if ((s = bc_lex_next(&p->l))) return s;
  4213. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4214. +
  4215. +   if ((s = bc_parse_push(p, BC_INST_READ))) return s;
  4216. +
  4217. +   return bc_lex_next(&p->l);
  4218. +}
  4219. +
  4220. +static BcStatus bc_parse_builtin(BcParse *p, BcLexType type,
  4221. +                                 uint8_t flags, BcInst *prev)
  4222. +{
  4223. +   BcStatus s;
  4224. +
  4225. +   if ((s = bc_lex_next(&p->l))) return s;
  4226. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4227. +
  4228. +   flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
  4229. +
  4230. +   if ((s = bc_lex_next(&p->l))) return s;
  4231. +   if ((s = bc_parse_expr(p, flags, bc_parse_next_rel))) return s;
  4232. +
  4233. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4234. +
  4235. +   *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
  4236. +   if ((s = bc_parse_push(p, (char) *prev))) return s;
  4237. +
  4238. +   return bc_lex_next(&p->l);
  4239. +}
  4240. +
  4241. +static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) {
  4242. +
  4243. +   BcStatus s;
  4244. +
  4245. +   if ((s = bc_lex_next(&p->l))) return s;
  4246. +
  4247. +   if (p->l.t.t != BC_LEX_LPAREN) {
  4248. +       *type = BC_INST_SCALE;
  4249. +       return bc_parse_push(p, BC_INST_SCALE);
  4250. +   }
  4251. +
  4252. +   *type = BC_INST_SCALE_FUNC;
  4253. +   flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
  4254. +
  4255. +   if ((s = bc_lex_next(&p->l))) return s;
  4256. +   if ((s = bc_parse_expr(p, flags, bc_parse_next_rel))) return s;
  4257. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4258. +   if ((s = bc_parse_push(p, BC_INST_SCALE_FUNC))) return s;
  4259. +
  4260. +   return bc_lex_next(&p->l);
  4261. +}
  4262. +
  4263. +static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
  4264. +                                size_t *nexprs, uint8_t flags)
  4265. +{
  4266. +   BcStatus s;
  4267. +   BcLexType type;
  4268. +   char inst;
  4269. +   BcInst etype = *prev;
  4270. +
  4271. +   if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
  4272. +       etype == BC_INST_SCALE || etype == BC_INST_LAST ||
  4273. +       etype == BC_INST_IBASE || etype == BC_INST_OBASE)
  4274. +   {
  4275. +       *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
  4276. +       if ((s = bc_parse_push(p, inst))) return s;
  4277. +       s = bc_lex_next(&p->l);
  4278. +   }
  4279. +   else {
  4280. +
  4281. +       *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
  4282. +       *paren_expr = true;
  4283. +
  4284. +       if ((s = bc_lex_next(&p->l))) return s;
  4285. +       type = p->l.t.t;
  4286. +
  4287. +       // Because we parse the next part of the expression
  4288. +       // right here, we need to increment this.
  4289. +       *nexprs = *nexprs + 1;
  4290. +
  4291. +       switch (type) {
  4292. +
  4293. +           case BC_LEX_NAME:
  4294. +           {
  4295. +               s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
  4296. +               break;
  4297. +           }
  4298. +
  4299. +           case BC_LEX_KEY_IBASE:
  4300. +           {
  4301. +               if ((s = bc_parse_push(p, BC_INST_IBASE))) return s;
  4302. +               s = bc_lex_next(&p->l);
  4303. +               break;
  4304. +           }
  4305. +
  4306. +           case BC_LEX_KEY_LAST:
  4307. +           {
  4308. +               if ((s = bc_parse_push(p, BC_INST_LAST))) return s;
  4309. +               s = bc_lex_next(&p->l);
  4310. +               break;
  4311. +           }
  4312. +
  4313. +           case BC_LEX_KEY_OBASE:
  4314. +           {
  4315. +               if ((s = bc_parse_push(p, BC_INST_OBASE))) return s;
  4316. +               s = bc_lex_next(&p->l);
  4317. +               break;
  4318. +           }
  4319. +
  4320. +           case BC_LEX_KEY_SCALE:
  4321. +           {
  4322. +               if ((s = bc_lex_next(&p->l))) return s;
  4323. +               if (p->l.t.t == BC_LEX_LPAREN)
  4324. +                   return BC_STATUS_PARSE_BAD_TOKEN;
  4325. +
  4326. +               s = bc_parse_push(p, BC_INST_SCALE);
  4327. +
  4328. +               break;
  4329. +           }
  4330. +
  4331. +           default:
  4332. +           {
  4333. +               return BC_STATUS_PARSE_BAD_TOKEN;
  4334. +           }
  4335. +       }
  4336. +
  4337. +       if (!s) s = bc_parse_push(p, inst);
  4338. +   }
  4339. +
  4340. +   return s;
  4341. +}
  4342. +
  4343. +static BcStatus bc_parse_minus(BcParse *p, BcVec *ops, BcInst *prev,
  4344. +                               size_t start, bool rparen, size_t *nexprs)
  4345. +{
  4346. +   BcStatus s;
  4347. +   BcLexType type;
  4348. +   BcInst etype = *prev;
  4349. +
  4350. +   if ((s = bc_lex_next(&p->l))) return s;
  4351. +
  4352. +   type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
  4353. +          (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
  4354. +                    BC_LEX_OP_MINUS : BC_LEX_NEG;
  4355. +   *prev = BC_PARSE_TOKEN_INST(type);
  4356. +
  4357. +   if (type == BC_LEX_OP_MINUS)
  4358. +       s = bc_parse_operator(p, ops, type, start, nexprs, false);
  4359. +   else
  4360. +       // We can just push onto the op stack because this is the largest
  4361. +       // precedence operator that gets pushed. Inc/dec does not.
  4362. +       s = bc_vec_push(ops, &type);
  4363. +
  4364. +   return s;
  4365. +}
  4366. +
  4367. +static BcStatus bc_parse_string(BcParse *p, char inst) {
  4368. +
  4369. +   BcStatus s;
  4370. +   char *str;
  4371. +
  4372. +   if (!(str = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  4373. +   if ((s = bc_parse_push(p, BC_INST_STR))) goto err;
  4374. +   if ((s = bc_parse_pushIndex(p, p->prog->strs.len))) goto err;
  4375. +   if ((s = bc_vec_push(&p->prog->strs, &str))) goto err;
  4376. +   if ((s = bc_parse_push(p, inst))) return s;
  4377. +
  4378. +   return bc_lex_next(&p->l);
  4379. +
  4380. +err:
  4381. +   free(str);
  4382. +   return s;
  4383. +}
  4384. +
  4385. +static BcStatus bc_parse_print(BcParse *p) {
  4386. +
  4387. +   BcStatus s;
  4388. +   BcLexType type;
  4389. +   bool comma = false;
  4390. +
  4391. +   if ((s = bc_lex_next(&p->l))) return s;
  4392. +
  4393. +   type = p->l.t.t;
  4394. +
  4395. +   if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
  4396. +       return BC_STATUS_PARSE_BAD_PRINT;
  4397. +
  4398. +   while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
  4399. +
  4400. +       if (type == BC_LEX_STR) s = bc_parse_string(p, BC_INST_PRINT_POP);
  4401. +       else {
  4402. +           if ((s = bc_parse_expr(p, 0, bc_parse_next_print))) return s;
  4403. +           s = bc_parse_push(p, BC_INST_PRINT_POP);
  4404. +       }
  4405. +
  4406. +       if (s) return s;
  4407. +       if ((comma = p->l.t.t == BC_LEX_COMMA)) s = bc_lex_next(&p->l);
  4408. +       type = p->l.t.t;
  4409. +   }
  4410. +
  4411. +   if (s) return s;
  4412. +   if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
  4413. +
  4414. +   return bc_lex_next(&p->l);
  4415. +}
  4416. +
  4417. +static BcStatus bc_parse_return(BcParse *p) {
  4418. +
  4419. +   BcStatus s;
  4420. +   BcLexType t;
  4421. +   bool paren;
  4422. +
  4423. +   if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
  4424. +   if ((s = bc_lex_next(&p->l))) return s;
  4425. +
  4426. +   t = p->l.t.t;
  4427. +   paren = t == BC_LEX_LPAREN;
  4428. +
  4429. +   if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
  4430. +       s = bc_parse_push(p, BC_INST_RET0);
  4431. +   else {
  4432. +
  4433. +       s = bc_parse_expr(p, 0, bc_parse_next_expr);
  4434. +       if (s && s != BC_STATUS_PARSE_EMPTY_EXP) return s;
  4435. +       else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
  4436. +           if ((s = bc_parse_push(p, BC_INST_RET0))) return s;
  4437. +           if ((s = bc_lex_next(&p->l))) return s;
  4438. +       }
  4439. +
  4440. +       if ((!paren || p->l.t.last != BC_LEX_RPAREN) &&
  4441. +           (s = bc_vm_posixError(BC_STATUS_POSIX_RET_PARENS,
  4442. +                                 p->l.f, p->l.line, NULL)))
  4443. +       {
  4444. +           return s;
  4445. +       }
  4446. +
  4447. +       s = bc_parse_push(p, BC_INST_RET);
  4448. +   }
  4449. +
  4450. +   return s;
  4451. +}
  4452. +
  4453. +static BcStatus bc_parse_endBody(BcParse *p, bool brace) {
  4454. +
  4455. +   BcStatus s = BC_STATUS_SUCCESS;
  4456. +
  4457. +   if (p->flags.len <= 1 || (brace && p->nbraces == 0))
  4458. +       return BC_STATUS_PARSE_BAD_TOKEN;
  4459. +
  4460. +   if (brace) {
  4461. +
  4462. +       if (p->l.t.t == BC_LEX_RBRACE) {
  4463. +           if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
  4464. +           --p->nbraces;
  4465. +           if ((s = bc_lex_next(&p->l))) return s;
  4466. +       }
  4467. +       else return BC_STATUS_PARSE_BAD_TOKEN;
  4468. +   }
  4469. +
  4470. +   if (BC_PARSE_IF(p)) {
  4471. +
  4472. +       uint8_t *flag_ptr;
  4473. +
  4474. +       while (p->l.t.t == BC_LEX_NLINE) {
  4475. +           if ((s = bc_lex_next(&p->l))) return s;
  4476. +       }
  4477. +
  4478. +       bc_vec_pop(&p->flags);
  4479. +
  4480. +       flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
  4481. +       *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
  4482. +
  4483. +       if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
  4484. +   }
  4485. +   else if (BC_PARSE_ELSE(p)) {
  4486. +
  4487. +       BcInstPtr *ip;
  4488. +       size_t *label;
  4489. +
  4490. +       bc_vec_pop(&p->flags);
  4491. +
  4492. +       ip = bc_vec_top(&p->exits);
  4493. +       label = bc_vec_item(&p->func->labels, ip->idx);
  4494. +       *label = p->func->code.len;
  4495. +
  4496. +       bc_vec_pop(&p->exits);
  4497. +   }
  4498. +   else if (BC_PARSE_FUNC_INNER(p)) {
  4499. +       if ((s = bc_parse_push(p, BC_INST_RET0))) return s;
  4500. +       bc_parse_updateFunc(p, BC_PROG_MAIN);
  4501. +       bc_vec_pop(&p->flags);
  4502. +   }
  4503. +   else {
  4504. +
  4505. +       BcInstPtr *ip = bc_vec_top(&p->exits);
  4506. +       size_t *label = bc_vec_top(&p->conds);
  4507. +
  4508. +       if ((s = bc_parse_push(p, BC_INST_JUMP))) return s;
  4509. +       if ((s = bc_parse_pushIndex(p, *label))) return s;
  4510. +
  4511. +       label = bc_vec_item(&p->func->labels, ip->idx);
  4512. +       *label = p->func->code.len;
  4513. +
  4514. +       bc_vec_pop(&p->flags);
  4515. +       bc_vec_pop(&p->exits);
  4516. +       bc_vec_pop(&p->conds);
  4517. +   }
  4518. +
  4519. +   return s;
  4520. +}
  4521. +
  4522. +static BcStatus bc_parse_startBody(BcParse *p, uint8_t flags) {
  4523. +   uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
  4524. +   flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
  4525. +   flags |= BC_PARSE_FLAG_BODY;
  4526. +   return bc_vec_push(&p->flags, &flags);
  4527. +}
  4528. +
  4529. +static void bc_parse_noElse(BcParse *p) {
  4530. +
  4531. +   BcInstPtr *ip;
  4532. +   size_t *label;
  4533. +   uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
  4534. +
  4535. +   *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
  4536. +
  4537. +   ip = bc_vec_top(&p->exits);
  4538. +   label = bc_vec_item(&p->func->labels, ip->idx);
  4539. +   *label = p->func->code.len;
  4540. +
  4541. +   bc_vec_pop(&p->exits);
  4542. +}
  4543. +
  4544. +static BcStatus bc_parse_if(BcParse *p) {
  4545. +
  4546. +   BcStatus s;
  4547. +   BcInstPtr ip;
  4548. +
  4549. +   if ((s = bc_lex_next(&p->l))) return s;
  4550. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4551. +
  4552. +   if ((s = bc_lex_next(&p->l))) return s;
  4553. +   if ((s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel))) return s;
  4554. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4555. +
  4556. +   if ((s = bc_lex_next(&p->l))) return s;
  4557. +   if ((s = bc_parse_push(p, BC_INST_JUMP_ZERO))) return s;
  4558. +
  4559. +   ip.idx = p->func->labels.len;
  4560. +   ip.func = ip.len = 0;
  4561. +
  4562. +   if ((s = bc_parse_pushIndex(p, ip.idx))) return s;
  4563. +   if ((s = bc_vec_push(&p->exits, &ip))) return s;
  4564. +   if ((s = bc_vec_push(&p->func->labels, &ip.idx))) return s;
  4565. +
  4566. +   return bc_parse_startBody(p, BC_PARSE_FLAG_IF);
  4567. +}
  4568. +
  4569. +static BcStatus bc_parse_else(BcParse *p) {
  4570. +
  4571. +   BcStatus s;
  4572. +   BcInstPtr ip;
  4573. +
  4574. +   if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
  4575. +
  4576. +   ip.idx = p->func->labels.len;
  4577. +   ip.func = ip.len = 0;
  4578. +
  4579. +   if ((s = bc_parse_push(p, BC_INST_JUMP))) return s;
  4580. +   if ((s = bc_parse_pushIndex(p, ip.idx))) return s;
  4581. +
  4582. +   bc_parse_noElse(p);
  4583. +
  4584. +   if ((s = bc_vec_push(&p->exits, &ip))) return s;
  4585. +   if ((s = bc_vec_push(&p->func->labels, &ip.idx))) return s;
  4586. +   if ((s = bc_lex_next(&p->l))) return s;
  4587. +
  4588. +   return bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
  4589. +}
  4590. +
  4591. +static BcStatus bc_parse_while(BcParse *p) {
  4592. +
  4593. +   BcStatus s;
  4594. +   BcInstPtr ip;
  4595. +
  4596. +   if ((s = bc_lex_next(&p->l))) return s;
  4597. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4598. +   if ((s = bc_lex_next(&p->l))) return s;
  4599. +
  4600. +   ip.idx = p->func->labels.len;
  4601. +
  4602. +   if ((s = bc_vec_push(&p->func->labels, &p->func->code.len))) return s;
  4603. +   if ((s = bc_vec_push(&p->conds, &ip.idx))) return s;
  4604. +
  4605. +   ip.idx = p->func->labels.len;
  4606. +   ip.func = 1;
  4607. +   ip.len = 0;
  4608. +
  4609. +   if ((s = bc_vec_push(&p->exits, &ip))) return s;
  4610. +   if ((s = bc_vec_push(&p->func->labels, &ip.idx))) return s;
  4611. +
  4612. +   if ((s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel))) return s;
  4613. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4614. +
  4615. +   if ((s = bc_lex_next(&p->l))) return s;
  4616. +   if ((s = bc_parse_push(p, BC_INST_JUMP_ZERO))) return s;
  4617. +   if ((s = bc_parse_pushIndex(p, ip.idx))) return s;
  4618. +
  4619. +   return bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
  4620. +}
  4621. +
  4622. +static BcStatus bc_parse_for(BcParse *p) {
  4623. +
  4624. +   BcStatus s;
  4625. +   BcInstPtr ip;
  4626. +   size_t cond_idx, exit_idx, body_idx, update_idx;
  4627. +
  4628. +   if ((s = bc_lex_next(&p->l))) return s;
  4629. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4630. +   if ((s = bc_lex_next(&p->l))) return s;
  4631. +
  4632. +   if (p->l.t.t != BC_LEX_SCOLON)
  4633. +       s = bc_parse_expr(p, 0, bc_parse_next_for);
  4634. +   else
  4635. +       s = bc_vm_posixError(BC_STATUS_POSIX_FOR_INIT, p->l.f, p->l.line, NULL);
  4636. +
  4637. +   if (s) return s;
  4638. +   if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
  4639. +   if ((s = bc_lex_next(&p->l))) return s;
  4640. +
  4641. +   cond_idx = p->func->labels.len;
  4642. +   update_idx = cond_idx + 1;
  4643. +   body_idx = update_idx + 1;
  4644. +   exit_idx = body_idx + 1;
  4645. +
  4646. +   if ((s = bc_vec_push(&p->func->labels, &p->func->code.len))) return s;
  4647. +
  4648. +   if (p->l.t.t != BC_LEX_SCOLON)
  4649. +       s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
  4650. +   else
  4651. +       s = bc_vm_posixError(BC_STATUS_POSIX_FOR_COND, p->l.f, p->l.line, NULL);
  4652. +
  4653. +   if (s) return s;
  4654. +   if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
  4655. +
  4656. +   if ((s = bc_lex_next(&p->l))) return s;
  4657. +   if ((s = bc_parse_push(p, BC_INST_JUMP_ZERO))) return s;
  4658. +   if ((s = bc_parse_pushIndex(p, exit_idx))) return s;
  4659. +   if ((s = bc_parse_push(p, BC_INST_JUMP))) return s;
  4660. +   if ((s = bc_parse_pushIndex(p, body_idx))) return s;
  4661. +
  4662. +   ip.idx = p->func->labels.len;
  4663. +
  4664. +   if ((s = bc_vec_push(&p->conds, &update_idx))) return s;
  4665. +   if ((s = bc_vec_push(&p->func->labels, &p->func->code.len))) return s;
  4666. +
  4667. +   if (p->l.t.t != BC_LEX_RPAREN)
  4668. +       s = bc_parse_expr(p, 0, bc_parse_next_rel);
  4669. +   else
  4670. +       s = bc_vm_posixError(BC_STATUS_POSIX_FOR_END, p->l.f, p->l.line, NULL);
  4671. +
  4672. +   if (s) return s;
  4673. +
  4674. +   if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
  4675. +   if ((s = bc_parse_push(p, BC_INST_JUMP))) return s;
  4676. +   if ((s = bc_parse_pushIndex(p, cond_idx))) return s;
  4677. +   if ((s = bc_vec_push(&p->func->labels, &p->func->code.len))) return s;
  4678. +
  4679. +   ip.idx = exit_idx;
  4680. +   ip.func = 1;
  4681. +   ip.len = 0;
  4682. +
  4683. +   if ((s = bc_vec_push(&p->exits, &ip))) return s;
  4684. +   if ((s = bc_vec_push(&p->func->labels, &ip.idx))) return s;
  4685. +   if ((s = bc_lex_next(&p->l))) return s;
  4686. +
  4687. +   return bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
  4688. +}
  4689. +
  4690. +static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) {
  4691. +
  4692. +   BcStatus s;
  4693. +   size_t i;
  4694. +   BcInstPtr *ip;
  4695. +
  4696. +   if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
  4697. +
  4698. +   if (type == BC_LEX_KEY_BREAK) {
  4699. +
  4700. +       if (!p->exits.len) return BC_STATUS_PARSE_BAD_TOKEN;
  4701. +
  4702. +       i = p->exits.len - 1;
  4703. +       ip = bc_vec_item(&p->exits, i);
  4704. +
  4705. +       while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
  4706. +       if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
  4707. +
  4708. +       i = ip->idx;
  4709. +   }
  4710. +   else i = *((size_t*) bc_vec_top(&p->conds));
  4711. +
  4712. +   if ((s = bc_parse_push(p, BC_INST_JUMP))) return s;
  4713. +   if ((s = bc_parse_pushIndex(p, i))) return s;
  4714. +   if ((s = bc_lex_next(&p->l))) return s;
  4715. +
  4716. +   if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
  4717. +       return BC_STATUS_PARSE_BAD_TOKEN;
  4718. +
  4719. +   return bc_lex_next(&p->l);
  4720. +}
  4721. +
  4722. +static BcStatus bc_parse_func(BcParse *p) {
  4723. +
  4724. +   BcStatus s;
  4725. +   bool var, comma = false;
  4726. +   uint8_t flags;
  4727. +   char *name;
  4728. +
  4729. +   if ((s = bc_lex_next(&p->l))) return s;
  4730. +   if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
  4731. +
  4732. +   if (!(name = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  4733. +   if ((s = bc_parse_addFunc(p, name, &p->fidx))) return s;
  4734. +
  4735. +   if ((s = bc_lex_next(&p->l))) return s;
  4736. +   if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
  4737. +   if ((s = bc_lex_next(&p->l))) return s;
  4738. +
  4739. +   while (!s && p->l.t.t != BC_LEX_RPAREN) {
  4740. +
  4741. +       if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
  4742. +
  4743. +       ++p->func->nparams;
  4744. +
  4745. +       if (!(name = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  4746. +       if ((s = bc_lex_next(&p->l))) goto err;
  4747. +
  4748. +       var = p->l.t.t != BC_LEX_LBRACKET;
  4749. +
  4750. +       if (!var) {
  4751. +
  4752. +           if ((s = bc_lex_next(&p->l))) goto err;
  4753. +
  4754. +           if (p->l.t.t != BC_LEX_RBRACKET) {
  4755. +               s = BC_STATUS_PARSE_BAD_FUNC;
  4756. +               goto err;
  4757. +           }
  4758. +
  4759. +           if ((s = bc_lex_next(&p->l))) goto err;
  4760. +       }
  4761. +
  4762. +       comma = p->l.t.t == BC_LEX_COMMA;
  4763. +       if (comma && (s = bc_lex_next(&p->l))) goto err;
  4764. +
  4765. +       if ((s = bc_func_insert(p->func, name, var))) goto err;
  4766. +   }
  4767. +
  4768. +   if (comma) return BC_STATUS_PARSE_BAD_FUNC;
  4769. +
  4770. +   flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
  4771. +
  4772. +   if ((s = bc_parse_startBody(p, flags))) return s;
  4773. +   if ((s = bc_lex_next(&p->l))) return s;
  4774. +
  4775. +   if (p->l.t.t != BC_LEX_LBRACE)
  4776. +       s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
  4777. +
  4778. +   return s;
  4779. +
  4780. +err:
  4781. +   free(name);
  4782. +   return s;
  4783. +}
  4784. +
  4785. +static BcStatus bc_parse_auto(BcParse *p) {
  4786. +
  4787. +   BcStatus s;
  4788. +   bool comma, var, one;
  4789. +   char *name;
  4790. +
  4791. +   if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
  4792. +   if ((s = bc_lex_next(&p->l))) return s;
  4793. +
  4794. +   p->auto_part = comma = false;
  4795. +   one = p->l.t.t == BC_LEX_NAME;
  4796. +
  4797. +   while (!s && p->l.t.t == BC_LEX_NAME) {
  4798. +
  4799. +       if (!(name = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  4800. +       if ((s = bc_lex_next(&p->l))) goto err;
  4801. +
  4802. +       if (!(var = p->l.t.t != BC_LEX_LBRACKET)) {
  4803. +
  4804. +           if ((s = bc_lex_next(&p->l))) goto err;
  4805. +
  4806. +           if (p->l.t.t != BC_LEX_RBRACKET) {
  4807. +               s = BC_STATUS_PARSE_BAD_FUNC;
  4808. +               goto err;
  4809. +           }
  4810. +
  4811. +           if ((s = bc_lex_next(&p->l))) goto err;
  4812. +       }
  4813. +
  4814. +       comma = p->l.t.t == BC_LEX_COMMA;
  4815. +       if (comma && (s = bc_lex_next(&p->l))) goto err;
  4816. +
  4817. +       if ((s = bc_func_insert(p->func, name, var))) goto err;
  4818. +   }
  4819. +
  4820. +   if (comma) return BC_STATUS_PARSE_BAD_FUNC;
  4821. +   if (!one) return BC_STATUS_PARSE_NO_AUTO;
  4822. +
  4823. +   if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
  4824. +       return BC_STATUS_PARSE_BAD_TOKEN;
  4825. +
  4826. +   return bc_lex_next(&p->l);
  4827. +
  4828. +err:
  4829. +   free(name);
  4830. +   return s;
  4831. +}
  4832. +
  4833. +static BcStatus bc_parse_body(BcParse *p, bool brace) {
  4834. +
  4835. +   BcStatus s = BC_STATUS_SUCCESS;
  4836. +   uint8_t *flag_ptr = bc_vec_top(&p->flags);
  4837. +
  4838. +   *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
  4839. +
  4840. +   if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
  4841. +
  4842. +       if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
  4843. +       p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
  4844. +
  4845. +       if (!p->auto_part && (s = bc_parse_auto(p))) return s;
  4846. +       if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
  4847. +   }
  4848. +   else {
  4849. +       if ((s = bc_parse_stmt(p))) return s;
  4850. +       if (!brace) s = bc_parse_endBody(p, false);
  4851. +   }
  4852. +
  4853. +   return s;
  4854. +}
  4855. +
  4856. +static BcStatus bc_parse_stmt(BcParse *p) {
  4857. +
  4858. +   BcStatus s;
  4859. +
  4860. +   switch (p->l.t.t) {
  4861. +
  4862. +       case BC_LEX_NLINE:
  4863. +       {
  4864. +           return bc_lex_next(&p->l);
  4865. +       }
  4866. +
  4867. +       case BC_LEX_KEY_ELSE:
  4868. +       {
  4869. +           p->auto_part = false;
  4870. +           break;
  4871. +       }
  4872. +
  4873. +       case BC_LEX_LBRACE:
  4874. +       {
  4875. +           if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
  4876. +
  4877. +           ++p->nbraces;
  4878. +           if ((s = bc_lex_next(&p->l))) return s;
  4879. +
  4880. +           return bc_parse_body(p, true);
  4881. +       }
  4882. +
  4883. +       case BC_LEX_KEY_AUTO:
  4884. +       {
  4885. +           return bc_parse_auto(p);
  4886. +       }
  4887. +
  4888. +       default:
  4889. +       {
  4890. +           p->auto_part = false;
  4891. +
  4892. +           if (BC_PARSE_IF_END(p)) {
  4893. +               bc_parse_noElse(p);
  4894. +               return BC_STATUS_SUCCESS;
  4895. +           }
  4896. +           else if (BC_PARSE_BODY(p)) return bc_parse_body(p, false);
  4897. +
  4898. +           break;
  4899. +       }
  4900. +   }
  4901. +
  4902. +   switch (p->l.t.t) {
  4903. +
  4904. +       case BC_LEX_OP_INC:
  4905. +       case BC_LEX_OP_DEC:
  4906. +       case BC_LEX_OP_MINUS:
  4907. +       case BC_LEX_OP_BOOL_NOT:
  4908. +       case BC_LEX_LPAREN:
  4909. +       case BC_LEX_NAME:
  4910. +       case BC_LEX_NUMBER:
  4911. +       case BC_LEX_KEY_IBASE:
  4912. +       case BC_LEX_KEY_LAST:
  4913. +       case BC_LEX_KEY_LENGTH:
  4914. +       case BC_LEX_KEY_OBASE:
  4915. +       case BC_LEX_KEY_READ:
  4916. +       case BC_LEX_KEY_SCALE:
  4917. +       case BC_LEX_KEY_SQRT:
  4918. +       {
  4919. +           s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
  4920. +           break;
  4921. +       }
  4922. +
  4923. +       case BC_LEX_KEY_ELSE:
  4924. +       {
  4925. +           s = bc_parse_else(p);
  4926. +           break;
  4927. +       }
  4928. +
  4929. +       case BC_LEX_SCOLON:
  4930. +       {
  4931. +           s = BC_STATUS_SUCCESS;
  4932. +           while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
  4933. +           break;
  4934. +       }
  4935. +
  4936. +       case BC_LEX_RBRACE:
  4937. +       {
  4938. +           s = bc_parse_endBody(p, true);
  4939. +           break;
  4940. +       }
  4941. +
  4942. +       case BC_LEX_STR:
  4943. +       {
  4944. +           s = bc_parse_string(p, BC_INST_PRINT_STR);
  4945. +           break;
  4946. +       }
  4947. +
  4948. +       case BC_LEX_KEY_BREAK:
  4949. +       case BC_LEX_KEY_CONTINUE:
  4950. +       {
  4951. +           s = bc_parse_loopExit(p, p->l.t.t);
  4952. +           break;
  4953. +       }
  4954. +
  4955. +       case BC_LEX_KEY_FOR:
  4956. +       {
  4957. +           s = bc_parse_for(p);
  4958. +           break;
  4959. +       }
  4960. +
  4961. +       case BC_LEX_KEY_HALT:
  4962. +       {
  4963. +           if ((s = bc_parse_push(p, BC_INST_HALT))) return s;
  4964. +           s = bc_lex_next(&p->l);
  4965. +           break;
  4966. +       }
  4967. +
  4968. +       case BC_LEX_KEY_IF:
  4969. +       {
  4970. +           s = bc_parse_if(p);
  4971. +           break;
  4972. +       }
  4973. +
  4974. +       case BC_LEX_KEY_LIMITS:
  4975. +       {
  4976. +           if ((s = bc_lex_next(&p->l))) return s;
  4977. +           s = BC_STATUS_LIMITS;
  4978. +           break;
  4979. +       }
  4980. +
  4981. +       case BC_LEX_KEY_PRINT:
  4982. +       {
  4983. +           s = bc_parse_print(p);
  4984. +           break;
  4985. +       }
  4986. +
  4987. +       case BC_LEX_KEY_QUIT:
  4988. +       {
  4989. +           // Quit is a compile-time command. We don't exit directly,
  4990. +           // so the vm can clean up. Limits do the same thing.
  4991. +           s = BC_STATUS_QUIT;
  4992. +           break;
  4993. +       }
  4994. +
  4995. +       case BC_LEX_KEY_RETURN:
  4996. +       {
  4997. +           if ((s = bc_parse_return(p))) return s;
  4998. +           break;
  4999. +       }
  5000. +
  5001. +       case BC_LEX_KEY_WHILE:
  5002. +       {
  5003. +           s = bc_parse_while(p);
  5004. +           break;
  5005. +       }
  5006. +
  5007. +       default:
  5008. +       {
  5009. +           s = BC_STATUS_PARSE_BAD_TOKEN;
  5010. +           break;
  5011. +       }
  5012. +   }
  5013. +
  5014. +   return s;
  5015. +}
  5016. +
  5017. +static BcStatus bc_parse_parse(BcParse *p) {
  5018. +
  5019. +   BcStatus s;
  5020. +
  5021. +   if (p->l.t.t == BC_LEX_EOF)
  5022. +       s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
  5023. +   else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
  5024. +       if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
  5025. +       s = bc_parse_func(p);
  5026. +   }
  5027. +   else s = bc_parse_stmt(p);
  5028. +
  5029. +   if (s || bcg.signe) s = bc_parse_reset(p, s);
  5030. +
  5031. +   return s;
  5032. +}
  5033. +
  5034. +BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next) {
  5035. +
  5036. +   BcStatus s = BC_STATUS_SUCCESS;
  5037. +   BcInst prev = BC_INST_PRINT;
  5038. +   BcLexType top, t = p->l.t.t;
  5039. +   size_t nexprs = 0, ops_start = p->ops.len;
  5040. +   uint32_t i, nparens, nrelops;
  5041. +   bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
  5042. +
  5043. +   paren_first = p->l.t.t == BC_LEX_LPAREN;
  5044. +   nparens = nrelops = 0;
  5045. +   paren_expr = rprn = done = get_token = assign = false;
  5046. +   bin_last = true;
  5047. +
  5048. +   for (; !bcg.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t)
  5049. +   {
  5050. +       switch (t) {
  5051. +
  5052. +           case BC_LEX_OP_INC:
  5053. +           case BC_LEX_OP_DEC:
  5054. +           {
  5055. +               s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
  5056. +               rprn = get_token = bin_last = false;
  5057. +               break;
  5058. +           }
  5059. +
  5060. +           case BC_LEX_OP_MINUS:
  5061. +           {
  5062. +               s = bc_parse_minus(p, &p->ops, &prev, ops_start, rprn, &nexprs);
  5063. +               rprn = get_token = false;
  5064. +               bin_last = prev == BC_INST_MINUS;
  5065. +               break;
  5066. +           }
  5067. +
  5068. +           case BC_LEX_OP_ASSIGN_POWER:
  5069. +           case BC_LEX_OP_ASSIGN_MULTIPLY:
  5070. +           case BC_LEX_OP_ASSIGN_DIVIDE:
  5071. +           case BC_LEX_OP_ASSIGN_MODULUS:
  5072. +           case BC_LEX_OP_ASSIGN_PLUS:
  5073. +           case BC_LEX_OP_ASSIGN_MINUS:
  5074. +           case BC_LEX_OP_ASSIGN:
  5075. +           {
  5076. +               if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
  5077. +                   prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
  5078. +                   prev != BC_INST_OBASE && prev != BC_INST_LAST)
  5079. +               {
  5080. +                   s = BC_STATUS_PARSE_BAD_ASSIGN;
  5081. +                   break;
  5082. +               }
  5083. +           }
  5084. +           // Fallthrough.
  5085. +           case BC_LEX_OP_POWER:
  5086. +           case BC_LEX_OP_MULTIPLY:
  5087. +           case BC_LEX_OP_DIVIDE:
  5088. +           case BC_LEX_OP_MODULUS:
  5089. +           case BC_LEX_OP_PLUS:
  5090. +           case BC_LEX_OP_REL_EQ:
  5091. +           case BC_LEX_OP_REL_LE:
  5092. +           case BC_LEX_OP_REL_GE:
  5093. +           case BC_LEX_OP_REL_NE:
  5094. +           case BC_LEX_OP_REL_LT:
  5095. +           case BC_LEX_OP_REL_GT:
  5096. +           case BC_LEX_OP_BOOL_NOT:
  5097. +           case BC_LEX_OP_BOOL_OR:
  5098. +           case BC_LEX_OP_BOOL_AND:
  5099. +           {
  5100. +               if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
  5101. +                   (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
  5102. +               {
  5103. +                   return BC_STATUS_PARSE_BAD_EXP;
  5104. +               }
  5105. +
  5106. +               nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
  5107. +               prev = BC_PARSE_TOKEN_INST(t);
  5108. +               s = bc_parse_operator(p, &p->ops, t, ops_start, &nexprs, true);
  5109. +               rprn = get_token = false;
  5110. +               bin_last = t != BC_LEX_OP_BOOL_NOT;
  5111. +
  5112. +               break;
  5113. +           }
  5114. +
  5115. +           case BC_LEX_LPAREN:
  5116. +           {
  5117. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5118. +
  5119. +               ++nparens;
  5120. +               paren_expr = rprn = bin_last = false;
  5121. +               get_token = true;
  5122. +               s = bc_vec_push(&p->ops, &t);
  5123. +
  5124. +               break;
  5125. +           }
  5126. +
  5127. +           case BC_LEX_RPAREN:
  5128. +           {
  5129. +               if (bin_last || prev == BC_INST_BOOL_NOT)
  5130. +                   return BC_STATUS_PARSE_BAD_EXP;
  5131. +
  5132. +               if (nparens == 0) {
  5133. +                   s = BC_STATUS_SUCCESS;
  5134. +                   done = true;
  5135. +                   get_token = false;
  5136. +                   break;
  5137. +               }
  5138. +               else if (!paren_expr) return BC_STATUS_PARSE_EMPTY_EXP;
  5139. +
  5140. +               --nparens;
  5141. +               paren_expr = rprn = true;
  5142. +               get_token = bin_last = false;
  5143. +
  5144. +               s = bc_parse_rightParen(p, &p->ops, &nexprs);
  5145. +
  5146. +               break;
  5147. +           }
  5148. +
  5149. +           case BC_LEX_NAME:
  5150. +           {
  5151. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5152. +
  5153. +               paren_expr = true;
  5154. +               rprn = get_token = bin_last = false;
  5155. +               s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
  5156. +               ++nexprs;
  5157. +
  5158. +               break;
  5159. +           }
  5160. +
  5161. +           case BC_LEX_NUMBER:
  5162. +           {
  5163. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5164. +
  5165. +               s = bc_parse_number(p, &prev, &nexprs);
  5166. +               paren_expr = get_token = true;
  5167. +               rprn = bin_last = false;
  5168. +
  5169. +               break;
  5170. +           }
  5171. +
  5172. +           case BC_LEX_KEY_IBASE:
  5173. +           case BC_LEX_KEY_LAST:
  5174. +           case BC_LEX_KEY_OBASE:
  5175. +           {
  5176. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5177. +
  5178. +               prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
  5179. +               s = bc_parse_push(p, (char) prev);
  5180. +
  5181. +               paren_expr = get_token = true;
  5182. +               rprn = bin_last = false;
  5183. +               ++nexprs;
  5184. +
  5185. +               break;
  5186. +           }
  5187. +
  5188. +           case BC_LEX_KEY_LENGTH:
  5189. +           case BC_LEX_KEY_SQRT:
  5190. +           {
  5191. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5192. +
  5193. +               s = bc_parse_builtin(p, t, flags, &prev);
  5194. +               paren_expr = true;
  5195. +               rprn = get_token = bin_last = false;
  5196. +               ++nexprs;
  5197. +
  5198. +               break;
  5199. +           }
  5200. +
  5201. +           case BC_LEX_KEY_READ:
  5202. +           {
  5203. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5204. +               else if (flags & BC_PARSE_NOREAD) s = BC_STATUS_EXEC_REC_READ;
  5205. +               else s = bc_parse_read(p);
  5206. +
  5207. +               paren_expr = true;
  5208. +               rprn = get_token = bin_last = false;
  5209. +               ++nexprs;
  5210. +               prev = BC_INST_READ;
  5211. +
  5212. +               break;
  5213. +           }
  5214. +
  5215. +           case BC_LEX_KEY_SCALE:
  5216. +           {
  5217. +               if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
  5218. +
  5219. +               s = bc_parse_scale(p, &prev, flags);
  5220. +               paren_expr = true;
  5221. +               rprn = get_token = bin_last = false;
  5222. +               ++nexprs;
  5223. +               prev = BC_INST_SCALE;
  5224. +
  5225. +               break;
  5226. +           }
  5227. +
  5228. +           default:
  5229. +           {
  5230. +               s = BC_STATUS_PARSE_BAD_TOKEN;
  5231. +               break;
  5232. +           }
  5233. +       }
  5234. +
  5235. +       if (!s && get_token) s = bc_lex_next(&p->l);
  5236. +   }
  5237. +
  5238. +   if (s) return s;
  5239. +   if (bcg.signe) return BC_STATUS_EXEC_SIGNAL;
  5240. +
  5241. +   while (!s && p->ops.len > ops_start) {
  5242. +
  5243. +       top = *((BcLexType*) bc_vec_top(&p->ops));
  5244. +       assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
  5245. +
  5246. +       if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
  5247. +           return BC_STATUS_PARSE_BAD_EXP;
  5248. +
  5249. +       if ((s = bc_parse_push(p, BC_PARSE_TOKEN_INST(top)))) return s;
  5250. +
  5251. +       nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
  5252. +       bc_vec_pop(&p->ops);
  5253. +   }
  5254. +
  5255. +   s = BC_STATUS_PARSE_BAD_EXP;
  5256. +   if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
  5257. +
  5258. +   for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
  5259. +   if (s) return s;
  5260. +
  5261. +   if (!(flags & BC_PARSE_REL) && nrelops &&
  5262. +       (s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS,
  5263. +                             p->l.f, p->l.line, NULL)))
  5264. +   {
  5265. +       return s;
  5266. +   }
  5267. +   else if ((flags & BC_PARSE_REL) && nrelops > 1 &&
  5268. +            (s = bc_vm_posixError(BC_STATUS_POSIX_MULTIPLE_REL,
  5269. +                                  p->l.f, p->l.line, NULL)))
  5270. +   {
  5271. +       return s;
  5272. +   }
  5273. +
  5274. +   if (flags & BC_PARSE_PRINT) {
  5275. +
  5276. +       if (paren_first || !assign) {
  5277. +           if ((s = bc_parse_push(p, BC_INST_PRINT))) return s;
  5278. +       }
  5279. +
  5280. +       s = bc_parse_push(p, BC_INST_POP);
  5281. +   }
  5282. +
  5283. +   return s;
  5284. +}
  5285. +
  5286. +BcStatus bc_parse_init(BcParse *p, BcProgram *prog, size_t func) {
  5287. +   return bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
  5288. +}
  5289. +
  5290. +BcStatus bc_parse_expression(BcParse *p, uint8_t flags) {
  5291. +   return bc_parse_expr(p, flags, bc_parse_next_read);
  5292. +}
  5293. +#endif // CONFIG_BC
  5294. +
  5295. +#ifdef CONFIG_DC
  5296. +static BcStatus dc_parse_register(BcParse *p) {
  5297. +
  5298. +   BcStatus s;
  5299. +   char *name;
  5300. +
  5301. +   if ((s = bc_lex_next(&p->l))) return s;
  5302. +   if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
  5303. +   if (!(name = strdup(p->l.t.v.v))) return BC_STATUS_ALLOC_ERR;
  5304. +   if ((s = bc_parse_pushName(p, name))) free(name);
  5305. +
  5306. +   return s;
  5307. +}
  5308. +
  5309. +static BcStatus dc_parse_string(BcParse *p) {
  5310. +
  5311. +   BcStatus s = BC_STATUS_ALLOC_ERR;
  5312. +   char *str, *name, b[DC_PARSE_BUF_LEN + 1];
  5313. +   size_t idx, len = p->prog->strs.len;
  5314. +
  5315. +   if (sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len) < 0) return BC_STATUS_IO_ERR;
  5316. +   if (!(name = strdup(b))) return s;
  5317. +
  5318. +   if (!(str = strdup(p->l.t.v.v))) goto str_err;
  5319. +   if ((s = bc_parse_push(p, BC_INST_STR))) goto err;
  5320. +   if ((s = bc_parse_pushIndex(p, len))) goto err;
  5321. +   if ((s = bc_vec_push(&p->prog->strs, &str))) goto err;
  5322. +   if ((s = bc_parse_addFunc(p, name, &idx))) return s;
  5323. +   if ((s = bc_lex_next(&p->l))) return s;
  5324. +
  5325. +   return s;
  5326. +
  5327. +err:
  5328. +   free(str);
  5329. +str_err:
  5330. +   free(name);
  5331. +   return s;
  5332. +}
  5333. +
  5334. +static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store) {
  5335. +
  5336. +   BcStatus s;
  5337. +
  5338. +   if ((s = bc_parse_push(p, inst))) return s;
  5339. +   if (name && (s = dc_parse_register(p))) return s;
  5340. +
  5341. +   if (store) {
  5342. +       if ((s = bc_parse_push(p, BC_INST_SWAP))) return s;
  5343. +       if ((s = bc_parse_push(p, BC_INST_ASSIGN))) return s;
  5344. +       if ((s = bc_parse_push(p, BC_INST_POP))) return s;
  5345. +   }
  5346. +
  5347. +   return bc_lex_next(&p->l);
  5348. +}
  5349. +
  5350. +static BcStatus dc_parse_cond(BcParse *p, uint8_t inst) {
  5351. +
  5352. +   BcStatus s;
  5353. +
  5354. +   if ((s = bc_parse_push(p, inst))) return s;
  5355. +   if ((s = bc_parse_push(p, BC_INST_EXEC_COND))) return s;
  5356. +   if ((s = dc_parse_register(p))) return s;
  5357. +   if ((s = bc_lex_next(&p->l))) return s;
  5358. +
  5359. +   if (p->l.t.t == BC_LEX_ELSE) {
  5360. +       if ((s = dc_parse_register(p))) return s;
  5361. +       s = bc_lex_next(&p->l);
  5362. +   }
  5363. +   else s = bc_parse_push(p, BC_PARSE_STREND);
  5364. +
  5365. +   return s;
  5366. +}
  5367. +
  5368. +static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags) {
  5369. +
  5370. +   BcStatus s = BC_STATUS_SUCCESS;
  5371. +   BcInst prev;
  5372. +   uint8_t inst;
  5373. +   bool assign, get_token = false;
  5374. +
  5375. +   switch (t) {
  5376. +
  5377. +       case BC_LEX_OP_REL_EQ:
  5378. +       case BC_LEX_OP_REL_LE:
  5379. +       case BC_LEX_OP_REL_GE:
  5380. +       case BC_LEX_OP_REL_NE:
  5381. +       case BC_LEX_OP_REL_LT:
  5382. +       case BC_LEX_OP_REL_GT:
  5383. +       {
  5384. +           s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
  5385. +           break;
  5386. +       }
  5387. +
  5388. +       case BC_LEX_SCOLON:
  5389. +       case BC_LEX_COLON:
  5390. +       {
  5391. +           s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
  5392. +           break;
  5393. +       }
  5394. +
  5395. +       case BC_LEX_STR:
  5396. +       {
  5397. +           s = dc_parse_string(p);
  5398. +           break;
  5399. +       }
  5400. +
  5401. +       case BC_LEX_NEG:
  5402. +       case BC_LEX_NUMBER:
  5403. +       {
  5404. +           if (t == BC_LEX_NEG) {
  5405. +               if ((s = bc_lex_next(&p->l))) return s;
  5406. +               if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
  5407. +           }
  5408. +
  5409. +           s = bc_parse_number(p, &prev, &p->nbraces);
  5410. +
  5411. +           if (t == BC_LEX_NEG && !s) s = bc_parse_push(p, BC_INST_NEG);
  5412. +           get_token = true;
  5413. +
  5414. +           break;
  5415. +       }
  5416. +
  5417. +       case BC_LEX_KEY_READ:
  5418. +       {
  5419. +           if (flags & BC_PARSE_NOREAD) s = BC_STATUS_EXEC_REC_READ;
  5420. +           else s = bc_parse_push(p, BC_INST_READ);
  5421. +           get_token = true;
  5422. +           break;
  5423. +       }
  5424. +
  5425. +       case BC_LEX_OP_ASSIGN:
  5426. +       case BC_LEX_STORE_PUSH:
  5427. +       {
  5428. +           assign = t == BC_LEX_OP_ASSIGN;
  5429. +           inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
  5430. +           s = dc_parse_mem(p, inst, true, assign);
  5431. +           break;
  5432. +       }
  5433. +
  5434. +       case BC_LEX_LOAD:
  5435. +       case BC_LEX_LOAD_POP:
  5436. +       {
  5437. +           inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
  5438. +           s = dc_parse_mem(p, inst, true, false);
  5439. +           break;
  5440. +       }
  5441. +
  5442. +       case BC_LEX_STORE_IBASE:
  5443. +       case BC_LEX_STORE_SCALE:
  5444. +       case BC_LEX_STORE_OBASE:
  5445. +       {
  5446. +           inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
  5447. +           s = dc_parse_mem(p, inst, false, true);
  5448. +           break;
  5449. +       }
  5450. +
  5451. +       default:
  5452. +       {
  5453. +           s = BC_STATUS_PARSE_BAD_TOKEN;
  5454. +           get_token = true;
  5455. +           break;
  5456. +       }
  5457. +   }
  5458. +
  5459. +   if (!s && get_token) s = bc_lex_next(&p->l);
  5460. +
  5461. +   return s;
  5462. +}
  5463. +
  5464. +BcStatus dc_parse_expr(BcParse *p, uint8_t flags) {
  5465. +
  5466. +   BcStatus s = BC_STATUS_SUCCESS;
  5467. +   BcInst inst;
  5468. +   BcLexType t;
  5469. +
  5470. +   if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
  5471. +
  5472. +   while (!s && (t = p->l.t.t) != BC_LEX_EOF) {
  5473. +       if ((inst = dc_parse_insts[t]) != BC_INST_INVALID) {
  5474. +           if ((s = bc_parse_push(p, inst))) return s;
  5475. +           if ((s = bc_lex_next(&p->l))) return s;
  5476. +       }
  5477. +       else if ((s = dc_parse_token(p, t, flags))) return s;
  5478. +   }
  5479. +
  5480. +   if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
  5481. +       s = bc_parse_push(p, BC_INST_POP_EXEC);
  5482. +
  5483. +   return s;
  5484. +}
  5485. +
  5486. +static BcStatus dc_parse_parse(BcParse *p) {
  5487. +
  5488. +   BcStatus s;
  5489. +
  5490. +   if (p->l.t.t == BC_LEX_EOF) s = BC_STATUS_LEX_EOF;
  5491. +   else s = dc_parse_expr(p, 0);
  5492. +
  5493. +   if (s || bcg.signe) s = bc_parse_reset(p, s);
  5494. +
  5495. +   return s;
  5496. +}
  5497. +
  5498. +BcStatus dc_parse_init(BcParse *p, BcProgram *prog, size_t func) {
  5499. +   return bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
  5500. +}
  5501. +#endif // CONFIG_DC
  5502. +
  5503. +static BcStatus bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
  5504. +{
  5505. +   BcStatus s;
  5506. +   BcId e, *ptr;
  5507. +   BcVec *v, *map;
  5508. +   size_t i;
  5509. +   BcResultData data;
  5510. +   bool new;
  5511. +
  5512. +   v = var ? &p->vars : &p->arrs;
  5513. +   map = var ? &p->var_map : &p->arr_map;
  5514. +
  5515. +   e.name = id;
  5516. +   e.idx = v->len;
  5517. +
  5518. +   if ((new = (s = bc_map_insert(map, &e, &i)) != BC_STATUS_VEC_ITEM_EXISTS)) {
  5519. +       if (s || (s = bc_array_init(&data.v, var))) return s;
  5520. +       if ((s = bc_vec_push(v, &data.v))) {
  5521. +           bc_vec_free(&data.v);
  5522. +           return s;
  5523. +       }
  5524. +   }
  5525. +
  5526. +   ptr = bc_map_item(map, i);
  5527. +   if (new && !(ptr->name = strdup(e.name))) return BC_STATUS_ALLOC_ERR;
  5528. +   *ret = bc_vec_item(v, ptr->idx);
  5529. +
  5530. +   return BC_STATUS_SUCCESS;
  5531. +}
  5532. +
  5533. +static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
  5534. +{
  5535. +   BcStatus s = BC_STATUS_SUCCESS;
  5536. +
  5537. +   switch (r->t) {
  5538. +
  5539. +       case BC_RESULT_STR:
  5540. +       case BC_RESULT_TEMP:
  5541. +       case BC_RESULT_IBASE:
  5542. +       case BC_RESULT_SCALE:
  5543. +       case BC_RESULT_OBASE:
  5544. +       {
  5545. +           *num = &r->d.n;
  5546. +           break;
  5547. +       }
  5548. +
  5549. +       case BC_RESULT_CONSTANT:
  5550. +       {
  5551. +           char **str = bc_vec_item(&p->consts, r->d.id.idx);
  5552. +           size_t base_t, len = strlen(*str);
  5553. +           BcNum *base;
  5554. +
  5555. +           if ((s = bc_num_init(&r->d.n, len))) return s;
  5556. +
  5557. +           hex = hex && len == 1;
  5558. +           base = hex ? &p->hexb : &p->ib;
  5559. +           base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
  5560. +
  5561. +           if ((s = bc_num_parse(&r->d.n, *str, base, base_t))) {
  5562. +               bc_num_free(&r->d.n);
  5563. +               return s;
  5564. +           }
  5565. +
  5566. +           *num = &r->d.n;
  5567. +           r->t = BC_RESULT_TEMP;
  5568. +
  5569. +           break;
  5570. +       }
  5571. +
  5572. +       case BC_RESULT_VAR:
  5573. +       case BC_RESULT_ARRAY:
  5574. +       case BC_RESULT_ARRAY_ELEM:
  5575. +       {
  5576. +           BcVec *v;
  5577. +
  5578. +           s = bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
  5579. +           if (s) return s;
  5580. +
  5581. +           if (r->t == BC_RESULT_ARRAY_ELEM) {
  5582. +
  5583. +               if ((v = bc_vec_top(v))->len <= r->d.id.idx) {
  5584. +                   if ((s = bc_array_expand(v, r->d.id.idx + 1))) return s;
  5585. +               }
  5586. +
  5587. +               *num = bc_vec_item(v, r->d.id.idx);
  5588. +           }
  5589. +           else *num = bc_vec_top(v);
  5590. +
  5591. +           break;
  5592. +       }
  5593. +
  5594. +       case BC_RESULT_LAST:
  5595. +       {
  5596. +           *num = &p->last;
  5597. +           break;
  5598. +       }
  5599. +
  5600. +       case BC_RESULT_ONE:
  5601. +       {
  5602. +           *num = &p->one;
  5603. +           break;
  5604. +       }
  5605. +   }
  5606. +
  5607. +   return s;
  5608. +}
  5609. +
  5610. +static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
  5611. +                                     BcResult **r, BcNum **rn, bool assign)
  5612. +{
  5613. +   BcStatus s;
  5614. +   bool hex;
  5615. +   BcResultType lt, rt;
  5616. +
  5617. +   if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
  5618. +
  5619. +   *r = bc_vec_item_rev(&p->results, 0);
  5620. +   *l = bc_vec_item_rev(&p->results, 1);
  5621. +
  5622. +   lt = (*l)->t;
  5623. +   rt = (*r)->t;
  5624. +   hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
  5625. +
  5626. +   if ((s = bc_program_num(p, *l, ln, false))) return s;
  5627. +   if ((s = bc_program_num(p, *r, rn, hex))) return s;
  5628. +
  5629. +   // We run this again under these conditions in case any vector has been
  5630. +   // reallocated out from under the BcNums or arrays we had.
  5631. +   if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
  5632. +       s = bc_program_num(p, *l, ln, false);
  5633. +
  5634. +   if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
  5635. +       return BC_STATUS_EXEC_BAD_TYPE;
  5636. +   if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
  5637. +
  5638. +#ifdef CONFIG_DC
  5639. +#else // CONFIG_DC
  5640. +#endif // CONFIG_DC
  5641. +
  5642. +   return s;
  5643. +}
  5644. +
  5645. +static BcStatus bc_program_binOpRetire(BcProgram *p, BcResult *r) {
  5646. +   r->t = BC_RESULT_TEMP;
  5647. +   bc_vec_pop(&p->results);
  5648. +   bc_vec_pop(&p->results);
  5649. +   return bc_vec_push(&p->results, r);
  5650. +}
  5651. +
  5652. +static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) {
  5653. +
  5654. +   BcStatus s;
  5655. +
  5656. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  5657. +
  5658. +   *r = bc_vec_top(&p->results);
  5659. +
  5660. +   if ((s = bc_program_num(p, *r, n, false))) return s;
  5661. +
  5662. +#ifdef CONFIG_DC
  5663. +#endif // CONFIG_DC
  5664. +
  5665. +   if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
  5666. +
  5667. +   return s;
  5668. +}
  5669. +
  5670. +static BcStatus bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) {
  5671. +   r->t = t;
  5672. +   bc_vec_pop(&p->results);
  5673. +   return bc_vec_push(&p->results, r);
  5674. +}
  5675. +
  5676. +static BcStatus bc_program_op(BcProgram *p, uint8_t inst) {
  5677. +
  5678. +   BcStatus s;
  5679. +   BcResult *opd1, *opd2, res;
  5680. +   BcNum *n1, *n2 = NULL;
  5681. +   BcNumBinaryOp op;
  5682. +
  5683. +   if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
  5684. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  5685. +
  5686. +   op = bc_program_ops[inst - BC_INST_POWER];
  5687. +   if ((s = op(n1, n2, &res.d.n, p->scale))) goto err;
  5688. +   if ((s = bc_program_binOpRetire(p, &res))) goto err;
  5689. +
  5690. +   return s;
  5691. +
  5692. +err:
  5693. +   bc_num_free(&res.d.n);
  5694. +   return s;
  5695. +}
  5696. +
  5697. +static BcStatus bc_program_read(BcProgram *p) {
  5698. +
  5699. +   BcStatus s;
  5700. +   BcParse parse;
  5701. +   BcVec buf;
  5702. +   BcInstPtr ip;
  5703. +   size_t i;
  5704. +   BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
  5705. +
  5706. +   for (i = 0; i < p->stack.len; ++i) {
  5707. +       if (((BcInstPtr*) bc_vec_item(&p->stack, i))->func == BC_PROG_READ)
  5708. +           return BC_STATUS_EXEC_REC_READ;
  5709. +   }
  5710. +
  5711. +   bc_vec_npop(&f->code, f->code.len);
  5712. +
  5713. +   if ((s = bc_vec_init(&buf, sizeof(char), NULL))) return BC_STATUS_ALLOC_ERR;
  5714. +   if ((s = bc_read_line(&buf, "read> "))) goto io_err;
  5715. +
  5716. +   if ((s = p->parse_init(&parse, p, BC_PROG_READ))) goto io_err;
  5717. +   bc_lex_file(&parse.l, bc_program_stdin_name);
  5718. +   if ((s = bc_parse_text(&parse, buf.v))) goto exec_err;
  5719. +
  5720. +   if ((s = p->parse_expr(&parse, BC_PARSE_NOREAD))) goto exec_err;
  5721. +
  5722. +   if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
  5723. +       s = BC_STATUS_EXEC_BAD_READ_EXPR;
  5724. +       goto exec_err;
  5725. +   }
  5726. +
  5727. +   ip.func = BC_PROG_READ;
  5728. +   ip.idx = 0;
  5729. +   ip.len = p->results.len;
  5730. +
  5731. +   // Update this pointer, just in case.
  5732. +   f = bc_vec_item(&p->fns, BC_PROG_READ);
  5733. +
  5734. +   if ((s = bc_vec_pushByte(&f->code, BC_INST_POP_EXEC))) goto exec_err;
  5735. +   if ((s = bc_vec_push(&p->stack, &ip))) goto exec_err;
  5736. +
  5737. +exec_err:
  5738. +   bc_parse_free(&parse);
  5739. +io_err:
  5740. +   bc_vec_free(&buf);
  5741. +   return s;
  5742. +}
  5743. +
  5744. +static size_t bc_program_index(char *code, size_t *bgn) {
  5745. +
  5746. +   uint8_t amt = code[(*bgn)++], i = 0;
  5747. +   size_t res = 0;
  5748. +
  5749. +   for (; i < amt; ++i, ++(*bgn))
  5750. +       res |= (((size_t) ((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
  5751. +
  5752. +   return res;
  5753. +}
  5754. +
  5755. +static char* bc_program_name(char *code, size_t *bgn) {
  5756. +
  5757. +   size_t i;
  5758. +   char byte, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
  5759. +
  5760. +   if (!(s = malloc(ptr - str + 1))) return NULL;
  5761. +
  5762. +   for (i = 0; (byte = (char) code[(*bgn)++]) && byte != BC_PARSE_STREND; ++i)
  5763. +       s[i] = byte;
  5764. +
  5765. +   s[i] = '\0';
  5766. +
  5767. +   return s;
  5768. +}
  5769. +
  5770. +static BcStatus bc_program_printString(const char *str, size_t *nchars) {
  5771. +
  5772. +   size_t i, len = strlen(str);
  5773. +
  5774. +#ifdef CONFIG_DC
  5775. +   if (!len) return putchar('\0') < 0 ? BC_STATUS_IO_ERR : BC_STATUS_SUCCESS;
  5776. +#endif // CONFIG_DC
  5777. +
  5778. +   for (i = 0; i < len; ++i, ++(*nchars)) {
  5779. +
  5780. +       int err, c;
  5781. +
  5782. +       if ((c = str[i]) != '\\' || i == len - 1) err = putchar(c);
  5783. +       else {
  5784. +
  5785. +           switch ((c = str[++i])) {
  5786. +
  5787. +               case 'a':
  5788. +               {
  5789. +                   err = putchar('\a');
  5790. +                   break;
  5791. +               }
  5792. +
  5793. +               case 'b':
  5794. +               {
  5795. +                   err = putchar('\b');
  5796. +                   break;
  5797. +               }
  5798. +
  5799. +               case '\\':
  5800. +               case 'e':
  5801. +               {
  5802. +                   err = putchar('\\');
  5803. +                   break;
  5804. +               }
  5805. +
  5806. +               case 'f':
  5807. +               {
  5808. +                   err = putchar('\f');
  5809. +                   break;
  5810. +               }
  5811. +
  5812. +               case 'n':
  5813. +               {
  5814. +                   err = putchar('\n');
  5815. +                   *nchars = SIZE_MAX;
  5816. +                   break;
  5817. +               }
  5818. +
  5819. +               case 'r':
  5820. +               {
  5821. +                   err = putchar('\r');
  5822. +                   break;
  5823. +               }
  5824. +
  5825. +               case 'q':
  5826. +               {
  5827. +                   err = putchar('"');
  5828. +                   break;
  5829. +               }
  5830. +
  5831. +               case 't':
  5832. +               {
  5833. +                   err = putchar('\t');
  5834. +                   break;
  5835. +               }
  5836. +
  5837. +               default:
  5838. +               {
  5839. +                   // Just print the backslash and following character.
  5840. +                   if (putchar('\\') == EOF) return BC_STATUS_IO_ERR;
  5841. +                   ++(*nchars);
  5842. +                   err = putchar(c);
  5843. +                   break;
  5844. +               }
  5845. +           }
  5846. +       }
  5847. +
  5848. +       if (err == EOF) return BC_STATUS_IO_ERR;
  5849. +   }
  5850. +
  5851. +   return BC_STATUS_SUCCESS;
  5852. +}
  5853. +
  5854. +static BcStatus bc_program_print(BcProgram *p, uint8_t inst, size_t idx) {
  5855. +
  5856. +   BcStatus s = BC_STATUS_SUCCESS;
  5857. +   BcResult *r;
  5858. +   size_t len, i;
  5859. +   char *str;
  5860. +   BcNum *num = NULL;
  5861. +   bool pop = inst != BC_INST_PRINT;
  5862. +
  5863. +   if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
  5864. +
  5865. +   r = bc_vec_item_rev(&p->results, idx);
  5866. +   if ((s = bc_program_num(p, r, &num, false))) return s;
  5867. +
  5868. +   if (BC_PROG_NUM(r, num)) {
  5869. +       s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
  5870. +       if (!s) s = bc_num_copy(&p->last, num);
  5871. +   }
  5872. +   else {
  5873. +
  5874. +       idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
  5875. +       str = *((char**) bc_vec_item(&p->strs, idx));
  5876. +
  5877. +       if (inst == BC_INST_PRINT_STR) {
  5878. +           for (i = 0, len = strlen(str); i < len; ++i) {
  5879. +               char c = str[i];
  5880. +               if (putchar(c) == EOF) return BC_STATUS_IO_ERR;
  5881. +               if (c == '\n') p->nchars = SIZE_MAX;
  5882. +               ++p->nchars;
  5883. +           }
  5884. +       }
  5885. +       else {
  5886. +           if ((s = bc_program_printString(str, &p->nchars))) return s;
  5887. +           if (inst == BC_INST_PRINT && putchar('\n') == EOF)
  5888. +               s = BC_STATUS_IO_ERR;
  5889. +       }
  5890. +   }
  5891. +
  5892. +   if (!s && pop) bc_vec_pop(&p->results);
  5893. +
  5894. +   return s;
  5895. +}
  5896. +
  5897. +static BcStatus bc_program_negate(BcProgram *p) {
  5898. +
  5899. +   BcStatus s;
  5900. +   BcResult res, *ptr;
  5901. +   BcNum *num = NULL;
  5902. +
  5903. +   if ((s = bc_program_prep(p, &ptr, &num))) return s;
  5904. +   if ((s = bc_num_init(&res.d.n, num->len))) return s;
  5905. +   if ((s = bc_num_copy(&res.d.n, num))) goto err;
  5906. +
  5907. +   if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
  5908. +
  5909. +   if ((s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
  5910. +
  5911. +   return s;
  5912. +
  5913. +err:
  5914. +   bc_num_free(&res.d.n);
  5915. +   return s;
  5916. +}
  5917. +
  5918. +static BcStatus bc_program_logical(BcProgram *p, uint8_t inst) {
  5919. +
  5920. +   BcStatus s;
  5921. +   BcResult *opd1, *opd2, res;
  5922. +   BcNum *n1, *n2;
  5923. +   bool cond = 0;
  5924. +   ssize_t cmp;
  5925. +
  5926. +   if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
  5927. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  5928. +
  5929. +   if (inst == BC_INST_BOOL_AND)
  5930. +       cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
  5931. +   else if (inst == BC_INST_BOOL_OR)
  5932. +       cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
  5933. +   else {
  5934. +
  5935. +       cmp = bc_num_cmp(n1, n2);
  5936. +
  5937. +       switch (inst) {
  5938. +
  5939. +           case BC_INST_REL_EQ:
  5940. +           {
  5941. +               cond = cmp == 0;
  5942. +               break;
  5943. +           }
  5944. +
  5945. +           case BC_INST_REL_LE:
  5946. +           {
  5947. +               cond = cmp <= 0;
  5948. +               break;
  5949. +           }
  5950. +
  5951. +           case BC_INST_REL_GE:
  5952. +           {
  5953. +               cond = cmp >= 0;
  5954. +               break;
  5955. +           }
  5956. +
  5957. +           case BC_INST_REL_NE:
  5958. +           {
  5959. +               cond = cmp != 0;
  5960. +               break;
  5961. +           }
  5962. +
  5963. +           case BC_INST_REL_LT:
  5964. +           {
  5965. +               cond = cmp < 0;
  5966. +               break;
  5967. +           }
  5968. +
  5969. +           case BC_INST_REL_GT:
  5970. +           {
  5971. +               cond = cmp > 0;
  5972. +               break;
  5973. +           }
  5974. +       }
  5975. +   }
  5976. +
  5977. +   (cond ? bc_num_one : bc_num_zero)(&res.d.n);
  5978. +
  5979. +   if ((s = bc_program_binOpRetire(p, &res))) goto err;
  5980. +
  5981. +   return s;
  5982. +
  5983. +err:
  5984. +   bc_num_free(&res.d.n);
  5985. +   return s;
  5986. +}
  5987. +
  5988. +#ifdef CONFIG_DC
  5989. +static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
  5990. +                                     bool push)
  5991. +{
  5992. +   BcStatus s;
  5993. +   BcNum n2;
  5994. +   BcResult res;
  5995. +
  5996. +   memset(&n2, 0, sizeof(BcNum));
  5997. +   n2.rdx = res.d.id.idx = r->d.id.idx;
  5998. +   res.t = BC_RESULT_STR;
  5999. +
  6000. +   if (!push) {
  6001. +       if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
  6002. +       bc_vec_pop(v);
  6003. +       bc_vec_pop(&p->results);
  6004. +   }
  6005. +
  6006. +   bc_vec_pop(&p->results);
  6007. +
  6008. +   if ((s = bc_vec_push(&p->results, &res))) return s;
  6009. +
  6010. +   return bc_vec_push(v, &n2);
  6011. +}
  6012. +#endif // CONFIG_DC
  6013. +
  6014. +static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var) {
  6015. +
  6016. +   BcStatus s;
  6017. +   BcResult *ptr, r;
  6018. +   BcVec *v;
  6019. +   BcNum *n;
  6020. +
  6021. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  6022. +
  6023. +   ptr = bc_vec_top(&p->results);
  6024. +   if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
  6025. +
  6026. +   if ((s = bc_program_search(p, name, &v, var))) return s;
  6027. +
  6028. +#ifdef CONFIG_DC
  6029. +   if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
  6030. +   if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
  6031. +#endif // CONFIG_DC
  6032. +
  6033. +   if ((s = bc_program_num(p, ptr, &n, false))) return s;
  6034. +
  6035. +   // Do this once more to make sure that pointers were not invalidated.
  6036. +   if ((s = bc_program_search(p, name, &v, var))) return s;
  6037. +
  6038. +   if (var) {
  6039. +       if ((s = bc_num_init(&r.d.n, BC_NUM_DEF_SIZE))) return s;
  6040. +       s = bc_num_copy(&r.d.n, n);
  6041. +   }
  6042. +   else {
  6043. +       if ((s = bc_array_init(&r.d.v, true))) return s;
  6044. +       s = bc_array_copy(&r.d.v, (BcVec*) n);
  6045. +   }
  6046. +
  6047. +   if (s || (s = bc_vec_push(v, &r.d))) goto err;
  6048. +
  6049. +   bc_vec_pop(&p->results);
  6050. +
  6051. +   return s;
  6052. +
  6053. +err:
  6054. +   if (var) bc_num_free(&r.d.n);
  6055. +   else bc_vec_free(&r.d.v);
  6056. +   return s;
  6057. +}
  6058. +
  6059. +static BcStatus bc_program_assign(BcProgram *p, uint8_t inst) {
  6060. +
  6061. +   BcStatus s;
  6062. +   BcResult *left, *right, res;
  6063. +   BcNum *l = NULL, *r = NULL;
  6064. +   unsigned long val, max;
  6065. +   bool assign = inst == BC_INST_ASSIGN, ib, sc;
  6066. +
  6067. +   if ((s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign))) return s;
  6068. +
  6069. +   ib = left->t == BC_RESULT_IBASE;
  6070. +   sc = left->t == BC_RESULT_SCALE;
  6071. +
  6072. +#ifdef CONFIG_DC
  6073. +
  6074. +   if (right->t == BC_RESULT_STR) {
  6075. +
  6076. +       BcVec *v;
  6077. +
  6078. +       if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
  6079. +       if ((s = bc_program_search(p, left->d.id.name, &v, true))) return s;
  6080. +
  6081. +       return bc_program_assignStr(p, right, v, false);
  6082. +   }
  6083. +#endif // CONFIG_DC
  6084. +
  6085. +   if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
  6086. +       return BC_STATUS_PARSE_BAD_ASSIGN;
  6087. +
  6088. +#ifdef CONFIG_BC
  6089. +   if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
  6090. +       return BC_STATUS_MATH_DIVIDE_BY_ZERO;
  6091. +
  6092. +   if (assign) s = bc_num_copy(l, r);
  6093. +   else s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
  6094. +
  6095. +   if (s) return s;
  6096. +#else // CONFIG_BC
  6097. +   if ((s = bc_num_copy(l, r))) return s;
  6098. +#endif // CONFIG_BC
  6099. +
  6100. +   if (ib || sc || left->t == BC_RESULT_OBASE) {
  6101. +
  6102. +       size_t *ptr;
  6103. +
  6104. +       if ((s = bc_num_ulong(l, &val))) return s;
  6105. +       s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
  6106. +
  6107. +       if (sc) {
  6108. +           max = BC_MAX_SCALE;
  6109. +           ptr = &p->scale;
  6110. +       }
  6111. +       else {
  6112. +           if (val < BC_NUM_MIN_BASE) return s;
  6113. +           max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
  6114. +           ptr = ib ? &p->ib_t : &p->ob_t;
  6115. +       }
  6116. +
  6117. +       if (val > max) return s;
  6118. +       else if (!sc && (s = bc_num_copy(ib ? &p->ib : &p->ob, l))) return s;
  6119. +
  6120. +       *ptr = (size_t) val;
  6121. +   }
  6122. +
  6123. +   if ((s = bc_num_init(&res.d.n, l->len))) return s;
  6124. +   if ((s = bc_num_copy(&res.d.n, l))) goto err;
  6125. +   if ((s = bc_program_binOpRetire(p, &res))) goto err;
  6126. +
  6127. +   return s;
  6128. +
  6129. +err:
  6130. +   bc_num_free(&res.d.n);
  6131. +   return s;
  6132. +}
  6133. +
  6134. +static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
  6135. +                                   bool pop, bool copy)
  6136. +{
  6137. +   BcStatus s;
  6138. +   BcResult r;
  6139. +   char *name;
  6140. +#ifdef CONFIG_DC // Exclude
  6141. +   BcNum *num;
  6142. +   BcVec *v;
  6143. +#else // CONFIG_DC
  6144. +   (void) pop, (void) copy;
  6145. +#endif // CONFIG_DC Exclude
  6146. +
  6147. +   if (!(name = bc_program_name(code, bgn))) return BC_STATUS_ALLOC_ERR;
  6148. +   r.t = BC_RESULT_VAR;
  6149. +   r.d.id.name = name;
  6150. +
  6151. +#ifdef CONFIG_DC
  6152. +   if ((s = bc_program_search(p, name, &v, true))) goto err;
  6153. +   num = bc_vec_top(v);
  6154. +
  6155. +   if (pop || copy) {
  6156. +
  6157. +       if (!BC_PROG_STACK(v, 2 - copy)) {
  6158. +           s = BC_STATUS_EXEC_STACK;
  6159. +           goto err;
  6160. +       }
  6161. +
  6162. +       free(name);
  6163. +       name = NULL;
  6164. +
  6165. +       if ((pop = !BC_PROG_STR(num))) {
  6166. +
  6167. +           r.t = BC_RESULT_TEMP;
  6168. +
  6169. +           if ((s = bc_num_init(&r.d.n, BC_NUM_DEF_SIZE))) goto err;
  6170. +           if ((s = bc_num_copy(&r.d.n, num))) goto copy_err;
  6171. +       }
  6172. +       else {
  6173. +           r.t = BC_RESULT_STR;
  6174. +           r.d.id.idx = num->rdx;
  6175. +       }
  6176. +
  6177. +       if (!copy) bc_vec_pop(v);
  6178. +   }
  6179. +#endif // CONFIG_DC
  6180. +
  6181. +   s = bc_vec_push(&p->results, &r);
  6182. +
  6183. +#ifdef CONFIG_DC
  6184. +copy_err:
  6185. +   if (s && pop) bc_num_free(&r.d.n);
  6186. +err:
  6187. +#endif // CONFIG_DC
  6188. +   if (s) free(name);
  6189. +   return s;
  6190. +}
  6191. +
  6192. +static BcStatus bc_program_pushArray(BcProgram *p, char *code,
  6193. +                                     size_t *bgn, uint8_t inst)
  6194. +{
  6195. +   BcStatus s;
  6196. +   BcResult r;
  6197. +   BcNum *num;
  6198. +
  6199. +   if (!(r.d.id.name = bc_program_name(code, bgn))) return BC_STATUS_ALLOC_ERR;
  6200. +
  6201. +   if (inst == BC_INST_ARRAY) {
  6202. +       r.t = BC_RESULT_ARRAY;
  6203. +       s = bc_vec_push(&p->results, &r);
  6204. +   }
  6205. +   else {
  6206. +
  6207. +       BcResult *operand;
  6208. +       unsigned long temp;
  6209. +
  6210. +       if ((s = bc_program_prep(p, &operand, &num))) goto err;
  6211. +       if ((s = bc_num_ulong(num, &temp))) goto err;
  6212. +
  6213. +       if (temp > BC_MAX_DIM) {
  6214. +           s = BC_STATUS_EXEC_ARRAY_LEN;
  6215. +           goto err;
  6216. +       }
  6217. +
  6218. +       r.d.id.idx = (size_t) temp;
  6219. +       s = bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
  6220. +   }
  6221. +
  6222. +err:
  6223. +   if (s) free(r.d.id.name);
  6224. +   return s;
  6225. +}
  6226. +
  6227. +#ifdef CONFIG_BC
  6228. +static BcStatus bc_program_incdec(BcProgram *p, uint8_t inst) {
  6229. +
  6230. +   BcStatus s;
  6231. +   BcResult *ptr, res, copy;
  6232. +   BcNum *num = NULL;
  6233. +   uint8_t inst2 = inst;
  6234. +
  6235. +   if ((s = bc_program_prep(p, &ptr, &num))) return s;
  6236. +
  6237. +   if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
  6238. +       copy.t = BC_RESULT_TEMP;
  6239. +       if ((s = bc_num_init(&copy.d.n, num->len))) return s;
  6240. +       if ((s = bc_num_copy(&copy.d.n, num))) goto err;
  6241. +   }
  6242. +
  6243. +   res.t = BC_RESULT_ONE;
  6244. +   inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
  6245. +              BC_INST_ASSIGN_PLUS : BC_INST_ASSIGN_MINUS;
  6246. +
  6247. +   if ((s = bc_vec_push(&p->results, &res))) goto err;
  6248. +   if ((s = bc_program_assign(p, inst))) goto err;
  6249. +
  6250. +   if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
  6251. +       bc_vec_pop(&p->results);
  6252. +       if ((s = bc_vec_push(&p->results, &copy))) goto err;
  6253. +   }
  6254. +
  6255. +   return s;
  6256. +
  6257. +err:
  6258. +   if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST)
  6259. +       bc_num_free(&copy.d.n);
  6260. +   return s;
  6261. +}
  6262. +
  6263. +static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx) {
  6264. +
  6265. +   BcStatus s = BC_STATUS_SUCCESS;
  6266. +   BcInstPtr ip;
  6267. +   size_t i, nparams = bc_program_index(code, idx);
  6268. +   BcFunc *func;
  6269. +   BcVec *v;
  6270. +   BcId *a;
  6271. +   BcResultData param;
  6272. +   BcResult *arg;
  6273. +
  6274. +   ip.idx = 0;
  6275. +   ip.func = bc_program_index(code, idx);
  6276. +   func = bc_vec_item(&p->fns, ip.func);
  6277. +
  6278. +   if (!func->code.len) return BC_STATUS_EXEC_UNDEFINED_FUNC;
  6279. +   if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
  6280. +   ip.len = p->results.len - nparams;
  6281. +
  6282. +   for (i = 0; i < nparams; ++i) {
  6283. +
  6284. +       a = bc_vec_item(&func->autos, nparams - 1 - i);
  6285. +       arg = bc_vec_top(&p->results);
  6286. +
  6287. +       if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
  6288. +           return BC_STATUS_EXEC_BAD_TYPE;
  6289. +
  6290. +       if ((s = bc_program_copyToVar(p, a->name, a->idx))) return s;
  6291. +   }
  6292. +
  6293. +   for (; i < func->autos.len; ++i) {
  6294. +
  6295. +       a = bc_vec_item(&func->autos, i);
  6296. +       if ((s = bc_program_search(p, a->name, &v, a->idx))) return s;
  6297. +
  6298. +       if (a->idx) {
  6299. +           if ((s = bc_num_init(&param.n, BC_NUM_DEF_SIZE))) return s;
  6300. +           if ((s = bc_vec_push(v, &param.n))) goto err;
  6301. +       }
  6302. +       else {
  6303. +           if ((s = bc_array_init(&param.v, true))) return s;
  6304. +           if ((s = bc_vec_push(v, &param.v))) goto err;
  6305. +       }
  6306. +   }
  6307. +
  6308. +   return bc_vec_push(&p->stack, &ip);
  6309. +
  6310. +err:
  6311. +   if (a->idx) bc_num_free(&param.n);
  6312. +   else bc_vec_free(&param.v);
  6313. +   return s;
  6314. +}
  6315. +
  6316. +static BcStatus bc_program_return(BcProgram *p, uint8_t inst) {
  6317. +
  6318. +   BcStatus s;
  6319. +   BcResult res;
  6320. +   BcFunc *f;
  6321. +   size_t i;
  6322. +   BcInstPtr *ip = bc_vec_top(&p->stack);
  6323. +
  6324. +   if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
  6325. +       return BC_STATUS_EXEC_STACK;
  6326. +
  6327. +   f = bc_vec_item(&p->fns, ip->func);
  6328. +   res.t = BC_RESULT_TEMP;
  6329. +
  6330. +   if (inst == BC_INST_RET) {
  6331. +
  6332. +       BcNum *num;
  6333. +       BcResult *operand = bc_vec_top(&p->results);
  6334. +
  6335. +       if ((s = bc_program_num(p, operand, &num, false))) return s;
  6336. +       if ((s = bc_num_init(&res.d.n, num->len))) return s;
  6337. +       if ((s = bc_num_copy(&res.d.n, num))) goto err;
  6338. +   }
  6339. +   else {
  6340. +       if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  6341. +       bc_num_zero(&res.d.n);
  6342. +   }
  6343. +
  6344. +   // We need to pop arguments as well, so this takes that into account.
  6345. +   for (i = 0; i < f->autos.len; ++i) {
  6346. +
  6347. +       BcVec *v;
  6348. +       BcId *a = bc_vec_item(&f->autos, i);
  6349. +
  6350. +       if ((s = bc_program_search(p, a->name, &v, a->idx))) goto err;
  6351. +
  6352. +       bc_vec_pop(v);
  6353. +   }
  6354. +
  6355. +   bc_vec_npop(&p->results, p->results.len - ip->len);
  6356. +   if ((s = bc_vec_push(&p->results, &res))) goto err;
  6357. +   bc_vec_pop(&p->stack);
  6358. +
  6359. +   return s;
  6360. +
  6361. +err:
  6362. +   bc_num_free(&res.d.n);
  6363. +   return s;
  6364. +}
  6365. +#endif // CONFIG_BC
  6366. +
  6367. +static unsigned long bc_program_scale(BcNum *n) {
  6368. +   return (unsigned long) n->rdx;
  6369. +}
  6370. +
  6371. +static unsigned long bc_program_len(BcNum *n) {
  6372. +
  6373. +   unsigned long len = n->len;
  6374. +
  6375. +   if (n->rdx == n->len) {
  6376. +       size_t i;
  6377. +       for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
  6378. +   }
  6379. +
  6380. +   return len;
  6381. +}
  6382. +
  6383. +static BcStatus bc_program_builtin(BcProgram *p, uint8_t inst) {
  6384. +
  6385. +   BcStatus s;
  6386. +   BcResult *opnd;
  6387. +   BcNum *num = NULL;
  6388. +   BcResult res;
  6389. +   bool len = inst == BC_INST_LENGTH;
  6390. +
  6391. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  6392. +   opnd = bc_vec_top(&p->results);
  6393. +   if ((s = bc_program_num(p, opnd, &num, false))) return s;
  6394. +
  6395. +#ifdef CONFIG_DC
  6396. +   if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
  6397. +#endif // CONFIG_DC
  6398. +
  6399. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  6400. +
  6401. +   if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
  6402. +#ifdef CONFIG_BC
  6403. +   else if (len && opnd->t == BC_RESULT_ARRAY) {
  6404. +       BcVec *vec = (BcVec*) num;
  6405. +       s = bc_num_ulong2num(&res.d.n, (unsigned long) vec->len);
  6406. +   }
  6407. +#endif // CONFIG_BC
  6408. +#ifdef CONFIG_DC
  6409. +   else if (len && !BC_PROG_NUM(opnd, num)) {
  6410. +
  6411. +       char **str;
  6412. +       size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
  6413. +
  6414. +       str = bc_vec_item(&p->strs, idx);
  6415. +       s = bc_num_ulong2num(&res.d.n, strlen(*str));
  6416. +   }
  6417. +#endif // CONFIG_DC
  6418. +   else {
  6419. +       BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
  6420. +       s = bc_num_ulong2num(&res.d.n, f(num));
  6421. +   }
  6422. +
  6423. +   if (s || (s = bc_program_retire(p, &res, BC_RESULT_TEMP))) goto err;
  6424. +
  6425. +   return s;
  6426. +
  6427. +err:
  6428. +   bc_num_free(&res.d.n);
  6429. +   return s;
  6430. +}
  6431. +
  6432. +#ifdef CONFIG_DC
  6433. +static BcStatus bc_program_divmod(BcProgram *p) {
  6434. +
  6435. +   BcStatus s;
  6436. +   BcResult *opd1, *opd2, res, res2;
  6437. +   BcNum *n1, *n2 = NULL;
  6438. +
  6439. +   if ((s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false))) return s;
  6440. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  6441. +   if ((s = bc_num_init(&res2.d.n, n2->len))) goto res2_err;
  6442. +
  6443. +   if ((s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale))) goto err;
  6444. +
  6445. +   if ((s = bc_program_binOpRetire(p, &res2))) goto err;
  6446. +   res.t = BC_RESULT_TEMP;
  6447. +   if ((s = bc_vec_push(&p->results, &res))) goto res2_err;
  6448. +
  6449. +   return s;
  6450. +
  6451. +err:
  6452. +   bc_num_free(&res2.d.n);
  6453. +res2_err:
  6454. +   bc_num_free(&res.d.n);
  6455. +   return s;
  6456. +}
  6457. +
  6458. +static BcStatus bc_program_modexp(BcProgram *p) {
  6459. +
  6460. +   BcStatus s;
  6461. +   BcResult *r1, *r2, *r3, res;
  6462. +   BcNum *n1, *n2, *n3;
  6463. +
  6464. +   if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
  6465. +   if ((s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false))) return s;
  6466. +
  6467. +   r1 = bc_vec_item_rev(&p->results, 2);
  6468. +   if ((s = bc_program_num(p, r1, &n1, false))) return s;
  6469. +   if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
  6470. +
  6471. +   // Make sure that the values have their pointers updated, if necessary.
  6472. +   if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
  6473. +       if (r1->t == r2->t && (s = bc_program_num(p, r2, &n2, false))) return s;
  6474. +       if (r1->t == r3->t && (s = bc_program_num(p, r3, &n3, false))) return s;
  6475. +   }
  6476. +
  6477. +   if ((s = bc_num_init(&res.d.n, n3->len))) return s;
  6478. +   if ((s = bc_num_modexp(n1, n2, n3, &res.d.n))) goto err;
  6479. +
  6480. +   bc_vec_pop(&p->results);
  6481. +
  6482. +   if ((s = bc_program_binOpRetire(p, &res))) goto err;
  6483. +
  6484. +   return s;
  6485. +
  6486. +err:
  6487. +   bc_num_free(&res.d.n);
  6488. +   return s;
  6489. +}
  6490. +
  6491. +static BcStatus bc_program_stackLen(BcProgram *p) {
  6492. +
  6493. +   BcStatus s;
  6494. +   BcResult res;
  6495. +   size_t len = p->results.len;
  6496. +
  6497. +   res.t = BC_RESULT_TEMP;
  6498. +
  6499. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  6500. +   if ((s = bc_num_ulong2num(&res.d.n, len))) goto err;
  6501. +   if ((s = bc_vec_push(&p->results, &res))) goto err;
  6502. +
  6503. +   return s;
  6504. +
  6505. +err:
  6506. +   bc_num_free(&res.d.n);
  6507. +   return s;
  6508. +}
  6509. +
  6510. +static BcStatus bc_program_asciify(BcProgram *p) {
  6511. +
  6512. +   BcStatus s;
  6513. +   BcResult *r, res;
  6514. +   BcNum *num = NULL, n;
  6515. +   char *str, *str2, c;
  6516. +   size_t len = p->strs.len, idx;
  6517. +   unsigned long val;
  6518. +
  6519. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  6520. +
  6521. +   r = bc_vec_top(&p->results);
  6522. +   if ((s = bc_program_num(p, r, &num, false))) return s;
  6523. +
  6524. +   if (BC_PROG_NUM(r, num)) {
  6525. +
  6526. +       if ((s = bc_num_init(&n, BC_NUM_DEF_SIZE))) return s;
  6527. +       if ((s = bc_num_copy(&n, num))) goto num_err;
  6528. +       bc_num_truncate(&n, n.rdx);
  6529. +
  6530. +       if ((s = bc_num_mod(&n, &p->strmb, &n, 0))) goto num_err;
  6531. +       if ((s = bc_num_ulong(&n, &val))) goto num_err;
  6532. +
  6533. +       c = (char) val;
  6534. +
  6535. +       bc_num_free(&n);
  6536. +   }
  6537. +   else {
  6538. +       idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
  6539. +       str2 = *((char**) bc_vec_item(&p->strs, idx));
  6540. +       c = str2[0];
  6541. +   }
  6542. +
  6543. +   if (!(str = malloc(2))) return BC_STATUS_ALLOC_ERR;
  6544. +
  6545. +   str[0] = c;
  6546. +   str[1] = '\0';
  6547. +
  6548. +   if (!(str2 = strdup(str))) {
  6549. +       s = BC_STATUS_ALLOC_ERR;
  6550. +       goto err;
  6551. +   }
  6552. +
  6553. +   if ((s = bc_program_addFunc(p, str2, &idx))) goto err;
  6554. +
  6555. +   if (idx != len + BC_PROG_REQ_FUNCS) {
  6556. +
  6557. +       for (idx = 0; idx < p->strs.len; ++idx) {
  6558. +           if (!strcmp(*((char**) bc_vec_item(&p->strs, idx)), str)) {
  6559. +               len = idx;
  6560. +               break;
  6561. +           }
  6562. +       }
  6563. +
  6564. +       free(str);
  6565. +   }
  6566. +   else if ((s = bc_vec_push(&p->strs, &str))) goto err;
  6567. +
  6568. +   res.t = BC_RESULT_STR;
  6569. +   res.d.id.idx = len;
  6570. +
  6571. +   bc_vec_pop(&p->results);
  6572. +
  6573. +   return bc_vec_push(&p->results, &res);
  6574. +
  6575. +num_err:
  6576. +   bc_num_free(&n);
  6577. +   return s;
  6578. +err:
  6579. +   free(str);
  6580. +   return s;
  6581. +}
  6582. +
  6583. +static BcStatus bc_program_printStream(BcProgram *p) {
  6584. +
  6585. +   BcStatus s;
  6586. +   BcResult *r;
  6587. +   BcNum *n = NULL;
  6588. +   size_t idx;
  6589. +   char *str;
  6590. +
  6591. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  6592. +
  6593. +   r = bc_vec_top(&p->results);
  6594. +   if ((s = bc_program_num(p, r, &n, false))) return s;
  6595. +
  6596. +   if (BC_PROG_NUM(r, n)) s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
  6597. +   else {
  6598. +       idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
  6599. +       str = *((char**) bc_vec_item(&p->strs, idx));
  6600. +       if (printf("%s", str) < 0) s = BC_STATUS_IO_ERR;
  6601. +   }
  6602. +
  6603. +   return s;
  6604. +}
  6605. +
  6606. +static BcStatus bc_program_nquit(BcProgram *p) {
  6607. +
  6608. +   BcStatus s;
  6609. +   BcResult *opnd;
  6610. +   BcNum *num = NULL;
  6611. +   unsigned long val;
  6612. +
  6613. +   if ((s = bc_program_prep(p, &opnd, &num))) return s;
  6614. +   if ((s = bc_num_ulong(num, &val))) return s;
  6615. +
  6616. +   bc_vec_pop(&p->results);
  6617. +
  6618. +   if (p->stack.len < val) return BC_STATUS_EXEC_STACK;
  6619. +   else if (p->stack.len == val) return BC_STATUS_QUIT;
  6620. +
  6621. +   bc_vec_npop(&p->stack, val);
  6622. +
  6623. +   return s;
  6624. +}
  6625. +
  6626. +static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
  6627. +                                   bool cond)
  6628. +{
  6629. +   BcStatus s = BC_STATUS_SUCCESS;
  6630. +   BcResult *r;
  6631. +   char **str;
  6632. +   BcFunc *f;
  6633. +   BcParse prs;
  6634. +   BcInstPtr ip;
  6635. +   size_t fidx, sidx;
  6636. +   BcNum *n;
  6637. +   bool exec;
  6638. +
  6639. +   if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  6640. +
  6641. +   r = bc_vec_top(&p->results);
  6642. +
  6643. +   if (cond) {
  6644. +
  6645. +       BcVec *v;
  6646. +       char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
  6647. +
  6648. +       if (code[*bgn] == BC_PARSE_STREND) (*bgn) += 1;
  6649. +       else else_name = bc_program_name(code, bgn);
  6650. +
  6651. +       if ((exec = r->d.n.len)) name = then_name;
  6652. +       else if ((exec = (else_name != NULL))) name = else_name;
  6653. +
  6654. +       if (exec) {
  6655. +           s = bc_program_search(p, name, &v, true);
  6656. +           n = bc_vec_top(v);
  6657. +       }
  6658. +
  6659. +       free(then_name);
  6660. +       free(else_name);
  6661. +
  6662. +       if (s || !exec) goto exit;
  6663. +       if (!BC_PROG_STR(n)) {
  6664. +           s = BC_STATUS_EXEC_BAD_TYPE;
  6665. +           goto exit;
  6666. +       }
  6667. +
  6668. +       sidx = n->rdx;
  6669. +   }
  6670. +   else {
  6671. +
  6672. +       if (r->t == BC_RESULT_STR) sidx = r->d.id.idx;
  6673. +       else if (r->t == BC_RESULT_VAR) {
  6674. +           if ((s = bc_program_num(p, r, &n, false))) goto exit;
  6675. +           if (!BC_PROG_STR(n)) goto exit;
  6676. +           sidx = n->rdx;
  6677. +       }
  6678. +       else goto exit;
  6679. +   }
  6680. +
  6681. +   fidx = sidx + BC_PROG_REQ_FUNCS;
  6682. +
  6683. +   str = bc_vec_item(&p->strs, sidx);
  6684. +   f = bc_vec_item(&p->fns, fidx);
  6685. +
  6686. +   if (!f->code.len) {
  6687. +
  6688. +       if ((s = p->parse_init(&prs, p, fidx))) goto exit;
  6689. +       if ((s = bc_parse_text(&prs, *str))) goto err;
  6690. +       if ((s = p->parse_expr(&prs, BC_PARSE_NOCALL))) goto err;
  6691. +
  6692. +       if (prs.l.t.t != BC_LEX_EOF) {
  6693. +           s = BC_STATUS_PARSE_BAD_EXP;
  6694. +           goto err;
  6695. +       }
  6696. +
  6697. +       bc_parse_free(&prs);
  6698. +   }
  6699. +
  6700. +   ip.idx = 0;
  6701. +   ip.len = p->results.len;
  6702. +   ip.func = fidx;
  6703. +
  6704. +   bc_vec_pop(&p->results);
  6705. +
  6706. +   return bc_vec_push(&p->stack, &ip);
  6707. +
  6708. +err:
  6709. +   bc_parse_free(&prs);
  6710. +   f = bc_vec_item(&p->fns, fidx);
  6711. +   bc_vec_npop(&f->code, f->code.len);
  6712. +exit:
  6713. +   bc_vec_pop(&p->results);
  6714. +   return s;
  6715. +}
  6716. +#endif // CONFIG_DC
  6717. +
  6718. +static BcStatus bc_program_pushGlobal(BcProgram *p, uint8_t inst) {
  6719. +
  6720. +   BcStatus s;
  6721. +   BcResult res;
  6722. +   unsigned long val;
  6723. +
  6724. +   res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
  6725. +   if (inst == BC_INST_IBASE) val = (unsigned long) p->ib_t;
  6726. +   else if (inst == BC_INST_SCALE) val = (unsigned long) p->scale;
  6727. +   else val = (unsigned long) p->ob_t;
  6728. +
  6729. +   if ((s = bc_num_init(&res.d.n, BC_NUM_DEF_SIZE))) return s;
  6730. +   if ((s = bc_num_ulong2num(&res.d.n, val))) goto err;
  6731. +   if ((s = bc_vec_push(&p->results, &res))) goto err;
  6732. +
  6733. +   return s;
  6734. +
  6735. +err:
  6736. +   bc_num_free(&res.d.n);
  6737. +   return s;
  6738. +}
  6739. +
  6740. +void bc_program_free(BcProgram *p) {
  6741. +   bc_num_free(&p->ib);
  6742. +   bc_num_free(&p->ob);
  6743. +   bc_num_free(&p->hexb);
  6744. +#ifdef CONFIG_DC
  6745. +   bc_num_free(&p->strmb);
  6746. +#endif // CONFIG_DC
  6747. +   bc_vec_free(&p->fns);
  6748. +   bc_vec_free(&p->fn_map);
  6749. +   bc_vec_free(&p->vars);
  6750. +   bc_vec_free(&p->var_map);
  6751. +   bc_vec_free(&p->arrs);
  6752. +   bc_vec_free(&p->arr_map);
  6753. +   bc_vec_free(&p->strs);
  6754. +   bc_vec_free(&p->consts);
  6755. +   bc_vec_free(&p->results);
  6756. +   bc_vec_free(&p->stack);
  6757. +   bc_num_free(&p->last);
  6758. +   bc_num_free(&p->zero);
  6759. +   bc_num_free(&p->one);
  6760. +}
  6761. +
  6762. +BcStatus bc_program_init(BcProgram *p, size_t line_len,
  6763. +                         BcParseInit init, BcParseExpr expr)
  6764. +{
  6765. +   BcStatus s;
  6766. +   size_t idx;
  6767. +   char *main_name, *read_name;
  6768. +   BcInstPtr ip;
  6769. +
  6770. +   memset(p, 0, sizeof(BcProgram));
  6771. +   memset(&ip, 0, sizeof(BcInstPtr));
  6772. +
  6773. +   p->nchars = p->scale = 0;
  6774. +   p->len = line_len;
  6775. +   p->parse_init = init;
  6776. +   p->parse_expr = expr;
  6777. +
  6778. +   if ((s = bc_num_init(&p->ib, BC_NUM_DEF_SIZE))) return s;
  6779. +   bc_num_ten(&p->ib);
  6780. +   p->ib_t = 10;
  6781. +
  6782. +   if ((s = bc_num_init(&p->ob, BC_NUM_DEF_SIZE))) goto err;
  6783. +   bc_num_ten(&p->ob);
  6784. +   p->ob_t = 10;
  6785. +
  6786. +   if ((s = bc_num_init(&p->hexb, BC_NUM_DEF_SIZE))) goto err;
  6787. +   bc_num_ten(&p->hexb);
  6788. +   p->hexb.num[0] = 6;
  6789. +
  6790. +#ifdef CONFIG_DC
  6791. +   if ((s = bc_num_init(&p->strmb, BC_NUM_DEF_SIZE))) goto err;
  6792. +   if ((s = bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1))) goto err;
  6793. +#endif // CONFIG_DC
  6794. +
  6795. +   if ((s = bc_num_init(&p->last, BC_NUM_DEF_SIZE))) goto err;
  6796. +   bc_num_zero(&p->last);
  6797. +
  6798. +   if ((s = bc_num_init(&p->zero, BC_NUM_DEF_SIZE))) goto err;
  6799. +   bc_num_zero(&p->zero);
  6800. +
  6801. +   if ((s = bc_num_init(&p->one, BC_NUM_DEF_SIZE))) goto err;
  6802. +   bc_num_one(&p->one);
  6803. +
  6804. +   if ((s = bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free))) goto err;
  6805. +   if ((s = bc_map_init(&p->fn_map))) goto err;
  6806. +
  6807. +   if (!(main_name = strdup(bc_func_main))) goto alloc_err;
  6808. +   if ((s = bc_program_addFunc(p, main_name, &idx))) goto err;
  6809. +
  6810. +   if (!(read_name = strdup(bc_func_read))) goto alloc_err;
  6811. +   if ((s = bc_program_addFunc(p, read_name, &idx))) goto err;
  6812. +
  6813. +   if ((s = bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free))) goto err;
  6814. +   if ((s = bc_map_init(&p->var_map))) goto err;
  6815. +
  6816. +   if ((s = bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free))) goto err;
  6817. +   if ((s = bc_map_init(&p->arr_map))) goto err;
  6818. +
  6819. +   if ((s = bc_vec_init(&p->strs, sizeof(char*), bc_string_free))) goto err;
  6820. +   if ((s = bc_vec_init(&p->consts, sizeof(char*), bc_string_free))) goto err;
  6821. +   if ((s = bc_vec_init(&p->results, sizeof(BcResult), bc_result_free)))
  6822. +       goto err;
  6823. +   if ((s = bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL))) goto err;
  6824. +   if ((s = bc_vec_push(&p->stack, &ip))) goto err;
  6825. +
  6826. +   return s;
  6827. +
  6828. +alloc_err:
  6829. +   s = BC_STATUS_ALLOC_ERR;
  6830. +err:
  6831. +   bc_program_free(p);
  6832. +   return s;
  6833. +}
  6834. +
  6835. +BcStatus bc_program_addFunc(BcProgram *p, char *name, size_t *idx) {
  6836. +
  6837. +   BcStatus s;
  6838. +   BcId entry, *entry_ptr;
  6839. +   BcFunc f;
  6840. +
  6841. +   entry.name = name;
  6842. +   entry.idx = p->fns.len;
  6843. +
  6844. +   if ((s = bc_map_insert(&p->fn_map, &entry, idx))) {
  6845. +       free(name);
  6846. +       if (s != BC_STATUS_VEC_ITEM_EXISTS) return s;
  6847. +   }
  6848. +
  6849. +   entry_ptr = bc_map_item(&p->fn_map, *idx);
  6850. +   *idx = entry_ptr->idx;
  6851. +
  6852. +   if (s == BC_STATUS_VEC_ITEM_EXISTS) {
  6853. +
  6854. +       BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
  6855. +       s = BC_STATUS_SUCCESS;
  6856. +
  6857. +       // We need to reset these, so the function can be repopulated.
  6858. +       func->nparams = 0;
  6859. +       bc_vec_npop(&func->autos, func->autos.len);
  6860. +       bc_vec_npop(&func->code, func->code.len);
  6861. +       bc_vec_npop(&func->labels, func->labels.len);
  6862. +   }
  6863. +   else {
  6864. +       if ((s = bc_func_init(&f))) return s;
  6865. +       if ((s = bc_vec_push(&p->fns, &f))) bc_func_free(&f);
  6866. +   }
  6867. +
  6868. +   return s;
  6869. +}
  6870. +
  6871. +BcStatus bc_program_reset(BcProgram *p, BcStatus s) {
  6872. +
  6873. +   BcFunc *f;
  6874. +   BcInstPtr *ip;
  6875. +
  6876. +   bc_vec_npop(&p->stack, p->stack.len - 1);
  6877. +   bc_vec_npop(&p->results, p->results.len);
  6878. +
  6879. +   f = bc_vec_item(&p->fns, 0);
  6880. +   ip = bc_vec_top(&p->stack);
  6881. +   ip->idx = f->code.len;
  6882. +
  6883. +   if (!s && bcg.signe && !bcg.tty) return BC_STATUS_QUIT;
  6884. +
  6885. +   bcg.sigc += bcg.signe;
  6886. +   bcg.signe = bcg.sig != bcg.sigc;
  6887. +
  6888. +   if (!s || s == BC_STATUS_EXEC_SIGNAL) {
  6889. +       if (bcg.ttyin) {
  6890. +           if (fputs(bc_program_ready_msg, stderr) < 0 || fflush(stderr) < 0)
  6891. +               s = BC_STATUS_IO_ERR;
  6892. +           else s = BC_STATUS_SUCCESS;
  6893. +       }
  6894. +       else s = BC_STATUS_QUIT;
  6895. +   }
  6896. +
  6897. +   return s;
  6898. +}
  6899. +
  6900. +BcStatus bc_program_exec(BcProgram *p) {
  6901. +
  6902. +   BcStatus s = BC_STATUS_SUCCESS;
  6903. +   size_t idx;
  6904. +   BcResult r;
  6905. +   BcResult *ptr;
  6906. +   BcNum *num;
  6907. +   BcInstPtr *ip = bc_vec_top(&p->stack);
  6908. +   BcFunc *func = bc_vec_item(&p->fns, ip->func);
  6909. +   char *code = func->code.v;
  6910. +   bool cond = false;
  6911. +
  6912. +   while (!s && !bcg.sig_other && ip->idx < func->code.len) {
  6913. +
  6914. +       uint8_t inst = code[(ip->idx)++];
  6915. +
  6916. +       switch (inst) {
  6917. +
  6918. +#ifdef CONFIG_BC
  6919. +           case BC_INST_JUMP_ZERO:
  6920. +           {
  6921. +               if ((s = bc_program_prep(p, &ptr, &num))) return s;
  6922. +               cond = !bc_num_cmp(num, &p->zero);
  6923. +               bc_vec_pop(&p->results);
  6924. +           }
  6925. +           // Fallthrough.
  6926. +           case BC_INST_JUMP:
  6927. +           {
  6928. +               size_t *addr;
  6929. +               idx = bc_program_index(code, &ip->idx);
  6930. +               addr = bc_vec_item(&func->labels, idx);
  6931. +               if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
  6932. +               break;
  6933. +           }
  6934. +
  6935. +           case BC_INST_CALL:
  6936. +           {
  6937. +               s = bc_program_call(p, code, &ip->idx);
  6938. +               break;
  6939. +           }
  6940. +
  6941. +           case BC_INST_INC_PRE:
  6942. +           case BC_INST_DEC_PRE:
  6943. +           case BC_INST_INC_POST:
  6944. +           case BC_INST_DEC_POST:
  6945. +           {
  6946. +               s = bc_program_incdec(p, inst);
  6947. +               break;
  6948. +           }
  6949. +
  6950. +           case BC_INST_HALT:
  6951. +           {
  6952. +               s = BC_STATUS_QUIT;
  6953. +               break;
  6954. +           }
  6955. +
  6956. +           case BC_INST_RET:
  6957. +           case BC_INST_RET0:
  6958. +           {
  6959. +               s = bc_program_return(p, inst);
  6960. +               break;
  6961. +           }
  6962. +
  6963. +           case BC_INST_BOOL_OR:
  6964. +           case BC_INST_BOOL_AND:
  6965. +#endif // CONFIG_BC
  6966. +           case BC_INST_REL_EQ:
  6967. +           case BC_INST_REL_LE:
  6968. +           case BC_INST_REL_GE:
  6969. +           case BC_INST_REL_NE:
  6970. +           case BC_INST_REL_LT:
  6971. +           case BC_INST_REL_GT:
  6972. +           {
  6973. +               s = bc_program_logical(p, inst);
  6974. +               break;
  6975. +           }
  6976. +
  6977. +           case BC_INST_READ:
  6978. +           {
  6979. +               s = bc_program_read(p);
  6980. +               break;
  6981. +           }
  6982. +
  6983. +           case BC_INST_VAR:
  6984. +           {
  6985. +               s = bc_program_pushVar(p, code, &ip->idx, false, false);
  6986. +               break;
  6987. +           }
  6988. +
  6989. +           case BC_INST_ARRAY_ELEM:
  6990. +           case BC_INST_ARRAY:
  6991. +           {
  6992. +               s = bc_program_pushArray(p, code, &ip->idx, inst);
  6993. +               break;
  6994. +           }
  6995. +
  6996. +           case BC_INST_LAST:
  6997. +           {
  6998. +               r.t = BC_RESULT_LAST;
  6999. +               s = bc_vec_push(&p->results, &r);
  7000. +               break;
  7001. +           }
  7002. +
  7003. +           case BC_INST_IBASE:
  7004. +           case BC_INST_SCALE:
  7005. +           case BC_INST_OBASE:
  7006. +           {
  7007. +               s = bc_program_pushGlobal(p, inst);
  7008. +               break;
  7009. +           }
  7010. +
  7011. +           case BC_INST_SCALE_FUNC:
  7012. +           case BC_INST_LENGTH:
  7013. +           case BC_INST_SQRT:
  7014. +           {
  7015. +               s = bc_program_builtin(p, inst);
  7016. +               break;
  7017. +           }
  7018. +
  7019. +           case BC_INST_NUM:
  7020. +           {
  7021. +               r.t = BC_RESULT_CONSTANT;
  7022. +               r.d.id.idx = bc_program_index(code, &ip->idx);
  7023. +               s = bc_vec_push(&p->results, &r);
  7024. +               break;
  7025. +           }
  7026. +
  7027. +           case BC_INST_POP:
  7028. +           {
  7029. +               if (!BC_PROG_STACK(&p->results, 1)) s = BC_STATUS_EXEC_STACK;
  7030. +               else bc_vec_pop(&p->results);
  7031. +               break;
  7032. +           }
  7033. +
  7034. +           case BC_INST_POP_EXEC:
  7035. +           {
  7036. +               bc_vec_pop(&p->stack);
  7037. +               break;
  7038. +           }
  7039. +
  7040. +           case BC_INST_PRINT:
  7041. +           case BC_INST_PRINT_POP:
  7042. +           case BC_INST_PRINT_STR:
  7043. +           {
  7044. +               s = bc_program_print(p, inst, 0);
  7045. +               break;
  7046. +           }
  7047. +
  7048. +           case BC_INST_STR:
  7049. +           {
  7050. +               r.t = BC_RESULT_STR;
  7051. +               r.d.id.idx = bc_program_index(code, &ip->idx);
  7052. +               s = bc_vec_push(&p->results, &r);
  7053. +               break;
  7054. +           }
  7055. +
  7056. +           case BC_INST_POWER:
  7057. +           case BC_INST_MULTIPLY:
  7058. +           case BC_INST_DIVIDE:
  7059. +           case BC_INST_MODULUS:
  7060. +           case BC_INST_PLUS:
  7061. +           case BC_INST_MINUS:
  7062. +           {
  7063. +               s = bc_program_op(p, inst);
  7064. +               break;
  7065. +           }
  7066. +
  7067. +           case BC_INST_BOOL_NOT:
  7068. +           {
  7069. +               if ((s = bc_program_prep(p, &ptr, &num))) return s;
  7070. +               if ((s = bc_num_init(&r.d.n, BC_NUM_DEF_SIZE))) return s;
  7071. +
  7072. +               (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
  7073. +
  7074. +               s = bc_program_retire(p, &r, BC_RESULT_TEMP);
  7075. +               if (s) bc_num_free(&r.d.n);
  7076. +
  7077. +               break;
  7078. +           }
  7079. +
  7080. +           case BC_INST_NEG:
  7081. +           {
  7082. +               s = bc_program_negate(p);
  7083. +               break;
  7084. +           }
  7085. +
  7086. +#ifdef CONFIG_BC
  7087. +           case BC_INST_ASSIGN_POWER:
  7088. +           case BC_INST_ASSIGN_MULTIPLY:
  7089. +           case BC_INST_ASSIGN_DIVIDE:
  7090. +           case BC_INST_ASSIGN_MODULUS:
  7091. +           case BC_INST_ASSIGN_PLUS:
  7092. +           case BC_INST_ASSIGN_MINUS:
  7093. +#endif // CONFIG_BC
  7094. +           case BC_INST_ASSIGN:
  7095. +           {
  7096. +               s = bc_program_assign(p, inst);
  7097. +               break;
  7098. +           }
  7099. +
  7100. +#ifdef CONFIG_DC
  7101. +           case BC_INST_MODEXP:
  7102. +           {
  7103. +               s = bc_program_modexp(p);
  7104. +               break;
  7105. +           }
  7106. +
  7107. +           case BC_INST_DIVMOD:
  7108. +           {
  7109. +               s = bc_program_divmod(p);
  7110. +               break;
  7111. +           }
  7112. +
  7113. +           case BC_INST_EXECUTE:
  7114. +           case BC_INST_EXEC_COND:
  7115. +           {
  7116. +               cond = inst == BC_INST_EXEC_COND;
  7117. +               s = bc_program_execStr(p, code, &ip->idx, cond);
  7118. +               break;
  7119. +           }
  7120. +
  7121. +           case BC_INST_PRINT_STACK:
  7122. +           {
  7123. +               for (idx = 0; !s && idx < p->results.len; ++idx)
  7124. +                   s = bc_program_print(p, BC_INST_PRINT, idx);
  7125. +               break;
  7126. +           }
  7127. +
  7128. +           case BC_INST_CLEAR_STACK:
  7129. +           {
  7130. +               bc_vec_npop(&p->results, p->results.len);
  7131. +               break;
  7132. +           }
  7133. +
  7134. +           case BC_INST_STACK_LEN:
  7135. +           {
  7136. +               s = bc_program_stackLen(p);
  7137. +               break;
  7138. +           }
  7139. +
  7140. +           case BC_INST_DUPLICATE:
  7141. +           {
  7142. +               if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
  7143. +               ptr = bc_vec_top(&p->results);
  7144. +               if ((s = bc_result_copy(&r, ptr))) return s;
  7145. +               s = bc_vec_push(&p->results, &r);
  7146. +               break;
  7147. +           }
  7148. +
  7149. +           case BC_INST_SWAP:
  7150. +           {
  7151. +               BcResult *ptr2;
  7152. +
  7153. +               if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
  7154. +
  7155. +               ptr = bc_vec_item_rev(&p->results, 0);
  7156. +               ptr2 = bc_vec_item_rev(&p->results, 1);
  7157. +               memcpy(&r, ptr, sizeof(BcResult));
  7158. +               memcpy(ptr, ptr2, sizeof(BcResult));
  7159. +               memcpy(ptr2, &r, sizeof(BcResult));
  7160. +
  7161. +               break;
  7162. +           }
  7163. +
  7164. +           case BC_INST_ASCIIFY:
  7165. +           {
  7166. +               s = bc_program_asciify(p);
  7167. +               break;
  7168. +           }
  7169. +
  7170. +           case BC_INST_PRINT_STREAM:
  7171. +           {
  7172. +               s = bc_program_printStream(p);
  7173. +               break;
  7174. +           }
  7175. +
  7176. +           case BC_INST_LOAD:
  7177. +           case BC_INST_PUSH_VAR:
  7178. +           {
  7179. +               bool copy = inst == BC_INST_LOAD;
  7180. +               s = bc_program_pushVar(p, code, &ip->idx, true, copy);
  7181. +               break;
  7182. +           }
  7183. +
  7184. +           case BC_INST_PUSH_TO_VAR:
  7185. +           {
  7186. +               char *name;
  7187. +               if (!(name = bc_program_name(code, &ip->idx))) return s;
  7188. +               s = bc_program_copyToVar(p, name, true);
  7189. +               free(name);
  7190. +               break;
  7191. +           }
  7192. +
  7193. +           case BC_INST_QUIT:
  7194. +           {
  7195. +               if (p->stack.len <= 2) s = BC_STATUS_QUIT;
  7196. +               else bc_vec_npop(&p->stack, 2);
  7197. +               break;
  7198. +           }
  7199. +
  7200. +           case BC_INST_NQUIT:
  7201. +           {
  7202. +               s = bc_program_nquit(p);
  7203. +               break;
  7204. +           }
  7205. +#endif // CONFIG_DC
  7206. +       }
  7207. +
  7208. +       if ((s && s != BC_STATUS_QUIT) || bcg.signe) s = bc_program_reset(p, s);
  7209. +
  7210. +       // If the stack has changed, pointers may be invalid.
  7211. +       ip = bc_vec_top(&p->stack);
  7212. +       func = bc_vec_item(&p->fns, ip->func);
  7213. +       code = func->code.v;
  7214. +   }
  7215. +
  7216. +   return s;
  7217. +}
  7218. +
  7219. +static void bc_vm_sig(int sig) {
  7220. +   if (sig == SIGINT) {
  7221. +       size_t len = strlen(bcg.sig_msg);
  7222. +       if (write(2, bcg.sig_msg, len) == (ssize_t) len)
  7223. +           bcg.sig += (bcg.signe = bcg.sig == bcg.sigc);
  7224. +   }
  7225. +   else bcg.sig_other = 1;
  7226. +}
  7227. +
  7228. +BcStatus bc_vm_info(const char* const help) {
  7229. +   if (printf("%s %s\n", bcg.name, BC_VERSION) < 0) return BC_STATUS_IO_ERR;
  7230. +   if (puts(bc_copyright) == EOF) return BC_STATUS_IO_ERR;
  7231. +   if (help && printf(help, bcg.name) < 0) return BC_STATUS_IO_ERR;
  7232. +   return BC_STATUS_SUCCESS;
  7233. +}
  7234. +
  7235. +static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line) {
  7236. +
  7237. +   if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
  7238. +
  7239. +   if (fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]) < 0)
  7240. +       return BC_STATUS_IO_ERR;
  7241. +   if (fprintf(stderr, "    %s", file) < 0) return BC_STATUS_IO_ERR;
  7242. +   if (fprintf(stderr, bc_err_line + 4 * !line, line) < 0)
  7243. +       return BC_STATUS_IO_ERR;
  7244. +
  7245. +   return s * (!bcg.ttyin || !!strcmp(file, bc_program_stdin_name));
  7246. +}
  7247. +
  7248. +#ifdef CONFIG_BC
  7249. +BcStatus bc_vm_posixError(BcStatus s, const char *file,
  7250. +                           size_t line, const char *msg)
  7251. +{
  7252. +   int p = (int) bcg.posix, w = (int) bcg.warn;
  7253. +   const char* const fmt = p ? bc_err_fmt : bc_warn_fmt;
  7254. +
  7255. +   if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
  7256. +
  7257. +   if (fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]) < 0)
  7258. +       return BC_STATUS_IO_ERR;
  7259. +   if (msg && fprintf(stderr, "    %s\n", msg) < 0) return BC_STATUS_IO_ERR;
  7260. +   if (fprintf(stderr, "    %s", file) < 0) return BC_STATUS_IO_ERR;
  7261. +   if (fprintf(stderr, bc_err_line + 4 * !line, line) < 0)
  7262. +       return BC_STATUS_IO_ERR;
  7263. +
  7264. +   return s * (!bcg.ttyin && !!p);
  7265. +}
  7266. +
  7267. +static BcStatus bc_vm_envArgs(BcVm *vm) {
  7268. +
  7269. +   BcStatus s;
  7270. +   BcVec args;
  7271. +   char *env_args = NULL, *buf;
  7272. +
  7273. +   if (!(env_args = getenv(bc_args_env_name))) return BC_STATUS_SUCCESS;
  7274. +   if (!(buf = (vm->env_args = strdup(env_args)))) return BC_STATUS_ALLOC_ERR;
  7275. +
  7276. +   if ((s = bc_vec_init(&args, sizeof(char*), NULL))) goto err;
  7277. +   if ((s = bc_vec_push(&args, &bc_args_env_name))) goto err;
  7278. +
  7279. +   while (*buf) {
  7280. +       if (!isspace(*buf)) {
  7281. +           if ((s = bc_vec_push(&args, &buf))) goto err;
  7282. +           while (*buf && !isspace(*buf)) ++buf;
  7283. +           if (*buf) (*(buf++)) = '\0';
  7284. +       }
  7285. +       else ++buf;
  7286. +   }
  7287. +
  7288. +   s = bc_args((int) args.len, (char**) args.v,
  7289. +               &vm->flags, &vm->exprs, &vm->files);
  7290. +
  7291. +err:
  7292. +   bc_vec_free(&args);
  7293. +   return s;
  7294. +}
  7295. +#endif // CONFIG_BC
  7296. +
  7297. +static size_t bc_vm_envLen(const char *var) {
  7298. +
  7299. +   char *lenv;
  7300. +   size_t i, len = BC_NUM_PRINT_WIDTH;
  7301. +   int num;
  7302. +
  7303. +   if ((lenv = getenv(var))) {
  7304. +       len = strlen(lenv);
  7305. +       for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
  7306. +       if (!num || (len = (size_t) atoi(lenv) - 1) < 2 || len >= INT32_MAX)
  7307. +           len = BC_NUM_PRINT_WIDTH;
  7308. +   }
  7309. +
  7310. +   return len;
  7311. +}
  7312. +
  7313. +static BcStatus bc_vm_process(BcVm *vm, const char *text) {
  7314. +
  7315. +   BcStatus s = bc_parse_text(&vm->prs, text);
  7316. +
  7317. +   if ((s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line))) return s;
  7318. +
  7319. +   while (vm->prs.l.t.t != BC_LEX_EOF) {
  7320. +
  7321. +       if ((s = vm->prs.parse(&vm->prs)) == BC_STATUS_LIMITS) {
  7322. +
  7323. +           s = BC_STATUS_IO_ERR;
  7324. +
  7325. +           if (putchar('\n') == EOF) return s;
  7326. +           if (printf("BC_BASE_MAX     = %lu\n", BC_MAX_OBASE) < 0) return s;
  7327. +           if (printf("BC_DIM_MAX      = %lu\n", BC_MAX_DIM) < 0) return s;
  7328. +           if (printf("BC_SCALE_MAX    = %lu\n", BC_MAX_SCALE) < 0) return s;
  7329. +           if (printf("BC_STRING_MAX   = %lu\n", BC_MAX_STRING) < 0) return s;
  7330. +           if (printf("BC_NAME_MAX     = %lu\n", BC_MAX_NAME) < 0) return s;
  7331. +           if (printf("BC_NUM_MAX      = %lu\n", BC_MAX_NUM) < 0) return s;
  7332. +           if (printf("Max Exponent    = %lu\n", BC_MAX_EXP) < 0) return s;
  7333. +           if (printf("Number of Vars  = %lu\n", BC_MAX_VARS) < 0) return s;
  7334. +           if (putchar('\n') == EOF) return s;
  7335. +
  7336. +           s = BC_STATUS_SUCCESS;
  7337. +       }
  7338. +       else if (s == BC_STATUS_QUIT || bcg.sig_other ||
  7339. +                (s = bc_vm_error(s, vm->prs.l.f, vm->prs.l.line)))
  7340. +       {
  7341. +           return s;
  7342. +       }
  7343. +   }
  7344. +
  7345. +   if (BC_PARSE_CAN_EXEC(&vm->prs)) {
  7346. +       s = bc_program_exec(&vm->prog);
  7347. +       if (!s && bcg.tty && fflush(stdout) == EOF) s = BC_STATUS_IO_ERR;
  7348. +       if (s && s != BC_STATUS_QUIT)
  7349. +           s = bc_vm_error(bc_program_reset(&vm->prog, s), vm->prs.l.f, 0);
  7350. +   }
  7351. +
  7352. +   return s;
  7353. +}
  7354. +
  7355. +static BcStatus bc_vm_file(BcVm *vm, const char *file) {
  7356. +
  7357. +   BcStatus s;
  7358. +   char *data;
  7359. +   BcFunc *main_func;
  7360. +   BcInstPtr *ip;
  7361. +
  7362. +   vm->prog.file = file;
  7363. +   if ((s = bc_read_file(file, &data))) return bc_vm_error(s, file, 0);
  7364. +
  7365. +   bc_lex_file(&vm->prs.l, file);
  7366. +   if ((s = bc_vm_process(vm, data))) goto err;
  7367. +
  7368. +   main_func = bc_vec_item(&vm->prog.fns, BC_PROG_MAIN);
  7369. +   ip = bc_vec_item(&vm->prog.stack, 0);
  7370. +
  7371. +   if (main_func->code.len < ip->idx)
  7372. +       s = bc_vm_error(BC_STATUS_EXEC_FILE_NOT_EXECUTABLE, file, 0);
  7373. +
  7374. +err:
  7375. +   free(data);
  7376. +   return s;
  7377. +}
  7378. +
  7379. +static BcStatus bc_vm_stdin(BcVm *vm) {
  7380. +
  7381. +   BcStatus s;
  7382. +   BcVec buf, buffer;
  7383. +   char c;
  7384. +   size_t len, i, str = 0;
  7385. +   bool comment = false, notend;
  7386. +
  7387. +   vm->prog.file = bc_program_stdin_name;
  7388. +   bc_lex_file(&vm->prs.l, bc_program_stdin_name);
  7389. +
  7390. +   if ((s = bc_vec_init(&buffer, sizeof(char), NULL))) return s;
  7391. +   if ((s = bc_vec_init(&buf, sizeof(char), NULL))) goto buf_err;
  7392. +   if ((s = bc_vec_pushByte(&buffer, '\0'))) goto err;
  7393. +
  7394. +   // This loop is complex because the vm tries not to send any lines that end
  7395. +   // with a backslash to the parser. The reason for that is because the parser
  7396. +   // treats a backslash+newline combo as whitespace, per the bc spec. In that
  7397. +   // case, and for strings and comments, the parser will expect more stuff.
  7398. +   while (!s && !(s = bc_read_line(&buf, ">>> "))) {
  7399. +
  7400. +       char *string = buf.v;
  7401. +
  7402. +       if ((len = buf.len - 1) == 1) {
  7403. +           if (str && buf.v[0] == vm->exe.send) str -= 1;
  7404. +           else if (buf.v[0] == vm->exe.sbgn) str += 1;
  7405. +       }
  7406. +       else if (len > 1 || comment) {
  7407. +
  7408. +           for (i = 0; i < len; ++i) {
  7409. +
  7410. +               notend = len > i + 1;
  7411. +               c = string[i];
  7412. +
  7413. +               if (i - 1 > len || string[i - 1] != '\\') {
  7414. +                   if (vm->exe.sbgn == vm->exe.send) str ^= c == vm->exe.sbgn;
  7415. +                   else if (c == vm->exe.send) str -= 1;
  7416. +                   else if (c == vm->exe.sbgn) str += 1;
  7417. +               }
  7418. +
  7419. +               if (c == '/' && notend && !comment && string[i + 1] == '*') {
  7420. +                   comment = true;
  7421. +                   break;
  7422. +               }
  7423. +               else if (c == '*' && notend && comment && string[i + 1] == '/')
  7424. +                   comment = false;
  7425. +           }
  7426. +
  7427. +           if (str || comment || string[len - 2] == '\\') {
  7428. +               if ((s = bc_vec_concat(&buffer, buf.v))) goto err;
  7429. +               continue;
  7430. +           }
  7431. +       }
  7432. +
  7433. +       if ((s = bc_vec_concat(&buffer, buf.v))) goto err;
  7434. +       if ((s = bc_vm_process(vm, buffer.v))) goto err;
  7435. +
  7436. +       bc_vec_npop(&buffer, buffer.len);
  7437. +   }
  7438. +
  7439. +   if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, vm->prs.l.f, 0);
  7440. +
  7441. +   // I/O error will always happen when stdin is
  7442. +   // closed. It's not a problem in that case.
  7443. +   s = s == BC_STATUS_IO_ERR || s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
  7444. +
  7445. +   if (str) s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END,
  7446. +                            vm->prs.l.f, vm->prs.l.line);
  7447. +   else if (comment) s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END,
  7448. +                                     vm->prs.l.f, vm->prs.l.line);
  7449. +
  7450. +err:
  7451. +   bc_vec_free(&buf);
  7452. +buf_err:
  7453. +   bc_vec_free(&buffer);
  7454. +   return s;
  7455. +}
  7456. +
  7457. +static BcStatus bc_vm_exec(BcVm *vm) {
  7458. +
  7459. +   BcStatus s = BC_STATUS_SUCCESS;
  7460. +   size_t i;
  7461. +
  7462. +#ifdef CONFIG_BC
  7463. +   if (vm->flags & BC_FLAG_L) {
  7464. +
  7465. +       bc_lex_file(&vm->prs.l, bc_lib_name);
  7466. +       if ((s = bc_parse_text(&vm->prs, bc_lib))) return s;
  7467. +
  7468. +       while (!s && vm->prs.l.t.t != BC_LEX_EOF) s = vm->prs.parse(&vm->prs);
  7469. +
  7470. +       if (s || (s = bc_program_exec(&vm->prog))) return s;
  7471. +   }
  7472. +#endif // CONFIG_BC
  7473. +
  7474. +   if (vm->exprs.len) {
  7475. +       bc_lex_file(&vm->prs.l, bc_program_exprs_name);
  7476. +       if ((s = bc_vm_process(vm, vm->exprs.v))) return s;
  7477. +   }
  7478. +
  7479. +   for (i = 0; !bcg.sig_other && !s && i < vm->files.len; ++i)
  7480. +       s = bc_vm_file(vm, *((char**) bc_vec_item(&vm->files, i)));
  7481. +   if ((s && s != BC_STATUS_QUIT) || bcg.sig_other) return s;
  7482. +
  7483. +   if ((bcg.bc || !vm->files.len) && !vm->exprs.len) s = bc_vm_stdin(vm);
  7484. +   if (!s && !bcg.sig_other && !BC_PARSE_CAN_EXEC(&vm->prs))
  7485. +       s = bc_vm_process(vm, "");
  7486. +
  7487. +   return s == BC_STATUS_QUIT ? BC_STATUS_SUCCESS : s;
  7488. +}
  7489. +
  7490. +static void bc_vm_free(BcVm *vm) {
  7491. +   bc_vec_free(&vm->files);
  7492. +   bc_vec_free(&vm->exprs);
  7493. +   bc_program_free(&vm->prog);
  7494. +   bc_parse_free(&vm->prs);
  7495. +   free(vm->env_args);
  7496. +}
  7497. +
  7498. +static BcStatus bc_vm_init(BcVm *vm, BcVmExe exe, const char *env_len) {
  7499. +
  7500. +   BcStatus s;
  7501. +   size_t len = bc_vm_envLen(env_len);
  7502. +   struct sigaction sa;
  7503. +
  7504. +   sigemptyset(&sa.sa_mask);
  7505. +   sa.sa_handler = bc_vm_sig;
  7506. +   sa.sa_flags = 0;
  7507. +
  7508. +   if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGPIPE, &sa, NULL) < 0 ||
  7509. +       sigaction(SIGHUP, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0)
  7510. +   {
  7511. +       return BC_STATUS_EXEC_SIGACTION_FAIL;
  7512. +   }
  7513. +
  7514. +   memset(vm, 0, sizeof(BcVm));
  7515. +
  7516. +   vm->exe = exe;
  7517. +   vm->flags = 0;
  7518. +   vm->env_args = NULL;
  7519. +
  7520. +   if ((s = bc_vec_init(&vm->files, sizeof(char*), NULL))) return s;
  7521. +   if ((s = bc_vec_init(&vm->exprs, sizeof(char), NULL))) goto err;
  7522. +
  7523. +#ifdef CONFIG_BC
  7524. +   vm->flags |= BC_FLAG_S * bcg.bc * (getenv("POSIXLY_CORRECT") != NULL);
  7525. +   if (bcg.bc && (s = bc_vm_envArgs(vm))) goto err;
  7526. +#endif // CONFIG_BC
  7527. +
  7528. +   if ((s = bc_program_init(&vm->prog, len, exe.init, exe.exp))) goto err;
  7529. +   if ((s = exe.init(&vm->prs, &vm->prog, BC_PROG_MAIN))) goto err;
  7530. +
  7531. +   return s;
  7532. +
  7533. +err:
  7534. +   bc_vm_free(vm);
  7535. +   return s;
  7536. +}
  7537. +
  7538. +BcStatus bc_vm_run(int argc, char *argv[], BcVmExe exe, const char *env_len) {
  7539. +
  7540. +   BcStatus st;
  7541. +   BcVm vm;
  7542. +
  7543. +   if ((st = bc_vm_init(&vm, exe, env_len))) return st;
  7544. +   if ((st = bc_args(argc, argv, &vm.flags, &vm.exprs, &vm.files))) goto err;
  7545. +
  7546. +   bcg.tty = (bcg.ttyin = isatty(0)) || (vm.flags & BC_FLAG_I) || isatty(1);
  7547. +
  7548. +#ifdef CONFIG_BC
  7549. +   bcg.posix = vm.flags & BC_FLAG_S;
  7550. +   bcg.warn = vm.flags & BC_FLAG_W;
  7551. +#endif // CONFIG_BC
  7552. +#ifdef CONFIG_DC
  7553. +   bcg.exreg = vm.flags & BC_FLAG_X;
  7554. +#endif // CONFIG_DC
  7555. +
  7556. +   if (bcg.ttyin && !(vm.flags & BC_FLAG_Q)) st = bc_vm_info(NULL);
  7557. +   if (!st) st = bc_vm_exec(&vm);
  7558. +
  7559. +err:
  7560. +   bc_vm_free(&vm);
  7561. +   return st;
  7562. +}
  7563. +
  7564. +#ifdef CONFIG_BC
  7565. +BcStatus bc_main(int argc, char *argv[]) {
  7566. +
  7567. +   BcVmExe exec;
  7568. +
  7569. +   bcg.bc = true;
  7570. +   bcg.name = bc_name;
  7571. +   bcg.sig_msg = bc_sig_msg;
  7572. +
  7573. +   exec.init = bc_parse_init;
  7574. +   exec.exp = bc_parse_expression;
  7575. +   exec.sbgn = exec.send = '"';
  7576. +
  7577. +   return bc_vm_run(argc, argv, exec, "BC_LINE_LENGTH");
  7578. +}
  7579. +#endif // CONFIG_BC
  7580. +
  7581. +#ifdef CONFIG_DC
  7582. +BcStatus dc_main(int argc, char *argv[]) {
  7583. +
  7584. +   BcVmExe exec;
  7585. +
  7586. +   bcg.bc = false;
  7587. +   bcg.name = dc_name;
  7588. +   bcg.sig_msg = dc_sig_msg;
  7589. +
  7590. +   exec.init = dc_parse_init;
  7591. +   exec.exp = dc_parse_expr;
  7592. +   exec.sbgn = '[';
  7593. +   exec.send = ']';
  7594. +
  7595. +   return bc_vm_run(argc, argv, exec, "DC_LINE_LENGTH");
  7596. +}
  7597. +#endif // CONFIG_DC
  7598. --
  7599. 2.17.1
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement