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