blob: 45680c139d4ab1b0ddcf755303c73ac3043f0b15 [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 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600174} BcStatus;
175
Gavin Howard01055ba2018-11-03 11:00:21 -0600176#define BC_VEC_INVALID_IDX ((size_t) -1)
177#define BC_VEC_START_CAP (1 << 5)
178
179typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600180
181typedef struct BcVec {
182 char *v;
183 size_t len;
184 size_t cap;
185 size_t size;
186 BcVecFree dtor;
187} BcVec;
188
189#define bc_vec_pop(v) (bc_vec_npop((v), 1))
190#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
191
Gavin Howard01055ba2018-11-03 11:00:21 -0600192typedef signed char BcDig;
193
194typedef struct BcNum {
195 BcDig *restrict num;
196 size_t rdx;
197 size_t len;
198 size_t cap;
199 bool neg;
200} BcNum;
201
202#define BC_NUM_MIN_BASE ((unsigned long) 2)
203#define BC_NUM_MAX_IBASE ((unsigned long) 16)
204#define BC_NUM_DEF_SIZE (16)
205#define BC_NUM_PRINT_WIDTH (69)
206
207#define BC_NUM_KARATSUBA_LEN (32)
208
209#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212#define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214#define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
216
217typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
219
220static void bc_num_init(BcNum *n, size_t req);
221static void bc_num_expand(BcNum *n, size_t req);
222static void bc_num_copy(BcNum *d, BcNum *s);
223static void bc_num_free(void *num);
224
225static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100226static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600227
228static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
236 size_t scale);
237
238typedef enum BcInst {
239
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100240#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600241 BC_INST_INC_PRE,
242 BC_INST_DEC_PRE,
243 BC_INST_INC_POST,
244 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100245#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600246
247 BC_INST_NEG,
248
249 BC_INST_POWER,
250 BC_INST_MULTIPLY,
251 BC_INST_DIVIDE,
252 BC_INST_MODULUS,
253 BC_INST_PLUS,
254 BC_INST_MINUS,
255
256 BC_INST_REL_EQ,
257 BC_INST_REL_LE,
258 BC_INST_REL_GE,
259 BC_INST_REL_NE,
260 BC_INST_REL_LT,
261 BC_INST_REL_GT,
262
263 BC_INST_BOOL_NOT,
264 BC_INST_BOOL_OR,
265 BC_INST_BOOL_AND,
266
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100267#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
272 BC_INST_ASSIGN_PLUS,
273 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100274#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600275 BC_INST_ASSIGN,
276
277 BC_INST_NUM,
278 BC_INST_VAR,
279 BC_INST_ARRAY_ELEM,
280 BC_INST_ARRAY,
281
282 BC_INST_SCALE_FUNC,
283 BC_INST_IBASE,
284 BC_INST_SCALE,
285 BC_INST_LAST,
286 BC_INST_LENGTH,
287 BC_INST_READ,
288 BC_INST_OBASE,
289 BC_INST_SQRT,
290
291 BC_INST_PRINT,
292 BC_INST_PRINT_POP,
293 BC_INST_STR,
294 BC_INST_PRINT_STR,
295
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100296#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600297 BC_INST_JUMP,
298 BC_INST_JUMP_ZERO,
299
300 BC_INST_CALL,
301
302 BC_INST_RET,
303 BC_INST_RET0,
304
305 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100306#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600307
308 BC_INST_POP,
309 BC_INST_POP_EXEC,
310
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100311#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600312 BC_INST_MODEXP,
313 BC_INST_DIVMOD,
314
315 BC_INST_EXECUTE,
316 BC_INST_EXEC_COND,
317
318 BC_INST_ASCIIFY,
319 BC_INST_PRINT_STREAM,
320
321 BC_INST_PRINT_STACK,
322 BC_INST_CLEAR_STACK,
323 BC_INST_STACK_LEN,
324 BC_INST_DUPLICATE,
325 BC_INST_SWAP,
326
327 BC_INST_LOAD,
328 BC_INST_PUSH_VAR,
329 BC_INST_PUSH_TO_VAR,
330
331 BC_INST_QUIT,
332 BC_INST_NQUIT,
333
334 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100335#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600336
337} BcInst;
338
339typedef struct BcId {
340 char *name;
341 size_t idx;
342} BcId;
343
344typedef struct BcFunc {
345 BcVec code;
346 BcVec labels;
347 size_t nparams;
348 BcVec autos;
349} BcFunc;
350
351typedef enum BcResultType {
352
353 BC_RESULT_TEMP,
354
355 BC_RESULT_VAR,
356 BC_RESULT_ARRAY_ELEM,
357 BC_RESULT_ARRAY,
358
359 BC_RESULT_STR,
360
361 BC_RESULT_IBASE,
362 BC_RESULT_SCALE,
363 BC_RESULT_LAST,
364
365 // These are between to calculate ibase, obase, and last from instructions.
366 BC_RESULT_CONSTANT,
367 BC_RESULT_ONE,
368
369 BC_RESULT_OBASE,
370
371} BcResultType;
372
373typedef union BcResultData {
374 BcNum n;
375 BcVec v;
376 BcId id;
377} BcResultData;
378
379typedef struct BcResult {
380 BcResultType t;
381 BcResultData d;
382} BcResult;
383
384typedef struct BcInstPtr {
385 size_t func;
386 size_t idx;
387 size_t len;
388} BcInstPtr;
389
390static void bc_array_expand(BcVec *a, size_t len);
391static int bc_id_cmp(const void *e1, const void *e2);
392
393// BC_LEX_NEG is not used in lexing; it is only for parsing.
394typedef enum BcLexType {
395
396 BC_LEX_EOF,
397 BC_LEX_INVALID,
398
399 BC_LEX_OP_INC,
400 BC_LEX_OP_DEC,
401
402 BC_LEX_NEG,
403
404 BC_LEX_OP_POWER,
405 BC_LEX_OP_MULTIPLY,
406 BC_LEX_OP_DIVIDE,
407 BC_LEX_OP_MODULUS,
408 BC_LEX_OP_PLUS,
409 BC_LEX_OP_MINUS,
410
411 BC_LEX_OP_REL_EQ,
412 BC_LEX_OP_REL_LE,
413 BC_LEX_OP_REL_GE,
414 BC_LEX_OP_REL_NE,
415 BC_LEX_OP_REL_LT,
416 BC_LEX_OP_REL_GT,
417
418 BC_LEX_OP_BOOL_NOT,
419 BC_LEX_OP_BOOL_OR,
420 BC_LEX_OP_BOOL_AND,
421
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
428 BC_LEX_OP_ASSIGN,
429
430 BC_LEX_NLINE,
431 BC_LEX_WHITESPACE,
432
433 BC_LEX_LPAREN,
434 BC_LEX_RPAREN,
435
436 BC_LEX_LBRACKET,
437 BC_LEX_COMMA,
438 BC_LEX_RBRACKET,
439
440 BC_LEX_LBRACE,
441 BC_LEX_SCOLON,
442 BC_LEX_RBRACE,
443
444 BC_LEX_STR,
445 BC_LEX_NAME,
446 BC_LEX_NUMBER,
447
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600450 BC_LEX_KEY_BREAK,
451 BC_LEX_KEY_CONTINUE,
452 BC_LEX_KEY_DEFINE,
453 BC_LEX_KEY_ELSE,
454 BC_LEX_KEY_FOR,
455 BC_LEX_KEY_HALT,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600458 BC_LEX_KEY_IF,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600460 BC_LEX_KEY_LENGTH,
461 BC_LEX_KEY_LIMITS,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600463 BC_LEX_KEY_PRINT,
464 BC_LEX_KEY_QUIT,
465 BC_LEX_KEY_READ,
466 BC_LEX_KEY_RETURN,
467 BC_LEX_KEY_SCALE,
468 BC_LEX_KEY_SQRT,
469 BC_LEX_KEY_WHILE,
470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100471#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_EQ_NO_REG,
473 BC_LEX_OP_MODEXP,
474 BC_LEX_OP_DIVMOD,
475
476 BC_LEX_COLON,
477 BC_LEX_ELSE,
478 BC_LEX_EXECUTE,
479 BC_LEX_PRINT_STACK,
480 BC_LEX_CLEAR_STACK,
481 BC_LEX_STACK_LEVEL,
482 BC_LEX_DUPLICATE,
483 BC_LEX_SWAP,
484 BC_LEX_POP,
485
486 BC_LEX_ASCIIFY,
487 BC_LEX_PRINT_STREAM,
488
489 BC_LEX_STORE_IBASE,
490 BC_LEX_STORE_SCALE,
491 BC_LEX_LOAD,
492 BC_LEX_LOAD_POP,
493 BC_LEX_STORE_PUSH,
494 BC_LEX_STORE_OBASE,
495 BC_LEX_PRINT_POP,
496 BC_LEX_NQUIT,
497 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100498#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600499} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100500// must match order of BC_LEX_KEY_foo etc above
501#if ENABLE_BC
502struct BcLexKeyword {
503 char name8[8];
504};
505#define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
512
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
517
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
522
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
527
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
532};
533enum {
534 POSIX_KWORD_MASK = 0
535 | (1 << 0)
536 | (1 << 1)
537 | (0 << 2)
538 | (1 << 3)
539 \
540 | (0 << 4)
541 | (1 << 5)
542 | (0 << 6)
543 | (1 << 7)
544 \
545 | (1 << 8)
546 | (0 << 9)
547 | (1 << 10)
548 | (0 << 11)
549 \
550 | (1 << 12)
551 | (0 << 13)
552 | (1 << 14)
553 | (0 << 15)
554 \
555 | (1 << 16)
556 | (1 << 17)
557 | (1 << 18)
558 | (1 << 19)
559};
560#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600561
562struct BcLex;
563typedef BcStatus (*BcLexNext)(struct BcLex *);
564
565typedef struct BcLex {
566
567 const char *buf;
568 size_t i;
569 size_t line;
570 const char *f;
571 size_t len;
572 bool newline;
573
574 struct {
575 BcLexType t;
576 BcLexType last;
577 BcVec v;
578 } t;
579
580 BcLexNext next;
581
582} BcLex;
583
584#define BC_PARSE_STREND ((char) UCHAR_MAX)
585
586#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
587#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100588 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600589
590#define BC_PARSE_REL (1 << 0)
591#define BC_PARSE_PRINT (1 << 1)
592#define BC_PARSE_NOCALL (1 << 2)
593#define BC_PARSE_NOREAD (1 << 3)
594#define BC_PARSE_ARRAY (1 << 4)
595
596#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
597#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598
599#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
600#define BC_PARSE_FUNC_INNER(parse) \
601 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602
603#define BC_PARSE_FLAG_FUNC (1 << 1)
604#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605
606#define BC_PARSE_FLAG_BODY (1 << 2)
607#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608
609#define BC_PARSE_FLAG_LOOP (1 << 3)
610#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611
612#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
613#define BC_PARSE_LOOP_INNER(parse) \
614 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615
616#define BC_PARSE_FLAG_IF (1 << 5)
617#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618
619#define BC_PARSE_FLAG_ELSE (1 << 6)
620#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621
622#define BC_PARSE_FLAG_IF_END (1 << 7)
623#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624
625#define BC_PARSE_CAN_EXEC(parse) \
626 (!(BC_PARSE_TOP_FLAG(parse) & \
627 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
628 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
629 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630
631typedef struct BcOp {
632 char prec;
633 bool left;
634} BcOp;
635
636typedef struct BcParseNext {
637 uint32_t len;
638 BcLexType tokens[4];
639} BcParseNext;
640
641#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
642#define BC_PARSE_NEXT(a, ...) \
643 { \
644 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
645 }
646
647struct BcParse;
648
649struct BcProgram;
650
Gavin Howard01055ba2018-11-03 11:00:21 -0600651typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600652
653typedef struct BcParse {
654
655 BcParseParse parse;
656
657 BcLex l;
658
659 BcVec flags;
660
661 BcVec exits;
662 BcVec conds;
663
664 BcVec ops;
665
Gavin Howard01055ba2018-11-03 11:00:21 -0600666 BcFunc *func;
667 size_t fidx;
668
669 size_t nbraces;
670 bool auto_part;
671
672} BcParse;
673
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100674#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600675
Gavin Howard01055ba2018-11-03 11:00:21 -0600676static BcStatus bc_lex_token(BcLex *l);
677
678#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
679#define BC_PARSE_LEAF(p, rparen) \
680 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
681 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682
683// We can calculate the conversion between tokens and exprs by subtracting the
684// position of the first operator in the lex enum and adding the position of the
685// first in the expr enum. Note: This only works for binary operators.
686#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687
Gavin Howard01055ba2018-11-03 11:00:21 -0600688static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
689
Denys Vlasenko00d77792018-11-30 23:13:42 +0100690#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600691
Denys Vlasenko00d77792018-11-30 23:13:42 +0100692#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600693
694#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695
Gavin Howard01055ba2018-11-03 11:00:21 -0600696static BcStatus dc_lex_token(BcLex *l);
697
Gavin Howard01055ba2018-11-03 11:00:21 -0600698static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
699
700#endif // ENABLE_DC
701
702typedef struct BcProgram {
703
704 size_t len;
705 size_t scale;
706
707 BcNum ib;
708 size_t ib_t;
709 BcNum ob;
710 size_t ob_t;
711
712 BcNum hexb;
713
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100714#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600715 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100716#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600717
718 BcVec results;
719 BcVec stack;
720
721 BcVec fns;
722 BcVec fn_map;
723
724 BcVec vars;
725 BcVec var_map;
726
727 BcVec arrs;
728 BcVec arr_map;
729
730 BcVec strs;
731 BcVec consts;
732
733 const char *file;
734
735 BcNum last;
736 BcNum zero;
737 BcNum one;
738
739 size_t nchars;
740
Gavin Howard01055ba2018-11-03 11:00:21 -0600741} BcProgram;
742
743#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744
745#define BC_PROG_MAIN (0)
746#define BC_PROG_READ (1)
747
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100748#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600749#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100750#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600751
752#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
753#define BC_PROG_NUM(r, n) \
754 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755
756typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100758static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100759static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600760
761#define BC_FLAG_X (1 << 0)
762#define BC_FLAG_W (1 << 1)
763#define BC_FLAG_V (1 << 2)
764#define BC_FLAG_S (1 << 3)
765#define BC_FLAG_Q (1 << 4)
766#define BC_FLAG_L (1 << 5)
767#define BC_FLAG_I (1 << 6)
768
769#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
770#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100772#define BC_MAX_OBASE ((unsigned) 999)
773#define BC_MAX_DIM ((unsigned) INT_MAX)
774#define BC_MAX_SCALE ((unsigned) UINT_MAX)
775#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
776#define BC_MAX_NAME BC_MAX_STRING
777#define BC_MAX_NUM BC_MAX_STRING
778#define BC_MAX_EXP ((unsigned long) LONG_MAX)
779#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600780
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100781struct globals {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100782 smallint ttyin;
783 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600784 char sbgn;
785 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600786
787 BcParse prs;
788 BcProgram prog;
789
Gavin Howard01055ba2018-11-03 11:00:21 -0600790 BcVec files;
791
792 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100793} FIX_ALIASING;
794#define G (*ptr_to_globals)
795#define INIT_G() do { \
796 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
797} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100798#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
799#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
800#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100801#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600802
Gavin Howard01055ba2018-11-03 11:00:21 -0600803
Denys Vlasenko00d77792018-11-30 23:13:42 +0100804#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
805
Denys Vlasenko00d77792018-11-30 23:13:42 +0100806static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600807
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100808#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600809
810// This is an array that corresponds to token types. An entry is
811// true if the token is valid in an expression, false otherwise.
812static const bool bc_parse_exprs[] = {
813 false, false, true, true, true, true, true, true, true, true, true, true,
814 true, true, true, true, true, true, true, true, true, true, true, true,
815 true, true, true, false, false, true, true, false, false, false, false,
816 false, false, false, true, true, false, false, false, false, false, false,
817 false, true, false, true, true, true, true, false, false, true, false, true,
818 true, false,
819};
820
821// This is an array of data for operators that correspond to token types.
822static const BcOp bc_parse_ops[] = {
823 { 0, false }, { 0, false },
824 { 1, false },
825 { 2, false },
826 { 3, true }, { 3, true }, { 3, true },
827 { 4, true }, { 4, true },
828 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
829 { 1, false },
830 { 7, true }, { 7, true },
831 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
832 { 5, false }, { 5, false },
833};
834
835// These identify what tokens can come after expressions in certain cases.
836static const BcParseNext bc_parse_next_expr =
837 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
838static const BcParseNext bc_parse_next_param =
839 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
840static const BcParseNext bc_parse_next_print =
841 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
842static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
843static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
844static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
845static const BcParseNext bc_parse_next_read =
846 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
847#endif // ENABLE_BC
848
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100849#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600850static const BcLexType dc_lex_regs[] = {
851 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
852 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
853 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
854 BC_LEX_STORE_PUSH,
855};
856
Gavin Howard01055ba2018-11-03 11:00:21 -0600857static const BcLexType dc_lex_tokens[] = {
858 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
859 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
860 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
861 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
862 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
863 BC_LEX_INVALID, BC_LEX_INVALID,
864 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
865 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
868 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
869 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
870 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
871 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
872 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
873 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
874 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
875 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
877 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
878 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
879 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
880 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
881 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
882 BC_LEX_INVALID
883};
884
885static const BcInst dc_parse_insts[] = {
886 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
887 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
888 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
890 BC_INST_INVALID, BC_INST_INVALID,
891 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
896 BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
899 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
901 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
903 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
904 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
905 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
906 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
908 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
909};
910#endif // ENABLE_DC
911
Gavin Howard01055ba2018-11-03 11:00:21 -0600912static const BcNumBinaryOp bc_program_ops[] = {
913 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
914};
915
916static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600917
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100918#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600919static const char *bc_lib_name = "gen/lib.bc";
920
921static const char bc_lib[] = {
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100922 "scale=20"
923"\ndefine e(x){"
924"\n auto b,s,n,r,d,i,p,f,v"
925"\n b=ibase"
926"\n ibase=A"
927"\n if(x<0){"
928"\n n=1"
929"\n x=-x"
930"\n }"
931"\n s=scale"
932"\n r=6+s+0.44*x"
933"\n scale=scale(x)+1"
934"\n while(x>1){"
935"\n d+=1"
936"\n x/=2"
937"\n scale+=1"
938"\n }"
939"\n scale=r"
940"\n r=x+1"
941"\n p=x"
942"\n f=v=1"
943"\n for(i=2;v!=0;++i){"
944"\n p*=x"
945"\n f*=i"
946"\n v=p/f"
947"\n r+=v"
948"\n }"
949"\n while((d--)!=0)r*=r"
950"\n scale=s"
951"\n ibase=b"
952"\n if(n!=0)return(1/r)"
953"\n return(r/1)"
954"\n}"
955"\ndefine l(x){"
956"\n auto b,s,r,p,a,q,i,v"
957"\n b=ibase"
958"\n ibase=A"
959"\n if(x<=0){"
960"\n r=(1-10^scale)/1"
961"\n ibase=b"
962"\n return(r)"
963"\n }"
964"\n s=scale"
965"\n scale+=6"
966"\n p=2"
967"\n while(x>=2){"
968"\n p*=2"
969"\n x=sqrt(x)"
970"\n }"
971"\n while(x<=0.5){"
972"\n p*=2"
973"\n x=sqrt(x)"
974"\n }"
975"\n r=a=(x-1)/(x+1)"
976"\n q=a*a"
977"\n v=1"
978"\n for(i=3;v!=0;i+=2){"
979"\n a*=q"
980"\n v=a/i"
981"\n r+=v"
982"\n }"
983"\n r*=p"
984"\n scale=s"
985"\n ibase=b"
986"\n return(r/1)"
987"\n}"
988"\ndefine s(x){"
989"\n auto b,s,r,n,a,q,i"
990"\n b=ibase"
991"\n ibase=A"
992"\n s=scale"
993"\n scale=1.1*s+2"
994"\n a=a(1)"
995"\n if(x<0){"
996"\n n=1"
997"\n x=-x"
998"\n }"
999"\n scale=0"
1000"\n q=(x/a+2)/4"
1001"\n x=x-4*q*a"
1002"\n if(q%2!=0)x=-x"
1003"\n scale=s+2"
1004"\n r=a=x"
1005"\n q=-x*x"
1006"\n for(i=3;a!=0;i+=2){"
1007"\n a*=q/(i*(i-1))"
1008"\n r+=a"
1009"\n }"
1010"\n scale=s"
1011"\n ibase=b"
1012"\n if(n!=0)return(-r/1)"
1013"\n return(r/1)"
1014"\n}"
1015"\ndefine c(x){"
1016"\n auto b,s"
1017"\n b=ibase"
1018"\n ibase=A"
1019"\n s=scale"
1020"\n scale*=1.2"
1021"\n x=s(2*a(1)+x)"
1022"\n scale=s"
1023"\n ibase=b"
1024"\n return(x/1)"
1025"\n}"
1026"\ndefine a(x){"
1027"\n auto b,s,r,n,a,m,t,f,i,u"
1028"\n b=ibase"
1029"\n ibase=A"
1030"\n n=1"
1031"\n if(x<0){"
1032"\n n=-1"
1033"\n x=-x"
1034"\n }"
1035"\n if(x==1){"
1036"\n if(scale<65){"
1037"\n return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
1038"\n }"
1039"\n }"
1040"\n if(x==.2){"
1041"\n if(scale<65){"
1042"\n return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
1043"\n }"
1044"\n }"
1045"\n s=scale"
1046"\n if(x>.2){"
1047"\n scale+=5"
1048"\n a=a(.2)"
1049"\n }"
1050"\n scale=s+3"
1051"\n while(x>.2){"
1052"\n m+=1"
1053"\n x=(x-.2)/(1+.2*x)"
1054"\n }"
1055"\n r=u=x"
1056"\n f=-x*x"
1057"\n t=1"
1058"\n for(i=3;t!=0;i+=2){"
1059"\n u*=f"
1060"\n t=u/i"
1061"\n r+=t"
1062"\n }"
1063"\n scale=s"
1064"\n ibase=b"
1065"\n return((m*a+r)/n)"
1066"\n}"
1067"\ndefine j(n,x){"
1068"\n auto b,s,o,a,i,v,f"
1069"\n b=ibase"
1070"\n ibase=A"
1071"\n s=scale"
1072"\n scale=0"
1073"\n n/=1"
1074"\n if(n<0){"
1075"\n n=-n"
1076"\n if(n%2==1)o=1"
1077"\n }"
1078"\n a=1"
1079"\n for(i=2;i<=n;++i)a*=i"
1080"\n scale=1.5*s"
1081"\n a=(x^n)/2^n/a"
1082"\n r=v=1"
1083"\n f=-x*x/4"
1084"\n scale=scale+length(a)-scale(a)"
1085"\n for(i=1;v!=0;++i){"
1086"\n v=v*f/i/(n+i)"
1087"\n r+=v"
1088"\n }"
1089"\n scale=s"
1090"\n ibase=b"
1091"\n if(o!=0)a=-a"
1092"\n return(a*r/1)"
1093"\n}"
Gavin Howard01055ba2018-11-03 11:00:21 -06001094};
1095#endif // ENABLE_BC
1096
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001097static void fflush_and_check(void)
1098{
1099 fflush_all();
1100 if (ferror(stdout) || ferror(stderr))
1101 bb_perror_msg_and_die("output error");
1102}
1103
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001104static void quit(void) NORETURN;
1105static void quit(void)
1106{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001107 if (ferror(stdin))
1108 bb_perror_msg_and_die("input error");
1109 fflush_and_check();
1110 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001111}
1112
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001113static int bc_error(const char *fmt, ...)
1114{
1115 va_list p;
1116
1117 va_start(p, fmt);
1118 bb_verror_msg(fmt, p, NULL);
1119 va_end(p);
1120 if (!G.ttyin)
1121 exit(1);
1122 return BC_STATUS_FAILURE;
1123}
1124
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001125static int bc_posix_error(const char *fmt, ...)
1126{
1127 va_list p;
1128
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001129 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001130 return BC_STATUS_SUCCESS;
1131
1132 va_start(p, fmt);
1133 bb_verror_msg(fmt, p, NULL);
1134 va_end(p);
1135
1136 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001137 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001138 return BC_STATUS_SUCCESS; // no, it's a warning
1139 if (!G.ttyin)
1140 exit(1);
1141 return BC_STATUS_FAILURE;
1142}
1143
Gavin Howard01055ba2018-11-03 11:00:21 -06001144static void bc_vec_grow(BcVec *v, size_t n)
1145{
1146 size_t cap = v->cap * 2;
1147 while (cap < v->len + n) cap *= 2;
1148 v->v = xrealloc(v->v, v->size * cap);
1149 v->cap = cap;
1150}
1151
1152static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1153{
1154 v->size = esize;
1155 v->cap = BC_VEC_START_CAP;
1156 v->len = 0;
1157 v->dtor = dtor;
1158 v->v = xmalloc(esize * BC_VEC_START_CAP);
1159}
1160
Denys Vlasenko7d628012018-12-04 21:46:47 +01001161static void bc_char_vec_init(BcVec *v)
1162{
1163 bc_vec_init(v, sizeof(char), NULL);
1164}
1165
Gavin Howard01055ba2018-11-03 11:00:21 -06001166static void bc_vec_expand(BcVec *v, size_t req)
1167{
1168 if (v->cap < req) {
1169 v->v = xrealloc(v->v, v->size * req);
1170 v->cap = req;
1171 }
1172}
1173
1174static void bc_vec_npop(BcVec *v, size_t n)
1175{
1176 if (!v->dtor)
1177 v->len -= n;
1178 else {
1179 size_t len = v->len - n;
1180 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1181 }
1182}
1183
Denys Vlasenko7d628012018-12-04 21:46:47 +01001184static void bc_vec_pop_all(BcVec *v)
1185{
1186 bc_vec_npop(v, v->len);
1187}
1188
Gavin Howard01055ba2018-11-03 11:00:21 -06001189static void bc_vec_push(BcVec *v, const void *data)
1190{
1191 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1192 memmove(v->v + (v->size * v->len), data, v->size);
1193 v->len += 1;
1194}
1195
1196static void bc_vec_pushByte(BcVec *v, char data)
1197{
1198 bc_vec_push(v, &data);
1199}
1200
1201static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1202{
1203 if (idx == v->len)
1204 bc_vec_push(v, data);
1205 else {
1206
1207 char *ptr;
1208
1209 if (v->len == v->cap) bc_vec_grow(v, 1);
1210
1211 ptr = v->v + v->size * idx;
1212
1213 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1214 memmove(ptr, data, v->size);
1215 }
1216}
1217
1218static void bc_vec_string(BcVec *v, size_t len, const char *str)
1219{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001220 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001221 bc_vec_expand(v, len + 1);
1222 memcpy(v->v, str, len);
1223 v->len = len;
1224
1225 bc_vec_pushByte(v, '\0');
1226}
1227
1228static void bc_vec_concat(BcVec *v, const char *str)
1229{
1230 size_t len;
1231
1232 if (v->len == 0) bc_vec_pushByte(v, '\0');
1233
1234 len = v->len + strlen(str);
1235
1236 if (v->cap < len) bc_vec_grow(v, len - v->len);
1237 strcat(v->v, str);
1238
1239 v->len = len;
1240}
1241
1242static void *bc_vec_item(const BcVec *v, size_t idx)
1243{
1244 return v->v + v->size * idx;
1245}
1246
1247static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1248{
1249 return v->v + v->size * (v->len - idx - 1);
1250}
1251
1252static void bc_vec_free(void *vec)
1253{
1254 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001255 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001256 free(v->v);
1257}
1258
1259static size_t bc_map_find(const BcVec *v, const void *ptr)
1260{
1261 size_t low = 0, high = v->len;
1262
1263 while (low < high) {
1264
1265 size_t mid = (low + high) / 2;
1266 BcId *id = bc_vec_item(v, mid);
1267 int result = bc_id_cmp(ptr, id);
1268
1269 if (result == 0)
1270 return mid;
1271 else if (result < 0)
1272 high = mid;
1273 else
1274 low = mid + 1;
1275 }
1276
1277 return low;
1278}
1279
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001280static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001281{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001282 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001283
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001284 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001285 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001286 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1287 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001288 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001289 bc_vec_pushAt(v, ptr, n);
1290 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001291}
1292
1293static size_t bc_map_index(const BcVec *v, const void *ptr)
1294{
1295 size_t i = bc_map_find(v, ptr);
1296 if (i >= v->len) return BC_VEC_INVALID_IDX;
1297 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1298}
1299
1300static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1301{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001302 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001303
Denys Vlasenko00d77792018-11-30 23:13:42 +01001304 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001305 int i;
1306 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001307
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001308 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001309 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001310
1311 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001312#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001313 if (bb_got_signal) { // ^C was pressed
1314 intr:
1315 bb_got_signal = 0; // resets G_interrupt to zero
1316 fputs(IS_BC
1317 ? "\ninterrupt (type \"quit\" to exit)\n"
1318 : "\ninterrupt (type \"q\" to exit)\n"
1319 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001320 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001321#endif
1322 if (G.ttyin && !G_posix)
1323 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001324
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001325#if ENABLE_FEATURE_BC_SIGNALS
1326 errno = 0;
1327#endif
1328 do {
1329 i = fgetc(stdin);
1330 if (i == EOF) {
1331#if ENABLE_FEATURE_BC_SIGNALS
1332 // Both conditions appear simultaneously, check both just in case
1333 if (errno == EINTR || bb_got_signal) {
1334 // ^C was pressed
1335 clearerr(stdin);
1336 goto intr;
1337 }
1338#endif
1339 if (ferror(stdin))
1340 quit(); // this emits error message
1341 G.eof = 1;
1342 // Note: EOF does not append '\n', therefore:
1343 // printf 'print 123\n' | bc - works
1344 // printf 'print 123' | bc - fails (syntax error)
1345 break;
1346 }
1347
1348 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1349 || i > 0x7e
1350 ) {
1351 // Bad chars on this line, ignore entire line
1352 bc_error("illegal character 0x%02x", i);
1353 bad_chars = 1;
1354 }
1355 c = (char) i;
1356 bc_vec_push(vec, &c);
1357 } while (i != '\n');
1358 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001359
1360 bc_vec_pushByte(vec, '\0');
1361
1362 return BC_STATUS_SUCCESS;
1363}
1364
Denys Vlasenkodf515392018-12-02 19:27:48 +01001365static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001366{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001367 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001368 size_t size = ((size_t) -1);
1369 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001370
Denys Vlasenkodf515392018-12-02 19:27:48 +01001371 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001372
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001373 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001374 char c = buf[i];
1375 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1376 || c > 0x7e
1377 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001378 free(buf);
1379 buf = NULL;
1380 break;
1381 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001382 }
1383
Denys Vlasenkodf515392018-12-02 19:27:48 +01001384 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001385}
1386
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001387static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001388{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001389 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001390 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001391
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001392 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001393#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001394 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001395 "extended-register\0" No_argument "x"
1396 "warn\0" No_argument "w"
1397 "version\0" No_argument "v"
1398 "standard\0" No_argument "s"
1399 "quiet\0" No_argument "q"
1400 "mathlib\0" No_argument "l"
1401 "interactive\0" No_argument "i"
1402 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001403#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001404 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001405#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001406 if (getenv("POSIXLY_CORRECT"))
1407 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001408
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001409 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001410 // should not be necessary, getopt32() handles this??
1411 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001412
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001413 for (i = optind; i < argc; ++i)
1414 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001415}
1416
1417static void bc_num_setToZero(BcNum *n, size_t scale)
1418{
1419 n->len = 0;
1420 n->neg = false;
1421 n->rdx = scale;
1422}
1423
1424static void bc_num_zero(BcNum *n)
1425{
1426 bc_num_setToZero(n, 0);
1427}
1428
1429static void bc_num_one(BcNum *n)
1430{
1431 bc_num_setToZero(n, 0);
1432 n->len = 1;
1433 n->num[0] = 1;
1434}
1435
1436static void bc_num_ten(BcNum *n)
1437{
1438 bc_num_setToZero(n, 0);
1439 n->len = 2;
1440 n->num[0] = 0;
1441 n->num[1] = 1;
1442}
1443
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001444static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001445 size_t len)
1446{
1447 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001448 for (i = 0; i < len; ++i) {
1449 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001450 a[i + j++] += 10;
1451 a[i + j] -= 1;
1452 }
1453 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001454}
1455
1456static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1457{
1458 size_t i;
1459 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001460 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001461 return BC_NUM_NEG(i + 1, c < 0);
1462}
1463
1464static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1465{
1466 size_t i, min, a_int, b_int, diff;
1467 BcDig *max_num, *min_num;
1468 bool a_max, neg = false;
1469 ssize_t cmp;
1470
1471 if (a == b) return 0;
1472 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1473 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1474 if (a->neg) {
1475 if (b->neg)
1476 neg = true;
1477 else
1478 return -1;
1479 }
1480 else if (b->neg)
1481 return 1;
1482
1483 a_int = BC_NUM_INT(a);
1484 b_int = BC_NUM_INT(b);
1485 a_int -= b_int;
1486 a_max = (a->rdx > b->rdx);
1487
1488 if (a_int != 0) return (ssize_t) a_int;
1489
1490 if (a_max) {
1491 min = b->rdx;
1492 diff = a->rdx - b->rdx;
1493 max_num = a->num + diff;
1494 min_num = b->num;
1495 }
1496 else {
1497 min = a->rdx;
1498 diff = b->rdx - a->rdx;
1499 max_num = b->num + diff;
1500 min_num = a->num;
1501 }
1502
1503 cmp = bc_num_compare(max_num, min_num, b_int + min);
1504 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1505
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001506 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001507 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1508 }
1509
1510 return 0;
1511}
1512
1513static void bc_num_truncate(BcNum *n, size_t places)
1514{
1515 if (places == 0) return;
1516
1517 n->rdx -= places;
1518
1519 if (n->len != 0) {
1520 n->len -= places;
1521 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1522 }
1523}
1524
1525static void bc_num_extend(BcNum *n, size_t places)
1526{
1527 size_t len = n->len + places;
1528
1529 if (places != 0) {
1530
1531 if (n->cap < len) bc_num_expand(n, len);
1532
1533 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1534 memset(n->num, 0, sizeof(BcDig) * places);
1535
1536 n->len += places;
1537 n->rdx += places;
1538 }
1539}
1540
1541static void bc_num_clean(BcNum *n)
1542{
1543 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1544 if (n->len == 0)
1545 n->neg = false;
1546 else if (n->len < n->rdx)
1547 n->len = n->rdx;
1548}
1549
1550static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1551{
1552 if (n->rdx < scale)
1553 bc_num_extend(n, scale - n->rdx);
1554 else
1555 bc_num_truncate(n, n->rdx - scale);
1556
1557 bc_num_clean(n);
1558 if (n->len != 0) n->neg = !neg1 != !neg2;
1559}
1560
1561static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1562 BcNum *restrict b)
1563{
1564 if (idx < n->len) {
1565
1566 b->len = n->len - idx;
1567 a->len = idx;
1568 a->rdx = b->rdx = 0;
1569
1570 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1571 memcpy(a->num, n->num, idx * sizeof(BcDig));
1572 }
1573 else {
1574 bc_num_zero(b);
1575 bc_num_copy(a, n);
1576 }
1577
1578 bc_num_clean(a);
1579 bc_num_clean(b);
1580}
1581
1582static BcStatus bc_num_shift(BcNum *n, size_t places)
1583{
1584 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001585 if (places + n->len > BC_MAX_NUM)
1586 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001587
1588 if (n->rdx >= places)
1589 n->rdx -= places;
1590 else {
1591 bc_num_extend(n, places - n->rdx);
1592 n->rdx = 0;
1593 }
1594
1595 bc_num_clean(n);
1596
1597 return BC_STATUS_SUCCESS;
1598}
1599
1600static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1601{
1602 BcNum one;
1603 BcDig num[2];
1604
1605 one.cap = 2;
1606 one.num = num;
1607 bc_num_one(&one);
1608
1609 return bc_num_div(&one, a, b, scale);
1610}
1611
1612static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1613{
1614 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1615 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1616 int carry, in;
1617
1618 // Because this function doesn't need to use scale (per the bc spec),
1619 // I am hijacking it to say whether it's doing an add or a subtract.
1620
1621 if (a->len == 0) {
1622 bc_num_copy(c, b);
1623 if (sub && c->len) c->neg = !c->neg;
1624 return BC_STATUS_SUCCESS;
1625 }
1626 else if (b->len == 0) {
1627 bc_num_copy(c, a);
1628 return BC_STATUS_SUCCESS;
1629 }
1630
1631 c->neg = a->neg;
1632 c->rdx = BC_MAX(a->rdx, b->rdx);
1633 min_rdx = BC_MIN(a->rdx, b->rdx);
1634 c->len = 0;
1635
1636 if (a->rdx > b->rdx) {
1637 diff = a->rdx - b->rdx;
1638 ptr = a->num;
1639 ptr_a = a->num + diff;
1640 ptr_b = b->num;
1641 }
1642 else {
1643 diff = b->rdx - a->rdx;
1644 ptr = b->num;
1645 ptr_a = a->num;
1646 ptr_b = b->num + diff;
1647 }
1648
1649 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1650
1651 ptr_c += diff;
1652 a_int = BC_NUM_INT(a);
1653 b_int = BC_NUM_INT(b);
1654
1655 if (a_int > b_int) {
1656 min_int = b_int;
1657 max = a_int;
1658 ptr = ptr_a;
1659 }
1660 else {
1661 min_int = a_int;
1662 max = b_int;
1663 ptr = ptr_b;
1664 }
1665
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001666 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001667 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1668 carry = in / 10;
1669 ptr_c[i] = (BcDig)(in % 10);
1670 }
1671
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001672 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001673 in = ((int) ptr[i]) + carry;
1674 carry = in / 10;
1675 ptr_c[i] = (BcDig)(in % 10);
1676 }
1677
1678 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1679
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001680 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001681}
1682
1683static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1684{
Gavin Howard01055ba2018-11-03 11:00:21 -06001685 ssize_t cmp;
1686 BcNum *minuend, *subtrahend;
1687 size_t start;
1688 bool aneg, bneg, neg;
1689
1690 // Because this function doesn't need to use scale (per the bc spec),
1691 // I am hijacking it to say whether it's doing an add or a subtract.
1692
1693 if (a->len == 0) {
1694 bc_num_copy(c, b);
1695 if (sub && c->len) c->neg = !c->neg;
1696 return BC_STATUS_SUCCESS;
1697 }
1698 else if (b->len == 0) {
1699 bc_num_copy(c, a);
1700 return BC_STATUS_SUCCESS;
1701 }
1702
1703 aneg = a->neg;
1704 bneg = b->neg;
1705 a->neg = b->neg = false;
1706
1707 cmp = bc_num_cmp(a, b);
1708
1709 a->neg = aneg;
1710 b->neg = bneg;
1711
1712 if (cmp == 0) {
1713 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1714 return BC_STATUS_SUCCESS;
1715 }
1716 else if (cmp > 0) {
1717 neg = a->neg;
1718 minuend = a;
1719 subtrahend = b;
1720 }
1721 else {
1722 neg = b->neg;
1723 if (sub) neg = !neg;
1724 minuend = b;
1725 subtrahend = a;
1726 }
1727
1728 bc_num_copy(c, minuend);
1729 c->neg = neg;
1730
1731 if (c->rdx < subtrahend->rdx) {
1732 bc_num_extend(c, subtrahend->rdx - c->rdx);
1733 start = 0;
1734 }
1735 else
1736 start = c->rdx - subtrahend->rdx;
1737
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001738 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001739
1740 bc_num_clean(c);
1741
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001742 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001743}
1744
1745static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1746 BcNum *restrict c)
1747{
1748 BcStatus s;
1749 int carry;
1750 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1751 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1752 bool aone = BC_NUM_ONE(a);
1753
Gavin Howard01055ba2018-11-03 11:00:21 -06001754 if (a->len == 0 || b->len == 0) {
1755 bc_num_zero(c);
1756 return BC_STATUS_SUCCESS;
1757 }
1758 else if (aone || BC_NUM_ONE(b)) {
1759 bc_num_copy(c, aone ? b : a);
1760 return BC_STATUS_SUCCESS;
1761 }
1762
1763 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1764 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1765 {
1766 bc_num_expand(c, a->len + b->len + 1);
1767
1768 memset(c->num, 0, sizeof(BcDig) * c->cap);
1769 c->len = carry = len = 0;
1770
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001771 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001772
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001773 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001774 int in = (int) c->num[i + j];
1775 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1776 carry = in / 10;
1777 c->num[i + j] = (BcDig)(in % 10);
1778 }
1779
1780 c->num[i + j] += (BcDig) carry;
1781 len = BC_MAX(len, i + j + !!carry);
1782 carry = 0;
1783 }
1784
1785 c->len = len;
1786
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001787 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001788 }
1789
1790 bc_num_init(&l1, max);
1791 bc_num_init(&h1, max);
1792 bc_num_init(&l2, max);
1793 bc_num_init(&h2, max);
1794 bc_num_init(&m1, max);
1795 bc_num_init(&m2, max);
1796 bc_num_init(&z0, max);
1797 bc_num_init(&z1, max);
1798 bc_num_init(&z2, max);
1799 bc_num_init(&temp, max + max);
1800
1801 bc_num_split(a, max2, &l1, &h1);
1802 bc_num_split(b, max2, &l2, &h2);
1803
1804 s = bc_num_add(&h1, &l1, &m1, 0);
1805 if (s) goto err;
1806 s = bc_num_add(&h2, &l2, &m2, 0);
1807 if (s) goto err;
1808
1809 s = bc_num_k(&h1, &h2, &z0);
1810 if (s) goto err;
1811 s = bc_num_k(&m1, &m2, &z1);
1812 if (s) goto err;
1813 s = bc_num_k(&l1, &l2, &z2);
1814 if (s) goto err;
1815
1816 s = bc_num_sub(&z1, &z0, &temp, 0);
1817 if (s) goto err;
1818 s = bc_num_sub(&temp, &z2, &z1, 0);
1819 if (s) goto err;
1820
1821 s = bc_num_shift(&z0, max2 * 2);
1822 if (s) goto err;
1823 s = bc_num_shift(&z1, max2);
1824 if (s) goto err;
1825 s = bc_num_add(&z0, &z1, &temp, 0);
1826 if (s) goto err;
1827 s = bc_num_add(&temp, &z2, c, 0);
1828
1829err:
1830 bc_num_free(&temp);
1831 bc_num_free(&z2);
1832 bc_num_free(&z1);
1833 bc_num_free(&z0);
1834 bc_num_free(&m2);
1835 bc_num_free(&m1);
1836 bc_num_free(&h2);
1837 bc_num_free(&l2);
1838 bc_num_free(&h1);
1839 bc_num_free(&l1);
1840 return s;
1841}
1842
1843static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1844{
1845 BcStatus s;
1846 BcNum cpa, cpb;
1847 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1848
1849 scale = BC_MAX(scale, a->rdx);
1850 scale = BC_MAX(scale, b->rdx);
1851 scale = BC_MIN(a->rdx + b->rdx, scale);
1852 maxrdx = BC_MAX(maxrdx, scale);
1853
1854 bc_num_init(&cpa, a->len);
1855 bc_num_init(&cpb, b->len);
1856
1857 bc_num_copy(&cpa, a);
1858 bc_num_copy(&cpb, b);
1859 cpa.neg = cpb.neg = false;
1860
1861 s = bc_num_shift(&cpa, maxrdx);
1862 if (s) goto err;
1863 s = bc_num_shift(&cpb, maxrdx);
1864 if (s) goto err;
1865 s = bc_num_k(&cpa, &cpb, c);
1866 if (s) goto err;
1867
1868 maxrdx += scale;
1869 bc_num_expand(c, c->len + maxrdx);
1870
1871 if (c->len < maxrdx) {
1872 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1873 c->len += maxrdx;
1874 }
1875
1876 c->rdx = maxrdx;
1877 bc_num_retireMul(c, scale, a->neg, b->neg);
1878
1879err:
1880 bc_num_free(&cpb);
1881 bc_num_free(&cpa);
1882 return s;
1883}
1884
1885static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1886{
1887 BcStatus s = BC_STATUS_SUCCESS;
1888 BcDig *n, *p, q;
1889 size_t len, end, i;
1890 BcNum cp;
1891 bool zero = true;
1892
1893 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001894 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001895 else if (a->len == 0) {
1896 bc_num_setToZero(c, scale);
1897 return BC_STATUS_SUCCESS;
1898 }
1899 else if (BC_NUM_ONE(b)) {
1900 bc_num_copy(c, a);
1901 bc_num_retireMul(c, scale, a->neg, b->neg);
1902 return BC_STATUS_SUCCESS;
1903 }
1904
1905 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1906 bc_num_copy(&cp, a);
1907 len = b->len;
1908
1909 if (len > cp.len) {
1910 bc_num_expand(&cp, len + 2);
1911 bc_num_extend(&cp, len - cp.len);
1912 }
1913
1914 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1915 cp.rdx -= b->rdx;
1916 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1917
1918 if (b->rdx == b->len) {
1919 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1920 len -= i - 1;
1921 }
1922
1923 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1924
1925 // We want an extra zero in front to make things simpler.
1926 cp.num[cp.len++] = 0;
1927 end = cp.len - len;
1928
1929 bc_num_expand(c, cp.len);
1930
1931 bc_num_zero(c);
1932 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1933 c->rdx = cp.rdx;
1934 c->len = cp.len;
1935 p = b->num;
1936
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001937 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001938 n = cp.num + i;
1939 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001940 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001941 c->num[i] = q;
1942 }
1943
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001944 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001945 bc_num_free(&cp);
1946
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001947 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001948}
1949
1950static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1951 BcNum *restrict d, size_t scale, size_t ts)
1952{
1953 BcStatus s;
1954 BcNum temp;
1955 bool neg;
1956
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001957 if (b->len == 0)
1958 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001959
1960 if (a->len == 0) {
1961 bc_num_setToZero(d, ts);
1962 return BC_STATUS_SUCCESS;
1963 }
1964
1965 bc_num_init(&temp, d->cap);
1966 bc_num_d(a, b, c, scale);
1967
1968 if (scale != 0) scale = ts;
1969
1970 s = bc_num_m(c, b, &temp, scale);
1971 if (s) goto err;
1972 s = bc_num_sub(a, &temp, d, scale);
1973 if (s) goto err;
1974
1975 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1976
1977 neg = d->neg;
1978 bc_num_retireMul(d, ts, a->neg, b->neg);
1979 d->neg = neg;
1980
1981err:
1982 bc_num_free(&temp);
1983 return s;
1984}
1985
1986static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1987{
1988 BcStatus s;
1989 BcNum c1;
1990 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1991
1992 bc_num_init(&c1, len);
1993 s = bc_num_r(a, b, &c1, c, scale, ts);
1994 bc_num_free(&c1);
1995
1996 return s;
1997}
1998
1999static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2000{
2001 BcStatus s = BC_STATUS_SUCCESS;
2002 BcNum copy;
2003 unsigned long pow;
2004 size_t i, powrdx, resrdx;
2005 bool neg, zero;
2006
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002007 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002008
2009 if (b->len == 0) {
2010 bc_num_one(c);
2011 return BC_STATUS_SUCCESS;
2012 }
2013 else if (a->len == 0) {
2014 bc_num_setToZero(c, scale);
2015 return BC_STATUS_SUCCESS;
2016 }
2017 else if (BC_NUM_ONE(b)) {
2018 if (!b->neg)
2019 bc_num_copy(c, a);
2020 else
2021 s = bc_num_inv(a, c, scale);
2022 return s;
2023 }
2024
2025 neg = b->neg;
2026 b->neg = false;
2027
2028 s = bc_num_ulong(b, &pow);
2029 if (s) return s;
2030
2031 bc_num_init(&copy, a->len);
2032 bc_num_copy(&copy, a);
2033
2034 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2035
2036 b->neg = neg;
2037
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002038 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002039 powrdx <<= 1;
2040 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2041 if (s) goto err;
2042 }
2043
Gavin Howard01055ba2018-11-03 11:00:21 -06002044 bc_num_copy(c, &copy);
2045
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002046 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002047
2048 powrdx <<= 1;
2049 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2050 if (s) goto err;
2051
2052 if (pow & 1) {
2053 resrdx += powrdx;
2054 s = bc_num_mul(c, &copy, c, resrdx);
2055 if (s) goto err;
2056 }
2057 }
2058
2059 if (neg) {
2060 s = bc_num_inv(c, c, scale);
2061 if (s) goto err;
2062 }
2063
Gavin Howard01055ba2018-11-03 11:00:21 -06002064 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2065
2066 // We can't use bc_num_clean() here.
2067 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2068 if (zero) bc_num_setToZero(c, scale);
2069
2070err:
2071 bc_num_free(&copy);
2072 return s;
2073}
2074
2075static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2076 BcNumBinaryOp op, size_t req)
2077{
2078 BcStatus s;
2079 BcNum num2, *ptr_a, *ptr_b;
2080 bool init = false;
2081
2082 if (c == a) {
2083 ptr_a = &num2;
2084 memcpy(ptr_a, c, sizeof(BcNum));
2085 init = true;
2086 }
2087 else
2088 ptr_a = a;
2089
2090 if (c == b) {
2091 ptr_b = &num2;
2092 if (c != a) {
2093 memcpy(ptr_b, c, sizeof(BcNum));
2094 init = true;
2095 }
2096 }
2097 else
2098 ptr_b = b;
2099
2100 if (init)
2101 bc_num_init(c, req);
2102 else
2103 bc_num_expand(c, req);
2104
2105 s = op(ptr_a, ptr_b, c, scale);
2106
2107 if (init) bc_num_free(&num2);
2108
2109 return s;
2110}
2111
2112static bool bc_num_strValid(const char *val, size_t base)
2113{
2114 BcDig b;
2115 bool small, radix = false;
2116 size_t i, len = strlen(val);
2117
2118 if (!len) return true;
2119
2120 small = base <= 10;
2121 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2122
2123 for (i = 0; i < len; ++i) {
2124
2125 BcDig c = val[i];
2126
2127 if (c == '.') {
2128
2129 if (radix) return false;
2130
2131 radix = true;
2132 continue;
2133 }
2134
2135 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2136 return false;
2137 }
2138
2139 return true;
2140}
2141
2142static void bc_num_parseDecimal(BcNum *n, const char *val)
2143{
2144 size_t len, i;
2145 const char *ptr;
2146 bool zero = true;
2147
2148 for (i = 0; val[i] == '0'; ++i);
2149
2150 val += i;
2151 len = strlen(val);
2152 bc_num_zero(n);
2153
2154 if (len != 0) {
2155 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2156 bc_num_expand(n, len);
2157 }
2158
2159 ptr = strchr(val, '.');
2160
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002161 n->rdx = 0;
2162 if (ptr != NULL)
2163 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002164
2165 if (!zero) {
2166 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2167 n->num[n->len] = val[i] - '0';
2168 }
2169}
2170
2171static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2172{
2173 BcStatus s;
2174 BcNum temp, mult, result;
2175 BcDig c = '\0';
2176 bool zero = true;
2177 unsigned long v;
2178 size_t i, digits, len = strlen(val);
2179
2180 bc_num_zero(n);
2181
2182 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2183 if (zero) return;
2184
2185 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2186 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2187
2188 for (i = 0; i < len; ++i) {
2189
2190 c = val[i];
2191 if (c == '.') break;
2192
2193 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2194
2195 s = bc_num_mul(n, base, &mult, 0);
2196 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002197 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002198 s = bc_num_add(&mult, &temp, n, 0);
2199 if (s) goto int_err;
2200 }
2201
2202 if (i == len) {
2203 c = val[i];
2204 if (c == 0) goto int_err;
2205 }
2206
2207 bc_num_init(&result, base->len);
2208 bc_num_zero(&result);
2209 bc_num_one(&mult);
2210
2211 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2212
2213 c = val[i];
2214 if (c == 0) break;
2215
2216 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2217
2218 s = bc_num_mul(&result, base, &result, 0);
2219 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002220 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002221 s = bc_num_add(&result, &temp, &result, 0);
2222 if (s) goto err;
2223 s = bc_num_mul(&mult, base, &mult, 0);
2224 if (s) goto err;
2225 }
2226
2227 s = bc_num_div(&result, &mult, &result, digits);
2228 if (s) goto err;
2229 s = bc_num_add(n, &result, n, digits);
2230 if (s) goto err;
2231
2232 if (n->len != 0) {
2233 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2234 }
2235 else
2236 bc_num_zero(n);
2237
2238err:
2239 bc_num_free(&result);
2240int_err:
2241 bc_num_free(&mult);
2242 bc_num_free(&temp);
2243}
2244
2245static void bc_num_printNewline(size_t *nchars, size_t line_len)
2246{
2247 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002248 bb_putchar('\\');
2249 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002250 *nchars = 0;
2251 }
2252}
2253
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002254#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002255static void bc_num_printChar(size_t num, size_t width, bool radix,
2256 size_t *nchars, size_t line_len)
2257{
2258 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002259 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002260 *nchars = *nchars + width;
2261}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002262#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002263
2264static void bc_num_printDigits(size_t num, size_t width, bool radix,
2265 size_t *nchars, size_t line_len)
2266{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002267 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002268
2269 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002270 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002271 ++(*nchars);
2272
2273 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002274 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2275 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002276
2277 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002278 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002279 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002280 dig = num / pow;
2281 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002282 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002283 }
2284}
2285
2286static void bc_num_printHex(size_t num, size_t width, bool radix,
2287 size_t *nchars, size_t line_len)
2288{
2289 if (radix) {
2290 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002291 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002292 *nchars += 1;
2293 }
2294
2295 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002296 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002297 *nchars = *nchars + width;
2298}
2299
2300static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2301{
2302 size_t i, rdx = n->rdx - 1;
2303
Denys Vlasenko00d77792018-11-30 23:13:42 +01002304 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002305 (*nchars) += n->neg;
2306
2307 for (i = n->len - 1; i < n->len; --i)
2308 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2309}
2310
2311static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2312 size_t *nchars, size_t len, BcNumDigitOp print)
2313{
2314 BcStatus s;
2315 BcVec stack;
2316 BcNum intp, fracp, digit, frac_len;
2317 unsigned long dig, *ptr;
2318 size_t i;
2319 bool radix;
2320
2321 if (n->len == 0) {
2322 print(0, width, false, nchars, len);
2323 return BC_STATUS_SUCCESS;
2324 }
2325
2326 bc_vec_init(&stack, sizeof(long), NULL);
2327 bc_num_init(&intp, n->len);
2328 bc_num_init(&fracp, n->rdx);
2329 bc_num_init(&digit, width);
2330 bc_num_init(&frac_len, BC_NUM_INT(n));
2331 bc_num_copy(&intp, n);
2332 bc_num_one(&frac_len);
2333
2334 bc_num_truncate(&intp, intp.rdx);
2335 s = bc_num_sub(n, &intp, &fracp, 0);
2336 if (s) goto err;
2337
2338 while (intp.len != 0) {
2339 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2340 if (s) goto err;
2341 s = bc_num_ulong(&digit, &dig);
2342 if (s) goto err;
2343 bc_vec_push(&stack, &dig);
2344 }
2345
2346 for (i = 0; i < stack.len; ++i) {
2347 ptr = bc_vec_item_rev(&stack, i);
2348 print(*ptr, width, false, nchars, len);
2349 }
2350
2351 if (!n->rdx) goto err;
2352
2353 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2354 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2355 if (s) goto err;
2356 s = bc_num_ulong(&fracp, &dig);
2357 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002358 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002359 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2360 if (s) goto err;
2361 print(dig, width, radix, nchars, len);
2362 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2363 if (s) goto err;
2364 }
2365
2366err:
2367 bc_num_free(&frac_len);
2368 bc_num_free(&digit);
2369 bc_num_free(&fracp);
2370 bc_num_free(&intp);
2371 bc_vec_free(&stack);
2372 return s;
2373}
2374
2375static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2376 size_t *nchars, size_t line_len)
2377{
2378 BcStatus s;
2379 size_t width, i;
2380 BcNumDigitOp print;
2381 bool neg = n->neg;
2382
Denys Vlasenko00d77792018-11-30 23:13:42 +01002383 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002384 (*nchars) += neg;
2385
2386 n->neg = false;
2387
2388 if (base_t <= BC_NUM_MAX_IBASE) {
2389 width = 1;
2390 print = bc_num_printHex;
2391 }
2392 else {
2393 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2394 print = bc_num_printDigits;
2395 }
2396
2397 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2398 n->neg = neg;
2399
2400 return s;
2401}
2402
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002403#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002404static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2405{
2406 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2407}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002408#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002409
2410static void bc_num_init(BcNum *n, size_t req)
2411{
2412 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2413 memset(n, 0, sizeof(BcNum));
2414 n->num = xmalloc(req);
2415 n->cap = req;
2416}
2417
2418static void bc_num_expand(BcNum *n, size_t req)
2419{
2420 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2421 if (req > n->cap) {
2422 n->num = xrealloc(n->num, req);
2423 n->cap = req;
2424 }
2425}
2426
2427static void bc_num_free(void *num)
2428{
2429 free(((BcNum *) num)->num);
2430}
2431
2432static void bc_num_copy(BcNum *d, BcNum *s)
2433{
2434 if (d != s) {
2435 bc_num_expand(d, s->cap);
2436 d->len = s->len;
2437 d->neg = s->neg;
2438 d->rdx = s->rdx;
2439 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2440 }
2441}
2442
2443static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2444 size_t base_t)
2445{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002446 if (!bc_num_strValid(val, base_t))
2447 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002448
2449 if (base_t == 10)
2450 bc_num_parseDecimal(n, val);
2451 else
2452 bc_num_parseBase(n, val, base);
2453
2454 return BC_STATUS_SUCCESS;
2455}
2456
2457static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2458 size_t *nchars, size_t line_len)
2459{
2460 BcStatus s = BC_STATUS_SUCCESS;
2461
2462 bc_num_printNewline(nchars, line_len);
2463
2464 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002465 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002466 ++(*nchars);
2467 }
2468 else if (base_t == 10)
2469 bc_num_printDecimal(n, nchars, line_len);
2470 else
2471 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2472
2473 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002474 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002475 *nchars = 0;
2476 }
2477
2478 return s;
2479}
2480
2481static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2482{
2483 size_t i;
2484 unsigned long pow;
2485
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002486 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002487
2488 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2489
2490 unsigned long prev = *result, powprev = pow;
2491
2492 *result += ((unsigned long) n->num[i]) * pow;
2493 pow *= 10;
2494
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002495 if (*result < prev || pow < powprev)
2496 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002497 }
2498
2499 return BC_STATUS_SUCCESS;
2500}
2501
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002502static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002503{
2504 size_t len;
2505 BcDig *ptr;
2506 unsigned long i;
2507
2508 bc_num_zero(n);
2509
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002510 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002511
2512 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2513 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002514}
2515
2516static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2517{
2518 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2519 (void) scale;
2520 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2521}
2522
2523static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2524{
2525 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2526 (void) scale;
2527 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2528}
2529
2530static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2531{
2532 size_t req = BC_NUM_MREQ(a, b, scale);
2533 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2534}
2535
2536static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2537{
2538 size_t req = BC_NUM_MREQ(a, b, scale);
2539 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2540}
2541
2542static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2543{
2544 size_t req = BC_NUM_MREQ(a, b, scale);
2545 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2546}
2547
2548static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2549{
2550 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2551}
2552
2553static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2554{
2555 BcStatus s;
2556 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2557 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2558 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2559
2560 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2561 bc_num_expand(b, req);
2562
2563 if (a->len == 0) {
2564 bc_num_setToZero(b, scale);
2565 return BC_STATUS_SUCCESS;
2566 }
2567 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002568 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002569 else if (BC_NUM_ONE(a)) {
2570 bc_num_one(b);
2571 bc_num_extend(b, scale);
2572 return BC_STATUS_SUCCESS;
2573 }
2574
2575 scale = BC_MAX(scale, a->rdx) + 1;
2576 len = a->len + scale;
2577
2578 bc_num_init(&num1, len);
2579 bc_num_init(&num2, len);
2580 bc_num_init(&half, BC_NUM_DEF_SIZE);
2581
2582 bc_num_one(&half);
2583 half.num[0] = 5;
2584 half.rdx = 1;
2585
2586 bc_num_init(&f, len);
2587 bc_num_init(&fprime, len);
2588
2589 x0 = &num1;
2590 x1 = &num2;
2591
2592 bc_num_one(x0);
2593 pow = BC_NUM_INT(a);
2594
2595 if (pow) {
2596
2597 if (pow & 1)
2598 x0->num[0] = 2;
2599 else
2600 x0->num[0] = 6;
2601
2602 pow -= 2 - (pow & 1);
2603
2604 bc_num_extend(x0, pow);
2605
2606 // Make sure to move the radix back.
2607 x0->rdx -= pow;
2608 }
2609
2610 x0->rdx = digs = digs1 = 0;
2611 resrdx = scale + 2;
2612 len = BC_NUM_INT(x0) + resrdx - 1;
2613
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002614 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002615
2616 s = bc_num_div(a, x0, &f, resrdx);
2617 if (s) goto err;
2618 s = bc_num_add(x0, &f, &fprime, resrdx);
2619 if (s) goto err;
2620 s = bc_num_mul(&fprime, &half, x1, resrdx);
2621 if (s) goto err;
2622
2623 cmp = bc_num_cmp(x1, x0);
2624 digs = x1->len - (unsigned long long) llabs(cmp);
2625
2626 if (cmp == cmp2 && digs == digs1)
2627 times += 1;
2628 else
2629 times = 0;
2630
2631 resrdx += times > 4;
2632
2633 cmp2 = cmp1;
2634 cmp1 = cmp;
2635 digs1 = digs;
2636
2637 temp = x0;
2638 x0 = x1;
2639 x1 = temp;
2640 }
2641
Gavin Howard01055ba2018-11-03 11:00:21 -06002642 bc_num_copy(b, x0);
2643 scale -= 1;
2644 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2645
2646err:
2647 bc_num_free(&fprime);
2648 bc_num_free(&f);
2649 bc_num_free(&half);
2650 bc_num_free(&num2);
2651 bc_num_free(&num1);
2652 return s;
2653}
2654
2655static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2656 size_t scale)
2657{
2658 BcStatus s;
2659 BcNum num2, *ptr_a;
2660 bool init = false;
2661 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2662
2663 if (c == a) {
2664 memcpy(&num2, c, sizeof(BcNum));
2665 ptr_a = &num2;
2666 bc_num_init(c, len);
2667 init = true;
2668 }
2669 else {
2670 ptr_a = a;
2671 bc_num_expand(c, len);
2672 }
2673
2674 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2675
2676 if (init) bc_num_free(&num2);
2677
2678 return s;
2679}
2680
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002681#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002682static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2683{
2684 BcStatus s;
2685 BcNum base, exp, two, temp;
2686
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002687 if (c->len == 0)
2688 return bc_error("divide by zero");
2689 if (a->rdx || b->rdx || c->rdx)
2690 return bc_error("non integer number");
2691 if (b->neg)
2692 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002693
2694 bc_num_expand(d, c->len);
2695 bc_num_init(&base, c->len);
2696 bc_num_init(&exp, b->len);
2697 bc_num_init(&two, BC_NUM_DEF_SIZE);
2698 bc_num_init(&temp, b->len);
2699
2700 bc_num_one(&two);
2701 two.num[0] = 2;
2702 bc_num_one(d);
2703
2704 s = bc_num_rem(a, c, &base, 0);
2705 if (s) goto err;
2706 bc_num_copy(&exp, b);
2707
2708 while (exp.len != 0) {
2709
2710 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2711 if (s) goto err;
2712
2713 if (BC_NUM_ONE(&temp)) {
2714 s = bc_num_mul(d, &base, &temp, 0);
2715 if (s) goto err;
2716 s = bc_num_rem(&temp, c, d, 0);
2717 if (s) goto err;
2718 }
2719
2720 s = bc_num_mul(&base, &base, &temp, 0);
2721 if (s) goto err;
2722 s = bc_num_rem(&temp, c, &base, 0);
2723 if (s) goto err;
2724 }
2725
2726err:
2727 bc_num_free(&temp);
2728 bc_num_free(&two);
2729 bc_num_free(&exp);
2730 bc_num_free(&base);
2731 return s;
2732}
2733#endif // ENABLE_DC
2734
2735static int bc_id_cmp(const void *e1, const void *e2)
2736{
2737 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2738}
2739
2740static void bc_id_free(void *id)
2741{
2742 free(((BcId *) id)->name);
2743}
2744
2745static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2746{
2747 BcId a;
2748 size_t i;
2749
2750 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002751 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2752 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002753 }
2754
2755 a.idx = var;
2756 a.name = name;
2757
2758 bc_vec_push(&f->autos, &a);
2759
2760 return BC_STATUS_SUCCESS;
2761}
2762
2763static void bc_func_init(BcFunc *f)
2764{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002765 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002766 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2767 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2768 f->nparams = 0;
2769}
2770
2771static void bc_func_free(void *func)
2772{
2773 BcFunc *f = (BcFunc *) func;
2774 bc_vec_free(&f->code);
2775 bc_vec_free(&f->autos);
2776 bc_vec_free(&f->labels);
2777}
2778
2779static void bc_array_init(BcVec *a, bool nums)
2780{
2781 if (nums)
2782 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2783 else
2784 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2785 bc_array_expand(a, 1);
2786}
2787
2788static void bc_array_copy(BcVec *d, const BcVec *s)
2789{
2790 size_t i;
2791
Denys Vlasenko7d628012018-12-04 21:46:47 +01002792 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002793 bc_vec_expand(d, s->cap);
2794 d->len = s->len;
2795
2796 for (i = 0; i < s->len; ++i) {
2797 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2798 bc_num_init(dnum, snum->len);
2799 bc_num_copy(dnum, snum);
2800 }
2801}
2802
2803static void bc_array_expand(BcVec *a, size_t len)
2804{
2805 BcResultData data;
2806
2807 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2808 while (len > a->len) {
2809 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2810 bc_vec_push(a, &data.n);
2811 }
2812 }
2813 else {
2814 while (len > a->len) {
2815 bc_array_init(&data.v, true);
2816 bc_vec_push(a, &data.v);
2817 }
2818 }
2819}
2820
2821static void bc_string_free(void *string)
2822{
2823 free(*((char **) string));
2824}
2825
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002826#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002827static void bc_result_copy(BcResult *d, BcResult *src)
2828{
2829 d->t = src->t;
2830
2831 switch (d->t) {
2832
2833 case BC_RESULT_TEMP:
2834 case BC_RESULT_IBASE:
2835 case BC_RESULT_SCALE:
2836 case BC_RESULT_OBASE:
2837 {
2838 bc_num_init(&d->d.n, src->d.n.len);
2839 bc_num_copy(&d->d.n, &src->d.n);
2840 break;
2841 }
2842
2843 case BC_RESULT_VAR:
2844 case BC_RESULT_ARRAY:
2845 case BC_RESULT_ARRAY_ELEM:
2846 {
2847 d->d.id.name = xstrdup(src->d.id.name);
2848 break;
2849 }
2850
2851 case BC_RESULT_CONSTANT:
2852 case BC_RESULT_LAST:
2853 case BC_RESULT_ONE:
2854 case BC_RESULT_STR:
2855 {
2856 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2857 break;
2858 }
2859 }
2860}
2861#endif // ENABLE_DC
2862
2863static void bc_result_free(void *result)
2864{
2865 BcResult *r = (BcResult *) result;
2866
2867 switch (r->t) {
2868
2869 case BC_RESULT_TEMP:
2870 case BC_RESULT_IBASE:
2871 case BC_RESULT_SCALE:
2872 case BC_RESULT_OBASE:
2873 {
2874 bc_num_free(&r->d.n);
2875 break;
2876 }
2877
2878 case BC_RESULT_VAR:
2879 case BC_RESULT_ARRAY:
2880 case BC_RESULT_ARRAY_ELEM:
2881 {
2882 free(r->d.id.name);
2883 break;
2884 }
2885
2886 default:
2887 {
2888 // Do nothing.
2889 break;
2890 }
2891 }
2892}
2893
2894static void bc_lex_lineComment(BcLex *l)
2895{
2896 l->t.t = BC_LEX_WHITESPACE;
2897 while (l->i < l->len && l->buf[l->i++] != '\n');
2898 --l->i;
2899}
2900
2901static void bc_lex_whitespace(BcLex *l)
2902{
2903 char c;
2904 l->t.t = BC_LEX_WHITESPACE;
2905 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2906}
2907
2908static BcStatus bc_lex_number(BcLex *l, char start)
2909{
2910 const char *buf = l->buf + l->i;
2911 size_t len, hits = 0, bslashes = 0, i = 0, j;
2912 char c = buf[i];
2913 bool last_pt, pt = start == '.';
2914
2915 last_pt = pt;
2916 l->t.t = BC_LEX_NUMBER;
2917
2918 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2919 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2920 {
2921 if (c != '\\') {
2922 last_pt = c == '.';
2923 pt = pt || last_pt;
2924 }
2925 else {
2926 ++i;
2927 bslashes += 1;
2928 }
2929
2930 c = buf[++i];
2931 }
2932
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002933 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002934 if (len > BC_MAX_NUM)
2935 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002936
Denys Vlasenko7d628012018-12-04 21:46:47 +01002937 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002938 bc_vec_expand(&l->t.v, len + 1);
2939 bc_vec_push(&l->t.v, &start);
2940
2941 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2942
2943 c = buf[j];
2944
2945 // If we have hit a backslash, skip it. We don't have
2946 // to check for a newline because it's guaranteed.
2947 if (hits < bslashes && c == '\\') {
2948 ++hits;
2949 ++j;
2950 continue;
2951 }
2952
2953 bc_vec_push(&l->t.v, &c);
2954 }
2955
2956 bc_vec_pushByte(&l->t.v, '\0');
2957 l->i += i;
2958
2959 return BC_STATUS_SUCCESS;
2960}
2961
2962static BcStatus bc_lex_name(BcLex *l)
2963{
2964 size_t i = 0;
2965 const char *buf = l->buf + l->i - 1;
2966 char c = buf[i];
2967
2968 l->t.t = BC_LEX_NAME;
2969
2970 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2971
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002972 if (i > BC_MAX_STRING)
2973 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002974 bc_vec_string(&l->t.v, i, buf);
2975
2976 // Increment the index. We minus 1 because it has already been incremented.
2977 l->i += i - 1;
2978
2979 return BC_STATUS_SUCCESS;
2980}
2981
2982static void bc_lex_init(BcLex *l, BcLexNext next)
2983{
2984 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002985 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002986}
2987
2988static void bc_lex_free(BcLex *l)
2989{
2990 bc_vec_free(&l->t.v);
2991}
2992
2993static void bc_lex_file(BcLex *l, const char *file)
2994{
2995 l->line = 1;
2996 l->newline = false;
2997 l->f = file;
2998}
2999
3000static BcStatus bc_lex_next(BcLex *l)
3001{
3002 BcStatus s;
3003
3004 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003005 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06003006
3007 l->line += l->newline;
3008 l->t.t = BC_LEX_EOF;
3009
3010 l->newline = (l->i == l->len);
3011 if (l->newline) return BC_STATUS_SUCCESS;
3012
3013 // Loop until failure or we don't have whitespace. This
3014 // is so the parser doesn't get inundated with whitespace.
3015 do {
3016 s = l->next(l);
3017 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3018
3019 return s;
3020}
3021
3022static BcStatus bc_lex_text(BcLex *l, const char *text)
3023{
3024 l->buf = text;
3025 l->i = 0;
3026 l->len = strlen(text);
3027 l->t.t = l->t.last = BC_LEX_INVALID;
3028 return bc_lex_next(l);
3029}
3030
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003031#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003032static BcStatus bc_lex_identifier(BcLex *l)
3033{
3034 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003035 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06003036 const char *buf = l->buf + l->i - 1;
3037
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003038 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3039 const char *keyword8 = bc_lex_kws[i].name8;
3040 unsigned j = 0;
3041 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3042 j++;
3043 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06003044 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003045 if (keyword8[j] != '\0')
3046 continue;
3047 match:
3048 // buf starts with keyword bc_lex_kws[i]
3049 l->t.t = BC_LEX_KEY_1st_keyword + i;
3050 if ((1 << i) & POSIX_KWORD_MASK) {
3051 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
3052 if (s) return s;
3053 }
3054
3055 // We minus 1 because the index has already been incremented.
3056 l->i += j - 1;
3057 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003058 }
3059
3060 s = bc_lex_name(l);
3061 if (s) return s;
3062
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003063 if (l->t.v.len > 2)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003064 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06003065
3066 return s;
3067}
3068
3069static BcStatus bc_lex_string(BcLex *l)
3070{
3071 size_t len, nls = 0, i = l->i;
3072 char c;
3073
3074 l->t.t = BC_LEX_STR;
3075
3076 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3077
3078 if (c == '\0') {
3079 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003080 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003081 }
3082
3083 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003084 if (len > BC_MAX_STRING)
3085 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003086 bc_vec_string(&l->t.v, len, l->buf + l->i);
3087
3088 l->i = i + 1;
3089 l->line += nls;
3090
3091 return BC_STATUS_SUCCESS;
3092}
3093
3094static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3095{
3096 if (l->buf[l->i] == '=') {
3097 ++l->i;
3098 l->t.t = with;
3099 }
3100 else
3101 l->t.t = without;
3102}
3103
3104static BcStatus bc_lex_comment(BcLex *l)
3105{
3106 size_t i, nls = 0;
3107 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003108
3109 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003110 i = ++l->i;
3111 for (;;) {
3112 char c = buf[i];
3113 check_star:
3114 if (c == '*') {
3115 c = buf[++i];
3116 if (c == '/')
3117 break;
3118 goto check_star;
3119 }
3120 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003121 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003122 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003123 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003124 nls += (c == '\n');
3125 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003126 }
3127
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003128 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003129 l->line += nls;
3130
3131 return BC_STATUS_SUCCESS;
3132}
3133
3134static BcStatus bc_lex_token(BcLex *l)
3135{
3136 BcStatus s = BC_STATUS_SUCCESS;
3137 char c = l->buf[l->i++], c2;
3138
3139 // This is the workhorse of the lexer.
3140 switch (c) {
3141
3142 case '\0':
3143 case '\n':
3144 {
3145 l->newline = true;
3146 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3147 break;
3148 }
3149
3150 case '\t':
3151 case '\v':
3152 case '\f':
3153 case '\r':
3154 case ' ':
3155 {
3156 bc_lex_whitespace(l);
3157 break;
3158 }
3159
3160 case '!':
3161 {
3162 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3163
3164 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003165 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003166 if (s) return s;
3167 }
3168
3169 break;
3170 }
3171
3172 case '"':
3173 {
3174 s = bc_lex_string(l);
3175 break;
3176 }
3177
3178 case '#':
3179 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003180 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003181 if (s) return s;
3182
3183 bc_lex_lineComment(l);
3184
3185 break;
3186 }
3187
3188 case '%':
3189 {
3190 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3191 break;
3192 }
3193
3194 case '&':
3195 {
3196 c2 = l->buf[l->i];
3197 if (c2 == '&') {
3198
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003199 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003200 if (s) return s;
3201
3202 ++l->i;
3203 l->t.t = BC_LEX_OP_BOOL_AND;
3204 }
3205 else {
3206 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003207 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003208 }
3209
3210 break;
3211 }
3212
3213 case '(':
3214 case ')':
3215 {
3216 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3217 break;
3218 }
3219
3220 case '*':
3221 {
3222 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3223 break;
3224 }
3225
3226 case '+':
3227 {
3228 c2 = l->buf[l->i];
3229 if (c2 == '+') {
3230 ++l->i;
3231 l->t.t = BC_LEX_OP_INC;
3232 }
3233 else
3234 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3235 break;
3236 }
3237
3238 case ',':
3239 {
3240 l->t.t = BC_LEX_COMMA;
3241 break;
3242 }
3243
3244 case '-':
3245 {
3246 c2 = l->buf[l->i];
3247 if (c2 == '-') {
3248 ++l->i;
3249 l->t.t = BC_LEX_OP_DEC;
3250 }
3251 else
3252 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3253 break;
3254 }
3255
3256 case '.':
3257 {
3258 if (isdigit(l->buf[l->i]))
3259 s = bc_lex_number(l, c);
3260 else {
3261 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003262 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003263 }
3264 break;
3265 }
3266
3267 case '/':
3268 {
3269 c2 = l->buf[l->i];
3270 if (c2 == '*')
3271 s = bc_lex_comment(l);
3272 else
3273 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3274 break;
3275 }
3276
3277 case '0':
3278 case '1':
3279 case '2':
3280 case '3':
3281 case '4':
3282 case '5':
3283 case '6':
3284 case '7':
3285 case '8':
3286 case '9':
3287 case 'A':
3288 case 'B':
3289 case 'C':
3290 case 'D':
3291 case 'E':
3292 case 'F':
3293 {
3294 s = bc_lex_number(l, c);
3295 break;
3296 }
3297
3298 case ';':
3299 {
3300 l->t.t = BC_LEX_SCOLON;
3301 break;
3302 }
3303
3304 case '<':
3305 {
3306 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3307 break;
3308 }
3309
3310 case '=':
3311 {
3312 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3313 break;
3314 }
3315
3316 case '>':
3317 {
3318 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3319 break;
3320 }
3321
3322 case '[':
3323 case ']':
3324 {
3325 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3326 break;
3327 }
3328
3329 case '\\':
3330 {
3331 if (l->buf[l->i] == '\n') {
3332 l->t.t = BC_LEX_WHITESPACE;
3333 ++l->i;
3334 }
3335 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003336 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003337 break;
3338 }
3339
3340 case '^':
3341 {
3342 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3343 break;
3344 }
3345
3346 case 'a':
3347 case 'b':
3348 case 'c':
3349 case 'd':
3350 case 'e':
3351 case 'f':
3352 case 'g':
3353 case 'h':
3354 case 'i':
3355 case 'j':
3356 case 'k':
3357 case 'l':
3358 case 'm':
3359 case 'n':
3360 case 'o':
3361 case 'p':
3362 case 'q':
3363 case 'r':
3364 case 's':
3365 case 't':
3366 case 'u':
3367 case 'v':
3368 case 'w':
3369 case 'x':
3370 case 'y':
3371 case 'z':
3372 {
3373 s = bc_lex_identifier(l);
3374 break;
3375 }
3376
3377 case '{':
3378 case '}':
3379 {
3380 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3381 break;
3382 }
3383
3384 case '|':
3385 {
3386 c2 = l->buf[l->i];
3387
3388 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003389 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003390 if (s) return s;
3391
3392 ++l->i;
3393 l->t.t = BC_LEX_OP_BOOL_OR;
3394 }
3395 else {
3396 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003397 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003398 }
3399
3400 break;
3401 }
3402
3403 default:
3404 {
3405 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003406 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003407 break;
3408 }
3409 }
3410
3411 return s;
3412}
3413#endif // ENABLE_BC
3414
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003415#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003416static BcStatus dc_lex_register(BcLex *l)
3417{
3418 BcStatus s = BC_STATUS_SUCCESS;
3419
3420 if (isspace(l->buf[l->i - 1])) {
3421 bc_lex_whitespace(l);
3422 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003423 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003424 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003425 else
3426 s = bc_lex_name(l);
3427 }
3428 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003429 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003430 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3431 bc_vec_pushByte(&l->t.v, '\0');
3432 l->t.t = BC_LEX_NAME;
3433 }
3434
3435 return s;
3436}
3437
3438static BcStatus dc_lex_string(BcLex *l)
3439{
3440 size_t depth = 1, nls = 0, i = l->i;
3441 char c;
3442
3443 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003444 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003445
3446 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3447
3448 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3449 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3450 nls += (c == '\n');
3451
3452 if (depth) bc_vec_push(&l->t.v, &c);
3453 }
3454
3455 if (c == '\0') {
3456 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003457 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003458 }
3459
3460 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003461 if (i - l->i > BC_MAX_STRING)
3462 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003463
3464 l->i = i;
3465 l->line += nls;
3466
3467 return BC_STATUS_SUCCESS;
3468}
3469
3470static BcStatus dc_lex_token(BcLex *l)
3471{
3472 BcStatus s = BC_STATUS_SUCCESS;
3473 char c = l->buf[l->i++], c2;
3474 size_t i;
3475
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003476 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3477 if (l->t.last == dc_lex_regs[i])
3478 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003479 }
3480
3481 if (c >= '%' && c <= '~' &&
3482 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3483 {
3484 return s;
3485 }
3486
3487 // This is the workhorse of the lexer.
3488 switch (c) {
3489
3490 case '\0':
3491 {
3492 l->t.t = BC_LEX_EOF;
3493 break;
3494 }
3495
3496 case '\n':
3497 case '\t':
3498 case '\v':
3499 case '\f':
3500 case '\r':
3501 case ' ':
3502 {
3503 l->newline = (c == '\n');
3504 bc_lex_whitespace(l);
3505 break;
3506 }
3507
3508 case '!':
3509 {
3510 c2 = l->buf[l->i];
3511
3512 if (c2 == '=')
3513 l->t.t = BC_LEX_OP_REL_NE;
3514 else if (c2 == '<')
3515 l->t.t = BC_LEX_OP_REL_LE;
3516 else if (c2 == '>')
3517 l->t.t = BC_LEX_OP_REL_GE;
3518 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003519 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003520
3521 ++l->i;
3522 break;
3523 }
3524
3525 case '#':
3526 {
3527 bc_lex_lineComment(l);
3528 break;
3529 }
3530
3531 case '.':
3532 {
3533 if (isdigit(l->buf[l->i]))
3534 s = bc_lex_number(l, c);
3535 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003536 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003537 break;
3538 }
3539
3540 case '0':
3541 case '1':
3542 case '2':
3543 case '3':
3544 case '4':
3545 case '5':
3546 case '6':
3547 case '7':
3548 case '8':
3549 case '9':
3550 case 'A':
3551 case 'B':
3552 case 'C':
3553 case 'D':
3554 case 'E':
3555 case 'F':
3556 {
3557 s = bc_lex_number(l, c);
3558 break;
3559 }
3560
3561 case '[':
3562 {
3563 s = dc_lex_string(l);
3564 break;
3565 }
3566
3567 default:
3568 {
3569 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003570 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003571 break;
3572 }
3573 }
3574
3575 return s;
3576}
3577#endif // ENABLE_DC
3578
3579static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3580{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003581 bc_program_addFunc(name, idx);
3582 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003583}
3584
3585static void bc_parse_pushName(BcParse *p, char *name)
3586{
3587 size_t i = 0, len = strlen(name);
3588
3589 for (; i < len; ++i) bc_parse_push(p, name[i]);
3590 bc_parse_push(p, BC_PARSE_STREND);
3591
3592 free(name);
3593}
3594
3595static void bc_parse_pushIndex(BcParse *p, size_t idx)
3596{
3597 unsigned char amt, i, nums[sizeof(size_t)];
3598
3599 for (amt = 0; idx; ++amt) {
3600 nums[amt] = (char) idx;
3601 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3602 }
3603
3604 bc_parse_push(p, amt);
3605 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3606}
3607
3608static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3609{
3610 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003611 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003612
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003613 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003614
3615 bc_parse_push(p, BC_INST_NUM);
3616 bc_parse_pushIndex(p, idx);
3617
3618 ++(*nexs);
3619 (*prev) = BC_INST_NUM;
3620}
3621
3622static BcStatus bc_parse_text(BcParse *p, const char *text)
3623{
3624 BcStatus s;
3625
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003626 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003627
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003628 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003629 p->l.t.t = BC_LEX_INVALID;
3630 s = p->parse(p);
3631 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003632 if (!BC_PARSE_CAN_EXEC(p))
3633 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003634 }
3635
3636 return bc_lex_text(&p->l, text);
3637}
3638
Denys Vlasenkod38af482018-12-04 19:11:02 +01003639// Called when bc/dc_parse_parse() detects a failure,
3640// resets parsing structures.
3641static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003642{
3643 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003644 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003645 bc_vec_pop_all(&p->func->code);
3646 bc_vec_pop_all(&p->func->autos);
3647 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003648
3649 bc_parse_updateFunc(p, BC_PROG_MAIN);
3650 }
3651
3652 p->l.i = p->l.len;
3653 p->l.t.t = BC_LEX_EOF;
3654 p->auto_part = (p->nbraces = 0);
3655
3656 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003657 bc_vec_pop_all(&p->exits);
3658 bc_vec_pop_all(&p->conds);
3659 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003660
Denys Vlasenkod38af482018-12-04 19:11:02 +01003661 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003662}
3663
3664static void bc_parse_free(BcParse *p)
3665{
3666 bc_vec_free(&p->flags);
3667 bc_vec_free(&p->exits);
3668 bc_vec_free(&p->conds);
3669 bc_vec_free(&p->ops);
3670 bc_lex_free(&p->l);
3671}
3672
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003673static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003674 BcParseParse parse, BcLexNext next)
3675{
3676 memset(p, 0, sizeof(BcParse));
3677
3678 bc_lex_init(&p->l, next);
3679 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3680 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3681 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3682 bc_vec_pushByte(&p->flags, 0);
3683 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3684
3685 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003686 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003687 bc_parse_updateFunc(p, func);
3688}
3689
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003690#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003691static BcStatus bc_parse_else(BcParse *p);
3692static BcStatus bc_parse_stmt(BcParse *p);
3693
3694static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3695 size_t *nexprs, bool next)
3696{
3697 BcStatus s = BC_STATUS_SUCCESS;
3698 BcLexType t;
3699 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3700 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3701
3702 while (p->ops.len > start) {
3703
3704 t = BC_PARSE_TOP_OP(p);
3705 if (t == BC_LEX_LPAREN) break;
3706
3707 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3708 if (l >= r && (l != r || !left)) break;
3709
3710 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3711 bc_vec_pop(&p->ops);
3712 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3713 }
3714
3715 bc_vec_push(&p->ops, &type);
3716 if (next) s = bc_lex_next(&p->l);
3717
3718 return s;
3719}
3720
3721static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3722{
3723 BcLexType top;
3724
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003725 if (p->ops.len <= ops_bgn)
3726 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003727 top = BC_PARSE_TOP_OP(p);
3728
3729 while (top != BC_LEX_LPAREN) {
3730
3731 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3732
3733 bc_vec_pop(&p->ops);
3734 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3735
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003736 if (p->ops.len <= ops_bgn)
3737 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003738 top = BC_PARSE_TOP_OP(p);
3739 }
3740
3741 bc_vec_pop(&p->ops);
3742
3743 return bc_lex_next(&p->l);
3744}
3745
3746static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3747{
3748 BcStatus s;
3749 bool comma = false;
3750 size_t nparams;
3751
3752 s = bc_lex_next(&p->l);
3753 if (s) return s;
3754
3755 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3756
3757 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3758 s = bc_parse_expr(p, flags, bc_parse_next_param);
3759 if (s) return s;
3760
3761 comma = p->l.t.t == BC_LEX_COMMA;
3762 if (comma) {
3763 s = bc_lex_next(&p->l);
3764 if (s) return s;
3765 }
3766 }
3767
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003768 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003769 bc_parse_push(p, BC_INST_CALL);
3770 bc_parse_pushIndex(p, nparams);
3771
3772 return BC_STATUS_SUCCESS;
3773}
3774
3775static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3776{
3777 BcStatus s;
3778 BcId entry, *entry_ptr;
3779 size_t idx;
3780
3781 entry.name = name;
3782
3783 s = bc_parse_params(p, flags);
3784 if (s) goto err;
3785
3786 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003787 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003788 goto err;
3789 }
3790
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003791 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003792
3793 if (idx == BC_VEC_INVALID_IDX) {
3794 name = xstrdup(entry.name);
3795 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003796 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003797 free(entry.name);
3798 }
3799 else
3800 free(name);
3801
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003802 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003803 bc_parse_pushIndex(p, entry_ptr->idx);
3804
3805 return bc_lex_next(&p->l);
3806
3807err:
3808 free(name);
3809 return s;
3810}
3811
3812static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3813{
3814 BcStatus s;
3815 char *name;
3816
3817 name = xstrdup(p->l.t.v.v);
3818 s = bc_lex_next(&p->l);
3819 if (s) goto err;
3820
3821 if (p->l.t.t == BC_LEX_LBRACKET) {
3822
3823 s = bc_lex_next(&p->l);
3824 if (s) goto err;
3825
3826 if (p->l.t.t == BC_LEX_RBRACKET) {
3827
3828 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003829 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003830 goto err;
3831 }
3832
3833 *type = BC_INST_ARRAY;
3834 }
3835 else {
3836
3837 *type = BC_INST_ARRAY_ELEM;
3838
3839 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3840 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3841 if (s) goto err;
3842 }
3843
3844 s = bc_lex_next(&p->l);
3845 if (s) goto err;
3846 bc_parse_push(p, *type);
3847 bc_parse_pushName(p, name);
3848 }
3849 else if (p->l.t.t == BC_LEX_LPAREN) {
3850
3851 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003852 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003853 goto err;
3854 }
3855
3856 *type = BC_INST_CALL;
3857 s = bc_parse_call(p, name, flags);
3858 }
3859 else {
3860 *type = BC_INST_VAR;
3861 bc_parse_push(p, BC_INST_VAR);
3862 bc_parse_pushName(p, name);
3863 }
3864
3865 return s;
3866
3867err:
3868 free(name);
3869 return s;
3870}
3871
3872static BcStatus bc_parse_read(BcParse *p)
3873{
3874 BcStatus s;
3875
3876 s = bc_lex_next(&p->l);
3877 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003878 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003879
3880 s = bc_lex_next(&p->l);
3881 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003882 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003883
3884 bc_parse_push(p, BC_INST_READ);
3885
3886 return bc_lex_next(&p->l);
3887}
3888
3889static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3890 BcInst *prev)
3891{
3892 BcStatus s;
3893
3894 s = bc_lex_next(&p->l);
3895 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003896 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003897
3898 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3899
3900 s = bc_lex_next(&p->l);
3901 if (s) return s;
3902
3903 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3904 if (s) return s;
3905
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003906 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003907
3908 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3909 bc_parse_push(p, *prev);
3910
3911 return bc_lex_next(&p->l);
3912}
3913
3914static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3915{
3916 BcStatus s;
3917
3918 s = bc_lex_next(&p->l);
3919 if (s) return s;
3920
3921 if (p->l.t.t != BC_LEX_LPAREN) {
3922 *type = BC_INST_SCALE;
3923 bc_parse_push(p, BC_INST_SCALE);
3924 return BC_STATUS_SUCCESS;
3925 }
3926
3927 *type = BC_INST_SCALE_FUNC;
3928 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3929
3930 s = bc_lex_next(&p->l);
3931 if (s) return s;
3932
3933 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3934 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003935 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003936 bc_parse_push(p, BC_INST_SCALE_FUNC);
3937
3938 return bc_lex_next(&p->l);
3939}
3940
3941static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3942 size_t *nexprs, uint8_t flags)
3943{
3944 BcStatus s;
3945 BcLexType type;
3946 char inst;
3947 BcInst etype = *prev;
3948
3949 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3950 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3951 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3952 {
3953 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3954 bc_parse_push(p, inst);
3955 s = bc_lex_next(&p->l);
3956 }
3957 else {
3958
3959 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3960 *paren_expr = true;
3961
3962 s = bc_lex_next(&p->l);
3963 if (s) return s;
3964 type = p->l.t.t;
3965
3966 // Because we parse the next part of the expression
3967 // right here, we need to increment this.
3968 *nexprs = *nexprs + 1;
3969
3970 switch (type) {
3971
3972 case BC_LEX_NAME:
3973 {
3974 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3975 break;
3976 }
3977
3978 case BC_LEX_KEY_IBASE:
3979 case BC_LEX_KEY_LAST:
3980 case BC_LEX_KEY_OBASE:
3981 {
3982 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3983 s = bc_lex_next(&p->l);
3984 break;
3985 }
3986
3987 case BC_LEX_KEY_SCALE:
3988 {
3989 s = bc_lex_next(&p->l);
3990 if (s) return s;
3991 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003992 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003993 else
3994 bc_parse_push(p, BC_INST_SCALE);
3995 break;
3996 }
3997
3998 default:
3999 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004000 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004001 break;
4002 }
4003 }
4004
4005 if (!s) bc_parse_push(p, inst);
4006 }
4007
4008 return s;
4009}
4010
4011static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4012 bool rparen, size_t *nexprs)
4013{
4014 BcStatus s;
4015 BcLexType type;
4016 BcInst etype = *prev;
4017
4018 s = bc_lex_next(&p->l);
4019 if (s) return s;
4020
4021 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4022 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4023 BC_LEX_OP_MINUS :
4024 BC_LEX_NEG;
4025 *prev = BC_PARSE_TOKEN_INST(type);
4026
4027 // We can just push onto the op stack because this is the largest
4028 // precedence operator that gets pushed. Inc/dec does not.
4029 if (type != BC_LEX_OP_MINUS)
4030 bc_vec_push(&p->ops, &type);
4031 else
4032 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4033
4034 return s;
4035}
4036
4037static BcStatus bc_parse_string(BcParse *p, char inst)
4038{
4039 char *str = xstrdup(p->l.t.v.v);
4040
4041 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004042 bc_parse_pushIndex(p, G.prog.strs.len);
4043 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004044 bc_parse_push(p, inst);
4045
4046 return bc_lex_next(&p->l);
4047}
4048
4049static BcStatus bc_parse_print(BcParse *p)
4050{
4051 BcStatus s;
4052 BcLexType type;
4053 bool comma = false;
4054
4055 s = bc_lex_next(&p->l);
4056 if (s) return s;
4057
4058 type = p->l.t.t;
4059
4060 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004061 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06004062
4063 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4064
4065 if (type == BC_LEX_STR)
4066 s = bc_parse_string(p, BC_INST_PRINT_POP);
4067 else {
4068 s = bc_parse_expr(p, 0, bc_parse_next_print);
4069 if (s) return s;
4070 bc_parse_push(p, BC_INST_PRINT_POP);
4071 }
4072
4073 if (s) return s;
4074
4075 comma = p->l.t.t == BC_LEX_COMMA;
4076 if (comma) s = bc_lex_next(&p->l);
4077 type = p->l.t.t;
4078 }
4079
4080 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004081 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004082
4083 return bc_lex_next(&p->l);
4084}
4085
4086static BcStatus bc_parse_return(BcParse *p)
4087{
4088 BcStatus s;
4089 BcLexType t;
4090 bool paren;
4091
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004092 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004093
4094 s = bc_lex_next(&p->l);
4095 if (s) return s;
4096
4097 t = p->l.t.t;
4098 paren = t == BC_LEX_LPAREN;
4099
4100 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4101 bc_parse_push(p, BC_INST_RET0);
4102 else {
4103
4104 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4105 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4106 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004107
4108 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004109 bc_parse_push(p, BC_INST_RET0);
4110 s = bc_lex_next(&p->l);
4111 if (s) return s;
4112 }
4113
4114 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004115 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004116 if (s) return s;
4117 }
4118
4119 bc_parse_push(p, BC_INST_RET);
4120 }
4121
4122 return s;
4123}
4124
4125static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4126{
4127 BcStatus s = BC_STATUS_SUCCESS;
4128
4129 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004130 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004131
4132 if (brace) {
4133
4134 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004135 if (!p->nbraces) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004136 --p->nbraces;
4137 s = bc_lex_next(&p->l);
4138 if (s) return s;
4139 }
4140 else
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004141 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004142 }
4143
4144 if (BC_PARSE_IF(p)) {
4145
4146 uint8_t *flag_ptr;
4147
4148 while (p->l.t.t == BC_LEX_NLINE) {
4149 s = bc_lex_next(&p->l);
4150 if (s) return s;
4151 }
4152
4153 bc_vec_pop(&p->flags);
4154
4155 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4156 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4157
4158 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4159 }
4160 else if (BC_PARSE_ELSE(p)) {
4161
4162 BcInstPtr *ip;
4163 size_t *label;
4164
4165 bc_vec_pop(&p->flags);
4166
4167 ip = bc_vec_top(&p->exits);
4168 label = bc_vec_item(&p->func->labels, ip->idx);
4169 *label = p->func->code.len;
4170
4171 bc_vec_pop(&p->exits);
4172 }
4173 else if (BC_PARSE_FUNC_INNER(p)) {
4174 bc_parse_push(p, BC_INST_RET0);
4175 bc_parse_updateFunc(p, BC_PROG_MAIN);
4176 bc_vec_pop(&p->flags);
4177 }
4178 else {
4179
4180 BcInstPtr *ip = bc_vec_top(&p->exits);
4181 size_t *label = bc_vec_top(&p->conds);
4182
4183 bc_parse_push(p, BC_INST_JUMP);
4184 bc_parse_pushIndex(p, *label);
4185
4186 label = bc_vec_item(&p->func->labels, ip->idx);
4187 *label = p->func->code.len;
4188
4189 bc_vec_pop(&p->flags);
4190 bc_vec_pop(&p->exits);
4191 bc_vec_pop(&p->conds);
4192 }
4193
4194 return s;
4195}
4196
4197static void bc_parse_startBody(BcParse *p, uint8_t flags)
4198{
4199 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4200 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4201 flags |= BC_PARSE_FLAG_BODY;
4202 bc_vec_push(&p->flags, &flags);
4203}
4204
4205static void bc_parse_noElse(BcParse *p)
4206{
4207 BcInstPtr *ip;
4208 size_t *label;
4209 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4210
4211 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4212
4213 ip = bc_vec_top(&p->exits);
4214 label = bc_vec_item(&p->func->labels, ip->idx);
4215 *label = p->func->code.len;
4216
4217 bc_vec_pop(&p->exits);
4218}
4219
4220static BcStatus bc_parse_if(BcParse *p)
4221{
4222 BcStatus s;
4223 BcInstPtr ip;
4224
4225 s = bc_lex_next(&p->l);
4226 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004227 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004228
4229 s = bc_lex_next(&p->l);
4230 if (s) return s;
4231 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4232 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004233 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004234
4235 s = bc_lex_next(&p->l);
4236 if (s) return s;
4237 bc_parse_push(p, BC_INST_JUMP_ZERO);
4238
4239 ip.idx = p->func->labels.len;
4240 ip.func = ip.len = 0;
4241
4242 bc_parse_pushIndex(p, ip.idx);
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4246
4247 return BC_STATUS_SUCCESS;
4248}
4249
4250static BcStatus bc_parse_else(BcParse *p)
4251{
4252 BcInstPtr ip;
4253
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004254 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004255
4256 ip.idx = p->func->labels.len;
4257 ip.func = ip.len = 0;
4258
4259 bc_parse_push(p, BC_INST_JUMP);
4260 bc_parse_pushIndex(p, ip.idx);
4261
4262 bc_parse_noElse(p);
4263
4264 bc_vec_push(&p->exits, &ip);
4265 bc_vec_push(&p->func->labels, &ip.idx);
4266 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4267
4268 return bc_lex_next(&p->l);
4269}
4270
4271static BcStatus bc_parse_while(BcParse *p)
4272{
4273 BcStatus s;
4274 BcInstPtr ip;
4275
4276 s = bc_lex_next(&p->l);
4277 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004278 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004279 s = bc_lex_next(&p->l);
4280 if (s) return s;
4281
4282 ip.idx = p->func->labels.len;
4283
4284 bc_vec_push(&p->func->labels, &p->func->code.len);
4285 bc_vec_push(&p->conds, &ip.idx);
4286
4287 ip.idx = p->func->labels.len;
4288 ip.func = 1;
4289 ip.len = 0;
4290
4291 bc_vec_push(&p->exits, &ip);
4292 bc_vec_push(&p->func->labels, &ip.idx);
4293
4294 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4295 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004296 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004297 s = bc_lex_next(&p->l);
4298 if (s) return s;
4299
4300 bc_parse_push(p, BC_INST_JUMP_ZERO);
4301 bc_parse_pushIndex(p, ip.idx);
4302 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4303
4304 return BC_STATUS_SUCCESS;
4305}
4306
4307static BcStatus bc_parse_for(BcParse *p)
4308{
4309 BcStatus s;
4310 BcInstPtr ip;
4311 size_t cond_idx, exit_idx, body_idx, update_idx;
4312
4313 s = bc_lex_next(&p->l);
4314 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004315 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004316 s = bc_lex_next(&p->l);
4317 if (s) return s;
4318
4319 if (p->l.t.t != BC_LEX_SCOLON)
4320 s = bc_parse_expr(p, 0, bc_parse_next_for);
4321 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004322 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004323
4324 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004325 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004326 s = bc_lex_next(&p->l);
4327 if (s) return s;
4328
4329 cond_idx = p->func->labels.len;
4330 update_idx = cond_idx + 1;
4331 body_idx = update_idx + 1;
4332 exit_idx = body_idx + 1;
4333
4334 bc_vec_push(&p->func->labels, &p->func->code.len);
4335
4336 if (p->l.t.t != BC_LEX_SCOLON)
4337 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4338 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004339 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004340
4341 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004342 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004343
4344 s = bc_lex_next(&p->l);
4345 if (s) return s;
4346
4347 bc_parse_push(p, BC_INST_JUMP_ZERO);
4348 bc_parse_pushIndex(p, exit_idx);
4349 bc_parse_push(p, BC_INST_JUMP);
4350 bc_parse_pushIndex(p, body_idx);
4351
4352 ip.idx = p->func->labels.len;
4353
4354 bc_vec_push(&p->conds, &update_idx);
4355 bc_vec_push(&p->func->labels, &p->func->code.len);
4356
4357 if (p->l.t.t != BC_LEX_RPAREN)
4358 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4359 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004360 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004361
4362 if (s) return s;
4363
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004364 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004365 bc_parse_push(p, BC_INST_JUMP);
4366 bc_parse_pushIndex(p, cond_idx);
4367 bc_vec_push(&p->func->labels, &p->func->code.len);
4368
4369 ip.idx = exit_idx;
4370 ip.func = 1;
4371 ip.len = 0;
4372
4373 bc_vec_push(&p->exits, &ip);
4374 bc_vec_push(&p->func->labels, &ip.idx);
4375 bc_lex_next(&p->l);
4376 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4377
4378 return BC_STATUS_SUCCESS;
4379}
4380
4381static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4382{
4383 BcStatus s;
4384 size_t i;
4385 BcInstPtr *ip;
4386
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004387 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004388
4389 if (type == BC_LEX_KEY_BREAK) {
4390
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004391 if (p->exits.len == 0) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004392
4393 i = p->exits.len - 1;
4394 ip = bc_vec_item(&p->exits, i);
4395
4396 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004397 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004398
4399 i = ip->idx;
4400 }
4401 else
4402 i = *((size_t *) bc_vec_top(&p->conds));
4403
4404 bc_parse_push(p, BC_INST_JUMP);
4405 bc_parse_pushIndex(p, i);
4406
4407 s = bc_lex_next(&p->l);
4408 if (s) return s;
4409
4410 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004411 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004412
4413 return bc_lex_next(&p->l);
4414}
4415
4416static BcStatus bc_parse_func(BcParse *p)
4417{
4418 BcStatus s;
4419 bool var, comma = false;
4420 uint8_t flags;
4421 char *name;
4422
4423 s = bc_lex_next(&p->l);
4424 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004425 if (p->l.t.t != BC_LEX_NAME)
4426 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004427
4428 name = xstrdup(p->l.t.v.v);
4429 bc_parse_addFunc(p, name, &p->fidx);
4430
4431 s = bc_lex_next(&p->l);
4432 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004433 if (p->l.t.t != BC_LEX_LPAREN)
4434 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004435 s = bc_lex_next(&p->l);
4436 if (s) return s;
4437
4438 while (p->l.t.t != BC_LEX_RPAREN) {
4439
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004440 if (p->l.t.t != BC_LEX_NAME)
4441 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004442
4443 ++p->func->nparams;
4444
4445 name = xstrdup(p->l.t.v.v);
4446 s = bc_lex_next(&p->l);
4447 if (s) goto err;
4448
4449 var = p->l.t.t != BC_LEX_LBRACKET;
4450
4451 if (!var) {
4452
4453 s = bc_lex_next(&p->l);
4454 if (s) goto err;
4455
4456 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004457 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004458 goto err;
4459 }
4460
4461 s = bc_lex_next(&p->l);
4462 if (s) goto err;
4463 }
4464
4465 comma = p->l.t.t == BC_LEX_COMMA;
4466 if (comma) {
4467 s = bc_lex_next(&p->l);
4468 if (s) goto err;
4469 }
4470
4471 s = bc_func_insert(p->func, name, var);
4472 if (s) goto err;
4473 }
4474
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004475 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004476
4477 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4478 bc_parse_startBody(p, flags);
4479
4480 s = bc_lex_next(&p->l);
4481 if (s) return s;
4482
4483 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004484 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
Gavin Howard01055ba2018-11-03 11:00:21 -06004485
4486 return s;
4487
4488err:
4489 free(name);
4490 return s;
4491}
4492
4493static BcStatus bc_parse_auto(BcParse *p)
4494{
4495 BcStatus s;
4496 bool comma, var, one;
4497 char *name;
4498
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004499 if (!p->auto_part) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004500 s = bc_lex_next(&p->l);
4501 if (s) return s;
4502
4503 p->auto_part = comma = false;
4504 one = p->l.t.t == BC_LEX_NAME;
4505
4506 while (p->l.t.t == BC_LEX_NAME) {
4507
4508 name = xstrdup(p->l.t.v.v);
4509 s = bc_lex_next(&p->l);
4510 if (s) goto err;
4511
4512 var = p->l.t.t != BC_LEX_LBRACKET;
4513 if (!var) {
4514
4515 s = bc_lex_next(&p->l);
4516 if (s) goto err;
4517
4518 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004519 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004520 goto err;
4521 }
4522
4523 s = bc_lex_next(&p->l);
4524 if (s) goto err;
4525 }
4526
4527 comma = p->l.t.t == BC_LEX_COMMA;
4528 if (comma) {
4529 s = bc_lex_next(&p->l);
4530 if (s) goto err;
4531 }
4532
4533 s = bc_func_insert(p->func, name, var);
4534 if (s) goto err;
4535 }
4536
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004537 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004538 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004539
4540 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004541 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004542
4543 return bc_lex_next(&p->l);
4544
4545err:
4546 free(name);
4547 return s;
4548}
4549
4550static BcStatus bc_parse_body(BcParse *p, bool brace)
4551{
4552 BcStatus s = BC_STATUS_SUCCESS;
4553 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4554
4555 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4556
4557 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4558
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004559 if (!brace) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004560 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4561
4562 if (!p->auto_part) {
4563 s = bc_parse_auto(p);
4564 if (s) return s;
4565 }
4566
4567 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4568 }
4569 else {
4570 s = bc_parse_stmt(p);
4571 if (!s && !brace) s = bc_parse_endBody(p, false);
4572 }
4573
4574 return s;
4575}
4576
4577static BcStatus bc_parse_stmt(BcParse *p)
4578{
4579 BcStatus s = BC_STATUS_SUCCESS;
4580
4581 switch (p->l.t.t) {
4582
4583 case BC_LEX_NLINE:
4584 {
4585 return bc_lex_next(&p->l);
4586 }
4587
4588 case BC_LEX_KEY_ELSE:
4589 {
4590 p->auto_part = false;
4591 break;
4592 }
4593
4594 case BC_LEX_LBRACE:
4595 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004596 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004597
4598 ++p->nbraces;
4599 s = bc_lex_next(&p->l);
4600 if (s) return s;
4601
4602 return bc_parse_body(p, true);
4603 }
4604
4605 case BC_LEX_KEY_AUTO:
4606 {
4607 return bc_parse_auto(p);
4608 }
4609
4610 default:
4611 {
4612 p->auto_part = false;
4613
4614 if (BC_PARSE_IF_END(p)) {
4615 bc_parse_noElse(p);
4616 return BC_STATUS_SUCCESS;
4617 }
4618 else if (BC_PARSE_BODY(p))
4619 return bc_parse_body(p, false);
4620
4621 break;
4622 }
4623 }
4624
4625 switch (p->l.t.t) {
4626
4627 case BC_LEX_OP_INC:
4628 case BC_LEX_OP_DEC:
4629 case BC_LEX_OP_MINUS:
4630 case BC_LEX_OP_BOOL_NOT:
4631 case BC_LEX_LPAREN:
4632 case BC_LEX_NAME:
4633 case BC_LEX_NUMBER:
4634 case BC_LEX_KEY_IBASE:
4635 case BC_LEX_KEY_LAST:
4636 case BC_LEX_KEY_LENGTH:
4637 case BC_LEX_KEY_OBASE:
4638 case BC_LEX_KEY_READ:
4639 case BC_LEX_KEY_SCALE:
4640 case BC_LEX_KEY_SQRT:
4641 {
4642 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4643 break;
4644 }
4645
4646 case BC_LEX_KEY_ELSE:
4647 {
4648 s = bc_parse_else(p);
4649 break;
4650 }
4651
4652 case BC_LEX_SCOLON:
4653 {
4654 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4655 break;
4656 }
4657
4658 case BC_LEX_RBRACE:
4659 {
4660 s = bc_parse_endBody(p, true);
4661 break;
4662 }
4663
4664 case BC_LEX_STR:
4665 {
4666 s = bc_parse_string(p, BC_INST_PRINT_STR);
4667 break;
4668 }
4669
4670 case BC_LEX_KEY_BREAK:
4671 case BC_LEX_KEY_CONTINUE:
4672 {
4673 s = bc_parse_loopExit(p, p->l.t.t);
4674 break;
4675 }
4676
4677 case BC_LEX_KEY_FOR:
4678 {
4679 s = bc_parse_for(p);
4680 break;
4681 }
4682
4683 case BC_LEX_KEY_HALT:
4684 {
4685 bc_parse_push(p, BC_INST_HALT);
4686 s = bc_lex_next(&p->l);
4687 break;
4688 }
4689
4690 case BC_LEX_KEY_IF:
4691 {
4692 s = bc_parse_if(p);
4693 break;
4694 }
4695
4696 case BC_LEX_KEY_LIMITS:
4697 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004698 // "limits" is a compile-time command,
4699 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004700 s = bc_lex_next(&p->l);
4701 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004702 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4703 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4704 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4705 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4706 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4707 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4708 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4709 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004710 break;
4711 }
4712
4713 case BC_LEX_KEY_PRINT:
4714 {
4715 s = bc_parse_print(p);
4716 break;
4717 }
4718
4719 case BC_LEX_KEY_QUIT:
4720 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004721 // "quit" is a compile-time command. For example,
4722 // "if (0 == 1) quit" terminates when parsing the statement,
4723 // not when it is executed
4724 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004725 }
4726
4727 case BC_LEX_KEY_RETURN:
4728 {
4729 s = bc_parse_return(p);
4730 break;
4731 }
4732
4733 case BC_LEX_KEY_WHILE:
4734 {
4735 s = bc_parse_while(p);
4736 break;
4737 }
4738
4739 default:
4740 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004741 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004742 break;
4743 }
4744 }
4745
4746 return s;
4747}
4748
4749static BcStatus bc_parse_parse(BcParse *p)
4750{
4751 BcStatus s;
4752
4753 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004754 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06004755 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004756 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004757 s = bc_parse_func(p);
4758 }
4759 else
4760 s = bc_parse_stmt(p);
4761
Denys Vlasenkod38af482018-12-04 19:11:02 +01004762 if (s || G_interrupt) {
4763 bc_parse_reset(p);
4764 s = BC_STATUS_FAILURE;
4765 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004766
4767 return s;
4768}
4769
4770static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4771{
4772 BcStatus s = BC_STATUS_SUCCESS;
4773 BcInst prev = BC_INST_PRINT;
4774 BcLexType top, t = p->l.t.t;
4775 size_t nexprs = 0, ops_bgn = p->ops.len;
4776 uint32_t i, nparens, nrelops;
4777 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4778
4779 paren_first = p->l.t.t == BC_LEX_LPAREN;
4780 nparens = nrelops = 0;
4781 paren_expr = rprn = done = get_token = assign = false;
4782 bin_last = true;
4783
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004784 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004785 switch (t) {
4786
4787 case BC_LEX_OP_INC:
4788 case BC_LEX_OP_DEC:
4789 {
4790 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4791 rprn = get_token = bin_last = false;
4792 break;
4793 }
4794
4795 case BC_LEX_OP_MINUS:
4796 {
4797 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4798 rprn = get_token = false;
4799 bin_last = prev == BC_INST_MINUS;
4800 break;
4801 }
4802
4803 case BC_LEX_OP_ASSIGN_POWER:
4804 case BC_LEX_OP_ASSIGN_MULTIPLY:
4805 case BC_LEX_OP_ASSIGN_DIVIDE:
4806 case BC_LEX_OP_ASSIGN_MODULUS:
4807 case BC_LEX_OP_ASSIGN_PLUS:
4808 case BC_LEX_OP_ASSIGN_MINUS:
4809 case BC_LEX_OP_ASSIGN:
4810 {
4811 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4812 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4813 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4814 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004815 s = bc_error("bad assignment:"
4816 " left side must be scale,"
4817 " ibase, obase, last, var,"
4818 " or array element"
4819 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004820 break;
4821 }
4822 }
4823 // Fallthrough.
4824 case BC_LEX_OP_POWER:
4825 case BC_LEX_OP_MULTIPLY:
4826 case BC_LEX_OP_DIVIDE:
4827 case BC_LEX_OP_MODULUS:
4828 case BC_LEX_OP_PLUS:
4829 case BC_LEX_OP_REL_EQ:
4830 case BC_LEX_OP_REL_LE:
4831 case BC_LEX_OP_REL_GE:
4832 case BC_LEX_OP_REL_NE:
4833 case BC_LEX_OP_REL_LT:
4834 case BC_LEX_OP_REL_GT:
4835 case BC_LEX_OP_BOOL_NOT:
4836 case BC_LEX_OP_BOOL_OR:
4837 case BC_LEX_OP_BOOL_AND:
4838 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004839 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4840 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4841 ) {
4842 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004843 }
4844
4845 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4846 prev = BC_PARSE_TOKEN_INST(t);
4847 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4848 rprn = get_token = false;
4849 bin_last = t != BC_LEX_OP_BOOL_NOT;
4850
4851 break;
4852 }
4853
4854 case BC_LEX_LPAREN:
4855 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004856 if (BC_PARSE_LEAF(prev, rprn))
4857 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004858 ++nparens;
4859 paren_expr = rprn = bin_last = false;
4860 get_token = true;
4861 bc_vec_push(&p->ops, &t);
4862
4863 break;
4864 }
4865
4866 case BC_LEX_RPAREN:
4867 {
4868 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004869 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004870
4871 if (nparens == 0) {
4872 s = BC_STATUS_SUCCESS;
4873 done = true;
4874 get_token = false;
4875 break;
4876 }
4877 else if (!paren_expr)
4878 return BC_STATUS_PARSE_EMPTY_EXP;
4879
4880 --nparens;
4881 paren_expr = rprn = true;
4882 get_token = bin_last = false;
4883
4884 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4885
4886 break;
4887 }
4888
4889 case BC_LEX_NAME:
4890 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004891 if (BC_PARSE_LEAF(prev, rprn))
4892 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004893 paren_expr = true;
4894 rprn = get_token = bin_last = false;
4895 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4896 ++nexprs;
4897
4898 break;
4899 }
4900
4901 case BC_LEX_NUMBER:
4902 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004903 if (BC_PARSE_LEAF(prev, rprn))
4904 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004905 bc_parse_number(p, &prev, &nexprs);
4906 paren_expr = get_token = true;
4907 rprn = bin_last = false;
4908
4909 break;
4910 }
4911
4912 case BC_LEX_KEY_IBASE:
4913 case BC_LEX_KEY_LAST:
4914 case BC_LEX_KEY_OBASE:
4915 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004916 if (BC_PARSE_LEAF(prev, rprn))
4917 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004918 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4919 bc_parse_push(p, (char) prev);
4920
4921 paren_expr = get_token = true;
4922 rprn = bin_last = false;
4923 ++nexprs;
4924
4925 break;
4926 }
4927
4928 case BC_LEX_KEY_LENGTH:
4929 case BC_LEX_KEY_SQRT:
4930 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004931 if (BC_PARSE_LEAF(prev, rprn))
4932 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004933 s = bc_parse_builtin(p, t, flags, &prev);
4934 paren_expr = true;
4935 rprn = get_token = bin_last = false;
4936 ++nexprs;
4937
4938 break;
4939 }
4940
4941 case BC_LEX_KEY_READ:
4942 {
4943 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004944 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004945 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004946 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06004947 else
4948 s = bc_parse_read(p);
4949
4950 paren_expr = true;
4951 rprn = get_token = bin_last = false;
4952 ++nexprs;
4953 prev = BC_INST_READ;
4954
4955 break;
4956 }
4957
4958 case BC_LEX_KEY_SCALE:
4959 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004960 if (BC_PARSE_LEAF(prev, rprn))
4961 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004962 s = bc_parse_scale(p, &prev, flags);
4963 paren_expr = true;
4964 rprn = get_token = bin_last = false;
4965 ++nexprs;
4966 prev = BC_INST_SCALE;
4967
4968 break;
4969 }
4970
4971 default:
4972 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004973 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004974 break;
4975 }
4976 }
4977
4978 if (!s && get_token) s = bc_lex_next(&p->l);
4979 }
4980
4981 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004982 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004983
4984 while (p->ops.len > ops_bgn) {
4985
4986 top = BC_PARSE_TOP_OP(p);
4987 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4988
4989 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004990 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004991
4992 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4993
4994 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4995 bc_vec_pop(&p->ops);
4996 }
4997
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004998 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4999 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005000
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005001 for (i = 0; i < next.len; ++i)
5002 if (t == next.tokens[i])
5003 goto ok;
5004 return bc_error("bad expression");
5005 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06005006
5007 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01005008 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06005009 if (s) return s;
5010 }
5011 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01005012 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06005013 if (s) return s;
5014 }
5015
5016 if (flags & BC_PARSE_PRINT) {
5017 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5018 bc_parse_push(p, BC_INST_POP);
5019 }
5020
5021 return s;
5022}
5023
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005024static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005025{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005026 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005027}
5028
5029static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5030{
5031 return bc_parse_expr(p, flags, bc_parse_next_read);
5032}
5033#endif // ENABLE_BC
5034
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005035#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005036static BcStatus dc_parse_register(BcParse *p)
5037{
5038 BcStatus s;
5039 char *name;
5040
5041 s = bc_lex_next(&p->l);
5042 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005043 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005044
5045 name = xstrdup(p->l.t.v.v);
5046 bc_parse_pushName(p, name);
5047
5048 return s;
5049}
5050
5051static BcStatus dc_parse_string(BcParse *p)
5052{
5053 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005054 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005055
5056 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5057 name = xstrdup(b);
5058
5059 str = xstrdup(p->l.t.v.v);
5060 bc_parse_push(p, BC_INST_STR);
5061 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005062 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005063 bc_parse_addFunc(p, name, &idx);
5064
5065 return bc_lex_next(&p->l);
5066}
5067
5068static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5069{
5070 BcStatus s;
5071
5072 bc_parse_push(p, inst);
5073 if (name) {
5074 s = dc_parse_register(p);
5075 if (s) return s;
5076 }
5077
5078 if (store) {
5079 bc_parse_push(p, BC_INST_SWAP);
5080 bc_parse_push(p, BC_INST_ASSIGN);
5081 bc_parse_push(p, BC_INST_POP);
5082 }
5083
5084 return bc_lex_next(&p->l);
5085}
5086
5087static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5088{
5089 BcStatus s;
5090
5091 bc_parse_push(p, inst);
5092 bc_parse_push(p, BC_INST_EXEC_COND);
5093
5094 s = dc_parse_register(p);
5095 if (s) return s;
5096
5097 s = bc_lex_next(&p->l);
5098 if (s) return s;
5099
5100 if (p->l.t.t == BC_LEX_ELSE) {
5101 s = dc_parse_register(p);
5102 if (s) return s;
5103 s = bc_lex_next(&p->l);
5104 }
5105 else
5106 bc_parse_push(p, BC_PARSE_STREND);
5107
5108 return s;
5109}
5110
5111static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5112{
5113 BcStatus s = BC_STATUS_SUCCESS;
5114 BcInst prev;
5115 uint8_t inst;
5116 bool assign, get_token = false;
5117
5118 switch (t) {
5119
5120 case BC_LEX_OP_REL_EQ:
5121 case BC_LEX_OP_REL_LE:
5122 case BC_LEX_OP_REL_GE:
5123 case BC_LEX_OP_REL_NE:
5124 case BC_LEX_OP_REL_LT:
5125 case BC_LEX_OP_REL_GT:
5126 {
5127 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5128 break;
5129 }
5130
5131 case BC_LEX_SCOLON:
5132 case BC_LEX_COLON:
5133 {
5134 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5135 break;
5136 }
5137
5138 case BC_LEX_STR:
5139 {
5140 s = dc_parse_string(p);
5141 break;
5142 }
5143
5144 case BC_LEX_NEG:
5145 case BC_LEX_NUMBER:
5146 {
5147 if (t == BC_LEX_NEG) {
5148 s = bc_lex_next(&p->l);
5149 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005150 if (p->l.t.t != BC_LEX_NUMBER)
5151 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005152 }
5153
5154 bc_parse_number(p, &prev, &p->nbraces);
5155
5156 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5157 get_token = true;
5158
5159 break;
5160 }
5161
5162 case BC_LEX_KEY_READ:
5163 {
5164 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005165 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005166 else
5167 bc_parse_push(p, BC_INST_READ);
5168 get_token = true;
5169 break;
5170 }
5171
5172 case BC_LEX_OP_ASSIGN:
5173 case BC_LEX_STORE_PUSH:
5174 {
5175 assign = t == BC_LEX_OP_ASSIGN;
5176 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5177 s = dc_parse_mem(p, inst, true, assign);
5178 break;
5179 }
5180
5181 case BC_LEX_LOAD:
5182 case BC_LEX_LOAD_POP:
5183 {
5184 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5185 s = dc_parse_mem(p, inst, true, false);
5186 break;
5187 }
5188
5189 case BC_LEX_STORE_IBASE:
5190 case BC_LEX_STORE_SCALE:
5191 case BC_LEX_STORE_OBASE:
5192 {
5193 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5194 s = dc_parse_mem(p, inst, false, true);
5195 break;
5196 }
5197
5198 default:
5199 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005200 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005201 get_token = true;
5202 break;
5203 }
5204 }
5205
5206 if (!s && get_token) s = bc_lex_next(&p->l);
5207
5208 return s;
5209}
5210
5211static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5212{
5213 BcStatus s = BC_STATUS_SUCCESS;
5214 BcInst inst;
5215 BcLexType t;
5216
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005217 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005218
5219 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5220
5221 inst = dc_parse_insts[t];
5222
5223 if (inst != BC_INST_INVALID) {
5224 bc_parse_push(p, inst);
5225 s = bc_lex_next(&p->l);
5226 }
5227 else
5228 s = dc_parse_token(p, t, flags);
5229 }
5230
5231 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5232 bc_parse_push(p, BC_INST_POP_EXEC);
5233
5234 return s;
5235}
5236
5237static BcStatus dc_parse_parse(BcParse *p)
5238{
5239 BcStatus s;
5240
5241 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005242 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005243 else
5244 s = dc_parse_expr(p, 0);
5245
Denys Vlasenkod38af482018-12-04 19:11:02 +01005246 if (s || G_interrupt) {
5247 bc_parse_reset(p);
5248 s = BC_STATUS_FAILURE;
5249 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005250
5251 return s;
5252}
5253
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005254static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005255{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005256 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005257}
5258#endif // ENABLE_DC
5259
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005260static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005261{
5262 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005263 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005264 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005265 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005266 }
5267}
5268
5269static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5270{
5271 if (IS_BC) {
5272 return bc_parse_expression(p, flags);
5273 } else {
5274 return dc_parse_expr(p, flags);
5275 }
5276}
5277
Denys Vlasenkodf515392018-12-02 19:27:48 +01005278static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005279{
Gavin Howard01055ba2018-11-03 11:00:21 -06005280 BcId e, *ptr;
5281 BcVec *v, *map;
5282 size_t i;
5283 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005284 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005285
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005286 v = var ? &G.prog.vars : &G.prog.arrs;
5287 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005288
5289 e.name = id;
5290 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005291 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005292
5293 if (new) {
5294 bc_array_init(&data.v, var);
5295 bc_vec_push(v, &data.v);
5296 }
5297
5298 ptr = bc_vec_item(map, i);
5299 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005300 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005301}
5302
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005303static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005304{
5305 BcStatus s = BC_STATUS_SUCCESS;
5306
5307 switch (r->t) {
5308
5309 case BC_RESULT_STR:
5310 case BC_RESULT_TEMP:
5311 case BC_RESULT_IBASE:
5312 case BC_RESULT_SCALE:
5313 case BC_RESULT_OBASE:
5314 {
5315 *num = &r->d.n;
5316 break;
5317 }
5318
5319 case BC_RESULT_CONSTANT:
5320 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005321 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005322 size_t base_t, len = strlen(*str);
5323 BcNum *base;
5324
5325 bc_num_init(&r->d.n, len);
5326
5327 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005328 base = hex ? &G.prog.hexb : &G.prog.ib;
5329 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005330 s = bc_num_parse(&r->d.n, *str, base, base_t);
5331
5332 if (s) {
5333 bc_num_free(&r->d.n);
5334 return s;
5335 }
5336
5337 *num = &r->d.n;
5338 r->t = BC_RESULT_TEMP;
5339
5340 break;
5341 }
5342
5343 case BC_RESULT_VAR:
5344 case BC_RESULT_ARRAY:
5345 case BC_RESULT_ARRAY_ELEM:
5346 {
5347 BcVec *v;
5348
Denys Vlasenkodf515392018-12-02 19:27:48 +01005349 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005350
5351 if (r->t == BC_RESULT_ARRAY_ELEM) {
5352 v = bc_vec_top(v);
5353 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5354 *num = bc_vec_item(v, r->d.id.idx);
5355 }
5356 else
5357 *num = bc_vec_top(v);
5358
5359 break;
5360 }
5361
5362 case BC_RESULT_LAST:
5363 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005364 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005365 break;
5366 }
5367
5368 case BC_RESULT_ONE:
5369 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005370 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005371 break;
5372 }
5373 }
5374
5375 return s;
5376}
5377
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005378static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005379 BcResult **r, BcNum **rn, bool assign)
5380{
5381 BcStatus s;
5382 bool hex;
5383 BcResultType lt, rt;
5384
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005385 if (!BC_PROG_STACK(&G.prog.results, 2))
5386 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005387
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005388 *r = bc_vec_item_rev(&G.prog.results, 0);
5389 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005390
5391 lt = (*l)->t;
5392 rt = (*r)->t;
5393 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5394
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005395 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005396 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005397 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005398 if (s) return s;
5399
5400 // We run this again under these conditions in case any vector has been
5401 // reallocated out from under the BcNums or arrays we had.
5402 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005403 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005404 if (s) return s;
5405 }
5406
5407 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005408 return bc_error("variable is wrong type");
5409 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5410 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005411
Gavin Howard01055ba2018-11-03 11:00:21 -06005412 return s;
5413}
5414
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005415static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005416{
5417 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005418 bc_vec_pop(&G.prog.results);
5419 bc_vec_pop(&G.prog.results);
5420 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005421}
5422
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005423static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005424{
5425 BcStatus s;
5426
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005427 if (!BC_PROG_STACK(&G.prog.results, 1))
5428 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005429 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005430
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005431 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005432 if (s) return s;
5433
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005434 if (!BC_PROG_NUM((*r), (*n)))
5435 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005436
5437 return s;
5438}
5439
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005440static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005441{
5442 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005443 bc_vec_pop(&G.prog.results);
5444 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005445}
5446
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005447static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005448{
5449 BcStatus s;
5450 BcResult *opd1, *opd2, res;
5451 BcNum *n1, *n2 = NULL;
5452
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005453 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005454 if (s) return s;
5455 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5456
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005457 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005458 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005459 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005460
5461 return s;
5462
5463err:
5464 bc_num_free(&res.d.n);
5465 return s;
5466}
5467
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005468static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005469{
5470 BcStatus s;
5471 BcParse parse;
5472 BcVec buf;
5473 BcInstPtr ip;
5474 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005475 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005476
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005477 for (i = 0; i < G.prog.stack.len; ++i) {
5478 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005479 if (ip_ptr->func == BC_PROG_READ)
5480 return bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005481 }
5482
Denys Vlasenko7d628012018-12-04 21:46:47 +01005483 bc_vec_pop_all(&f->code);
5484 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005485
5486 s = bc_read_line(&buf, "read> ");
5487 if (s) goto io_err;
5488
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005489 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005490 bc_lex_file(&parse.l, bc_program_stdin_name);
5491
5492 s = bc_parse_text(&parse, buf.v);
5493 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005494 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005495 if (s) goto exec_err;
5496
5497 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005498 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005499 goto exec_err;
5500 }
5501
5502 ip.func = BC_PROG_READ;
5503 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005504 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005505
5506 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005507 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005508
5509 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005510 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005511
5512exec_err:
5513 bc_parse_free(&parse);
5514io_err:
5515 bc_vec_free(&buf);
5516 return s;
5517}
5518
5519static size_t bc_program_index(char *code, size_t *bgn)
5520{
5521 char amt = code[(*bgn)++], i = 0;
5522 size_t res = 0;
5523
5524 for (; i < amt; ++i, ++(*bgn))
5525 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5526
5527 return res;
5528}
5529
5530static char *bc_program_name(char *code, size_t *bgn)
5531{
5532 size_t i;
5533 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5534
5535 s = xmalloc(ptr - str + 1);
5536 c = code[(*bgn)++];
5537
5538 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5539 s[i] = c;
5540
5541 s[i] = '\0';
5542
5543 return s;
5544}
5545
5546static void bc_program_printString(const char *str, size_t *nchars)
5547{
5548 size_t i, len = strlen(str);
5549
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005550#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005551 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005552 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005553 return;
5554 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005555#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005556
5557 for (i = 0; i < len; ++i, ++(*nchars)) {
5558
5559 int c = str[i];
5560
5561 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005562 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005563 else {
5564
5565 c = str[++i];
5566
5567 switch (c) {
5568
5569 case 'a':
5570 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005571 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005572 break;
5573 }
5574
5575 case 'b':
5576 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005577 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005578 break;
5579 }
5580
5581 case '\\':
5582 case 'e':
5583 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005584 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005585 break;
5586 }
5587
5588 case 'f':
5589 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005590 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005591 break;
5592 }
5593
5594 case 'n':
5595 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005596 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005597 *nchars = SIZE_MAX;
5598 break;
5599 }
5600
5601 case 'r':
5602 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005603 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005604 break;
5605 }
5606
5607 case 'q':
5608 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005609 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005610 break;
5611 }
5612
5613 case 't':
5614 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005615 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005616 break;
5617 }
5618
5619 default:
5620 {
5621 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005622 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005623 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005624 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005625 break;
5626 }
5627 }
5628 }
5629 }
5630}
5631
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005632static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005633{
5634 BcStatus s = BC_STATUS_SUCCESS;
5635 BcResult *r;
5636 size_t len, i;
5637 char *str;
5638 BcNum *num = NULL;
5639 bool pop = inst != BC_INST_PRINT;
5640
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005641 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5642 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005643
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005644 r = bc_vec_item_rev(&G.prog.results, idx);
5645 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005646 if (s) return s;
5647
5648 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5650 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005651 }
5652 else {
5653
5654 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005655 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005656
5657 if (inst == BC_INST_PRINT_STR) {
5658 for (i = 0, len = strlen(str); i < len; ++i) {
5659 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005660 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005661 if (c == '\n') G.prog.nchars = SIZE_MAX;
5662 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005663 }
5664 }
5665 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005666 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005667 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005668 }
5669 }
5670
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005671 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005672
5673 return s;
5674}
5675
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005676static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005677{
5678 BcStatus s;
5679 BcResult res, *ptr;
5680 BcNum *num = NULL;
5681
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005682 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005683 if (s) return s;
5684
5685 bc_num_init(&res.d.n, num->len);
5686 bc_num_copy(&res.d.n, num);
5687 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5688
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005689 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005690
5691 return s;
5692}
5693
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005694static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005695{
5696 BcStatus s;
5697 BcResult *opd1, *opd2, res;
5698 BcNum *n1, *n2;
5699 bool cond = 0;
5700 ssize_t cmp;
5701
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005702 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005703 if (s) return s;
5704 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5705
5706 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005707 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005708 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005709 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005710 else {
5711
5712 cmp = bc_num_cmp(n1, n2);
5713
5714 switch (inst) {
5715
5716 case BC_INST_REL_EQ:
5717 {
5718 cond = cmp == 0;
5719 break;
5720 }
5721
5722 case BC_INST_REL_LE:
5723 {
5724 cond = cmp <= 0;
5725 break;
5726 }
5727
5728 case BC_INST_REL_GE:
5729 {
5730 cond = cmp >= 0;
5731 break;
5732 }
5733
5734 case BC_INST_REL_NE:
5735 {
5736 cond = cmp != 0;
5737 break;
5738 }
5739
5740 case BC_INST_REL_LT:
5741 {
5742 cond = cmp < 0;
5743 break;
5744 }
5745
5746 case BC_INST_REL_GT:
5747 {
5748 cond = cmp > 0;
5749 break;
5750 }
5751 }
5752 }
5753
5754 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5755
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005756 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005757
5758 return s;
5759}
5760
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005761#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005762static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005763 bool push)
5764{
5765 BcNum n2;
5766 BcResult res;
5767
5768 memset(&n2, 0, sizeof(BcNum));
5769 n2.rdx = res.d.id.idx = r->d.id.idx;
5770 res.t = BC_RESULT_STR;
5771
5772 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005773 if (!BC_PROG_STACK(&G.prog.results, 2))
5774 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005775 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005776 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005777 }
5778
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005779 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005780
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005781 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005782 bc_vec_push(v, &n2);
5783
5784 return BC_STATUS_SUCCESS;
5785}
5786#endif // ENABLE_DC
5787
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005788static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005789{
5790 BcStatus s;
5791 BcResult *ptr, r;
5792 BcVec *v;
5793 BcNum *n;
5794
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005795 if (!BC_PROG_STACK(&G.prog.results, 1))
5796 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005797
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005798 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005799 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5800 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005801 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005802
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005803#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005804 if (ptr->t == BC_RESULT_STR && !var)
5805 return bc_error("variable is wrong type");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005806 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005807#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005808
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005809 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005810 if (s) return s;
5811
5812 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005813 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005814
5815 if (var) {
5816 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5817 bc_num_copy(&r.d.n, n);
5818 }
5819 else {
5820 bc_array_init(&r.d.v, true);
5821 bc_array_copy(&r.d.v, (BcVec *) n);
5822 }
5823
5824 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005825 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005826
5827 return s;
5828}
5829
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005830static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005831{
5832 BcStatus s;
5833 BcResult *left, *right, res;
5834 BcNum *l = NULL, *r = NULL;
5835 unsigned long val, max;
5836 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5837
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005838 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005839 if (s) return s;
5840
5841 ib = left->t == BC_RESULT_IBASE;
5842 sc = left->t == BC_RESULT_SCALE;
5843
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005844#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005845
5846 if (right->t == BC_RESULT_STR) {
5847
5848 BcVec *v;
5849
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005850 if (left->t != BC_RESULT_VAR)
5851 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005852 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005853
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005854 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005855 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005856#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005857
5858 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005859 return bc_error("bad assignment:"
5860 " left side must be scale,"
5861 " ibase, obase, last, var,"
5862 " or array element"
5863 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005864
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005865#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005866 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005867 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005868
5869 if (assign)
5870 bc_num_copy(l, r);
5871 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005872 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005873
5874 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005875#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005876 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005877#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005878
5879 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005880 static const char *const msg[] = {
5881 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5882 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5883 "?1", //BC_RESULT_LAST
5884 "?2", //BC_RESULT_CONSTANT
5885 "?3", //BC_RESULT_ONE
5886 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5887 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005888 size_t *ptr;
5889
5890 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005891 if (s)
5892 return s;
5893 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005894 if (sc) {
5895 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005896 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005897 }
5898 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005899 if (val < BC_NUM_MIN_BASE)
5900 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005901 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005902 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005903 }
5904
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005905 if (val > max)
5906 return bc_error(msg[s]);
5907 if (!sc)
5908 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005909
5910 *ptr = (size_t) val;
5911 s = BC_STATUS_SUCCESS;
5912 }
5913
5914 bc_num_init(&res.d.n, l->len);
5915 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005916 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005917
5918 return s;
5919}
5920
Denys Vlasenko416ce762018-12-02 20:57:17 +01005921#if !ENABLE_DC
5922#define bc_program_pushVar(code, bgn, pop, copy) \
5923 bc_program_pushVar(code, bgn)
5924// for bc, 'pop' and 'copy' are always false
5925#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005926static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005927 bool pop, bool copy)
5928{
5929 BcStatus s = BC_STATUS_SUCCESS;
5930 BcResult r;
5931 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005932
5933 r.t = BC_RESULT_VAR;
5934 r.d.id.name = name;
5935
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005936#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005937 {
5938 BcVec *v = bc_program_search(name, true);
5939 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005940
Denys Vlasenko416ce762018-12-02 20:57:17 +01005941 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005942
Denys Vlasenko416ce762018-12-02 20:57:17 +01005943 if (!BC_PROG_STACK(v, 2 - copy)) {
5944 free(name);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005945 return bc_error("stack has too few elements");
Denys Vlasenko416ce762018-12-02 20:57:17 +01005946 }
5947
Gavin Howard01055ba2018-11-03 11:00:21 -06005948 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005949 name = NULL;
5950
5951 if (!BC_PROG_STR(num)) {
5952
5953 r.t = BC_RESULT_TEMP;
5954
5955 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5956 bc_num_copy(&r.d.n, num);
5957 }
5958 else {
5959 r.t = BC_RESULT_STR;
5960 r.d.id.idx = num->rdx;
5961 }
5962
5963 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005964 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005965 }
5966#endif // ENABLE_DC
5967
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005968 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005969
5970 return s;
5971}
5972
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005973static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005974 char inst)
5975{
5976 BcStatus s = BC_STATUS_SUCCESS;
5977 BcResult r;
5978 BcNum *num;
5979
5980 r.d.id.name = bc_program_name(code, bgn);
5981
5982 if (inst == BC_INST_ARRAY) {
5983 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005984 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005985 }
5986 else {
5987
5988 BcResult *operand;
5989 unsigned long temp;
5990
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005991 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005992 if (s) goto err;
5993 s = bc_num_ulong(num, &temp);
5994 if (s) goto err;
5995
5996 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005997 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005998 goto err;
5999 }
6000
6001 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006002 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06006003 }
6004
6005err:
6006 if (s) free(r.d.id.name);
6007 return s;
6008}
6009
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006010#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006011static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006012{
6013 BcStatus s;
6014 BcResult *ptr, res, copy;
6015 BcNum *num = NULL;
6016 char inst2 = inst;
6017
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006018 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006019 if (s) return s;
6020
6021 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6022 copy.t = BC_RESULT_TEMP;
6023 bc_num_init(&copy.d.n, num->len);
6024 bc_num_copy(&copy.d.n, num);
6025 }
6026
6027 res.t = BC_RESULT_ONE;
6028 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6029 BC_INST_ASSIGN_PLUS :
6030 BC_INST_ASSIGN_MINUS;
6031
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006032 bc_vec_push(&G.prog.results, &res);
6033 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006034
6035 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006036 bc_vec_pop(&G.prog.results);
6037 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006038 }
6039
6040 return s;
6041}
6042
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006043static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006044{
6045 BcStatus s = BC_STATUS_SUCCESS;
6046 BcInstPtr ip;
6047 size_t i, nparams = bc_program_index(code, idx);
6048 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006049 BcId *a;
6050 BcResultData param;
6051 BcResult *arg;
6052
6053 ip.idx = 0;
6054 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006055 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006056
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006057 if (func->code.len == 0) {
6058 return bc_error("undefined function");
6059 }
6060 if (nparams != func->nparams) {
6061 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
6062 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006063 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006064
6065 for (i = 0; i < nparams; ++i) {
6066
6067 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006068 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006069
6070 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006071 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006072
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006073 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006074 if (s) return s;
6075 }
6076
6077 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006078 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006079
6080 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006081 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006082
6083 if (a->idx) {
6084 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6085 bc_vec_push(v, &param.n);
6086 }
6087 else {
6088 bc_array_init(&param.v, true);
6089 bc_vec_push(v, &param.v);
6090 }
6091 }
6092
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006093 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006094
6095 return BC_STATUS_SUCCESS;
6096}
6097
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006098static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006099{
6100 BcStatus s;
6101 BcResult res;
6102 BcFunc *f;
6103 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006104 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006105
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006106 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006107 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006108
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006109 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006110 res.t = BC_RESULT_TEMP;
6111
6112 if (inst == BC_INST_RET) {
6113
6114 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006115 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006116
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006117 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006118 if (s) return s;
6119 bc_num_init(&res.d.n, num->len);
6120 bc_num_copy(&res.d.n, num);
6121 }
6122 else {
6123 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6124 bc_num_zero(&res.d.n);
6125 }
6126
6127 // We need to pop arguments as well, so this takes that into account.
6128 for (i = 0; i < f->autos.len; ++i) {
6129
6130 BcVec *v;
6131 BcId *a = bc_vec_item(&f->autos, i);
6132
Denys Vlasenkodf515392018-12-02 19:27:48 +01006133 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006134 bc_vec_pop(v);
6135 }
6136
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006137 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6138 bc_vec_push(&G.prog.results, &res);
6139 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006140
6141 return BC_STATUS_SUCCESS;
6142}
6143#endif // ENABLE_BC
6144
6145static unsigned long bc_program_scale(BcNum *n)
6146{
6147 return (unsigned long) n->rdx;
6148}
6149
6150static unsigned long bc_program_len(BcNum *n)
6151{
6152 unsigned long len = n->len;
6153 size_t i;
6154
6155 if (n->rdx != n->len) return len;
6156 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6157
6158 return len;
6159}
6160
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006161static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006162{
6163 BcStatus s;
6164 BcResult *opnd;
6165 BcNum *num = NULL;
6166 BcResult res;
6167 bool len = inst == BC_INST_LENGTH;
6168
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006169 if (!BC_PROG_STACK(&G.prog.results, 1))
6170 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006171 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006172
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006173 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006174 if (s) return s;
6175
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006176#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006177 if (!BC_PROG_NUM(opnd, num) && !len)
6178 return bc_error("variable is wrong type");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006179#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006180
6181 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6182
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006183 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006184#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006185 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006186 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006187 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006188#endif
6189#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006190 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6191
6192 char **str;
6193 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6194
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006195 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006196 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006197 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006198#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006199 else {
6200 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006201 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006202 }
6203
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006204 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006205
6206 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006207}
6208
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006209#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006210static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006211{
6212 BcStatus s;
6213 BcResult *opd1, *opd2, res, res2;
6214 BcNum *n1, *n2 = NULL;
6215
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006216 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006217 if (s) return s;
6218
6219 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6220 bc_num_init(&res2.d.n, n2->len);
6221
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006222 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006223 if (s) goto err;
6224
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006225 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006226 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006227 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006228
6229 return s;
6230
6231err:
6232 bc_num_free(&res2.d.n);
6233 bc_num_free(&res.d.n);
6234 return s;
6235}
6236
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006237static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006238{
6239 BcStatus s;
6240 BcResult *r1, *r2, *r3, res;
6241 BcNum *n1, *n2, *n3;
6242
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006243 if (!BC_PROG_STACK(&G.prog.results, 3))
6244 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006245 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006246 if (s) return s;
6247
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006248 r1 = bc_vec_item_rev(&G.prog.results, 2);
6249 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006250 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006251 if (!BC_PROG_NUM(r1, n1))
6252 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006253
6254 // Make sure that the values have their pointers updated, if necessary.
6255 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6256
6257 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006258 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006259 if (s) return s;
6260 }
6261
6262 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006263 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006264 if (s) return s;
6265 }
6266 }
6267
6268 bc_num_init(&res.d.n, n3->len);
6269 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6270 if (s) goto err;
6271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 bc_vec_pop(&G.prog.results);
6273 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006274
6275 return s;
6276
6277err:
6278 bc_num_free(&res.d.n);
6279 return s;
6280}
6281
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006282static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006283{
Gavin Howard01055ba2018-11-03 11:00:21 -06006284 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006285 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006286
6287 res.t = BC_RESULT_TEMP;
6288
6289 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006290 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006291 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006292}
6293
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006294static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006295{
6296 BcStatus s;
6297 BcResult *r, res;
6298 BcNum *num = NULL, n;
6299 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006300 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006301 unsigned long val;
6302
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006303 if (!BC_PROG_STACK(&G.prog.results, 1))
6304 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006305 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006306
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006307 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006308 if (s) return s;
6309
6310 if (BC_PROG_NUM(r, num)) {
6311
6312 bc_num_init(&n, BC_NUM_DEF_SIZE);
6313 bc_num_copy(&n, num);
6314 bc_num_truncate(&n, n.rdx);
6315
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006316 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006317 if (s) goto num_err;
6318 s = bc_num_ulong(&n, &val);
6319 if (s) goto num_err;
6320
6321 c = (char) val;
6322
6323 bc_num_free(&n);
6324 }
6325 else {
6326 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006327 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006328 c = str2[0];
6329 }
6330
6331 str = xmalloc(2);
6332 str[0] = c;
6333 str[1] = '\0';
6334
6335 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006336 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006337
6338 if (idx != len + BC_PROG_REQ_FUNCS) {
6339
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006340 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6341 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006342 len = idx;
6343 break;
6344 }
6345 }
6346
6347 free(str);
6348 }
6349 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006350 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006351
6352 res.t = BC_RESULT_STR;
6353 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006354 bc_vec_pop(&G.prog.results);
6355 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006356
6357 return BC_STATUS_SUCCESS;
6358
6359num_err:
6360 bc_num_free(&n);
6361 return s;
6362}
6363
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006364static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006365{
6366 BcStatus s;
6367 BcResult *r;
6368 BcNum *n = NULL;
6369 size_t idx;
6370 char *str;
6371
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006372 if (!BC_PROG_STACK(&G.prog.results, 1))
6373 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006374 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006375
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006376 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006377 if (s) return s;
6378
6379 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006380 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006381 else {
6382 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006383 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006384 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006385 }
6386
6387 return s;
6388}
6389
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006390static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006391{
6392 BcStatus s;
6393 BcResult *opnd;
6394 BcNum *num = NULL;
6395 unsigned long val;
6396
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006397 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006398 if (s) return s;
6399 s = bc_num_ulong(num, &val);
6400 if (s) return s;
6401
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006402 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006403
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006404 if (G.prog.stack.len < val)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006405 return bc_error("stack has too few elements");
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006406 if (G.prog.stack.len == val)
6407 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006408
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006409 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006410
6411 return s;
6412}
6413
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006414static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006415 bool cond)
6416{
6417 BcStatus s = BC_STATUS_SUCCESS;
6418 BcResult *r;
6419 char **str;
6420 BcFunc *f;
6421 BcParse prs;
6422 BcInstPtr ip;
6423 size_t fidx, sidx;
6424 BcNum *n;
6425 bool exec;
6426
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006427 if (!BC_PROG_STACK(&G.prog.results, 1))
6428 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006429
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006430 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006431
6432 if (cond) {
6433
Gavin Howard01055ba2018-11-03 11:00:21 -06006434 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6435
6436 if (code[*bgn] == BC_PARSE_STREND)
6437 (*bgn) += 1;
6438 else
6439 else_name = bc_program_name(code, bgn);
6440
6441 exec = r->d.n.len != 0;
6442
6443 if (exec)
6444 name = then_name;
6445 else if (else_name != NULL) {
6446 exec = true;
6447 name = else_name;
6448 }
6449
6450 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006451 BcVec *v;
6452 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006453 n = bc_vec_top(v);
6454 }
6455
6456 free(then_name);
6457 free(else_name);
6458
6459 if (!exec) goto exit;
6460 if (!BC_PROG_STR(n)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006461 s = bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006462 goto exit;
6463 }
6464
6465 sidx = n->rdx;
6466 }
6467 else {
6468
6469 if (r->t == BC_RESULT_STR)
6470 sidx = r->d.id.idx;
6471 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006472 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006473 if (s || !BC_PROG_STR(n)) goto exit;
6474 sidx = n->rdx;
6475 }
6476 else
6477 goto exit;
6478 }
6479
6480 fidx = sidx + BC_PROG_REQ_FUNCS;
6481
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006482 str = bc_vec_item(&G.prog.strs, sidx);
6483 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006484
6485 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006486 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006487 s = bc_parse_text(&prs, *str);
6488 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006489 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006490 if (s) goto err;
6491
6492 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006493 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06006494 goto err;
6495 }
6496
6497 bc_parse_free(&prs);
6498 }
6499
6500 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006501 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006502 ip.func = fidx;
6503
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006504 bc_vec_pop(&G.prog.results);
6505 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006506
6507 return BC_STATUS_SUCCESS;
6508
6509err:
6510 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006511 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006512 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006513exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006514 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006515 return s;
6516}
6517#endif // ENABLE_DC
6518
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006519static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006520{
Gavin Howard01055ba2018-11-03 11:00:21 -06006521 BcResult res;
6522 unsigned long val;
6523
6524 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6525 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006526 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006527 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006528 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006529 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006530 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006531
6532 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006533 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006534 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006535}
6536
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006537static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006538{
Gavin Howard01055ba2018-11-03 11:00:21 -06006539 BcId entry, *entry_ptr;
6540 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006541 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006542
6543 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006544 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006545
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006546 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6547 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006548
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006549 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006550 *idx = entry_ptr->idx;
6551
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006552 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006553
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006554 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006555
6556 // We need to reset these, so the function can be repopulated.
6557 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006558 bc_vec_pop_all(&func->autos);
6559 bc_vec_pop_all(&func->code);
6560 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006561 }
6562 else {
6563 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006564 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006565 }
6566}
6567
Denys Vlasenkod38af482018-12-04 19:11:02 +01006568// Called when parsing or execution detects a failure,
6569// resets execution structures.
6570static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006571{
6572 BcFunc *f;
6573 BcInstPtr *ip;
6574
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006575 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006576 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006577
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006578 f = bc_vec_item(&G.prog.fns, 0);
6579 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 ip->idx = f->code.len;
6581
Denys Vlasenkod38af482018-12-04 19:11:02 +01006582 // If !tty, no need to check for ^C: we don't have ^C handler,
6583 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006584}
6585
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006586static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006587{
6588 BcStatus s = BC_STATUS_SUCCESS;
6589 size_t idx;
6590 BcResult r, *ptr;
6591 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006592 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6593 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006594 char *code = func->code.v;
6595 bool cond = false;
6596
6597 while (!s && ip->idx < func->code.len) {
6598
6599 char inst = code[(ip->idx)++];
6600
6601 switch (inst) {
6602
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006603#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006604 case BC_INST_JUMP_ZERO:
6605 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006606 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006607 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006608 cond = !bc_num_cmp(num, &G.prog.zero);
6609 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 }
6611 // Fallthrough.
6612 case BC_INST_JUMP:
6613 {
6614 size_t *addr;
6615 idx = bc_program_index(code, &ip->idx);
6616 addr = bc_vec_item(&func->labels, idx);
6617 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6618 break;
6619 }
6620
6621 case BC_INST_CALL:
6622 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006623 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006624 break;
6625 }
6626
6627 case BC_INST_INC_PRE:
6628 case BC_INST_DEC_PRE:
6629 case BC_INST_INC_POST:
6630 case BC_INST_DEC_POST:
6631 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006632 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006633 break;
6634 }
6635
6636 case BC_INST_HALT:
6637 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006638 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
6642 case BC_INST_RET:
6643 case BC_INST_RET0:
6644 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006645 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006646 break;
6647 }
6648
6649 case BC_INST_BOOL_OR:
6650 case BC_INST_BOOL_AND:
6651#endif // ENABLE_BC
6652 case BC_INST_REL_EQ:
6653 case BC_INST_REL_LE:
6654 case BC_INST_REL_GE:
6655 case BC_INST_REL_NE:
6656 case BC_INST_REL_LT:
6657 case BC_INST_REL_GT:
6658 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006659 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006660 break;
6661 }
6662
6663 case BC_INST_READ:
6664 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006665 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006666 break;
6667 }
6668
6669 case BC_INST_VAR:
6670 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006671 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006672 break;
6673 }
6674
6675 case BC_INST_ARRAY_ELEM:
6676 case BC_INST_ARRAY:
6677 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006678 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006679 break;
6680 }
6681
6682 case BC_INST_LAST:
6683 {
6684 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006685 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006686 break;
6687 }
6688
6689 case BC_INST_IBASE:
6690 case BC_INST_SCALE:
6691 case BC_INST_OBASE:
6692 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006693 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006694 break;
6695 }
6696
6697 case BC_INST_SCALE_FUNC:
6698 case BC_INST_LENGTH:
6699 case BC_INST_SQRT:
6700 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006701 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006702 break;
6703 }
6704
6705 case BC_INST_NUM:
6706 {
6707 r.t = BC_RESULT_CONSTANT;
6708 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006709 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006710 break;
6711 }
6712
6713 case BC_INST_POP:
6714 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006715 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006716 s = bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006717 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006718 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006719 break;
6720 }
6721
6722 case BC_INST_POP_EXEC:
6723 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006724 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006725 break;
6726 }
6727
6728 case BC_INST_PRINT:
6729 case BC_INST_PRINT_POP:
6730 case BC_INST_PRINT_STR:
6731 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006732 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006733 break;
6734 }
6735
6736 case BC_INST_STR:
6737 {
6738 r.t = BC_RESULT_STR;
6739 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006740 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006741 break;
6742 }
6743
6744 case BC_INST_POWER:
6745 case BC_INST_MULTIPLY:
6746 case BC_INST_DIVIDE:
6747 case BC_INST_MODULUS:
6748 case BC_INST_PLUS:
6749 case BC_INST_MINUS:
6750 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006751 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006752 break;
6753 }
6754
6755 case BC_INST_BOOL_NOT:
6756 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006757 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006758 if (s) return s;
6759
6760 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006761 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6762 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006763
6764 break;
6765 }
6766
6767 case BC_INST_NEG:
6768 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006769 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006770 break;
6771 }
6772
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006773#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006774 case BC_INST_ASSIGN_POWER:
6775 case BC_INST_ASSIGN_MULTIPLY:
6776 case BC_INST_ASSIGN_DIVIDE:
6777 case BC_INST_ASSIGN_MODULUS:
6778 case BC_INST_ASSIGN_PLUS:
6779 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006780#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006781 case BC_INST_ASSIGN:
6782 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006783 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006784 break;
6785 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006786#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006787 case BC_INST_MODEXP:
6788 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006789 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 break;
6791 }
6792
6793 case BC_INST_DIVMOD:
6794 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006795 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 break;
6797 }
6798
6799 case BC_INST_EXECUTE:
6800 case BC_INST_EXEC_COND:
6801 {
6802 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006803 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006804 break;
6805 }
6806
6807 case BC_INST_PRINT_STACK:
6808 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006809 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6810 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006811 break;
6812 }
6813
6814 case BC_INST_CLEAR_STACK:
6815 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006816 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006817 break;
6818 }
6819
6820 case BC_INST_STACK_LEN:
6821 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006822 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006823 break;
6824 }
6825
6826 case BC_INST_DUPLICATE:
6827 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006828 if (!BC_PROG_STACK(&G.prog.results, 1))
6829 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006830 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006831 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006832 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006833 break;
6834 }
6835
6836 case BC_INST_SWAP:
6837 {
6838 BcResult *ptr2;
6839
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006840 if (!BC_PROG_STACK(&G.prog.results, 2))
6841 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006842
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006843 ptr = bc_vec_item_rev(&G.prog.results, 0);
6844 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006845 memcpy(&r, ptr, sizeof(BcResult));
6846 memcpy(ptr, ptr2, sizeof(BcResult));
6847 memcpy(ptr2, &r, sizeof(BcResult));
6848
6849 break;
6850 }
6851
6852 case BC_INST_ASCIIFY:
6853 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006854 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006855 break;
6856 }
6857
6858 case BC_INST_PRINT_STREAM:
6859 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006860 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006861 break;
6862 }
6863
6864 case BC_INST_LOAD:
6865 case BC_INST_PUSH_VAR:
6866 {
6867 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006868 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006869 break;
6870 }
6871
6872 case BC_INST_PUSH_TO_VAR:
6873 {
6874 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006875 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006876 free(name);
6877 break;
6878 }
6879
6880 case BC_INST_QUIT:
6881 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006882 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006883 quit();
6884 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006885 break;
6886 }
6887
6888 case BC_INST_NQUIT:
6889 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006890 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006891 break;
6892 }
6893#endif // ENABLE_DC
6894 }
6895
Denys Vlasenkod38af482018-12-04 19:11:02 +01006896 if (s || G_interrupt) {
6897 bc_program_reset();
6898 break;
6899 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006900
6901 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006902 ip = bc_vec_top(&G.prog.stack);
6903 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006904 code = func->code.v;
6905 }
6906
6907 return s;
6908}
6909
Denys Vlasenko00d77792018-11-30 23:13:42 +01006910static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006911{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006912 printf("%s "BB_VER"\n"
6913 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006914 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006915 "This is free software with ABSOLUTELY NO WARRANTY\n"
6916 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006917}
6918
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006919#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006920static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006921{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006922 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6923
Gavin Howard01055ba2018-11-03 11:00:21 -06006924 BcVec v;
6925 char *env_args = getenv(bc_args_env_name), *buf;
6926
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006927 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006928
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006929 G.env_args = xstrdup(env_args);
6930 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006931
6932 bc_vec_init(&v, sizeof(char *), NULL);
6933 bc_vec_push(&v, &bc_args_env_name);
6934
6935 while (*buf != 0) {
6936 if (!isspace(*buf)) {
6937 bc_vec_push(&v, &buf);
6938 while (*buf != 0 && !isspace(*buf)) ++buf;
6939 if (*buf != 0) (*(buf++)) = '\0';
6940 }
6941 else
6942 ++buf;
6943 }
6944
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006945 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006946
6947 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006948}
6949#endif // ENABLE_BC
6950
6951static size_t bc_vm_envLen(const char *var)
6952{
6953 char *lenv = getenv(var);
6954 size_t i, len = BC_NUM_PRINT_WIDTH;
6955 int num;
6956
6957 if (!lenv) return len;
6958
6959 len = strlen(lenv);
6960
6961 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6962 if (num) {
6963 len = (size_t) atoi(lenv) - 1;
6964 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6965 }
6966 else
6967 len = BC_NUM_PRINT_WIDTH;
6968
6969 return len;
6970}
6971
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006972static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006973{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006974 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006975
Gavin Howard01055ba2018-11-03 11:00:21 -06006976 if (s) return s;
6977
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006978 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006979 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006980 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006981 }
6982
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006983 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006984 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006985 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006986 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006987 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006988 }
6989
6990 return s;
6991}
6992
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006993static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006994{
6995 BcStatus s;
6996 char *data;
6997 BcFunc *main_func;
6998 BcInstPtr *ip;
6999
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007000 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01007001 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01007002 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007003
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007004 bc_lex_file(&G.prs.l, file);
7005 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007006 if (s) goto err;
7007
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007008 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7009 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007010
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007011 if (main_func->code.len < ip->idx)
7012 s = bc_error("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007013
7014err:
7015 free(data);
7016 return s;
7017}
7018
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007019static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007020{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007021 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007022 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007023 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007024 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007025
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007026 G.prog.file = bc_program_stdin_name;
7027 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007028
Denys Vlasenko7d628012018-12-04 21:46:47 +01007029 bc_char_vec_init(&buffer);
7030 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06007031 bc_vec_pushByte(&buffer, '\0');
7032
7033 // This loop is complex because the vm tries not to send any lines that end
7034 // with a backslash to the parser. The reason for that is because the parser
7035 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7036 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01007037 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007038
7039 char *string = buf.v;
7040
7041 len = buf.len - 1;
7042
7043 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007044 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007045 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007046 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007047 str += 1;
7048 }
7049 else if (len > 1 || comment) {
7050
7051 for (i = 0; i < len; ++i) {
7052
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007053 bool notend = len > i + 1;
7054 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007055
7056 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007057 if (G.sbgn == G.send)
7058 str ^= c == G.sbgn;
7059 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007060 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007061 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007062 str += 1;
7063 }
7064
7065 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7066 comment = true;
7067 break;
7068 }
7069 else if (c == '*' && notend && comment && string[i + 1] == '/')
7070 comment = false;
7071 }
7072
7073 if (str || comment || string[len - 2] == '\\') {
7074 bc_vec_concat(&buffer, buf.v);
7075 continue;
7076 }
7077 }
7078
7079 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007080 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007081 if (s) {
7082 fflush_and_check();
7083 fputs("ready for more input\n", stderr);
7084 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007085
Denys Vlasenko7d628012018-12-04 21:46:47 +01007086 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007087 }
7088
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007089 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007090 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007091 }
7092 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007093 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007094 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007095
Gavin Howard01055ba2018-11-03 11:00:21 -06007096 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 Vlasenkod70d4a02018-12-04 20:58:40 +01007107 if (option_mask32 & 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 Vlasenko9b70f192018-12-04 20:51:40 +01007112 while (!s && G.prs.l.t.t != BC_LEX_EOF)
7113 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007114
7115 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007116 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007117 if (s) return s;
7118 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007119#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007120
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007121 for (i = 0; !s && i < G.files.len; ++i)
7122 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007123 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007124 fflush_and_check();
7125 fputs("ready for more input\n", stderr);
7126 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007127
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007128 if (IS_BC || !G.files.len)
7129 s = bc_vm_stdin();
7130 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7131 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007132
Denys Vlasenko00d77792018-11-30 23:13:42 +01007133 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007134}
7135
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007136#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007137static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007138{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007139 bc_num_free(&G.prog.ib);
7140 bc_num_free(&G.prog.ob);
7141 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007142# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007143 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007144# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007145 bc_vec_free(&G.prog.fns);
7146 bc_vec_free(&G.prog.fn_map);
7147 bc_vec_free(&G.prog.vars);
7148 bc_vec_free(&G.prog.var_map);
7149 bc_vec_free(&G.prog.arrs);
7150 bc_vec_free(&G.prog.arr_map);
7151 bc_vec_free(&G.prog.strs);
7152 bc_vec_free(&G.prog.consts);
7153 bc_vec_free(&G.prog.results);
7154 bc_vec_free(&G.prog.stack);
7155 bc_num_free(&G.prog.last);
7156 bc_num_free(&G.prog.zero);
7157 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007158}
7159
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007160static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007161{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007162 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007163 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007164 bc_parse_free(&G.prs);
7165 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007166}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007167#endif
7168
7169static void bc_program_init(size_t line_len)
7170{
7171 size_t idx;
7172 BcInstPtr ip;
7173
7174 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7175 memset(&ip, 0, sizeof(BcInstPtr));
7176
7177 /* G.prog.nchars = G.prog.scale = 0; - already is */
7178 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007179
7180 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7181 bc_num_ten(&G.prog.ib);
7182 G.prog.ib_t = 10;
7183
7184 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7185 bc_num_ten(&G.prog.ob);
7186 G.prog.ob_t = 10;
7187
7188 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7189 bc_num_ten(&G.prog.hexb);
7190 G.prog.hexb.num[0] = 6;
7191
7192#if ENABLE_DC
7193 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7194 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7195#endif
7196
7197 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7198 bc_num_zero(&G.prog.last);
7199
7200 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7201 bc_num_zero(&G.prog.zero);
7202
7203 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7204 bc_num_one(&G.prog.one);
7205
7206 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007207 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007208
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007209 bc_program_addFunc(xstrdup("(main)"), &idx);
7210 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007211
7212 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007213 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007214
7215 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007216 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007217
7218 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7219 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7220 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7221 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7222 bc_vec_push(&G.prog.stack, &ip);
7223}
Gavin Howard01055ba2018-11-03 11:00:21 -06007224
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007225static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007226{
Gavin Howard01055ba2018-11-03 11:00:21 -06007227 size_t len = bc_vm_envLen(env_len);
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 Vlasenkoab3c5682018-12-02 16:32:36 +01007232 bc_vm_envArgs();
7233 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007234
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007235 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007236 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007237 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007238 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007239 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007240 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007241}
7242
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007243static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007244 const char *env_len)
7245{
7246 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007247
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007248 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007249 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007250
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007251 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007252
Denys Vlasenkod38af482018-12-04 19:11:02 +01007253 if (G.ttyin) {
7254#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007255 // With SA_RESTART, most system calls will restart
7256 // (IOW: they won't fail with EINTR).
7257 // In particular, this means ^C won't cause
7258 // stdout to get into "error state" if SIGINT hits
7259 // within write() syscall.
7260 // The downside is that ^C while line input is taken
7261 // will only be handled after [Enter] since read()
7262 // from stdin is not interrupted by ^C either,
7263 // it restarts, thus fgetc() does not return on ^C.
7264 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7265
7266 // Without SA_RESTART, this exhibits a bug:
7267 // "while (1) print 1" and try ^C-ing it.
7268 // Intermittently, instead of returning to input line,
7269 // you'll get "output error: Interrupted system call"
7270 // and exit.
7271 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007272#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007273 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007274 bc_vm_info();
7275 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007276 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007277
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007278#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007279 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007280#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007281 return st;
7282}
7283
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007284#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007285int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7286int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007287{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007288 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007289 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007290
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007291 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007292}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007293#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007294
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007295#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007296int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7297int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007298{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007299 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007300 G.sbgn = '[';
7301 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007302
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007303 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007304}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007305#endif