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