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