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