blob: ee05cd4b4cdcf3c60dec4337f81e51e3e3a83b91 [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 Vlasenko416ce762018-12-02 20:57:17 +01005875#if !ENABLE_DC
5876#define bc_program_pushVar(code, bgn, pop, copy) \
5877 bc_program_pushVar(code, bgn)
5878// for bc, 'pop' and 'copy' are always false
5879#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005880static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005881 bool pop, bool copy)
5882{
5883 BcStatus s = BC_STATUS_SUCCESS;
5884 BcResult r;
5885 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005886
5887 r.t = BC_RESULT_VAR;
5888 r.d.id.name = name;
5889
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005890#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005891 {
5892 BcVec *v = bc_program_search(name, true);
5893 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005894
Denys Vlasenko416ce762018-12-02 20:57:17 +01005895 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005896
Denys Vlasenko416ce762018-12-02 20:57:17 +01005897 if (!BC_PROG_STACK(v, 2 - copy)) {
5898 free(name);
5899 return BC_STATUS_EXEC_STACK;
5900 }
5901
Gavin Howard01055ba2018-11-03 11:00:21 -06005902 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005903 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);
Gavin Howard01055ba2018-11-03 11:00:21 -06005918 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005919 }
5920#endif // ENABLE_DC
5921
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005922 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005923
5924 return s;
5925}
5926
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005927static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005928 char inst)
5929{
5930 BcStatus s = BC_STATUS_SUCCESS;
5931 BcResult r;
5932 BcNum *num;
5933
5934 r.d.id.name = bc_program_name(code, bgn);
5935
5936 if (inst == BC_INST_ARRAY) {
5937 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005938 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005939 }
5940 else {
5941
5942 BcResult *operand;
5943 unsigned long temp;
5944
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005945 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005946 if (s) goto err;
5947 s = bc_num_ulong(num, &temp);
5948 if (s) goto err;
5949
5950 if (temp > BC_MAX_DIM) {
5951 s = BC_STATUS_EXEC_ARRAY_LEN;
5952 goto err;
5953 }
5954
5955 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005956 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005957 }
5958
5959err:
5960 if (s) free(r.d.id.name);
5961 return s;
5962}
5963
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005964#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005965static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005966{
5967 BcStatus s;
5968 BcResult *ptr, res, copy;
5969 BcNum *num = NULL;
5970 char inst2 = inst;
5971
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005972 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005973 if (s) return s;
5974
5975 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5976 copy.t = BC_RESULT_TEMP;
5977 bc_num_init(&copy.d.n, num->len);
5978 bc_num_copy(&copy.d.n, num);
5979 }
5980
5981 res.t = BC_RESULT_ONE;
5982 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5983 BC_INST_ASSIGN_PLUS :
5984 BC_INST_ASSIGN_MINUS;
5985
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005986 bc_vec_push(&G.prog.results, &res);
5987 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005988
5989 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005990 bc_vec_pop(&G.prog.results);
5991 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005992 }
5993
5994 return s;
5995}
5996
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005997static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005998{
5999 BcStatus s = BC_STATUS_SUCCESS;
6000 BcInstPtr ip;
6001 size_t i, nparams = bc_program_index(code, idx);
6002 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006003 BcId *a;
6004 BcResultData param;
6005 BcResult *arg;
6006
6007 ip.idx = 0;
6008 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006009 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006010
6011 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6012 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006013 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006014
6015 for (i = 0; i < nparams; ++i) {
6016
6017 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006018 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006019
6020 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6021 return BC_STATUS_EXEC_BAD_TYPE;
6022
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006023 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006024 if (s) return s;
6025 }
6026
6027 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006028 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006029
6030 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006031 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006032
6033 if (a->idx) {
6034 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6035 bc_vec_push(v, &param.n);
6036 }
6037 else {
6038 bc_array_init(&param.v, true);
6039 bc_vec_push(v, &param.v);
6040 }
6041 }
6042
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006043 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006044
6045 return BC_STATUS_SUCCESS;
6046}
6047
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006048static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006049{
6050 BcStatus s;
6051 BcResult res;
6052 BcFunc *f;
6053 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006054 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006055
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006056 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Gavin Howard01055ba2018-11-03 11:00:21 -06006057 return BC_STATUS_EXEC_STACK;
6058
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006059 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006060 res.t = BC_RESULT_TEMP;
6061
6062 if (inst == BC_INST_RET) {
6063
6064 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006065 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006066
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006067 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006068 if (s) return s;
6069 bc_num_init(&res.d.n, num->len);
6070 bc_num_copy(&res.d.n, num);
6071 }
6072 else {
6073 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6074 bc_num_zero(&res.d.n);
6075 }
6076
6077 // We need to pop arguments as well, so this takes that into account.
6078 for (i = 0; i < f->autos.len; ++i) {
6079
6080 BcVec *v;
6081 BcId *a = bc_vec_item(&f->autos, i);
6082
Denys Vlasenkodf515392018-12-02 19:27:48 +01006083 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006084 bc_vec_pop(v);
6085 }
6086
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006087 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6088 bc_vec_push(&G.prog.results, &res);
6089 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006090
6091 return BC_STATUS_SUCCESS;
6092}
6093#endif // ENABLE_BC
6094
6095static unsigned long bc_program_scale(BcNum *n)
6096{
6097 return (unsigned long) n->rdx;
6098}
6099
6100static unsigned long bc_program_len(BcNum *n)
6101{
6102 unsigned long len = n->len;
6103 size_t i;
6104
6105 if (n->rdx != n->len) return len;
6106 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6107
6108 return len;
6109}
6110
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006111static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006112{
6113 BcStatus s;
6114 BcResult *opnd;
6115 BcNum *num = NULL;
6116 BcResult res;
6117 bool len = inst == BC_INST_LENGTH;
6118
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006119 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6120 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006121
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006122 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006123 if (s) return s;
6124
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006125#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006126 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006127#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006128
6129 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6130
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006131 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006132#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006133 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006134 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006135 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006136#endif
6137#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006138 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6139
6140 char **str;
6141 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6142
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006143 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006144 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006145 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006146#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006147 else {
6148 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006149 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006150 }
6151
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006152 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006153
6154 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006155}
6156
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006157#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006158static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006159{
6160 BcStatus s;
6161 BcResult *opd1, *opd2, res, res2;
6162 BcNum *n1, *n2 = NULL;
6163
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006164 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006165 if (s) return s;
6166
6167 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6168 bc_num_init(&res2.d.n, n2->len);
6169
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006170 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006171 if (s) goto err;
6172
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006173 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006174 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006175 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006176
6177 return s;
6178
6179err:
6180 bc_num_free(&res2.d.n);
6181 bc_num_free(&res.d.n);
6182 return s;
6183}
6184
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006185static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006186{
6187 BcStatus s;
6188 BcResult *r1, *r2, *r3, res;
6189 BcNum *n1, *n2, *n3;
6190
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006191 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6192 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006193 if (s) return s;
6194
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006195 r1 = bc_vec_item_rev(&G.prog.results, 2);
6196 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006197 if (s) return s;
6198 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6199
6200 // Make sure that the values have their pointers updated, if necessary.
6201 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6202
6203 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006204 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006205 if (s) return s;
6206 }
6207
6208 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006209 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006210 if (s) return s;
6211 }
6212 }
6213
6214 bc_num_init(&res.d.n, n3->len);
6215 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6216 if (s) goto err;
6217
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006218 bc_vec_pop(&G.prog.results);
6219 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006220
6221 return s;
6222
6223err:
6224 bc_num_free(&res.d.n);
6225 return s;
6226}
6227
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006228static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006229{
Gavin Howard01055ba2018-11-03 11:00:21 -06006230 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006231 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006232
6233 res.t = BC_RESULT_TEMP;
6234
6235 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006236 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006237 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006238}
6239
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006240static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006241{
6242 BcStatus s;
6243 BcResult *r, res;
6244 BcNum *num = NULL, n;
6245 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006246 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006247 unsigned long val;
6248
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006249 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6250 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006251
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006252 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006253 if (s) return s;
6254
6255 if (BC_PROG_NUM(r, num)) {
6256
6257 bc_num_init(&n, BC_NUM_DEF_SIZE);
6258 bc_num_copy(&n, num);
6259 bc_num_truncate(&n, n.rdx);
6260
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006261 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006262 if (s) goto num_err;
6263 s = bc_num_ulong(&n, &val);
6264 if (s) goto num_err;
6265
6266 c = (char) val;
6267
6268 bc_num_free(&n);
6269 }
6270 else {
6271 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006273 c = str2[0];
6274 }
6275
6276 str = xmalloc(2);
6277 str[0] = c;
6278 str[1] = '\0';
6279
6280 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006281 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006282
6283 if (idx != len + BC_PROG_REQ_FUNCS) {
6284
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006285 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6286 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006287 len = idx;
6288 break;
6289 }
6290 }
6291
6292 free(str);
6293 }
6294 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006295 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006296
6297 res.t = BC_RESULT_STR;
6298 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006299 bc_vec_pop(&G.prog.results);
6300 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006301
6302 return BC_STATUS_SUCCESS;
6303
6304num_err:
6305 bc_num_free(&n);
6306 return s;
6307}
6308
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006309static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006310{
6311 BcStatus s;
6312 BcResult *r;
6313 BcNum *n = NULL;
6314 size_t idx;
6315 char *str;
6316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006317 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6318 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006319
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006320 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006321 if (s) return s;
6322
6323 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006324 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006325 else {
6326 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006327 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006328 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006329 }
6330
6331 return s;
6332}
6333
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006334static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006335{
6336 BcStatus s;
6337 BcResult *opnd;
6338 BcNum *num = NULL;
6339 unsigned long val;
6340
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006341 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006342 if (s) return s;
6343 s = bc_num_ulong(num, &val);
6344 if (s) return s;
6345
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006346 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006347
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006348 if (G.prog.stack.len < val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006349 return BC_STATUS_EXEC_STACK;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006350 else if (G.prog.stack.len == val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006351 return BC_STATUS_QUIT;
6352
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006353 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006354
6355 return s;
6356}
6357
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006358static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006359 bool cond)
6360{
6361 BcStatus s = BC_STATUS_SUCCESS;
6362 BcResult *r;
6363 char **str;
6364 BcFunc *f;
6365 BcParse prs;
6366 BcInstPtr ip;
6367 size_t fidx, sidx;
6368 BcNum *n;
6369 bool exec;
6370
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006371 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006372
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006373 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006374
6375 if (cond) {
6376
Gavin Howard01055ba2018-11-03 11:00:21 -06006377 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6378
6379 if (code[*bgn] == BC_PARSE_STREND)
6380 (*bgn) += 1;
6381 else
6382 else_name = bc_program_name(code, bgn);
6383
6384 exec = r->d.n.len != 0;
6385
6386 if (exec)
6387 name = then_name;
6388 else if (else_name != NULL) {
6389 exec = true;
6390 name = else_name;
6391 }
6392
6393 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006394 BcVec *v;
6395 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006396 n = bc_vec_top(v);
6397 }
6398
6399 free(then_name);
6400 free(else_name);
6401
6402 if (!exec) goto exit;
6403 if (!BC_PROG_STR(n)) {
6404 s = BC_STATUS_EXEC_BAD_TYPE;
6405 goto exit;
6406 }
6407
6408 sidx = n->rdx;
6409 }
6410 else {
6411
6412 if (r->t == BC_RESULT_STR)
6413 sidx = r->d.id.idx;
6414 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006415 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006416 if (s || !BC_PROG_STR(n)) goto exit;
6417 sidx = n->rdx;
6418 }
6419 else
6420 goto exit;
6421 }
6422
6423 fidx = sidx + BC_PROG_REQ_FUNCS;
6424
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006425 str = bc_vec_item(&G.prog.strs, sidx);
6426 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006427
6428 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006429 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006430 s = bc_parse_text(&prs, *str);
6431 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006432 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006433 if (s) goto err;
6434
6435 if (prs.l.t.t != BC_LEX_EOF) {
6436 s = BC_STATUS_PARSE_BAD_EXP;
6437 goto err;
6438 }
6439
6440 bc_parse_free(&prs);
6441 }
6442
6443 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006444 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006445 ip.func = fidx;
6446
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006447 bc_vec_pop(&G.prog.results);
6448 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006449
6450 return BC_STATUS_SUCCESS;
6451
6452err:
6453 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006454 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006455 bc_vec_npop(&f->code, f->code.len);
6456exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006457 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006458 return s;
6459}
6460#endif // ENABLE_DC
6461
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006462static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006463{
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 BcResult res;
6465 unsigned long val;
6466
6467 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6468 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006469 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006470 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006471 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006472 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006473 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006474
6475 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006476 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006477 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006478}
6479
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006480static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006481{
6482 BcStatus s;
6483 BcId entry, *entry_ptr;
6484 BcFunc f;
6485
6486 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006487 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006488
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006489 s = bc_map_insert(&G.prog.fn_map, &entry, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006490 if (s) free(name);
6491
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006492 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006493 *idx = entry_ptr->idx;
6494
6495 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6496
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006497 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006498
6499 // We need to reset these, so the function can be repopulated.
6500 func->nparams = 0;
6501 bc_vec_npop(&func->autos, func->autos.len);
6502 bc_vec_npop(&func->code, func->code.len);
6503 bc_vec_npop(&func->labels, func->labels.len);
6504 }
6505 else {
6506 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006507 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006508 }
6509}
6510
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006511static BcStatus bc_program_reset(BcStatus s)
Gavin Howard01055ba2018-11-03 11:00:21 -06006512{
6513 BcFunc *f;
6514 BcInstPtr *ip;
6515
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006516 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6517 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006518
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006519 f = bc_vec_item(&G.prog.fns, 0);
6520 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006521 ip->idx = f->code.len;
6522
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006523 if (!s && G_interrupt && !G.tty) return BC_STATUS_QUIT;
Gavin Howard01055ba2018-11-03 11:00:21 -06006524
6525 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006526 if (G.ttyin) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01006527 fflush(stdout);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006528 fputs(bc_program_ready_msg, stderr);
6529 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530 s = BC_STATUS_SUCCESS;
6531 }
6532 else
6533 s = BC_STATUS_QUIT;
6534 }
6535
6536 return s;
6537}
6538
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006539static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006540{
6541 BcStatus s = BC_STATUS_SUCCESS;
6542 size_t idx;
6543 BcResult r, *ptr;
6544 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006545 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6546 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006547 char *code = func->code.v;
6548 bool cond = false;
6549
6550 while (!s && ip->idx < func->code.len) {
6551
6552 char inst = code[(ip->idx)++];
6553
6554 switch (inst) {
6555
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006556#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006557 case BC_INST_JUMP_ZERO:
6558 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006559 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006560 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006561 cond = !bc_num_cmp(num, &G.prog.zero);
6562 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 }
6564 // Fallthrough.
6565 case BC_INST_JUMP:
6566 {
6567 size_t *addr;
6568 idx = bc_program_index(code, &ip->idx);
6569 addr = bc_vec_item(&func->labels, idx);
6570 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6571 break;
6572 }
6573
6574 case BC_INST_CALL:
6575 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006576 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006577 break;
6578 }
6579
6580 case BC_INST_INC_PRE:
6581 case BC_INST_DEC_PRE:
6582 case BC_INST_INC_POST:
6583 case BC_INST_DEC_POST:
6584 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006585 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006586 break;
6587 }
6588
6589 case BC_INST_HALT:
6590 {
6591 s = BC_STATUS_QUIT;
6592 break;
6593 }
6594
6595 case BC_INST_RET:
6596 case BC_INST_RET0:
6597 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006598 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006599 break;
6600 }
6601
6602 case BC_INST_BOOL_OR:
6603 case BC_INST_BOOL_AND:
6604#endif // ENABLE_BC
6605 case BC_INST_REL_EQ:
6606 case BC_INST_REL_LE:
6607 case BC_INST_REL_GE:
6608 case BC_INST_REL_NE:
6609 case BC_INST_REL_LT:
6610 case BC_INST_REL_GT:
6611 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006612 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006613 break;
6614 }
6615
6616 case BC_INST_READ:
6617 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006618 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006619 break;
6620 }
6621
6622 case BC_INST_VAR:
6623 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006624 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006625 break;
6626 }
6627
6628 case BC_INST_ARRAY_ELEM:
6629 case BC_INST_ARRAY:
6630 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006631 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006632 break;
6633 }
6634
6635 case BC_INST_LAST:
6636 {
6637 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006638 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
6642 case BC_INST_IBASE:
6643 case BC_INST_SCALE:
6644 case BC_INST_OBASE:
6645 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006646 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006647 break;
6648 }
6649
6650 case BC_INST_SCALE_FUNC:
6651 case BC_INST_LENGTH:
6652 case BC_INST_SQRT:
6653 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006654 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006655 break;
6656 }
6657
6658 case BC_INST_NUM:
6659 {
6660 r.t = BC_RESULT_CONSTANT;
6661 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006662 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006663 break;
6664 }
6665
6666 case BC_INST_POP:
6667 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006668 if (!BC_PROG_STACK(&G.prog.results, 1))
Gavin Howard01055ba2018-11-03 11:00:21 -06006669 s = BC_STATUS_EXEC_STACK;
6670 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006671 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006672 break;
6673 }
6674
6675 case BC_INST_POP_EXEC:
6676 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006677 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006678 break;
6679 }
6680
6681 case BC_INST_PRINT:
6682 case BC_INST_PRINT_POP:
6683 case BC_INST_PRINT_STR:
6684 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006685 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006686 break;
6687 }
6688
6689 case BC_INST_STR:
6690 {
6691 r.t = BC_RESULT_STR;
6692 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006693 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006694 break;
6695 }
6696
6697 case BC_INST_POWER:
6698 case BC_INST_MULTIPLY:
6699 case BC_INST_DIVIDE:
6700 case BC_INST_MODULUS:
6701 case BC_INST_PLUS:
6702 case BC_INST_MINUS:
6703 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006704 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006705 break;
6706 }
6707
6708 case BC_INST_BOOL_NOT:
6709 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006710 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006711 if (s) return s;
6712
6713 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006714 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6715 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006716
6717 break;
6718 }
6719
6720 case BC_INST_NEG:
6721 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006722 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006723 break;
6724 }
6725
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006726#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006727 case BC_INST_ASSIGN_POWER:
6728 case BC_INST_ASSIGN_MULTIPLY:
6729 case BC_INST_ASSIGN_DIVIDE:
6730 case BC_INST_ASSIGN_MODULUS:
6731 case BC_INST_ASSIGN_PLUS:
6732 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006733#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006734 case BC_INST_ASSIGN:
6735 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006736 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006737 break;
6738 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006739#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006740 case BC_INST_MODEXP:
6741 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006742 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006743 break;
6744 }
6745
6746 case BC_INST_DIVMOD:
6747 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006748 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006749 break;
6750 }
6751
6752 case BC_INST_EXECUTE:
6753 case BC_INST_EXEC_COND:
6754 {
6755 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006756 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006757 break;
6758 }
6759
6760 case BC_INST_PRINT_STACK:
6761 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006762 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6763 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006764 break;
6765 }
6766
6767 case BC_INST_CLEAR_STACK:
6768 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006769 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006770 break;
6771 }
6772
6773 case BC_INST_STACK_LEN:
6774 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006775 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006776 break;
6777 }
6778
6779 case BC_INST_DUPLICATE:
6780 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006781 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6782 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006783 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006784 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006785 break;
6786 }
6787
6788 case BC_INST_SWAP:
6789 {
6790 BcResult *ptr2;
6791
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006792 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006793
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006794 ptr = bc_vec_item_rev(&G.prog.results, 0);
6795 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 memcpy(&r, ptr, sizeof(BcResult));
6797 memcpy(ptr, ptr2, sizeof(BcResult));
6798 memcpy(ptr2, &r, sizeof(BcResult));
6799
6800 break;
6801 }
6802
6803 case BC_INST_ASCIIFY:
6804 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006805 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006806 break;
6807 }
6808
6809 case BC_INST_PRINT_STREAM:
6810 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006811 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006812 break;
6813 }
6814
6815 case BC_INST_LOAD:
6816 case BC_INST_PUSH_VAR:
6817 {
6818 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006819 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006820 break;
6821 }
6822
6823 case BC_INST_PUSH_TO_VAR:
6824 {
6825 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006826 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006827 free(name);
6828 break;
6829 }
6830
6831 case BC_INST_QUIT:
6832 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006833 if (G.prog.stack.len <= 2)
Gavin Howard01055ba2018-11-03 11:00:21 -06006834 s = BC_STATUS_QUIT;
6835 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006836 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006837 break;
6838 }
6839
6840 case BC_INST_NQUIT:
6841 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006842 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006843 break;
6844 }
6845#endif // ENABLE_DC
6846 }
6847
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006848 if ((s && s != BC_STATUS_QUIT) || G_interrupt) s = bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006849
6850 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006851 ip = bc_vec_top(&G.prog.stack);
6852 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006853 code = func->code.v;
6854 }
6855
6856 return s;
6857}
6858
Denys Vlasenko00d77792018-11-30 23:13:42 +01006859static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006860{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006861 printf("%s "BB_VER"\n"
6862 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006863 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006864 "This is free software with ABSOLUTELY NO WARRANTY\n"
6865 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006866}
6867
6868static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6869{
6870 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6871
Denys Vlasenko00d77792018-11-30 23:13:42 +01006872 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6873 fprintf(stderr, " %s", file);
6874 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006875
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006876 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
Gavin Howard01055ba2018-11-03 11:00:21 -06006877}
6878
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006879#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006880static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6881 const char *msg)
6882{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006883 int p = (int) G_posix, w = (int) G_warn;
Gavin Howard01055ba2018-11-03 11:00:21 -06006884 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
6885
6886 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6887
Denys Vlasenko00d77792018-11-30 23:13:42 +01006888 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
6889 if (msg) fprintf(stderr, " %s\n", msg);
6890 fprintf(stderr, " %s", file);
6891 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006892
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006893 return s * (!G.ttyin && !!p);
Gavin Howard01055ba2018-11-03 11:00:21 -06006894}
6895
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006896static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006897{
Gavin Howard01055ba2018-11-03 11:00:21 -06006898 BcVec v;
6899 char *env_args = getenv(bc_args_env_name), *buf;
6900
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006901 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006902
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006903 G.env_args = xstrdup(env_args);
6904 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006905
6906 bc_vec_init(&v, sizeof(char *), NULL);
6907 bc_vec_push(&v, &bc_args_env_name);
6908
6909 while (*buf != 0) {
6910 if (!isspace(*buf)) {
6911 bc_vec_push(&v, &buf);
6912 while (*buf != 0 && !isspace(*buf)) ++buf;
6913 if (*buf != 0) (*(buf++)) = '\0';
6914 }
6915 else
6916 ++buf;
6917 }
6918
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006919 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006920
6921 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006922}
6923#endif // ENABLE_BC
6924
6925static size_t bc_vm_envLen(const char *var)
6926{
6927 char *lenv = getenv(var);
6928 size_t i, len = BC_NUM_PRINT_WIDTH;
6929 int num;
6930
6931 if (!lenv) return len;
6932
6933 len = strlen(lenv);
6934
6935 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6936 if (num) {
6937 len = (size_t) atoi(lenv) - 1;
6938 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6939 }
6940 else
6941 len = BC_NUM_PRINT_WIDTH;
6942
6943 return len;
6944}
6945
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006946static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006947{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006948 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006949
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006950 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006951 if (s) return s;
6952
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006953 while (G.prs.l.t.t != BC_LEX_EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006954
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006955 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006956
6957 if (s == BC_STATUS_LIMITS) {
6958
Denys Vlasenko00d77792018-11-30 23:13:42 +01006959 bb_putchar('\n');
6960 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
6961 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
6962 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
6963 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
6964 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
6965 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
6966 printf("Max Exponent = %lu\n", BC_MAX_EXP);
6967 printf("Number of Vars = %lu\n", BC_MAX_VARS);
6968 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06006969
6970 s = BC_STATUS_SUCCESS;
6971 }
6972 else {
6973 if (s == BC_STATUS_QUIT) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006974 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006975 if (s) return s;
6976 }
6977 }
6978
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006979 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006980 s = bc_program_exec();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006981 if (!s && G.tty) fflush(stdout);
Gavin Howard01055ba2018-11-03 11:00:21 -06006982 if (s && s != BC_STATUS_QUIT)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006983 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006984 }
6985
6986 return s;
6987}
6988
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006989static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006990{
6991 BcStatus s;
6992 char *data;
6993 BcFunc *main_func;
6994 BcInstPtr *ip;
6995
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006996 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006997 data = bc_read_file(file);
6998 if (!data) return bc_vm_error(BC_STATUS_BIN_FILE, file, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006999
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007000 bc_lex_file(&G.prs.l, file);
7001 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007002 if (s) goto err;
7003
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007004 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7005 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007006
7007 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7008
7009err:
7010 free(data);
7011 return s;
7012}
7013
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007014static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007015{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007016 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007017 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007018 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007019 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007020
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007021 G.prog.file = bc_program_stdin_name;
7022 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007023
7024 bc_vec_init(&buffer, sizeof(char), NULL);
7025 bc_vec_init(&buf, sizeof(char), NULL);
7026 bc_vec_pushByte(&buffer, '\0');
7027
7028 // This loop is complex because the vm tries not to send any lines that end
7029 // with a backslash to the parser. The reason for that is because the parser
7030 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7031 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007032 while ((s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007033
7034 char *string = buf.v;
7035
7036 len = buf.len - 1;
7037
7038 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007039 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007040 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007041 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007042 str += 1;
7043 }
7044 else if (len > 1 || comment) {
7045
7046 for (i = 0; i < len; ++i) {
7047
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007048 bool notend = len > i + 1;
7049 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007050
7051 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007052 if (G.sbgn == G.send)
7053 str ^= c == G.sbgn;
7054 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007055 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007056 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007057 str += 1;
7058 }
7059
7060 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7061 comment = true;
7062 break;
7063 }
7064 else if (c == '*' && notend && comment && string[i + 1] == '/')
7065 comment = false;
7066 }
7067
7068 if (str || comment || string[len - 2] == '\\') {
7069 bc_vec_concat(&buffer, buf.v);
7070 continue;
7071 }
7072 }
7073
7074 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007075 s = bc_vm_process(buffer.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007076 if (s) goto err;
7077
7078 bc_vec_npop(&buffer, buffer.len);
7079 }
7080
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007081 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007082
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007083 // INPUT_EOF will always happen when stdin is
Gavin Howard01055ba2018-11-03 11:00:21 -06007084 // closed. It's not a problem in that case.
Denys Vlasenko00d77792018-11-30 23:13:42 +01007085 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7086 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06007087
7088 if (str)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007089 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7090 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007091 else if (comment)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007092 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7093 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007094
7095err:
7096 bc_vec_free(&buf);
7097 bc_vec_free(&buffer);
7098 return s;
7099}
7100
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007101static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007102{
7103 BcStatus s = BC_STATUS_SUCCESS;
7104 size_t i;
7105
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007106#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007107 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007108
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007109 bc_lex_file(&G.prs.l, bc_lib_name);
7110 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007111
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007112 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007113
7114 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007115 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007116 if (s) return s;
7117 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007118#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007119
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007120 for (i = 0; !s && i < G.files.len; ++i)
7121 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Gavin Howard01055ba2018-11-03 11:00:21 -06007122 if (s && s != BC_STATUS_QUIT) return s;
7123
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007124 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7125 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007126
Denys Vlasenko00d77792018-11-30 23:13:42 +01007127 if (s == BC_STATUS_QUIT)
7128 s = BC_STATUS_SUCCESS;
7129 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007130}
7131
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007132#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007133static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007134{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007135 bc_num_free(&G.prog.ib);
7136 bc_num_free(&G.prog.ob);
7137 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007138# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007139 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007140# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007141 bc_vec_free(&G.prog.fns);
7142 bc_vec_free(&G.prog.fn_map);
7143 bc_vec_free(&G.prog.vars);
7144 bc_vec_free(&G.prog.var_map);
7145 bc_vec_free(&G.prog.arrs);
7146 bc_vec_free(&G.prog.arr_map);
7147 bc_vec_free(&G.prog.strs);
7148 bc_vec_free(&G.prog.consts);
7149 bc_vec_free(&G.prog.results);
7150 bc_vec_free(&G.prog.stack);
7151 bc_num_free(&G.prog.last);
7152 bc_num_free(&G.prog.zero);
7153 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007154}
7155
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007156static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007157{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007158 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007159 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007160 bc_parse_free(&G.prs);
7161 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007162}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007163#endif
7164
7165static void bc_program_init(size_t line_len)
7166{
7167 size_t idx;
7168 BcInstPtr ip;
7169
7170 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7171 memset(&ip, 0, sizeof(BcInstPtr));
7172
7173 /* G.prog.nchars = G.prog.scale = 0; - already is */
7174 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007175
7176 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7177 bc_num_ten(&G.prog.ib);
7178 G.prog.ib_t = 10;
7179
7180 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7181 bc_num_ten(&G.prog.ob);
7182 G.prog.ob_t = 10;
7183
7184 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7185 bc_num_ten(&G.prog.hexb);
7186 G.prog.hexb.num[0] = 6;
7187
7188#if ENABLE_DC
7189 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7190 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7191#endif
7192
7193 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7194 bc_num_zero(&G.prog.last);
7195
7196 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7197 bc_num_zero(&G.prog.zero);
7198
7199 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7200 bc_num_one(&G.prog.one);
7201
7202 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7203 bc_map_init(&G.prog.fn_map);
7204
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007205 bc_program_addFunc(xstrdup(bc_func_main), &idx);
7206 bc_program_addFunc(xstrdup(bc_func_read), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007207
7208 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7209 bc_map_init(&G.prog.var_map);
7210
7211 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7212 bc_map_init(&G.prog.arr_map);
7213
7214 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7215 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7216 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7217 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7218 bc_vec_push(&G.prog.stack, &ip);
7219}
Gavin Howard01055ba2018-11-03 11:00:21 -06007220
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007221static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007222{
Gavin Howard01055ba2018-11-03 11:00:21 -06007223 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007224
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007225#if ENABLE_FEATURE_BC_SIGNALS
7226 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007227#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007228
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007229 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007230
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007231 if (IS_BC) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007232 if (getenv("POSIXLY_CORRECT"))
7233 G.flags |= BC_FLAG_S;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007234 bc_vm_envArgs();
7235 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007236
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007237 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007238 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007239 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007240 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007241 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007242 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007243}
7244
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007245static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007246 const char *env_len)
7247{
7248 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007249
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007250 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007251 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007252
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007253 G.ttyin = isatty(0);
7254 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007255
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007256 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7257 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007258
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007259#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007260 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007261#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007262 return st;
7263}
7264
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007265#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007266int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7267int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007268{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007269 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007270 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007271
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007272 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007273}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007274#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007275
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007276#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007277int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7278int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007279{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007280 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007281 G.sbgn = '[';
7282 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007283
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007284 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007285}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007286#endif