blob: 7e72ab28f36cb1c267582aaa417d66aafde2b3b9 [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);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100302static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600303
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) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100602 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600603
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
Gavin Howard01055ba2018-11-03 11:00:21 -0600665typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600666
667typedef struct BcParse {
668
669 BcParseParse parse;
670
671 BcLex l;
672
673 BcVec flags;
674
675 BcVec exits;
676 BcVec conds;
677
678 BcVec ops;
679
Gavin Howard01055ba2018-11-03 11:00:21 -0600680 BcFunc *func;
681 size_t fidx;
682
683 size_t nbraces;
684 bool auto_part;
685
686} BcParse;
687
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100688#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600689
Gavin Howard01055ba2018-11-03 11:00:21 -0600690typedef struct BcLexKeyword {
691 const char name[9];
692 const char len;
693 const bool posix;
694} BcLexKeyword;
695
696#define BC_LEX_KW_ENTRY(a, b, c) \
697 { \
698 .name = a, .len = (b), .posix = (c) \
699 }
700
701static BcStatus bc_lex_token(BcLex *l);
702
703#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
704#define BC_PARSE_LEAF(p, rparen) \
705 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
706 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
707
708// We can calculate the conversion between tokens and exprs by subtracting the
709// position of the first operator in the lex enum and adding the position of the
710// first in the expr enum. Note: This only works for binary operators.
711#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
712
713static BcStatus bc_parse_parse(BcParse *p);
714static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
715
Denys Vlasenko00d77792018-11-30 23:13:42 +0100716#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600717
Denys Vlasenko00d77792018-11-30 23:13:42 +0100718#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600719
720#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
721
Gavin Howard01055ba2018-11-03 11:00:21 -0600722static BcStatus dc_lex_token(BcLex *l);
723
Gavin Howard01055ba2018-11-03 11:00:21 -0600724static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
725
726#endif // ENABLE_DC
727
728typedef struct BcProgram {
729
730 size_t len;
731 size_t scale;
732
733 BcNum ib;
734 size_t ib_t;
735 BcNum ob;
736 size_t ob_t;
737
738 BcNum hexb;
739
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100740#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600741 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100742#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600743
744 BcVec results;
745 BcVec stack;
746
747 BcVec fns;
748 BcVec fn_map;
749
750 BcVec vars;
751 BcVec var_map;
752
753 BcVec arrs;
754 BcVec arr_map;
755
756 BcVec strs;
757 BcVec consts;
758
759 const char *file;
760
761 BcNum last;
762 BcNum zero;
763 BcNum one;
764
765 size_t nchars;
766
Gavin Howard01055ba2018-11-03 11:00:21 -0600767} BcProgram;
768
769#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
770
771#define BC_PROG_MAIN (0)
772#define BC_PROG_READ (1)
773
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100774#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600775#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100776#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600777
778#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
779#define BC_PROG_NUM(r, n) \
780 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
781
782typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
783
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100784static void bc_program_addFunc(char *name, size_t *idx);
785static BcStatus bc_program_reset(BcStatus s);
Gavin Howard01055ba2018-11-03 11:00:21 -0600786
787#define BC_FLAG_X (1 << 0)
788#define BC_FLAG_W (1 << 1)
789#define BC_FLAG_V (1 << 2)
790#define BC_FLAG_S (1 << 3)
791#define BC_FLAG_Q (1 << 4)
792#define BC_FLAG_L (1 << 5)
793#define BC_FLAG_I (1 << 6)
794
795#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
796#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
797
798#define BC_MAX_OBASE ((unsigned long) 999)
799#define BC_MAX_DIM ((unsigned long) INT_MAX)
800#define BC_MAX_SCALE ((unsigned long) UINT_MAX)
801#define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
802#define BC_MAX_NAME BC_MAX_STRING
803#define BC_MAX_NUM BC_MAX_STRING
804#define BC_MAX_EXP ((unsigned long) LONG_MAX)
805#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
806
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100807struct globals {
Gavin Howard01055ba2018-11-03 11:00:21 -0600808 char sbgn;
809 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600810
811 BcParse prs;
812 BcProgram prog;
813
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100814 unsigned flags;
Gavin Howard01055ba2018-11-03 11:00:21 -0600815 BcVec files;
816
817 char *env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -0600818
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100819 smallint tty;
820 smallint ttyin;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100821} FIX_ALIASING;
822#define G (*ptr_to_globals)
823#define INIT_G() do { \
824 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
825} while (0)
826#define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
827#define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
828#define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100829#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600830
Gavin Howard01055ba2018-11-03 11:00:21 -0600831
Denys Vlasenko00d77792018-11-30 23:13:42 +0100832#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
833
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100834#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600835static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
836 const char *msg);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100837#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600838
Denys Vlasenko00d77792018-11-30 23:13:42 +0100839static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600840
Gavin Howard01055ba2018-11-03 11:00:21 -0600841static const char* const bc_args_env_name = "BC_ENV_ARGS";
842
843static const char bc_err_fmt[] = "\n%s error: %s\n";
844static const char bc_warn_fmt[] = "\n%s warning: %s\n";
845static const char bc_err_line[] = ":%zu\n\n";
846
847static const char *bc_errs[] = {
848 "VM",
849 "Lex",
850 "Parse",
851 "Math",
852 "Runtime",
853 "Vector",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100854#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600855 "POSIX",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100856#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600857};
858
859static const uint8_t bc_err_ids[] = {
860 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
861 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100862#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600863 BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100864#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600865 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
866 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
867 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
868 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100869#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600870 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100871#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600872 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
873 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
874 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
875 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
876 BC_ERR_IDX_EXEC,
877 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100878#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600879 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
880 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
881 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100882#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600883 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
884};
885
886static const char *bc_err_msgs[] = {
887
888 NULL,
889 "memory allocation error",
890 "I/O error",
891 "file is not text:",
892 "path is a directory:",
893
894 "bad character",
895 "string end could not be found",
896 "comment end could not be found",
897 "end of file",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100898#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600899 "extended register",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100900#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600901
902 "bad token",
903 "bad expression",
904 "empty expression",
905 "bad print statement",
906 "bad function definition",
907 "bad assignment: left side must be scale, ibase, "
908 "obase, last, var, or array element",
909 "no auto variable found",
910 "function parameter or auto var has the same name as another",
911 "block end could not be found",
912
913 "negative number",
914 "non integer number",
915 "overflow",
916 "divide by zero",
917 "bad number string",
918
919 "could not open file:",
920 "mismatched parameters",
921 "undefined function",
922 "file is not executable:",
923 "number too long: must be [1, BC_NUM_MAX]",
924 "name too long: must be [1, BC_NAME_MAX]",
925 "string too long: must be [1, BC_STRING_MAX]",
926 "array too long; must be [1, BC_DIM_MAX]",
927 "bad ibase; must be [2, 16]",
928 "bad scale; must be [0, BC_SCALE_MAX]",
929 "bad read() expression",
930 "read() call inside of a read() call",
931 "variable is wrong type",
932 "bad obase; must be [2, BC_BASE_MAX]",
933 "signal caught and not handled",
934 "stack has too few elements",
935
936 "index is out of bounds",
937 "item already exists",
938
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100939#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600940 "POSIX only allows one character names; the following is bad:",
941 "POSIX does not allow '#' script comments",
942 "POSIX does not allow the following keyword:",
943 "POSIX does not allow a period ('.') as a shortcut for the last result",
944 "POSIX requires parentheses around return expressions",
945 "POSIX does not allow boolean operators; the following is bad:",
946 "POSIX does not allow comparison operators outside if or loops",
947 "POSIX requires exactly one comparison operator per condition",
948 "POSIX does not allow an empty init expression in a for loop",
949 "POSIX does not allow an empty condition expression in a for loop",
950 "POSIX does not allow an empty update expression in a for loop",
951 "POSIX requires the left brace be on the same line as the function header",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100952#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600953
954};
955
956static const char bc_func_main[] = "(main)";
957static const char bc_func_read[] = "(read)";
958
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100959#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600960static const BcLexKeyword bc_lex_kws[20] = {
961 BC_LEX_KW_ENTRY("auto", 4, true),
962 BC_LEX_KW_ENTRY("break", 5, true),
963 BC_LEX_KW_ENTRY("continue", 8, false),
964 BC_LEX_KW_ENTRY("define", 6, true),
965 BC_LEX_KW_ENTRY("else", 4, false),
966 BC_LEX_KW_ENTRY("for", 3, true),
967 BC_LEX_KW_ENTRY("halt", 4, false),
968 BC_LEX_KW_ENTRY("ibase", 5, true),
969 BC_LEX_KW_ENTRY("if", 2, true),
970 BC_LEX_KW_ENTRY("last", 4, false),
971 BC_LEX_KW_ENTRY("length", 6, true),
972 BC_LEX_KW_ENTRY("limits", 6, false),
973 BC_LEX_KW_ENTRY("obase", 5, true),
974 BC_LEX_KW_ENTRY("print", 5, false),
975 BC_LEX_KW_ENTRY("quit", 4, true),
976 BC_LEX_KW_ENTRY("read", 4, false),
977 BC_LEX_KW_ENTRY("return", 6, true),
978 BC_LEX_KW_ENTRY("scale", 5, true),
979 BC_LEX_KW_ENTRY("sqrt", 4, true),
980 BC_LEX_KW_ENTRY("while", 5, true),
981};
982
983// This is an array that corresponds to token types. An entry is
984// true if the token is valid in an expression, false otherwise.
985static const bool bc_parse_exprs[] = {
986 false, false, true, true, true, true, true, true, true, true, true, true,
987 true, true, true, true, true, true, true, true, true, true, true, true,
988 true, true, true, false, false, true, true, false, false, false, false,
989 false, false, false, true, true, false, false, false, false, false, false,
990 false, true, false, true, true, true, true, false, false, true, false, true,
991 true, false,
992};
993
994// This is an array of data for operators that correspond to token types.
995static const BcOp bc_parse_ops[] = {
996 { 0, false }, { 0, false },
997 { 1, false },
998 { 2, false },
999 { 3, true }, { 3, true }, { 3, true },
1000 { 4, true }, { 4, true },
1001 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1002 { 1, false },
1003 { 7, true }, { 7, true },
1004 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1005 { 5, false }, { 5, false },
1006};
1007
1008// These identify what tokens can come after expressions in certain cases.
1009static const BcParseNext bc_parse_next_expr =
1010 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1011static const BcParseNext bc_parse_next_param =
1012 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1013static const BcParseNext bc_parse_next_print =
1014 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1015static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1016static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1017static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1018static const BcParseNext bc_parse_next_read =
1019 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1020#endif // ENABLE_BC
1021
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001022#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06001023static const BcLexType dc_lex_regs[] = {
1024 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1025 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1026 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1027 BC_LEX_STORE_PUSH,
1028};
1029
1030static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1031
1032static const BcLexType dc_lex_tokens[] = {
1033 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1034 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1035 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1036 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1037 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1038 BC_LEX_INVALID, BC_LEX_INVALID,
1039 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1040 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1041 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1042 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1043 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1044 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1045 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1046 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1047 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1048 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1049 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1050 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1051 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1052 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1053 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1054 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1055 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1056 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1057 BC_LEX_INVALID
1058};
1059
1060static const BcInst dc_parse_insts[] = {
1061 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1062 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1063 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1064 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1065 BC_INST_INVALID, BC_INST_INVALID,
1066 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1067 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1069 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1070 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1071 BC_INST_INVALID, BC_INST_INVALID,
1072 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1075 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1076 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1078 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1080 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1081 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1084};
1085#endif // ENABLE_DC
1086
Gavin Howard01055ba2018-11-03 11:00:21 -06001087static const BcNumBinaryOp bc_program_ops[] = {
1088 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1089};
1090
1091static const char bc_program_stdin_name[] = "<stdin>";
1092static const char bc_program_ready_msg[] = "ready for more input\n";
1093
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001094#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001095static const char *bc_lib_name = "gen/lib.bc";
1096
1097static const char bc_lib[] = {
1098 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1099 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1100 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1101 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,
1102 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1103 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1104 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,
1105 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1106 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1107 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,
1108 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1109 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1110 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1111 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1112 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1113 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1114 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1115 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1116 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1117 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1118 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1119 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1120 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1121 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,
1122 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1123 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,
1124 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1125 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1126 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1127 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1128 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1129 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,
1130 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1131 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1132 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1133 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1134 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,
1135 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1136 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1137 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1138 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1139 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1140 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1141 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1142 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1143 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1144 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1145 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,
1146 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,
1147 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1148 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,
1149 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,
1150 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,
1151 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1152 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1153 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,
1154 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,
1155 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,
1156 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1157 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,
1158 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1159 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1160 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1161 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,
1162 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1163 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1164 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1165 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1166 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1167 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1168 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1169 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1170 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1171 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1172 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1173 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1174 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1175 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1176 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1177 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1178};
1179#endif // ENABLE_BC
1180
1181static void bc_vec_grow(BcVec *v, size_t n)
1182{
1183 size_t cap = v->cap * 2;
1184 while (cap < v->len + n) cap *= 2;
1185 v->v = xrealloc(v->v, v->size * cap);
1186 v->cap = cap;
1187}
1188
1189static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1190{
1191 v->size = esize;
1192 v->cap = BC_VEC_START_CAP;
1193 v->len = 0;
1194 v->dtor = dtor;
1195 v->v = xmalloc(esize * BC_VEC_START_CAP);
1196}
1197
1198static void bc_vec_expand(BcVec *v, size_t req)
1199{
1200 if (v->cap < req) {
1201 v->v = xrealloc(v->v, v->size * req);
1202 v->cap = req;
1203 }
1204}
1205
1206static void bc_vec_npop(BcVec *v, size_t n)
1207{
1208 if (!v->dtor)
1209 v->len -= n;
1210 else {
1211 size_t len = v->len - n;
1212 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1213 }
1214}
1215
1216static void bc_vec_push(BcVec *v, const void *data)
1217{
1218 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1219 memmove(v->v + (v->size * v->len), data, v->size);
1220 v->len += 1;
1221}
1222
1223static void bc_vec_pushByte(BcVec *v, char data)
1224{
1225 bc_vec_push(v, &data);
1226}
1227
1228static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1229{
1230 if (idx == v->len)
1231 bc_vec_push(v, data);
1232 else {
1233
1234 char *ptr;
1235
1236 if (v->len == v->cap) bc_vec_grow(v, 1);
1237
1238 ptr = v->v + v->size * idx;
1239
1240 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1241 memmove(ptr, data, v->size);
1242 }
1243}
1244
1245static void bc_vec_string(BcVec *v, size_t len, const char *str)
1246{
1247 bc_vec_npop(v, v->len);
1248 bc_vec_expand(v, len + 1);
1249 memcpy(v->v, str, len);
1250 v->len = len;
1251
1252 bc_vec_pushByte(v, '\0');
1253}
1254
1255static void bc_vec_concat(BcVec *v, const char *str)
1256{
1257 size_t len;
1258
1259 if (v->len == 0) bc_vec_pushByte(v, '\0');
1260
1261 len = v->len + strlen(str);
1262
1263 if (v->cap < len) bc_vec_grow(v, len - v->len);
1264 strcat(v->v, str);
1265
1266 v->len = len;
1267}
1268
1269static void *bc_vec_item(const BcVec *v, size_t idx)
1270{
1271 return v->v + v->size * idx;
1272}
1273
1274static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1275{
1276 return v->v + v->size * (v->len - idx - 1);
1277}
1278
1279static void bc_vec_free(void *vec)
1280{
1281 BcVec *v = (BcVec *) vec;
1282 bc_vec_npop(v, v->len);
1283 free(v->v);
1284}
1285
1286static size_t bc_map_find(const BcVec *v, const void *ptr)
1287{
1288 size_t low = 0, high = v->len;
1289
1290 while (low < high) {
1291
1292 size_t mid = (low + high) / 2;
1293 BcId *id = bc_vec_item(v, mid);
1294 int result = bc_id_cmp(ptr, id);
1295
1296 if (result == 0)
1297 return mid;
1298 else if (result < 0)
1299 high = mid;
1300 else
1301 low = mid + 1;
1302 }
1303
1304 return low;
1305}
1306
1307static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1308{
1309 BcStatus s = BC_STATUS_SUCCESS;
1310
1311 *i = bc_map_find(v, ptr);
1312
1313 if (*i == v->len)
1314 bc_vec_push(v, ptr);
1315 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1316 s = BC_STATUS_VEC_ITEM_EXISTS;
1317 else
1318 bc_vec_pushAt(v, ptr, *i);
1319
1320 return s;
1321}
1322
1323static size_t bc_map_index(const BcVec *v, const void *ptr)
1324{
1325 size_t i = bc_map_find(v, ptr);
1326 if (i >= v->len) return BC_VEC_INVALID_IDX;
1327 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1328}
1329
1330static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1331{
1332 int i;
Denys Vlasenko00d77792018-11-30 23:13:42 +01001333 signed char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001334
Gavin Howard01055ba2018-11-03 11:00:21 -06001335 bc_vec_npop(vec, vec->len);
1336
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001337 fflush(stdout);
1338#if ENABLE_FEATURE_BC_SIGNALS
1339 if (bb_got_signal) { /* ^C was pressed */
1340 intr:
1341 fputs(IS_BC
1342 ? "\ninterrupt (type \"quit\" to exit)\n"
1343 : "\ninterrupt (type \"q\" to exit)\n"
1344 , stderr);
1345 }
1346 bb_got_signal = 0; /* resets G_interrupt to zero */
1347#endif
1348 if (G.ttyin && !G_posix)
1349 fputs(prompt, stderr);
1350 fflush(stderr);
1351
1352#if ENABLE_FEATURE_BC_SIGNALS
1353 again:
1354 errno = 0;
1355#endif
Denys Vlasenko00d77792018-11-30 23:13:42 +01001356 do {
1357 if (ferror(stdout) || ferror(stderr))
1358 bb_perror_msg_and_die("output error");
Gavin Howard01055ba2018-11-03 11:00:21 -06001359
1360 i = fgetc(stdin);
1361
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001362#if ENABLE_FEATURE_BC_SIGNALS
1363 if (bb_got_signal) /* ^C was pressed */
1364 goto intr;
1365#endif
1366
Gavin Howard01055ba2018-11-03 11:00:21 -06001367 if (i == EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001368#if ENABLE_FEATURE_BC_SIGNALS
1369 if (errno == EINTR) {
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001370 clearerr(stdin);
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001371 goto again;
Gavin Howard01055ba2018-11-03 11:00:21 -06001372 }
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001373#endif
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001374 if (ferror(stdin))
1375 bb_perror_msg_and_die("input error");
Denys Vlasenko00d77792018-11-30 23:13:42 +01001376 return BC_STATUS_INPUT_EOF;
Gavin Howard01055ba2018-11-03 11:00:21 -06001377 }
1378
1379 c = (signed char) i;
1380 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1381 bc_vec_push(vec, &c);
Denys Vlasenko00d77792018-11-30 23:13:42 +01001382 } while (c != '\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06001383
1384 bc_vec_pushByte(vec, '\0');
1385
1386 return BC_STATUS_SUCCESS;
1387}
1388
Denys Vlasenkodf515392018-12-02 19:27:48 +01001389static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001390{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001391 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001392 size_t size = ((size_t) -1);
1393 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001394
Denys Vlasenkodf515392018-12-02 19:27:48 +01001395 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001396
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001397 for (i = 0; i < size; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001398 if (BC_READ_BIN_CHAR(buf[i])) {
1399 free(buf);
1400 buf = NULL;
1401 break;
1402 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001403 }
1404
Denys Vlasenkodf515392018-12-02 19:27:48 +01001405 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001406}
1407
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001408static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001409{
Gavin Howard01055ba2018-11-03 11:00:21 -06001410 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001411
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001412 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001413#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001414 G.flags = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001415 "extended-register\0" No_argument "x"
1416 "warn\0" No_argument "w"
1417 "version\0" No_argument "v"
1418 "standard\0" No_argument "s"
1419 "quiet\0" No_argument "q"
1420 "mathlib\0" No_argument "l"
1421 "interactive\0" No_argument "i"
1422 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001423#else
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001424 G.flags = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001425#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001426
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001427 if (G.flags & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001428 // should not be necessary, getopt32() handles this??
1429 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001430
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001431 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001432}
1433
1434static void bc_num_setToZero(BcNum *n, size_t scale)
1435{
1436 n->len = 0;
1437 n->neg = false;
1438 n->rdx = scale;
1439}
1440
1441static void bc_num_zero(BcNum *n)
1442{
1443 bc_num_setToZero(n, 0);
1444}
1445
1446static void bc_num_one(BcNum *n)
1447{
1448 bc_num_setToZero(n, 0);
1449 n->len = 1;
1450 n->num[0] = 1;
1451}
1452
1453static void bc_num_ten(BcNum *n)
1454{
1455 bc_num_setToZero(n, 0);
1456 n->len = 2;
1457 n->num[0] = 0;
1458 n->num[1] = 1;
1459}
1460
1461static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1462 size_t len)
1463{
1464 size_t i, j;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001465 for (i = 0; !G_interrupt && i < len; ++i) {
1466 for (a[i] -= b[i], j = 0; !G_interrupt && a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001467 a[i + j++] += 10;
1468 a[i + j] -= 1;
1469 }
1470 }
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01001471///move ^C detection to bc_num_binary() (can make bc_num_s() return void)
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001472 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001473}
1474
1475static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1476{
1477 size_t i;
1478 int c = 0;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001479 for (i = len - 1; !G_interrupt && i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001480 return BC_NUM_NEG(i + 1, c < 0);
1481}
1482
1483static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1484{
1485 size_t i, min, a_int, b_int, diff;
1486 BcDig *max_num, *min_num;
1487 bool a_max, neg = false;
1488 ssize_t cmp;
1489
1490 if (a == b) return 0;
1491 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1492 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1493 if (a->neg) {
1494 if (b->neg)
1495 neg = true;
1496 else
1497 return -1;
1498 }
1499 else if (b->neg)
1500 return 1;
1501
1502 a_int = BC_NUM_INT(a);
1503 b_int = BC_NUM_INT(b);
1504 a_int -= b_int;
1505 a_max = (a->rdx > b->rdx);
1506
1507 if (a_int != 0) return (ssize_t) a_int;
1508
1509 if (a_max) {
1510 min = b->rdx;
1511 diff = a->rdx - b->rdx;
1512 max_num = a->num + diff;
1513 min_num = b->num;
1514 }
1515 else {
1516 min = a->rdx;
1517 diff = b->rdx - a->rdx;
1518 max_num = b->num + diff;
1519 min_num = a->num;
1520 }
1521
1522 cmp = bc_num_compare(max_num, min_num, b_int + min);
1523 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1524
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001525 for (max_num -= diff, i = diff - 1; !G_interrupt && i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001526 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1527 }
1528
1529 return 0;
1530}
1531
1532static void bc_num_truncate(BcNum *n, size_t places)
1533{
1534 if (places == 0) return;
1535
1536 n->rdx -= places;
1537
1538 if (n->len != 0) {
1539 n->len -= places;
1540 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1541 }
1542}
1543
1544static void bc_num_extend(BcNum *n, size_t places)
1545{
1546 size_t len = n->len + places;
1547
1548 if (places != 0) {
1549
1550 if (n->cap < len) bc_num_expand(n, len);
1551
1552 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1553 memset(n->num, 0, sizeof(BcDig) * places);
1554
1555 n->len += places;
1556 n->rdx += places;
1557 }
1558}
1559
1560static void bc_num_clean(BcNum *n)
1561{
1562 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1563 if (n->len == 0)
1564 n->neg = false;
1565 else if (n->len < n->rdx)
1566 n->len = n->rdx;
1567}
1568
1569static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1570{
1571 if (n->rdx < scale)
1572 bc_num_extend(n, scale - n->rdx);
1573 else
1574 bc_num_truncate(n, n->rdx - scale);
1575
1576 bc_num_clean(n);
1577 if (n->len != 0) n->neg = !neg1 != !neg2;
1578}
1579
1580static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1581 BcNum *restrict b)
1582{
1583 if (idx < n->len) {
1584
1585 b->len = n->len - idx;
1586 a->len = idx;
1587 a->rdx = b->rdx = 0;
1588
1589 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1590 memcpy(a->num, n->num, idx * sizeof(BcDig));
1591 }
1592 else {
1593 bc_num_zero(b);
1594 bc_num_copy(a, n);
1595 }
1596
1597 bc_num_clean(a);
1598 bc_num_clean(b);
1599}
1600
1601static BcStatus bc_num_shift(BcNum *n, size_t places)
1602{
1603 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1604 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1605
1606 if (n->rdx >= places)
1607 n->rdx -= places;
1608 else {
1609 bc_num_extend(n, places - n->rdx);
1610 n->rdx = 0;
1611 }
1612
1613 bc_num_clean(n);
1614
1615 return BC_STATUS_SUCCESS;
1616}
1617
1618static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1619{
1620 BcNum one;
1621 BcDig num[2];
1622
1623 one.cap = 2;
1624 one.num = num;
1625 bc_num_one(&one);
1626
1627 return bc_num_div(&one, a, b, scale);
1628}
1629
1630static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1631{
1632 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1633 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1634 int carry, in;
1635
1636 // Because this function doesn't need to use scale (per the bc spec),
1637 // I am hijacking it to say whether it's doing an add or a subtract.
1638
1639 if (a->len == 0) {
1640 bc_num_copy(c, b);
1641 if (sub && c->len) c->neg = !c->neg;
1642 return BC_STATUS_SUCCESS;
1643 }
1644 else if (b->len == 0) {
1645 bc_num_copy(c, a);
1646 return BC_STATUS_SUCCESS;
1647 }
1648
1649 c->neg = a->neg;
1650 c->rdx = BC_MAX(a->rdx, b->rdx);
1651 min_rdx = BC_MIN(a->rdx, b->rdx);
1652 c->len = 0;
1653
1654 if (a->rdx > b->rdx) {
1655 diff = a->rdx - b->rdx;
1656 ptr = a->num;
1657 ptr_a = a->num + diff;
1658 ptr_b = b->num;
1659 }
1660 else {
1661 diff = b->rdx - a->rdx;
1662 ptr = b->num;
1663 ptr_a = a->num;
1664 ptr_b = b->num + diff;
1665 }
1666
1667 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1668
1669 ptr_c += diff;
1670 a_int = BC_NUM_INT(a);
1671 b_int = BC_NUM_INT(b);
1672
1673 if (a_int > b_int) {
1674 min_int = b_int;
1675 max = a_int;
1676 ptr = ptr_a;
1677 }
1678 else {
1679 min_int = a_int;
1680 max = b_int;
1681 ptr = ptr_b;
1682 }
1683
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001684 for (carry = 0, i = 0; !G_interrupt && i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001685 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1686 carry = in / 10;
1687 ptr_c[i] = (BcDig)(in % 10);
1688 }
1689
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001690 for (; !G_interrupt && i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001691 in = ((int) ptr[i]) + carry;
1692 carry = in / 10;
1693 ptr_c[i] = (BcDig)(in % 10);
1694 }
1695
1696 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1697
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01001698///move ^C detection to bc_num_binary()
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001699 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001700}
1701
1702static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1703{
1704 BcStatus s;
1705 ssize_t cmp;
1706 BcNum *minuend, *subtrahend;
1707 size_t start;
1708 bool aneg, bneg, neg;
1709
1710 // Because this function doesn't need to use scale (per the bc spec),
1711 // I am hijacking it to say whether it's doing an add or a subtract.
1712
1713 if (a->len == 0) {
1714 bc_num_copy(c, b);
1715 if (sub && c->len) c->neg = !c->neg;
1716 return BC_STATUS_SUCCESS;
1717 }
1718 else if (b->len == 0) {
1719 bc_num_copy(c, a);
1720 return BC_STATUS_SUCCESS;
1721 }
1722
1723 aneg = a->neg;
1724 bneg = b->neg;
1725 a->neg = b->neg = false;
1726
1727 cmp = bc_num_cmp(a, b);
1728
1729 a->neg = aneg;
1730 b->neg = bneg;
1731
1732 if (cmp == 0) {
1733 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1734 return BC_STATUS_SUCCESS;
1735 }
1736 else if (cmp > 0) {
1737 neg = a->neg;
1738 minuend = a;
1739 subtrahend = b;
1740 }
1741 else {
1742 neg = b->neg;
1743 if (sub) neg = !neg;
1744 minuend = b;
1745 subtrahend = a;
1746 }
1747
1748 bc_num_copy(c, minuend);
1749 c->neg = neg;
1750
1751 if (c->rdx < subtrahend->rdx) {
1752 bc_num_extend(c, subtrahend->rdx - c->rdx);
1753 start = 0;
1754 }
1755 else
1756 start = c->rdx - subtrahend->rdx;
1757
1758 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1759
1760 bc_num_clean(c);
1761
1762 return s;
1763}
1764
1765static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1766 BcNum *restrict c)
1767{
1768 BcStatus s;
1769 int carry;
1770 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1771 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1772 bool aone = BC_NUM_ONE(a);
1773
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01001774///move ^C detection to bc_num_binary()
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001775 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06001776 if (a->len == 0 || b->len == 0) {
1777 bc_num_zero(c);
1778 return BC_STATUS_SUCCESS;
1779 }
1780 else if (aone || BC_NUM_ONE(b)) {
1781 bc_num_copy(c, aone ? b : a);
1782 return BC_STATUS_SUCCESS;
1783 }
1784
1785 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1786 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1787 {
1788 bc_num_expand(c, a->len + b->len + 1);
1789
1790 memset(c->num, 0, sizeof(BcDig) * c->cap);
1791 c->len = carry = len = 0;
1792
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001793 for (i = 0; !G_interrupt && i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001794
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001795 for (j = 0; !G_interrupt && j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001796 int in = (int) c->num[i + j];
1797 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1798 carry = in / 10;
1799 c->num[i + j] = (BcDig)(in % 10);
1800 }
1801
1802 c->num[i + j] += (BcDig) carry;
1803 len = BC_MAX(len, i + j + !!carry);
1804 carry = 0;
1805 }
1806
1807 c->len = len;
1808
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01001809///move ^C detection to bc_num_binary()
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001810 return G_interrupt ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001811 }
1812
1813 bc_num_init(&l1, max);
1814 bc_num_init(&h1, max);
1815 bc_num_init(&l2, max);
1816 bc_num_init(&h2, max);
1817 bc_num_init(&m1, max);
1818 bc_num_init(&m2, max);
1819 bc_num_init(&z0, max);
1820 bc_num_init(&z1, max);
1821 bc_num_init(&z2, max);
1822 bc_num_init(&temp, max + max);
1823
1824 bc_num_split(a, max2, &l1, &h1);
1825 bc_num_split(b, max2, &l2, &h2);
1826
1827 s = bc_num_add(&h1, &l1, &m1, 0);
1828 if (s) goto err;
1829 s = bc_num_add(&h2, &l2, &m2, 0);
1830 if (s) goto err;
1831
1832 s = bc_num_k(&h1, &h2, &z0);
1833 if (s) goto err;
1834 s = bc_num_k(&m1, &m2, &z1);
1835 if (s) goto err;
1836 s = bc_num_k(&l1, &l2, &z2);
1837 if (s) goto err;
1838
1839 s = bc_num_sub(&z1, &z0, &temp, 0);
1840 if (s) goto err;
1841 s = bc_num_sub(&temp, &z2, &z1, 0);
1842 if (s) goto err;
1843
1844 s = bc_num_shift(&z0, max2 * 2);
1845 if (s) goto err;
1846 s = bc_num_shift(&z1, max2);
1847 if (s) goto err;
1848 s = bc_num_add(&z0, &z1, &temp, 0);
1849 if (s) goto err;
1850 s = bc_num_add(&temp, &z2, c, 0);
1851
1852err:
1853 bc_num_free(&temp);
1854 bc_num_free(&z2);
1855 bc_num_free(&z1);
1856 bc_num_free(&z0);
1857 bc_num_free(&m2);
1858 bc_num_free(&m1);
1859 bc_num_free(&h2);
1860 bc_num_free(&l2);
1861 bc_num_free(&h1);
1862 bc_num_free(&l1);
1863 return s;
1864}
1865
1866static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1867{
1868 BcStatus s;
1869 BcNum cpa, cpb;
1870 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1871
1872 scale = BC_MAX(scale, a->rdx);
1873 scale = BC_MAX(scale, b->rdx);
1874 scale = BC_MIN(a->rdx + b->rdx, scale);
1875 maxrdx = BC_MAX(maxrdx, scale);
1876
1877 bc_num_init(&cpa, a->len);
1878 bc_num_init(&cpb, b->len);
1879
1880 bc_num_copy(&cpa, a);
1881 bc_num_copy(&cpb, b);
1882 cpa.neg = cpb.neg = false;
1883
1884 s = bc_num_shift(&cpa, maxrdx);
1885 if (s) goto err;
1886 s = bc_num_shift(&cpb, maxrdx);
1887 if (s) goto err;
1888 s = bc_num_k(&cpa, &cpb, c);
1889 if (s) goto err;
1890
1891 maxrdx += scale;
1892 bc_num_expand(c, c->len + maxrdx);
1893
1894 if (c->len < maxrdx) {
1895 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1896 c->len += maxrdx;
1897 }
1898
1899 c->rdx = maxrdx;
1900 bc_num_retireMul(c, scale, a->neg, b->neg);
1901
1902err:
1903 bc_num_free(&cpb);
1904 bc_num_free(&cpa);
1905 return s;
1906}
1907
1908static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1909{
1910 BcStatus s = BC_STATUS_SUCCESS;
1911 BcDig *n, *p, q;
1912 size_t len, end, i;
1913 BcNum cp;
1914 bool zero = true;
1915
1916 if (b->len == 0)
1917 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1918 else if (a->len == 0) {
1919 bc_num_setToZero(c, scale);
1920 return BC_STATUS_SUCCESS;
1921 }
1922 else if (BC_NUM_ONE(b)) {
1923 bc_num_copy(c, a);
1924 bc_num_retireMul(c, scale, a->neg, b->neg);
1925 return BC_STATUS_SUCCESS;
1926 }
1927
1928 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1929 bc_num_copy(&cp, a);
1930 len = b->len;
1931
1932 if (len > cp.len) {
1933 bc_num_expand(&cp, len + 2);
1934 bc_num_extend(&cp, len - cp.len);
1935 }
1936
1937 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1938 cp.rdx -= b->rdx;
1939 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1940
1941 if (b->rdx == b->len) {
1942 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1943 len -= i - 1;
1944 }
1945
1946 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1947
1948 // We want an extra zero in front to make things simpler.
1949 cp.num[cp.len++] = 0;
1950 end = cp.len - len;
1951
1952 bc_num_expand(c, cp.len);
1953
1954 bc_num_zero(c);
1955 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1956 c->rdx = cp.rdx;
1957 c->len = cp.len;
1958 p = b->num;
1959
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001960 for (i = end - 1; !G_interrupt && !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001961 n = cp.num + i;
1962 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1963 s = bc_num_subArrays(n, p, len);
1964 c->num[i] = q;
1965 }
1966
1967 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1968 bc_num_free(&cp);
1969
1970 return s;
1971}
1972
1973static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1974 BcNum *restrict d, size_t scale, size_t ts)
1975{
1976 BcStatus s;
1977 BcNum temp;
1978 bool neg;
1979
1980 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1981
1982 if (a->len == 0) {
1983 bc_num_setToZero(d, ts);
1984 return BC_STATUS_SUCCESS;
1985 }
1986
1987 bc_num_init(&temp, d->cap);
1988 bc_num_d(a, b, c, scale);
1989
1990 if (scale != 0) scale = ts;
1991
1992 s = bc_num_m(c, b, &temp, scale);
1993 if (s) goto err;
1994 s = bc_num_sub(a, &temp, d, scale);
1995 if (s) goto err;
1996
1997 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1998
1999 neg = d->neg;
2000 bc_num_retireMul(d, ts, a->neg, b->neg);
2001 d->neg = neg;
2002
2003err:
2004 bc_num_free(&temp);
2005 return s;
2006}
2007
2008static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2009{
2010 BcStatus s;
2011 BcNum c1;
2012 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2013
2014 bc_num_init(&c1, len);
2015 s = bc_num_r(a, b, &c1, c, scale, ts);
2016 bc_num_free(&c1);
2017
2018 return s;
2019}
2020
2021static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2022{
2023 BcStatus s = BC_STATUS_SUCCESS;
2024 BcNum copy;
2025 unsigned long pow;
2026 size_t i, powrdx, resrdx;
2027 bool neg, zero;
2028
2029 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2030
2031 if (b->len == 0) {
2032 bc_num_one(c);
2033 return BC_STATUS_SUCCESS;
2034 }
2035 else if (a->len == 0) {
2036 bc_num_setToZero(c, scale);
2037 return BC_STATUS_SUCCESS;
2038 }
2039 else if (BC_NUM_ONE(b)) {
2040 if (!b->neg)
2041 bc_num_copy(c, a);
2042 else
2043 s = bc_num_inv(a, c, scale);
2044 return s;
2045 }
2046
2047 neg = b->neg;
2048 b->neg = false;
2049
2050 s = bc_num_ulong(b, &pow);
2051 if (s) return s;
2052
2053 bc_num_init(&copy, a->len);
2054 bc_num_copy(&copy, a);
2055
2056 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2057
2058 b->neg = neg;
2059
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002060 for (powrdx = a->rdx; !G_interrupt && !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002061 powrdx <<= 1;
2062 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2063 if (s) goto err;
2064 }
2065
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002066 if (G_interrupt) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002067///move ^C detection to bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06002068 s = BC_STATUS_EXEC_SIGNAL;
2069 goto err;
2070 }
2071
2072 bc_num_copy(c, &copy);
2073
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002074 for (resrdx = powrdx, pow >>= 1; !G_interrupt && pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002075
2076 powrdx <<= 1;
2077 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2078 if (s) goto err;
2079
2080 if (pow & 1) {
2081 resrdx += powrdx;
2082 s = bc_num_mul(c, &copy, c, resrdx);
2083 if (s) goto err;
2084 }
2085 }
2086
2087 if (neg) {
2088 s = bc_num_inv(c, c, scale);
2089 if (s) goto err;
2090 }
2091
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002092 if (G_interrupt) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002093///move ^C detection to bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06002094 s = BC_STATUS_EXEC_SIGNAL;
2095 goto err;
2096 }
2097
2098 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2099
2100 // We can't use bc_num_clean() here.
2101 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2102 if (zero) bc_num_setToZero(c, scale);
2103
2104err:
2105 bc_num_free(&copy);
2106 return s;
2107}
2108
2109static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2110 BcNumBinaryOp op, size_t req)
2111{
2112 BcStatus s;
2113 BcNum num2, *ptr_a, *ptr_b;
2114 bool init = false;
2115
2116 if (c == a) {
2117 ptr_a = &num2;
2118 memcpy(ptr_a, c, sizeof(BcNum));
2119 init = true;
2120 }
2121 else
2122 ptr_a = a;
2123
2124 if (c == b) {
2125 ptr_b = &num2;
2126 if (c != a) {
2127 memcpy(ptr_b, c, sizeof(BcNum));
2128 init = true;
2129 }
2130 }
2131 else
2132 ptr_b = b;
2133
2134 if (init)
2135 bc_num_init(c, req);
2136 else
2137 bc_num_expand(c, req);
2138
2139 s = op(ptr_a, ptr_b, c, scale);
2140
2141 if (init) bc_num_free(&num2);
2142
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002143///move ^C detection here:
2144// if (s == 0 && G_interrupt) s = BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06002145 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;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002232 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002233 s = bc_num_add(&mult, &temp, n, 0);
2234 if (s) goto int_err;
2235 }
2236
2237 if (i == len) {
2238 c = val[i];
2239 if (c == 0) goto int_err;
2240 }
2241
2242 bc_num_init(&result, base->len);
2243 bc_num_zero(&result);
2244 bc_num_one(&mult);
2245
2246 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2247
2248 c = val[i];
2249 if (c == 0) break;
2250
2251 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2252
2253 s = bc_num_mul(&result, base, &result, 0);
2254 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002255 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002256 s = bc_num_add(&result, &temp, &result, 0);
2257 if (s) goto err;
2258 s = bc_num_mul(&mult, base, &mult, 0);
2259 if (s) goto err;
2260 }
2261
2262 s = bc_num_div(&result, &mult, &result, digits);
2263 if (s) goto err;
2264 s = bc_num_add(n, &result, n, digits);
2265 if (s) goto err;
2266
2267 if (n->len != 0) {
2268 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2269 }
2270 else
2271 bc_num_zero(n);
2272
2273err:
2274 bc_num_free(&result);
2275int_err:
2276 bc_num_free(&mult);
2277 bc_num_free(&temp);
2278}
2279
2280static void bc_num_printNewline(size_t *nchars, size_t line_len)
2281{
2282 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002283 bb_putchar('\\');
2284 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002285 *nchars = 0;
2286 }
2287}
2288
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002289#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002290static void bc_num_printChar(size_t num, size_t width, bool radix,
2291 size_t *nchars, size_t line_len)
2292{
2293 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002294 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002295 *nchars = *nchars + width;
2296}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002297#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002298
2299static void bc_num_printDigits(size_t num, size_t width, bool radix,
2300 size_t *nchars, size_t line_len)
2301{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002302 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002303
2304 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002305 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002306 ++(*nchars);
2307
2308 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002309 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2310 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002311
2312 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002313 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002314 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002315 dig = num / pow;
2316 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002317 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002318 }
2319}
2320
2321static void bc_num_printHex(size_t num, size_t width, bool radix,
2322 size_t *nchars, size_t line_len)
2323{
2324 if (radix) {
2325 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002326 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002327 *nchars += 1;
2328 }
2329
2330 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002331 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002332 *nchars = *nchars + width;
2333}
2334
2335static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2336{
2337 size_t i, rdx = n->rdx - 1;
2338
Denys Vlasenko00d77792018-11-30 23:13:42 +01002339 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002340 (*nchars) += n->neg;
2341
2342 for (i = n->len - 1; i < n->len; --i)
2343 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2344}
2345
2346static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2347 size_t *nchars, size_t len, BcNumDigitOp print)
2348{
2349 BcStatus s;
2350 BcVec stack;
2351 BcNum intp, fracp, digit, frac_len;
2352 unsigned long dig, *ptr;
2353 size_t i;
2354 bool radix;
2355
2356 if (n->len == 0) {
2357 print(0, width, false, nchars, len);
2358 return BC_STATUS_SUCCESS;
2359 }
2360
2361 bc_vec_init(&stack, sizeof(long), NULL);
2362 bc_num_init(&intp, n->len);
2363 bc_num_init(&fracp, n->rdx);
2364 bc_num_init(&digit, width);
2365 bc_num_init(&frac_len, BC_NUM_INT(n));
2366 bc_num_copy(&intp, n);
2367 bc_num_one(&frac_len);
2368
2369 bc_num_truncate(&intp, intp.rdx);
2370 s = bc_num_sub(n, &intp, &fracp, 0);
2371 if (s) goto err;
2372
2373 while (intp.len != 0) {
2374 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2375 if (s) goto err;
2376 s = bc_num_ulong(&digit, &dig);
2377 if (s) goto err;
2378 bc_vec_push(&stack, &dig);
2379 }
2380
2381 for (i = 0; i < stack.len; ++i) {
2382 ptr = bc_vec_item_rev(&stack, i);
2383 print(*ptr, width, false, nchars, len);
2384 }
2385
2386 if (!n->rdx) goto err;
2387
2388 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2389 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2390 if (s) goto err;
2391 s = bc_num_ulong(&fracp, &dig);
2392 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002393 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002394 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2395 if (s) goto err;
2396 print(dig, width, radix, nchars, len);
2397 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2398 if (s) goto err;
2399 }
2400
2401err:
2402 bc_num_free(&frac_len);
2403 bc_num_free(&digit);
2404 bc_num_free(&fracp);
2405 bc_num_free(&intp);
2406 bc_vec_free(&stack);
2407 return s;
2408}
2409
2410static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2411 size_t *nchars, size_t line_len)
2412{
2413 BcStatus s;
2414 size_t width, i;
2415 BcNumDigitOp print;
2416 bool neg = n->neg;
2417
Denys Vlasenko00d77792018-11-30 23:13:42 +01002418 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002419 (*nchars) += neg;
2420
2421 n->neg = false;
2422
2423 if (base_t <= BC_NUM_MAX_IBASE) {
2424 width = 1;
2425 print = bc_num_printHex;
2426 }
2427 else {
2428 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2429 print = bc_num_printDigits;
2430 }
2431
2432 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2433 n->neg = neg;
2434
2435 return s;
2436}
2437
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002438#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002439static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2440{
2441 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2442}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002443#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002444
2445static void bc_num_init(BcNum *n, size_t req)
2446{
2447 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2448 memset(n, 0, sizeof(BcNum));
2449 n->num = xmalloc(req);
2450 n->cap = req;
2451}
2452
2453static void bc_num_expand(BcNum *n, size_t req)
2454{
2455 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2456 if (req > n->cap) {
2457 n->num = xrealloc(n->num, req);
2458 n->cap = req;
2459 }
2460}
2461
2462static void bc_num_free(void *num)
2463{
2464 free(((BcNum *) num)->num);
2465}
2466
2467static void bc_num_copy(BcNum *d, BcNum *s)
2468{
2469 if (d != s) {
2470 bc_num_expand(d, s->cap);
2471 d->len = s->len;
2472 d->neg = s->neg;
2473 d->rdx = s->rdx;
2474 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2475 }
2476}
2477
2478static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2479 size_t base_t)
2480{
2481 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2482
2483 if (base_t == 10)
2484 bc_num_parseDecimal(n, val);
2485 else
2486 bc_num_parseBase(n, val, base);
2487
2488 return BC_STATUS_SUCCESS;
2489}
2490
2491static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2492 size_t *nchars, size_t line_len)
2493{
2494 BcStatus s = BC_STATUS_SUCCESS;
2495
2496 bc_num_printNewline(nchars, line_len);
2497
2498 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002499 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002500 ++(*nchars);
2501 }
2502 else if (base_t == 10)
2503 bc_num_printDecimal(n, nchars, line_len);
2504 else
2505 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2506
2507 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002508 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002509 *nchars = 0;
2510 }
2511
2512 return s;
2513}
2514
2515static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2516{
2517 size_t i;
2518 unsigned long pow;
2519
2520 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2521
2522 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2523
2524 unsigned long prev = *result, powprev = pow;
2525
2526 *result += ((unsigned long) n->num[i]) * pow;
2527 pow *= 10;
2528
2529 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2530 }
2531
2532 return BC_STATUS_SUCCESS;
2533}
2534
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002535static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002536{
2537 size_t len;
2538 BcDig *ptr;
2539 unsigned long i;
2540
2541 bc_num_zero(n);
2542
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002543 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002544
2545 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2546 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002547}
2548
2549static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2550{
2551 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2552 (void) scale;
2553 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2554}
2555
2556static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2557{
2558 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2559 (void) scale;
2560 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2561}
2562
2563static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2564{
2565 size_t req = BC_NUM_MREQ(a, b, scale);
2566 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2567}
2568
2569static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2570{
2571 size_t req = BC_NUM_MREQ(a, b, scale);
2572 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2573}
2574
2575static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2576{
2577 size_t req = BC_NUM_MREQ(a, b, scale);
2578 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2579}
2580
2581static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2582{
2583 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2584}
2585
2586static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2587{
2588 BcStatus s;
2589 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2590 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2591 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2592
2593 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2594 bc_num_expand(b, req);
2595
2596 if (a->len == 0) {
2597 bc_num_setToZero(b, scale);
2598 return BC_STATUS_SUCCESS;
2599 }
2600 else if (a->neg)
2601 return BC_STATUS_MATH_NEGATIVE;
2602 else if (BC_NUM_ONE(a)) {
2603 bc_num_one(b);
2604 bc_num_extend(b, scale);
2605 return BC_STATUS_SUCCESS;
2606 }
2607
2608 scale = BC_MAX(scale, a->rdx) + 1;
2609 len = a->len + scale;
2610
2611 bc_num_init(&num1, len);
2612 bc_num_init(&num2, len);
2613 bc_num_init(&half, BC_NUM_DEF_SIZE);
2614
2615 bc_num_one(&half);
2616 half.num[0] = 5;
2617 half.rdx = 1;
2618
2619 bc_num_init(&f, len);
2620 bc_num_init(&fprime, len);
2621
2622 x0 = &num1;
2623 x1 = &num2;
2624
2625 bc_num_one(x0);
2626 pow = BC_NUM_INT(a);
2627
2628 if (pow) {
2629
2630 if (pow & 1)
2631 x0->num[0] = 2;
2632 else
2633 x0->num[0] = 6;
2634
2635 pow -= 2 - (pow & 1);
2636
2637 bc_num_extend(x0, pow);
2638
2639 // Make sure to move the radix back.
2640 x0->rdx -= pow;
2641 }
2642
2643 x0->rdx = digs = digs1 = 0;
2644 resrdx = scale + 2;
2645 len = BC_NUM_INT(x0) + resrdx - 1;
2646
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002647///move ^C detection to callers
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002648 while (!G_interrupt && (cmp != 0 || digs < len)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002649
2650 s = bc_num_div(a, x0, &f, resrdx);
2651 if (s) goto err;
2652 s = bc_num_add(x0, &f, &fprime, resrdx);
2653 if (s) goto err;
2654 s = bc_num_mul(&fprime, &half, x1, resrdx);
2655 if (s) goto err;
2656
2657 cmp = bc_num_cmp(x1, x0);
2658 digs = x1->len - (unsigned long long) llabs(cmp);
2659
2660 if (cmp == cmp2 && digs == digs1)
2661 times += 1;
2662 else
2663 times = 0;
2664
2665 resrdx += times > 4;
2666
2667 cmp2 = cmp1;
2668 cmp1 = cmp;
2669 digs1 = digs;
2670
2671 temp = x0;
2672 x0 = x1;
2673 x1 = temp;
2674 }
2675
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01002676 if (G_interrupt) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002677///move ^C detection to callers
Gavin Howard01055ba2018-11-03 11:00:21 -06002678 s = BC_STATUS_EXEC_SIGNAL;
2679 goto err;
2680 }
2681
2682 bc_num_copy(b, x0);
2683 scale -= 1;
2684 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2685
2686err:
2687 bc_num_free(&fprime);
2688 bc_num_free(&f);
2689 bc_num_free(&half);
2690 bc_num_free(&num2);
2691 bc_num_free(&num1);
2692 return s;
2693}
2694
2695static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2696 size_t scale)
2697{
2698 BcStatus s;
2699 BcNum num2, *ptr_a;
2700 bool init = false;
2701 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2702
2703 if (c == a) {
2704 memcpy(&num2, c, sizeof(BcNum));
2705 ptr_a = &num2;
2706 bc_num_init(c, len);
2707 init = true;
2708 }
2709 else {
2710 ptr_a = a;
2711 bc_num_expand(c, len);
2712 }
2713
2714 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2715
2716 if (init) bc_num_free(&num2);
2717
2718 return s;
2719}
2720
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002721#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002722static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2723{
2724 BcStatus s;
2725 BcNum base, exp, two, temp;
2726
2727 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2728 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2729 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2730
2731 bc_num_expand(d, c->len);
2732 bc_num_init(&base, c->len);
2733 bc_num_init(&exp, b->len);
2734 bc_num_init(&two, BC_NUM_DEF_SIZE);
2735 bc_num_init(&temp, b->len);
2736
2737 bc_num_one(&two);
2738 two.num[0] = 2;
2739 bc_num_one(d);
2740
2741 s = bc_num_rem(a, c, &base, 0);
2742 if (s) goto err;
2743 bc_num_copy(&exp, b);
2744
2745 while (exp.len != 0) {
2746
2747 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2748 if (s) goto err;
2749
2750 if (BC_NUM_ONE(&temp)) {
2751 s = bc_num_mul(d, &base, &temp, 0);
2752 if (s) goto err;
2753 s = bc_num_rem(&temp, c, d, 0);
2754 if (s) goto err;
2755 }
2756
2757 s = bc_num_mul(&base, &base, &temp, 0);
2758 if (s) goto err;
2759 s = bc_num_rem(&temp, c, &base, 0);
2760 if (s) goto err;
2761 }
2762
2763err:
2764 bc_num_free(&temp);
2765 bc_num_free(&two);
2766 bc_num_free(&exp);
2767 bc_num_free(&base);
2768 return s;
2769}
2770#endif // ENABLE_DC
2771
2772static int bc_id_cmp(const void *e1, const void *e2)
2773{
2774 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2775}
2776
2777static void bc_id_free(void *id)
2778{
2779 free(((BcId *) id)->name);
2780}
2781
2782static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2783{
2784 BcId a;
2785 size_t i;
2786
2787 for (i = 0; i < f->autos.len; ++i) {
2788 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2789 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2790 }
2791
2792 a.idx = var;
2793 a.name = name;
2794
2795 bc_vec_push(&f->autos, &a);
2796
2797 return BC_STATUS_SUCCESS;
2798}
2799
2800static void bc_func_init(BcFunc *f)
2801{
2802 bc_vec_init(&f->code, sizeof(char), NULL);
2803 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2804 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2805 f->nparams = 0;
2806}
2807
2808static void bc_func_free(void *func)
2809{
2810 BcFunc *f = (BcFunc *) func;
2811 bc_vec_free(&f->code);
2812 bc_vec_free(&f->autos);
2813 bc_vec_free(&f->labels);
2814}
2815
2816static void bc_array_init(BcVec *a, bool nums)
2817{
2818 if (nums)
2819 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2820 else
2821 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2822 bc_array_expand(a, 1);
2823}
2824
2825static void bc_array_copy(BcVec *d, const BcVec *s)
2826{
2827 size_t i;
2828
2829 bc_vec_npop(d, d->len);
2830 bc_vec_expand(d, s->cap);
2831 d->len = s->len;
2832
2833 for (i = 0; i < s->len; ++i) {
2834 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2835 bc_num_init(dnum, snum->len);
2836 bc_num_copy(dnum, snum);
2837 }
2838}
2839
2840static void bc_array_expand(BcVec *a, size_t len)
2841{
2842 BcResultData data;
2843
2844 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2845 while (len > a->len) {
2846 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2847 bc_vec_push(a, &data.n);
2848 }
2849 }
2850 else {
2851 while (len > a->len) {
2852 bc_array_init(&data.v, true);
2853 bc_vec_push(a, &data.v);
2854 }
2855 }
2856}
2857
2858static void bc_string_free(void *string)
2859{
2860 free(*((char **) string));
2861}
2862
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002863#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002864static void bc_result_copy(BcResult *d, BcResult *src)
2865{
2866 d->t = src->t;
2867
2868 switch (d->t) {
2869
2870 case BC_RESULT_TEMP:
2871 case BC_RESULT_IBASE:
2872 case BC_RESULT_SCALE:
2873 case BC_RESULT_OBASE:
2874 {
2875 bc_num_init(&d->d.n, src->d.n.len);
2876 bc_num_copy(&d->d.n, &src->d.n);
2877 break;
2878 }
2879
2880 case BC_RESULT_VAR:
2881 case BC_RESULT_ARRAY:
2882 case BC_RESULT_ARRAY_ELEM:
2883 {
2884 d->d.id.name = xstrdup(src->d.id.name);
2885 break;
2886 }
2887
2888 case BC_RESULT_CONSTANT:
2889 case BC_RESULT_LAST:
2890 case BC_RESULT_ONE:
2891 case BC_RESULT_STR:
2892 {
2893 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2894 break;
2895 }
2896 }
2897}
2898#endif // ENABLE_DC
2899
2900static void bc_result_free(void *result)
2901{
2902 BcResult *r = (BcResult *) result;
2903
2904 switch (r->t) {
2905
2906 case BC_RESULT_TEMP:
2907 case BC_RESULT_IBASE:
2908 case BC_RESULT_SCALE:
2909 case BC_RESULT_OBASE:
2910 {
2911 bc_num_free(&r->d.n);
2912 break;
2913 }
2914
2915 case BC_RESULT_VAR:
2916 case BC_RESULT_ARRAY:
2917 case BC_RESULT_ARRAY_ELEM:
2918 {
2919 free(r->d.id.name);
2920 break;
2921 }
2922
2923 default:
2924 {
2925 // Do nothing.
2926 break;
2927 }
2928 }
2929}
2930
2931static void bc_lex_lineComment(BcLex *l)
2932{
2933 l->t.t = BC_LEX_WHITESPACE;
2934 while (l->i < l->len && l->buf[l->i++] != '\n');
2935 --l->i;
2936}
2937
2938static void bc_lex_whitespace(BcLex *l)
2939{
2940 char c;
2941 l->t.t = BC_LEX_WHITESPACE;
2942 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2943}
2944
2945static BcStatus bc_lex_number(BcLex *l, char start)
2946{
2947 const char *buf = l->buf + l->i;
2948 size_t len, hits = 0, bslashes = 0, i = 0, j;
2949 char c = buf[i];
2950 bool last_pt, pt = start == '.';
2951
2952 last_pt = pt;
2953 l->t.t = BC_LEX_NUMBER;
2954
2955 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2956 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2957 {
2958 if (c != '\\') {
2959 last_pt = c == '.';
2960 pt = pt || last_pt;
2961 }
2962 else {
2963 ++i;
2964 bslashes += 1;
2965 }
2966
2967 c = buf[++i];
2968 }
2969
2970 len = i + 1 * !last_pt - bslashes * 2;
2971 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2972
2973 bc_vec_npop(&l->t.v, l->t.v.len);
2974 bc_vec_expand(&l->t.v, len + 1);
2975 bc_vec_push(&l->t.v, &start);
2976
2977 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2978
2979 c = buf[j];
2980
2981 // If we have hit a backslash, skip it. We don't have
2982 // to check for a newline because it's guaranteed.
2983 if (hits < bslashes && c == '\\') {
2984 ++hits;
2985 ++j;
2986 continue;
2987 }
2988
2989 bc_vec_push(&l->t.v, &c);
2990 }
2991
2992 bc_vec_pushByte(&l->t.v, '\0');
2993 l->i += i;
2994
2995 return BC_STATUS_SUCCESS;
2996}
2997
2998static BcStatus bc_lex_name(BcLex *l)
2999{
3000 size_t i = 0;
3001 const char *buf = l->buf + l->i - 1;
3002 char c = buf[i];
3003
3004 l->t.t = BC_LEX_NAME;
3005
3006 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3007
3008 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3009 bc_vec_string(&l->t.v, i, buf);
3010
3011 // Increment the index. We minus 1 because it has already been incremented.
3012 l->i += i - 1;
3013
3014 return BC_STATUS_SUCCESS;
3015}
3016
3017static void bc_lex_init(BcLex *l, BcLexNext next)
3018{
3019 l->next = next;
3020 bc_vec_init(&l->t.v, sizeof(char), NULL);
3021}
3022
3023static void bc_lex_free(BcLex *l)
3024{
3025 bc_vec_free(&l->t.v);
3026}
3027
3028static void bc_lex_file(BcLex *l, const char *file)
3029{
3030 l->line = 1;
3031 l->newline = false;
3032 l->f = file;
3033}
3034
3035static BcStatus bc_lex_next(BcLex *l)
3036{
3037 BcStatus s;
3038
3039 l->t.last = l->t.t;
3040 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3041
3042 l->line += l->newline;
3043 l->t.t = BC_LEX_EOF;
3044
3045 l->newline = (l->i == l->len);
3046 if (l->newline) return BC_STATUS_SUCCESS;
3047
3048 // Loop until failure or we don't have whitespace. This
3049 // is so the parser doesn't get inundated with whitespace.
3050 do {
3051 s = l->next(l);
3052 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3053
3054 return s;
3055}
3056
3057static BcStatus bc_lex_text(BcLex *l, const char *text)
3058{
3059 l->buf = text;
3060 l->i = 0;
3061 l->len = strlen(text);
3062 l->t.t = l->t.last = BC_LEX_INVALID;
3063 return bc_lex_next(l);
3064}
3065
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003066#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003067static BcStatus bc_lex_identifier(BcLex *l)
3068{
3069 BcStatus s;
3070 size_t i;
3071 const char *buf = l->buf + l->i - 1;
3072
3073 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3074
3075 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3076
3077 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3078
3079 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3080
3081 if (!bc_lex_kws[i].posix) {
3082 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3083 bc_lex_kws[i].name);
3084 if (s) return s;
3085 }
3086
3087 // We minus 1 because the index has already been incremented.
3088 l->i += len - 1;
3089 return BC_STATUS_SUCCESS;
3090 }
3091 }
3092
3093 s = bc_lex_name(l);
3094 if (s) return s;
3095
3096 if (l->t.v.len - 1 > 1)
3097 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3098
3099 return s;
3100}
3101
3102static BcStatus bc_lex_string(BcLex *l)
3103{
3104 size_t len, nls = 0, i = l->i;
3105 char c;
3106
3107 l->t.t = BC_LEX_STR;
3108
3109 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3110
3111 if (c == '\0') {
3112 l->i = i;
3113 return BC_STATUS_LEX_NO_STRING_END;
3114 }
3115
3116 len = i - l->i;
3117 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3118 bc_vec_string(&l->t.v, len, l->buf + l->i);
3119
3120 l->i = i + 1;
3121 l->line += nls;
3122
3123 return BC_STATUS_SUCCESS;
3124}
3125
3126static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3127{
3128 if (l->buf[l->i] == '=') {
3129 ++l->i;
3130 l->t.t = with;
3131 }
3132 else
3133 l->t.t = without;
3134}
3135
3136static BcStatus bc_lex_comment(BcLex *l)
3137{
3138 size_t i, nls = 0;
3139 const char *buf = l->buf;
3140 bool end = false;
3141 char c;
3142
3143 l->t.t = BC_LEX_WHITESPACE;
3144
3145 for (i = ++l->i; !end; i += !end) {
3146
3147 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3148
3149 if (c == 0 || buf[i + 1] == '\0') {
3150 l->i = i;
3151 return BC_STATUS_LEX_NO_COMMENT_END;
3152 }
3153
3154 end = buf[i + 1] == '/';
3155 }
3156
3157 l->i = i + 2;
3158 l->line += nls;
3159
3160 return BC_STATUS_SUCCESS;
3161}
3162
3163static BcStatus bc_lex_token(BcLex *l)
3164{
3165 BcStatus s = BC_STATUS_SUCCESS;
3166 char c = l->buf[l->i++], c2;
3167
3168 // This is the workhorse of the lexer.
3169 switch (c) {
3170
3171 case '\0':
3172 case '\n':
3173 {
3174 l->newline = true;
3175 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3176 break;
3177 }
3178
3179 case '\t':
3180 case '\v':
3181 case '\f':
3182 case '\r':
3183 case ' ':
3184 {
3185 bc_lex_whitespace(l);
3186 break;
3187 }
3188
3189 case '!':
3190 {
3191 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3192
3193 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3194 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3195 if (s) return s;
3196 }
3197
3198 break;
3199 }
3200
3201 case '"':
3202 {
3203 s = bc_lex_string(l);
3204 break;
3205 }
3206
3207 case '#':
3208 {
3209 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3210 if (s) return s;
3211
3212 bc_lex_lineComment(l);
3213
3214 break;
3215 }
3216
3217 case '%':
3218 {
3219 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3220 break;
3221 }
3222
3223 case '&':
3224 {
3225 c2 = l->buf[l->i];
3226 if (c2 == '&') {
3227
3228 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3229 if (s) return s;
3230
3231 ++l->i;
3232 l->t.t = BC_LEX_OP_BOOL_AND;
3233 }
3234 else {
3235 l->t.t = BC_LEX_INVALID;
3236 s = BC_STATUS_LEX_BAD_CHAR;
3237 }
3238
3239 break;
3240 }
3241
3242 case '(':
3243 case ')':
3244 {
3245 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3246 break;
3247 }
3248
3249 case '*':
3250 {
3251 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3252 break;
3253 }
3254
3255 case '+':
3256 {
3257 c2 = l->buf[l->i];
3258 if (c2 == '+') {
3259 ++l->i;
3260 l->t.t = BC_LEX_OP_INC;
3261 }
3262 else
3263 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3264 break;
3265 }
3266
3267 case ',':
3268 {
3269 l->t.t = BC_LEX_COMMA;
3270 break;
3271 }
3272
3273 case '-':
3274 {
3275 c2 = l->buf[l->i];
3276 if (c2 == '-') {
3277 ++l->i;
3278 l->t.t = BC_LEX_OP_DEC;
3279 }
3280 else
3281 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3282 break;
3283 }
3284
3285 case '.':
3286 {
3287 if (isdigit(l->buf[l->i]))
3288 s = bc_lex_number(l, c);
3289 else {
3290 l->t.t = BC_LEX_KEY_LAST;
3291 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3292 }
3293 break;
3294 }
3295
3296 case '/':
3297 {
3298 c2 = l->buf[l->i];
3299 if (c2 == '*')
3300 s = bc_lex_comment(l);
3301 else
3302 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3303 break;
3304 }
3305
3306 case '0':
3307 case '1':
3308 case '2':
3309 case '3':
3310 case '4':
3311 case '5':
3312 case '6':
3313 case '7':
3314 case '8':
3315 case '9':
3316 case 'A':
3317 case 'B':
3318 case 'C':
3319 case 'D':
3320 case 'E':
3321 case 'F':
3322 {
3323 s = bc_lex_number(l, c);
3324 break;
3325 }
3326
3327 case ';':
3328 {
3329 l->t.t = BC_LEX_SCOLON;
3330 break;
3331 }
3332
3333 case '<':
3334 {
3335 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3336 break;
3337 }
3338
3339 case '=':
3340 {
3341 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3342 break;
3343 }
3344
3345 case '>':
3346 {
3347 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3348 break;
3349 }
3350
3351 case '[':
3352 case ']':
3353 {
3354 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3355 break;
3356 }
3357
3358 case '\\':
3359 {
3360 if (l->buf[l->i] == '\n') {
3361 l->t.t = BC_LEX_WHITESPACE;
3362 ++l->i;
3363 }
3364 else
3365 s = BC_STATUS_LEX_BAD_CHAR;
3366 break;
3367 }
3368
3369 case '^':
3370 {
3371 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3372 break;
3373 }
3374
3375 case 'a':
3376 case 'b':
3377 case 'c':
3378 case 'd':
3379 case 'e':
3380 case 'f':
3381 case 'g':
3382 case 'h':
3383 case 'i':
3384 case 'j':
3385 case 'k':
3386 case 'l':
3387 case 'm':
3388 case 'n':
3389 case 'o':
3390 case 'p':
3391 case 'q':
3392 case 'r':
3393 case 's':
3394 case 't':
3395 case 'u':
3396 case 'v':
3397 case 'w':
3398 case 'x':
3399 case 'y':
3400 case 'z':
3401 {
3402 s = bc_lex_identifier(l);
3403 break;
3404 }
3405
3406 case '{':
3407 case '}':
3408 {
3409 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3410 break;
3411 }
3412
3413 case '|':
3414 {
3415 c2 = l->buf[l->i];
3416
3417 if (c2 == '|') {
3418
3419 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3420 if (s) return s;
3421
3422 ++l->i;
3423 l->t.t = BC_LEX_OP_BOOL_OR;
3424 }
3425 else {
3426 l->t.t = BC_LEX_INVALID;
3427 s = BC_STATUS_LEX_BAD_CHAR;
3428 }
3429
3430 break;
3431 }
3432
3433 default:
3434 {
3435 l->t.t = BC_LEX_INVALID;
3436 s = BC_STATUS_LEX_BAD_CHAR;
3437 break;
3438 }
3439 }
3440
3441 return s;
3442}
3443#endif // ENABLE_BC
3444
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003445#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003446static BcStatus dc_lex_register(BcLex *l)
3447{
3448 BcStatus s = BC_STATUS_SUCCESS;
3449
3450 if (isspace(l->buf[l->i - 1])) {
3451 bc_lex_whitespace(l);
3452 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003453 if (!G_exreg)
Gavin Howard01055ba2018-11-03 11:00:21 -06003454 s = BC_STATUS_LEX_EXTENDED_REG;
3455 else
3456 s = bc_lex_name(l);
3457 }
3458 else {
3459 bc_vec_npop(&l->t.v, l->t.v.len);
3460 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3461 bc_vec_pushByte(&l->t.v, '\0');
3462 l->t.t = BC_LEX_NAME;
3463 }
3464
3465 return s;
3466}
3467
3468static BcStatus dc_lex_string(BcLex *l)
3469{
3470 size_t depth = 1, nls = 0, i = l->i;
3471 char c;
3472
3473 l->t.t = BC_LEX_STR;
3474 bc_vec_npop(&l->t.v, l->t.v.len);
3475
3476 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3477
3478 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3479 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3480 nls += (c == '\n');
3481
3482 if (depth) bc_vec_push(&l->t.v, &c);
3483 }
3484
3485 if (c == '\0') {
3486 l->i = i;
3487 return BC_STATUS_LEX_NO_STRING_END;
3488 }
3489
3490 bc_vec_pushByte(&l->t.v, '\0');
3491 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3492
3493 l->i = i;
3494 l->line += nls;
3495
3496 return BC_STATUS_SUCCESS;
3497}
3498
3499static BcStatus dc_lex_token(BcLex *l)
3500{
3501 BcStatus s = BC_STATUS_SUCCESS;
3502 char c = l->buf[l->i++], c2;
3503 size_t i;
3504
3505 for (i = 0; i < dc_lex_regs_len; ++i) {
3506 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3507 }
3508
3509 if (c >= '%' && c <= '~' &&
3510 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3511 {
3512 return s;
3513 }
3514
3515 // This is the workhorse of the lexer.
3516 switch (c) {
3517
3518 case '\0':
3519 {
3520 l->t.t = BC_LEX_EOF;
3521 break;
3522 }
3523
3524 case '\n':
3525 case '\t':
3526 case '\v':
3527 case '\f':
3528 case '\r':
3529 case ' ':
3530 {
3531 l->newline = (c == '\n');
3532 bc_lex_whitespace(l);
3533 break;
3534 }
3535
3536 case '!':
3537 {
3538 c2 = l->buf[l->i];
3539
3540 if (c2 == '=')
3541 l->t.t = BC_LEX_OP_REL_NE;
3542 else if (c2 == '<')
3543 l->t.t = BC_LEX_OP_REL_LE;
3544 else if (c2 == '>')
3545 l->t.t = BC_LEX_OP_REL_GE;
3546 else
3547 return BC_STATUS_LEX_BAD_CHAR;
3548
3549 ++l->i;
3550 break;
3551 }
3552
3553 case '#':
3554 {
3555 bc_lex_lineComment(l);
3556 break;
3557 }
3558
3559 case '.':
3560 {
3561 if (isdigit(l->buf[l->i]))
3562 s = bc_lex_number(l, c);
3563 else
3564 s = BC_STATUS_LEX_BAD_CHAR;
3565 break;
3566 }
3567
3568 case '0':
3569 case '1':
3570 case '2':
3571 case '3':
3572 case '4':
3573 case '5':
3574 case '6':
3575 case '7':
3576 case '8':
3577 case '9':
3578 case 'A':
3579 case 'B':
3580 case 'C':
3581 case 'D':
3582 case 'E':
3583 case 'F':
3584 {
3585 s = bc_lex_number(l, c);
3586 break;
3587 }
3588
3589 case '[':
3590 {
3591 s = dc_lex_string(l);
3592 break;
3593 }
3594
3595 default:
3596 {
3597 l->t.t = BC_LEX_INVALID;
3598 s = BC_STATUS_LEX_BAD_CHAR;
3599 break;
3600 }
3601 }
3602
3603 return s;
3604}
3605#endif // ENABLE_DC
3606
3607static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3608{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003609 bc_program_addFunc(name, idx);
3610 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003611}
3612
3613static void bc_parse_pushName(BcParse *p, char *name)
3614{
3615 size_t i = 0, len = strlen(name);
3616
3617 for (; i < len; ++i) bc_parse_push(p, name[i]);
3618 bc_parse_push(p, BC_PARSE_STREND);
3619
3620 free(name);
3621}
3622
3623static void bc_parse_pushIndex(BcParse *p, size_t idx)
3624{
3625 unsigned char amt, i, nums[sizeof(size_t)];
3626
3627 for (amt = 0; idx; ++amt) {
3628 nums[amt] = (char) idx;
3629 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3630 }
3631
3632 bc_parse_push(p, amt);
3633 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3634}
3635
3636static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3637{
3638 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003639 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003640
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003641 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003642
3643 bc_parse_push(p, BC_INST_NUM);
3644 bc_parse_pushIndex(p, idx);
3645
3646 ++(*nexs);
3647 (*prev) = BC_INST_NUM;
3648}
3649
3650static BcStatus bc_parse_text(BcParse *p, const char *text)
3651{
3652 BcStatus s;
3653
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003654 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003655
3656 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3657 p->l.t.t = BC_LEX_INVALID;
3658 s = p->parse(p);
3659 if (s) return s;
3660 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3661 }
3662
3663 return bc_lex_text(&p->l, text);
3664}
3665
3666static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3667{
3668 if (p->fidx != BC_PROG_MAIN) {
3669
3670 p->func->nparams = 0;
3671 bc_vec_npop(&p->func->code, p->func->code.len);
3672 bc_vec_npop(&p->func->autos, p->func->autos.len);
3673 bc_vec_npop(&p->func->labels, p->func->labels.len);
3674
3675 bc_parse_updateFunc(p, BC_PROG_MAIN);
3676 }
3677
3678 p->l.i = p->l.len;
3679 p->l.t.t = BC_LEX_EOF;
3680 p->auto_part = (p->nbraces = 0);
3681
3682 bc_vec_npop(&p->flags, p->flags.len - 1);
3683 bc_vec_npop(&p->exits, p->exits.len);
3684 bc_vec_npop(&p->conds, p->conds.len);
3685 bc_vec_npop(&p->ops, p->ops.len);
3686
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003687 return bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003688}
3689
3690static void bc_parse_free(BcParse *p)
3691{
3692 bc_vec_free(&p->flags);
3693 bc_vec_free(&p->exits);
3694 bc_vec_free(&p->conds);
3695 bc_vec_free(&p->ops);
3696 bc_lex_free(&p->l);
3697}
3698
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003699static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003700 BcParseParse parse, BcLexNext next)
3701{
3702 memset(p, 0, sizeof(BcParse));
3703
3704 bc_lex_init(&p->l, next);
3705 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3706 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3707 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3708 bc_vec_pushByte(&p->flags, 0);
3709 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3710
3711 p->parse = parse;
Gavin Howard01055ba2018-11-03 11:00:21 -06003712 p->auto_part = (p->nbraces = 0);
3713 bc_parse_updateFunc(p, func);
3714}
3715
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003716#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003717static BcStatus bc_parse_else(BcParse *p);
3718static BcStatus bc_parse_stmt(BcParse *p);
3719
3720static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3721 size_t *nexprs, bool next)
3722{
3723 BcStatus s = BC_STATUS_SUCCESS;
3724 BcLexType t;
3725 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3726 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3727
3728 while (p->ops.len > start) {
3729
3730 t = BC_PARSE_TOP_OP(p);
3731 if (t == BC_LEX_LPAREN) break;
3732
3733 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3734 if (l >= r && (l != r || !left)) break;
3735
3736 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3737 bc_vec_pop(&p->ops);
3738 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3739 }
3740
3741 bc_vec_push(&p->ops, &type);
3742 if (next) s = bc_lex_next(&p->l);
3743
3744 return s;
3745}
3746
3747static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3748{
3749 BcLexType top;
3750
3751 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3752 top = BC_PARSE_TOP_OP(p);
3753
3754 while (top != BC_LEX_LPAREN) {
3755
3756 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3757
3758 bc_vec_pop(&p->ops);
3759 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3760
3761 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3762 top = BC_PARSE_TOP_OP(p);
3763 }
3764
3765 bc_vec_pop(&p->ops);
3766
3767 return bc_lex_next(&p->l);
3768}
3769
3770static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3771{
3772 BcStatus s;
3773 bool comma = false;
3774 size_t nparams;
3775
3776 s = bc_lex_next(&p->l);
3777 if (s) return s;
3778
3779 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3780
3781 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3782 s = bc_parse_expr(p, flags, bc_parse_next_param);
3783 if (s) return s;
3784
3785 comma = p->l.t.t == BC_LEX_COMMA;
3786 if (comma) {
3787 s = bc_lex_next(&p->l);
3788 if (s) return s;
3789 }
3790 }
3791
3792 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3793 bc_parse_push(p, BC_INST_CALL);
3794 bc_parse_pushIndex(p, nparams);
3795
3796 return BC_STATUS_SUCCESS;
3797}
3798
3799static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3800{
3801 BcStatus s;
3802 BcId entry, *entry_ptr;
3803 size_t idx;
3804
3805 entry.name = name;
3806
3807 s = bc_parse_params(p, flags);
3808 if (s) goto err;
3809
3810 if (p->l.t.t != BC_LEX_RPAREN) {
3811 s = BC_STATUS_PARSE_BAD_TOKEN;
3812 goto err;
3813 }
3814
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003815 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003816
3817 if (idx == BC_VEC_INVALID_IDX) {
3818 name = xstrdup(entry.name);
3819 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003820 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003821 free(entry.name);
3822 }
3823 else
3824 free(name);
3825
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003826 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003827 bc_parse_pushIndex(p, entry_ptr->idx);
3828
3829 return bc_lex_next(&p->l);
3830
3831err:
3832 free(name);
3833 return s;
3834}
3835
3836static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3837{
3838 BcStatus s;
3839 char *name;
3840
3841 name = xstrdup(p->l.t.v.v);
3842 s = bc_lex_next(&p->l);
3843 if (s) goto err;
3844
3845 if (p->l.t.t == BC_LEX_LBRACKET) {
3846
3847 s = bc_lex_next(&p->l);
3848 if (s) goto err;
3849
3850 if (p->l.t.t == BC_LEX_RBRACKET) {
3851
3852 if (!(flags & BC_PARSE_ARRAY)) {
3853 s = BC_STATUS_PARSE_BAD_EXP;
3854 goto err;
3855 }
3856
3857 *type = BC_INST_ARRAY;
3858 }
3859 else {
3860
3861 *type = BC_INST_ARRAY_ELEM;
3862
3863 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3864 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3865 if (s) goto err;
3866 }
3867
3868 s = bc_lex_next(&p->l);
3869 if (s) goto err;
3870 bc_parse_push(p, *type);
3871 bc_parse_pushName(p, name);
3872 }
3873 else if (p->l.t.t == BC_LEX_LPAREN) {
3874
3875 if (flags & BC_PARSE_NOCALL) {
3876 s = BC_STATUS_PARSE_BAD_TOKEN;
3877 goto err;
3878 }
3879
3880 *type = BC_INST_CALL;
3881 s = bc_parse_call(p, name, flags);
3882 }
3883 else {
3884 *type = BC_INST_VAR;
3885 bc_parse_push(p, BC_INST_VAR);
3886 bc_parse_pushName(p, name);
3887 }
3888
3889 return s;
3890
3891err:
3892 free(name);
3893 return s;
3894}
3895
3896static BcStatus bc_parse_read(BcParse *p)
3897{
3898 BcStatus s;
3899
3900 s = bc_lex_next(&p->l);
3901 if (s) return s;
3902 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3903
3904 s = bc_lex_next(&p->l);
3905 if (s) return s;
3906 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3907
3908 bc_parse_push(p, BC_INST_READ);
3909
3910 return bc_lex_next(&p->l);
3911}
3912
3913static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3914 BcInst *prev)
3915{
3916 BcStatus s;
3917
3918 s = bc_lex_next(&p->l);
3919 if (s) return s;
3920 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3921
3922 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3923
3924 s = bc_lex_next(&p->l);
3925 if (s) return s;
3926
3927 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3928 if (s) return s;
3929
3930 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3931
3932 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3933 bc_parse_push(p, *prev);
3934
3935 return bc_lex_next(&p->l);
3936}
3937
3938static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3939{
3940 BcStatus s;
3941
3942 s = bc_lex_next(&p->l);
3943 if (s) return s;
3944
3945 if (p->l.t.t != BC_LEX_LPAREN) {
3946 *type = BC_INST_SCALE;
3947 bc_parse_push(p, BC_INST_SCALE);
3948 return BC_STATUS_SUCCESS;
3949 }
3950
3951 *type = BC_INST_SCALE_FUNC;
3952 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3953
3954 s = bc_lex_next(&p->l);
3955 if (s) return s;
3956
3957 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3958 if (s) return s;
3959 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3960 bc_parse_push(p, BC_INST_SCALE_FUNC);
3961
3962 return bc_lex_next(&p->l);
3963}
3964
3965static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3966 size_t *nexprs, uint8_t flags)
3967{
3968 BcStatus s;
3969 BcLexType type;
3970 char inst;
3971 BcInst etype = *prev;
3972
3973 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3974 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3975 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3976 {
3977 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3978 bc_parse_push(p, inst);
3979 s = bc_lex_next(&p->l);
3980 }
3981 else {
3982
3983 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3984 *paren_expr = true;
3985
3986 s = bc_lex_next(&p->l);
3987 if (s) return s;
3988 type = p->l.t.t;
3989
3990 // Because we parse the next part of the expression
3991 // right here, we need to increment this.
3992 *nexprs = *nexprs + 1;
3993
3994 switch (type) {
3995
3996 case BC_LEX_NAME:
3997 {
3998 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3999 break;
4000 }
4001
4002 case BC_LEX_KEY_IBASE:
4003 case BC_LEX_KEY_LAST:
4004 case BC_LEX_KEY_OBASE:
4005 {
4006 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4007 s = bc_lex_next(&p->l);
4008 break;
4009 }
4010
4011 case BC_LEX_KEY_SCALE:
4012 {
4013 s = bc_lex_next(&p->l);
4014 if (s) return s;
4015 if (p->l.t.t == BC_LEX_LPAREN)
4016 s = BC_STATUS_PARSE_BAD_TOKEN;
4017 else
4018 bc_parse_push(p, BC_INST_SCALE);
4019 break;
4020 }
4021
4022 default:
4023 {
4024 s = BC_STATUS_PARSE_BAD_TOKEN;
4025 break;
4026 }
4027 }
4028
4029 if (!s) bc_parse_push(p, inst);
4030 }
4031
4032 return s;
4033}
4034
4035static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4036 bool rparen, size_t *nexprs)
4037{
4038 BcStatus s;
4039 BcLexType type;
4040 BcInst etype = *prev;
4041
4042 s = bc_lex_next(&p->l);
4043 if (s) return s;
4044
4045 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4046 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4047 BC_LEX_OP_MINUS :
4048 BC_LEX_NEG;
4049 *prev = BC_PARSE_TOKEN_INST(type);
4050
4051 // We can just push onto the op stack because this is the largest
4052 // precedence operator that gets pushed. Inc/dec does not.
4053 if (type != BC_LEX_OP_MINUS)
4054 bc_vec_push(&p->ops, &type);
4055 else
4056 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4057
4058 return s;
4059}
4060
4061static BcStatus bc_parse_string(BcParse *p, char inst)
4062{
4063 char *str = xstrdup(p->l.t.v.v);
4064
4065 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004066 bc_parse_pushIndex(p, G.prog.strs.len);
4067 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004068 bc_parse_push(p, inst);
4069
4070 return bc_lex_next(&p->l);
4071}
4072
4073static BcStatus bc_parse_print(BcParse *p)
4074{
4075 BcStatus s;
4076 BcLexType type;
4077 bool comma = false;
4078
4079 s = bc_lex_next(&p->l);
4080 if (s) return s;
4081
4082 type = p->l.t.t;
4083
4084 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4085 return BC_STATUS_PARSE_BAD_PRINT;
4086
4087 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4088
4089 if (type == BC_LEX_STR)
4090 s = bc_parse_string(p, BC_INST_PRINT_POP);
4091 else {
4092 s = bc_parse_expr(p, 0, bc_parse_next_print);
4093 if (s) return s;
4094 bc_parse_push(p, BC_INST_PRINT_POP);
4095 }
4096
4097 if (s) return s;
4098
4099 comma = p->l.t.t == BC_LEX_COMMA;
4100 if (comma) s = bc_lex_next(&p->l);
4101 type = p->l.t.t;
4102 }
4103
4104 if (s) return s;
4105 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4106
4107 return bc_lex_next(&p->l);
4108}
4109
4110static BcStatus bc_parse_return(BcParse *p)
4111{
4112 BcStatus s;
4113 BcLexType t;
4114 bool paren;
4115
4116 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4117
4118 s = bc_lex_next(&p->l);
4119 if (s) return s;
4120
4121 t = p->l.t.t;
4122 paren = t == BC_LEX_LPAREN;
4123
4124 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4125 bc_parse_push(p, BC_INST_RET0);
4126 else {
4127
4128 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4129 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4130 return s;
4131 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4132 bc_parse_push(p, BC_INST_RET0);
4133 s = bc_lex_next(&p->l);
4134 if (s) return s;
4135 }
4136
4137 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4138 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4139 if (s) return s;
4140 }
4141
4142 bc_parse_push(p, BC_INST_RET);
4143 }
4144
4145 return s;
4146}
4147
4148static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4149{
4150 BcStatus s = BC_STATUS_SUCCESS;
4151
4152 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4153 return BC_STATUS_PARSE_BAD_TOKEN;
4154
4155 if (brace) {
4156
4157 if (p->l.t.t == BC_LEX_RBRACE) {
4158 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4159 --p->nbraces;
4160 s = bc_lex_next(&p->l);
4161 if (s) return s;
4162 }
4163 else
4164 return BC_STATUS_PARSE_BAD_TOKEN;
4165 }
4166
4167 if (BC_PARSE_IF(p)) {
4168
4169 uint8_t *flag_ptr;
4170
4171 while (p->l.t.t == BC_LEX_NLINE) {
4172 s = bc_lex_next(&p->l);
4173 if (s) return s;
4174 }
4175
4176 bc_vec_pop(&p->flags);
4177
4178 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4179 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4180
4181 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4182 }
4183 else if (BC_PARSE_ELSE(p)) {
4184
4185 BcInstPtr *ip;
4186 size_t *label;
4187
4188 bc_vec_pop(&p->flags);
4189
4190 ip = bc_vec_top(&p->exits);
4191 label = bc_vec_item(&p->func->labels, ip->idx);
4192 *label = p->func->code.len;
4193
4194 bc_vec_pop(&p->exits);
4195 }
4196 else if (BC_PARSE_FUNC_INNER(p)) {
4197 bc_parse_push(p, BC_INST_RET0);
4198 bc_parse_updateFunc(p, BC_PROG_MAIN);
4199 bc_vec_pop(&p->flags);
4200 }
4201 else {
4202
4203 BcInstPtr *ip = bc_vec_top(&p->exits);
4204 size_t *label = bc_vec_top(&p->conds);
4205
4206 bc_parse_push(p, BC_INST_JUMP);
4207 bc_parse_pushIndex(p, *label);
4208
4209 label = bc_vec_item(&p->func->labels, ip->idx);
4210 *label = p->func->code.len;
4211
4212 bc_vec_pop(&p->flags);
4213 bc_vec_pop(&p->exits);
4214 bc_vec_pop(&p->conds);
4215 }
4216
4217 return s;
4218}
4219
4220static void bc_parse_startBody(BcParse *p, uint8_t flags)
4221{
4222 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4223 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4224 flags |= BC_PARSE_FLAG_BODY;
4225 bc_vec_push(&p->flags, &flags);
4226}
4227
4228static void bc_parse_noElse(BcParse *p)
4229{
4230 BcInstPtr *ip;
4231 size_t *label;
4232 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4233
4234 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4235
4236 ip = bc_vec_top(&p->exits);
4237 label = bc_vec_item(&p->func->labels, ip->idx);
4238 *label = p->func->code.len;
4239
4240 bc_vec_pop(&p->exits);
4241}
4242
4243static BcStatus bc_parse_if(BcParse *p)
4244{
4245 BcStatus s;
4246 BcInstPtr ip;
4247
4248 s = bc_lex_next(&p->l);
4249 if (s) return s;
4250 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4251
4252 s = bc_lex_next(&p->l);
4253 if (s) return s;
4254 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4255 if (s) return s;
4256 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4257
4258 s = bc_lex_next(&p->l);
4259 if (s) return s;
4260 bc_parse_push(p, BC_INST_JUMP_ZERO);
4261
4262 ip.idx = p->func->labels.len;
4263 ip.func = ip.len = 0;
4264
4265 bc_parse_pushIndex(p, ip.idx);
4266 bc_vec_push(&p->exits, &ip);
4267 bc_vec_push(&p->func->labels, &ip.idx);
4268 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4269
4270 return BC_STATUS_SUCCESS;
4271}
4272
4273static BcStatus bc_parse_else(BcParse *p)
4274{
4275 BcInstPtr ip;
4276
4277 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4278
4279 ip.idx = p->func->labels.len;
4280 ip.func = ip.len = 0;
4281
4282 bc_parse_push(p, BC_INST_JUMP);
4283 bc_parse_pushIndex(p, ip.idx);
4284
4285 bc_parse_noElse(p);
4286
4287 bc_vec_push(&p->exits, &ip);
4288 bc_vec_push(&p->func->labels, &ip.idx);
4289 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4290
4291 return bc_lex_next(&p->l);
4292}
4293
4294static BcStatus bc_parse_while(BcParse *p)
4295{
4296 BcStatus s;
4297 BcInstPtr ip;
4298
4299 s = bc_lex_next(&p->l);
4300 if (s) return s;
4301 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4302 s = bc_lex_next(&p->l);
4303 if (s) return s;
4304
4305 ip.idx = p->func->labels.len;
4306
4307 bc_vec_push(&p->func->labels, &p->func->code.len);
4308 bc_vec_push(&p->conds, &ip.idx);
4309
4310 ip.idx = p->func->labels.len;
4311 ip.func = 1;
4312 ip.len = 0;
4313
4314 bc_vec_push(&p->exits, &ip);
4315 bc_vec_push(&p->func->labels, &ip.idx);
4316
4317 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4318 if (s) return s;
4319 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4320 s = bc_lex_next(&p->l);
4321 if (s) return s;
4322
4323 bc_parse_push(p, BC_INST_JUMP_ZERO);
4324 bc_parse_pushIndex(p, ip.idx);
4325 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4326
4327 return BC_STATUS_SUCCESS;
4328}
4329
4330static BcStatus bc_parse_for(BcParse *p)
4331{
4332 BcStatus s;
4333 BcInstPtr ip;
4334 size_t cond_idx, exit_idx, body_idx, update_idx;
4335
4336 s = bc_lex_next(&p->l);
4337 if (s) return s;
4338 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4339 s = bc_lex_next(&p->l);
4340 if (s) return s;
4341
4342 if (p->l.t.t != BC_LEX_SCOLON)
4343 s = bc_parse_expr(p, 0, bc_parse_next_for);
4344 else
4345 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4346
4347 if (s) return s;
4348 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4349 s = bc_lex_next(&p->l);
4350 if (s) return s;
4351
4352 cond_idx = p->func->labels.len;
4353 update_idx = cond_idx + 1;
4354 body_idx = update_idx + 1;
4355 exit_idx = body_idx + 1;
4356
4357 bc_vec_push(&p->func->labels, &p->func->code.len);
4358
4359 if (p->l.t.t != BC_LEX_SCOLON)
4360 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4361 else
4362 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4363
4364 if (s) return s;
4365 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4366
4367 s = bc_lex_next(&p->l);
4368 if (s) return s;
4369
4370 bc_parse_push(p, BC_INST_JUMP_ZERO);
4371 bc_parse_pushIndex(p, exit_idx);
4372 bc_parse_push(p, BC_INST_JUMP);
4373 bc_parse_pushIndex(p, body_idx);
4374
4375 ip.idx = p->func->labels.len;
4376
4377 bc_vec_push(&p->conds, &update_idx);
4378 bc_vec_push(&p->func->labels, &p->func->code.len);
4379
4380 if (p->l.t.t != BC_LEX_RPAREN)
4381 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4382 else
4383 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4384
4385 if (s) return s;
4386
4387 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4388 bc_parse_push(p, BC_INST_JUMP);
4389 bc_parse_pushIndex(p, cond_idx);
4390 bc_vec_push(&p->func->labels, &p->func->code.len);
4391
4392 ip.idx = exit_idx;
4393 ip.func = 1;
4394 ip.len = 0;
4395
4396 bc_vec_push(&p->exits, &ip);
4397 bc_vec_push(&p->func->labels, &ip.idx);
4398 bc_lex_next(&p->l);
4399 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4400
4401 return BC_STATUS_SUCCESS;
4402}
4403
4404static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4405{
4406 BcStatus s;
4407 size_t i;
4408 BcInstPtr *ip;
4409
4410 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4411
4412 if (type == BC_LEX_KEY_BREAK) {
4413
4414 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4415
4416 i = p->exits.len - 1;
4417 ip = bc_vec_item(&p->exits, i);
4418
4419 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4420 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4421
4422 i = ip->idx;
4423 }
4424 else
4425 i = *((size_t *) bc_vec_top(&p->conds));
4426
4427 bc_parse_push(p, BC_INST_JUMP);
4428 bc_parse_pushIndex(p, i);
4429
4430 s = bc_lex_next(&p->l);
4431 if (s) return s;
4432
4433 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4434 return BC_STATUS_PARSE_BAD_TOKEN;
4435
4436 return bc_lex_next(&p->l);
4437}
4438
4439static BcStatus bc_parse_func(BcParse *p)
4440{
4441 BcStatus s;
4442 bool var, comma = false;
4443 uint8_t flags;
4444 char *name;
4445
4446 s = bc_lex_next(&p->l);
4447 if (s) return s;
4448 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4449
4450 name = xstrdup(p->l.t.v.v);
4451 bc_parse_addFunc(p, name, &p->fidx);
4452
4453 s = bc_lex_next(&p->l);
4454 if (s) return s;
4455 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4456 s = bc_lex_next(&p->l);
4457 if (s) return s;
4458
4459 while (p->l.t.t != BC_LEX_RPAREN) {
4460
4461 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4462
4463 ++p->func->nparams;
4464
4465 name = xstrdup(p->l.t.v.v);
4466 s = bc_lex_next(&p->l);
4467 if (s) goto err;
4468
4469 var = p->l.t.t != BC_LEX_LBRACKET;
4470
4471 if (!var) {
4472
4473 s = bc_lex_next(&p->l);
4474 if (s) goto err;
4475
4476 if (p->l.t.t != BC_LEX_RBRACKET) {
4477 s = BC_STATUS_PARSE_BAD_FUNC;
4478 goto err;
4479 }
4480
4481 s = bc_lex_next(&p->l);
4482 if (s) goto err;
4483 }
4484
4485 comma = p->l.t.t == BC_LEX_COMMA;
4486 if (comma) {
4487 s = bc_lex_next(&p->l);
4488 if (s) goto err;
4489 }
4490
4491 s = bc_func_insert(p->func, name, var);
4492 if (s) goto err;
4493 }
4494
4495 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4496
4497 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4498 bc_parse_startBody(p, flags);
4499
4500 s = bc_lex_next(&p->l);
4501 if (s) return s;
4502
4503 if (p->l.t.t != BC_LEX_LBRACE)
4504 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4505
4506 return s;
4507
4508err:
4509 free(name);
4510 return s;
4511}
4512
4513static BcStatus bc_parse_auto(BcParse *p)
4514{
4515 BcStatus s;
4516 bool comma, var, one;
4517 char *name;
4518
4519 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4520 s = bc_lex_next(&p->l);
4521 if (s) return s;
4522
4523 p->auto_part = comma = false;
4524 one = p->l.t.t == BC_LEX_NAME;
4525
4526 while (p->l.t.t == BC_LEX_NAME) {
4527
4528 name = xstrdup(p->l.t.v.v);
4529 s = bc_lex_next(&p->l);
4530 if (s) goto err;
4531
4532 var = p->l.t.t != BC_LEX_LBRACKET;
4533 if (!var) {
4534
4535 s = bc_lex_next(&p->l);
4536 if (s) goto err;
4537
4538 if (p->l.t.t != BC_LEX_RBRACKET) {
4539 s = BC_STATUS_PARSE_BAD_FUNC;
4540 goto err;
4541 }
4542
4543 s = bc_lex_next(&p->l);
4544 if (s) goto err;
4545 }
4546
4547 comma = p->l.t.t == BC_LEX_COMMA;
4548 if (comma) {
4549 s = bc_lex_next(&p->l);
4550 if (s) goto err;
4551 }
4552
4553 s = bc_func_insert(p->func, name, var);
4554 if (s) goto err;
4555 }
4556
4557 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4558 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4559
4560 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4561 return BC_STATUS_PARSE_BAD_TOKEN;
4562
4563 return bc_lex_next(&p->l);
4564
4565err:
4566 free(name);
4567 return s;
4568}
4569
4570static BcStatus bc_parse_body(BcParse *p, bool brace)
4571{
4572 BcStatus s = BC_STATUS_SUCCESS;
4573 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4574
4575 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4576
4577 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4578
4579 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4580 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4581
4582 if (!p->auto_part) {
4583 s = bc_parse_auto(p);
4584 if (s) return s;
4585 }
4586
4587 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4588 }
4589 else {
4590 s = bc_parse_stmt(p);
4591 if (!s && !brace) s = bc_parse_endBody(p, false);
4592 }
4593
4594 return s;
4595}
4596
4597static BcStatus bc_parse_stmt(BcParse *p)
4598{
4599 BcStatus s = BC_STATUS_SUCCESS;
4600
4601 switch (p->l.t.t) {
4602
4603 case BC_LEX_NLINE:
4604 {
4605 return bc_lex_next(&p->l);
4606 }
4607
4608 case BC_LEX_KEY_ELSE:
4609 {
4610 p->auto_part = false;
4611 break;
4612 }
4613
4614 case BC_LEX_LBRACE:
4615 {
4616 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4617
4618 ++p->nbraces;
4619 s = bc_lex_next(&p->l);
4620 if (s) return s;
4621
4622 return bc_parse_body(p, true);
4623 }
4624
4625 case BC_LEX_KEY_AUTO:
4626 {
4627 return bc_parse_auto(p);
4628 }
4629
4630 default:
4631 {
4632 p->auto_part = false;
4633
4634 if (BC_PARSE_IF_END(p)) {
4635 bc_parse_noElse(p);
4636 return BC_STATUS_SUCCESS;
4637 }
4638 else if (BC_PARSE_BODY(p))
4639 return bc_parse_body(p, false);
4640
4641 break;
4642 }
4643 }
4644
4645 switch (p->l.t.t) {
4646
4647 case BC_LEX_OP_INC:
4648 case BC_LEX_OP_DEC:
4649 case BC_LEX_OP_MINUS:
4650 case BC_LEX_OP_BOOL_NOT:
4651 case BC_LEX_LPAREN:
4652 case BC_LEX_NAME:
4653 case BC_LEX_NUMBER:
4654 case BC_LEX_KEY_IBASE:
4655 case BC_LEX_KEY_LAST:
4656 case BC_LEX_KEY_LENGTH:
4657 case BC_LEX_KEY_OBASE:
4658 case BC_LEX_KEY_READ:
4659 case BC_LEX_KEY_SCALE:
4660 case BC_LEX_KEY_SQRT:
4661 {
4662 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4663 break;
4664 }
4665
4666 case BC_LEX_KEY_ELSE:
4667 {
4668 s = bc_parse_else(p);
4669 break;
4670 }
4671
4672 case BC_LEX_SCOLON:
4673 {
4674 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4675 break;
4676 }
4677
4678 case BC_LEX_RBRACE:
4679 {
4680 s = bc_parse_endBody(p, true);
4681 break;
4682 }
4683
4684 case BC_LEX_STR:
4685 {
4686 s = bc_parse_string(p, BC_INST_PRINT_STR);
4687 break;
4688 }
4689
4690 case BC_LEX_KEY_BREAK:
4691 case BC_LEX_KEY_CONTINUE:
4692 {
4693 s = bc_parse_loopExit(p, p->l.t.t);
4694 break;
4695 }
4696
4697 case BC_LEX_KEY_FOR:
4698 {
4699 s = bc_parse_for(p);
4700 break;
4701 }
4702
4703 case BC_LEX_KEY_HALT:
4704 {
4705 bc_parse_push(p, BC_INST_HALT);
4706 s = bc_lex_next(&p->l);
4707 break;
4708 }
4709
4710 case BC_LEX_KEY_IF:
4711 {
4712 s = bc_parse_if(p);
4713 break;
4714 }
4715
4716 case BC_LEX_KEY_LIMITS:
4717 {
4718 s = bc_lex_next(&p->l);
4719 if (s) return s;
4720 s = BC_STATUS_LIMITS;
4721 break;
4722 }
4723
4724 case BC_LEX_KEY_PRINT:
4725 {
4726 s = bc_parse_print(p);
4727 break;
4728 }
4729
4730 case BC_LEX_KEY_QUIT:
4731 {
4732 // Quit is a compile-time command. We don't exit directly,
4733 // so the vm can clean up. Limits do the same thing.
4734 s = BC_STATUS_QUIT;
4735 break;
4736 }
4737
4738 case BC_LEX_KEY_RETURN:
4739 {
4740 s = bc_parse_return(p);
4741 break;
4742 }
4743
4744 case BC_LEX_KEY_WHILE:
4745 {
4746 s = bc_parse_while(p);
4747 break;
4748 }
4749
4750 default:
4751 {
4752 s = BC_STATUS_PARSE_BAD_TOKEN;
4753 break;
4754 }
4755 }
4756
4757 return s;
4758}
4759
4760static BcStatus bc_parse_parse(BcParse *p)
4761{
4762 BcStatus s;
4763
4764 if (p->l.t.t == BC_LEX_EOF)
4765 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4766 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4767 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4768 s = bc_parse_func(p);
4769 }
4770 else
4771 s = bc_parse_stmt(p);
4772
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004773 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
Gavin Howard01055ba2018-11-03 11:00:21 -06004774 s = bc_parse_reset(p, s);
4775
4776 return s;
4777}
4778
4779static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4780{
4781 BcStatus s = BC_STATUS_SUCCESS;
4782 BcInst prev = BC_INST_PRINT;
4783 BcLexType top, t = p->l.t.t;
4784 size_t nexprs = 0, ops_bgn = p->ops.len;
4785 uint32_t i, nparens, nrelops;
4786 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4787
4788 paren_first = p->l.t.t == BC_LEX_LPAREN;
4789 nparens = nrelops = 0;
4790 paren_expr = rprn = done = get_token = assign = false;
4791 bin_last = true;
4792
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004793 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004794 switch (t) {
4795
4796 case BC_LEX_OP_INC:
4797 case BC_LEX_OP_DEC:
4798 {
4799 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4800 rprn = get_token = bin_last = false;
4801 break;
4802 }
4803
4804 case BC_LEX_OP_MINUS:
4805 {
4806 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4807 rprn = get_token = false;
4808 bin_last = prev == BC_INST_MINUS;
4809 break;
4810 }
4811
4812 case BC_LEX_OP_ASSIGN_POWER:
4813 case BC_LEX_OP_ASSIGN_MULTIPLY:
4814 case BC_LEX_OP_ASSIGN_DIVIDE:
4815 case BC_LEX_OP_ASSIGN_MODULUS:
4816 case BC_LEX_OP_ASSIGN_PLUS:
4817 case BC_LEX_OP_ASSIGN_MINUS:
4818 case BC_LEX_OP_ASSIGN:
4819 {
4820 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4821 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4822 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4823 {
4824 s = BC_STATUS_PARSE_BAD_ASSIGN;
4825 break;
4826 }
4827 }
4828 // Fallthrough.
4829 case BC_LEX_OP_POWER:
4830 case BC_LEX_OP_MULTIPLY:
4831 case BC_LEX_OP_DIVIDE:
4832 case BC_LEX_OP_MODULUS:
4833 case BC_LEX_OP_PLUS:
4834 case BC_LEX_OP_REL_EQ:
4835 case BC_LEX_OP_REL_LE:
4836 case BC_LEX_OP_REL_GE:
4837 case BC_LEX_OP_REL_NE:
4838 case BC_LEX_OP_REL_LT:
4839 case BC_LEX_OP_REL_GT:
4840 case BC_LEX_OP_BOOL_NOT:
4841 case BC_LEX_OP_BOOL_OR:
4842 case BC_LEX_OP_BOOL_AND:
4843 {
4844 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4845 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4846 {
4847 return BC_STATUS_PARSE_BAD_EXP;
4848 }
4849
4850 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4851 prev = BC_PARSE_TOKEN_INST(t);
4852 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4853 rprn = get_token = false;
4854 bin_last = t != BC_LEX_OP_BOOL_NOT;
4855
4856 break;
4857 }
4858
4859 case BC_LEX_LPAREN:
4860 {
4861 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4862
4863 ++nparens;
4864 paren_expr = rprn = bin_last = false;
4865 get_token = true;
4866 bc_vec_push(&p->ops, &t);
4867
4868 break;
4869 }
4870
4871 case BC_LEX_RPAREN:
4872 {
4873 if (bin_last || prev == BC_INST_BOOL_NOT)
4874 return BC_STATUS_PARSE_BAD_EXP;
4875
4876 if (nparens == 0) {
4877 s = BC_STATUS_SUCCESS;
4878 done = true;
4879 get_token = false;
4880 break;
4881 }
4882 else if (!paren_expr)
4883 return BC_STATUS_PARSE_EMPTY_EXP;
4884
4885 --nparens;
4886 paren_expr = rprn = true;
4887 get_token = bin_last = false;
4888
4889 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4890
4891 break;
4892 }
4893
4894 case BC_LEX_NAME:
4895 {
4896 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4897
4898 paren_expr = true;
4899 rprn = get_token = bin_last = false;
4900 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4901 ++nexprs;
4902
4903 break;
4904 }
4905
4906 case BC_LEX_NUMBER:
4907 {
4908 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4909
4910 bc_parse_number(p, &prev, &nexprs);
4911 paren_expr = get_token = true;
4912 rprn = bin_last = false;
4913
4914 break;
4915 }
4916
4917 case BC_LEX_KEY_IBASE:
4918 case BC_LEX_KEY_LAST:
4919 case BC_LEX_KEY_OBASE:
4920 {
4921 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4922
4923 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4924 bc_parse_push(p, (char) prev);
4925
4926 paren_expr = get_token = true;
4927 rprn = bin_last = false;
4928 ++nexprs;
4929
4930 break;
4931 }
4932
4933 case BC_LEX_KEY_LENGTH:
4934 case BC_LEX_KEY_SQRT:
4935 {
4936 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4937
4938 s = bc_parse_builtin(p, t, flags, &prev);
4939 paren_expr = true;
4940 rprn = get_token = bin_last = false;
4941 ++nexprs;
4942
4943 break;
4944 }
4945
4946 case BC_LEX_KEY_READ:
4947 {
4948 if (BC_PARSE_LEAF(prev, rprn))
4949 return BC_STATUS_PARSE_BAD_EXP;
4950 else if (flags & BC_PARSE_NOREAD)
4951 s = BC_STATUS_EXEC_REC_READ;
4952 else
4953 s = bc_parse_read(p);
4954
4955 paren_expr = true;
4956 rprn = get_token = bin_last = false;
4957 ++nexprs;
4958 prev = BC_INST_READ;
4959
4960 break;
4961 }
4962
4963 case BC_LEX_KEY_SCALE:
4964 {
4965 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4966
4967 s = bc_parse_scale(p, &prev, flags);
4968 paren_expr = true;
4969 rprn = get_token = bin_last = false;
4970 ++nexprs;
4971 prev = BC_INST_SCALE;
4972
4973 break;
4974 }
4975
4976 default:
4977 {
4978 s = BC_STATUS_PARSE_BAD_TOKEN;
4979 break;
4980 }
4981 }
4982
4983 if (!s && get_token) s = bc_lex_next(&p->l);
4984 }
4985
4986 if (s) return s;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004987 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06004988
4989 while (p->ops.len > ops_bgn) {
4990
4991 top = BC_PARSE_TOP_OP(p);
4992 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4993
4994 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4995 return BC_STATUS_PARSE_BAD_EXP;
4996
4997 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4998
4999 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5000 bc_vec_pop(&p->ops);
5001 }
5002
5003 s = BC_STATUS_PARSE_BAD_EXP;
5004 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5005
5006 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5007 if (s) return s;
5008
5009 if (!(flags & BC_PARSE_REL) && nrelops) {
5010 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5011 if (s) return s;
5012 }
5013 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5014 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5015 if (s) return s;
5016 }
5017
5018 if (flags & BC_PARSE_PRINT) {
5019 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5020 bc_parse_push(p, BC_INST_POP);
5021 }
5022
5023 return s;
5024}
5025
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005026static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005027{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005028 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005029}
5030
5031static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5032{
5033 return bc_parse_expr(p, flags, bc_parse_next_read);
5034}
5035#endif // ENABLE_BC
5036
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005037#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005038static BcStatus dc_parse_register(BcParse *p)
5039{
5040 BcStatus s;
5041 char *name;
5042
5043 s = bc_lex_next(&p->l);
5044 if (s) return s;
5045 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5046
5047 name = xstrdup(p->l.t.v.v);
5048 bc_parse_pushName(p, name);
5049
5050 return s;
5051}
5052
5053static BcStatus dc_parse_string(BcParse *p)
5054{
5055 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005056 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005057
5058 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5059 name = xstrdup(b);
5060
5061 str = xstrdup(p->l.t.v.v);
5062 bc_parse_push(p, BC_INST_STR);
5063 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005064 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005065 bc_parse_addFunc(p, name, &idx);
5066
5067 return bc_lex_next(&p->l);
5068}
5069
5070static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5071{
5072 BcStatus s;
5073
5074 bc_parse_push(p, inst);
5075 if (name) {
5076 s = dc_parse_register(p);
5077 if (s) return s;
5078 }
5079
5080 if (store) {
5081 bc_parse_push(p, BC_INST_SWAP);
5082 bc_parse_push(p, BC_INST_ASSIGN);
5083 bc_parse_push(p, BC_INST_POP);
5084 }
5085
5086 return bc_lex_next(&p->l);
5087}
5088
5089static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5090{
5091 BcStatus s;
5092
5093 bc_parse_push(p, inst);
5094 bc_parse_push(p, BC_INST_EXEC_COND);
5095
5096 s = dc_parse_register(p);
5097 if (s) return s;
5098
5099 s = bc_lex_next(&p->l);
5100 if (s) return s;
5101
5102 if (p->l.t.t == BC_LEX_ELSE) {
5103 s = dc_parse_register(p);
5104 if (s) return s;
5105 s = bc_lex_next(&p->l);
5106 }
5107 else
5108 bc_parse_push(p, BC_PARSE_STREND);
5109
5110 return s;
5111}
5112
5113static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5114{
5115 BcStatus s = BC_STATUS_SUCCESS;
5116 BcInst prev;
5117 uint8_t inst;
5118 bool assign, get_token = false;
5119
5120 switch (t) {
5121
5122 case BC_LEX_OP_REL_EQ:
5123 case BC_LEX_OP_REL_LE:
5124 case BC_LEX_OP_REL_GE:
5125 case BC_LEX_OP_REL_NE:
5126 case BC_LEX_OP_REL_LT:
5127 case BC_LEX_OP_REL_GT:
5128 {
5129 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5130 break;
5131 }
5132
5133 case BC_LEX_SCOLON:
5134 case BC_LEX_COLON:
5135 {
5136 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5137 break;
5138 }
5139
5140 case BC_LEX_STR:
5141 {
5142 s = dc_parse_string(p);
5143 break;
5144 }
5145
5146 case BC_LEX_NEG:
5147 case BC_LEX_NUMBER:
5148 {
5149 if (t == BC_LEX_NEG) {
5150 s = bc_lex_next(&p->l);
5151 if (s) return s;
5152 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5153 }
5154
5155 bc_parse_number(p, &prev, &p->nbraces);
5156
5157 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5158 get_token = true;
5159
5160 break;
5161 }
5162
5163 case BC_LEX_KEY_READ:
5164 {
5165 if (flags & BC_PARSE_NOREAD)
5166 s = BC_STATUS_EXEC_REC_READ;
5167 else
5168 bc_parse_push(p, BC_INST_READ);
5169 get_token = true;
5170 break;
5171 }
5172
5173 case BC_LEX_OP_ASSIGN:
5174 case BC_LEX_STORE_PUSH:
5175 {
5176 assign = t == BC_LEX_OP_ASSIGN;
5177 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5178 s = dc_parse_mem(p, inst, true, assign);
5179 break;
5180 }
5181
5182 case BC_LEX_LOAD:
5183 case BC_LEX_LOAD_POP:
5184 {
5185 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5186 s = dc_parse_mem(p, inst, true, false);
5187 break;
5188 }
5189
5190 case BC_LEX_STORE_IBASE:
5191 case BC_LEX_STORE_SCALE:
5192 case BC_LEX_STORE_OBASE:
5193 {
5194 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5195 s = dc_parse_mem(p, inst, false, true);
5196 break;
5197 }
5198
5199 default:
5200 {
5201 s = BC_STATUS_PARSE_BAD_TOKEN;
5202 get_token = true;
5203 break;
5204 }
5205 }
5206
5207 if (!s && get_token) s = bc_lex_next(&p->l);
5208
5209 return s;
5210}
5211
5212static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5213{
5214 BcStatus s = BC_STATUS_SUCCESS;
5215 BcInst inst;
5216 BcLexType t;
5217
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005218 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005219
5220 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5221
5222 inst = dc_parse_insts[t];
5223
5224 if (inst != BC_INST_INVALID) {
5225 bc_parse_push(p, inst);
5226 s = bc_lex_next(&p->l);
5227 }
5228 else
5229 s = dc_parse_token(p, t, flags);
5230 }
5231
5232 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5233 bc_parse_push(p, BC_INST_POP_EXEC);
5234
5235 return s;
5236}
5237
5238static BcStatus dc_parse_parse(BcParse *p)
5239{
5240 BcStatus s;
5241
5242 if (p->l.t.t == BC_LEX_EOF)
5243 s = BC_STATUS_LEX_EOF;
5244 else
5245 s = dc_parse_expr(p, 0);
5246
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01005247 if (s || G_interrupt) s = bc_parse_reset(p, s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005248
5249 return s;
5250}
5251
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005252static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005253{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005254 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005255}
5256#endif // ENABLE_DC
5257
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005258static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005259{
5260 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005261 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005262 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005263 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005264 }
5265}
5266
5267static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5268{
5269 if (IS_BC) {
5270 return bc_parse_expression(p, flags);
5271 } else {
5272 return dc_parse_expr(p, flags);
5273 }
5274}
5275
Denys Vlasenkodf515392018-12-02 19:27:48 +01005276static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005277{
5278 BcStatus s;
5279 BcId e, *ptr;
5280 BcVec *v, *map;
5281 size_t i;
5282 BcResultData data;
5283 bool new;
5284
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005285 v = var ? &G.prog.vars : &G.prog.arrs;
5286 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005287
5288 e.name = id;
5289 e.idx = v->len;
5290 s = bc_map_insert(map, &e, &i);
5291 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5292
5293 if (new) {
5294 bc_array_init(&data.v, var);
5295 bc_vec_push(v, &data.v);
5296 }
5297
5298 ptr = bc_vec_item(map, i);
5299 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005300 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005301}
5302
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005303static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005304{
5305 BcStatus s = BC_STATUS_SUCCESS;
5306
5307 switch (r->t) {
5308
5309 case BC_RESULT_STR:
5310 case BC_RESULT_TEMP:
5311 case BC_RESULT_IBASE:
5312 case BC_RESULT_SCALE:
5313 case BC_RESULT_OBASE:
5314 {
5315 *num = &r->d.n;
5316 break;
5317 }
5318
5319 case BC_RESULT_CONSTANT:
5320 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005321 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005322 size_t base_t, len = strlen(*str);
5323 BcNum *base;
5324
5325 bc_num_init(&r->d.n, len);
5326
5327 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005328 base = hex ? &G.prog.hexb : &G.prog.ib;
5329 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005330 s = bc_num_parse(&r->d.n, *str, base, base_t);
5331
5332 if (s) {
5333 bc_num_free(&r->d.n);
5334 return s;
5335 }
5336
5337 *num = &r->d.n;
5338 r->t = BC_RESULT_TEMP;
5339
5340 break;
5341 }
5342
5343 case BC_RESULT_VAR:
5344 case BC_RESULT_ARRAY:
5345 case BC_RESULT_ARRAY_ELEM:
5346 {
5347 BcVec *v;
5348
Denys Vlasenkodf515392018-12-02 19:27:48 +01005349 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005350
5351 if (r->t == BC_RESULT_ARRAY_ELEM) {
5352 v = bc_vec_top(v);
5353 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5354 *num = bc_vec_item(v, r->d.id.idx);
5355 }
5356 else
5357 *num = bc_vec_top(v);
5358
5359 break;
5360 }
5361
5362 case BC_RESULT_LAST:
5363 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005364 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005365 break;
5366 }
5367
5368 case BC_RESULT_ONE:
5369 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005370 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005371 break;
5372 }
5373 }
5374
5375 return s;
5376}
5377
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005378static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005379 BcResult **r, BcNum **rn, bool assign)
5380{
5381 BcStatus s;
5382 bool hex;
5383 BcResultType lt, rt;
5384
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005385 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005386
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005387 *r = bc_vec_item_rev(&G.prog.results, 0);
5388 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005389
5390 lt = (*l)->t;
5391 rt = (*r)->t;
5392 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5393
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005394 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005395 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005396 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005397 if (s) return s;
5398
5399 // We run this again under these conditions in case any vector has been
5400 // reallocated out from under the BcNums or arrays we had.
5401 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005402 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005403 if (s) return s;
5404 }
5405
5406 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5407 return BC_STATUS_EXEC_BAD_TYPE;
5408 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5409
Gavin Howard01055ba2018-11-03 11:00:21 -06005410 return s;
5411}
5412
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005413static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005414{
5415 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005416 bc_vec_pop(&G.prog.results);
5417 bc_vec_pop(&G.prog.results);
5418 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005419}
5420
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005421static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005422{
5423 BcStatus s;
5424
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005425 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5426 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005427
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005428 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005429 if (s) return s;
5430
Gavin Howard01055ba2018-11-03 11:00:21 -06005431 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5432
5433 return s;
5434}
5435
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005436static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005437{
5438 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005439 bc_vec_pop(&G.prog.results);
5440 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005441}
5442
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005443static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005444{
5445 BcStatus s;
5446 BcResult *opd1, *opd2, res;
5447 BcNum *n1, *n2 = NULL;
5448
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005449 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005450 if (s) return s;
5451 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5452
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005453 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005454 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005455 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005456
5457 return s;
5458
5459err:
5460 bc_num_free(&res.d.n);
5461 return s;
5462}
5463
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005464static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005465{
5466 BcStatus s;
5467 BcParse parse;
5468 BcVec buf;
5469 BcInstPtr ip;
5470 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005471 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005472
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005473 for (i = 0; i < G.prog.stack.len; ++i) {
5474 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Gavin Howard01055ba2018-11-03 11:00:21 -06005475 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5476 }
5477
5478 bc_vec_npop(&f->code, f->code.len);
5479 bc_vec_init(&buf, sizeof(char), NULL);
5480
5481 s = bc_read_line(&buf, "read> ");
5482 if (s) goto io_err;
5483
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005484 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005485 bc_lex_file(&parse.l, bc_program_stdin_name);
5486
5487 s = bc_parse_text(&parse, buf.v);
5488 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005489 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005490 if (s) goto exec_err;
5491
5492 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5493 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5494 goto exec_err;
5495 }
5496
5497 ip.func = BC_PROG_READ;
5498 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005499 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005500
5501 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005502 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005503
5504 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005505 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005506
5507exec_err:
5508 bc_parse_free(&parse);
5509io_err:
5510 bc_vec_free(&buf);
5511 return s;
5512}
5513
5514static size_t bc_program_index(char *code, size_t *bgn)
5515{
5516 char amt = code[(*bgn)++], i = 0;
5517 size_t res = 0;
5518
5519 for (; i < amt; ++i, ++(*bgn))
5520 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5521
5522 return res;
5523}
5524
5525static char *bc_program_name(char *code, size_t *bgn)
5526{
5527 size_t i;
5528 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5529
5530 s = xmalloc(ptr - str + 1);
5531 c = code[(*bgn)++];
5532
5533 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5534 s[i] = c;
5535
5536 s[i] = '\0';
5537
5538 return s;
5539}
5540
5541static void bc_program_printString(const char *str, size_t *nchars)
5542{
5543 size_t i, len = strlen(str);
5544
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005545#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005546 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005547 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005548 return;
5549 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005550#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005551
5552 for (i = 0; i < len; ++i, ++(*nchars)) {
5553
5554 int c = str[i];
5555
5556 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005557 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005558 else {
5559
5560 c = str[++i];
5561
5562 switch (c) {
5563
5564 case 'a':
5565 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005566 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005567 break;
5568 }
5569
5570 case 'b':
5571 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005572 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005573 break;
5574 }
5575
5576 case '\\':
5577 case 'e':
5578 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005579 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005580 break;
5581 }
5582
5583 case 'f':
5584 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005585 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005586 break;
5587 }
5588
5589 case 'n':
5590 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005591 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005592 *nchars = SIZE_MAX;
5593 break;
5594 }
5595
5596 case 'r':
5597 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005598 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005599 break;
5600 }
5601
5602 case 'q':
5603 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005604 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005605 break;
5606 }
5607
5608 case 't':
5609 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005610 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005611 break;
5612 }
5613
5614 default:
5615 {
5616 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005617 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005618 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005619 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005620 break;
5621 }
5622 }
5623 }
5624 }
5625}
5626
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005627static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005628{
5629 BcStatus s = BC_STATUS_SUCCESS;
5630 BcResult *r;
5631 size_t len, i;
5632 char *str;
5633 BcNum *num = NULL;
5634 bool pop = inst != BC_INST_PRINT;
5635
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005636 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005637
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005638 r = bc_vec_item_rev(&G.prog.results, idx);
5639 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005640 if (s) return s;
5641
5642 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005643 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5644 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005645 }
5646 else {
5647
5648 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005650
5651 if (inst == BC_INST_PRINT_STR) {
5652 for (i = 0, len = strlen(str); i < len; ++i) {
5653 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005654 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005655 if (c == '\n') G.prog.nchars = SIZE_MAX;
5656 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005657 }
5658 }
5659 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005660 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005661 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005662 }
5663 }
5664
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005665 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005666
5667 return s;
5668}
5669
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005670static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005671{
5672 BcStatus s;
5673 BcResult res, *ptr;
5674 BcNum *num = NULL;
5675
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005676 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005677 if (s) return s;
5678
5679 bc_num_init(&res.d.n, num->len);
5680 bc_num_copy(&res.d.n, num);
5681 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5682
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005683 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005684
5685 return s;
5686}
5687
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005688static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005689{
5690 BcStatus s;
5691 BcResult *opd1, *opd2, res;
5692 BcNum *n1, *n2;
5693 bool cond = 0;
5694 ssize_t cmp;
5695
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005696 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005697 if (s) return s;
5698 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5699
5700 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005701 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005702 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005703 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005704 else {
5705
5706 cmp = bc_num_cmp(n1, n2);
5707
5708 switch (inst) {
5709
5710 case BC_INST_REL_EQ:
5711 {
5712 cond = cmp == 0;
5713 break;
5714 }
5715
5716 case BC_INST_REL_LE:
5717 {
5718 cond = cmp <= 0;
5719 break;
5720 }
5721
5722 case BC_INST_REL_GE:
5723 {
5724 cond = cmp >= 0;
5725 break;
5726 }
5727
5728 case BC_INST_REL_NE:
5729 {
5730 cond = cmp != 0;
5731 break;
5732 }
5733
5734 case BC_INST_REL_LT:
5735 {
5736 cond = cmp < 0;
5737 break;
5738 }
5739
5740 case BC_INST_REL_GT:
5741 {
5742 cond = cmp > 0;
5743 break;
5744 }
5745 }
5746 }
5747
5748 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5749
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005750 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005751
5752 return s;
5753}
5754
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005755#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005756static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005757 bool push)
5758{
5759 BcNum n2;
5760 BcResult res;
5761
5762 memset(&n2, 0, sizeof(BcNum));
5763 n2.rdx = res.d.id.idx = r->d.id.idx;
5764 res.t = BC_RESULT_STR;
5765
5766 if (!push) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005767 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005768 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005769 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005770 }
5771
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005772 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005773
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005774 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005775 bc_vec_push(v, &n2);
5776
5777 return BC_STATUS_SUCCESS;
5778}
5779#endif // ENABLE_DC
5780
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005781static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005782{
5783 BcStatus s;
5784 BcResult *ptr, r;
5785 BcVec *v;
5786 BcNum *n;
5787
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005788 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005789
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005790 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005791 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005792 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005793
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005794#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005795 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005796 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005797#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005798
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005799 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005800 if (s) return s;
5801
5802 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005803 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005804
5805 if (var) {
5806 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5807 bc_num_copy(&r.d.n, n);
5808 }
5809 else {
5810 bc_array_init(&r.d.v, true);
5811 bc_array_copy(&r.d.v, (BcVec *) n);
5812 }
5813
5814 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005815 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005816
5817 return s;
5818}
5819
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005820static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005821{
5822 BcStatus s;
5823 BcResult *left, *right, res;
5824 BcNum *l = NULL, *r = NULL;
5825 unsigned long val, max;
5826 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5827
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005828 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005829 if (s) return s;
5830
5831 ib = left->t == BC_RESULT_IBASE;
5832 sc = left->t == BC_RESULT_SCALE;
5833
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005834#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005835
5836 if (right->t == BC_RESULT_STR) {
5837
5838 BcVec *v;
5839
5840 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005841 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005842
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005843 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005844 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005845#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005846
5847 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5848 return BC_STATUS_PARSE_BAD_ASSIGN;
5849
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005850#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005851 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Gavin Howard01055ba2018-11-03 11:00:21 -06005852 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5853
5854 if (assign)
5855 bc_num_copy(l, r);
5856 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005857 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005858
5859 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005860#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005861 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005862#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005863
5864 if (ib || sc || left->t == BC_RESULT_OBASE) {
5865
5866 size_t *ptr;
5867
5868 s = bc_num_ulong(l, &val);
5869 if (s) return s;
5870 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5871
5872 if (sc) {
5873 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005874 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005875 }
5876 else {
5877 if (val < BC_NUM_MIN_BASE) return s;
5878 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005879 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005880 }
5881
5882 if (val > max) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005883 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005884
5885 *ptr = (size_t) val;
5886 s = BC_STATUS_SUCCESS;
5887 }
5888
5889 bc_num_init(&res.d.n, l->len);
5890 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005891 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005892
5893 return s;
5894}
5895
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005896static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005897 bool pop, bool copy)
5898{
5899 BcStatus s = BC_STATUS_SUCCESS;
5900 BcResult r;
5901 char *name = bc_program_name(code, bgn);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005902#if ENABLE_DC // Exclude
Gavin Howard01055ba2018-11-03 11:00:21 -06005903 BcNum *num;
5904 BcVec *v;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005905#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005906 (void) pop, (void) copy;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005907#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005908
5909 r.t = BC_RESULT_VAR;
5910 r.d.id.name = name;
5911
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005912#if ENABLE_DC
Denys Vlasenkodf515392018-12-02 19:27:48 +01005913 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005914 num = bc_vec_top(v);
5915
5916 if (pop || copy) {
5917
5918 if (!BC_PROG_STACK(v, 2 - copy)) {
5919 free(name);
5920 return BC_STATUS_EXEC_STACK;
5921 }
5922
5923 free(name);
5924 name = NULL;
5925
5926 if (!BC_PROG_STR(num)) {
5927
5928 r.t = BC_RESULT_TEMP;
5929
5930 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5931 bc_num_copy(&r.d.n, num);
5932 }
5933 else {
5934 r.t = BC_RESULT_STR;
5935 r.d.id.idx = num->rdx;
5936 }
5937
5938 if (!copy) bc_vec_pop(v);
5939 }
5940#endif // ENABLE_DC
5941
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005942 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005943
5944 return s;
5945}
5946
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005947static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005948 char inst)
5949{
5950 BcStatus s = BC_STATUS_SUCCESS;
5951 BcResult r;
5952 BcNum *num;
5953
5954 r.d.id.name = bc_program_name(code, bgn);
5955
5956 if (inst == BC_INST_ARRAY) {
5957 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005958 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005959 }
5960 else {
5961
5962 BcResult *operand;
5963 unsigned long temp;
5964
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005965 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005966 if (s) goto err;
5967 s = bc_num_ulong(num, &temp);
5968 if (s) goto err;
5969
5970 if (temp > BC_MAX_DIM) {
5971 s = BC_STATUS_EXEC_ARRAY_LEN;
5972 goto err;
5973 }
5974
5975 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005976 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005977 }
5978
5979err:
5980 if (s) free(r.d.id.name);
5981 return s;
5982}
5983
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005984#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005985static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005986{
5987 BcStatus s;
5988 BcResult *ptr, res, copy;
5989 BcNum *num = NULL;
5990 char inst2 = inst;
5991
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005992 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005993 if (s) return s;
5994
5995 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5996 copy.t = BC_RESULT_TEMP;
5997 bc_num_init(&copy.d.n, num->len);
5998 bc_num_copy(&copy.d.n, num);
5999 }
6000
6001 res.t = BC_RESULT_ONE;
6002 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6003 BC_INST_ASSIGN_PLUS :
6004 BC_INST_ASSIGN_MINUS;
6005
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006006 bc_vec_push(&G.prog.results, &res);
6007 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006008
6009 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006010 bc_vec_pop(&G.prog.results);
6011 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006012 }
6013
6014 return s;
6015}
6016
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006017static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006018{
6019 BcStatus s = BC_STATUS_SUCCESS;
6020 BcInstPtr ip;
6021 size_t i, nparams = bc_program_index(code, idx);
6022 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006023 BcId *a;
6024 BcResultData param;
6025 BcResult *arg;
6026
6027 ip.idx = 0;
6028 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006029 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006030
6031 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6032 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006033 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006034
6035 for (i = 0; i < nparams; ++i) {
6036
6037 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006038 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006039
6040 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6041 return BC_STATUS_EXEC_BAD_TYPE;
6042
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006043 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006044 if (s) return s;
6045 }
6046
6047 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006048 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006049
6050 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006051 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006052
6053 if (a->idx) {
6054 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6055 bc_vec_push(v, &param.n);
6056 }
6057 else {
6058 bc_array_init(&param.v, true);
6059 bc_vec_push(v, &param.v);
6060 }
6061 }
6062
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006063 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006064
6065 return BC_STATUS_SUCCESS;
6066}
6067
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006068static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006069{
6070 BcStatus s;
6071 BcResult res;
6072 BcFunc *f;
6073 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006074 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006075
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006076 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Gavin Howard01055ba2018-11-03 11:00:21 -06006077 return BC_STATUS_EXEC_STACK;
6078
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006079 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006080 res.t = BC_RESULT_TEMP;
6081
6082 if (inst == BC_INST_RET) {
6083
6084 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006085 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006086
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006087 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006088 if (s) return s;
6089 bc_num_init(&res.d.n, num->len);
6090 bc_num_copy(&res.d.n, num);
6091 }
6092 else {
6093 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6094 bc_num_zero(&res.d.n);
6095 }
6096
6097 // We need to pop arguments as well, so this takes that into account.
6098 for (i = 0; i < f->autos.len; ++i) {
6099
6100 BcVec *v;
6101 BcId *a = bc_vec_item(&f->autos, i);
6102
Denys Vlasenkodf515392018-12-02 19:27:48 +01006103 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006104 bc_vec_pop(v);
6105 }
6106
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006107 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6108 bc_vec_push(&G.prog.results, &res);
6109 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006110
6111 return BC_STATUS_SUCCESS;
6112}
6113#endif // ENABLE_BC
6114
6115static unsigned long bc_program_scale(BcNum *n)
6116{
6117 return (unsigned long) n->rdx;
6118}
6119
6120static unsigned long bc_program_len(BcNum *n)
6121{
6122 unsigned long len = n->len;
6123 size_t i;
6124
6125 if (n->rdx != n->len) return len;
6126 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6127
6128 return len;
6129}
6130
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006131static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006132{
6133 BcStatus s;
6134 BcResult *opnd;
6135 BcNum *num = NULL;
6136 BcResult res;
6137 bool len = inst == BC_INST_LENGTH;
6138
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006139 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6140 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006143 if (s) return s;
6144
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006145#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006146 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006147#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006148
6149 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6150
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006151 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006152#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006153 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006154 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006155 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006156#endif
6157#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006158 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6159
6160 char **str;
6161 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6162
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006163 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006164 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006165 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006166#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006167 else {
6168 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006169 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006170 }
6171
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006172 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006173
6174 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006175}
6176
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006177#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006178static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006179{
6180 BcStatus s;
6181 BcResult *opd1, *opd2, res, res2;
6182 BcNum *n1, *n2 = NULL;
6183
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006185 if (s) return s;
6186
6187 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6188 bc_num_init(&res2.d.n, n2->len);
6189
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006190 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006191 if (s) goto err;
6192
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006193 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006194 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006195 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006196
6197 return s;
6198
6199err:
6200 bc_num_free(&res2.d.n);
6201 bc_num_free(&res.d.n);
6202 return s;
6203}
6204
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006205static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006206{
6207 BcStatus s;
6208 BcResult *r1, *r2, *r3, res;
6209 BcNum *n1, *n2, *n3;
6210
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006211 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6212 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006213 if (s) return s;
6214
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006215 r1 = bc_vec_item_rev(&G.prog.results, 2);
6216 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006217 if (s) return s;
6218 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6219
6220 // Make sure that the values have their pointers updated, if necessary.
6221 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6222
6223 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006224 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006225 if (s) return s;
6226 }
6227
6228 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006229 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006230 if (s) return s;
6231 }
6232 }
6233
6234 bc_num_init(&res.d.n, n3->len);
6235 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6236 if (s) goto err;
6237
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006238 bc_vec_pop(&G.prog.results);
6239 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006240
6241 return s;
6242
6243err:
6244 bc_num_free(&res.d.n);
6245 return s;
6246}
6247
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006248static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006249{
Gavin Howard01055ba2018-11-03 11:00:21 -06006250 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006251 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006252
6253 res.t = BC_RESULT_TEMP;
6254
6255 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006256 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006257 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006258}
6259
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006260static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006261{
6262 BcStatus s;
6263 BcResult *r, res;
6264 BcNum *num = NULL, n;
6265 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006266 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006267 unsigned long val;
6268
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006269 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6270 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006273 if (s) return s;
6274
6275 if (BC_PROG_NUM(r, num)) {
6276
6277 bc_num_init(&n, BC_NUM_DEF_SIZE);
6278 bc_num_copy(&n, num);
6279 bc_num_truncate(&n, n.rdx);
6280
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006281 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006282 if (s) goto num_err;
6283 s = bc_num_ulong(&n, &val);
6284 if (s) goto num_err;
6285
6286 c = (char) val;
6287
6288 bc_num_free(&n);
6289 }
6290 else {
6291 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006292 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006293 c = str2[0];
6294 }
6295
6296 str = xmalloc(2);
6297 str[0] = c;
6298 str[1] = '\0';
6299
6300 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006301 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006302
6303 if (idx != len + BC_PROG_REQ_FUNCS) {
6304
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006305 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6306 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006307 len = idx;
6308 break;
6309 }
6310 }
6311
6312 free(str);
6313 }
6314 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006315 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006316
6317 res.t = BC_RESULT_STR;
6318 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006319 bc_vec_pop(&G.prog.results);
6320 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006321
6322 return BC_STATUS_SUCCESS;
6323
6324num_err:
6325 bc_num_free(&n);
6326 return s;
6327}
6328
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006329static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006330{
6331 BcStatus s;
6332 BcResult *r;
6333 BcNum *n = NULL;
6334 size_t idx;
6335 char *str;
6336
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006337 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6338 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006339
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006340 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006341 if (s) return s;
6342
6343 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006344 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006345 else {
6346 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006347 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006348 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006349 }
6350
6351 return s;
6352}
6353
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006354static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006355{
6356 BcStatus s;
6357 BcResult *opnd;
6358 BcNum *num = NULL;
6359 unsigned long val;
6360
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006361 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006362 if (s) return s;
6363 s = bc_num_ulong(num, &val);
6364 if (s) return s;
6365
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006366 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006367
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006368 if (G.prog.stack.len < val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006369 return BC_STATUS_EXEC_STACK;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006370 else if (G.prog.stack.len == val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006371 return BC_STATUS_QUIT;
6372
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006373 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006374
6375 return s;
6376}
6377
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006378static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006379 bool cond)
6380{
6381 BcStatus s = BC_STATUS_SUCCESS;
6382 BcResult *r;
6383 char **str;
6384 BcFunc *f;
6385 BcParse prs;
6386 BcInstPtr ip;
6387 size_t fidx, sidx;
6388 BcNum *n;
6389 bool exec;
6390
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006391 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006392
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006393 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006394
6395 if (cond) {
6396
Gavin Howard01055ba2018-11-03 11:00:21 -06006397 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6398
6399 if (code[*bgn] == BC_PARSE_STREND)
6400 (*bgn) += 1;
6401 else
6402 else_name = bc_program_name(code, bgn);
6403
6404 exec = r->d.n.len != 0;
6405
6406 if (exec)
6407 name = then_name;
6408 else if (else_name != NULL) {
6409 exec = true;
6410 name = else_name;
6411 }
6412
6413 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006414 BcVec *v;
6415 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006416 n = bc_vec_top(v);
6417 }
6418
6419 free(then_name);
6420 free(else_name);
6421
6422 if (!exec) goto exit;
6423 if (!BC_PROG_STR(n)) {
6424 s = BC_STATUS_EXEC_BAD_TYPE;
6425 goto exit;
6426 }
6427
6428 sidx = n->rdx;
6429 }
6430 else {
6431
6432 if (r->t == BC_RESULT_STR)
6433 sidx = r->d.id.idx;
6434 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006435 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006436 if (s || !BC_PROG_STR(n)) goto exit;
6437 sidx = n->rdx;
6438 }
6439 else
6440 goto exit;
6441 }
6442
6443 fidx = sidx + BC_PROG_REQ_FUNCS;
6444
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006445 str = bc_vec_item(&G.prog.strs, sidx);
6446 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006447
6448 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006449 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006450 s = bc_parse_text(&prs, *str);
6451 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006452 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006453 if (s) goto err;
6454
6455 if (prs.l.t.t != BC_LEX_EOF) {
6456 s = BC_STATUS_PARSE_BAD_EXP;
6457 goto err;
6458 }
6459
6460 bc_parse_free(&prs);
6461 }
6462
6463 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006464 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006465 ip.func = fidx;
6466
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006467 bc_vec_pop(&G.prog.results);
6468 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006469
6470 return BC_STATUS_SUCCESS;
6471
6472err:
6473 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006474 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006475 bc_vec_npop(&f->code, f->code.len);
6476exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006477 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006478 return s;
6479}
6480#endif // ENABLE_DC
6481
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006482static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006483{
Gavin Howard01055ba2018-11-03 11:00:21 -06006484 BcResult res;
6485 unsigned long val;
6486
6487 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6488 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006489 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006490 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006491 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006492 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006493 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006494
6495 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006496 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006497 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006498}
6499
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006500static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006501{
6502 BcStatus s;
6503 BcId entry, *entry_ptr;
6504 BcFunc f;
6505
6506 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006507 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006508
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006509 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006510 if (s) free(name);
6511
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006512 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006513 *idx = entry_ptr->idx;
6514
6515 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6516
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006517 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006518
6519 // We need to reset these, so the function can be repopulated.
6520 func->nparams = 0;
6521 bc_vec_npop(&func->autos, func->autos.len);
6522 bc_vec_npop(&func->code, func->code.len);
6523 bc_vec_npop(&func->labels, func->labels.len);
6524 }
6525 else {
6526 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006527 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006528 }
6529}
6530
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006531static BcStatus bc_program_reset(BcStatus s)
Gavin Howard01055ba2018-11-03 11:00:21 -06006532{
6533 BcFunc *f;
6534 BcInstPtr *ip;
6535
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006536 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6537 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006538
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006539 f = bc_vec_item(&G.prog.fns, 0);
6540 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006541 ip->idx = f->code.len;
6542
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006543 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
Gavin Howard01055ba2018-11-03 11:00:21 -06006544
6545 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006546 if (G.ttyin) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006547 fflush(stdout);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006548 fputs(bc_program_ready_msg, stderr);
6549 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06006550 s = BC_STATUS_SUCCESS;
6551 }
6552 else
6553 s = BC_STATUS_QUIT;
6554 }
6555
6556 return s;
6557}
6558
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006559static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006560{
6561 BcStatus s = BC_STATUS_SUCCESS;
6562 size_t idx;
6563 BcResult r, *ptr;
6564 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006565 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6566 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006567 char *code = func->code.v;
6568 bool cond = false;
6569
6570 while (!s && ip->idx < func->code.len) {
6571
6572 char inst = code[(ip->idx)++];
6573
6574 switch (inst) {
6575
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006576#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006577 case BC_INST_JUMP_ZERO:
6578 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006579 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006581 cond = !bc_num_cmp(num, &G.prog.zero);
6582 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006583 }
6584 // Fallthrough.
6585 case BC_INST_JUMP:
6586 {
6587 size_t *addr;
6588 idx = bc_program_index(code, &ip->idx);
6589 addr = bc_vec_item(&func->labels, idx);
6590 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6591 break;
6592 }
6593
6594 case BC_INST_CALL:
6595 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006596 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006597 break;
6598 }
6599
6600 case BC_INST_INC_PRE:
6601 case BC_INST_DEC_PRE:
6602 case BC_INST_INC_POST:
6603 case BC_INST_DEC_POST:
6604 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006605 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006606 break;
6607 }
6608
6609 case BC_INST_HALT:
6610 {
6611 s = BC_STATUS_QUIT;
6612 break;
6613 }
6614
6615 case BC_INST_RET:
6616 case BC_INST_RET0:
6617 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006618 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006619 break;
6620 }
6621
6622 case BC_INST_BOOL_OR:
6623 case BC_INST_BOOL_AND:
6624#endif // ENABLE_BC
6625 case BC_INST_REL_EQ:
6626 case BC_INST_REL_LE:
6627 case BC_INST_REL_GE:
6628 case BC_INST_REL_NE:
6629 case BC_INST_REL_LT:
6630 case BC_INST_REL_GT:
6631 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006632 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006633 break;
6634 }
6635
6636 case BC_INST_READ:
6637 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006638 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
6642 case BC_INST_VAR:
6643 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006644 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006645 break;
6646 }
6647
6648 case BC_INST_ARRAY_ELEM:
6649 case BC_INST_ARRAY:
6650 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006651 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006652 break;
6653 }
6654
6655 case BC_INST_LAST:
6656 {
6657 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006658 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006659 break;
6660 }
6661
6662 case BC_INST_IBASE:
6663 case BC_INST_SCALE:
6664 case BC_INST_OBASE:
6665 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006666 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006667 break;
6668 }
6669
6670 case BC_INST_SCALE_FUNC:
6671 case BC_INST_LENGTH:
6672 case BC_INST_SQRT:
6673 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006674 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006675 break;
6676 }
6677
6678 case BC_INST_NUM:
6679 {
6680 r.t = BC_RESULT_CONSTANT;
6681 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006682 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006683 break;
6684 }
6685
6686 case BC_INST_POP:
6687 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006688 if (!BC_PROG_STACK(&G.prog.results, 1))
Gavin Howard01055ba2018-11-03 11:00:21 -06006689 s = BC_STATUS_EXEC_STACK;
6690 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006691 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006692 break;
6693 }
6694
6695 case BC_INST_POP_EXEC:
6696 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006697 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006698 break;
6699 }
6700
6701 case BC_INST_PRINT:
6702 case BC_INST_PRINT_POP:
6703 case BC_INST_PRINT_STR:
6704 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006705 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006706 break;
6707 }
6708
6709 case BC_INST_STR:
6710 {
6711 r.t = BC_RESULT_STR;
6712 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006713 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006714 break;
6715 }
6716
6717 case BC_INST_POWER:
6718 case BC_INST_MULTIPLY:
6719 case BC_INST_DIVIDE:
6720 case BC_INST_MODULUS:
6721 case BC_INST_PLUS:
6722 case BC_INST_MINUS:
6723 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006724 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006725 break;
6726 }
6727
6728 case BC_INST_BOOL_NOT:
6729 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006730 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006731 if (s) return s;
6732
6733 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006734 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6735 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006736
6737 break;
6738 }
6739
6740 case BC_INST_NEG:
6741 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006742 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006743 break;
6744 }
6745
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006746#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006747 case BC_INST_ASSIGN_POWER:
6748 case BC_INST_ASSIGN_MULTIPLY:
6749 case BC_INST_ASSIGN_DIVIDE:
6750 case BC_INST_ASSIGN_MODULUS:
6751 case BC_INST_ASSIGN_PLUS:
6752 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006753#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006754 case BC_INST_ASSIGN:
6755 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006756 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006757 break;
6758 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006759#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006760 case BC_INST_MODEXP:
6761 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006762 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006763 break;
6764 }
6765
6766 case BC_INST_DIVMOD:
6767 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006768 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006769 break;
6770 }
6771
6772 case BC_INST_EXECUTE:
6773 case BC_INST_EXEC_COND:
6774 {
6775 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006776 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006777 break;
6778 }
6779
6780 case BC_INST_PRINT_STACK:
6781 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006782 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6783 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006784 break;
6785 }
6786
6787 case BC_INST_CLEAR_STACK:
6788 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006789 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 break;
6791 }
6792
6793 case BC_INST_STACK_LEN:
6794 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006795 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 break;
6797 }
6798
6799 case BC_INST_DUPLICATE:
6800 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006801 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6802 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006803 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006804 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006805 break;
6806 }
6807
6808 case BC_INST_SWAP:
6809 {
6810 BcResult *ptr2;
6811
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006812 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006813
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006814 ptr = bc_vec_item_rev(&G.prog.results, 0);
6815 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816 memcpy(&r, ptr, sizeof(BcResult));
6817 memcpy(ptr, ptr2, sizeof(BcResult));
6818 memcpy(ptr2, &r, sizeof(BcResult));
6819
6820 break;
6821 }
6822
6823 case BC_INST_ASCIIFY:
6824 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006825 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006826 break;
6827 }
6828
6829 case BC_INST_PRINT_STREAM:
6830 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006831 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006832 break;
6833 }
6834
6835 case BC_INST_LOAD:
6836 case BC_INST_PUSH_VAR:
6837 {
6838 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006839 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006840 break;
6841 }
6842
6843 case BC_INST_PUSH_TO_VAR:
6844 {
6845 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006846 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006847 free(name);
6848 break;
6849 }
6850
6851 case BC_INST_QUIT:
6852 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006853 if (G.prog.stack.len <= 2)
Gavin Howard01055ba2018-11-03 11:00:21 -06006854 s = BC_STATUS_QUIT;
6855 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006856 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006857 break;
6858 }
6859
6860 case BC_INST_NQUIT:
6861 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006862 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006863 break;
6864 }
6865#endif // ENABLE_DC
6866 }
6867
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006868 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006869
6870 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006871 ip = bc_vec_top(&G.prog.stack);
6872 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006873 code = func->code.v;
6874 }
6875
6876 return s;
6877}
6878
Denys Vlasenko00d77792018-11-30 23:13:42 +01006879static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006880{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006881 printf("%s "BB_VER"\n"
6882 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006883 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006884 "This is free software with ABSOLUTELY NO WARRANTY\n"
6885 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006886}
6887
6888static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6889{
6890 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6891
Denys Vlasenko00d77792018-11-30 23:13:42 +01006892 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6893 fprintf(stderr, " %s", file);
6894 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006895
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006896 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
Gavin Howard01055ba2018-11-03 11:00:21 -06006897}
6898
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006899#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006900static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6901 const char *msg)
6902{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006903 int p = (int) G_posix, w = (int) G_warn;
Gavin Howard01055ba2018-11-03 11:00:21 -06006904 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6905
6906 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6907
Denys Vlasenko00d77792018-11-30 23:13:42 +01006908 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6909 if (msg) fprintf(stderr, " %s\n", msg);
6910 fprintf(stderr, " %s", file);
6911 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006912
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006913 return s * (!G.ttyin && !!p);
Gavin Howard01055ba2018-11-03 11:00:21 -06006914}
6915
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006916static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006917{
Gavin Howard01055ba2018-11-03 11:00:21 -06006918 BcVec v;
6919 char *env_args = getenv(bc_args_env_name), *buf;
6920
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006921 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006922
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006923 G.env_args = xstrdup(env_args);
6924 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006925
6926 bc_vec_init(&v, sizeof(char *), NULL);
6927 bc_vec_push(&v, &bc_args_env_name);
6928
6929 while (*buf != 0) {
6930 if (!isspace(*buf)) {
6931 bc_vec_push(&v, &buf);
6932 while (*buf != 0 && !isspace(*buf)) ++buf;
6933 if (*buf != 0) (*(buf++)) = '\0';
6934 }
6935 else
6936 ++buf;
6937 }
6938
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006939 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006940
6941 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006942}
6943#endif // ENABLE_BC
6944
6945static size_t bc_vm_envLen(const char *var)
6946{
6947 char *lenv = getenv(var);
6948 size_t i, len = BC_NUM_PRINT_WIDTH;
6949 int num;
6950
6951 if (!lenv) return len;
6952
6953 len = strlen(lenv);
6954
6955 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6956 if (num) {
6957 len = (size_t) atoi(lenv) - 1;
6958 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6959 }
6960 else
6961 len = BC_NUM_PRINT_WIDTH;
6962
6963 return len;
6964}
6965
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006966static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006967{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006968 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006969
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006970 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006971 if (s) return s;
6972
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006973 while (G.prs.l.t.t != BC_LEX_EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006974
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006975 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006976
6977 if (s == BC_STATUS_LIMITS) {
6978
Denys Vlasenko00d77792018-11-30 23:13:42 +01006979 bb_putchar('\n');
6980 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
6981 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
6982 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
6983 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
6984 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
6985 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
6986 printf("Max Exponent = %lu\n", BC_MAX_EXP);
6987 printf("Number of Vars = %lu\n", BC_MAX_VARS);
6988 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06006989
6990 s = BC_STATUS_SUCCESS;
6991 }
6992 else {
6993 if (s == BC_STATUS_QUIT) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006994 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006995 if (s) return s;
6996 }
6997 }
6998
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006999 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007000 s = bc_program_exec();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007001 if (!s && G.tty) fflush(stdout);
Gavin Howard01055ba2018-11-03 11:00:21 -06007002 if (s && s != BC_STATUS_QUIT)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007003 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007004 }
7005
7006 return s;
7007}
7008
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007009static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06007010{
7011 BcStatus s;
7012 char *data;
7013 BcFunc *main_func;
7014 BcInstPtr *ip;
7015
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007016 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01007017 data = bc_read_file(file);
7018 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007019
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007020 bc_lex_file(&G.prs.l, file);
7021 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007022 if (s) goto err;
7023
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007024 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7025 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007026
7027 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7028
7029err:
7030 free(data);
7031 return s;
7032}
7033
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007034static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007035{
7036 BcStatus s = BC_STATUS_SUCCESS;
7037 BcVec buf, buffer;
7038 char c;
7039 size_t len, i, str = 0;
7040 bool comment = false, notend;
7041
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007042 G.prog.file = bc_program_stdin_name;
7043 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007044
7045 bc_vec_init(&buffer, sizeof(char), NULL);
7046 bc_vec_init(&buf, sizeof(char), NULL);
7047 bc_vec_pushByte(&buffer, '\0');
7048
7049 // This loop is complex because the vm tries not to send any lines that end
7050 // with a backslash to the parser. The reason for that is because the parser
7051 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7052 // case, and for strings and comments, the parser will expect more stuff.
7053 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7054
7055 char *string = buf.v;
7056
7057 len = buf.len - 1;
7058
7059 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007060 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007061 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007062 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007063 str += 1;
7064 }
7065 else if (len > 1 || comment) {
7066
7067 for (i = 0; i < len; ++i) {
7068
7069 notend = len > i + 1;
7070 c = string[i];
7071
7072 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007073 if (G.sbgn == G.send)
7074 str ^= c == G.sbgn;
7075 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007076 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007077 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007078 str += 1;
7079 }
7080
7081 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7082 comment = true;
7083 break;
7084 }
7085 else if (c == '*' && notend && comment && string[i + 1] == '/')
7086 comment = false;
7087 }
7088
7089 if (str || comment || string[len - 2] == '\\') {
7090 bc_vec_concat(&buffer, buf.v);
7091 continue;
7092 }
7093 }
7094
7095 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007096 s = bc_vm_process(buffer.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007097 if (s) goto err;
7098
7099 bc_vec_npop(&buffer, buffer.len);
7100 }
7101
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007102 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007103
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007104 // INPUT_EOF will always happen when stdin is
Gavin Howard01055ba2018-11-03 11:00:21 -06007105 // closed. It's not a problem in that case.
Denys Vlasenko00d77792018-11-30 23:13:42 +01007106 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7107 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06007108
7109 if (str)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007110 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7111 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007112 else if (comment)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007113 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7114 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007115
7116err:
7117 bc_vec_free(&buf);
7118 bc_vec_free(&buffer);
7119 return s;
7120}
7121
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007122static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007123{
7124 BcStatus s = BC_STATUS_SUCCESS;
7125 size_t i;
7126
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007127#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007128 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007129
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007130 bc_lex_file(&G.prs.l, bc_lib_name);
7131 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007132
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007133 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007134
7135 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007136 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007137 if (s) return s;
7138 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007139#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007140
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007141 for (i = 0; !s && i < G.files.len; ++i)
7142 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Gavin Howard01055ba2018-11-03 11:00:21 -06007143 if (s && s != BC_STATUS_QUIT) return s;
7144
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007145 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7146 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007147
Denys Vlasenko00d77792018-11-30 23:13:42 +01007148 if (s == BC_STATUS_QUIT)
7149 s = BC_STATUS_SUCCESS;
7150 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007151}
7152
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007153#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007154static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007155{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007156 bc_num_free(&G.prog.ib);
7157 bc_num_free(&G.prog.ob);
7158 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007159# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007160 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007161# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007162 bc_vec_free(&G.prog.fns);
7163 bc_vec_free(&G.prog.fn_map);
7164 bc_vec_free(&G.prog.vars);
7165 bc_vec_free(&G.prog.var_map);
7166 bc_vec_free(&G.prog.arrs);
7167 bc_vec_free(&G.prog.arr_map);
7168 bc_vec_free(&G.prog.strs);
7169 bc_vec_free(&G.prog.consts);
7170 bc_vec_free(&G.prog.results);
7171 bc_vec_free(&G.prog.stack);
7172 bc_num_free(&G.prog.last);
7173 bc_num_free(&G.prog.zero);
7174 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007175}
7176
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007177static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007178{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007179 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007180 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007181 bc_parse_free(&G.prs);
7182 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007183}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007184#endif
7185
7186static void bc_program_init(size_t line_len)
7187{
7188 size_t idx;
7189 BcInstPtr ip;
7190
7191 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7192 memset(&ip, 0, sizeof(BcInstPtr));
7193
7194 /* G.prog.nchars = G.prog.scale = 0; - already is */
7195 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007196
7197 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7198 bc_num_ten(&G.prog.ib);
7199 G.prog.ib_t = 10;
7200
7201 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7202 bc_num_ten(&G.prog.ob);
7203 G.prog.ob_t = 10;
7204
7205 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7206 bc_num_ten(&G.prog.hexb);
7207 G.prog.hexb.num[0] = 6;
7208
7209#if ENABLE_DC
7210 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7211 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7212#endif
7213
7214 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7215 bc_num_zero(&G.prog.last);
7216
7217 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7218 bc_num_zero(&G.prog.zero);
7219
7220 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7221 bc_num_one(&G.prog.one);
7222
7223 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7224 bc_map_init(&G.prog.fn_map);
7225
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007226 bc_program_addFunc(xstrdup(bc_func_main), &idx);
7227 bc_program_addFunc(xstrdup(bc_func_read), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007228
7229 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7230 bc_map_init(&G.prog.var_map);
7231
7232 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7233 bc_map_init(&G.prog.arr_map);
7234
7235 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7236 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7237 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7238 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7239 bc_vec_push(&G.prog.stack, &ip);
7240}
Gavin Howard01055ba2018-11-03 11:00:21 -06007241
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007242static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007243{
Gavin Howard01055ba2018-11-03 11:00:21 -06007244 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007245
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007246#if ENABLE_FEATURE_BC_SIGNALS
7247 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007248#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007249
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007250 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007251
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007252 if (IS_BC) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007253 if (getenv("POSIXLY_CORRECT"))
7254 G.flags |= BC_FLAG_S;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007255 bc_vm_envArgs();
7256 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007257
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007258 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007259 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007260 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007261 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007262 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007263 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007264}
7265
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007266static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007267 const char *env_len)
7268{
7269 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007270
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007271 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007272 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007273
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007274 G.ttyin = isatty(0);
7275 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007276
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007277 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7278 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007279
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007280#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007281 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007282#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007283 return st;
7284}
7285
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007286#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007287int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7288int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007289{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007290 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007291 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007292
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007293 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007294}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007295#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007296
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007297#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007298int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7299int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007300{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007301 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007302 G.sbgn = '[';
7303 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007304
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007305 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007306}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007307#endif