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