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