blob: 4257511f0aabbffc556f6e71b4fe15ff8742a085 [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
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100117//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600118//usage:#define bc_trivial_usage
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100119//usage: "[-sqli] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600120//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100121//usage:#define bc_full_usage "\n"
122//usage: "\nArbitrary precision calculator"
123//usage: "\n"
124//usage: "\n -i Interactive"
125//usage: "\n -l Load standard math library"
126//usage: "\n -s Be POSIX compatible"
127//usage: "\n -q Quiet"
128//usage: "\n -w Warn if extensions are used"
129///////: "\n -v Version"
Gavin Howard01055ba2018-11-03 11:00:21 -0600130//usage:
131//usage:#define bc_example_usage
132//usage: "3 + 4.129\n"
133//usage: "1903 - 2893\n"
134//usage: "-129 * 213.28935\n"
135//usage: "12 / -1932\n"
136//usage: "12 % 12\n"
137//usage: "34 ^ 189\n"
138//usage: "scale = 13\n"
139//usage: "ibase = 2\n"
140//usage: "obase = A\n"
141//usage:
142//usage:#define dc_trivial_usage
143//usage: "EXPRESSION..."
144//usage:
145//usage:#define dc_full_usage "\n\n"
146//usage: "Tiny RPN calculator. Operations:\n"
147//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148//usage: "modular exponentiation,\n"
149//usage: "p - print top of the stack (without popping),\n"
150//usage: "f - print entire stack,\n"
151//usage: "k - pop the value and set the precision.\n"
152//usage: "i - pop the value and set input radix.\n"
153//usage: "o - pop the value and set output radix.\n"
154//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
155//usage:
156//usage:#define dc_example_usage
157//usage: "$ dc 2 2 + p\n"
158//usage: "4\n"
159//usage: "$ dc 8 8 \\* 2 2 + / p\n"
160//usage: "16\n"
161//usage: "$ dc 0 1 and p\n"
162//usage: "0\n"
163//usage: "$ dc 0 1 or p\n"
164//usage: "1\n"
165//usage: "$ echo 72 9 div 8 mul p | dc\n"
166//usage: "64\n"
167
168#include "libbb.h"
169
170typedef enum BcStatus {
171
172 BC_STATUS_SUCCESS,
173
174 BC_STATUS_ALLOC_ERR,
Denys Vlasenko00d77792018-11-30 23:13:42 +0100175 BC_STATUS_INPUT_EOF,
Gavin Howard01055ba2018-11-03 11:00:21 -0600176 BC_STATUS_BIN_FILE,
177 BC_STATUS_PATH_IS_DIR,
178
179 BC_STATUS_LEX_BAD_CHAR,
180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
182 BC_STATUS_LEX_EOF,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100183#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600184 BC_STATUS_LEX_EXTENDED_REG,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100185#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600186
187 BC_STATUS_PARSE_BAD_TOKEN,
188 BC_STATUS_PARSE_BAD_EXP,
189 BC_STATUS_PARSE_EMPTY_EXP,
190 BC_STATUS_PARSE_BAD_PRINT,
191 BC_STATUS_PARSE_BAD_FUNC,
192 BC_STATUS_PARSE_BAD_ASSIGN,
193 BC_STATUS_PARSE_NO_AUTO,
194 BC_STATUS_PARSE_DUPLICATE_LOCAL,
195 BC_STATUS_PARSE_NO_BLOCK_END,
196
197 BC_STATUS_MATH_NEGATIVE,
198 BC_STATUS_MATH_NON_INTEGER,
199 BC_STATUS_MATH_OVERFLOW,
200 BC_STATUS_MATH_DIVIDE_BY_ZERO,
201 BC_STATUS_MATH_BAD_STRING,
202
203 BC_STATUS_EXEC_FILE_ERR,
204 BC_STATUS_EXEC_MISMATCHED_PARAMS,
205 BC_STATUS_EXEC_UNDEFINED_FUNC,
206 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
207 BC_STATUS_EXEC_NUM_LEN,
208 BC_STATUS_EXEC_NAME_LEN,
209 BC_STATUS_EXEC_STRING_LEN,
210 BC_STATUS_EXEC_ARRAY_LEN,
211 BC_STATUS_EXEC_BAD_IBASE,
212 BC_STATUS_EXEC_BAD_SCALE,
213 BC_STATUS_EXEC_BAD_READ_EXPR,
214 BC_STATUS_EXEC_REC_READ,
215 BC_STATUS_EXEC_BAD_TYPE,
216 BC_STATUS_EXEC_BAD_OBASE,
217 BC_STATUS_EXEC_SIGNAL,
218 BC_STATUS_EXEC_STACK,
219
220 BC_STATUS_VEC_OUT_OF_BOUNDS,
221 BC_STATUS_VEC_ITEM_EXISTS,
222
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100223#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600224 BC_STATUS_POSIX_NAME_LEN,
225 BC_STATUS_POSIX_COMMENT,
226 BC_STATUS_POSIX_BAD_KW,
227 BC_STATUS_POSIX_DOT,
228 BC_STATUS_POSIX_RET,
229 BC_STATUS_POSIX_BOOL,
230 BC_STATUS_POSIX_REL_POS,
231 BC_STATUS_POSIX_MULTIREL,
232 BC_STATUS_POSIX_FOR1,
233 BC_STATUS_POSIX_FOR2,
234 BC_STATUS_POSIX_FOR3,
235 BC_STATUS_POSIX_BRACE,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100236#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600237
238 BC_STATUS_QUIT,
239 BC_STATUS_LIMITS,
240
241 BC_STATUS_INVALID_OPTION,
242
243} BcStatus;
244
245#define BC_ERR_IDX_VM (0)
246#define BC_ERR_IDX_LEX (1)
247#define BC_ERR_IDX_PARSE (2)
248#define BC_ERR_IDX_MATH (3)
249#define BC_ERR_IDX_EXEC (4)
250#define BC_ERR_IDX_VEC (5)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100251#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600252#define BC_ERR_IDX_POSIX (6)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100253#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600254
255#define BC_VEC_INVALID_IDX ((size_t) -1)
256#define BC_VEC_START_CAP (1 << 5)
257
258typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600259
260typedef struct BcVec {
261 char *v;
262 size_t len;
263 size_t cap;
264 size_t size;
265 BcVecFree dtor;
266} BcVec;
267
268#define bc_vec_pop(v) (bc_vec_npop((v), 1))
269#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
270
271#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
272
273#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
274
275typedef signed char BcDig;
276
277typedef struct BcNum {
278 BcDig *restrict num;
279 size_t rdx;
280 size_t len;
281 size_t cap;
282 bool neg;
283} BcNum;
284
285#define BC_NUM_MIN_BASE ((unsigned long) 2)
286#define BC_NUM_MAX_IBASE ((unsigned long) 16)
287#define BC_NUM_DEF_SIZE (16)
288#define BC_NUM_PRINT_WIDTH (69)
289
290#define BC_NUM_KARATSUBA_LEN (32)
291
292#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
293#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
294#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
295#define BC_NUM_AREQ(a, b) \
296 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
297#define BC_NUM_MREQ(a, b, scale) \
298 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
299
300typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
301typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
302
303static void bc_num_init(BcNum *n, size_t req);
304static void bc_num_expand(BcNum *n, size_t req);
305static void bc_num_copy(BcNum *d, BcNum *s);
306static void bc_num_free(void *num);
307
308static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100309static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600310
311static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
312static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
313static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
314static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
315static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
316static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
317static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
318static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
319 size_t scale);
320
321typedef enum BcInst {
322
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100323#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600324 BC_INST_INC_PRE,
325 BC_INST_DEC_PRE,
326 BC_INST_INC_POST,
327 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100328#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600329
330 BC_INST_NEG,
331
332 BC_INST_POWER,
333 BC_INST_MULTIPLY,
334 BC_INST_DIVIDE,
335 BC_INST_MODULUS,
336 BC_INST_PLUS,
337 BC_INST_MINUS,
338
339 BC_INST_REL_EQ,
340 BC_INST_REL_LE,
341 BC_INST_REL_GE,
342 BC_INST_REL_NE,
343 BC_INST_REL_LT,
344 BC_INST_REL_GT,
345
346 BC_INST_BOOL_NOT,
347 BC_INST_BOOL_OR,
348 BC_INST_BOOL_AND,
349
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100350#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600351 BC_INST_ASSIGN_POWER,
352 BC_INST_ASSIGN_MULTIPLY,
353 BC_INST_ASSIGN_DIVIDE,
354 BC_INST_ASSIGN_MODULUS,
355 BC_INST_ASSIGN_PLUS,
356 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100357#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600358 BC_INST_ASSIGN,
359
360 BC_INST_NUM,
361 BC_INST_VAR,
362 BC_INST_ARRAY_ELEM,
363 BC_INST_ARRAY,
364
365 BC_INST_SCALE_FUNC,
366 BC_INST_IBASE,
367 BC_INST_SCALE,
368 BC_INST_LAST,
369 BC_INST_LENGTH,
370 BC_INST_READ,
371 BC_INST_OBASE,
372 BC_INST_SQRT,
373
374 BC_INST_PRINT,
375 BC_INST_PRINT_POP,
376 BC_INST_STR,
377 BC_INST_PRINT_STR,
378
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100379#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600380 BC_INST_JUMP,
381 BC_INST_JUMP_ZERO,
382
383 BC_INST_CALL,
384
385 BC_INST_RET,
386 BC_INST_RET0,
387
388 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100389#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600390
391 BC_INST_POP,
392 BC_INST_POP_EXEC,
393
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100394#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600395 BC_INST_MODEXP,
396 BC_INST_DIVMOD,
397
398 BC_INST_EXECUTE,
399 BC_INST_EXEC_COND,
400
401 BC_INST_ASCIIFY,
402 BC_INST_PRINT_STREAM,
403
404 BC_INST_PRINT_STACK,
405 BC_INST_CLEAR_STACK,
406 BC_INST_STACK_LEN,
407 BC_INST_DUPLICATE,
408 BC_INST_SWAP,
409
410 BC_INST_LOAD,
411 BC_INST_PUSH_VAR,
412 BC_INST_PUSH_TO_VAR,
413
414 BC_INST_QUIT,
415 BC_INST_NQUIT,
416
417 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100418#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600419
420} BcInst;
421
422typedef struct BcId {
423 char *name;
424 size_t idx;
425} BcId;
426
427typedef struct BcFunc {
428 BcVec code;
429 BcVec labels;
430 size_t nparams;
431 BcVec autos;
432} BcFunc;
433
434typedef enum BcResultType {
435
436 BC_RESULT_TEMP,
437
438 BC_RESULT_VAR,
439 BC_RESULT_ARRAY_ELEM,
440 BC_RESULT_ARRAY,
441
442 BC_RESULT_STR,
443
444 BC_RESULT_IBASE,
445 BC_RESULT_SCALE,
446 BC_RESULT_LAST,
447
448 // These are between to calculate ibase, obase, and last from instructions.
449 BC_RESULT_CONSTANT,
450 BC_RESULT_ONE,
451
452 BC_RESULT_OBASE,
453
454} BcResultType;
455
456typedef union BcResultData {
457 BcNum n;
458 BcVec v;
459 BcId id;
460} BcResultData;
461
462typedef struct BcResult {
463 BcResultType t;
464 BcResultData d;
465} BcResult;
466
467typedef struct BcInstPtr {
468 size_t func;
469 size_t idx;
470 size_t len;
471} BcInstPtr;
472
473static void bc_array_expand(BcVec *a, size_t len);
474static int bc_id_cmp(const void *e1, const void *e2);
475
476// BC_LEX_NEG is not used in lexing; it is only for parsing.
477typedef enum BcLexType {
478
479 BC_LEX_EOF,
480 BC_LEX_INVALID,
481
482 BC_LEX_OP_INC,
483 BC_LEX_OP_DEC,
484
485 BC_LEX_NEG,
486
487 BC_LEX_OP_POWER,
488 BC_LEX_OP_MULTIPLY,
489 BC_LEX_OP_DIVIDE,
490 BC_LEX_OP_MODULUS,
491 BC_LEX_OP_PLUS,
492 BC_LEX_OP_MINUS,
493
494 BC_LEX_OP_REL_EQ,
495 BC_LEX_OP_REL_LE,
496 BC_LEX_OP_REL_GE,
497 BC_LEX_OP_REL_NE,
498 BC_LEX_OP_REL_LT,
499 BC_LEX_OP_REL_GT,
500
501 BC_LEX_OP_BOOL_NOT,
502 BC_LEX_OP_BOOL_OR,
503 BC_LEX_OP_BOOL_AND,
504
505 BC_LEX_OP_ASSIGN_POWER,
506 BC_LEX_OP_ASSIGN_MULTIPLY,
507 BC_LEX_OP_ASSIGN_DIVIDE,
508 BC_LEX_OP_ASSIGN_MODULUS,
509 BC_LEX_OP_ASSIGN_PLUS,
510 BC_LEX_OP_ASSIGN_MINUS,
511 BC_LEX_OP_ASSIGN,
512
513 BC_LEX_NLINE,
514 BC_LEX_WHITESPACE,
515
516 BC_LEX_LPAREN,
517 BC_LEX_RPAREN,
518
519 BC_LEX_LBRACKET,
520 BC_LEX_COMMA,
521 BC_LEX_RBRACKET,
522
523 BC_LEX_LBRACE,
524 BC_LEX_SCOLON,
525 BC_LEX_RBRACE,
526
527 BC_LEX_STR,
528 BC_LEX_NAME,
529 BC_LEX_NUMBER,
530
531 BC_LEX_KEY_AUTO,
532 BC_LEX_KEY_BREAK,
533 BC_LEX_KEY_CONTINUE,
534 BC_LEX_KEY_DEFINE,
535 BC_LEX_KEY_ELSE,
536 BC_LEX_KEY_FOR,
537 BC_LEX_KEY_HALT,
538 BC_LEX_KEY_IBASE,
539 BC_LEX_KEY_IF,
540 BC_LEX_KEY_LAST,
541 BC_LEX_KEY_LENGTH,
542 BC_LEX_KEY_LIMITS,
543 BC_LEX_KEY_OBASE,
544 BC_LEX_KEY_PRINT,
545 BC_LEX_KEY_QUIT,
546 BC_LEX_KEY_READ,
547 BC_LEX_KEY_RETURN,
548 BC_LEX_KEY_SCALE,
549 BC_LEX_KEY_SQRT,
550 BC_LEX_KEY_WHILE,
551
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100552#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600553 BC_LEX_EQ_NO_REG,
554 BC_LEX_OP_MODEXP,
555 BC_LEX_OP_DIVMOD,
556
557 BC_LEX_COLON,
558 BC_LEX_ELSE,
559 BC_LEX_EXECUTE,
560 BC_LEX_PRINT_STACK,
561 BC_LEX_CLEAR_STACK,
562 BC_LEX_STACK_LEVEL,
563 BC_LEX_DUPLICATE,
564 BC_LEX_SWAP,
565 BC_LEX_POP,
566
567 BC_LEX_ASCIIFY,
568 BC_LEX_PRINT_STREAM,
569
570 BC_LEX_STORE_IBASE,
571 BC_LEX_STORE_SCALE,
572 BC_LEX_LOAD,
573 BC_LEX_LOAD_POP,
574 BC_LEX_STORE_PUSH,
575 BC_LEX_STORE_OBASE,
576 BC_LEX_PRINT_POP,
577 BC_LEX_NQUIT,
578 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100579#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600580
581} BcLexType;
582
583struct BcLex;
584typedef BcStatus (*BcLexNext)(struct BcLex *);
585
586typedef struct BcLex {
587
588 const char *buf;
589 size_t i;
590 size_t line;
591 const char *f;
592 size_t len;
593 bool newline;
594
595 struct {
596 BcLexType t;
597 BcLexType last;
598 BcVec v;
599 } t;
600
601 BcLexNext next;
602
603} BcLex;
604
605#define BC_PARSE_STREND ((char) UCHAR_MAX)
606
607#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
608#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100609 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600610
611#define BC_PARSE_REL (1 << 0)
612#define BC_PARSE_PRINT (1 << 1)
613#define BC_PARSE_NOCALL (1 << 2)
614#define BC_PARSE_NOREAD (1 << 3)
615#define BC_PARSE_ARRAY (1 << 4)
616
617#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
618#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
619
620#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
621#define BC_PARSE_FUNC_INNER(parse) \
622 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
623
624#define BC_PARSE_FLAG_FUNC (1 << 1)
625#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
626
627#define BC_PARSE_FLAG_BODY (1 << 2)
628#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
629
630#define BC_PARSE_FLAG_LOOP (1 << 3)
631#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
632
633#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
634#define BC_PARSE_LOOP_INNER(parse) \
635 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
636
637#define BC_PARSE_FLAG_IF (1 << 5)
638#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
639
640#define BC_PARSE_FLAG_ELSE (1 << 6)
641#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
642
643#define BC_PARSE_FLAG_IF_END (1 << 7)
644#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
645
646#define BC_PARSE_CAN_EXEC(parse) \
647 (!(BC_PARSE_TOP_FLAG(parse) & \
648 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
649 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
650 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
651
652typedef struct BcOp {
653 char prec;
654 bool left;
655} BcOp;
656
657typedef struct BcParseNext {
658 uint32_t len;
659 BcLexType tokens[4];
660} BcParseNext;
661
662#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
663#define BC_PARSE_NEXT(a, ...) \
664 { \
665 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
666 }
667
668struct BcParse;
669
670struct BcProgram;
671
Gavin Howard01055ba2018-11-03 11:00:21 -0600672typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600673
674typedef struct BcParse {
675
676 BcParseParse parse;
677
678 BcLex l;
679
680 BcVec flags;
681
682 BcVec exits;
683 BcVec conds;
684
685 BcVec ops;
686
Gavin Howard01055ba2018-11-03 11:00:21 -0600687 BcFunc *func;
688 size_t fidx;
689
690 size_t nbraces;
691 bool auto_part;
692
693} BcParse;
694
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100695#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600696
Gavin Howard01055ba2018-11-03 11:00:21 -0600697typedef struct BcLexKeyword {
698 const char name[9];
699 const char len;
700 const bool posix;
701} BcLexKeyword;
702
703#define BC_LEX_KW_ENTRY(a, b, c) \
704 { \
705 .name = a, .len = (b), .posix = (c) \
706 }
707
708static BcStatus bc_lex_token(BcLex *l);
709
710#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
711#define BC_PARSE_LEAF(p, rparen) \
712 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
713 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
714
715// We can calculate the conversion between tokens and exprs by subtracting the
716// position of the first operator in the lex enum and adding the position of the
717// first in the expr enum. Note: This only works for binary operators.
718#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
719
720static BcStatus bc_parse_parse(BcParse *p);
721static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
722
Denys Vlasenko00d77792018-11-30 23:13:42 +0100723#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600724
Denys Vlasenko00d77792018-11-30 23:13:42 +0100725#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600726
727#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
728
Gavin Howard01055ba2018-11-03 11:00:21 -0600729static BcStatus dc_lex_token(BcLex *l);
730
Gavin Howard01055ba2018-11-03 11:00:21 -0600731static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
732
733#endif // ENABLE_DC
734
735typedef struct BcProgram {
736
737 size_t len;
738 size_t scale;
739
740 BcNum ib;
741 size_t ib_t;
742 BcNum ob;
743 size_t ob_t;
744
745 BcNum hexb;
746
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100747#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600748 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100749#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600750
751 BcVec results;
752 BcVec stack;
753
754 BcVec fns;
755 BcVec fn_map;
756
757 BcVec vars;
758 BcVec var_map;
759
760 BcVec arrs;
761 BcVec arr_map;
762
763 BcVec strs;
764 BcVec consts;
765
766 const char *file;
767
768 BcNum last;
769 BcNum zero;
770 BcNum one;
771
772 size_t nchars;
773
Gavin Howard01055ba2018-11-03 11:00:21 -0600774} BcProgram;
775
776#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
777
778#define BC_PROG_MAIN (0)
779#define BC_PROG_READ (1)
780
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100781#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600782#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100783#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600784
785#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
786#define BC_PROG_NUM(r, n) \
787 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
788
789typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
790
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100791static void bc_program_addFunc(char *name, size_t *idx);
792static BcStatus bc_program_reset(BcStatus s);
Gavin Howard01055ba2018-11-03 11:00:21 -0600793
794#define BC_FLAG_X (1 << 0)
795#define BC_FLAG_W (1 << 1)
796#define BC_FLAG_V (1 << 2)
797#define BC_FLAG_S (1 << 3)
798#define BC_FLAG_Q (1 << 4)
799#define BC_FLAG_L (1 << 5)
800#define BC_FLAG_I (1 << 6)
801
802#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
803#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
804
805#define BC_MAX_OBASE ((unsigned long) 999)
806#define BC_MAX_DIM ((unsigned long) INT_MAX)
807#define BC_MAX_SCALE ((unsigned long) UINT_MAX)
808#define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
809#define BC_MAX_NAME BC_MAX_STRING
810#define BC_MAX_NUM BC_MAX_STRING
811#define BC_MAX_EXP ((unsigned long) LONG_MAX)
812#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
813
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100814struct globals {
Gavin Howard01055ba2018-11-03 11:00:21 -0600815 char sbgn;
816 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600817
818 BcParse prs;
819 BcProgram prog;
820
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100821 unsigned flags;
Gavin Howard01055ba2018-11-03 11:00:21 -0600822 BcVec files;
823
824 char *env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -0600825
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100826 smallint tty;
827 smallint ttyin;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100828} FIX_ALIASING;
829#define G (*ptr_to_globals)
830#define INIT_G() do { \
831 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
832} while (0)
833#define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
834#define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
835#define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100836#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600837
Gavin Howard01055ba2018-11-03 11:00:21 -0600838
Denys Vlasenko00d77792018-11-30 23:13:42 +0100839#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
840
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100841#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600842static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
843 const char *msg);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100844#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600845
Denys Vlasenko00d77792018-11-30 23:13:42 +0100846static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600847
Gavin Howard01055ba2018-11-03 11:00:21 -0600848static const char* const bc_args_env_name = "BC_ENV_ARGS";
849
850static const char bc_err_fmt[] = "\n%s error: %s\n";
851static const char bc_warn_fmt[] = "\n%s warning: %s\n";
852static const char bc_err_line[] = ":%zu\n\n";
853
854static const char *bc_errs[] = {
855 "VM",
856 "Lex",
857 "Parse",
858 "Math",
859 "Runtime",
860 "Vector",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100861#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600862 "POSIX",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100863#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600864};
865
866static const uint8_t bc_err_ids[] = {
867 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
868 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100869#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600870 BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100871#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600872 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
873 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
874 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
875 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100876#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600877 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100878#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600879 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
880 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
881 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
882 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
883 BC_ERR_IDX_EXEC,
884 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100885#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600886 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
887 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
888 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100889#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600890 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
891};
892
893static const char *bc_err_msgs[] = {
894
895 NULL,
896 "memory allocation error",
897 "I/O error",
898 "file is not text:",
899 "path is a directory:",
900
901 "bad character",
902 "string end could not be found",
903 "comment end could not be found",
904 "end of file",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100905#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600906 "extended register",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100907#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600908
909 "bad token",
910 "bad expression",
911 "empty expression",
912 "bad print statement",
913 "bad function definition",
914 "bad assignment: left side must be scale, ibase, "
915 "obase, last, var, or array element",
916 "no auto variable found",
917 "function parameter or auto var has the same name as another",
918 "block end could not be found",
919
920 "negative number",
921 "non integer number",
922 "overflow",
923 "divide by zero",
924 "bad number string",
925
926 "could not open file:",
927 "mismatched parameters",
928 "undefined function",
929 "file is not executable:",
930 "number too long: must be [1, BC_NUM_MAX]",
931 "name too long: must be [1, BC_NAME_MAX]",
932 "string too long: must be [1, BC_STRING_MAX]",
933 "array too long; must be [1, BC_DIM_MAX]",
934 "bad ibase; must be [2, 16]",
935 "bad scale; must be [0, BC_SCALE_MAX]",
936 "bad read() expression",
937 "read() call inside of a read() call",
938 "variable is wrong type",
939 "bad obase; must be [2, BC_BASE_MAX]",
940 "signal caught and not handled",
941 "stack has too few elements",
942
943 "index is out of bounds",
944 "item already exists",
945
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100946#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600947 "POSIX only allows one character names; the following is bad:",
948 "POSIX does not allow '#' script comments",
949 "POSIX does not allow the following keyword:",
950 "POSIX does not allow a period ('.') as a shortcut for the last result",
951 "POSIX requires parentheses around return expressions",
952 "POSIX does not allow boolean operators; the following is bad:",
953 "POSIX does not allow comparison operators outside if or loops",
954 "POSIX requires exactly one comparison operator per condition",
955 "POSIX does not allow an empty init expression in a for loop",
956 "POSIX does not allow an empty condition expression in a for loop",
957 "POSIX does not allow an empty update expression in a for loop",
958 "POSIX requires the left brace be on the same line as the function header",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100959#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600960
961};
962
963static const char bc_func_main[] = "(main)";
964static const char bc_func_read[] = "(read)";
965
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100966#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600967static const BcLexKeyword bc_lex_kws[20] = {
968 BC_LEX_KW_ENTRY("auto", 4, true),
969 BC_LEX_KW_ENTRY("break", 5, true),
970 BC_LEX_KW_ENTRY("continue", 8, false),
971 BC_LEX_KW_ENTRY("define", 6, true),
972 BC_LEX_KW_ENTRY("else", 4, false),
973 BC_LEX_KW_ENTRY("for", 3, true),
974 BC_LEX_KW_ENTRY("halt", 4, false),
975 BC_LEX_KW_ENTRY("ibase", 5, true),
976 BC_LEX_KW_ENTRY("if", 2, true),
977 BC_LEX_KW_ENTRY("last", 4, false),
978 BC_LEX_KW_ENTRY("length", 6, true),
979 BC_LEX_KW_ENTRY("limits", 6, false),
980 BC_LEX_KW_ENTRY("obase", 5, true),
981 BC_LEX_KW_ENTRY("print", 5, false),
982 BC_LEX_KW_ENTRY("quit", 4, true),
983 BC_LEX_KW_ENTRY("read", 4, false),
984 BC_LEX_KW_ENTRY("return", 6, true),
985 BC_LEX_KW_ENTRY("scale", 5, true),
986 BC_LEX_KW_ENTRY("sqrt", 4, true),
987 BC_LEX_KW_ENTRY("while", 5, true),
988};
989
990// This is an array that corresponds to token types. An entry is
991// true if the token is valid in an expression, false otherwise.
992static const bool bc_parse_exprs[] = {
993 false, false, true, true, true, true, true, true, true, true, true, true,
994 true, true, true, true, true, true, true, true, true, true, true, true,
995 true, true, true, false, false, true, true, false, false, false, false,
996 false, false, false, true, true, false, false, false, false, false, false,
997 false, true, false, true, true, true, true, false, false, true, false, true,
998 true, false,
999};
1000
1001// This is an array of data for operators that correspond to token types.
1002static const BcOp bc_parse_ops[] = {
1003 { 0, false }, { 0, false },
1004 { 1, false },
1005 { 2, false },
1006 { 3, true }, { 3, true }, { 3, true },
1007 { 4, true }, { 4, true },
1008 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1009 { 1, false },
1010 { 7, true }, { 7, true },
1011 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1012 { 5, false }, { 5, false },
1013};
1014
1015// These identify what tokens can come after expressions in certain cases.
1016static const BcParseNext bc_parse_next_expr =
1017 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1018static const BcParseNext bc_parse_next_param =
1019 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1020static const BcParseNext bc_parse_next_print =
1021 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1022static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1023static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1024static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1025static const BcParseNext bc_parse_next_read =
1026 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1027#endif // ENABLE_BC
1028
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001029#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06001030static const BcLexType dc_lex_regs[] = {
1031 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1032 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1033 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1034 BC_LEX_STORE_PUSH,
1035};
1036
1037static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1038
1039static const BcLexType dc_lex_tokens[] = {
1040 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1041 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1042 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1043 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1044 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1045 BC_LEX_INVALID, BC_LEX_INVALID,
1046 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1047 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1048 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1049 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1050 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1051 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1052 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1053 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1054 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1055 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1056 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1057 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1058 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1059 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1060 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1061 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1062 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1063 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1064 BC_LEX_INVALID
1065};
1066
1067static const BcInst dc_parse_insts[] = {
1068 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1069 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1070 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1071 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1072 BC_INST_INVALID, BC_INST_INVALID,
1073 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1074 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1075 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1076 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1077 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1078 BC_INST_INVALID, BC_INST_INVALID,
1079 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1080 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1081 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1082 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1083 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1085 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1086 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1087 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1088 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1091};
1092#endif // ENABLE_DC
1093
Gavin Howard01055ba2018-11-03 11:00:21 -06001094static const BcNumBinaryOp bc_program_ops[] = {
1095 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1096};
1097
1098static const char bc_program_stdin_name[] = "<stdin>";
1099static const char bc_program_ready_msg[] = "ready for more input\n";
1100
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001101#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001102static const char *bc_lib_name = "gen/lib.bc";
1103
1104static const char bc_lib[] = {
1105 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1106 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1107 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1108 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
1109 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1110 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1111 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
1112 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1113 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1114 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
1115 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1116 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1117 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1118 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1119 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1120 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1121 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1122 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1123 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1124 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1125 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1126 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1127 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1128 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
1129 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1130 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
1131 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1132 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1133 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1134 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1135 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1136 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
1137 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1138 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1139 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1140 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1141 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
1142 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1143 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1144 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1145 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1146 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1147 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1148 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1149 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1150 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1151 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1152 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
1153 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
1154 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1155 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
1156 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
1157 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
1158 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1159 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1160 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
1161 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
1162 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
1163 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1164 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
1165 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1166 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1167 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1168 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
1169 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1170 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1171 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1172 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1173 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1174 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1175 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1176 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1177 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1178 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1179 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1180 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1181 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1182 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1183 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1184 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1185};
1186#endif // ENABLE_BC
1187
1188static void bc_vec_grow(BcVec *v, size_t n)
1189{
1190 size_t cap = v->cap * 2;
1191 while (cap < v->len + n) cap *= 2;
1192 v->v = xrealloc(v->v, v->size * cap);
1193 v->cap = cap;
1194}
1195
1196static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1197{
1198 v->size = esize;
1199 v->cap = BC_VEC_START_CAP;
1200 v->len = 0;
1201 v->dtor = dtor;
1202 v->v = xmalloc(esize * BC_VEC_START_CAP);
1203}
1204
1205static void bc_vec_expand(BcVec *v, size_t req)
1206{
1207 if (v->cap < req) {
1208 v->v = xrealloc(v->v, v->size * req);
1209 v->cap = req;
1210 }
1211}
1212
1213static void bc_vec_npop(BcVec *v, size_t n)
1214{
1215 if (!v->dtor)
1216 v->len -= n;
1217 else {
1218 size_t len = v->len - n;
1219 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1220 }
1221}
1222
1223static void bc_vec_push(BcVec *v, const void *data)
1224{
1225 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1226 memmove(v->v + (v->size * v->len), data, v->size);
1227 v->len += 1;
1228}
1229
1230static void bc_vec_pushByte(BcVec *v, char data)
1231{
1232 bc_vec_push(v, &data);
1233}
1234
1235static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1236{
1237 if (idx == v->len)
1238 bc_vec_push(v, data);
1239 else {
1240
1241 char *ptr;
1242
1243 if (v->len == v->cap) bc_vec_grow(v, 1);
1244
1245 ptr = v->v + v->size * idx;
1246
1247 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1248 memmove(ptr, data, v->size);
1249 }
1250}
1251
1252static void bc_vec_string(BcVec *v, size_t len, const char *str)
1253{
1254 bc_vec_npop(v, v->len);
1255 bc_vec_expand(v, len + 1);
1256 memcpy(v->v, str, len);
1257 v->len = len;
1258
1259 bc_vec_pushByte(v, '\0');
1260}
1261
1262static void bc_vec_concat(BcVec *v, const char *str)
1263{
1264 size_t len;
1265
1266 if (v->len == 0) bc_vec_pushByte(v, '\0');
1267
1268 len = v->len + strlen(str);
1269
1270 if (v->cap < len) bc_vec_grow(v, len - v->len);
1271 strcat(v->v, str);
1272
1273 v->len = len;
1274}
1275
1276static void *bc_vec_item(const BcVec *v, size_t idx)
1277{
1278 return v->v + v->size * idx;
1279}
1280
1281static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1282{
1283 return v->v + v->size * (v->len - idx - 1);
1284}
1285
1286static void bc_vec_free(void *vec)
1287{
1288 BcVec *v = (BcVec *) vec;
1289 bc_vec_npop(v, v->len);
1290 free(v->v);
1291}
1292
1293static size_t bc_map_find(const BcVec *v, const void *ptr)
1294{
1295 size_t low = 0, high = v->len;
1296
1297 while (low < high) {
1298
1299 size_t mid = (low + high) / 2;
1300 BcId *id = bc_vec_item(v, mid);
1301 int result = bc_id_cmp(ptr, id);
1302
1303 if (result == 0)
1304 return mid;
1305 else if (result < 0)
1306 high = mid;
1307 else
1308 low = mid + 1;
1309 }
1310
1311 return low;
1312}
1313
1314static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1315{
1316 BcStatus s = BC_STATUS_SUCCESS;
1317
1318 *i = bc_map_find(v, ptr);
1319
1320 if (*i == v->len)
1321 bc_vec_push(v, ptr);
1322 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1323 s = BC_STATUS_VEC_ITEM_EXISTS;
1324 else
1325 bc_vec_pushAt(v, ptr, *i);
1326
1327 return s;
1328}
1329
1330static size_t bc_map_index(const BcVec *v, const void *ptr)
1331{
1332 size_t i = bc_map_find(v, ptr);
1333 if (i >= v->len) return BC_VEC_INVALID_IDX;
1334 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1335}
1336
1337static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1338{
1339 int i;
Denys Vlasenko00d77792018-11-30 23:13:42 +01001340 signed char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001341
Gavin Howard01055ba2018-11-03 11:00:21 -06001342 bc_vec_npop(vec, vec->len);
1343
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001344 fflush(stdout);
1345#if ENABLE_FEATURE_BC_SIGNALS
1346 if (bb_got_signal) { /* ^C was pressed */
1347 intr:
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001348 bb_got_signal = 0; /* resets G_interrupt to zero */
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001349 fputs(IS_BC
1350 ? "\ninterrupt (type \"quit\" to exit)\n"
1351 : "\ninterrupt (type \"q\" to exit)\n"
1352 , stderr);
1353 }
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001354#endif
1355 if (G.ttyin && !G_posix)
1356 fputs(prompt, stderr);
1357 fflush(stderr);
1358
1359#if ENABLE_FEATURE_BC_SIGNALS
1360 again:
1361 errno = 0;
1362#endif
Denys Vlasenko00d77792018-11-30 23:13:42 +01001363 do {
1364 if (ferror(stdout) || ferror(stderr))
1365 bb_perror_msg_and_die("output error");
Gavin Howard01055ba2018-11-03 11:00:21 -06001366
1367 i = fgetc(stdin);
1368
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001369#if ENABLE_FEATURE_BC_SIGNALS
1370 if (bb_got_signal) /* ^C was pressed */
1371 goto intr;
1372#endif
1373
Gavin Howard01055ba2018-11-03 11:00:21 -06001374 if (i == EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001375#if ENABLE_FEATURE_BC_SIGNALS
1376 if (errno == EINTR) {
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001377 clearerr(stdin);
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001378 goto again;
Gavin Howard01055ba2018-11-03 11:00:21 -06001379 }
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01001380#endif
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001381 if (ferror(stdin))
1382 bb_perror_msg_and_die("input error");
Denys Vlasenko00d77792018-11-30 23:13:42 +01001383 return BC_STATUS_INPUT_EOF;
Gavin Howard01055ba2018-11-03 11:00:21 -06001384 }
1385
1386 c = (signed char) i;
1387 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1388 bc_vec_push(vec, &c);
Denys Vlasenko00d77792018-11-30 23:13:42 +01001389 } while (c != '\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06001390
1391 bc_vec_pushByte(vec, '\0');
1392
1393 return BC_STATUS_SUCCESS;
1394}
1395
Denys Vlasenkodf515392018-12-02 19:27:48 +01001396static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001397{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001398 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001399 size_t size = ((size_t) -1);
1400 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001401
Denys Vlasenkodf515392018-12-02 19:27:48 +01001402 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001403
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001404 for (i = 0; i < size; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001405 if (BC_READ_BIN_CHAR(buf[i])) {
1406 free(buf);
1407 buf = NULL;
1408 break;
1409 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001410 }
1411
Denys Vlasenkodf515392018-12-02 19:27:48 +01001412 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001413}
1414
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001415static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001416{
Gavin Howard01055ba2018-11-03 11:00:21 -06001417 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001418
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001419 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001420#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001421 G.flags = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001422 "extended-register\0" No_argument "x"
1423 "warn\0" No_argument "w"
1424 "version\0" No_argument "v"
1425 "standard\0" No_argument "s"
1426 "quiet\0" No_argument "q"
1427 "mathlib\0" No_argument "l"
1428 "interactive\0" No_argument "i"
1429 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001430#else
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001431 G.flags = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001432#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001433
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001434 if (G.flags & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001435 // should not be necessary, getopt32() handles this??
1436 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001437
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001438 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001439}
1440
1441static void bc_num_setToZero(BcNum *n, size_t scale)
1442{
1443 n->len = 0;
1444 n->neg = false;
1445 n->rdx = scale;
1446}
1447
1448static void bc_num_zero(BcNum *n)
1449{
1450 bc_num_setToZero(n, 0);
1451}
1452
1453static void bc_num_one(BcNum *n)
1454{
1455 bc_num_setToZero(n, 0);
1456 n->len = 1;
1457 n->num[0] = 1;
1458}
1459
1460static void bc_num_ten(BcNum *n)
1461{
1462 bc_num_setToZero(n, 0);
1463 n->len = 2;
1464 n->num[0] = 0;
1465 n->num[1] = 1;
1466}
1467
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001468static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001469 size_t len)
1470{
1471 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001472 for (i = 0; i < len; ++i) {
1473 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001474 a[i + j++] += 10;
1475 a[i + j] -= 1;
1476 }
1477 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001478}
1479
1480static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1481{
1482 size_t i;
1483 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001484 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001485 return BC_NUM_NEG(i + 1, c < 0);
1486}
1487
1488static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1489{
1490 size_t i, min, a_int, b_int, diff;
1491 BcDig *max_num, *min_num;
1492 bool a_max, neg = false;
1493 ssize_t cmp;
1494
1495 if (a == b) return 0;
1496 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1497 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1498 if (a->neg) {
1499 if (b->neg)
1500 neg = true;
1501 else
1502 return -1;
1503 }
1504 else if (b->neg)
1505 return 1;
1506
1507 a_int = BC_NUM_INT(a);
1508 b_int = BC_NUM_INT(b);
1509 a_int -= b_int;
1510 a_max = (a->rdx > b->rdx);
1511
1512 if (a_int != 0) return (ssize_t) a_int;
1513
1514 if (a_max) {
1515 min = b->rdx;
1516 diff = a->rdx - b->rdx;
1517 max_num = a->num + diff;
1518 min_num = b->num;
1519 }
1520 else {
1521 min = a->rdx;
1522 diff = b->rdx - a->rdx;
1523 max_num = b->num + diff;
1524 min_num = a->num;
1525 }
1526
1527 cmp = bc_num_compare(max_num, min_num, b_int + min);
1528 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1529
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001530 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001531 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1532 }
1533
1534 return 0;
1535}
1536
1537static void bc_num_truncate(BcNum *n, size_t places)
1538{
1539 if (places == 0) return;
1540
1541 n->rdx -= places;
1542
1543 if (n->len != 0) {
1544 n->len -= places;
1545 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1546 }
1547}
1548
1549static void bc_num_extend(BcNum *n, size_t places)
1550{
1551 size_t len = n->len + places;
1552
1553 if (places != 0) {
1554
1555 if (n->cap < len) bc_num_expand(n, len);
1556
1557 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1558 memset(n->num, 0, sizeof(BcDig) * places);
1559
1560 n->len += places;
1561 n->rdx += places;
1562 }
1563}
1564
1565static void bc_num_clean(BcNum *n)
1566{
1567 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1568 if (n->len == 0)
1569 n->neg = false;
1570 else if (n->len < n->rdx)
1571 n->len = n->rdx;
1572}
1573
1574static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1575{
1576 if (n->rdx < scale)
1577 bc_num_extend(n, scale - n->rdx);
1578 else
1579 bc_num_truncate(n, n->rdx - scale);
1580
1581 bc_num_clean(n);
1582 if (n->len != 0) n->neg = !neg1 != !neg2;
1583}
1584
1585static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1586 BcNum *restrict b)
1587{
1588 if (idx < n->len) {
1589
1590 b->len = n->len - idx;
1591 a->len = idx;
1592 a->rdx = b->rdx = 0;
1593
1594 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1595 memcpy(a->num, n->num, idx * sizeof(BcDig));
1596 }
1597 else {
1598 bc_num_zero(b);
1599 bc_num_copy(a, n);
1600 }
1601
1602 bc_num_clean(a);
1603 bc_num_clean(b);
1604}
1605
1606static BcStatus bc_num_shift(BcNum *n, size_t places)
1607{
1608 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1609 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1610
1611 if (n->rdx >= places)
1612 n->rdx -= places;
1613 else {
1614 bc_num_extend(n, places - n->rdx);
1615 n->rdx = 0;
1616 }
1617
1618 bc_num_clean(n);
1619
1620 return BC_STATUS_SUCCESS;
1621}
1622
1623static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1624{
1625 BcNum one;
1626 BcDig num[2];
1627
1628 one.cap = 2;
1629 one.num = num;
1630 bc_num_one(&one);
1631
1632 return bc_num_div(&one, a, b, scale);
1633}
1634
1635static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1636{
1637 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1638 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1639 int carry, in;
1640
1641 // Because this function doesn't need to use scale (per the bc spec),
1642 // I am hijacking it to say whether it's doing an add or a subtract.
1643
1644 if (a->len == 0) {
1645 bc_num_copy(c, b);
1646 if (sub && c->len) c->neg = !c->neg;
1647 return BC_STATUS_SUCCESS;
1648 }
1649 else if (b->len == 0) {
1650 bc_num_copy(c, a);
1651 return BC_STATUS_SUCCESS;
1652 }
1653
1654 c->neg = a->neg;
1655 c->rdx = BC_MAX(a->rdx, b->rdx);
1656 min_rdx = BC_MIN(a->rdx, b->rdx);
1657 c->len = 0;
1658
1659 if (a->rdx > b->rdx) {
1660 diff = a->rdx - b->rdx;
1661 ptr = a->num;
1662 ptr_a = a->num + diff;
1663 ptr_b = b->num;
1664 }
1665 else {
1666 diff = b->rdx - a->rdx;
1667 ptr = b->num;
1668 ptr_a = a->num;
1669 ptr_b = b->num + diff;
1670 }
1671
1672 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1673
1674 ptr_c += diff;
1675 a_int = BC_NUM_INT(a);
1676 b_int = BC_NUM_INT(b);
1677
1678 if (a_int > b_int) {
1679 min_int = b_int;
1680 max = a_int;
1681 ptr = ptr_a;
1682 }
1683 else {
1684 min_int = a_int;
1685 max = b_int;
1686 ptr = ptr_b;
1687 }
1688
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001689 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001690 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1691 carry = in / 10;
1692 ptr_c[i] = (BcDig)(in % 10);
1693 }
1694
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001695 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001696 in = ((int) ptr[i]) + carry;
1697 carry = in / 10;
1698 ptr_c[i] = (BcDig)(in % 10);
1699 }
1700
1701 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1702
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001703 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001704}
1705
1706static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1707{
Gavin Howard01055ba2018-11-03 11:00:21 -06001708 ssize_t cmp;
1709 BcNum *minuend, *subtrahend;
1710 size_t start;
1711 bool aneg, bneg, neg;
1712
1713 // Because this function doesn't need to use scale (per the bc spec),
1714 // I am hijacking it to say whether it's doing an add or a subtract.
1715
1716 if (a->len == 0) {
1717 bc_num_copy(c, b);
1718 if (sub && c->len) c->neg = !c->neg;
1719 return BC_STATUS_SUCCESS;
1720 }
1721 else if (b->len == 0) {
1722 bc_num_copy(c, a);
1723 return BC_STATUS_SUCCESS;
1724 }
1725
1726 aneg = a->neg;
1727 bneg = b->neg;
1728 a->neg = b->neg = false;
1729
1730 cmp = bc_num_cmp(a, b);
1731
1732 a->neg = aneg;
1733 b->neg = bneg;
1734
1735 if (cmp == 0) {
1736 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1737 return BC_STATUS_SUCCESS;
1738 }
1739 else if (cmp > 0) {
1740 neg = a->neg;
1741 minuend = a;
1742 subtrahend = b;
1743 }
1744 else {
1745 neg = b->neg;
1746 if (sub) neg = !neg;
1747 minuend = b;
1748 subtrahend = a;
1749 }
1750
1751 bc_num_copy(c, minuend);
1752 c->neg = neg;
1753
1754 if (c->rdx < subtrahend->rdx) {
1755 bc_num_extend(c, subtrahend->rdx - c->rdx);
1756 start = 0;
1757 }
1758 else
1759 start = c->rdx - subtrahend->rdx;
1760
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001761 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001762
1763 bc_num_clean(c);
1764
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001765 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001766}
1767
1768static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1769 BcNum *restrict c)
1770{
1771 BcStatus s;
1772 int carry;
1773 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1774 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1775 bool aone = BC_NUM_ONE(a);
1776
Gavin Howard01055ba2018-11-03 11:00:21 -06001777 if (a->len == 0 || b->len == 0) {
1778 bc_num_zero(c);
1779 return BC_STATUS_SUCCESS;
1780 }
1781 else if (aone || BC_NUM_ONE(b)) {
1782 bc_num_copy(c, aone ? b : a);
1783 return BC_STATUS_SUCCESS;
1784 }
1785
1786 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1787 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1788 {
1789 bc_num_expand(c, a->len + b->len + 1);
1790
1791 memset(c->num, 0, sizeof(BcDig) * c->cap);
1792 c->len = carry = len = 0;
1793
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001794 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001795
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001796 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001797 int in = (int) c->num[i + j];
1798 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1799 carry = in / 10;
1800 c->num[i + j] = (BcDig)(in % 10);
1801 }
1802
1803 c->num[i + j] += (BcDig) carry;
1804 len = BC_MAX(len, i + j + !!carry);
1805 carry = 0;
1806 }
1807
1808 c->len = len;
1809
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001810 return 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 Vlasenko71e1fc62018-12-02 19:43:34 +01001960 for (i = end - 1; !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)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001963 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001964 c->num[i] = q;
1965 }
1966
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001967 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001968 bc_num_free(&cp);
1969
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001970 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001971}
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 Vlasenko71e1fc62018-12-02 19:43:34 +01002060 for (powrdx = a->rdx; !(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
Gavin Howard01055ba2018-11-03 11:00:21 -06002066 bc_num_copy(c, &copy);
2067
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002068 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002069
2070 powrdx <<= 1;
2071 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2072 if (s) goto err;
2073
2074 if (pow & 1) {
2075 resrdx += powrdx;
2076 s = bc_num_mul(c, &copy, c, resrdx);
2077 if (s) goto err;
2078 }
2079 }
2080
2081 if (neg) {
2082 s = bc_num_inv(c, c, scale);
2083 if (s) goto err;
2084 }
2085
Gavin Howard01055ba2018-11-03 11:00:21 -06002086 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2087
2088 // We can't use bc_num_clean() here.
2089 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2090 if (zero) bc_num_setToZero(c, scale);
2091
2092err:
2093 bc_num_free(&copy);
2094 return s;
2095}
2096
2097static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2098 BcNumBinaryOp op, size_t req)
2099{
2100 BcStatus s;
2101 BcNum num2, *ptr_a, *ptr_b;
2102 bool init = false;
2103
2104 if (c == a) {
2105 ptr_a = &num2;
2106 memcpy(ptr_a, c, sizeof(BcNum));
2107 init = true;
2108 }
2109 else
2110 ptr_a = a;
2111
2112 if (c == b) {
2113 ptr_b = &num2;
2114 if (c != a) {
2115 memcpy(ptr_b, c, sizeof(BcNum));
2116 init = true;
2117 }
2118 }
2119 else
2120 ptr_b = b;
2121
2122 if (init)
2123 bc_num_init(c, req);
2124 else
2125 bc_num_expand(c, req);
2126
2127 s = op(ptr_a, ptr_b, c, scale);
2128
2129 if (init) bc_num_free(&num2);
2130
2131 return s;
2132}
2133
2134static bool bc_num_strValid(const char *val, size_t base)
2135{
2136 BcDig b;
2137 bool small, radix = false;
2138 size_t i, len = strlen(val);
2139
2140 if (!len) return true;
2141
2142 small = base <= 10;
2143 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2144
2145 for (i = 0; i < len; ++i) {
2146
2147 BcDig c = val[i];
2148
2149 if (c == '.') {
2150
2151 if (radix) return false;
2152
2153 radix = true;
2154 continue;
2155 }
2156
2157 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2158 return false;
2159 }
2160
2161 return true;
2162}
2163
2164static void bc_num_parseDecimal(BcNum *n, const char *val)
2165{
2166 size_t len, i;
2167 const char *ptr;
2168 bool zero = true;
2169
2170 for (i = 0; val[i] == '0'; ++i);
2171
2172 val += i;
2173 len = strlen(val);
2174 bc_num_zero(n);
2175
2176 if (len != 0) {
2177 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2178 bc_num_expand(n, len);
2179 }
2180
2181 ptr = strchr(val, '.');
2182
2183 // Explicitly test for NULL here to produce either a 0 or 1.
2184 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2185
2186 if (!zero) {
2187 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2188 n->num[n->len] = val[i] - '0';
2189 }
2190}
2191
2192static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2193{
2194 BcStatus s;
2195 BcNum temp, mult, result;
2196 BcDig c = '\0';
2197 bool zero = true;
2198 unsigned long v;
2199 size_t i, digits, len = strlen(val);
2200
2201 bc_num_zero(n);
2202
2203 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2204 if (zero) return;
2205
2206 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2207 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2208
2209 for (i = 0; i < len; ++i) {
2210
2211 c = val[i];
2212 if (c == '.') break;
2213
2214 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2215
2216 s = bc_num_mul(n, base, &mult, 0);
2217 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002218 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002219 s = bc_num_add(&mult, &temp, n, 0);
2220 if (s) goto int_err;
2221 }
2222
2223 if (i == len) {
2224 c = val[i];
2225 if (c == 0) goto int_err;
2226 }
2227
2228 bc_num_init(&result, base->len);
2229 bc_num_zero(&result);
2230 bc_num_one(&mult);
2231
2232 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2233
2234 c = val[i];
2235 if (c == 0) break;
2236
2237 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2238
2239 s = bc_num_mul(&result, base, &result, 0);
2240 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002241 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002242 s = bc_num_add(&result, &temp, &result, 0);
2243 if (s) goto err;
2244 s = bc_num_mul(&mult, base, &mult, 0);
2245 if (s) goto err;
2246 }
2247
2248 s = bc_num_div(&result, &mult, &result, digits);
2249 if (s) goto err;
2250 s = bc_num_add(n, &result, n, digits);
2251 if (s) goto err;
2252
2253 if (n->len != 0) {
2254 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2255 }
2256 else
2257 bc_num_zero(n);
2258
2259err:
2260 bc_num_free(&result);
2261int_err:
2262 bc_num_free(&mult);
2263 bc_num_free(&temp);
2264}
2265
2266static void bc_num_printNewline(size_t *nchars, size_t line_len)
2267{
2268 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002269 bb_putchar('\\');
2270 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002271 *nchars = 0;
2272 }
2273}
2274
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002275#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002276static void bc_num_printChar(size_t num, size_t width, bool radix,
2277 size_t *nchars, size_t line_len)
2278{
2279 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002280 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002281 *nchars = *nchars + width;
2282}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002283#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002284
2285static void bc_num_printDigits(size_t num, size_t width, bool radix,
2286 size_t *nchars, size_t line_len)
2287{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002288 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002289
2290 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002291 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002292 ++(*nchars);
2293
2294 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002295 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2296 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002297
2298 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002299 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002300 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002301 dig = num / pow;
2302 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002303 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002304 }
2305}
2306
2307static void bc_num_printHex(size_t num, size_t width, bool radix,
2308 size_t *nchars, size_t line_len)
2309{
2310 if (radix) {
2311 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002312 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002313 *nchars += 1;
2314 }
2315
2316 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002317 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002318 *nchars = *nchars + width;
2319}
2320
2321static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2322{
2323 size_t i, rdx = n->rdx - 1;
2324
Denys Vlasenko00d77792018-11-30 23:13:42 +01002325 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002326 (*nchars) += n->neg;
2327
2328 for (i = n->len - 1; i < n->len; --i)
2329 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2330}
2331
2332static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2333 size_t *nchars, size_t len, BcNumDigitOp print)
2334{
2335 BcStatus s;
2336 BcVec stack;
2337 BcNum intp, fracp, digit, frac_len;
2338 unsigned long dig, *ptr;
2339 size_t i;
2340 bool radix;
2341
2342 if (n->len == 0) {
2343 print(0, width, false, nchars, len);
2344 return BC_STATUS_SUCCESS;
2345 }
2346
2347 bc_vec_init(&stack, sizeof(long), NULL);
2348 bc_num_init(&intp, n->len);
2349 bc_num_init(&fracp, n->rdx);
2350 bc_num_init(&digit, width);
2351 bc_num_init(&frac_len, BC_NUM_INT(n));
2352 bc_num_copy(&intp, n);
2353 bc_num_one(&frac_len);
2354
2355 bc_num_truncate(&intp, intp.rdx);
2356 s = bc_num_sub(n, &intp, &fracp, 0);
2357 if (s) goto err;
2358
2359 while (intp.len != 0) {
2360 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2361 if (s) goto err;
2362 s = bc_num_ulong(&digit, &dig);
2363 if (s) goto err;
2364 bc_vec_push(&stack, &dig);
2365 }
2366
2367 for (i = 0; i < stack.len; ++i) {
2368 ptr = bc_vec_item_rev(&stack, i);
2369 print(*ptr, width, false, nchars, len);
2370 }
2371
2372 if (!n->rdx) goto err;
2373
2374 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2375 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2376 if (s) goto err;
2377 s = bc_num_ulong(&fracp, &dig);
2378 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002379 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002380 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2381 if (s) goto err;
2382 print(dig, width, radix, nchars, len);
2383 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2384 if (s) goto err;
2385 }
2386
2387err:
2388 bc_num_free(&frac_len);
2389 bc_num_free(&digit);
2390 bc_num_free(&fracp);
2391 bc_num_free(&intp);
2392 bc_vec_free(&stack);
2393 return s;
2394}
2395
2396static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2397 size_t *nchars, size_t line_len)
2398{
2399 BcStatus s;
2400 size_t width, i;
2401 BcNumDigitOp print;
2402 bool neg = n->neg;
2403
Denys Vlasenko00d77792018-11-30 23:13:42 +01002404 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002405 (*nchars) += neg;
2406
2407 n->neg = false;
2408
2409 if (base_t <= BC_NUM_MAX_IBASE) {
2410 width = 1;
2411 print = bc_num_printHex;
2412 }
2413 else {
2414 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2415 print = bc_num_printDigits;
2416 }
2417
2418 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2419 n->neg = neg;
2420
2421 return s;
2422}
2423
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002424#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002425static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2426{
2427 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2428}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002429#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002430
2431static void bc_num_init(BcNum *n, size_t req)
2432{
2433 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2434 memset(n, 0, sizeof(BcNum));
2435 n->num = xmalloc(req);
2436 n->cap = req;
2437}
2438
2439static void bc_num_expand(BcNum *n, size_t req)
2440{
2441 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2442 if (req > n->cap) {
2443 n->num = xrealloc(n->num, req);
2444 n->cap = req;
2445 }
2446}
2447
2448static void bc_num_free(void *num)
2449{
2450 free(((BcNum *) num)->num);
2451}
2452
2453static void bc_num_copy(BcNum *d, BcNum *s)
2454{
2455 if (d != s) {
2456 bc_num_expand(d, s->cap);
2457 d->len = s->len;
2458 d->neg = s->neg;
2459 d->rdx = s->rdx;
2460 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2461 }
2462}
2463
2464static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2465 size_t base_t)
2466{
2467 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2468
2469 if (base_t == 10)
2470 bc_num_parseDecimal(n, val);
2471 else
2472 bc_num_parseBase(n, val, base);
2473
2474 return BC_STATUS_SUCCESS;
2475}
2476
2477static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2478 size_t *nchars, size_t line_len)
2479{
2480 BcStatus s = BC_STATUS_SUCCESS;
2481
2482 bc_num_printNewline(nchars, line_len);
2483
2484 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002485 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002486 ++(*nchars);
2487 }
2488 else if (base_t == 10)
2489 bc_num_printDecimal(n, nchars, line_len);
2490 else
2491 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2492
2493 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002494 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002495 *nchars = 0;
2496 }
2497
2498 return s;
2499}
2500
2501static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2502{
2503 size_t i;
2504 unsigned long pow;
2505
2506 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2507
2508 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2509
2510 unsigned long prev = *result, powprev = pow;
2511
2512 *result += ((unsigned long) n->num[i]) * pow;
2513 pow *= 10;
2514
2515 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2516 }
2517
2518 return BC_STATUS_SUCCESS;
2519}
2520
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002521static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002522{
2523 size_t len;
2524 BcDig *ptr;
2525 unsigned long i;
2526
2527 bc_num_zero(n);
2528
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002529 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002530
2531 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2532 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002533}
2534
2535static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2536{
2537 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2538 (void) scale;
2539 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2540}
2541
2542static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2543{
2544 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2545 (void) scale;
2546 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2547}
2548
2549static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2550{
2551 size_t req = BC_NUM_MREQ(a, b, scale);
2552 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2553}
2554
2555static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2556{
2557 size_t req = BC_NUM_MREQ(a, b, scale);
2558 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2559}
2560
2561static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2562{
2563 size_t req = BC_NUM_MREQ(a, b, scale);
2564 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2565}
2566
2567static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2568{
2569 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2570}
2571
2572static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2573{
2574 BcStatus s;
2575 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2576 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2577 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2578
2579 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2580 bc_num_expand(b, req);
2581
2582 if (a->len == 0) {
2583 bc_num_setToZero(b, scale);
2584 return BC_STATUS_SUCCESS;
2585 }
2586 else if (a->neg)
2587 return BC_STATUS_MATH_NEGATIVE;
2588 else if (BC_NUM_ONE(a)) {
2589 bc_num_one(b);
2590 bc_num_extend(b, scale);
2591 return BC_STATUS_SUCCESS;
2592 }
2593
2594 scale = BC_MAX(scale, a->rdx) + 1;
2595 len = a->len + scale;
2596
2597 bc_num_init(&num1, len);
2598 bc_num_init(&num2, len);
2599 bc_num_init(&half, BC_NUM_DEF_SIZE);
2600
2601 bc_num_one(&half);
2602 half.num[0] = 5;
2603 half.rdx = 1;
2604
2605 bc_num_init(&f, len);
2606 bc_num_init(&fprime, len);
2607
2608 x0 = &num1;
2609 x1 = &num2;
2610
2611 bc_num_one(x0);
2612 pow = BC_NUM_INT(a);
2613
2614 if (pow) {
2615
2616 if (pow & 1)
2617 x0->num[0] = 2;
2618 else
2619 x0->num[0] = 6;
2620
2621 pow -= 2 - (pow & 1);
2622
2623 bc_num_extend(x0, pow);
2624
2625 // Make sure to move the radix back.
2626 x0->rdx -= pow;
2627 }
2628
2629 x0->rdx = digs = digs1 = 0;
2630 resrdx = scale + 2;
2631 len = BC_NUM_INT(x0) + resrdx - 1;
2632
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002633 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002634
2635 s = bc_num_div(a, x0, &f, resrdx);
2636 if (s) goto err;
2637 s = bc_num_add(x0, &f, &fprime, resrdx);
2638 if (s) goto err;
2639 s = bc_num_mul(&fprime, &half, x1, resrdx);
2640 if (s) goto err;
2641
2642 cmp = bc_num_cmp(x1, x0);
2643 digs = x1->len - (unsigned long long) llabs(cmp);
2644
2645 if (cmp == cmp2 && digs == digs1)
2646 times += 1;
2647 else
2648 times = 0;
2649
2650 resrdx += times > 4;
2651
2652 cmp2 = cmp1;
2653 cmp1 = cmp;
2654 digs1 = digs;
2655
2656 temp = x0;
2657 x0 = x1;
2658 x1 = temp;
2659 }
2660
Gavin Howard01055ba2018-11-03 11:00:21 -06002661 bc_num_copy(b, x0);
2662 scale -= 1;
2663 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2664
2665err:
2666 bc_num_free(&fprime);
2667 bc_num_free(&f);
2668 bc_num_free(&half);
2669 bc_num_free(&num2);
2670 bc_num_free(&num1);
2671 return s;
2672}
2673
2674static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2675 size_t scale)
2676{
2677 BcStatus s;
2678 BcNum num2, *ptr_a;
2679 bool init = false;
2680 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2681
2682 if (c == a) {
2683 memcpy(&num2, c, sizeof(BcNum));
2684 ptr_a = &num2;
2685 bc_num_init(c, len);
2686 init = true;
2687 }
2688 else {
2689 ptr_a = a;
2690 bc_num_expand(c, len);
2691 }
2692
2693 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2694
2695 if (init) bc_num_free(&num2);
2696
2697 return s;
2698}
2699
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002700#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002701static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2702{
2703 BcStatus s;
2704 BcNum base, exp, two, temp;
2705
2706 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2707 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2708 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2709
2710 bc_num_expand(d, c->len);
2711 bc_num_init(&base, c->len);
2712 bc_num_init(&exp, b->len);
2713 bc_num_init(&two, BC_NUM_DEF_SIZE);
2714 bc_num_init(&temp, b->len);
2715
2716 bc_num_one(&two);
2717 two.num[0] = 2;
2718 bc_num_one(d);
2719
2720 s = bc_num_rem(a, c, &base, 0);
2721 if (s) goto err;
2722 bc_num_copy(&exp, b);
2723
2724 while (exp.len != 0) {
2725
2726 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2727 if (s) goto err;
2728
2729 if (BC_NUM_ONE(&temp)) {
2730 s = bc_num_mul(d, &base, &temp, 0);
2731 if (s) goto err;
2732 s = bc_num_rem(&temp, c, d, 0);
2733 if (s) goto err;
2734 }
2735
2736 s = bc_num_mul(&base, &base, &temp, 0);
2737 if (s) goto err;
2738 s = bc_num_rem(&temp, c, &base, 0);
2739 if (s) goto err;
2740 }
2741
2742err:
2743 bc_num_free(&temp);
2744 bc_num_free(&two);
2745 bc_num_free(&exp);
2746 bc_num_free(&base);
2747 return s;
2748}
2749#endif // ENABLE_DC
2750
2751static int bc_id_cmp(const void *e1, const void *e2)
2752{
2753 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2754}
2755
2756static void bc_id_free(void *id)
2757{
2758 free(((BcId *) id)->name);
2759}
2760
2761static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2762{
2763 BcId a;
2764 size_t i;
2765
2766 for (i = 0; i < f->autos.len; ++i) {
2767 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2768 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2769 }
2770
2771 a.idx = var;
2772 a.name = name;
2773
2774 bc_vec_push(&f->autos, &a);
2775
2776 return BC_STATUS_SUCCESS;
2777}
2778
2779static void bc_func_init(BcFunc *f)
2780{
2781 bc_vec_init(&f->code, sizeof(char), NULL);
2782 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2783 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2784 f->nparams = 0;
2785}
2786
2787static void bc_func_free(void *func)
2788{
2789 BcFunc *f = (BcFunc *) func;
2790 bc_vec_free(&f->code);
2791 bc_vec_free(&f->autos);
2792 bc_vec_free(&f->labels);
2793}
2794
2795static void bc_array_init(BcVec *a, bool nums)
2796{
2797 if (nums)
2798 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2799 else
2800 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2801 bc_array_expand(a, 1);
2802}
2803
2804static void bc_array_copy(BcVec *d, const BcVec *s)
2805{
2806 size_t i;
2807
2808 bc_vec_npop(d, d->len);
2809 bc_vec_expand(d, s->cap);
2810 d->len = s->len;
2811
2812 for (i = 0; i < s->len; ++i) {
2813 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2814 bc_num_init(dnum, snum->len);
2815 bc_num_copy(dnum, snum);
2816 }
2817}
2818
2819static void bc_array_expand(BcVec *a, size_t len)
2820{
2821 BcResultData data;
2822
2823 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2824 while (len > a->len) {
2825 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2826 bc_vec_push(a, &data.n);
2827 }
2828 }
2829 else {
2830 while (len > a->len) {
2831 bc_array_init(&data.v, true);
2832 bc_vec_push(a, &data.v);
2833 }
2834 }
2835}
2836
2837static void bc_string_free(void *string)
2838{
2839 free(*((char **) string));
2840}
2841
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002842#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002843static void bc_result_copy(BcResult *d, BcResult *src)
2844{
2845 d->t = src->t;
2846
2847 switch (d->t) {
2848
2849 case BC_RESULT_TEMP:
2850 case BC_RESULT_IBASE:
2851 case BC_RESULT_SCALE:
2852 case BC_RESULT_OBASE:
2853 {
2854 bc_num_init(&d->d.n, src->d.n.len);
2855 bc_num_copy(&d->d.n, &src->d.n);
2856 break;
2857 }
2858
2859 case BC_RESULT_VAR:
2860 case BC_RESULT_ARRAY:
2861 case BC_RESULT_ARRAY_ELEM:
2862 {
2863 d->d.id.name = xstrdup(src->d.id.name);
2864 break;
2865 }
2866
2867 case BC_RESULT_CONSTANT:
2868 case BC_RESULT_LAST:
2869 case BC_RESULT_ONE:
2870 case BC_RESULT_STR:
2871 {
2872 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2873 break;
2874 }
2875 }
2876}
2877#endif // ENABLE_DC
2878
2879static void bc_result_free(void *result)
2880{
2881 BcResult *r = (BcResult *) result;
2882
2883 switch (r->t) {
2884
2885 case BC_RESULT_TEMP:
2886 case BC_RESULT_IBASE:
2887 case BC_RESULT_SCALE:
2888 case BC_RESULT_OBASE:
2889 {
2890 bc_num_free(&r->d.n);
2891 break;
2892 }
2893
2894 case BC_RESULT_VAR:
2895 case BC_RESULT_ARRAY:
2896 case BC_RESULT_ARRAY_ELEM:
2897 {
2898 free(r->d.id.name);
2899 break;
2900 }
2901
2902 default:
2903 {
2904 // Do nothing.
2905 break;
2906 }
2907 }
2908}
2909
2910static void bc_lex_lineComment(BcLex *l)
2911{
2912 l->t.t = BC_LEX_WHITESPACE;
2913 while (l->i < l->len && l->buf[l->i++] != '\n');
2914 --l->i;
2915}
2916
2917static void bc_lex_whitespace(BcLex *l)
2918{
2919 char c;
2920 l->t.t = BC_LEX_WHITESPACE;
2921 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2922}
2923
2924static BcStatus bc_lex_number(BcLex *l, char start)
2925{
2926 const char *buf = l->buf + l->i;
2927 size_t len, hits = 0, bslashes = 0, i = 0, j;
2928 char c = buf[i];
2929 bool last_pt, pt = start == '.';
2930
2931 last_pt = pt;
2932 l->t.t = BC_LEX_NUMBER;
2933
2934 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2935 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2936 {
2937 if (c != '\\') {
2938 last_pt = c == '.';
2939 pt = pt || last_pt;
2940 }
2941 else {
2942 ++i;
2943 bslashes += 1;
2944 }
2945
2946 c = buf[++i];
2947 }
2948
2949 len = i + 1 * !last_pt - bslashes * 2;
2950 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2951
2952 bc_vec_npop(&l->t.v, l->t.v.len);
2953 bc_vec_expand(&l->t.v, len + 1);
2954 bc_vec_push(&l->t.v, &start);
2955
2956 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2957
2958 c = buf[j];
2959
2960 // If we have hit a backslash, skip it. We don't have
2961 // to check for a newline because it's guaranteed.
2962 if (hits < bslashes && c == '\\') {
2963 ++hits;
2964 ++j;
2965 continue;
2966 }
2967
2968 bc_vec_push(&l->t.v, &c);
2969 }
2970
2971 bc_vec_pushByte(&l->t.v, '\0');
2972 l->i += i;
2973
2974 return BC_STATUS_SUCCESS;
2975}
2976
2977static BcStatus bc_lex_name(BcLex *l)
2978{
2979 size_t i = 0;
2980 const char *buf = l->buf + l->i - 1;
2981 char c = buf[i];
2982
2983 l->t.t = BC_LEX_NAME;
2984
2985 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2986
2987 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2988 bc_vec_string(&l->t.v, i, buf);
2989
2990 // Increment the index. We minus 1 because it has already been incremented.
2991 l->i += i - 1;
2992
2993 return BC_STATUS_SUCCESS;
2994}
2995
2996static void bc_lex_init(BcLex *l, BcLexNext next)
2997{
2998 l->next = next;
2999 bc_vec_init(&l->t.v, sizeof(char), NULL);
3000}
3001
3002static void bc_lex_free(BcLex *l)
3003{
3004 bc_vec_free(&l->t.v);
3005}
3006
3007static void bc_lex_file(BcLex *l, const char *file)
3008{
3009 l->line = 1;
3010 l->newline = false;
3011 l->f = file;
3012}
3013
3014static BcStatus bc_lex_next(BcLex *l)
3015{
3016 BcStatus s;
3017
3018 l->t.last = l->t.t;
3019 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3020
3021 l->line += l->newline;
3022 l->t.t = BC_LEX_EOF;
3023
3024 l->newline = (l->i == l->len);
3025 if (l->newline) return BC_STATUS_SUCCESS;
3026
3027 // Loop until failure or we don't have whitespace. This
3028 // is so the parser doesn't get inundated with whitespace.
3029 do {
3030 s = l->next(l);
3031 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3032
3033 return s;
3034}
3035
3036static BcStatus bc_lex_text(BcLex *l, const char *text)
3037{
3038 l->buf = text;
3039 l->i = 0;
3040 l->len = strlen(text);
3041 l->t.t = l->t.last = BC_LEX_INVALID;
3042 return bc_lex_next(l);
3043}
3044
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003045#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003046static BcStatus bc_lex_identifier(BcLex *l)
3047{
3048 BcStatus s;
3049 size_t i;
3050 const char *buf = l->buf + l->i - 1;
3051
3052 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3053
3054 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3055
3056 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3057
3058 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3059
3060 if (!bc_lex_kws[i].posix) {
3061 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3062 bc_lex_kws[i].name);
3063 if (s) return s;
3064 }
3065
3066 // We minus 1 because the index has already been incremented.
3067 l->i += len - 1;
3068 return BC_STATUS_SUCCESS;
3069 }
3070 }
3071
3072 s = bc_lex_name(l);
3073 if (s) return s;
3074
3075 if (l->t.v.len - 1 > 1)
3076 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3077
3078 return s;
3079}
3080
3081static BcStatus bc_lex_string(BcLex *l)
3082{
3083 size_t len, nls = 0, i = l->i;
3084 char c;
3085
3086 l->t.t = BC_LEX_STR;
3087
3088 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3089
3090 if (c == '\0') {
3091 l->i = i;
3092 return BC_STATUS_LEX_NO_STRING_END;
3093 }
3094
3095 len = i - l->i;
3096 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3097 bc_vec_string(&l->t.v, len, l->buf + l->i);
3098
3099 l->i = i + 1;
3100 l->line += nls;
3101
3102 return BC_STATUS_SUCCESS;
3103}
3104
3105static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3106{
3107 if (l->buf[l->i] == '=') {
3108 ++l->i;
3109 l->t.t = with;
3110 }
3111 else
3112 l->t.t = without;
3113}
3114
3115static BcStatus bc_lex_comment(BcLex *l)
3116{
3117 size_t i, nls = 0;
3118 const char *buf = l->buf;
3119 bool end = false;
3120 char c;
3121
3122 l->t.t = BC_LEX_WHITESPACE;
3123
3124 for (i = ++l->i; !end; i += !end) {
3125
3126 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3127
3128 if (c == 0 || buf[i + 1] == '\0') {
3129 l->i = i;
3130 return BC_STATUS_LEX_NO_COMMENT_END;
3131 }
3132
3133 end = buf[i + 1] == '/';
3134 }
3135
3136 l->i = i + 2;
3137 l->line += nls;
3138
3139 return BC_STATUS_SUCCESS;
3140}
3141
3142static BcStatus bc_lex_token(BcLex *l)
3143{
3144 BcStatus s = BC_STATUS_SUCCESS;
3145 char c = l->buf[l->i++], c2;
3146
3147 // This is the workhorse of the lexer.
3148 switch (c) {
3149
3150 case '\0':
3151 case '\n':
3152 {
3153 l->newline = true;
3154 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3155 break;
3156 }
3157
3158 case '\t':
3159 case '\v':
3160 case '\f':
3161 case '\r':
3162 case ' ':
3163 {
3164 bc_lex_whitespace(l);
3165 break;
3166 }
3167
3168 case '!':
3169 {
3170 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3171
3172 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3173 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3174 if (s) return s;
3175 }
3176
3177 break;
3178 }
3179
3180 case '"':
3181 {
3182 s = bc_lex_string(l);
3183 break;
3184 }
3185
3186 case '#':
3187 {
3188 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3189 if (s) return s;
3190
3191 bc_lex_lineComment(l);
3192
3193 break;
3194 }
3195
3196 case '%':
3197 {
3198 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3199 break;
3200 }
3201
3202 case '&':
3203 {
3204 c2 = l->buf[l->i];
3205 if (c2 == '&') {
3206
3207 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3208 if (s) return s;
3209
3210 ++l->i;
3211 l->t.t = BC_LEX_OP_BOOL_AND;
3212 }
3213 else {
3214 l->t.t = BC_LEX_INVALID;
3215 s = BC_STATUS_LEX_BAD_CHAR;
3216 }
3217
3218 break;
3219 }
3220
3221 case '(':
3222 case ')':
3223 {
3224 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3225 break;
3226 }
3227
3228 case '*':
3229 {
3230 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3231 break;
3232 }
3233
3234 case '+':
3235 {
3236 c2 = l->buf[l->i];
3237 if (c2 == '+') {
3238 ++l->i;
3239 l->t.t = BC_LEX_OP_INC;
3240 }
3241 else
3242 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3243 break;
3244 }
3245
3246 case ',':
3247 {
3248 l->t.t = BC_LEX_COMMA;
3249 break;
3250 }
3251
3252 case '-':
3253 {
3254 c2 = l->buf[l->i];
3255 if (c2 == '-') {
3256 ++l->i;
3257 l->t.t = BC_LEX_OP_DEC;
3258 }
3259 else
3260 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3261 break;
3262 }
3263
3264 case '.':
3265 {
3266 if (isdigit(l->buf[l->i]))
3267 s = bc_lex_number(l, c);
3268 else {
3269 l->t.t = BC_LEX_KEY_LAST;
3270 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3271 }
3272 break;
3273 }
3274
3275 case '/':
3276 {
3277 c2 = l->buf[l->i];
3278 if (c2 == '*')
3279 s = bc_lex_comment(l);
3280 else
3281 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3282 break;
3283 }
3284
3285 case '0':
3286 case '1':
3287 case '2':
3288 case '3':
3289 case '4':
3290 case '5':
3291 case '6':
3292 case '7':
3293 case '8':
3294 case '9':
3295 case 'A':
3296 case 'B':
3297 case 'C':
3298 case 'D':
3299 case 'E':
3300 case 'F':
3301 {
3302 s = bc_lex_number(l, c);
3303 break;
3304 }
3305
3306 case ';':
3307 {
3308 l->t.t = BC_LEX_SCOLON;
3309 break;
3310 }
3311
3312 case '<':
3313 {
3314 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3315 break;
3316 }
3317
3318 case '=':
3319 {
3320 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3321 break;
3322 }
3323
3324 case '>':
3325 {
3326 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3327 break;
3328 }
3329
3330 case '[':
3331 case ']':
3332 {
3333 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3334 break;
3335 }
3336
3337 case '\\':
3338 {
3339 if (l->buf[l->i] == '\n') {
3340 l->t.t = BC_LEX_WHITESPACE;
3341 ++l->i;
3342 }
3343 else
3344 s = BC_STATUS_LEX_BAD_CHAR;
3345 break;
3346 }
3347
3348 case '^':
3349 {
3350 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3351 break;
3352 }
3353
3354 case 'a':
3355 case 'b':
3356 case 'c':
3357 case 'd':
3358 case 'e':
3359 case 'f':
3360 case 'g':
3361 case 'h':
3362 case 'i':
3363 case 'j':
3364 case 'k':
3365 case 'l':
3366 case 'm':
3367 case 'n':
3368 case 'o':
3369 case 'p':
3370 case 'q':
3371 case 'r':
3372 case 's':
3373 case 't':
3374 case 'u':
3375 case 'v':
3376 case 'w':
3377 case 'x':
3378 case 'y':
3379 case 'z':
3380 {
3381 s = bc_lex_identifier(l);
3382 break;
3383 }
3384
3385 case '{':
3386 case '}':
3387 {
3388 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3389 break;
3390 }
3391
3392 case '|':
3393 {
3394 c2 = l->buf[l->i];
3395
3396 if (c2 == '|') {
3397
3398 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3399 if (s) return s;
3400
3401 ++l->i;
3402 l->t.t = BC_LEX_OP_BOOL_OR;
3403 }
3404 else {
3405 l->t.t = BC_LEX_INVALID;
3406 s = BC_STATUS_LEX_BAD_CHAR;
3407 }
3408
3409 break;
3410 }
3411
3412 default:
3413 {
3414 l->t.t = BC_LEX_INVALID;
3415 s = BC_STATUS_LEX_BAD_CHAR;
3416 break;
3417 }
3418 }
3419
3420 return s;
3421}
3422#endif // ENABLE_BC
3423
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003424#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003425static BcStatus dc_lex_register(BcLex *l)
3426{
3427 BcStatus s = BC_STATUS_SUCCESS;
3428
3429 if (isspace(l->buf[l->i - 1])) {
3430 bc_lex_whitespace(l);
3431 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003432 if (!G_exreg)
Gavin Howard01055ba2018-11-03 11:00:21 -06003433 s = BC_STATUS_LEX_EXTENDED_REG;
3434 else
3435 s = bc_lex_name(l);
3436 }
3437 else {
3438 bc_vec_npop(&l->t.v, l->t.v.len);
3439 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3440 bc_vec_pushByte(&l->t.v, '\0');
3441 l->t.t = BC_LEX_NAME;
3442 }
3443
3444 return s;
3445}
3446
3447static BcStatus dc_lex_string(BcLex *l)
3448{
3449 size_t depth = 1, nls = 0, i = l->i;
3450 char c;
3451
3452 l->t.t = BC_LEX_STR;
3453 bc_vec_npop(&l->t.v, l->t.v.len);
3454
3455 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3456
3457 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3458 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3459 nls += (c == '\n');
3460
3461 if (depth) bc_vec_push(&l->t.v, &c);
3462 }
3463
3464 if (c == '\0') {
3465 l->i = i;
3466 return BC_STATUS_LEX_NO_STRING_END;
3467 }
3468
3469 bc_vec_pushByte(&l->t.v, '\0');
3470 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3471
3472 l->i = i;
3473 l->line += nls;
3474
3475 return BC_STATUS_SUCCESS;
3476}
3477
3478static BcStatus dc_lex_token(BcLex *l)
3479{
3480 BcStatus s = BC_STATUS_SUCCESS;
3481 char c = l->buf[l->i++], c2;
3482 size_t i;
3483
3484 for (i = 0; i < dc_lex_regs_len; ++i) {
3485 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3486 }
3487
3488 if (c >= '%' && c <= '~' &&
3489 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3490 {
3491 return s;
3492 }
3493
3494 // This is the workhorse of the lexer.
3495 switch (c) {
3496
3497 case '\0':
3498 {
3499 l->t.t = BC_LEX_EOF;
3500 break;
3501 }
3502
3503 case '\n':
3504 case '\t':
3505 case '\v':
3506 case '\f':
3507 case '\r':
3508 case ' ':
3509 {
3510 l->newline = (c == '\n');
3511 bc_lex_whitespace(l);
3512 break;
3513 }
3514
3515 case '!':
3516 {
3517 c2 = l->buf[l->i];
3518
3519 if (c2 == '=')
3520 l->t.t = BC_LEX_OP_REL_NE;
3521 else if (c2 == '<')
3522 l->t.t = BC_LEX_OP_REL_LE;
3523 else if (c2 == '>')
3524 l->t.t = BC_LEX_OP_REL_GE;
3525 else
3526 return BC_STATUS_LEX_BAD_CHAR;
3527
3528 ++l->i;
3529 break;
3530 }
3531
3532 case '#':
3533 {
3534 bc_lex_lineComment(l);
3535 break;
3536 }
3537
3538 case '.':
3539 {
3540 if (isdigit(l->buf[l->i]))
3541 s = bc_lex_number(l, c);
3542 else
3543 s = BC_STATUS_LEX_BAD_CHAR;
3544 break;
3545 }
3546
3547 case '0':
3548 case '1':
3549 case '2':
3550 case '3':
3551 case '4':
3552 case '5':
3553 case '6':
3554 case '7':
3555 case '8':
3556 case '9':
3557 case 'A':
3558 case 'B':
3559 case 'C':
3560 case 'D':
3561 case 'E':
3562 case 'F':
3563 {
3564 s = bc_lex_number(l, c);
3565 break;
3566 }
3567
3568 case '[':
3569 {
3570 s = dc_lex_string(l);
3571 break;
3572 }
3573
3574 default:
3575 {
3576 l->t.t = BC_LEX_INVALID;
3577 s = BC_STATUS_LEX_BAD_CHAR;
3578 break;
3579 }
3580 }
3581
3582 return s;
3583}
3584#endif // ENABLE_DC
3585
3586static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3587{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003588 bc_program_addFunc(name, idx);
3589 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003590}
3591
3592static void bc_parse_pushName(BcParse *p, char *name)
3593{
3594 size_t i = 0, len = strlen(name);
3595
3596 for (; i < len; ++i) bc_parse_push(p, name[i]);
3597 bc_parse_push(p, BC_PARSE_STREND);
3598
3599 free(name);
3600}
3601
3602static void bc_parse_pushIndex(BcParse *p, size_t idx)
3603{
3604 unsigned char amt, i, nums[sizeof(size_t)];
3605
3606 for (amt = 0; idx; ++amt) {
3607 nums[amt] = (char) idx;
3608 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3609 }
3610
3611 bc_parse_push(p, amt);
3612 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3613}
3614
3615static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3616{
3617 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003618 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003619
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003620 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003621
3622 bc_parse_push(p, BC_INST_NUM);
3623 bc_parse_pushIndex(p, idx);
3624
3625 ++(*nexs);
3626 (*prev) = BC_INST_NUM;
3627}
3628
3629static BcStatus bc_parse_text(BcParse *p, const char *text)
3630{
3631 BcStatus s;
3632
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003633 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003634
3635 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3636 p->l.t.t = BC_LEX_INVALID;
3637 s = p->parse(p);
3638 if (s) return s;
3639 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3640 }
3641
3642 return bc_lex_text(&p->l, text);
3643}
3644
3645static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3646{
3647 if (p->fidx != BC_PROG_MAIN) {
3648
3649 p->func->nparams = 0;
3650 bc_vec_npop(&p->func->code, p->func->code.len);
3651 bc_vec_npop(&p->func->autos, p->func->autos.len);
3652 bc_vec_npop(&p->func->labels, p->func->labels.len);
3653
3654 bc_parse_updateFunc(p, BC_PROG_MAIN);
3655 }
3656
3657 p->l.i = p->l.len;
3658 p->l.t.t = BC_LEX_EOF;
3659 p->auto_part = (p->nbraces = 0);
3660
3661 bc_vec_npop(&p->flags, p->flags.len - 1);
3662 bc_vec_npop(&p->exits, p->exits.len);
3663 bc_vec_npop(&p->conds, p->conds.len);
3664 bc_vec_npop(&p->ops, p->ops.len);
3665
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003666 return bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003667}
3668
3669static void bc_parse_free(BcParse *p)
3670{
3671 bc_vec_free(&p->flags);
3672 bc_vec_free(&p->exits);
3673 bc_vec_free(&p->conds);
3674 bc_vec_free(&p->ops);
3675 bc_lex_free(&p->l);
3676}
3677
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003678static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003679 BcParseParse parse, BcLexNext next)
3680{
3681 memset(p, 0, sizeof(BcParse));
3682
3683 bc_lex_init(&p->l, next);
3684 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3685 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3686 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3687 bc_vec_pushByte(&p->flags, 0);
3688 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3689
3690 p->parse = parse;
Gavin Howard01055ba2018-11-03 11:00:21 -06003691 p->auto_part = (p->nbraces = 0);
3692 bc_parse_updateFunc(p, func);
3693}
3694
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003695#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003696static BcStatus bc_parse_else(BcParse *p);
3697static BcStatus bc_parse_stmt(BcParse *p);
3698
3699static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3700 size_t *nexprs, bool next)
3701{
3702 BcStatus s = BC_STATUS_SUCCESS;
3703 BcLexType t;
3704 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3705 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3706
3707 while (p->ops.len > start) {
3708
3709 t = BC_PARSE_TOP_OP(p);
3710 if (t == BC_LEX_LPAREN) break;
3711
3712 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3713 if (l >= r && (l != r || !left)) break;
3714
3715 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3716 bc_vec_pop(&p->ops);
3717 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3718 }
3719
3720 bc_vec_push(&p->ops, &type);
3721 if (next) s = bc_lex_next(&p->l);
3722
3723 return s;
3724}
3725
3726static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3727{
3728 BcLexType top;
3729
3730 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3731 top = BC_PARSE_TOP_OP(p);
3732
3733 while (top != BC_LEX_LPAREN) {
3734
3735 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3736
3737 bc_vec_pop(&p->ops);
3738 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3739
3740 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3741 top = BC_PARSE_TOP_OP(p);
3742 }
3743
3744 bc_vec_pop(&p->ops);
3745
3746 return bc_lex_next(&p->l);
3747}
3748
3749static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3750{
3751 BcStatus s;
3752 bool comma = false;
3753 size_t nparams;
3754
3755 s = bc_lex_next(&p->l);
3756 if (s) return s;
3757
3758 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3759
3760 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3761 s = bc_parse_expr(p, flags, bc_parse_next_param);
3762 if (s) return s;
3763
3764 comma = p->l.t.t == BC_LEX_COMMA;
3765 if (comma) {
3766 s = bc_lex_next(&p->l);
3767 if (s) return s;
3768 }
3769 }
3770
3771 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3772 bc_parse_push(p, BC_INST_CALL);
3773 bc_parse_pushIndex(p, nparams);
3774
3775 return BC_STATUS_SUCCESS;
3776}
3777
3778static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3779{
3780 BcStatus s;
3781 BcId entry, *entry_ptr;
3782 size_t idx;
3783
3784 entry.name = name;
3785
3786 s = bc_parse_params(p, flags);
3787 if (s) goto err;
3788
3789 if (p->l.t.t != BC_LEX_RPAREN) {
3790 s = BC_STATUS_PARSE_BAD_TOKEN;
3791 goto err;
3792 }
3793
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003794 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003795
3796 if (idx == BC_VEC_INVALID_IDX) {
3797 name = xstrdup(entry.name);
3798 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003799 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003800 free(entry.name);
3801 }
3802 else
3803 free(name);
3804
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003805 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003806 bc_parse_pushIndex(p, entry_ptr->idx);
3807
3808 return bc_lex_next(&p->l);
3809
3810err:
3811 free(name);
3812 return s;
3813}
3814
3815static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3816{
3817 BcStatus s;
3818 char *name;
3819
3820 name = xstrdup(p->l.t.v.v);
3821 s = bc_lex_next(&p->l);
3822 if (s) goto err;
3823
3824 if (p->l.t.t == BC_LEX_LBRACKET) {
3825
3826 s = bc_lex_next(&p->l);
3827 if (s) goto err;
3828
3829 if (p->l.t.t == BC_LEX_RBRACKET) {
3830
3831 if (!(flags & BC_PARSE_ARRAY)) {
3832 s = BC_STATUS_PARSE_BAD_EXP;
3833 goto err;
3834 }
3835
3836 *type = BC_INST_ARRAY;
3837 }
3838 else {
3839
3840 *type = BC_INST_ARRAY_ELEM;
3841
3842 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3843 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3844 if (s) goto err;
3845 }
3846
3847 s = bc_lex_next(&p->l);
3848 if (s) goto err;
3849 bc_parse_push(p, *type);
3850 bc_parse_pushName(p, name);
3851 }
3852 else if (p->l.t.t == BC_LEX_LPAREN) {
3853
3854 if (flags & BC_PARSE_NOCALL) {
3855 s = BC_STATUS_PARSE_BAD_TOKEN;
3856 goto err;
3857 }
3858
3859 *type = BC_INST_CALL;
3860 s = bc_parse_call(p, name, flags);
3861 }
3862 else {
3863 *type = BC_INST_VAR;
3864 bc_parse_push(p, BC_INST_VAR);
3865 bc_parse_pushName(p, name);
3866 }
3867
3868 return s;
3869
3870err:
3871 free(name);
3872 return s;
3873}
3874
3875static BcStatus bc_parse_read(BcParse *p)
3876{
3877 BcStatus s;
3878
3879 s = bc_lex_next(&p->l);
3880 if (s) return s;
3881 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3882
3883 s = bc_lex_next(&p->l);
3884 if (s) return s;
3885 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3886
3887 bc_parse_push(p, BC_INST_READ);
3888
3889 return bc_lex_next(&p->l);
3890}
3891
3892static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3893 BcInst *prev)
3894{
3895 BcStatus s;
3896
3897 s = bc_lex_next(&p->l);
3898 if (s) return s;
3899 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3900
3901 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3902
3903 s = bc_lex_next(&p->l);
3904 if (s) return s;
3905
3906 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3907 if (s) return s;
3908
3909 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3910
3911 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3912 bc_parse_push(p, *prev);
3913
3914 return bc_lex_next(&p->l);
3915}
3916
3917static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3918{
3919 BcStatus s;
3920
3921 s = bc_lex_next(&p->l);
3922 if (s) return s;
3923
3924 if (p->l.t.t != BC_LEX_LPAREN) {
3925 *type = BC_INST_SCALE;
3926 bc_parse_push(p, BC_INST_SCALE);
3927 return BC_STATUS_SUCCESS;
3928 }
3929
3930 *type = BC_INST_SCALE_FUNC;
3931 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3932
3933 s = bc_lex_next(&p->l);
3934 if (s) return s;
3935
3936 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3937 if (s) return s;
3938 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3939 bc_parse_push(p, BC_INST_SCALE_FUNC);
3940
3941 return bc_lex_next(&p->l);
3942}
3943
3944static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3945 size_t *nexprs, uint8_t flags)
3946{
3947 BcStatus s;
3948 BcLexType type;
3949 char inst;
3950 BcInst etype = *prev;
3951
3952 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3953 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3954 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3955 {
3956 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3957 bc_parse_push(p, inst);
3958 s = bc_lex_next(&p->l);
3959 }
3960 else {
3961
3962 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3963 *paren_expr = true;
3964
3965 s = bc_lex_next(&p->l);
3966 if (s) return s;
3967 type = p->l.t.t;
3968
3969 // Because we parse the next part of the expression
3970 // right here, we need to increment this.
3971 *nexprs = *nexprs + 1;
3972
3973 switch (type) {
3974
3975 case BC_LEX_NAME:
3976 {
3977 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3978 break;
3979 }
3980
3981 case BC_LEX_KEY_IBASE:
3982 case BC_LEX_KEY_LAST:
3983 case BC_LEX_KEY_OBASE:
3984 {
3985 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3986 s = bc_lex_next(&p->l);
3987 break;
3988 }
3989
3990 case BC_LEX_KEY_SCALE:
3991 {
3992 s = bc_lex_next(&p->l);
3993 if (s) return s;
3994 if (p->l.t.t == BC_LEX_LPAREN)
3995 s = BC_STATUS_PARSE_BAD_TOKEN;
3996 else
3997 bc_parse_push(p, BC_INST_SCALE);
3998 break;
3999 }
4000
4001 default:
4002 {
4003 s = BC_STATUS_PARSE_BAD_TOKEN;
4004 break;
4005 }
4006 }
4007
4008 if (!s) bc_parse_push(p, inst);
4009 }
4010
4011 return s;
4012}
4013
4014static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4015 bool rparen, size_t *nexprs)
4016{
4017 BcStatus s;
4018 BcLexType type;
4019 BcInst etype = *prev;
4020
4021 s = bc_lex_next(&p->l);
4022 if (s) return s;
4023
4024 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4025 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4026 BC_LEX_OP_MINUS :
4027 BC_LEX_NEG;
4028 *prev = BC_PARSE_TOKEN_INST(type);
4029
4030 // We can just push onto the op stack because this is the largest
4031 // precedence operator that gets pushed. Inc/dec does not.
4032 if (type != BC_LEX_OP_MINUS)
4033 bc_vec_push(&p->ops, &type);
4034 else
4035 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4036
4037 return s;
4038}
4039
4040static BcStatus bc_parse_string(BcParse *p, char inst)
4041{
4042 char *str = xstrdup(p->l.t.v.v);
4043
4044 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004045 bc_parse_pushIndex(p, G.prog.strs.len);
4046 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004047 bc_parse_push(p, inst);
4048
4049 return bc_lex_next(&p->l);
4050}
4051
4052static BcStatus bc_parse_print(BcParse *p)
4053{
4054 BcStatus s;
4055 BcLexType type;
4056 bool comma = false;
4057
4058 s = bc_lex_next(&p->l);
4059 if (s) return s;
4060
4061 type = p->l.t.t;
4062
4063 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4064 return BC_STATUS_PARSE_BAD_PRINT;
4065
4066 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4067
4068 if (type == BC_LEX_STR)
4069 s = bc_parse_string(p, BC_INST_PRINT_POP);
4070 else {
4071 s = bc_parse_expr(p, 0, bc_parse_next_print);
4072 if (s) return s;
4073 bc_parse_push(p, BC_INST_PRINT_POP);
4074 }
4075
4076 if (s) return s;
4077
4078 comma = p->l.t.t == BC_LEX_COMMA;
4079 if (comma) s = bc_lex_next(&p->l);
4080 type = p->l.t.t;
4081 }
4082
4083 if (s) return s;
4084 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4085
4086 return bc_lex_next(&p->l);
4087}
4088
4089static BcStatus bc_parse_return(BcParse *p)
4090{
4091 BcStatus s;
4092 BcLexType t;
4093 bool paren;
4094
4095 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4096
4097 s = bc_lex_next(&p->l);
4098 if (s) return s;
4099
4100 t = p->l.t.t;
4101 paren = t == BC_LEX_LPAREN;
4102
4103 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4104 bc_parse_push(p, BC_INST_RET0);
4105 else {
4106
4107 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4108 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4109 return s;
4110 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4111 bc_parse_push(p, BC_INST_RET0);
4112 s = bc_lex_next(&p->l);
4113 if (s) return s;
4114 }
4115
4116 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4117 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4118 if (s) return s;
4119 }
4120
4121 bc_parse_push(p, BC_INST_RET);
4122 }
4123
4124 return s;
4125}
4126
4127static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4128{
4129 BcStatus s = BC_STATUS_SUCCESS;
4130
4131 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4132 return BC_STATUS_PARSE_BAD_TOKEN;
4133
4134 if (brace) {
4135
4136 if (p->l.t.t == BC_LEX_RBRACE) {
4137 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4138 --p->nbraces;
4139 s = bc_lex_next(&p->l);
4140 if (s) return s;
4141 }
4142 else
4143 return BC_STATUS_PARSE_BAD_TOKEN;
4144 }
4145
4146 if (BC_PARSE_IF(p)) {
4147
4148 uint8_t *flag_ptr;
4149
4150 while (p->l.t.t == BC_LEX_NLINE) {
4151 s = bc_lex_next(&p->l);
4152 if (s) return s;
4153 }
4154
4155 bc_vec_pop(&p->flags);
4156
4157 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4158 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4159
4160 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4161 }
4162 else if (BC_PARSE_ELSE(p)) {
4163
4164 BcInstPtr *ip;
4165 size_t *label;
4166
4167 bc_vec_pop(&p->flags);
4168
4169 ip = bc_vec_top(&p->exits);
4170 label = bc_vec_item(&p->func->labels, ip->idx);
4171 *label = p->func->code.len;
4172
4173 bc_vec_pop(&p->exits);
4174 }
4175 else if (BC_PARSE_FUNC_INNER(p)) {
4176 bc_parse_push(p, BC_INST_RET0);
4177 bc_parse_updateFunc(p, BC_PROG_MAIN);
4178 bc_vec_pop(&p->flags);
4179 }
4180 else {
4181
4182 BcInstPtr *ip = bc_vec_top(&p->exits);
4183 size_t *label = bc_vec_top(&p->conds);
4184
4185 bc_parse_push(p, BC_INST_JUMP);
4186 bc_parse_pushIndex(p, *label);
4187
4188 label = bc_vec_item(&p->func->labels, ip->idx);
4189 *label = p->func->code.len;
4190
4191 bc_vec_pop(&p->flags);
4192 bc_vec_pop(&p->exits);
4193 bc_vec_pop(&p->conds);
4194 }
4195
4196 return s;
4197}
4198
4199static void bc_parse_startBody(BcParse *p, uint8_t flags)
4200{
4201 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4202 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4203 flags |= BC_PARSE_FLAG_BODY;
4204 bc_vec_push(&p->flags, &flags);
4205}
4206
4207static void bc_parse_noElse(BcParse *p)
4208{
4209 BcInstPtr *ip;
4210 size_t *label;
4211 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4212
4213 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4214
4215 ip = bc_vec_top(&p->exits);
4216 label = bc_vec_item(&p->func->labels, ip->idx);
4217 *label = p->func->code.len;
4218
4219 bc_vec_pop(&p->exits);
4220}
4221
4222static BcStatus bc_parse_if(BcParse *p)
4223{
4224 BcStatus s;
4225 BcInstPtr ip;
4226
4227 s = bc_lex_next(&p->l);
4228 if (s) return s;
4229 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4230
4231 s = bc_lex_next(&p->l);
4232 if (s) return s;
4233 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4234 if (s) return s;
4235 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4236
4237 s = bc_lex_next(&p->l);
4238 if (s) return s;
4239 bc_parse_push(p, BC_INST_JUMP_ZERO);
4240
4241 ip.idx = p->func->labels.len;
4242 ip.func = ip.len = 0;
4243
4244 bc_parse_pushIndex(p, ip.idx);
4245 bc_vec_push(&p->exits, &ip);
4246 bc_vec_push(&p->func->labels, &ip.idx);
4247 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4248
4249 return BC_STATUS_SUCCESS;
4250}
4251
4252static BcStatus bc_parse_else(BcParse *p)
4253{
4254 BcInstPtr ip;
4255
4256 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4257
4258 ip.idx = p->func->labels.len;
4259 ip.func = ip.len = 0;
4260
4261 bc_parse_push(p, BC_INST_JUMP);
4262 bc_parse_pushIndex(p, ip.idx);
4263
4264 bc_parse_noElse(p);
4265
4266 bc_vec_push(&p->exits, &ip);
4267 bc_vec_push(&p->func->labels, &ip.idx);
4268 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4269
4270 return bc_lex_next(&p->l);
4271}
4272
4273static BcStatus bc_parse_while(BcParse *p)
4274{
4275 BcStatus s;
4276 BcInstPtr ip;
4277
4278 s = bc_lex_next(&p->l);
4279 if (s) return s;
4280 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4281 s = bc_lex_next(&p->l);
4282 if (s) return s;
4283
4284 ip.idx = p->func->labels.len;
4285
4286 bc_vec_push(&p->func->labels, &p->func->code.len);
4287 bc_vec_push(&p->conds, &ip.idx);
4288
4289 ip.idx = p->func->labels.len;
4290 ip.func = 1;
4291 ip.len = 0;
4292
4293 bc_vec_push(&p->exits, &ip);
4294 bc_vec_push(&p->func->labels, &ip.idx);
4295
4296 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4297 if (s) return s;
4298 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4299 s = bc_lex_next(&p->l);
4300 if (s) return s;
4301
4302 bc_parse_push(p, BC_INST_JUMP_ZERO);
4303 bc_parse_pushIndex(p, ip.idx);
4304 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4305
4306 return BC_STATUS_SUCCESS;
4307}
4308
4309static BcStatus bc_parse_for(BcParse *p)
4310{
4311 BcStatus s;
4312 BcInstPtr ip;
4313 size_t cond_idx, exit_idx, body_idx, update_idx;
4314
4315 s = bc_lex_next(&p->l);
4316 if (s) return s;
4317 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4318 s = bc_lex_next(&p->l);
4319 if (s) return s;
4320
4321 if (p->l.t.t != BC_LEX_SCOLON)
4322 s = bc_parse_expr(p, 0, bc_parse_next_for);
4323 else
4324 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4325
4326 if (s) return s;
4327 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4328 s = bc_lex_next(&p->l);
4329 if (s) return s;
4330
4331 cond_idx = p->func->labels.len;
4332 update_idx = cond_idx + 1;
4333 body_idx = update_idx + 1;
4334 exit_idx = body_idx + 1;
4335
4336 bc_vec_push(&p->func->labels, &p->func->code.len);
4337
4338 if (p->l.t.t != BC_LEX_SCOLON)
4339 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4340 else
4341 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4342
4343 if (s) return s;
4344 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4345
4346 s = bc_lex_next(&p->l);
4347 if (s) return s;
4348
4349 bc_parse_push(p, BC_INST_JUMP_ZERO);
4350 bc_parse_pushIndex(p, exit_idx);
4351 bc_parse_push(p, BC_INST_JUMP);
4352 bc_parse_pushIndex(p, body_idx);
4353
4354 ip.idx = p->func->labels.len;
4355
4356 bc_vec_push(&p->conds, &update_idx);
4357 bc_vec_push(&p->func->labels, &p->func->code.len);
4358
4359 if (p->l.t.t != BC_LEX_RPAREN)
4360 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4361 else
4362 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4363
4364 if (s) return s;
4365
4366 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4367 bc_parse_push(p, BC_INST_JUMP);
4368 bc_parse_pushIndex(p, cond_idx);
4369 bc_vec_push(&p->func->labels, &p->func->code.len);
4370
4371 ip.idx = exit_idx;
4372 ip.func = 1;
4373 ip.len = 0;
4374
4375 bc_vec_push(&p->exits, &ip);
4376 bc_vec_push(&p->func->labels, &ip.idx);
4377 bc_lex_next(&p->l);
4378 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4379
4380 return BC_STATUS_SUCCESS;
4381}
4382
4383static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4384{
4385 BcStatus s;
4386 size_t i;
4387 BcInstPtr *ip;
4388
4389 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4390
4391 if (type == BC_LEX_KEY_BREAK) {
4392
4393 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4394
4395 i = p->exits.len - 1;
4396 ip = bc_vec_item(&p->exits, i);
4397
4398 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4399 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4400
4401 i = ip->idx;
4402 }
4403 else
4404 i = *((size_t *) bc_vec_top(&p->conds));
4405
4406 bc_parse_push(p, BC_INST_JUMP);
4407 bc_parse_pushIndex(p, i);
4408
4409 s = bc_lex_next(&p->l);
4410 if (s) return s;
4411
4412 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4413 return BC_STATUS_PARSE_BAD_TOKEN;
4414
4415 return bc_lex_next(&p->l);
4416}
4417
4418static BcStatus bc_parse_func(BcParse *p)
4419{
4420 BcStatus s;
4421 bool var, comma = false;
4422 uint8_t flags;
4423 char *name;
4424
4425 s = bc_lex_next(&p->l);
4426 if (s) return s;
4427 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4428
4429 name = xstrdup(p->l.t.v.v);
4430 bc_parse_addFunc(p, name, &p->fidx);
4431
4432 s = bc_lex_next(&p->l);
4433 if (s) return s;
4434 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4435 s = bc_lex_next(&p->l);
4436 if (s) return s;
4437
4438 while (p->l.t.t != BC_LEX_RPAREN) {
4439
4440 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4441
4442 ++p->func->nparams;
4443
4444 name = xstrdup(p->l.t.v.v);
4445 s = bc_lex_next(&p->l);
4446 if (s) goto err;
4447
4448 var = p->l.t.t != BC_LEX_LBRACKET;
4449
4450 if (!var) {
4451
4452 s = bc_lex_next(&p->l);
4453 if (s) goto err;
4454
4455 if (p->l.t.t != BC_LEX_RBRACKET) {
4456 s = BC_STATUS_PARSE_BAD_FUNC;
4457 goto err;
4458 }
4459
4460 s = bc_lex_next(&p->l);
4461 if (s) goto err;
4462 }
4463
4464 comma = p->l.t.t == BC_LEX_COMMA;
4465 if (comma) {
4466 s = bc_lex_next(&p->l);
4467 if (s) goto err;
4468 }
4469
4470 s = bc_func_insert(p->func, name, var);
4471 if (s) goto err;
4472 }
4473
4474 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4475
4476 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4477 bc_parse_startBody(p, flags);
4478
4479 s = bc_lex_next(&p->l);
4480 if (s) return s;
4481
4482 if (p->l.t.t != BC_LEX_LBRACE)
4483 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4484
4485 return s;
4486
4487err:
4488 free(name);
4489 return s;
4490}
4491
4492static BcStatus bc_parse_auto(BcParse *p)
4493{
4494 BcStatus s;
4495 bool comma, var, one;
4496 char *name;
4497
4498 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4499 s = bc_lex_next(&p->l);
4500 if (s) return s;
4501
4502 p->auto_part = comma = false;
4503 one = p->l.t.t == BC_LEX_NAME;
4504
4505 while (p->l.t.t == BC_LEX_NAME) {
4506
4507 name = xstrdup(p->l.t.v.v);
4508 s = bc_lex_next(&p->l);
4509 if (s) goto err;
4510
4511 var = p->l.t.t != BC_LEX_LBRACKET;
4512 if (!var) {
4513
4514 s = bc_lex_next(&p->l);
4515 if (s) goto err;
4516
4517 if (p->l.t.t != BC_LEX_RBRACKET) {
4518 s = BC_STATUS_PARSE_BAD_FUNC;
4519 goto err;
4520 }
4521
4522 s = bc_lex_next(&p->l);
4523 if (s) goto err;
4524 }
4525
4526 comma = p->l.t.t == BC_LEX_COMMA;
4527 if (comma) {
4528 s = bc_lex_next(&p->l);
4529 if (s) goto err;
4530 }
4531
4532 s = bc_func_insert(p->func, name, var);
4533 if (s) goto err;
4534 }
4535
4536 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4537 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4538
4539 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4540 return BC_STATUS_PARSE_BAD_TOKEN;
4541
4542 return bc_lex_next(&p->l);
4543
4544err:
4545 free(name);
4546 return s;
4547}
4548
4549static BcStatus bc_parse_body(BcParse *p, bool brace)
4550{
4551 BcStatus s = BC_STATUS_SUCCESS;
4552 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4553
4554 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4555
4556 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4557
4558 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4559 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4560
4561 if (!p->auto_part) {
4562 s = bc_parse_auto(p);
4563 if (s) return s;
4564 }
4565
4566 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4567 }
4568 else {
4569 s = bc_parse_stmt(p);
4570 if (!s && !brace) s = bc_parse_endBody(p, false);
4571 }
4572
4573 return s;
4574}
4575
4576static BcStatus bc_parse_stmt(BcParse *p)
4577{
4578 BcStatus s = BC_STATUS_SUCCESS;
4579
4580 switch (p->l.t.t) {
4581
4582 case BC_LEX_NLINE:
4583 {
4584 return bc_lex_next(&p->l);
4585 }
4586
4587 case BC_LEX_KEY_ELSE:
4588 {
4589 p->auto_part = false;
4590 break;
4591 }
4592
4593 case BC_LEX_LBRACE:
4594 {
4595 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4596
4597 ++p->nbraces;
4598 s = bc_lex_next(&p->l);
4599 if (s) return s;
4600
4601 return bc_parse_body(p, true);
4602 }
4603
4604 case BC_LEX_KEY_AUTO:
4605 {
4606 return bc_parse_auto(p);
4607 }
4608
4609 default:
4610 {
4611 p->auto_part = false;
4612
4613 if (BC_PARSE_IF_END(p)) {
4614 bc_parse_noElse(p);
4615 return BC_STATUS_SUCCESS;
4616 }
4617 else if (BC_PARSE_BODY(p))
4618 return bc_parse_body(p, false);
4619
4620 break;
4621 }
4622 }
4623
4624 switch (p->l.t.t) {
4625
4626 case BC_LEX_OP_INC:
4627 case BC_LEX_OP_DEC:
4628 case BC_LEX_OP_MINUS:
4629 case BC_LEX_OP_BOOL_NOT:
4630 case BC_LEX_LPAREN:
4631 case BC_LEX_NAME:
4632 case BC_LEX_NUMBER:
4633 case BC_LEX_KEY_IBASE:
4634 case BC_LEX_KEY_LAST:
4635 case BC_LEX_KEY_LENGTH:
4636 case BC_LEX_KEY_OBASE:
4637 case BC_LEX_KEY_READ:
4638 case BC_LEX_KEY_SCALE:
4639 case BC_LEX_KEY_SQRT:
4640 {
4641 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4642 break;
4643 }
4644
4645 case BC_LEX_KEY_ELSE:
4646 {
4647 s = bc_parse_else(p);
4648 break;
4649 }
4650
4651 case BC_LEX_SCOLON:
4652 {
4653 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4654 break;
4655 }
4656
4657 case BC_LEX_RBRACE:
4658 {
4659 s = bc_parse_endBody(p, true);
4660 break;
4661 }
4662
4663 case BC_LEX_STR:
4664 {
4665 s = bc_parse_string(p, BC_INST_PRINT_STR);
4666 break;
4667 }
4668
4669 case BC_LEX_KEY_BREAK:
4670 case BC_LEX_KEY_CONTINUE:
4671 {
4672 s = bc_parse_loopExit(p, p->l.t.t);
4673 break;
4674 }
4675
4676 case BC_LEX_KEY_FOR:
4677 {
4678 s = bc_parse_for(p);
4679 break;
4680 }
4681
4682 case BC_LEX_KEY_HALT:
4683 {
4684 bc_parse_push(p, BC_INST_HALT);
4685 s = bc_lex_next(&p->l);
4686 break;
4687 }
4688
4689 case BC_LEX_KEY_IF:
4690 {
4691 s = bc_parse_if(p);
4692 break;
4693 }
4694
4695 case BC_LEX_KEY_LIMITS:
4696 {
4697 s = bc_lex_next(&p->l);
4698 if (s) return s;
4699 s = BC_STATUS_LIMITS;
4700 break;
4701 }
4702
4703 case BC_LEX_KEY_PRINT:
4704 {
4705 s = bc_parse_print(p);
4706 break;
4707 }
4708
4709 case BC_LEX_KEY_QUIT:
4710 {
4711 // Quit is a compile-time command. We don't exit directly,
4712 // so the vm can clean up. Limits do the same thing.
4713 s = BC_STATUS_QUIT;
4714 break;
4715 }
4716
4717 case BC_LEX_KEY_RETURN:
4718 {
4719 s = bc_parse_return(p);
4720 break;
4721 }
4722
4723 case BC_LEX_KEY_WHILE:
4724 {
4725 s = bc_parse_while(p);
4726 break;
4727 }
4728
4729 default:
4730 {
4731 s = BC_STATUS_PARSE_BAD_TOKEN;
4732 break;
4733 }
4734 }
4735
4736 return s;
4737}
4738
4739static BcStatus bc_parse_parse(BcParse *p)
4740{
4741 BcStatus s;
4742
4743 if (p->l.t.t == BC_LEX_EOF)
4744 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4745 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4746 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4747 s = bc_parse_func(p);
4748 }
4749 else
4750 s = bc_parse_stmt(p);
4751
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004752 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G_interrupt)
Gavin Howard01055ba2018-11-03 11:00:21 -06004753 s = bc_parse_reset(p, s);
4754
4755 return s;
4756}
4757
4758static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4759{
4760 BcStatus s = BC_STATUS_SUCCESS;
4761 BcInst prev = BC_INST_PRINT;
4762 BcLexType top, t = p->l.t.t;
4763 size_t nexprs = 0, ops_bgn = p->ops.len;
4764 uint32_t i, nparens, nrelops;
4765 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4766
4767 paren_first = p->l.t.t == BC_LEX_LPAREN;
4768 nparens = nrelops = 0;
4769 paren_expr = rprn = done = get_token = assign = false;
4770 bin_last = true;
4771
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004772 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004773 switch (t) {
4774
4775 case BC_LEX_OP_INC:
4776 case BC_LEX_OP_DEC:
4777 {
4778 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4779 rprn = get_token = bin_last = false;
4780 break;
4781 }
4782
4783 case BC_LEX_OP_MINUS:
4784 {
4785 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4786 rprn = get_token = false;
4787 bin_last = prev == BC_INST_MINUS;
4788 break;
4789 }
4790
4791 case BC_LEX_OP_ASSIGN_POWER:
4792 case BC_LEX_OP_ASSIGN_MULTIPLY:
4793 case BC_LEX_OP_ASSIGN_DIVIDE:
4794 case BC_LEX_OP_ASSIGN_MODULUS:
4795 case BC_LEX_OP_ASSIGN_PLUS:
4796 case BC_LEX_OP_ASSIGN_MINUS:
4797 case BC_LEX_OP_ASSIGN:
4798 {
4799 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4800 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4801 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4802 {
4803 s = BC_STATUS_PARSE_BAD_ASSIGN;
4804 break;
4805 }
4806 }
4807 // Fallthrough.
4808 case BC_LEX_OP_POWER:
4809 case BC_LEX_OP_MULTIPLY:
4810 case BC_LEX_OP_DIVIDE:
4811 case BC_LEX_OP_MODULUS:
4812 case BC_LEX_OP_PLUS:
4813 case BC_LEX_OP_REL_EQ:
4814 case BC_LEX_OP_REL_LE:
4815 case BC_LEX_OP_REL_GE:
4816 case BC_LEX_OP_REL_NE:
4817 case BC_LEX_OP_REL_LT:
4818 case BC_LEX_OP_REL_GT:
4819 case BC_LEX_OP_BOOL_NOT:
4820 case BC_LEX_OP_BOOL_OR:
4821 case BC_LEX_OP_BOOL_AND:
4822 {
4823 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4824 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4825 {
4826 return BC_STATUS_PARSE_BAD_EXP;
4827 }
4828
4829 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4830 prev = BC_PARSE_TOKEN_INST(t);
4831 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4832 rprn = get_token = false;
4833 bin_last = t != BC_LEX_OP_BOOL_NOT;
4834
4835 break;
4836 }
4837
4838 case BC_LEX_LPAREN:
4839 {
4840 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4841
4842 ++nparens;
4843 paren_expr = rprn = bin_last = false;
4844 get_token = true;
4845 bc_vec_push(&p->ops, &t);
4846
4847 break;
4848 }
4849
4850 case BC_LEX_RPAREN:
4851 {
4852 if (bin_last || prev == BC_INST_BOOL_NOT)
4853 return BC_STATUS_PARSE_BAD_EXP;
4854
4855 if (nparens == 0) {
4856 s = BC_STATUS_SUCCESS;
4857 done = true;
4858 get_token = false;
4859 break;
4860 }
4861 else if (!paren_expr)
4862 return BC_STATUS_PARSE_EMPTY_EXP;
4863
4864 --nparens;
4865 paren_expr = rprn = true;
4866 get_token = bin_last = false;
4867
4868 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4869
4870 break;
4871 }
4872
4873 case BC_LEX_NAME:
4874 {
4875 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4876
4877 paren_expr = true;
4878 rprn = get_token = bin_last = false;
4879 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4880 ++nexprs;
4881
4882 break;
4883 }
4884
4885 case BC_LEX_NUMBER:
4886 {
4887 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4888
4889 bc_parse_number(p, &prev, &nexprs);
4890 paren_expr = get_token = true;
4891 rprn = bin_last = false;
4892
4893 break;
4894 }
4895
4896 case BC_LEX_KEY_IBASE:
4897 case BC_LEX_KEY_LAST:
4898 case BC_LEX_KEY_OBASE:
4899 {
4900 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4901
4902 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4903 bc_parse_push(p, (char) prev);
4904
4905 paren_expr = get_token = true;
4906 rprn = bin_last = false;
4907 ++nexprs;
4908
4909 break;
4910 }
4911
4912 case BC_LEX_KEY_LENGTH:
4913 case BC_LEX_KEY_SQRT:
4914 {
4915 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4916
4917 s = bc_parse_builtin(p, t, flags, &prev);
4918 paren_expr = true;
4919 rprn = get_token = bin_last = false;
4920 ++nexprs;
4921
4922 break;
4923 }
4924
4925 case BC_LEX_KEY_READ:
4926 {
4927 if (BC_PARSE_LEAF(prev, rprn))
4928 return BC_STATUS_PARSE_BAD_EXP;
4929 else if (flags & BC_PARSE_NOREAD)
4930 s = BC_STATUS_EXEC_REC_READ;
4931 else
4932 s = bc_parse_read(p);
4933
4934 paren_expr = true;
4935 rprn = get_token = bin_last = false;
4936 ++nexprs;
4937 prev = BC_INST_READ;
4938
4939 break;
4940 }
4941
4942 case BC_LEX_KEY_SCALE:
4943 {
4944 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4945
4946 s = bc_parse_scale(p, &prev, flags);
4947 paren_expr = true;
4948 rprn = get_token = bin_last = false;
4949 ++nexprs;
4950 prev = BC_INST_SCALE;
4951
4952 break;
4953 }
4954
4955 default:
4956 {
4957 s = BC_STATUS_PARSE_BAD_TOKEN;
4958 break;
4959 }
4960 }
4961
4962 if (!s && get_token) s = bc_lex_next(&p->l);
4963 }
4964
4965 if (s) return s;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004966 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06004967
4968 while (p->ops.len > ops_bgn) {
4969
4970 top = BC_PARSE_TOP_OP(p);
4971 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4972
4973 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4974 return BC_STATUS_PARSE_BAD_EXP;
4975
4976 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4977
4978 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4979 bc_vec_pop(&p->ops);
4980 }
4981
4982 s = BC_STATUS_PARSE_BAD_EXP;
4983 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4984
4985 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4986 if (s) return s;
4987
4988 if (!(flags & BC_PARSE_REL) && nrelops) {
4989 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4990 if (s) return s;
4991 }
4992 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4993 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4994 if (s) return s;
4995 }
4996
4997 if (flags & BC_PARSE_PRINT) {
4998 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4999 bc_parse_push(p, BC_INST_POP);
5000 }
5001
5002 return s;
5003}
5004
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005005static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005006{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005007 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005008}
5009
5010static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5011{
5012 return bc_parse_expr(p, flags, bc_parse_next_read);
5013}
5014#endif // ENABLE_BC
5015
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005016#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005017static BcStatus dc_parse_register(BcParse *p)
5018{
5019 BcStatus s;
5020 char *name;
5021
5022 s = bc_lex_next(&p->l);
5023 if (s) return s;
5024 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5025
5026 name = xstrdup(p->l.t.v.v);
5027 bc_parse_pushName(p, name);
5028
5029 return s;
5030}
5031
5032static BcStatus dc_parse_string(BcParse *p)
5033{
5034 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005035 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005036
5037 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5038 name = xstrdup(b);
5039
5040 str = xstrdup(p->l.t.v.v);
5041 bc_parse_push(p, BC_INST_STR);
5042 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005043 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005044 bc_parse_addFunc(p, name, &idx);
5045
5046 return bc_lex_next(&p->l);
5047}
5048
5049static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5050{
5051 BcStatus s;
5052
5053 bc_parse_push(p, inst);
5054 if (name) {
5055 s = dc_parse_register(p);
5056 if (s) return s;
5057 }
5058
5059 if (store) {
5060 bc_parse_push(p, BC_INST_SWAP);
5061 bc_parse_push(p, BC_INST_ASSIGN);
5062 bc_parse_push(p, BC_INST_POP);
5063 }
5064
5065 return bc_lex_next(&p->l);
5066}
5067
5068static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5069{
5070 BcStatus s;
5071
5072 bc_parse_push(p, inst);
5073 bc_parse_push(p, BC_INST_EXEC_COND);
5074
5075 s = dc_parse_register(p);
5076 if (s) return s;
5077
5078 s = bc_lex_next(&p->l);
5079 if (s) return s;
5080
5081 if (p->l.t.t == BC_LEX_ELSE) {
5082 s = dc_parse_register(p);
5083 if (s) return s;
5084 s = bc_lex_next(&p->l);
5085 }
5086 else
5087 bc_parse_push(p, BC_PARSE_STREND);
5088
5089 return s;
5090}
5091
5092static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5093{
5094 BcStatus s = BC_STATUS_SUCCESS;
5095 BcInst prev;
5096 uint8_t inst;
5097 bool assign, get_token = false;
5098
5099 switch (t) {
5100
5101 case BC_LEX_OP_REL_EQ:
5102 case BC_LEX_OP_REL_LE:
5103 case BC_LEX_OP_REL_GE:
5104 case BC_LEX_OP_REL_NE:
5105 case BC_LEX_OP_REL_LT:
5106 case BC_LEX_OP_REL_GT:
5107 {
5108 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5109 break;
5110 }
5111
5112 case BC_LEX_SCOLON:
5113 case BC_LEX_COLON:
5114 {
5115 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5116 break;
5117 }
5118
5119 case BC_LEX_STR:
5120 {
5121 s = dc_parse_string(p);
5122 break;
5123 }
5124
5125 case BC_LEX_NEG:
5126 case BC_LEX_NUMBER:
5127 {
5128 if (t == BC_LEX_NEG) {
5129 s = bc_lex_next(&p->l);
5130 if (s) return s;
5131 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5132 }
5133
5134 bc_parse_number(p, &prev, &p->nbraces);
5135
5136 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5137 get_token = true;
5138
5139 break;
5140 }
5141
5142 case BC_LEX_KEY_READ:
5143 {
5144 if (flags & BC_PARSE_NOREAD)
5145 s = BC_STATUS_EXEC_REC_READ;
5146 else
5147 bc_parse_push(p, BC_INST_READ);
5148 get_token = true;
5149 break;
5150 }
5151
5152 case BC_LEX_OP_ASSIGN:
5153 case BC_LEX_STORE_PUSH:
5154 {
5155 assign = t == BC_LEX_OP_ASSIGN;
5156 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5157 s = dc_parse_mem(p, inst, true, assign);
5158 break;
5159 }
5160
5161 case BC_LEX_LOAD:
5162 case BC_LEX_LOAD_POP:
5163 {
5164 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5165 s = dc_parse_mem(p, inst, true, false);
5166 break;
5167 }
5168
5169 case BC_LEX_STORE_IBASE:
5170 case BC_LEX_STORE_SCALE:
5171 case BC_LEX_STORE_OBASE:
5172 {
5173 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5174 s = dc_parse_mem(p, inst, false, true);
5175 break;
5176 }
5177
5178 default:
5179 {
5180 s = BC_STATUS_PARSE_BAD_TOKEN;
5181 get_token = true;
5182 break;
5183 }
5184 }
5185
5186 if (!s && get_token) s = bc_lex_next(&p->l);
5187
5188 return s;
5189}
5190
5191static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5192{
5193 BcStatus s = BC_STATUS_SUCCESS;
5194 BcInst inst;
5195 BcLexType t;
5196
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005197 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005198
5199 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5200
5201 inst = dc_parse_insts[t];
5202
5203 if (inst != BC_INST_INVALID) {
5204 bc_parse_push(p, inst);
5205 s = bc_lex_next(&p->l);
5206 }
5207 else
5208 s = dc_parse_token(p, t, flags);
5209 }
5210
5211 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5212 bc_parse_push(p, BC_INST_POP_EXEC);
5213
5214 return s;
5215}
5216
5217static BcStatus dc_parse_parse(BcParse *p)
5218{
5219 BcStatus s;
5220
5221 if (p->l.t.t == BC_LEX_EOF)
5222 s = BC_STATUS_LEX_EOF;
5223 else
5224 s = dc_parse_expr(p, 0);
5225
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01005226 if (s || G_interrupt) s = bc_parse_reset(p, s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005227
5228 return s;
5229}
5230
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005231static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005232{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005233 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005234}
5235#endif // ENABLE_DC
5236
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005237static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005238{
5239 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005240 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005241 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005242 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005243 }
5244}
5245
5246static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5247{
5248 if (IS_BC) {
5249 return bc_parse_expression(p, flags);
5250 } else {
5251 return dc_parse_expr(p, flags);
5252 }
5253}
5254
Denys Vlasenkodf515392018-12-02 19:27:48 +01005255static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005256{
5257 BcStatus s;
5258 BcId e, *ptr;
5259 BcVec *v, *map;
5260 size_t i;
5261 BcResultData data;
5262 bool new;
5263
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005264 v = var ? &G.prog.vars : &G.prog.arrs;
5265 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005266
5267 e.name = id;
5268 e.idx = v->len;
5269 s = bc_map_insert(map, &e, &i);
5270 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5271
5272 if (new) {
5273 bc_array_init(&data.v, var);
5274 bc_vec_push(v, &data.v);
5275 }
5276
5277 ptr = bc_vec_item(map, i);
5278 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005279 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005280}
5281
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005282static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005283{
5284 BcStatus s = BC_STATUS_SUCCESS;
5285
5286 switch (r->t) {
5287
5288 case BC_RESULT_STR:
5289 case BC_RESULT_TEMP:
5290 case BC_RESULT_IBASE:
5291 case BC_RESULT_SCALE:
5292 case BC_RESULT_OBASE:
5293 {
5294 *num = &r->d.n;
5295 break;
5296 }
5297
5298 case BC_RESULT_CONSTANT:
5299 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005300 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005301 size_t base_t, len = strlen(*str);
5302 BcNum *base;
5303
5304 bc_num_init(&r->d.n, len);
5305
5306 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005307 base = hex ? &G.prog.hexb : &G.prog.ib;
5308 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005309 s = bc_num_parse(&r->d.n, *str, base, base_t);
5310
5311 if (s) {
5312 bc_num_free(&r->d.n);
5313 return s;
5314 }
5315
5316 *num = &r->d.n;
5317 r->t = BC_RESULT_TEMP;
5318
5319 break;
5320 }
5321
5322 case BC_RESULT_VAR:
5323 case BC_RESULT_ARRAY:
5324 case BC_RESULT_ARRAY_ELEM:
5325 {
5326 BcVec *v;
5327
Denys Vlasenkodf515392018-12-02 19:27:48 +01005328 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005329
5330 if (r->t == BC_RESULT_ARRAY_ELEM) {
5331 v = bc_vec_top(v);
5332 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5333 *num = bc_vec_item(v, r->d.id.idx);
5334 }
5335 else
5336 *num = bc_vec_top(v);
5337
5338 break;
5339 }
5340
5341 case BC_RESULT_LAST:
5342 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005343 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005344 break;
5345 }
5346
5347 case BC_RESULT_ONE:
5348 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005349 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005350 break;
5351 }
5352 }
5353
5354 return s;
5355}
5356
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005357static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005358 BcResult **r, BcNum **rn, bool assign)
5359{
5360 BcStatus s;
5361 bool hex;
5362 BcResultType lt, rt;
5363
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005364 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005365
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005366 *r = bc_vec_item_rev(&G.prog.results, 0);
5367 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005368
5369 lt = (*l)->t;
5370 rt = (*r)->t;
5371 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5372
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005373 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005374 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005375 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005376 if (s) return s;
5377
5378 // We run this again under these conditions in case any vector has been
5379 // reallocated out from under the BcNums or arrays we had.
5380 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005381 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005382 if (s) return s;
5383 }
5384
5385 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5386 return BC_STATUS_EXEC_BAD_TYPE;
5387 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5388
Gavin Howard01055ba2018-11-03 11:00:21 -06005389 return s;
5390}
5391
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005392static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005393{
5394 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005395 bc_vec_pop(&G.prog.results);
5396 bc_vec_pop(&G.prog.results);
5397 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005398}
5399
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005400static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005401{
5402 BcStatus s;
5403
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005404 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5405 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005406
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005407 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005408 if (s) return s;
5409
Gavin Howard01055ba2018-11-03 11:00:21 -06005410 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5411
5412 return s;
5413}
5414
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005415static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005416{
5417 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005418 bc_vec_pop(&G.prog.results);
5419 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005420}
5421
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005422static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005423{
5424 BcStatus s;
5425 BcResult *opd1, *opd2, res;
5426 BcNum *n1, *n2 = NULL;
5427
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005428 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005429 if (s) return s;
5430 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5431
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005432 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005433 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005434 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005435
5436 return s;
5437
5438err:
5439 bc_num_free(&res.d.n);
5440 return s;
5441}
5442
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005443static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005444{
5445 BcStatus s;
5446 BcParse parse;
5447 BcVec buf;
5448 BcInstPtr ip;
5449 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005450 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005451
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005452 for (i = 0; i < G.prog.stack.len; ++i) {
5453 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Gavin Howard01055ba2018-11-03 11:00:21 -06005454 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5455 }
5456
5457 bc_vec_npop(&f->code, f->code.len);
5458 bc_vec_init(&buf, sizeof(char), NULL);
5459
5460 s = bc_read_line(&buf, "read> ");
5461 if (s) goto io_err;
5462
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005463 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005464 bc_lex_file(&parse.l, bc_program_stdin_name);
5465
5466 s = bc_parse_text(&parse, buf.v);
5467 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005468 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005469 if (s) goto exec_err;
5470
5471 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5472 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5473 goto exec_err;
5474 }
5475
5476 ip.func = BC_PROG_READ;
5477 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005478 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005479
5480 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005481 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005482
5483 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005484 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005485
5486exec_err:
5487 bc_parse_free(&parse);
5488io_err:
5489 bc_vec_free(&buf);
5490 return s;
5491}
5492
5493static size_t bc_program_index(char *code, size_t *bgn)
5494{
5495 char amt = code[(*bgn)++], i = 0;
5496 size_t res = 0;
5497
5498 for (; i < amt; ++i, ++(*bgn))
5499 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5500
5501 return res;
5502}
5503
5504static char *bc_program_name(char *code, size_t *bgn)
5505{
5506 size_t i;
5507 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5508
5509 s = xmalloc(ptr - str + 1);
5510 c = code[(*bgn)++];
5511
5512 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5513 s[i] = c;
5514
5515 s[i] = '\0';
5516
5517 return s;
5518}
5519
5520static void bc_program_printString(const char *str, size_t *nchars)
5521{
5522 size_t i, len = strlen(str);
5523
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005524#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005525 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005526 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005527 return;
5528 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005529#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005530
5531 for (i = 0; i < len; ++i, ++(*nchars)) {
5532
5533 int c = str[i];
5534
5535 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005536 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005537 else {
5538
5539 c = str[++i];
5540
5541 switch (c) {
5542
5543 case 'a':
5544 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005545 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005546 break;
5547 }
5548
5549 case 'b':
5550 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005551 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005552 break;
5553 }
5554
5555 case '\\':
5556 case 'e':
5557 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005558 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005559 break;
5560 }
5561
5562 case 'f':
5563 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005564 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005565 break;
5566 }
5567
5568 case 'n':
5569 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005570 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005571 *nchars = SIZE_MAX;
5572 break;
5573 }
5574
5575 case 'r':
5576 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005577 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005578 break;
5579 }
5580
5581 case 'q':
5582 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005583 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005584 break;
5585 }
5586
5587 case 't':
5588 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005589 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005590 break;
5591 }
5592
5593 default:
5594 {
5595 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005596 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005597 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005598 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005599 break;
5600 }
5601 }
5602 }
5603 }
5604}
5605
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005606static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005607{
5608 BcStatus s = BC_STATUS_SUCCESS;
5609 BcResult *r;
5610 size_t len, i;
5611 char *str;
5612 BcNum *num = NULL;
5613 bool pop = inst != BC_INST_PRINT;
5614
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005615 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005616
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005617 r = bc_vec_item_rev(&G.prog.results, idx);
5618 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005619 if (s) return s;
5620
5621 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005622 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5623 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005624 }
5625 else {
5626
5627 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005628 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005629
5630 if (inst == BC_INST_PRINT_STR) {
5631 for (i = 0, len = strlen(str); i < len; ++i) {
5632 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005633 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005634 if (c == '\n') G.prog.nchars = SIZE_MAX;
5635 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005636 }
5637 }
5638 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005639 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005640 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005641 }
5642 }
5643
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005644 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005645
5646 return s;
5647}
5648
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005650{
5651 BcStatus s;
5652 BcResult res, *ptr;
5653 BcNum *num = NULL;
5654
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005655 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005656 if (s) return s;
5657
5658 bc_num_init(&res.d.n, num->len);
5659 bc_num_copy(&res.d.n, num);
5660 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5661
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005662 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005663
5664 return s;
5665}
5666
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005667static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005668{
5669 BcStatus s;
5670 BcResult *opd1, *opd2, res;
5671 BcNum *n1, *n2;
5672 bool cond = 0;
5673 ssize_t cmp;
5674
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005675 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005676 if (s) return s;
5677 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5678
5679 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005680 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005681 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005682 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005683 else {
5684
5685 cmp = bc_num_cmp(n1, n2);
5686
5687 switch (inst) {
5688
5689 case BC_INST_REL_EQ:
5690 {
5691 cond = cmp == 0;
5692 break;
5693 }
5694
5695 case BC_INST_REL_LE:
5696 {
5697 cond = cmp <= 0;
5698 break;
5699 }
5700
5701 case BC_INST_REL_GE:
5702 {
5703 cond = cmp >= 0;
5704 break;
5705 }
5706
5707 case BC_INST_REL_NE:
5708 {
5709 cond = cmp != 0;
5710 break;
5711 }
5712
5713 case BC_INST_REL_LT:
5714 {
5715 cond = cmp < 0;
5716 break;
5717 }
5718
5719 case BC_INST_REL_GT:
5720 {
5721 cond = cmp > 0;
5722 break;
5723 }
5724 }
5725 }
5726
5727 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5728
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005729 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005730
5731 return s;
5732}
5733
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005734#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005735static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005736 bool push)
5737{
5738 BcNum n2;
5739 BcResult res;
5740
5741 memset(&n2, 0, sizeof(BcNum));
5742 n2.rdx = res.d.id.idx = r->d.id.idx;
5743 res.t = BC_RESULT_STR;
5744
5745 if (!push) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005746 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005747 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005748 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005749 }
5750
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005751 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005752
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005753 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005754 bc_vec_push(v, &n2);
5755
5756 return BC_STATUS_SUCCESS;
5757}
5758#endif // ENABLE_DC
5759
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005760static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005761{
5762 BcStatus s;
5763 BcResult *ptr, r;
5764 BcVec *v;
5765 BcNum *n;
5766
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005767 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005768
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005769 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005770 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005771 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005772
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005773#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005774 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005775 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005776#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005777
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005778 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005779 if (s) return s;
5780
5781 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005782 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005783
5784 if (var) {
5785 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5786 bc_num_copy(&r.d.n, n);
5787 }
5788 else {
5789 bc_array_init(&r.d.v, true);
5790 bc_array_copy(&r.d.v, (BcVec *) n);
5791 }
5792
5793 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005794 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005795
5796 return s;
5797}
5798
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005799static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005800{
5801 BcStatus s;
5802 BcResult *left, *right, res;
5803 BcNum *l = NULL, *r = NULL;
5804 unsigned long val, max;
5805 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5806
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005807 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005808 if (s) return s;
5809
5810 ib = left->t == BC_RESULT_IBASE;
5811 sc = left->t == BC_RESULT_SCALE;
5812
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005813#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005814
5815 if (right->t == BC_RESULT_STR) {
5816
5817 BcVec *v;
5818
5819 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005820 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005821
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005822 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005823 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005824#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005825
5826 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5827 return BC_STATUS_PARSE_BAD_ASSIGN;
5828
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005829#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005830 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Gavin Howard01055ba2018-11-03 11:00:21 -06005831 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5832
5833 if (assign)
5834 bc_num_copy(l, r);
5835 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005836 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005837
5838 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005839#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005840 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005841#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005842
5843 if (ib || sc || left->t == BC_RESULT_OBASE) {
5844
5845 size_t *ptr;
5846
5847 s = bc_num_ulong(l, &val);
5848 if (s) return s;
5849 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5850
5851 if (sc) {
5852 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005853 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005854 }
5855 else {
5856 if (val < BC_NUM_MIN_BASE) return s;
5857 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005858 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005859 }
5860
5861 if (val > max) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005862 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005863
5864 *ptr = (size_t) val;
5865 s = BC_STATUS_SUCCESS;
5866 }
5867
5868 bc_num_init(&res.d.n, l->len);
5869 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005870 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005871
5872 return s;
5873}
5874
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005875static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005876 bool pop, bool copy)
5877{
5878 BcStatus s = BC_STATUS_SUCCESS;
5879 BcResult r;
5880 char *name = bc_program_name(code, bgn);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005881#if ENABLE_DC // Exclude
Gavin Howard01055ba2018-11-03 11:00:21 -06005882 BcNum *num;
5883 BcVec *v;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005884#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005885 (void) pop, (void) copy;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005886#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005887
5888 r.t = BC_RESULT_VAR;
5889 r.d.id.name = name;
5890
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005891#if ENABLE_DC
Denys Vlasenkodf515392018-12-02 19:27:48 +01005892 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005893 num = bc_vec_top(v);
5894
5895 if (pop || copy) {
5896
5897 if (!BC_PROG_STACK(v, 2 - copy)) {
5898 free(name);
5899 return BC_STATUS_EXEC_STACK;
5900 }
5901
5902 free(name);
5903 name = NULL;
5904
5905 if (!BC_PROG_STR(num)) {
5906
5907 r.t = BC_RESULT_TEMP;
5908
5909 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5910 bc_num_copy(&r.d.n, num);
5911 }
5912 else {
5913 r.t = BC_RESULT_STR;
5914 r.d.id.idx = num->rdx;
5915 }
5916
5917 if (!copy) bc_vec_pop(v);
5918 }
5919#endif // ENABLE_DC
5920
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005921 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005922
5923 return s;
5924}
5925
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005926static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005927 char inst)
5928{
5929 BcStatus s = BC_STATUS_SUCCESS;
5930 BcResult r;
5931 BcNum *num;
5932
5933 r.d.id.name = bc_program_name(code, bgn);
5934
5935 if (inst == BC_INST_ARRAY) {
5936 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005937 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005938 }
5939 else {
5940
5941 BcResult *operand;
5942 unsigned long temp;
5943
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005944 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005945 if (s) goto err;
5946 s = bc_num_ulong(num, &temp);
5947 if (s) goto err;
5948
5949 if (temp > BC_MAX_DIM) {
5950 s = BC_STATUS_EXEC_ARRAY_LEN;
5951 goto err;
5952 }
5953
5954 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005955 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005956 }
5957
5958err:
5959 if (s) free(r.d.id.name);
5960 return s;
5961}
5962
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005963#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005964static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005965{
5966 BcStatus s;
5967 BcResult *ptr, res, copy;
5968 BcNum *num = NULL;
5969 char inst2 = inst;
5970
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005971 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005972 if (s) return s;
5973
5974 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5975 copy.t = BC_RESULT_TEMP;
5976 bc_num_init(&copy.d.n, num->len);
5977 bc_num_copy(&copy.d.n, num);
5978 }
5979
5980 res.t = BC_RESULT_ONE;
5981 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5982 BC_INST_ASSIGN_PLUS :
5983 BC_INST_ASSIGN_MINUS;
5984
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005985 bc_vec_push(&G.prog.results, &res);
5986 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005987
5988 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005989 bc_vec_pop(&G.prog.results);
5990 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005991 }
5992
5993 return s;
5994}
5995
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005996static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005997{
5998 BcStatus s = BC_STATUS_SUCCESS;
5999 BcInstPtr ip;
6000 size_t i, nparams = bc_program_index(code, idx);
6001 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006002 BcId *a;
6003 BcResultData param;
6004 BcResult *arg;
6005
6006 ip.idx = 0;
6007 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006008 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006009
6010 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6011 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006012 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006013
6014 for (i = 0; i < nparams; ++i) {
6015
6016 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006017 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006018
6019 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6020 return BC_STATUS_EXEC_BAD_TYPE;
6021
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006022 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006023 if (s) return s;
6024 }
6025
6026 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006027 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006028
6029 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006030 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006031
6032 if (a->idx) {
6033 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6034 bc_vec_push(v, &param.n);
6035 }
6036 else {
6037 bc_array_init(&param.v, true);
6038 bc_vec_push(v, &param.v);
6039 }
6040 }
6041
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006042 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006043
6044 return BC_STATUS_SUCCESS;
6045}
6046
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006047static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006048{
6049 BcStatus s;
6050 BcResult res;
6051 BcFunc *f;
6052 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006053 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006054
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006055 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Gavin Howard01055ba2018-11-03 11:00:21 -06006056 return BC_STATUS_EXEC_STACK;
6057
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006058 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006059 res.t = BC_RESULT_TEMP;
6060
6061 if (inst == BC_INST_RET) {
6062
6063 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006064 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006065
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006066 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006067 if (s) return s;
6068 bc_num_init(&res.d.n, num->len);
6069 bc_num_copy(&res.d.n, num);
6070 }
6071 else {
6072 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6073 bc_num_zero(&res.d.n);
6074 }
6075
6076 // We need to pop arguments as well, so this takes that into account.
6077 for (i = 0; i < f->autos.len; ++i) {
6078
6079 BcVec *v;
6080 BcId *a = bc_vec_item(&f->autos, i);
6081
Denys Vlasenkodf515392018-12-02 19:27:48 +01006082 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006083 bc_vec_pop(v);
6084 }
6085
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006086 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6087 bc_vec_push(&G.prog.results, &res);
6088 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006089
6090 return BC_STATUS_SUCCESS;
6091}
6092#endif // ENABLE_BC
6093
6094static unsigned long bc_program_scale(BcNum *n)
6095{
6096 return (unsigned long) n->rdx;
6097}
6098
6099static unsigned long bc_program_len(BcNum *n)
6100{
6101 unsigned long len = n->len;
6102 size_t i;
6103
6104 if (n->rdx != n->len) return len;
6105 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6106
6107 return len;
6108}
6109
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006110static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006111{
6112 BcStatus s;
6113 BcResult *opnd;
6114 BcNum *num = NULL;
6115 BcResult res;
6116 bool len = inst == BC_INST_LENGTH;
6117
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006118 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6119 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006120
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006121 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006122 if (s) return s;
6123
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006124#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006125 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006126#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006127
6128 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6129
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006130 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006131#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006132 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006133 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006134 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006135#endif
6136#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006137 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6138
6139 char **str;
6140 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006143 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006144 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006145#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006146 else {
6147 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006148 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006149 }
6150
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006151 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006152
6153 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006154}
6155
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006156#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006157static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006158{
6159 BcStatus s;
6160 BcResult *opd1, *opd2, res, res2;
6161 BcNum *n1, *n2 = NULL;
6162
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006163 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006164 if (s) return s;
6165
6166 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6167 bc_num_init(&res2.d.n, n2->len);
6168
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006169 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006170 if (s) goto err;
6171
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006172 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006173 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006174 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006175
6176 return s;
6177
6178err:
6179 bc_num_free(&res2.d.n);
6180 bc_num_free(&res.d.n);
6181 return s;
6182}
6183
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006185{
6186 BcStatus s;
6187 BcResult *r1, *r2, *r3, res;
6188 BcNum *n1, *n2, *n3;
6189
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006190 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6191 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006192 if (s) return s;
6193
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006194 r1 = bc_vec_item_rev(&G.prog.results, 2);
6195 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006196 if (s) return s;
6197 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6198
6199 // Make sure that the values have their pointers updated, if necessary.
6200 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6201
6202 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006203 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006204 if (s) return s;
6205 }
6206
6207 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006208 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006209 if (s) return s;
6210 }
6211 }
6212
6213 bc_num_init(&res.d.n, n3->len);
6214 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6215 if (s) goto err;
6216
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006217 bc_vec_pop(&G.prog.results);
6218 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006219
6220 return s;
6221
6222err:
6223 bc_num_free(&res.d.n);
6224 return s;
6225}
6226
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006227static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006228{
Gavin Howard01055ba2018-11-03 11:00:21 -06006229 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006230 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006231
6232 res.t = BC_RESULT_TEMP;
6233
6234 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006235 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006236 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006237}
6238
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006239static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006240{
6241 BcStatus s;
6242 BcResult *r, res;
6243 BcNum *num = NULL, n;
6244 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006245 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006246 unsigned long val;
6247
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006248 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6249 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006250
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006251 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006252 if (s) return s;
6253
6254 if (BC_PROG_NUM(r, num)) {
6255
6256 bc_num_init(&n, BC_NUM_DEF_SIZE);
6257 bc_num_copy(&n, num);
6258 bc_num_truncate(&n, n.rdx);
6259
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006260 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006261 if (s) goto num_err;
6262 s = bc_num_ulong(&n, &val);
6263 if (s) goto num_err;
6264
6265 c = (char) val;
6266
6267 bc_num_free(&n);
6268 }
6269 else {
6270 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006271 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006272 c = str2[0];
6273 }
6274
6275 str = xmalloc(2);
6276 str[0] = c;
6277 str[1] = '\0';
6278
6279 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006280 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006281
6282 if (idx != len + BC_PROG_REQ_FUNCS) {
6283
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006284 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6285 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006286 len = idx;
6287 break;
6288 }
6289 }
6290
6291 free(str);
6292 }
6293 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006294 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006295
6296 res.t = BC_RESULT_STR;
6297 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006298 bc_vec_pop(&G.prog.results);
6299 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006300
6301 return BC_STATUS_SUCCESS;
6302
6303num_err:
6304 bc_num_free(&n);
6305 return s;
6306}
6307
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006308static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006309{
6310 BcStatus s;
6311 BcResult *r;
6312 BcNum *n = NULL;
6313 size_t idx;
6314 char *str;
6315
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006316 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6317 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006318
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006319 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006320 if (s) return s;
6321
6322 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006323 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006324 else {
6325 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006326 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006327 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006328 }
6329
6330 return s;
6331}
6332
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006333static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006334{
6335 BcStatus s;
6336 BcResult *opnd;
6337 BcNum *num = NULL;
6338 unsigned long val;
6339
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006340 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006341 if (s) return s;
6342 s = bc_num_ulong(num, &val);
6343 if (s) return s;
6344
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006345 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006346
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006347 if (G.prog.stack.len < val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006348 return BC_STATUS_EXEC_STACK;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006349 else if (G.prog.stack.len == val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006350 return BC_STATUS_QUIT;
6351
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006352 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006353
6354 return s;
6355}
6356
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006357static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006358 bool cond)
6359{
6360 BcStatus s = BC_STATUS_SUCCESS;
6361 BcResult *r;
6362 char **str;
6363 BcFunc *f;
6364 BcParse prs;
6365 BcInstPtr ip;
6366 size_t fidx, sidx;
6367 BcNum *n;
6368 bool exec;
6369
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006370 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006371
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006372 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006373
6374 if (cond) {
6375
Gavin Howard01055ba2018-11-03 11:00:21 -06006376 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6377
6378 if (code[*bgn] == BC_PARSE_STREND)
6379 (*bgn) += 1;
6380 else
6381 else_name = bc_program_name(code, bgn);
6382
6383 exec = r->d.n.len != 0;
6384
6385 if (exec)
6386 name = then_name;
6387 else if (else_name != NULL) {
6388 exec = true;
6389 name = else_name;
6390 }
6391
6392 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006393 BcVec *v;
6394 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006395 n = bc_vec_top(v);
6396 }
6397
6398 free(then_name);
6399 free(else_name);
6400
6401 if (!exec) goto exit;
6402 if (!BC_PROG_STR(n)) {
6403 s = BC_STATUS_EXEC_BAD_TYPE;
6404 goto exit;
6405 }
6406
6407 sidx = n->rdx;
6408 }
6409 else {
6410
6411 if (r->t == BC_RESULT_STR)
6412 sidx = r->d.id.idx;
6413 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006414 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006415 if (s || !BC_PROG_STR(n)) goto exit;
6416 sidx = n->rdx;
6417 }
6418 else
6419 goto exit;
6420 }
6421
6422 fidx = sidx + BC_PROG_REQ_FUNCS;
6423
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006424 str = bc_vec_item(&G.prog.strs, sidx);
6425 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006426
6427 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006428 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006429 s = bc_parse_text(&prs, *str);
6430 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006431 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006432 if (s) goto err;
6433
6434 if (prs.l.t.t != BC_LEX_EOF) {
6435 s = BC_STATUS_PARSE_BAD_EXP;
6436 goto err;
6437 }
6438
6439 bc_parse_free(&prs);
6440 }
6441
6442 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006443 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006444 ip.func = fidx;
6445
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006446 bc_vec_pop(&G.prog.results);
6447 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006448
6449 return BC_STATUS_SUCCESS;
6450
6451err:
6452 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006453 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006454 bc_vec_npop(&f->code, f->code.len);
6455exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006456 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006457 return s;
6458}
6459#endif // ENABLE_DC
6460
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006461static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006462{
Gavin Howard01055ba2018-11-03 11:00:21 -06006463 BcResult res;
6464 unsigned long val;
6465
6466 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6467 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006468 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006469 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006470 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006471 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006472 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006473
6474 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006475 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006476 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006477}
6478
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006479static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006480{
6481 BcStatus s;
6482 BcId entry, *entry_ptr;
6483 BcFunc f;
6484
6485 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006486 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006487
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006488 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006489 if (s) free(name);
6490
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006491 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006492 *idx = entry_ptr->idx;
6493
6494 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6495
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006496 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006497
6498 // We need to reset these, so the function can be repopulated.
6499 func->nparams = 0;
6500 bc_vec_npop(&func->autos, func->autos.len);
6501 bc_vec_npop(&func->code, func->code.len);
6502 bc_vec_npop(&func->labels, func->labels.len);
6503 }
6504 else {
6505 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006506 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006507 }
6508}
6509
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006510static BcStatus bc_program_reset(BcStatus s)
Gavin Howard01055ba2018-11-03 11:00:21 -06006511{
6512 BcFunc *f;
6513 BcInstPtr *ip;
6514
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006515 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6516 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006517
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006518 f = bc_vec_item(&G.prog.fns, 0);
6519 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006520 ip->idx = f->code.len;
6521
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006522 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
Gavin Howard01055ba2018-11-03 11:00:21 -06006523
6524 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006525 if (G.ttyin) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006526 fflush(stdout);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006527 fputs(bc_program_ready_msg, stderr);
6528 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06006529 s = BC_STATUS_SUCCESS;
6530 }
6531 else
6532 s = BC_STATUS_QUIT;
6533 }
6534
6535 return s;
6536}
6537
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006538static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006539{
6540 BcStatus s = BC_STATUS_SUCCESS;
6541 size_t idx;
6542 BcResult r, *ptr;
6543 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006544 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6545 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006546 char *code = func->code.v;
6547 bool cond = false;
6548
6549 while (!s && ip->idx < func->code.len) {
6550
6551 char inst = code[(ip->idx)++];
6552
6553 switch (inst) {
6554
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006555#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 case BC_INST_JUMP_ZERO:
6557 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006558 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006559 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006560 cond = !bc_num_cmp(num, &G.prog.zero);
6561 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006562 }
6563 // Fallthrough.
6564 case BC_INST_JUMP:
6565 {
6566 size_t *addr;
6567 idx = bc_program_index(code, &ip->idx);
6568 addr = bc_vec_item(&func->labels, idx);
6569 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6570 break;
6571 }
6572
6573 case BC_INST_CALL:
6574 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006575 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006576 break;
6577 }
6578
6579 case BC_INST_INC_PRE:
6580 case BC_INST_DEC_PRE:
6581 case BC_INST_INC_POST:
6582 case BC_INST_DEC_POST:
6583 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006584 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006585 break;
6586 }
6587
6588 case BC_INST_HALT:
6589 {
6590 s = BC_STATUS_QUIT;
6591 break;
6592 }
6593
6594 case BC_INST_RET:
6595 case BC_INST_RET0:
6596 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006597 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006598 break;
6599 }
6600
6601 case BC_INST_BOOL_OR:
6602 case BC_INST_BOOL_AND:
6603#endif // ENABLE_BC
6604 case BC_INST_REL_EQ:
6605 case BC_INST_REL_LE:
6606 case BC_INST_REL_GE:
6607 case BC_INST_REL_NE:
6608 case BC_INST_REL_LT:
6609 case BC_INST_REL_GT:
6610 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006611 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006612 break;
6613 }
6614
6615 case BC_INST_READ:
6616 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006617 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006618 break;
6619 }
6620
6621 case BC_INST_VAR:
6622 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006623 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006624 break;
6625 }
6626
6627 case BC_INST_ARRAY_ELEM:
6628 case BC_INST_ARRAY:
6629 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006630 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006631 break;
6632 }
6633
6634 case BC_INST_LAST:
6635 {
6636 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006637 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006638 break;
6639 }
6640
6641 case BC_INST_IBASE:
6642 case BC_INST_SCALE:
6643 case BC_INST_OBASE:
6644 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006645 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006646 break;
6647 }
6648
6649 case BC_INST_SCALE_FUNC:
6650 case BC_INST_LENGTH:
6651 case BC_INST_SQRT:
6652 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006653 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006654 break;
6655 }
6656
6657 case BC_INST_NUM:
6658 {
6659 r.t = BC_RESULT_CONSTANT;
6660 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006661 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006662 break;
6663 }
6664
6665 case BC_INST_POP:
6666 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006667 if (!BC_PROG_STACK(&G.prog.results, 1))
Gavin Howard01055ba2018-11-03 11:00:21 -06006668 s = BC_STATUS_EXEC_STACK;
6669 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006670 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006671 break;
6672 }
6673
6674 case BC_INST_POP_EXEC:
6675 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006676 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006677 break;
6678 }
6679
6680 case BC_INST_PRINT:
6681 case BC_INST_PRINT_POP:
6682 case BC_INST_PRINT_STR:
6683 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006684 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006685 break;
6686 }
6687
6688 case BC_INST_STR:
6689 {
6690 r.t = BC_RESULT_STR;
6691 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006692 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006693 break;
6694 }
6695
6696 case BC_INST_POWER:
6697 case BC_INST_MULTIPLY:
6698 case BC_INST_DIVIDE:
6699 case BC_INST_MODULUS:
6700 case BC_INST_PLUS:
6701 case BC_INST_MINUS:
6702 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006703 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006704 break;
6705 }
6706
6707 case BC_INST_BOOL_NOT:
6708 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006709 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006710 if (s) return s;
6711
6712 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006713 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6714 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006715
6716 break;
6717 }
6718
6719 case BC_INST_NEG:
6720 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006721 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006722 break;
6723 }
6724
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006725#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006726 case BC_INST_ASSIGN_POWER:
6727 case BC_INST_ASSIGN_MULTIPLY:
6728 case BC_INST_ASSIGN_DIVIDE:
6729 case BC_INST_ASSIGN_MODULUS:
6730 case BC_INST_ASSIGN_PLUS:
6731 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006732#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006733 case BC_INST_ASSIGN:
6734 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006735 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006736 break;
6737 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006738#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006739 case BC_INST_MODEXP:
6740 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006741 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006742 break;
6743 }
6744
6745 case BC_INST_DIVMOD:
6746 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006747 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006748 break;
6749 }
6750
6751 case BC_INST_EXECUTE:
6752 case BC_INST_EXEC_COND:
6753 {
6754 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006755 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006756 break;
6757 }
6758
6759 case BC_INST_PRINT_STACK:
6760 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006761 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6762 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006763 break;
6764 }
6765
6766 case BC_INST_CLEAR_STACK:
6767 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006768 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006769 break;
6770 }
6771
6772 case BC_INST_STACK_LEN:
6773 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006774 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006775 break;
6776 }
6777
6778 case BC_INST_DUPLICATE:
6779 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006780 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6781 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006782 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006783 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006784 break;
6785 }
6786
6787 case BC_INST_SWAP:
6788 {
6789 BcResult *ptr2;
6790
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006791 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006792
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006793 ptr = bc_vec_item_rev(&G.prog.results, 0);
6794 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006795 memcpy(&r, ptr, sizeof(BcResult));
6796 memcpy(ptr, ptr2, sizeof(BcResult));
6797 memcpy(ptr2, &r, sizeof(BcResult));
6798
6799 break;
6800 }
6801
6802 case BC_INST_ASCIIFY:
6803 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006804 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006805 break;
6806 }
6807
6808 case BC_INST_PRINT_STREAM:
6809 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006810 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006811 break;
6812 }
6813
6814 case BC_INST_LOAD:
6815 case BC_INST_PUSH_VAR:
6816 {
6817 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006818 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006819 break;
6820 }
6821
6822 case BC_INST_PUSH_TO_VAR:
6823 {
6824 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006825 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006826 free(name);
6827 break;
6828 }
6829
6830 case BC_INST_QUIT:
6831 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006832 if (G.prog.stack.len <= 2)
Gavin Howard01055ba2018-11-03 11:00:21 -06006833 s = BC_STATUS_QUIT;
6834 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006835 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006836 break;
6837 }
6838
6839 case BC_INST_NQUIT:
6840 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006841 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006842 break;
6843 }
6844#endif // ENABLE_DC
6845 }
6846
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006847 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006848
6849 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006850 ip = bc_vec_top(&G.prog.stack);
6851 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006852 code = func->code.v;
6853 }
6854
6855 return s;
6856}
6857
Denys Vlasenko00d77792018-11-30 23:13:42 +01006858static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006859{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006860 printf("%s "BB_VER"\n"
6861 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006862 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006863 "This is free software with ABSOLUTELY NO WARRANTY\n"
6864 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006865}
6866
6867static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6868{
6869 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6870
Denys Vlasenko00d77792018-11-30 23:13:42 +01006871 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6872 fprintf(stderr, " %s", file);
6873 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006874
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006875 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
Gavin Howard01055ba2018-11-03 11:00:21 -06006876}
6877
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006878#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006879static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6880 const char *msg)
6881{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006882 int p = (int) G_posix, w = (int) G_warn;
Gavin Howard01055ba2018-11-03 11:00:21 -06006883 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6884
6885 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6886
Denys Vlasenko00d77792018-11-30 23:13:42 +01006887 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6888 if (msg) fprintf(stderr, " %s\n", msg);
6889 fprintf(stderr, " %s", file);
6890 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006891
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006892 return s * (!G.ttyin && !!p);
Gavin Howard01055ba2018-11-03 11:00:21 -06006893}
6894
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006895static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006896{
Gavin Howard01055ba2018-11-03 11:00:21 -06006897 BcVec v;
6898 char *env_args = getenv(bc_args_env_name), *buf;
6899
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006900 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006901
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006902 G.env_args = xstrdup(env_args);
6903 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006904
6905 bc_vec_init(&v, sizeof(char *), NULL);
6906 bc_vec_push(&v, &bc_args_env_name);
6907
6908 while (*buf != 0) {
6909 if (!isspace(*buf)) {
6910 bc_vec_push(&v, &buf);
6911 while (*buf != 0 && !isspace(*buf)) ++buf;
6912 if (*buf != 0) (*(buf++)) = '\0';
6913 }
6914 else
6915 ++buf;
6916 }
6917
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006918 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006919
6920 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006921}
6922#endif // ENABLE_BC
6923
6924static size_t bc_vm_envLen(const char *var)
6925{
6926 char *lenv = getenv(var);
6927 size_t i, len = BC_NUM_PRINT_WIDTH;
6928 int num;
6929
6930 if (!lenv) return len;
6931
6932 len = strlen(lenv);
6933
6934 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6935 if (num) {
6936 len = (size_t) atoi(lenv) - 1;
6937 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6938 }
6939 else
6940 len = BC_NUM_PRINT_WIDTH;
6941
6942 return len;
6943}
6944
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006945static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006946{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006947 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006948
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006949 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006950 if (s) return s;
6951
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006952 while (G.prs.l.t.t != BC_LEX_EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006953
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006954 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006955
6956 if (s == BC_STATUS_LIMITS) {
6957
Denys Vlasenko00d77792018-11-30 23:13:42 +01006958 bb_putchar('\n');
6959 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
6960 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
6961 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
6962 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
6963 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
6964 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
6965 printf("Max Exponent = %lu\n", BC_MAX_EXP);
6966 printf("Number of Vars = %lu\n", BC_MAX_VARS);
6967 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06006968
6969 s = BC_STATUS_SUCCESS;
6970 }
6971 else {
6972 if (s == BC_STATUS_QUIT) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006973 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006974 if (s) return s;
6975 }
6976 }
6977
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006978 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006979 s = bc_program_exec();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006980 if (!s && G.tty) fflush(stdout);
Gavin Howard01055ba2018-11-03 11:00:21 -06006981 if (s && s != BC_STATUS_QUIT)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006982 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006983 }
6984
6985 return s;
6986}
6987
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006988static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006989{
6990 BcStatus s;
6991 char *data;
6992 BcFunc *main_func;
6993 BcInstPtr *ip;
6994
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006995 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006996 data = bc_read_file(file);
6997 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006998
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006999 bc_lex_file(&G.prs.l, file);
7000 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007001 if (s) goto err;
7002
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007003 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7004 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007005
7006 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7007
7008err:
7009 free(data);
7010 return s;
7011}
7012
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007013static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007014{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007015 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007016 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007017 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007018 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007019
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007020 G.prog.file = bc_program_stdin_name;
7021 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007022
7023 bc_vec_init(&buffer, sizeof(char), NULL);
7024 bc_vec_init(&buf, sizeof(char), NULL);
7025 bc_vec_pushByte(&buffer, '\0');
7026
7027 // This loop is complex because the vm tries not to send any lines that end
7028 // with a backslash to the parser. The reason for that is because the parser
7029 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7030 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007031 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007032
7033 char *string = buf.v;
7034
7035 len = buf.len - 1;
7036
7037 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007038 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007039 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007040 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007041 str += 1;
7042 }
7043 else if (len > 1 || comment) {
7044
7045 for (i = 0; i < len; ++i) {
7046
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007047 bool notend = len > i + 1;
7048 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007049
7050 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007051 if (G.sbgn == G.send)
7052 str ^= c == G.sbgn;
7053 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007054 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007055 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007056 str += 1;
7057 }
7058
7059 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7060 comment = true;
7061 break;
7062 }
7063 else if (c == '*' && notend && comment && string[i + 1] == '/')
7064 comment = false;
7065 }
7066
7067 if (str || comment || string[len - 2] == '\\') {
7068 bc_vec_concat(&buffer, buf.v);
7069 continue;
7070 }
7071 }
7072
7073 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007074 s = bc_vm_process(buffer.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007075 if (s) goto err;
7076
7077 bc_vec_npop(&buffer, buffer.len);
7078 }
7079
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007080 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007081
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007082 // INPUT_EOF will always happen when stdin is
Gavin Howard01055ba2018-11-03 11:00:21 -06007083 // closed. It's not a problem in that case.
Denys Vlasenko00d77792018-11-30 23:13:42 +01007084 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7085 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06007086
7087 if (str)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007088 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7089 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007090 else if (comment)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007091 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7092 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007093
7094err:
7095 bc_vec_free(&buf);
7096 bc_vec_free(&buffer);
7097 return s;
7098}
7099
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007100static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007101{
7102 BcStatus s = BC_STATUS_SUCCESS;
7103 size_t i;
7104
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007105#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007106 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007107
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007108 bc_lex_file(&G.prs.l, bc_lib_name);
7109 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007110
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007111 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007112
7113 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007114 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007115 if (s) return s;
7116 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007117#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007118
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007119 for (i = 0; !s && i < G.files.len; ++i)
7120 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Gavin Howard01055ba2018-11-03 11:00:21 -06007121 if (s && s != BC_STATUS_QUIT) return s;
7122
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007123 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7124 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007125
Denys Vlasenko00d77792018-11-30 23:13:42 +01007126 if (s == BC_STATUS_QUIT)
7127 s = BC_STATUS_SUCCESS;
7128 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007129}
7130
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007131#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007132static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007133{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007134 bc_num_free(&G.prog.ib);
7135 bc_num_free(&G.prog.ob);
7136 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007137# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007138 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007139# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007140 bc_vec_free(&G.prog.fns);
7141 bc_vec_free(&G.prog.fn_map);
7142 bc_vec_free(&G.prog.vars);
7143 bc_vec_free(&G.prog.var_map);
7144 bc_vec_free(&G.prog.arrs);
7145 bc_vec_free(&G.prog.arr_map);
7146 bc_vec_free(&G.prog.strs);
7147 bc_vec_free(&G.prog.consts);
7148 bc_vec_free(&G.prog.results);
7149 bc_vec_free(&G.prog.stack);
7150 bc_num_free(&G.prog.last);
7151 bc_num_free(&G.prog.zero);
7152 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007153}
7154
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007155static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007156{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007157 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007158 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007159 bc_parse_free(&G.prs);
7160 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007161}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007162#endif
7163
7164static void bc_program_init(size_t line_len)
7165{
7166 size_t idx;
7167 BcInstPtr ip;
7168
7169 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7170 memset(&ip, 0, sizeof(BcInstPtr));
7171
7172 /* G.prog.nchars = G.prog.scale = 0; - already is */
7173 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007174
7175 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7176 bc_num_ten(&G.prog.ib);
7177 G.prog.ib_t = 10;
7178
7179 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7180 bc_num_ten(&G.prog.ob);
7181 G.prog.ob_t = 10;
7182
7183 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7184 bc_num_ten(&G.prog.hexb);
7185 G.prog.hexb.num[0] = 6;
7186
7187#if ENABLE_DC
7188 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7189 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7190#endif
7191
7192 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7193 bc_num_zero(&G.prog.last);
7194
7195 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7196 bc_num_zero(&G.prog.zero);
7197
7198 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7199 bc_num_one(&G.prog.one);
7200
7201 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7202 bc_map_init(&G.prog.fn_map);
7203
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007204 bc_program_addFunc(xstrdup(bc_func_main), &idx);
7205 bc_program_addFunc(xstrdup(bc_func_read), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007206
7207 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7208 bc_map_init(&G.prog.var_map);
7209
7210 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7211 bc_map_init(&G.prog.arr_map);
7212
7213 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7214 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7215 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7216 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7217 bc_vec_push(&G.prog.stack, &ip);
7218}
Gavin Howard01055ba2018-11-03 11:00:21 -06007219
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007220static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007221{
Gavin Howard01055ba2018-11-03 11:00:21 -06007222 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007223
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007224#if ENABLE_FEATURE_BC_SIGNALS
7225 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007226#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007227
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007228 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007229
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007230 if (IS_BC) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007231 if (getenv("POSIXLY_CORRECT"))
7232 G.flags |= BC_FLAG_S;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007233 bc_vm_envArgs();
7234 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007235
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007236 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007237 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007238 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007239 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007240 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007241 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007242}
7243
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007244static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007245 const char *env_len)
7246{
7247 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007248
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007249 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007250 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007251
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007252 G.ttyin = isatty(0);
7253 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007254
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007255 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7256 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007257
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007258#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007259 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007260#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007261 return st;
7262}
7263
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007264#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007265int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7266int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007267{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007268 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007269 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007270
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007271 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007272}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007273#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007274
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007275#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007276int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7277int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007278{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007279 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007280 G.sbgn = '[';
7281 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007282
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007283 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007284}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007285#endif