blob: fd9e31cc5146b91a836b1388e850ebbdcce04589 [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 Vlasenkod4744ad2018-12-03 14:28:51 +0100918static void fflush_and_check(void)
919{
920 fflush_all();
921 if (ferror(stdout) || ferror(stderr))
922 bb_perror_msg_and_die("output error");
923}
924
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100925static void quit(void) NORETURN;
926static void quit(void)
927{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100928 if (ferror(stdin))
929 bb_perror_msg_and_die("input error");
930 fflush_and_check();
931 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100932}
933
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100934static NOINLINE int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100935{
936 va_list p;
937
938 va_start(p, fmt);
939 bb_verror_msg(fmt, p, NULL);
940 va_end(p);
941 if (!G.ttyin)
942 exit(1);
943 return BC_STATUS_FAILURE;
944}
945
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100946static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100947{
948 va_list p;
949
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100950 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100951 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100952 return BC_STATUS_SUCCESS; // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100953
954 va_start(p, fmt);
955 bb_verror_msg(fmt, p, NULL);
956 va_end(p);
957
958 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100959 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100960 return BC_STATUS_SUCCESS; // no, it's a warning
961 if (!G.ttyin)
962 exit(1);
963 return BC_STATUS_FAILURE;
964}
965
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100966// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
967// This idiom begs for tail-call optimization, but for it to work,
968// function must not have calller-cleaned parameters on stack.
969// Unfortunately, vararg functions do exactly that on most arches.
970// Thus, these shims for the cases when we have no PARAMS:
971static int bc_error(const char *msg)
972{
973 return bc_error_fmt("%s", msg);
974}
975static int bc_posix_error(const char *msg)
976{
977 return bc_posix_error_fmt("%s", msg);
978}
979static int bc_error_bad_character(char c)
980{
981 return bc_error_fmt("bad character '%c'", c);
982}
983static int bc_error_bad_expression(void)
984{
985 return bc_error("bad expression");
986}
987static int bc_error_bad_token(void)
988{
989 return bc_error("bad token");
990}
991static int bc_error_stack_has_too_few_elements(void)
992{
993 return bc_error("stack has too few elements");
994}
995static int bc_error_variable_is_wrong_type(void)
996{
997 return bc_error("variable is wrong type");
998}
999static int bc_error_nested_read_call(void)
1000{
1001 return bc_error("read() call inside of a read() call");
1002}
1003
Gavin Howard01055ba2018-11-03 11:00:21 -06001004static void bc_vec_grow(BcVec *v, size_t n)
1005{
1006 size_t cap = v->cap * 2;
1007 while (cap < v->len + n) cap *= 2;
1008 v->v = xrealloc(v->v, v->size * cap);
1009 v->cap = cap;
1010}
1011
1012static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1013{
1014 v->size = esize;
1015 v->cap = BC_VEC_START_CAP;
1016 v->len = 0;
1017 v->dtor = dtor;
1018 v->v = xmalloc(esize * BC_VEC_START_CAP);
1019}
1020
Denys Vlasenko7d628012018-12-04 21:46:47 +01001021static void bc_char_vec_init(BcVec *v)
1022{
1023 bc_vec_init(v, sizeof(char), NULL);
1024}
1025
Gavin Howard01055ba2018-11-03 11:00:21 -06001026static void bc_vec_expand(BcVec *v, size_t req)
1027{
1028 if (v->cap < req) {
1029 v->v = xrealloc(v->v, v->size * req);
1030 v->cap = req;
1031 }
1032}
1033
1034static void bc_vec_npop(BcVec *v, size_t n)
1035{
1036 if (!v->dtor)
1037 v->len -= n;
1038 else {
1039 size_t len = v->len - n;
1040 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1041 }
1042}
1043
Denys Vlasenko7d628012018-12-04 21:46:47 +01001044static void bc_vec_pop_all(BcVec *v)
1045{
1046 bc_vec_npop(v, v->len);
1047}
1048
Gavin Howard01055ba2018-11-03 11:00:21 -06001049static void bc_vec_push(BcVec *v, const void *data)
1050{
1051 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1052 memmove(v->v + (v->size * v->len), data, v->size);
1053 v->len += 1;
1054}
1055
1056static void bc_vec_pushByte(BcVec *v, char data)
1057{
1058 bc_vec_push(v, &data);
1059}
1060
1061static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1062{
1063 if (idx == v->len)
1064 bc_vec_push(v, data);
1065 else {
1066
1067 char *ptr;
1068
1069 if (v->len == v->cap) bc_vec_grow(v, 1);
1070
1071 ptr = v->v + v->size * idx;
1072
1073 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1074 memmove(ptr, data, v->size);
1075 }
1076}
1077
1078static void bc_vec_string(BcVec *v, size_t len, const char *str)
1079{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001080 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001081 bc_vec_expand(v, len + 1);
1082 memcpy(v->v, str, len);
1083 v->len = len;
1084
1085 bc_vec_pushByte(v, '\0');
1086}
1087
1088static void bc_vec_concat(BcVec *v, const char *str)
1089{
1090 size_t len;
1091
1092 if (v->len == 0) bc_vec_pushByte(v, '\0');
1093
1094 len = v->len + strlen(str);
1095
1096 if (v->cap < len) bc_vec_grow(v, len - v->len);
1097 strcat(v->v, str);
1098
1099 v->len = len;
1100}
1101
1102static void *bc_vec_item(const BcVec *v, size_t idx)
1103{
1104 return v->v + v->size * idx;
1105}
1106
1107static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1108{
1109 return v->v + v->size * (v->len - idx - 1);
1110}
1111
1112static void bc_vec_free(void *vec)
1113{
1114 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001115 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001116 free(v->v);
1117}
1118
1119static size_t bc_map_find(const BcVec *v, const void *ptr)
1120{
1121 size_t low = 0, high = v->len;
1122
1123 while (low < high) {
1124
1125 size_t mid = (low + high) / 2;
1126 BcId *id = bc_vec_item(v, mid);
1127 int result = bc_id_cmp(ptr, id);
1128
1129 if (result == 0)
1130 return mid;
1131 else if (result < 0)
1132 high = mid;
1133 else
1134 low = mid + 1;
1135 }
1136
1137 return low;
1138}
1139
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001140static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001141{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001142 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001143
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001144 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001145 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001146 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1147 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001148 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001149 bc_vec_pushAt(v, ptr, n);
1150 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001151}
1152
1153static size_t bc_map_index(const BcVec *v, const void *ptr)
1154{
1155 size_t i = bc_map_find(v, ptr);
1156 if (i >= v->len) return BC_VEC_INVALID_IDX;
1157 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1158}
1159
1160static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1161{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001162 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001163
Denys Vlasenko00d77792018-11-30 23:13:42 +01001164 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001165 int i;
1166 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001167
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001168 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001169 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001170
1171 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001172#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001173 if (bb_got_signal) { // ^C was pressed
1174 intr:
1175 bb_got_signal = 0; // resets G_interrupt to zero
1176 fputs(IS_BC
1177 ? "\ninterrupt (type \"quit\" to exit)\n"
1178 : "\ninterrupt (type \"q\" to exit)\n"
1179 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001180 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001181#endif
1182 if (G.ttyin && !G_posix)
1183 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001184
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001185#if ENABLE_FEATURE_BC_SIGNALS
1186 errno = 0;
1187#endif
1188 do {
1189 i = fgetc(stdin);
1190 if (i == EOF) {
1191#if ENABLE_FEATURE_BC_SIGNALS
1192 // Both conditions appear simultaneously, check both just in case
1193 if (errno == EINTR || bb_got_signal) {
1194 // ^C was pressed
1195 clearerr(stdin);
1196 goto intr;
1197 }
1198#endif
1199 if (ferror(stdin))
1200 quit(); // this emits error message
1201 G.eof = 1;
1202 // Note: EOF does not append '\n', therefore:
1203 // printf 'print 123\n' | bc - works
1204 // printf 'print 123' | bc - fails (syntax error)
1205 break;
1206 }
1207
1208 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1209 || i > 0x7e
1210 ) {
1211 // Bad chars on this line, ignore entire line
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001212 bc_error_fmt("illegal character 0x%02x", i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001213 bad_chars = 1;
1214 }
1215 c = (char) i;
1216 bc_vec_push(vec, &c);
1217 } while (i != '\n');
1218 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001219
1220 bc_vec_pushByte(vec, '\0');
1221
1222 return BC_STATUS_SUCCESS;
1223}
1224
Denys Vlasenkodf515392018-12-02 19:27:48 +01001225static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001226{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001227 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001228 size_t size = ((size_t) -1);
1229 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001230
Denys Vlasenkodf515392018-12-02 19:27:48 +01001231 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001232
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001233 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001234 char c = buf[i];
1235 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1236 || c > 0x7e
1237 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001238 free(buf);
1239 buf = NULL;
1240 break;
1241 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001242 }
1243
Denys Vlasenkodf515392018-12-02 19:27:48 +01001244 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001245}
1246
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001247static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001248{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001249 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001250 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001251
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001252 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001253#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001254 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001255 "extended-register\0" No_argument "x"
1256 "warn\0" No_argument "w"
1257 "version\0" No_argument "v"
1258 "standard\0" No_argument "s"
1259 "quiet\0" No_argument "q"
1260 "mathlib\0" No_argument "l"
1261 "interactive\0" No_argument "i"
1262 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001263#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001264 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001265#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001266 if (getenv("POSIXLY_CORRECT"))
1267 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001268
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001269 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001270 // should not be necessary, getopt32() handles this??
1271 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001272
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001273 for (i = optind; i < argc; ++i)
1274 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001275}
1276
1277static void bc_num_setToZero(BcNum *n, size_t scale)
1278{
1279 n->len = 0;
1280 n->neg = false;
1281 n->rdx = scale;
1282}
1283
1284static void bc_num_zero(BcNum *n)
1285{
1286 bc_num_setToZero(n, 0);
1287}
1288
1289static void bc_num_one(BcNum *n)
1290{
1291 bc_num_setToZero(n, 0);
1292 n->len = 1;
1293 n->num[0] = 1;
1294}
1295
1296static void bc_num_ten(BcNum *n)
1297{
1298 bc_num_setToZero(n, 0);
1299 n->len = 2;
1300 n->num[0] = 0;
1301 n->num[1] = 1;
1302}
1303
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001304static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001305 size_t len)
1306{
1307 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001308 for (i = 0; i < len; ++i) {
1309 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001310 a[i + j++] += 10;
1311 a[i + j] -= 1;
1312 }
1313 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001314}
1315
1316static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1317{
1318 size_t i;
1319 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001320 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001321 return BC_NUM_NEG(i + 1, c < 0);
1322}
1323
1324static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1325{
1326 size_t i, min, a_int, b_int, diff;
1327 BcDig *max_num, *min_num;
1328 bool a_max, neg = false;
1329 ssize_t cmp;
1330
1331 if (a == b) return 0;
1332 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1333 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1334 if (a->neg) {
1335 if (b->neg)
1336 neg = true;
1337 else
1338 return -1;
1339 }
1340 else if (b->neg)
1341 return 1;
1342
1343 a_int = BC_NUM_INT(a);
1344 b_int = BC_NUM_INT(b);
1345 a_int -= b_int;
1346 a_max = (a->rdx > b->rdx);
1347
1348 if (a_int != 0) return (ssize_t) a_int;
1349
1350 if (a_max) {
1351 min = b->rdx;
1352 diff = a->rdx - b->rdx;
1353 max_num = a->num + diff;
1354 min_num = b->num;
1355 }
1356 else {
1357 min = a->rdx;
1358 diff = b->rdx - a->rdx;
1359 max_num = b->num + diff;
1360 min_num = a->num;
1361 }
1362
1363 cmp = bc_num_compare(max_num, min_num, b_int + min);
1364 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1365
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001366 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001367 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1368 }
1369
1370 return 0;
1371}
1372
1373static void bc_num_truncate(BcNum *n, size_t places)
1374{
1375 if (places == 0) return;
1376
1377 n->rdx -= places;
1378
1379 if (n->len != 0) {
1380 n->len -= places;
1381 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1382 }
1383}
1384
1385static void bc_num_extend(BcNum *n, size_t places)
1386{
1387 size_t len = n->len + places;
1388
1389 if (places != 0) {
1390
1391 if (n->cap < len) bc_num_expand(n, len);
1392
1393 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1394 memset(n->num, 0, sizeof(BcDig) * places);
1395
1396 n->len += places;
1397 n->rdx += places;
1398 }
1399}
1400
1401static void bc_num_clean(BcNum *n)
1402{
1403 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1404 if (n->len == 0)
1405 n->neg = false;
1406 else if (n->len < n->rdx)
1407 n->len = n->rdx;
1408}
1409
1410static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1411{
1412 if (n->rdx < scale)
1413 bc_num_extend(n, scale - n->rdx);
1414 else
1415 bc_num_truncate(n, n->rdx - scale);
1416
1417 bc_num_clean(n);
1418 if (n->len != 0) n->neg = !neg1 != !neg2;
1419}
1420
1421static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1422 BcNum *restrict b)
1423{
1424 if (idx < n->len) {
1425
1426 b->len = n->len - idx;
1427 a->len = idx;
1428 a->rdx = b->rdx = 0;
1429
1430 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1431 memcpy(a->num, n->num, idx * sizeof(BcDig));
1432 }
1433 else {
1434 bc_num_zero(b);
1435 bc_num_copy(a, n);
1436 }
1437
1438 bc_num_clean(a);
1439 bc_num_clean(b);
1440}
1441
1442static BcStatus bc_num_shift(BcNum *n, size_t places)
1443{
1444 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001445 if (places + n->len > BC_MAX_NUM)
1446 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001447
1448 if (n->rdx >= places)
1449 n->rdx -= places;
1450 else {
1451 bc_num_extend(n, places - n->rdx);
1452 n->rdx = 0;
1453 }
1454
1455 bc_num_clean(n);
1456
1457 return BC_STATUS_SUCCESS;
1458}
1459
1460static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1461{
1462 BcNum one;
1463 BcDig num[2];
1464
1465 one.cap = 2;
1466 one.num = num;
1467 bc_num_one(&one);
1468
1469 return bc_num_div(&one, a, b, scale);
1470}
1471
1472static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1473{
1474 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1475 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1476 int carry, in;
1477
1478 // Because this function doesn't need to use scale (per the bc spec),
1479 // I am hijacking it to say whether it's doing an add or a subtract.
1480
1481 if (a->len == 0) {
1482 bc_num_copy(c, b);
1483 if (sub && c->len) c->neg = !c->neg;
1484 return BC_STATUS_SUCCESS;
1485 }
1486 else if (b->len == 0) {
1487 bc_num_copy(c, a);
1488 return BC_STATUS_SUCCESS;
1489 }
1490
1491 c->neg = a->neg;
1492 c->rdx = BC_MAX(a->rdx, b->rdx);
1493 min_rdx = BC_MIN(a->rdx, b->rdx);
1494 c->len = 0;
1495
1496 if (a->rdx > b->rdx) {
1497 diff = a->rdx - b->rdx;
1498 ptr = a->num;
1499 ptr_a = a->num + diff;
1500 ptr_b = b->num;
1501 }
1502 else {
1503 diff = b->rdx - a->rdx;
1504 ptr = b->num;
1505 ptr_a = a->num;
1506 ptr_b = b->num + diff;
1507 }
1508
1509 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1510
1511 ptr_c += diff;
1512 a_int = BC_NUM_INT(a);
1513 b_int = BC_NUM_INT(b);
1514
1515 if (a_int > b_int) {
1516 min_int = b_int;
1517 max = a_int;
1518 ptr = ptr_a;
1519 }
1520 else {
1521 min_int = a_int;
1522 max = b_int;
1523 ptr = ptr_b;
1524 }
1525
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001526 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001527 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1528 carry = in / 10;
1529 ptr_c[i] = (BcDig)(in % 10);
1530 }
1531
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001532 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001533 in = ((int) ptr[i]) + carry;
1534 carry = in / 10;
1535 ptr_c[i] = (BcDig)(in % 10);
1536 }
1537
1538 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1539
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001540 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001541}
1542
1543static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1544{
Gavin Howard01055ba2018-11-03 11:00:21 -06001545 ssize_t cmp;
1546 BcNum *minuend, *subtrahend;
1547 size_t start;
1548 bool aneg, bneg, neg;
1549
1550 // Because this function doesn't need to use scale (per the bc spec),
1551 // I am hijacking it to say whether it's doing an add or a subtract.
1552
1553 if (a->len == 0) {
1554 bc_num_copy(c, b);
1555 if (sub && c->len) c->neg = !c->neg;
1556 return BC_STATUS_SUCCESS;
1557 }
1558 else if (b->len == 0) {
1559 bc_num_copy(c, a);
1560 return BC_STATUS_SUCCESS;
1561 }
1562
1563 aneg = a->neg;
1564 bneg = b->neg;
1565 a->neg = b->neg = false;
1566
1567 cmp = bc_num_cmp(a, b);
1568
1569 a->neg = aneg;
1570 b->neg = bneg;
1571
1572 if (cmp == 0) {
1573 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1574 return BC_STATUS_SUCCESS;
1575 }
1576 else if (cmp > 0) {
1577 neg = a->neg;
1578 minuend = a;
1579 subtrahend = b;
1580 }
1581 else {
1582 neg = b->neg;
1583 if (sub) neg = !neg;
1584 minuend = b;
1585 subtrahend = a;
1586 }
1587
1588 bc_num_copy(c, minuend);
1589 c->neg = neg;
1590
1591 if (c->rdx < subtrahend->rdx) {
1592 bc_num_extend(c, subtrahend->rdx - c->rdx);
1593 start = 0;
1594 }
1595 else
1596 start = c->rdx - subtrahend->rdx;
1597
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001598 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001599
1600 bc_num_clean(c);
1601
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001602 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001603}
1604
1605static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1606 BcNum *restrict c)
1607{
1608 BcStatus s;
1609 int carry;
1610 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1611 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1612 bool aone = BC_NUM_ONE(a);
1613
Gavin Howard01055ba2018-11-03 11:00:21 -06001614 if (a->len == 0 || b->len == 0) {
1615 bc_num_zero(c);
1616 return BC_STATUS_SUCCESS;
1617 }
1618 else if (aone || BC_NUM_ONE(b)) {
1619 bc_num_copy(c, aone ? b : a);
1620 return BC_STATUS_SUCCESS;
1621 }
1622
1623 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1624 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1625 {
1626 bc_num_expand(c, a->len + b->len + 1);
1627
1628 memset(c->num, 0, sizeof(BcDig) * c->cap);
1629 c->len = carry = len = 0;
1630
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001631 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001632
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001633 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001634 int in = (int) c->num[i + j];
1635 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1636 carry = in / 10;
1637 c->num[i + j] = (BcDig)(in % 10);
1638 }
1639
1640 c->num[i + j] += (BcDig) carry;
1641 len = BC_MAX(len, i + j + !!carry);
1642 carry = 0;
1643 }
1644
1645 c->len = len;
1646
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001647 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001648 }
1649
1650 bc_num_init(&l1, max);
1651 bc_num_init(&h1, max);
1652 bc_num_init(&l2, max);
1653 bc_num_init(&h2, max);
1654 bc_num_init(&m1, max);
1655 bc_num_init(&m2, max);
1656 bc_num_init(&z0, max);
1657 bc_num_init(&z1, max);
1658 bc_num_init(&z2, max);
1659 bc_num_init(&temp, max + max);
1660
1661 bc_num_split(a, max2, &l1, &h1);
1662 bc_num_split(b, max2, &l2, &h2);
1663
1664 s = bc_num_add(&h1, &l1, &m1, 0);
1665 if (s) goto err;
1666 s = bc_num_add(&h2, &l2, &m2, 0);
1667 if (s) goto err;
1668
1669 s = bc_num_k(&h1, &h2, &z0);
1670 if (s) goto err;
1671 s = bc_num_k(&m1, &m2, &z1);
1672 if (s) goto err;
1673 s = bc_num_k(&l1, &l2, &z2);
1674 if (s) goto err;
1675
1676 s = bc_num_sub(&z1, &z0, &temp, 0);
1677 if (s) goto err;
1678 s = bc_num_sub(&temp, &z2, &z1, 0);
1679 if (s) goto err;
1680
1681 s = bc_num_shift(&z0, max2 * 2);
1682 if (s) goto err;
1683 s = bc_num_shift(&z1, max2);
1684 if (s) goto err;
1685 s = bc_num_add(&z0, &z1, &temp, 0);
1686 if (s) goto err;
1687 s = bc_num_add(&temp, &z2, c, 0);
1688
1689err:
1690 bc_num_free(&temp);
1691 bc_num_free(&z2);
1692 bc_num_free(&z1);
1693 bc_num_free(&z0);
1694 bc_num_free(&m2);
1695 bc_num_free(&m1);
1696 bc_num_free(&h2);
1697 bc_num_free(&l2);
1698 bc_num_free(&h1);
1699 bc_num_free(&l1);
1700 return s;
1701}
1702
1703static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1704{
1705 BcStatus s;
1706 BcNum cpa, cpb;
1707 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1708
1709 scale = BC_MAX(scale, a->rdx);
1710 scale = BC_MAX(scale, b->rdx);
1711 scale = BC_MIN(a->rdx + b->rdx, scale);
1712 maxrdx = BC_MAX(maxrdx, scale);
1713
1714 bc_num_init(&cpa, a->len);
1715 bc_num_init(&cpb, b->len);
1716
1717 bc_num_copy(&cpa, a);
1718 bc_num_copy(&cpb, b);
1719 cpa.neg = cpb.neg = false;
1720
1721 s = bc_num_shift(&cpa, maxrdx);
1722 if (s) goto err;
1723 s = bc_num_shift(&cpb, maxrdx);
1724 if (s) goto err;
1725 s = bc_num_k(&cpa, &cpb, c);
1726 if (s) goto err;
1727
1728 maxrdx += scale;
1729 bc_num_expand(c, c->len + maxrdx);
1730
1731 if (c->len < maxrdx) {
1732 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1733 c->len += maxrdx;
1734 }
1735
1736 c->rdx = maxrdx;
1737 bc_num_retireMul(c, scale, a->neg, b->neg);
1738
1739err:
1740 bc_num_free(&cpb);
1741 bc_num_free(&cpa);
1742 return s;
1743}
1744
1745static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1746{
1747 BcStatus s = BC_STATUS_SUCCESS;
1748 BcDig *n, *p, q;
1749 size_t len, end, i;
1750 BcNum cp;
1751 bool zero = true;
1752
1753 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001754 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001755 else if (a->len == 0) {
1756 bc_num_setToZero(c, scale);
1757 return BC_STATUS_SUCCESS;
1758 }
1759 else if (BC_NUM_ONE(b)) {
1760 bc_num_copy(c, a);
1761 bc_num_retireMul(c, scale, a->neg, b->neg);
1762 return BC_STATUS_SUCCESS;
1763 }
1764
1765 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1766 bc_num_copy(&cp, a);
1767 len = b->len;
1768
1769 if (len > cp.len) {
1770 bc_num_expand(&cp, len + 2);
1771 bc_num_extend(&cp, len - cp.len);
1772 }
1773
1774 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1775 cp.rdx -= b->rdx;
1776 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1777
1778 if (b->rdx == b->len) {
1779 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1780 len -= i - 1;
1781 }
1782
1783 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1784
1785 // We want an extra zero in front to make things simpler.
1786 cp.num[cp.len++] = 0;
1787 end = cp.len - len;
1788
1789 bc_num_expand(c, cp.len);
1790
1791 bc_num_zero(c);
1792 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1793 c->rdx = cp.rdx;
1794 c->len = cp.len;
1795 p = b->num;
1796
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001797 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001798 n = cp.num + i;
1799 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001800 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001801 c->num[i] = q;
1802 }
1803
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001804 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001805 bc_num_free(&cp);
1806
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001807 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001808}
1809
1810static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1811 BcNum *restrict d, size_t scale, size_t ts)
1812{
1813 BcStatus s;
1814 BcNum temp;
1815 bool neg;
1816
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001817 if (b->len == 0)
1818 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001819
1820 if (a->len == 0) {
1821 bc_num_setToZero(d, ts);
1822 return BC_STATUS_SUCCESS;
1823 }
1824
1825 bc_num_init(&temp, d->cap);
1826 bc_num_d(a, b, c, scale);
1827
1828 if (scale != 0) scale = ts;
1829
1830 s = bc_num_m(c, b, &temp, scale);
1831 if (s) goto err;
1832 s = bc_num_sub(a, &temp, d, scale);
1833 if (s) goto err;
1834
1835 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1836
1837 neg = d->neg;
1838 bc_num_retireMul(d, ts, a->neg, b->neg);
1839 d->neg = neg;
1840
1841err:
1842 bc_num_free(&temp);
1843 return s;
1844}
1845
1846static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1847{
1848 BcStatus s;
1849 BcNum c1;
1850 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1851
1852 bc_num_init(&c1, len);
1853 s = bc_num_r(a, b, &c1, c, scale, ts);
1854 bc_num_free(&c1);
1855
1856 return s;
1857}
1858
1859static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1860{
1861 BcStatus s = BC_STATUS_SUCCESS;
1862 BcNum copy;
1863 unsigned long pow;
1864 size_t i, powrdx, resrdx;
1865 bool neg, zero;
1866
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001867 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001868
1869 if (b->len == 0) {
1870 bc_num_one(c);
1871 return BC_STATUS_SUCCESS;
1872 }
1873 else if (a->len == 0) {
1874 bc_num_setToZero(c, scale);
1875 return BC_STATUS_SUCCESS;
1876 }
1877 else if (BC_NUM_ONE(b)) {
1878 if (!b->neg)
1879 bc_num_copy(c, a);
1880 else
1881 s = bc_num_inv(a, c, scale);
1882 return s;
1883 }
1884
1885 neg = b->neg;
1886 b->neg = false;
1887
1888 s = bc_num_ulong(b, &pow);
1889 if (s) return s;
1890
1891 bc_num_init(&copy, a->len);
1892 bc_num_copy(&copy, a);
1893
1894 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1895
1896 b->neg = neg;
1897
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001898 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001899 powrdx <<= 1;
1900 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1901 if (s) goto err;
Denys Vlasenkof359e002018-12-05 01:21:59 +01001902 // It is too slow to handle ^C only after entire "2^1000000" completes
1903 if (G_interrupt) {
1904 s = BC_STATUS_FAILURE;
1905 goto err;
1906 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001907 }
1908
Gavin Howard01055ba2018-11-03 11:00:21 -06001909 bc_num_copy(c, &copy);
1910
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001911 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001912
1913 powrdx <<= 1;
1914 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1915 if (s) goto err;
1916
1917 if (pow & 1) {
1918 resrdx += powrdx;
1919 s = bc_num_mul(c, &copy, c, resrdx);
1920 if (s) goto err;
1921 }
Denys Vlasenkof359e002018-12-05 01:21:59 +01001922 // It is too slow to handle ^C only after entire "2^1000000" completes
1923 if (G_interrupt) {
1924 s = BC_STATUS_FAILURE;
1925 goto err;
1926 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001927 }
1928
1929 if (neg) {
1930 s = bc_num_inv(c, c, scale);
1931 if (s) goto err;
1932 }
1933
Gavin Howard01055ba2018-11-03 11:00:21 -06001934 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1935
1936 // We can't use bc_num_clean() here.
1937 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1938 if (zero) bc_num_setToZero(c, scale);
1939
1940err:
1941 bc_num_free(&copy);
1942 return s;
1943}
1944
1945static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1946 BcNumBinaryOp op, size_t req)
1947{
1948 BcStatus s;
1949 BcNum num2, *ptr_a, *ptr_b;
1950 bool init = false;
1951
1952 if (c == a) {
1953 ptr_a = &num2;
1954 memcpy(ptr_a, c, sizeof(BcNum));
1955 init = true;
1956 }
1957 else
1958 ptr_a = a;
1959
1960 if (c == b) {
1961 ptr_b = &num2;
1962 if (c != a) {
1963 memcpy(ptr_b, c, sizeof(BcNum));
1964 init = true;
1965 }
1966 }
1967 else
1968 ptr_b = b;
1969
1970 if (init)
1971 bc_num_init(c, req);
1972 else
1973 bc_num_expand(c, req);
1974
1975 s = op(ptr_a, ptr_b, c, scale);
1976
1977 if (init) bc_num_free(&num2);
1978
1979 return s;
1980}
1981
1982static bool bc_num_strValid(const char *val, size_t base)
1983{
1984 BcDig b;
1985 bool small, radix = false;
1986 size_t i, len = strlen(val);
1987
1988 if (!len) return true;
1989
1990 small = base <= 10;
1991 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1992
1993 for (i = 0; i < len; ++i) {
1994
1995 BcDig c = val[i];
1996
1997 if (c == '.') {
1998
1999 if (radix) return false;
2000
2001 radix = true;
2002 continue;
2003 }
2004
2005 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2006 return false;
2007 }
2008
2009 return true;
2010}
2011
2012static void bc_num_parseDecimal(BcNum *n, const char *val)
2013{
2014 size_t len, i;
2015 const char *ptr;
2016 bool zero = true;
2017
2018 for (i = 0; val[i] == '0'; ++i);
2019
2020 val += i;
2021 len = strlen(val);
2022 bc_num_zero(n);
2023
2024 if (len != 0) {
2025 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2026 bc_num_expand(n, len);
2027 }
2028
2029 ptr = strchr(val, '.');
2030
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002031 n->rdx = 0;
2032 if (ptr != NULL)
2033 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002034
2035 if (!zero) {
2036 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2037 n->num[n->len] = val[i] - '0';
2038 }
2039}
2040
2041static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2042{
2043 BcStatus s;
2044 BcNum temp, mult, result;
2045 BcDig c = '\0';
2046 bool zero = true;
2047 unsigned long v;
2048 size_t i, digits, len = strlen(val);
2049
2050 bc_num_zero(n);
2051
2052 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2053 if (zero) return;
2054
2055 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2056 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2057
2058 for (i = 0; i < len; ++i) {
2059
2060 c = val[i];
2061 if (c == '.') break;
2062
2063 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2064
2065 s = bc_num_mul(n, base, &mult, 0);
2066 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002067 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002068 s = bc_num_add(&mult, &temp, n, 0);
2069 if (s) goto int_err;
2070 }
2071
2072 if (i == len) {
2073 c = val[i];
2074 if (c == 0) goto int_err;
2075 }
2076
2077 bc_num_init(&result, base->len);
2078 bc_num_zero(&result);
2079 bc_num_one(&mult);
2080
2081 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2082
2083 c = val[i];
2084 if (c == 0) break;
2085
2086 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2087
2088 s = bc_num_mul(&result, base, &result, 0);
2089 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002090 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002091 s = bc_num_add(&result, &temp, &result, 0);
2092 if (s) goto err;
2093 s = bc_num_mul(&mult, base, &mult, 0);
2094 if (s) goto err;
2095 }
2096
2097 s = bc_num_div(&result, &mult, &result, digits);
2098 if (s) goto err;
2099 s = bc_num_add(n, &result, n, digits);
2100 if (s) goto err;
2101
2102 if (n->len != 0) {
2103 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2104 }
2105 else
2106 bc_num_zero(n);
2107
2108err:
2109 bc_num_free(&result);
2110int_err:
2111 bc_num_free(&mult);
2112 bc_num_free(&temp);
2113}
2114
2115static void bc_num_printNewline(size_t *nchars, size_t line_len)
2116{
2117 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002118 bb_putchar('\\');
2119 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002120 *nchars = 0;
2121 }
2122}
2123
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002124#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002125static void bc_num_printChar(size_t num, size_t width, bool radix,
2126 size_t *nchars, size_t line_len)
2127{
2128 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002129 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002130 *nchars = *nchars + width;
2131}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002132#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002133
2134static void bc_num_printDigits(size_t num, size_t width, bool radix,
2135 size_t *nchars, size_t line_len)
2136{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002137 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002138
2139 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002140 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002141 ++(*nchars);
2142
2143 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002144 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2145 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002146
2147 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002148 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002149 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002150 dig = num / pow;
2151 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002152 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002153 }
2154}
2155
2156static void bc_num_printHex(size_t num, size_t width, bool radix,
2157 size_t *nchars, size_t line_len)
2158{
2159 if (radix) {
2160 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002161 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002162 *nchars += 1;
2163 }
2164
2165 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002166 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002167 *nchars = *nchars + width;
2168}
2169
2170static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2171{
2172 size_t i, rdx = n->rdx - 1;
2173
Denys Vlasenko00d77792018-11-30 23:13:42 +01002174 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002175 (*nchars) += n->neg;
2176
2177 for (i = n->len - 1; i < n->len; --i)
2178 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2179}
2180
2181static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2182 size_t *nchars, size_t len, BcNumDigitOp print)
2183{
2184 BcStatus s;
2185 BcVec stack;
2186 BcNum intp, fracp, digit, frac_len;
2187 unsigned long dig, *ptr;
2188 size_t i;
2189 bool radix;
2190
2191 if (n->len == 0) {
2192 print(0, width, false, nchars, len);
2193 return BC_STATUS_SUCCESS;
2194 }
2195
2196 bc_vec_init(&stack, sizeof(long), NULL);
2197 bc_num_init(&intp, n->len);
2198 bc_num_init(&fracp, n->rdx);
2199 bc_num_init(&digit, width);
2200 bc_num_init(&frac_len, BC_NUM_INT(n));
2201 bc_num_copy(&intp, n);
2202 bc_num_one(&frac_len);
2203
2204 bc_num_truncate(&intp, intp.rdx);
2205 s = bc_num_sub(n, &intp, &fracp, 0);
2206 if (s) goto err;
2207
2208 while (intp.len != 0) {
2209 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2210 if (s) goto err;
2211 s = bc_num_ulong(&digit, &dig);
2212 if (s) goto err;
2213 bc_vec_push(&stack, &dig);
2214 }
2215
2216 for (i = 0; i < stack.len; ++i) {
2217 ptr = bc_vec_item_rev(&stack, i);
2218 print(*ptr, width, false, nchars, len);
2219 }
2220
2221 if (!n->rdx) goto err;
2222
2223 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2224 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2225 if (s) goto err;
2226 s = bc_num_ulong(&fracp, &dig);
2227 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002228 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002229 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2230 if (s) goto err;
2231 print(dig, width, radix, nchars, len);
2232 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2233 if (s) goto err;
2234 }
2235
2236err:
2237 bc_num_free(&frac_len);
2238 bc_num_free(&digit);
2239 bc_num_free(&fracp);
2240 bc_num_free(&intp);
2241 bc_vec_free(&stack);
2242 return s;
2243}
2244
2245static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2246 size_t *nchars, size_t line_len)
2247{
2248 BcStatus s;
2249 size_t width, i;
2250 BcNumDigitOp print;
2251 bool neg = n->neg;
2252
Denys Vlasenko00d77792018-11-30 23:13:42 +01002253 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002254 (*nchars) += neg;
2255
2256 n->neg = false;
2257
2258 if (base_t <= BC_NUM_MAX_IBASE) {
2259 width = 1;
2260 print = bc_num_printHex;
2261 }
2262 else {
2263 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2264 print = bc_num_printDigits;
2265 }
2266
2267 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2268 n->neg = neg;
2269
2270 return s;
2271}
2272
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002273#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002274static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2275{
2276 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2277}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002278#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002279
2280static void bc_num_init(BcNum *n, size_t req)
2281{
2282 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2283 memset(n, 0, sizeof(BcNum));
2284 n->num = xmalloc(req);
2285 n->cap = req;
2286}
2287
2288static void bc_num_expand(BcNum *n, size_t req)
2289{
2290 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2291 if (req > n->cap) {
2292 n->num = xrealloc(n->num, req);
2293 n->cap = req;
2294 }
2295}
2296
2297static void bc_num_free(void *num)
2298{
2299 free(((BcNum *) num)->num);
2300}
2301
2302static void bc_num_copy(BcNum *d, BcNum *s)
2303{
2304 if (d != s) {
2305 bc_num_expand(d, s->cap);
2306 d->len = s->len;
2307 d->neg = s->neg;
2308 d->rdx = s->rdx;
2309 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2310 }
2311}
2312
2313static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2314 size_t base_t)
2315{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002316 if (!bc_num_strValid(val, base_t))
2317 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002318
2319 if (base_t == 10)
2320 bc_num_parseDecimal(n, val);
2321 else
2322 bc_num_parseBase(n, val, base);
2323
2324 return BC_STATUS_SUCCESS;
2325}
2326
2327static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2328 size_t *nchars, size_t line_len)
2329{
2330 BcStatus s = BC_STATUS_SUCCESS;
2331
2332 bc_num_printNewline(nchars, line_len);
2333
2334 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002335 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002336 ++(*nchars);
2337 }
2338 else if (base_t == 10)
2339 bc_num_printDecimal(n, nchars, line_len);
2340 else
2341 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2342
2343 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002344 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002345 *nchars = 0;
2346 }
2347
2348 return s;
2349}
2350
2351static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2352{
2353 size_t i;
2354 unsigned long pow;
2355
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002356 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002357
2358 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2359
2360 unsigned long prev = *result, powprev = pow;
2361
2362 *result += ((unsigned long) n->num[i]) * pow;
2363 pow *= 10;
2364
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002365 if (*result < prev || pow < powprev)
2366 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002367 }
2368
2369 return BC_STATUS_SUCCESS;
2370}
2371
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002372static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002373{
2374 size_t len;
2375 BcDig *ptr;
2376 unsigned long i;
2377
2378 bc_num_zero(n);
2379
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002380 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002381
2382 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2383 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002384}
2385
2386static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2387{
2388 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2389 (void) scale;
2390 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2391}
2392
2393static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2394{
2395 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2396 (void) scale;
2397 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2398}
2399
2400static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2401{
2402 size_t req = BC_NUM_MREQ(a, b, scale);
2403 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2404}
2405
2406static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2407{
2408 size_t req = BC_NUM_MREQ(a, b, scale);
2409 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2410}
2411
2412static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2413{
2414 size_t req = BC_NUM_MREQ(a, b, scale);
2415 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2416}
2417
2418static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2419{
2420 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2421}
2422
2423static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2424{
2425 BcStatus s;
2426 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2427 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2428 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2429
2430 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2431 bc_num_expand(b, req);
2432
2433 if (a->len == 0) {
2434 bc_num_setToZero(b, scale);
2435 return BC_STATUS_SUCCESS;
2436 }
2437 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002438 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002439 else if (BC_NUM_ONE(a)) {
2440 bc_num_one(b);
2441 bc_num_extend(b, scale);
2442 return BC_STATUS_SUCCESS;
2443 }
2444
2445 scale = BC_MAX(scale, a->rdx) + 1;
2446 len = a->len + scale;
2447
2448 bc_num_init(&num1, len);
2449 bc_num_init(&num2, len);
2450 bc_num_init(&half, BC_NUM_DEF_SIZE);
2451
2452 bc_num_one(&half);
2453 half.num[0] = 5;
2454 half.rdx = 1;
2455
2456 bc_num_init(&f, len);
2457 bc_num_init(&fprime, len);
2458
2459 x0 = &num1;
2460 x1 = &num2;
2461
2462 bc_num_one(x0);
2463 pow = BC_NUM_INT(a);
2464
2465 if (pow) {
2466
2467 if (pow & 1)
2468 x0->num[0] = 2;
2469 else
2470 x0->num[0] = 6;
2471
2472 pow -= 2 - (pow & 1);
2473
2474 bc_num_extend(x0, pow);
2475
2476 // Make sure to move the radix back.
2477 x0->rdx -= pow;
2478 }
2479
2480 x0->rdx = digs = digs1 = 0;
2481 resrdx = scale + 2;
2482 len = BC_NUM_INT(x0) + resrdx - 1;
2483
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002484 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002485
2486 s = bc_num_div(a, x0, &f, resrdx);
2487 if (s) goto err;
2488 s = bc_num_add(x0, &f, &fprime, resrdx);
2489 if (s) goto err;
2490 s = bc_num_mul(&fprime, &half, x1, resrdx);
2491 if (s) goto err;
2492
2493 cmp = bc_num_cmp(x1, x0);
2494 digs = x1->len - (unsigned long long) llabs(cmp);
2495
2496 if (cmp == cmp2 && digs == digs1)
2497 times += 1;
2498 else
2499 times = 0;
2500
2501 resrdx += times > 4;
2502
2503 cmp2 = cmp1;
2504 cmp1 = cmp;
2505 digs1 = digs;
2506
2507 temp = x0;
2508 x0 = x1;
2509 x1 = temp;
2510 }
2511
Gavin Howard01055ba2018-11-03 11:00:21 -06002512 bc_num_copy(b, x0);
2513 scale -= 1;
2514 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2515
2516err:
2517 bc_num_free(&fprime);
2518 bc_num_free(&f);
2519 bc_num_free(&half);
2520 bc_num_free(&num2);
2521 bc_num_free(&num1);
2522 return s;
2523}
2524
2525static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2526 size_t scale)
2527{
2528 BcStatus s;
2529 BcNum num2, *ptr_a;
2530 bool init = false;
2531 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2532
2533 if (c == a) {
2534 memcpy(&num2, c, sizeof(BcNum));
2535 ptr_a = &num2;
2536 bc_num_init(c, len);
2537 init = true;
2538 }
2539 else {
2540 ptr_a = a;
2541 bc_num_expand(c, len);
2542 }
2543
2544 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2545
2546 if (init) bc_num_free(&num2);
2547
2548 return s;
2549}
2550
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002551#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002552static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2553{
2554 BcStatus s;
2555 BcNum base, exp, two, temp;
2556
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002557 if (c->len == 0)
2558 return bc_error("divide by zero");
2559 if (a->rdx || b->rdx || c->rdx)
2560 return bc_error("non integer number");
2561 if (b->neg)
2562 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002563
2564 bc_num_expand(d, c->len);
2565 bc_num_init(&base, c->len);
2566 bc_num_init(&exp, b->len);
2567 bc_num_init(&two, BC_NUM_DEF_SIZE);
2568 bc_num_init(&temp, b->len);
2569
2570 bc_num_one(&two);
2571 two.num[0] = 2;
2572 bc_num_one(d);
2573
2574 s = bc_num_rem(a, c, &base, 0);
2575 if (s) goto err;
2576 bc_num_copy(&exp, b);
2577
2578 while (exp.len != 0) {
2579
2580 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2581 if (s) goto err;
2582
2583 if (BC_NUM_ONE(&temp)) {
2584 s = bc_num_mul(d, &base, &temp, 0);
2585 if (s) goto err;
2586 s = bc_num_rem(&temp, c, d, 0);
2587 if (s) goto err;
2588 }
2589
2590 s = bc_num_mul(&base, &base, &temp, 0);
2591 if (s) goto err;
2592 s = bc_num_rem(&temp, c, &base, 0);
2593 if (s) goto err;
2594 }
2595
2596err:
2597 bc_num_free(&temp);
2598 bc_num_free(&two);
2599 bc_num_free(&exp);
2600 bc_num_free(&base);
2601 return s;
2602}
2603#endif // ENABLE_DC
2604
2605static int bc_id_cmp(const void *e1, const void *e2)
2606{
2607 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2608}
2609
2610static void bc_id_free(void *id)
2611{
2612 free(((BcId *) id)->name);
2613}
2614
2615static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2616{
2617 BcId a;
2618 size_t i;
2619
2620 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002621 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2622 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002623 }
2624
2625 a.idx = var;
2626 a.name = name;
2627
2628 bc_vec_push(&f->autos, &a);
2629
2630 return BC_STATUS_SUCCESS;
2631}
2632
2633static void bc_func_init(BcFunc *f)
2634{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002635 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002636 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2637 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2638 f->nparams = 0;
2639}
2640
2641static void bc_func_free(void *func)
2642{
2643 BcFunc *f = (BcFunc *) func;
2644 bc_vec_free(&f->code);
2645 bc_vec_free(&f->autos);
2646 bc_vec_free(&f->labels);
2647}
2648
2649static void bc_array_init(BcVec *a, bool nums)
2650{
2651 if (nums)
2652 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2653 else
2654 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2655 bc_array_expand(a, 1);
2656}
2657
2658static void bc_array_copy(BcVec *d, const BcVec *s)
2659{
2660 size_t i;
2661
Denys Vlasenko7d628012018-12-04 21:46:47 +01002662 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002663 bc_vec_expand(d, s->cap);
2664 d->len = s->len;
2665
2666 for (i = 0; i < s->len; ++i) {
2667 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2668 bc_num_init(dnum, snum->len);
2669 bc_num_copy(dnum, snum);
2670 }
2671}
2672
2673static void bc_array_expand(BcVec *a, size_t len)
2674{
2675 BcResultData data;
2676
2677 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2678 while (len > a->len) {
2679 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2680 bc_vec_push(a, &data.n);
2681 }
2682 }
2683 else {
2684 while (len > a->len) {
2685 bc_array_init(&data.v, true);
2686 bc_vec_push(a, &data.v);
2687 }
2688 }
2689}
2690
2691static void bc_string_free(void *string)
2692{
2693 free(*((char **) string));
2694}
2695
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002696#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002697static void bc_result_copy(BcResult *d, BcResult *src)
2698{
2699 d->t = src->t;
2700
2701 switch (d->t) {
2702
2703 case BC_RESULT_TEMP:
2704 case BC_RESULT_IBASE:
2705 case BC_RESULT_SCALE:
2706 case BC_RESULT_OBASE:
2707 {
2708 bc_num_init(&d->d.n, src->d.n.len);
2709 bc_num_copy(&d->d.n, &src->d.n);
2710 break;
2711 }
2712
2713 case BC_RESULT_VAR:
2714 case BC_RESULT_ARRAY:
2715 case BC_RESULT_ARRAY_ELEM:
2716 {
2717 d->d.id.name = xstrdup(src->d.id.name);
2718 break;
2719 }
2720
2721 case BC_RESULT_CONSTANT:
2722 case BC_RESULT_LAST:
2723 case BC_RESULT_ONE:
2724 case BC_RESULT_STR:
2725 {
2726 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2727 break;
2728 }
2729 }
2730}
2731#endif // ENABLE_DC
2732
2733static void bc_result_free(void *result)
2734{
2735 BcResult *r = (BcResult *) result;
2736
2737 switch (r->t) {
2738
2739 case BC_RESULT_TEMP:
2740 case BC_RESULT_IBASE:
2741 case BC_RESULT_SCALE:
2742 case BC_RESULT_OBASE:
2743 {
2744 bc_num_free(&r->d.n);
2745 break;
2746 }
2747
2748 case BC_RESULT_VAR:
2749 case BC_RESULT_ARRAY:
2750 case BC_RESULT_ARRAY_ELEM:
2751 {
2752 free(r->d.id.name);
2753 break;
2754 }
2755
2756 default:
2757 {
2758 // Do nothing.
2759 break;
2760 }
2761 }
2762}
2763
2764static void bc_lex_lineComment(BcLex *l)
2765{
2766 l->t.t = BC_LEX_WHITESPACE;
2767 while (l->i < l->len && l->buf[l->i++] != '\n');
2768 --l->i;
2769}
2770
2771static void bc_lex_whitespace(BcLex *l)
2772{
2773 char c;
2774 l->t.t = BC_LEX_WHITESPACE;
2775 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2776}
2777
2778static BcStatus bc_lex_number(BcLex *l, char start)
2779{
2780 const char *buf = l->buf + l->i;
2781 size_t len, hits = 0, bslashes = 0, i = 0, j;
2782 char c = buf[i];
2783 bool last_pt, pt = start == '.';
2784
2785 last_pt = pt;
2786 l->t.t = BC_LEX_NUMBER;
2787
2788 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2789 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2790 {
2791 if (c != '\\') {
2792 last_pt = c == '.';
2793 pt = pt || last_pt;
2794 }
2795 else {
2796 ++i;
2797 bslashes += 1;
2798 }
2799
2800 c = buf[++i];
2801 }
2802
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002803 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002804 if (len > BC_MAX_NUM)
2805 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002806
Denys Vlasenko7d628012018-12-04 21:46:47 +01002807 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002808 bc_vec_expand(&l->t.v, len + 1);
2809 bc_vec_push(&l->t.v, &start);
2810
2811 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2812
2813 c = buf[j];
2814
2815 // If we have hit a backslash, skip it. We don't have
2816 // to check for a newline because it's guaranteed.
2817 if (hits < bslashes && c == '\\') {
2818 ++hits;
2819 ++j;
2820 continue;
2821 }
2822
2823 bc_vec_push(&l->t.v, &c);
2824 }
2825
2826 bc_vec_pushByte(&l->t.v, '\0');
2827 l->i += i;
2828
2829 return BC_STATUS_SUCCESS;
2830}
2831
2832static BcStatus bc_lex_name(BcLex *l)
2833{
2834 size_t i = 0;
2835 const char *buf = l->buf + l->i - 1;
2836 char c = buf[i];
2837
2838 l->t.t = BC_LEX_NAME;
2839
2840 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2841
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002842 if (i > BC_MAX_STRING)
2843 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002844 bc_vec_string(&l->t.v, i, buf);
2845
2846 // Increment the index. We minus 1 because it has already been incremented.
2847 l->i += i - 1;
2848
2849 return BC_STATUS_SUCCESS;
2850}
2851
2852static void bc_lex_init(BcLex *l, BcLexNext next)
2853{
2854 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002855 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002856}
2857
2858static void bc_lex_free(BcLex *l)
2859{
2860 bc_vec_free(&l->t.v);
2861}
2862
2863static void bc_lex_file(BcLex *l, const char *file)
2864{
2865 l->line = 1;
2866 l->newline = false;
2867 l->f = file;
2868}
2869
2870static BcStatus bc_lex_next(BcLex *l)
2871{
2872 BcStatus s;
2873
2874 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002875 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002876
2877 l->line += l->newline;
2878 l->t.t = BC_LEX_EOF;
2879
2880 l->newline = (l->i == l->len);
2881 if (l->newline) return BC_STATUS_SUCCESS;
2882
2883 // Loop until failure or we don't have whitespace. This
2884 // is so the parser doesn't get inundated with whitespace.
2885 do {
2886 s = l->next(l);
2887 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2888
2889 return s;
2890}
2891
2892static BcStatus bc_lex_text(BcLex *l, const char *text)
2893{
2894 l->buf = text;
2895 l->i = 0;
2896 l->len = strlen(text);
2897 l->t.t = l->t.last = BC_LEX_INVALID;
2898 return bc_lex_next(l);
2899}
2900
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002901#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002902static BcStatus bc_lex_identifier(BcLex *l)
2903{
2904 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002905 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06002906 const char *buf = l->buf + l->i - 1;
2907
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002908 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2909 const char *keyword8 = bc_lex_kws[i].name8;
2910 unsigned j = 0;
2911 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2912 j++;
2913 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06002914 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002915 if (keyword8[j] != '\0')
2916 continue;
2917 match:
2918 // buf starts with keyword bc_lex_kws[i]
2919 l->t.t = BC_LEX_KEY_1st_keyword + i;
2920 if ((1 << i) & POSIX_KWORD_MASK) {
2921 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
2922 if (s) return s;
2923 }
2924
2925 // We minus 1 because the index has already been incremented.
2926 l->i += j - 1;
2927 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06002928 }
2929
2930 s = bc_lex_name(l);
2931 if (s) return s;
2932
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002933 if (l->t.v.len > 2)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002934 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002935
2936 return s;
2937}
2938
2939static BcStatus bc_lex_string(BcLex *l)
2940{
2941 size_t len, nls = 0, i = l->i;
2942 char c;
2943
2944 l->t.t = BC_LEX_STR;
2945
2946 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2947
2948 if (c == '\0') {
2949 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002950 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002951 }
2952
2953 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002954 if (len > BC_MAX_STRING)
2955 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002956 bc_vec_string(&l->t.v, len, l->buf + l->i);
2957
2958 l->i = i + 1;
2959 l->line += nls;
2960
2961 return BC_STATUS_SUCCESS;
2962}
2963
2964static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2965{
2966 if (l->buf[l->i] == '=') {
2967 ++l->i;
2968 l->t.t = with;
2969 }
2970 else
2971 l->t.t = without;
2972}
2973
2974static BcStatus bc_lex_comment(BcLex *l)
2975{
2976 size_t i, nls = 0;
2977 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06002978
2979 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002980 i = ++l->i;
2981 for (;;) {
2982 char c = buf[i];
2983 check_star:
2984 if (c == '*') {
2985 c = buf[++i];
2986 if (c == '/')
2987 break;
2988 goto check_star;
2989 }
2990 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06002991 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002992 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002993 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002994 nls += (c == '\n');
2995 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06002996 }
2997
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002998 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002999 l->line += nls;
3000
3001 return BC_STATUS_SUCCESS;
3002}
3003
3004static BcStatus bc_lex_token(BcLex *l)
3005{
3006 BcStatus s = BC_STATUS_SUCCESS;
3007 char c = l->buf[l->i++], c2;
3008
3009 // This is the workhorse of the lexer.
3010 switch (c) {
3011
3012 case '\0':
3013 case '\n':
3014 {
3015 l->newline = true;
3016 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3017 break;
3018 }
3019
3020 case '\t':
3021 case '\v':
3022 case '\f':
3023 case '\r':
3024 case ' ':
3025 {
3026 bc_lex_whitespace(l);
3027 break;
3028 }
3029
3030 case '!':
3031 {
3032 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3033
3034 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003035 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003036 if (s) return s;
3037 }
3038
3039 break;
3040 }
3041
3042 case '"':
3043 {
3044 s = bc_lex_string(l);
3045 break;
3046 }
3047
3048 case '#':
3049 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003050 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003051 if (s) return s;
3052
3053 bc_lex_lineComment(l);
3054
3055 break;
3056 }
3057
3058 case '%':
3059 {
3060 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3061 break;
3062 }
3063
3064 case '&':
3065 {
3066 c2 = l->buf[l->i];
3067 if (c2 == '&') {
3068
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003069 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003070 if (s) return s;
3071
3072 ++l->i;
3073 l->t.t = BC_LEX_OP_BOOL_AND;
3074 }
3075 else {
3076 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003077 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003078 }
3079
3080 break;
3081 }
3082
3083 case '(':
3084 case ')':
3085 {
3086 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3087 break;
3088 }
3089
3090 case '*':
3091 {
3092 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3093 break;
3094 }
3095
3096 case '+':
3097 {
3098 c2 = l->buf[l->i];
3099 if (c2 == '+') {
3100 ++l->i;
3101 l->t.t = BC_LEX_OP_INC;
3102 }
3103 else
3104 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3105 break;
3106 }
3107
3108 case ',':
3109 {
3110 l->t.t = BC_LEX_COMMA;
3111 break;
3112 }
3113
3114 case '-':
3115 {
3116 c2 = l->buf[l->i];
3117 if (c2 == '-') {
3118 ++l->i;
3119 l->t.t = BC_LEX_OP_DEC;
3120 }
3121 else
3122 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3123 break;
3124 }
3125
3126 case '.':
3127 {
3128 if (isdigit(l->buf[l->i]))
3129 s = bc_lex_number(l, c);
3130 else {
3131 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003132 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003133 }
3134 break;
3135 }
3136
3137 case '/':
3138 {
3139 c2 = l->buf[l->i];
3140 if (c2 == '*')
3141 s = bc_lex_comment(l);
3142 else
3143 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3144 break;
3145 }
3146
3147 case '0':
3148 case '1':
3149 case '2':
3150 case '3':
3151 case '4':
3152 case '5':
3153 case '6':
3154 case '7':
3155 case '8':
3156 case '9':
3157 case 'A':
3158 case 'B':
3159 case 'C':
3160 case 'D':
3161 case 'E':
3162 case 'F':
3163 {
3164 s = bc_lex_number(l, c);
3165 break;
3166 }
3167
3168 case ';':
3169 {
3170 l->t.t = BC_LEX_SCOLON;
3171 break;
3172 }
3173
3174 case '<':
3175 {
3176 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3177 break;
3178 }
3179
3180 case '=':
3181 {
3182 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3183 break;
3184 }
3185
3186 case '>':
3187 {
3188 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3189 break;
3190 }
3191
3192 case '[':
3193 case ']':
3194 {
3195 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3196 break;
3197 }
3198
3199 case '\\':
3200 {
3201 if (l->buf[l->i] == '\n') {
3202 l->t.t = BC_LEX_WHITESPACE;
3203 ++l->i;
3204 }
3205 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003206 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003207 break;
3208 }
3209
3210 case '^':
3211 {
3212 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3213 break;
3214 }
3215
3216 case 'a':
3217 case 'b':
3218 case 'c':
3219 case 'd':
3220 case 'e':
3221 case 'f':
3222 case 'g':
3223 case 'h':
3224 case 'i':
3225 case 'j':
3226 case 'k':
3227 case 'l':
3228 case 'm':
3229 case 'n':
3230 case 'o':
3231 case 'p':
3232 case 'q':
3233 case 'r':
3234 case 's':
3235 case 't':
3236 case 'u':
3237 case 'v':
3238 case 'w':
3239 case 'x':
3240 case 'y':
3241 case 'z':
3242 {
3243 s = bc_lex_identifier(l);
3244 break;
3245 }
3246
3247 case '{':
3248 case '}':
3249 {
3250 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3251 break;
3252 }
3253
3254 case '|':
3255 {
3256 c2 = l->buf[l->i];
3257
3258 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003259 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003260 if (s) return s;
3261
3262 ++l->i;
3263 l->t.t = BC_LEX_OP_BOOL_OR;
3264 }
3265 else {
3266 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003267 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003268 }
3269
3270 break;
3271 }
3272
3273 default:
3274 {
3275 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003276 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003277 break;
3278 }
3279 }
3280
3281 return s;
3282}
3283#endif // ENABLE_BC
3284
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003285#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003286static BcStatus dc_lex_register(BcLex *l)
3287{
3288 BcStatus s = BC_STATUS_SUCCESS;
3289
3290 if (isspace(l->buf[l->i - 1])) {
3291 bc_lex_whitespace(l);
3292 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003293 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003294 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003295 else
3296 s = bc_lex_name(l);
3297 }
3298 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003299 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003300 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3301 bc_vec_pushByte(&l->t.v, '\0');
3302 l->t.t = BC_LEX_NAME;
3303 }
3304
3305 return s;
3306}
3307
3308static BcStatus dc_lex_string(BcLex *l)
3309{
3310 size_t depth = 1, nls = 0, i = l->i;
3311 char c;
3312
3313 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003314 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003315
3316 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3317
3318 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3319 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3320 nls += (c == '\n');
3321
3322 if (depth) bc_vec_push(&l->t.v, &c);
3323 }
3324
3325 if (c == '\0') {
3326 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003327 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003328 }
3329
3330 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003331 if (i - l->i > BC_MAX_STRING)
3332 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003333
3334 l->i = i;
3335 l->line += nls;
3336
3337 return BC_STATUS_SUCCESS;
3338}
3339
3340static BcStatus dc_lex_token(BcLex *l)
3341{
3342 BcStatus s = BC_STATUS_SUCCESS;
3343 char c = l->buf[l->i++], c2;
3344 size_t i;
3345
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003346 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3347 if (l->t.last == dc_lex_regs[i])
3348 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003349 }
3350
3351 if (c >= '%' && c <= '~' &&
3352 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3353 {
3354 return s;
3355 }
3356
3357 // This is the workhorse of the lexer.
3358 switch (c) {
3359
3360 case '\0':
3361 {
3362 l->t.t = BC_LEX_EOF;
3363 break;
3364 }
3365
3366 case '\n':
3367 case '\t':
3368 case '\v':
3369 case '\f':
3370 case '\r':
3371 case ' ':
3372 {
3373 l->newline = (c == '\n');
3374 bc_lex_whitespace(l);
3375 break;
3376 }
3377
3378 case '!':
3379 {
3380 c2 = l->buf[l->i];
3381
3382 if (c2 == '=')
3383 l->t.t = BC_LEX_OP_REL_NE;
3384 else if (c2 == '<')
3385 l->t.t = BC_LEX_OP_REL_LE;
3386 else if (c2 == '>')
3387 l->t.t = BC_LEX_OP_REL_GE;
3388 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003389 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003390
3391 ++l->i;
3392 break;
3393 }
3394
3395 case '#':
3396 {
3397 bc_lex_lineComment(l);
3398 break;
3399 }
3400
3401 case '.':
3402 {
3403 if (isdigit(l->buf[l->i]))
3404 s = bc_lex_number(l, c);
3405 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003406 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003407 break;
3408 }
3409
3410 case '0':
3411 case '1':
3412 case '2':
3413 case '3':
3414 case '4':
3415 case '5':
3416 case '6':
3417 case '7':
3418 case '8':
3419 case '9':
3420 case 'A':
3421 case 'B':
3422 case 'C':
3423 case 'D':
3424 case 'E':
3425 case 'F':
3426 {
3427 s = bc_lex_number(l, c);
3428 break;
3429 }
3430
3431 case '[':
3432 {
3433 s = dc_lex_string(l);
3434 break;
3435 }
3436
3437 default:
3438 {
3439 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003440 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003441 break;
3442 }
3443 }
3444
3445 return s;
3446}
3447#endif // ENABLE_DC
3448
3449static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3450{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003451 bc_program_addFunc(name, idx);
3452 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003453}
3454
3455static void bc_parse_pushName(BcParse *p, char *name)
3456{
3457 size_t i = 0, len = strlen(name);
3458
3459 for (; i < len; ++i) bc_parse_push(p, name[i]);
3460 bc_parse_push(p, BC_PARSE_STREND);
3461
3462 free(name);
3463}
3464
3465static void bc_parse_pushIndex(BcParse *p, size_t idx)
3466{
3467 unsigned char amt, i, nums[sizeof(size_t)];
3468
3469 for (amt = 0; idx; ++amt) {
3470 nums[amt] = (char) idx;
3471 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3472 }
3473
3474 bc_parse_push(p, amt);
3475 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3476}
3477
3478static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3479{
3480 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003481 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003482
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003483 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003484
3485 bc_parse_push(p, BC_INST_NUM);
3486 bc_parse_pushIndex(p, idx);
3487
3488 ++(*nexs);
3489 (*prev) = BC_INST_NUM;
3490}
3491
3492static BcStatus bc_parse_text(BcParse *p, const char *text)
3493{
3494 BcStatus s;
3495
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003496 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003497
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003498 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003499 p->l.t.t = BC_LEX_INVALID;
3500 s = p->parse(p);
3501 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003502 if (!BC_PARSE_CAN_EXEC(p))
3503 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003504 }
3505
3506 return bc_lex_text(&p->l, text);
3507}
3508
Denys Vlasenkod38af482018-12-04 19:11:02 +01003509// Called when bc/dc_parse_parse() detects a failure,
3510// resets parsing structures.
3511static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003512{
3513 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003514 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003515 bc_vec_pop_all(&p->func->code);
3516 bc_vec_pop_all(&p->func->autos);
3517 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003518
3519 bc_parse_updateFunc(p, BC_PROG_MAIN);
3520 }
3521
3522 p->l.i = p->l.len;
3523 p->l.t.t = BC_LEX_EOF;
3524 p->auto_part = (p->nbraces = 0);
3525
3526 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003527 bc_vec_pop_all(&p->exits);
3528 bc_vec_pop_all(&p->conds);
3529 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003530
Denys Vlasenkod38af482018-12-04 19:11:02 +01003531 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003532}
3533
3534static void bc_parse_free(BcParse *p)
3535{
3536 bc_vec_free(&p->flags);
3537 bc_vec_free(&p->exits);
3538 bc_vec_free(&p->conds);
3539 bc_vec_free(&p->ops);
3540 bc_lex_free(&p->l);
3541}
3542
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003543static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003544 BcParseParse parse, BcLexNext next)
3545{
3546 memset(p, 0, sizeof(BcParse));
3547
3548 bc_lex_init(&p->l, next);
3549 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3550 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3551 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3552 bc_vec_pushByte(&p->flags, 0);
3553 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3554
3555 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003556 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003557 bc_parse_updateFunc(p, func);
3558}
3559
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003560#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003561static BcStatus bc_parse_else(BcParse *p);
3562static BcStatus bc_parse_stmt(BcParse *p);
3563
3564static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3565 size_t *nexprs, bool next)
3566{
3567 BcStatus s = BC_STATUS_SUCCESS;
3568 BcLexType t;
3569 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3570 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3571
3572 while (p->ops.len > start) {
3573
3574 t = BC_PARSE_TOP_OP(p);
3575 if (t == BC_LEX_LPAREN) break;
3576
3577 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3578 if (l >= r && (l != r || !left)) break;
3579
3580 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3581 bc_vec_pop(&p->ops);
3582 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3583 }
3584
3585 bc_vec_push(&p->ops, &type);
3586 if (next) s = bc_lex_next(&p->l);
3587
3588 return s;
3589}
3590
3591static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3592{
3593 BcLexType top;
3594
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003595 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003596 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003597 top = BC_PARSE_TOP_OP(p);
3598
3599 while (top != BC_LEX_LPAREN) {
3600
3601 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3602
3603 bc_vec_pop(&p->ops);
3604 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3605
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003606 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003607 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003608 top = BC_PARSE_TOP_OP(p);
3609 }
3610
3611 bc_vec_pop(&p->ops);
3612
3613 return bc_lex_next(&p->l);
3614}
3615
3616static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3617{
3618 BcStatus s;
3619 bool comma = false;
3620 size_t nparams;
3621
3622 s = bc_lex_next(&p->l);
3623 if (s) return s;
3624
3625 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3626
3627 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3628 s = bc_parse_expr(p, flags, bc_parse_next_param);
3629 if (s) return s;
3630
3631 comma = p->l.t.t == BC_LEX_COMMA;
3632 if (comma) {
3633 s = bc_lex_next(&p->l);
3634 if (s) return s;
3635 }
3636 }
3637
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003638 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003639 bc_parse_push(p, BC_INST_CALL);
3640 bc_parse_pushIndex(p, nparams);
3641
3642 return BC_STATUS_SUCCESS;
3643}
3644
3645static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3646{
3647 BcStatus s;
3648 BcId entry, *entry_ptr;
3649 size_t idx;
3650
3651 entry.name = name;
3652
3653 s = bc_parse_params(p, flags);
3654 if (s) goto err;
3655
3656 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003657 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003658 goto err;
3659 }
3660
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003661 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003662
3663 if (idx == BC_VEC_INVALID_IDX) {
3664 name = xstrdup(entry.name);
3665 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003666 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003667 free(entry.name);
3668 }
3669 else
3670 free(name);
3671
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003672 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003673 bc_parse_pushIndex(p, entry_ptr->idx);
3674
3675 return bc_lex_next(&p->l);
3676
3677err:
3678 free(name);
3679 return s;
3680}
3681
3682static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3683{
3684 BcStatus s;
3685 char *name;
3686
3687 name = xstrdup(p->l.t.v.v);
3688 s = bc_lex_next(&p->l);
3689 if (s) goto err;
3690
3691 if (p->l.t.t == BC_LEX_LBRACKET) {
3692
3693 s = bc_lex_next(&p->l);
3694 if (s) goto err;
3695
3696 if (p->l.t.t == BC_LEX_RBRACKET) {
3697
3698 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003699 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003700 goto err;
3701 }
3702
3703 *type = BC_INST_ARRAY;
3704 }
3705 else {
3706
3707 *type = BC_INST_ARRAY_ELEM;
3708
3709 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3710 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3711 if (s) goto err;
3712 }
3713
3714 s = bc_lex_next(&p->l);
3715 if (s) goto err;
3716 bc_parse_push(p, *type);
3717 bc_parse_pushName(p, name);
3718 }
3719 else if (p->l.t.t == BC_LEX_LPAREN) {
3720
3721 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003722 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003723 goto err;
3724 }
3725
3726 *type = BC_INST_CALL;
3727 s = bc_parse_call(p, name, flags);
3728 }
3729 else {
3730 *type = BC_INST_VAR;
3731 bc_parse_push(p, BC_INST_VAR);
3732 bc_parse_pushName(p, name);
3733 }
3734
3735 return s;
3736
3737err:
3738 free(name);
3739 return s;
3740}
3741
3742static BcStatus bc_parse_read(BcParse *p)
3743{
3744 BcStatus s;
3745
3746 s = bc_lex_next(&p->l);
3747 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003748 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003749
3750 s = bc_lex_next(&p->l);
3751 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003752 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003753
3754 bc_parse_push(p, BC_INST_READ);
3755
3756 return bc_lex_next(&p->l);
3757}
3758
3759static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3760 BcInst *prev)
3761{
3762 BcStatus s;
3763
3764 s = bc_lex_next(&p->l);
3765 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003766 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003767
3768 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3769
3770 s = bc_lex_next(&p->l);
3771 if (s) return s;
3772
3773 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3774 if (s) return s;
3775
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003776 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003777
3778 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3779 bc_parse_push(p, *prev);
3780
3781 return bc_lex_next(&p->l);
3782}
3783
3784static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3785{
3786 BcStatus s;
3787
3788 s = bc_lex_next(&p->l);
3789 if (s) return s;
3790
3791 if (p->l.t.t != BC_LEX_LPAREN) {
3792 *type = BC_INST_SCALE;
3793 bc_parse_push(p, BC_INST_SCALE);
3794 return BC_STATUS_SUCCESS;
3795 }
3796
3797 *type = BC_INST_SCALE_FUNC;
3798 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3799
3800 s = bc_lex_next(&p->l);
3801 if (s) return s;
3802
3803 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3804 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003805 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003806 bc_parse_push(p, BC_INST_SCALE_FUNC);
3807
3808 return bc_lex_next(&p->l);
3809}
3810
3811static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3812 size_t *nexprs, uint8_t flags)
3813{
3814 BcStatus s;
3815 BcLexType type;
3816 char inst;
3817 BcInst etype = *prev;
3818
3819 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3820 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3821 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3822 {
3823 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3824 bc_parse_push(p, inst);
3825 s = bc_lex_next(&p->l);
3826 }
3827 else {
3828
3829 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3830 *paren_expr = true;
3831
3832 s = bc_lex_next(&p->l);
3833 if (s) return s;
3834 type = p->l.t.t;
3835
3836 // Because we parse the next part of the expression
3837 // right here, we need to increment this.
3838 *nexprs = *nexprs + 1;
3839
3840 switch (type) {
3841
3842 case BC_LEX_NAME:
3843 {
3844 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3845 break;
3846 }
3847
3848 case BC_LEX_KEY_IBASE:
3849 case BC_LEX_KEY_LAST:
3850 case BC_LEX_KEY_OBASE:
3851 {
3852 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3853 s = bc_lex_next(&p->l);
3854 break;
3855 }
3856
3857 case BC_LEX_KEY_SCALE:
3858 {
3859 s = bc_lex_next(&p->l);
3860 if (s) return s;
3861 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003862 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003863 else
3864 bc_parse_push(p, BC_INST_SCALE);
3865 break;
3866 }
3867
3868 default:
3869 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003870 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003871 break;
3872 }
3873 }
3874
3875 if (!s) bc_parse_push(p, inst);
3876 }
3877
3878 return s;
3879}
3880
3881static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3882 bool rparen, size_t *nexprs)
3883{
3884 BcStatus s;
3885 BcLexType type;
3886 BcInst etype = *prev;
3887
3888 s = bc_lex_next(&p->l);
3889 if (s) return s;
3890
3891 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3892 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3893 BC_LEX_OP_MINUS :
3894 BC_LEX_NEG;
3895 *prev = BC_PARSE_TOKEN_INST(type);
3896
3897 // We can just push onto the op stack because this is the largest
3898 // precedence operator that gets pushed. Inc/dec does not.
3899 if (type != BC_LEX_OP_MINUS)
3900 bc_vec_push(&p->ops, &type);
3901 else
3902 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3903
3904 return s;
3905}
3906
3907static BcStatus bc_parse_string(BcParse *p, char inst)
3908{
3909 char *str = xstrdup(p->l.t.v.v);
3910
3911 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003912 bc_parse_pushIndex(p, G.prog.strs.len);
3913 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003914 bc_parse_push(p, inst);
3915
3916 return bc_lex_next(&p->l);
3917}
3918
3919static BcStatus bc_parse_print(BcParse *p)
3920{
3921 BcStatus s;
3922 BcLexType type;
3923 bool comma = false;
3924
3925 s = bc_lex_next(&p->l);
3926 if (s) return s;
3927
3928 type = p->l.t.t;
3929
3930 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003931 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003932
3933 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3934
3935 if (type == BC_LEX_STR)
3936 s = bc_parse_string(p, BC_INST_PRINT_POP);
3937 else {
3938 s = bc_parse_expr(p, 0, bc_parse_next_print);
3939 if (s) return s;
3940 bc_parse_push(p, BC_INST_PRINT_POP);
3941 }
3942
3943 if (s) return s;
3944
3945 comma = p->l.t.t == BC_LEX_COMMA;
3946 if (comma) s = bc_lex_next(&p->l);
3947 type = p->l.t.t;
3948 }
3949
3950 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003951 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003952
3953 return bc_lex_next(&p->l);
3954}
3955
3956static BcStatus bc_parse_return(BcParse *p)
3957{
3958 BcStatus s;
3959 BcLexType t;
3960 bool paren;
3961
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003962 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003963
3964 s = bc_lex_next(&p->l);
3965 if (s) return s;
3966
3967 t = p->l.t.t;
3968 paren = t == BC_LEX_LPAREN;
3969
3970 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3971 bc_parse_push(p, BC_INST_RET0);
3972 else {
3973
3974 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3975 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3976 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003977
3978 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003979 bc_parse_push(p, BC_INST_RET0);
3980 s = bc_lex_next(&p->l);
3981 if (s) return s;
3982 }
3983
3984 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003985 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06003986 if (s) return s;
3987 }
3988
3989 bc_parse_push(p, BC_INST_RET);
3990 }
3991
3992 return s;
3993}
3994
3995static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3996{
3997 BcStatus s = BC_STATUS_SUCCESS;
3998
3999 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004000 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004001
4002 if (brace) {
4003
4004 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004005 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004006 --p->nbraces;
4007 s = bc_lex_next(&p->l);
4008 if (s) return s;
4009 }
4010 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004011 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004012 }
4013
4014 if (BC_PARSE_IF(p)) {
4015
4016 uint8_t *flag_ptr;
4017
4018 while (p->l.t.t == BC_LEX_NLINE) {
4019 s = bc_lex_next(&p->l);
4020 if (s) return s;
4021 }
4022
4023 bc_vec_pop(&p->flags);
4024
4025 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4026 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4027
4028 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4029 }
4030 else if (BC_PARSE_ELSE(p)) {
4031
4032 BcInstPtr *ip;
4033 size_t *label;
4034
4035 bc_vec_pop(&p->flags);
4036
4037 ip = bc_vec_top(&p->exits);
4038 label = bc_vec_item(&p->func->labels, ip->idx);
4039 *label = p->func->code.len;
4040
4041 bc_vec_pop(&p->exits);
4042 }
4043 else if (BC_PARSE_FUNC_INNER(p)) {
4044 bc_parse_push(p, BC_INST_RET0);
4045 bc_parse_updateFunc(p, BC_PROG_MAIN);
4046 bc_vec_pop(&p->flags);
4047 }
4048 else {
4049
4050 BcInstPtr *ip = bc_vec_top(&p->exits);
4051 size_t *label = bc_vec_top(&p->conds);
4052
4053 bc_parse_push(p, BC_INST_JUMP);
4054 bc_parse_pushIndex(p, *label);
4055
4056 label = bc_vec_item(&p->func->labels, ip->idx);
4057 *label = p->func->code.len;
4058
4059 bc_vec_pop(&p->flags);
4060 bc_vec_pop(&p->exits);
4061 bc_vec_pop(&p->conds);
4062 }
4063
4064 return s;
4065}
4066
4067static void bc_parse_startBody(BcParse *p, uint8_t flags)
4068{
4069 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4070 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4071 flags |= BC_PARSE_FLAG_BODY;
4072 bc_vec_push(&p->flags, &flags);
4073}
4074
4075static void bc_parse_noElse(BcParse *p)
4076{
4077 BcInstPtr *ip;
4078 size_t *label;
4079 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4080
4081 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4082
4083 ip = bc_vec_top(&p->exits);
4084 label = bc_vec_item(&p->func->labels, ip->idx);
4085 *label = p->func->code.len;
4086
4087 bc_vec_pop(&p->exits);
4088}
4089
4090static BcStatus bc_parse_if(BcParse *p)
4091{
4092 BcStatus s;
4093 BcInstPtr ip;
4094
4095 s = bc_lex_next(&p->l);
4096 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004097 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004098
4099 s = bc_lex_next(&p->l);
4100 if (s) return s;
4101 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4102 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004103 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004104
4105 s = bc_lex_next(&p->l);
4106 if (s) return s;
4107 bc_parse_push(p, BC_INST_JUMP_ZERO);
4108
4109 ip.idx = p->func->labels.len;
4110 ip.func = ip.len = 0;
4111
4112 bc_parse_pushIndex(p, ip.idx);
4113 bc_vec_push(&p->exits, &ip);
4114 bc_vec_push(&p->func->labels, &ip.idx);
4115 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4116
4117 return BC_STATUS_SUCCESS;
4118}
4119
4120static BcStatus bc_parse_else(BcParse *p)
4121{
4122 BcInstPtr ip;
4123
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004124 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004125
4126 ip.idx = p->func->labels.len;
4127 ip.func = ip.len = 0;
4128
4129 bc_parse_push(p, BC_INST_JUMP);
4130 bc_parse_pushIndex(p, ip.idx);
4131
4132 bc_parse_noElse(p);
4133
4134 bc_vec_push(&p->exits, &ip);
4135 bc_vec_push(&p->func->labels, &ip.idx);
4136 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4137
4138 return bc_lex_next(&p->l);
4139}
4140
4141static BcStatus bc_parse_while(BcParse *p)
4142{
4143 BcStatus s;
4144 BcInstPtr ip;
4145
4146 s = bc_lex_next(&p->l);
4147 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004148 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004149 s = bc_lex_next(&p->l);
4150 if (s) return s;
4151
4152 ip.idx = p->func->labels.len;
4153
4154 bc_vec_push(&p->func->labels, &p->func->code.len);
4155 bc_vec_push(&p->conds, &ip.idx);
4156
4157 ip.idx = p->func->labels.len;
4158 ip.func = 1;
4159 ip.len = 0;
4160
4161 bc_vec_push(&p->exits, &ip);
4162 bc_vec_push(&p->func->labels, &ip.idx);
4163
4164 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4165 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004166 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004167 s = bc_lex_next(&p->l);
4168 if (s) return s;
4169
4170 bc_parse_push(p, BC_INST_JUMP_ZERO);
4171 bc_parse_pushIndex(p, ip.idx);
4172 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4173
4174 return BC_STATUS_SUCCESS;
4175}
4176
4177static BcStatus bc_parse_for(BcParse *p)
4178{
4179 BcStatus s;
4180 BcInstPtr ip;
4181 size_t cond_idx, exit_idx, body_idx, update_idx;
4182
4183 s = bc_lex_next(&p->l);
4184 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004185 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004186 s = bc_lex_next(&p->l);
4187 if (s) return s;
4188
4189 if (p->l.t.t != BC_LEX_SCOLON)
4190 s = bc_parse_expr(p, 0, bc_parse_next_for);
4191 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004192 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004193
4194 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004195 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004196 s = bc_lex_next(&p->l);
4197 if (s) return s;
4198
4199 cond_idx = p->func->labels.len;
4200 update_idx = cond_idx + 1;
4201 body_idx = update_idx + 1;
4202 exit_idx = body_idx + 1;
4203
4204 bc_vec_push(&p->func->labels, &p->func->code.len);
4205
4206 if (p->l.t.t != BC_LEX_SCOLON)
4207 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4208 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004209 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004210
4211 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004212 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004213
4214 s = bc_lex_next(&p->l);
4215 if (s) return s;
4216
4217 bc_parse_push(p, BC_INST_JUMP_ZERO);
4218 bc_parse_pushIndex(p, exit_idx);
4219 bc_parse_push(p, BC_INST_JUMP);
4220 bc_parse_pushIndex(p, body_idx);
4221
4222 ip.idx = p->func->labels.len;
4223
4224 bc_vec_push(&p->conds, &update_idx);
4225 bc_vec_push(&p->func->labels, &p->func->code.len);
4226
4227 if (p->l.t.t != BC_LEX_RPAREN)
4228 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4229 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004230 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004231
4232 if (s) return s;
4233
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004234 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004235 bc_parse_push(p, BC_INST_JUMP);
4236 bc_parse_pushIndex(p, cond_idx);
4237 bc_vec_push(&p->func->labels, &p->func->code.len);
4238
4239 ip.idx = exit_idx;
4240 ip.func = 1;
4241 ip.len = 0;
4242
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_lex_next(&p->l);
4246 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4247
4248 return BC_STATUS_SUCCESS;
4249}
4250
4251static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4252{
4253 BcStatus s;
4254 size_t i;
4255 BcInstPtr *ip;
4256
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004257 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004258
4259 if (type == BC_LEX_KEY_BREAK) {
4260
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004261 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004262
4263 i = p->exits.len - 1;
4264 ip = bc_vec_item(&p->exits, i);
4265
4266 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004267 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004268
4269 i = ip->idx;
4270 }
4271 else
4272 i = *((size_t *) bc_vec_top(&p->conds));
4273
4274 bc_parse_push(p, BC_INST_JUMP);
4275 bc_parse_pushIndex(p, i);
4276
4277 s = bc_lex_next(&p->l);
4278 if (s) return s;
4279
4280 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004281 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004282
4283 return bc_lex_next(&p->l);
4284}
4285
4286static BcStatus bc_parse_func(BcParse *p)
4287{
4288 BcStatus s;
4289 bool var, comma = false;
4290 uint8_t flags;
4291 char *name;
4292
4293 s = bc_lex_next(&p->l);
4294 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004295 if (p->l.t.t != BC_LEX_NAME)
4296 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004297
4298 name = xstrdup(p->l.t.v.v);
4299 bc_parse_addFunc(p, name, &p->fidx);
4300
4301 s = bc_lex_next(&p->l);
4302 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004303 if (p->l.t.t != BC_LEX_LPAREN)
4304 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004305 s = bc_lex_next(&p->l);
4306 if (s) return s;
4307
4308 while (p->l.t.t != BC_LEX_RPAREN) {
4309
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004310 if (p->l.t.t != BC_LEX_NAME)
4311 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004312
4313 ++p->func->nparams;
4314
4315 name = xstrdup(p->l.t.v.v);
4316 s = bc_lex_next(&p->l);
4317 if (s) goto err;
4318
4319 var = p->l.t.t != BC_LEX_LBRACKET;
4320
4321 if (!var) {
4322
4323 s = bc_lex_next(&p->l);
4324 if (s) goto err;
4325
4326 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004327 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004328 goto err;
4329 }
4330
4331 s = bc_lex_next(&p->l);
4332 if (s) goto err;
4333 }
4334
4335 comma = p->l.t.t == BC_LEX_COMMA;
4336 if (comma) {
4337 s = bc_lex_next(&p->l);
4338 if (s) goto err;
4339 }
4340
4341 s = bc_func_insert(p->func, name, var);
4342 if (s) goto err;
4343 }
4344
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004345 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004346
4347 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4348 bc_parse_startBody(p, flags);
4349
4350 s = bc_lex_next(&p->l);
4351 if (s) return s;
4352
4353 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004354 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 -06004355
4356 return s;
4357
4358err:
4359 free(name);
4360 return s;
4361}
4362
4363static BcStatus bc_parse_auto(BcParse *p)
4364{
4365 BcStatus s;
4366 bool comma, var, one;
4367 char *name;
4368
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004369 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004370 s = bc_lex_next(&p->l);
4371 if (s) return s;
4372
4373 p->auto_part = comma = false;
4374 one = p->l.t.t == BC_LEX_NAME;
4375
4376 while (p->l.t.t == BC_LEX_NAME) {
4377
4378 name = xstrdup(p->l.t.v.v);
4379 s = bc_lex_next(&p->l);
4380 if (s) goto err;
4381
4382 var = p->l.t.t != BC_LEX_LBRACKET;
4383 if (!var) {
4384
4385 s = bc_lex_next(&p->l);
4386 if (s) goto err;
4387
4388 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004389 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004390 goto err;
4391 }
4392
4393 s = bc_lex_next(&p->l);
4394 if (s) goto err;
4395 }
4396
4397 comma = p->l.t.t == BC_LEX_COMMA;
4398 if (comma) {
4399 s = bc_lex_next(&p->l);
4400 if (s) goto err;
4401 }
4402
4403 s = bc_func_insert(p->func, name, var);
4404 if (s) goto err;
4405 }
4406
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004407 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004408 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004409
4410 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004411 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004412
4413 return bc_lex_next(&p->l);
4414
4415err:
4416 free(name);
4417 return s;
4418}
4419
4420static BcStatus bc_parse_body(BcParse *p, bool brace)
4421{
4422 BcStatus s = BC_STATUS_SUCCESS;
4423 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4424
4425 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4426
4427 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4428
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004429 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004430 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4431
4432 if (!p->auto_part) {
4433 s = bc_parse_auto(p);
4434 if (s) return s;
4435 }
4436
4437 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4438 }
4439 else {
4440 s = bc_parse_stmt(p);
4441 if (!s && !brace) s = bc_parse_endBody(p, false);
4442 }
4443
4444 return s;
4445}
4446
4447static BcStatus bc_parse_stmt(BcParse *p)
4448{
4449 BcStatus s = BC_STATUS_SUCCESS;
4450
4451 switch (p->l.t.t) {
4452
4453 case BC_LEX_NLINE:
4454 {
4455 return bc_lex_next(&p->l);
4456 }
4457
4458 case BC_LEX_KEY_ELSE:
4459 {
4460 p->auto_part = false;
4461 break;
4462 }
4463
4464 case BC_LEX_LBRACE:
4465 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004466 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004467
4468 ++p->nbraces;
4469 s = bc_lex_next(&p->l);
4470 if (s) return s;
4471
4472 return bc_parse_body(p, true);
4473 }
4474
4475 case BC_LEX_KEY_AUTO:
4476 {
4477 return bc_parse_auto(p);
4478 }
4479
4480 default:
4481 {
4482 p->auto_part = false;
4483
4484 if (BC_PARSE_IF_END(p)) {
4485 bc_parse_noElse(p);
4486 return BC_STATUS_SUCCESS;
4487 }
4488 else if (BC_PARSE_BODY(p))
4489 return bc_parse_body(p, false);
4490
4491 break;
4492 }
4493 }
4494
4495 switch (p->l.t.t) {
4496
4497 case BC_LEX_OP_INC:
4498 case BC_LEX_OP_DEC:
4499 case BC_LEX_OP_MINUS:
4500 case BC_LEX_OP_BOOL_NOT:
4501 case BC_LEX_LPAREN:
4502 case BC_LEX_NAME:
4503 case BC_LEX_NUMBER:
4504 case BC_LEX_KEY_IBASE:
4505 case BC_LEX_KEY_LAST:
4506 case BC_LEX_KEY_LENGTH:
4507 case BC_LEX_KEY_OBASE:
4508 case BC_LEX_KEY_READ:
4509 case BC_LEX_KEY_SCALE:
4510 case BC_LEX_KEY_SQRT:
4511 {
4512 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4513 break;
4514 }
4515
4516 case BC_LEX_KEY_ELSE:
4517 {
4518 s = bc_parse_else(p);
4519 break;
4520 }
4521
4522 case BC_LEX_SCOLON:
4523 {
4524 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4525 break;
4526 }
4527
4528 case BC_LEX_RBRACE:
4529 {
4530 s = bc_parse_endBody(p, true);
4531 break;
4532 }
4533
4534 case BC_LEX_STR:
4535 {
4536 s = bc_parse_string(p, BC_INST_PRINT_STR);
4537 break;
4538 }
4539
4540 case BC_LEX_KEY_BREAK:
4541 case BC_LEX_KEY_CONTINUE:
4542 {
4543 s = bc_parse_loopExit(p, p->l.t.t);
4544 break;
4545 }
4546
4547 case BC_LEX_KEY_FOR:
4548 {
4549 s = bc_parse_for(p);
4550 break;
4551 }
4552
4553 case BC_LEX_KEY_HALT:
4554 {
4555 bc_parse_push(p, BC_INST_HALT);
4556 s = bc_lex_next(&p->l);
4557 break;
4558 }
4559
4560 case BC_LEX_KEY_IF:
4561 {
4562 s = bc_parse_if(p);
4563 break;
4564 }
4565
4566 case BC_LEX_KEY_LIMITS:
4567 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004568 // "limits" is a compile-time command,
4569 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004570 s = bc_lex_next(&p->l);
4571 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004572 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4573 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4574 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4575 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4576 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4577 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4578 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4579 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004580 break;
4581 }
4582
4583 case BC_LEX_KEY_PRINT:
4584 {
4585 s = bc_parse_print(p);
4586 break;
4587 }
4588
4589 case BC_LEX_KEY_QUIT:
4590 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004591 // "quit" is a compile-time command. For example,
4592 // "if (0 == 1) quit" terminates when parsing the statement,
4593 // not when it is executed
4594 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004595 }
4596
4597 case BC_LEX_KEY_RETURN:
4598 {
4599 s = bc_parse_return(p);
4600 break;
4601 }
4602
4603 case BC_LEX_KEY_WHILE:
4604 {
4605 s = bc_parse_while(p);
4606 break;
4607 }
4608
4609 default:
4610 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004611 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004612 break;
4613 }
4614 }
4615
4616 return s;
4617}
4618
4619static BcStatus bc_parse_parse(BcParse *p)
4620{
4621 BcStatus s;
4622
4623 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004624 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 -06004625 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004626 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004627 s = bc_parse_func(p);
4628 }
4629 else
4630 s = bc_parse_stmt(p);
4631
Denys Vlasenkod38af482018-12-04 19:11:02 +01004632 if (s || G_interrupt) {
4633 bc_parse_reset(p);
4634 s = BC_STATUS_FAILURE;
4635 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004636
4637 return s;
4638}
4639
4640static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4641{
4642 BcStatus s = BC_STATUS_SUCCESS;
4643 BcInst prev = BC_INST_PRINT;
4644 BcLexType top, t = p->l.t.t;
4645 size_t nexprs = 0, ops_bgn = p->ops.len;
4646 uint32_t i, nparens, nrelops;
4647 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4648
4649 paren_first = p->l.t.t == BC_LEX_LPAREN;
4650 nparens = nrelops = 0;
4651 paren_expr = rprn = done = get_token = assign = false;
4652 bin_last = true;
4653
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004654 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004655 switch (t) {
4656
4657 case BC_LEX_OP_INC:
4658 case BC_LEX_OP_DEC:
4659 {
4660 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4661 rprn = get_token = bin_last = false;
4662 break;
4663 }
4664
4665 case BC_LEX_OP_MINUS:
4666 {
4667 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4668 rprn = get_token = false;
4669 bin_last = prev == BC_INST_MINUS;
4670 break;
4671 }
4672
4673 case BC_LEX_OP_ASSIGN_POWER:
4674 case BC_LEX_OP_ASSIGN_MULTIPLY:
4675 case BC_LEX_OP_ASSIGN_DIVIDE:
4676 case BC_LEX_OP_ASSIGN_MODULUS:
4677 case BC_LEX_OP_ASSIGN_PLUS:
4678 case BC_LEX_OP_ASSIGN_MINUS:
4679 case BC_LEX_OP_ASSIGN:
4680 {
4681 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4682 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4683 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4684 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004685 s = bc_error("bad assignment:"
4686 " left side must be scale,"
4687 " ibase, obase, last, var,"
4688 " or array element"
4689 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004690 break;
4691 }
4692 }
4693 // Fallthrough.
4694 case BC_LEX_OP_POWER:
4695 case BC_LEX_OP_MULTIPLY:
4696 case BC_LEX_OP_DIVIDE:
4697 case BC_LEX_OP_MODULUS:
4698 case BC_LEX_OP_PLUS:
4699 case BC_LEX_OP_REL_EQ:
4700 case BC_LEX_OP_REL_LE:
4701 case BC_LEX_OP_REL_GE:
4702 case BC_LEX_OP_REL_NE:
4703 case BC_LEX_OP_REL_LT:
4704 case BC_LEX_OP_REL_GT:
4705 case BC_LEX_OP_BOOL_NOT:
4706 case BC_LEX_OP_BOOL_OR:
4707 case BC_LEX_OP_BOOL_AND:
4708 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004709 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4710 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4711 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004712 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004713 }
4714
4715 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4716 prev = BC_PARSE_TOKEN_INST(t);
4717 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4718 rprn = get_token = false;
4719 bin_last = t != BC_LEX_OP_BOOL_NOT;
4720
4721 break;
4722 }
4723
4724 case BC_LEX_LPAREN:
4725 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004726 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004727 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004728 ++nparens;
4729 paren_expr = rprn = bin_last = false;
4730 get_token = true;
4731 bc_vec_push(&p->ops, &t);
4732
4733 break;
4734 }
4735
4736 case BC_LEX_RPAREN:
4737 {
4738 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004739 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004740
4741 if (nparens == 0) {
4742 s = BC_STATUS_SUCCESS;
4743 done = true;
4744 get_token = false;
4745 break;
4746 }
4747 else if (!paren_expr)
4748 return BC_STATUS_PARSE_EMPTY_EXP;
4749
4750 --nparens;
4751 paren_expr = rprn = true;
4752 get_token = bin_last = false;
4753
4754 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4755
4756 break;
4757 }
4758
4759 case BC_LEX_NAME:
4760 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004761 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004762 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004763 paren_expr = true;
4764 rprn = get_token = bin_last = false;
4765 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4766 ++nexprs;
4767
4768 break;
4769 }
4770
4771 case BC_LEX_NUMBER:
4772 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004773 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004774 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004775 bc_parse_number(p, &prev, &nexprs);
4776 paren_expr = get_token = true;
4777 rprn = bin_last = false;
4778
4779 break;
4780 }
4781
4782 case BC_LEX_KEY_IBASE:
4783 case BC_LEX_KEY_LAST:
4784 case BC_LEX_KEY_OBASE:
4785 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004786 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004787 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004788 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4789 bc_parse_push(p, (char) prev);
4790
4791 paren_expr = get_token = true;
4792 rprn = bin_last = false;
4793 ++nexprs;
4794
4795 break;
4796 }
4797
4798 case BC_LEX_KEY_LENGTH:
4799 case BC_LEX_KEY_SQRT:
4800 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004801 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004802 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004803 s = bc_parse_builtin(p, t, flags, &prev);
4804 paren_expr = true;
4805 rprn = get_token = bin_last = false;
4806 ++nexprs;
4807
4808 break;
4809 }
4810
4811 case BC_LEX_KEY_READ:
4812 {
4813 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004814 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004815 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004816 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06004817 else
4818 s = bc_parse_read(p);
4819
4820 paren_expr = true;
4821 rprn = get_token = bin_last = false;
4822 ++nexprs;
4823 prev = BC_INST_READ;
4824
4825 break;
4826 }
4827
4828 case BC_LEX_KEY_SCALE:
4829 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004830 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004831 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004832 s = bc_parse_scale(p, &prev, flags);
4833 paren_expr = true;
4834 rprn = get_token = bin_last = false;
4835 ++nexprs;
4836 prev = BC_INST_SCALE;
4837
4838 break;
4839 }
4840
4841 default:
4842 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004843 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004844 break;
4845 }
4846 }
4847
4848 if (!s && get_token) s = bc_lex_next(&p->l);
4849 }
4850
4851 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004852 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004853
4854 while (p->ops.len > ops_bgn) {
4855
4856 top = BC_PARSE_TOP_OP(p);
4857 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4858
4859 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004860 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004861
4862 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4863
4864 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4865 bc_vec_pop(&p->ops);
4866 }
4867
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004868 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004869 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004870
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004871 for (i = 0; i < next.len; ++i)
4872 if (t == next.tokens[i])
4873 goto ok;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004874 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004875 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004876
4877 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004878 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004879 if (s) return s;
4880 }
4881 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004882 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004883 if (s) return s;
4884 }
4885
4886 if (flags & BC_PARSE_PRINT) {
4887 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4888 bc_parse_push(p, BC_INST_POP);
4889 }
4890
4891 return s;
4892}
4893
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004894static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004895{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004896 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004897}
4898
4899static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4900{
4901 return bc_parse_expr(p, flags, bc_parse_next_read);
4902}
4903#endif // ENABLE_BC
4904
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004905#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004906static BcStatus dc_parse_register(BcParse *p)
4907{
4908 BcStatus s;
4909 char *name;
4910
4911 s = bc_lex_next(&p->l);
4912 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004913 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004914
4915 name = xstrdup(p->l.t.v.v);
4916 bc_parse_pushName(p, name);
4917
4918 return s;
4919}
4920
4921static BcStatus dc_parse_string(BcParse *p)
4922{
4923 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004924 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004925
4926 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4927 name = xstrdup(b);
4928
4929 str = xstrdup(p->l.t.v.v);
4930 bc_parse_push(p, BC_INST_STR);
4931 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004932 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004933 bc_parse_addFunc(p, name, &idx);
4934
4935 return bc_lex_next(&p->l);
4936}
4937
4938static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4939{
4940 BcStatus s;
4941
4942 bc_parse_push(p, inst);
4943 if (name) {
4944 s = dc_parse_register(p);
4945 if (s) return s;
4946 }
4947
4948 if (store) {
4949 bc_parse_push(p, BC_INST_SWAP);
4950 bc_parse_push(p, BC_INST_ASSIGN);
4951 bc_parse_push(p, BC_INST_POP);
4952 }
4953
4954 return bc_lex_next(&p->l);
4955}
4956
4957static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4958{
4959 BcStatus s;
4960
4961 bc_parse_push(p, inst);
4962 bc_parse_push(p, BC_INST_EXEC_COND);
4963
4964 s = dc_parse_register(p);
4965 if (s) return s;
4966
4967 s = bc_lex_next(&p->l);
4968 if (s) return s;
4969
4970 if (p->l.t.t == BC_LEX_ELSE) {
4971 s = dc_parse_register(p);
4972 if (s) return s;
4973 s = bc_lex_next(&p->l);
4974 }
4975 else
4976 bc_parse_push(p, BC_PARSE_STREND);
4977
4978 return s;
4979}
4980
4981static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4982{
4983 BcStatus s = BC_STATUS_SUCCESS;
4984 BcInst prev;
4985 uint8_t inst;
4986 bool assign, get_token = false;
4987
4988 switch (t) {
4989
4990 case BC_LEX_OP_REL_EQ:
4991 case BC_LEX_OP_REL_LE:
4992 case BC_LEX_OP_REL_GE:
4993 case BC_LEX_OP_REL_NE:
4994 case BC_LEX_OP_REL_LT:
4995 case BC_LEX_OP_REL_GT:
4996 {
4997 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
4998 break;
4999 }
5000
5001 case BC_LEX_SCOLON:
5002 case BC_LEX_COLON:
5003 {
5004 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5005 break;
5006 }
5007
5008 case BC_LEX_STR:
5009 {
5010 s = dc_parse_string(p);
5011 break;
5012 }
5013
5014 case BC_LEX_NEG:
5015 case BC_LEX_NUMBER:
5016 {
5017 if (t == BC_LEX_NEG) {
5018 s = bc_lex_next(&p->l);
5019 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005020 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005021 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005022 }
5023
5024 bc_parse_number(p, &prev, &p->nbraces);
5025
5026 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5027 get_token = true;
5028
5029 break;
5030 }
5031
5032 case BC_LEX_KEY_READ:
5033 {
5034 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005035 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005036 else
5037 bc_parse_push(p, BC_INST_READ);
5038 get_token = true;
5039 break;
5040 }
5041
5042 case BC_LEX_OP_ASSIGN:
5043 case BC_LEX_STORE_PUSH:
5044 {
5045 assign = t == BC_LEX_OP_ASSIGN;
5046 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5047 s = dc_parse_mem(p, inst, true, assign);
5048 break;
5049 }
5050
5051 case BC_LEX_LOAD:
5052 case BC_LEX_LOAD_POP:
5053 {
5054 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5055 s = dc_parse_mem(p, inst, true, false);
5056 break;
5057 }
5058
5059 case BC_LEX_STORE_IBASE:
5060 case BC_LEX_STORE_SCALE:
5061 case BC_LEX_STORE_OBASE:
5062 {
5063 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5064 s = dc_parse_mem(p, inst, false, true);
5065 break;
5066 }
5067
5068 default:
5069 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005070 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005071 get_token = true;
5072 break;
5073 }
5074 }
5075
5076 if (!s && get_token) s = bc_lex_next(&p->l);
5077
5078 return s;
5079}
5080
5081static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5082{
5083 BcStatus s = BC_STATUS_SUCCESS;
5084 BcInst inst;
5085 BcLexType t;
5086
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005087 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005088
5089 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5090
5091 inst = dc_parse_insts[t];
5092
5093 if (inst != BC_INST_INVALID) {
5094 bc_parse_push(p, inst);
5095 s = bc_lex_next(&p->l);
5096 }
5097 else
5098 s = dc_parse_token(p, t, flags);
5099 }
5100
5101 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5102 bc_parse_push(p, BC_INST_POP_EXEC);
5103
5104 return s;
5105}
5106
5107static BcStatus dc_parse_parse(BcParse *p)
5108{
5109 BcStatus s;
5110
5111 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005112 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005113 else
5114 s = dc_parse_expr(p, 0);
5115
Denys Vlasenkod38af482018-12-04 19:11:02 +01005116 if (s || G_interrupt) {
5117 bc_parse_reset(p);
5118 s = BC_STATUS_FAILURE;
5119 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005120
5121 return s;
5122}
5123
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005124static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005125{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005126 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005127}
5128#endif // ENABLE_DC
5129
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005130static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005131{
5132 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005133 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005134 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005135 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005136 }
5137}
5138
5139static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5140{
5141 if (IS_BC) {
5142 return bc_parse_expression(p, flags);
5143 } else {
5144 return dc_parse_expr(p, flags);
5145 }
5146}
5147
Denys Vlasenkodf515392018-12-02 19:27:48 +01005148static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005149{
Gavin Howard01055ba2018-11-03 11:00:21 -06005150 BcId e, *ptr;
5151 BcVec *v, *map;
5152 size_t i;
5153 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005154 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005155
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005156 v = var ? &G.prog.vars : &G.prog.arrs;
5157 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005158
5159 e.name = id;
5160 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005161 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005162
5163 if (new) {
5164 bc_array_init(&data.v, var);
5165 bc_vec_push(v, &data.v);
5166 }
5167
5168 ptr = bc_vec_item(map, i);
5169 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005170 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005171}
5172
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005173static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005174{
5175 BcStatus s = BC_STATUS_SUCCESS;
5176
5177 switch (r->t) {
5178
5179 case BC_RESULT_STR:
5180 case BC_RESULT_TEMP:
5181 case BC_RESULT_IBASE:
5182 case BC_RESULT_SCALE:
5183 case BC_RESULT_OBASE:
5184 {
5185 *num = &r->d.n;
5186 break;
5187 }
5188
5189 case BC_RESULT_CONSTANT:
5190 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005191 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005192 size_t base_t, len = strlen(*str);
5193 BcNum *base;
5194
5195 bc_num_init(&r->d.n, len);
5196
5197 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005198 base = hex ? &G.prog.hexb : &G.prog.ib;
5199 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005200 s = bc_num_parse(&r->d.n, *str, base, base_t);
5201
5202 if (s) {
5203 bc_num_free(&r->d.n);
5204 return s;
5205 }
5206
5207 *num = &r->d.n;
5208 r->t = BC_RESULT_TEMP;
5209
5210 break;
5211 }
5212
5213 case BC_RESULT_VAR:
5214 case BC_RESULT_ARRAY:
5215 case BC_RESULT_ARRAY_ELEM:
5216 {
5217 BcVec *v;
5218
Denys Vlasenkodf515392018-12-02 19:27:48 +01005219 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005220
5221 if (r->t == BC_RESULT_ARRAY_ELEM) {
5222 v = bc_vec_top(v);
5223 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5224 *num = bc_vec_item(v, r->d.id.idx);
5225 }
5226 else
5227 *num = bc_vec_top(v);
5228
5229 break;
5230 }
5231
5232 case BC_RESULT_LAST:
5233 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005234 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005235 break;
5236 }
5237
5238 case BC_RESULT_ONE:
5239 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005240 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005241 break;
5242 }
5243 }
5244
5245 return s;
5246}
5247
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005248static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005249 BcResult **r, BcNum **rn, bool assign)
5250{
5251 BcStatus s;
5252 bool hex;
5253 BcResultType lt, rt;
5254
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005255 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005256 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005257
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005258 *r = bc_vec_item_rev(&G.prog.results, 0);
5259 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005260
5261 lt = (*l)->t;
5262 rt = (*r)->t;
5263 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5264
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005265 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005266 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005267 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005268 if (s) return s;
5269
5270 // We run this again under these conditions in case any vector has been
5271 // reallocated out from under the BcNums or arrays we had.
5272 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005273 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005274 if (s) return s;
5275 }
5276
5277 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005278 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005279 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005280 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005281
Gavin Howard01055ba2018-11-03 11:00:21 -06005282 return s;
5283}
5284
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005285static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005286{
5287 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005288 bc_vec_pop(&G.prog.results);
5289 bc_vec_pop(&G.prog.results);
5290 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005291}
5292
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005293static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005294{
5295 BcStatus s;
5296
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005297 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005298 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005299 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005300
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005301 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005302 if (s) return s;
5303
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005304 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005305 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005306
5307 return s;
5308}
5309
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005310static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005311{
5312 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005313 bc_vec_pop(&G.prog.results);
5314 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005315}
5316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005317static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005318{
5319 BcStatus s;
5320 BcResult *opd1, *opd2, res;
5321 BcNum *n1, *n2 = NULL;
5322
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005323 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005324 if (s) return s;
5325 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5326
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005327 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005328 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005329 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005330
5331 return s;
5332
5333err:
5334 bc_num_free(&res.d.n);
5335 return s;
5336}
5337
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005338static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005339{
5340 BcStatus s;
5341 BcParse parse;
5342 BcVec buf;
5343 BcInstPtr ip;
5344 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005345 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005346
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005347 for (i = 0; i < G.prog.stack.len; ++i) {
5348 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005349 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005350 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005351 }
5352
Denys Vlasenko7d628012018-12-04 21:46:47 +01005353 bc_vec_pop_all(&f->code);
5354 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005355
5356 s = bc_read_line(&buf, "read> ");
5357 if (s) goto io_err;
5358
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005359 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005360 bc_lex_file(&parse.l, bc_program_stdin_name);
5361
5362 s = bc_parse_text(&parse, buf.v);
5363 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005364 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005365 if (s) goto exec_err;
5366
5367 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005368 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005369 goto exec_err;
5370 }
5371
5372 ip.func = BC_PROG_READ;
5373 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005374 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005375
5376 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005377 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005378
5379 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005380 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005381
5382exec_err:
5383 bc_parse_free(&parse);
5384io_err:
5385 bc_vec_free(&buf);
5386 return s;
5387}
5388
5389static size_t bc_program_index(char *code, size_t *bgn)
5390{
5391 char amt = code[(*bgn)++], i = 0;
5392 size_t res = 0;
5393
5394 for (; i < amt; ++i, ++(*bgn))
5395 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5396
5397 return res;
5398}
5399
5400static char *bc_program_name(char *code, size_t *bgn)
5401{
5402 size_t i;
5403 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5404
5405 s = xmalloc(ptr - str + 1);
5406 c = code[(*bgn)++];
5407
5408 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5409 s[i] = c;
5410
5411 s[i] = '\0';
5412
5413 return s;
5414}
5415
5416static void bc_program_printString(const char *str, size_t *nchars)
5417{
5418 size_t i, len = strlen(str);
5419
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005420#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005421 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005422 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005423 return;
5424 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005425#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005426
5427 for (i = 0; i < len; ++i, ++(*nchars)) {
5428
5429 int c = str[i];
5430
5431 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005432 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005433 else {
5434
5435 c = str[++i];
5436
5437 switch (c) {
5438
5439 case 'a':
5440 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005441 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005442 break;
5443 }
5444
5445 case 'b':
5446 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005447 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005448 break;
5449 }
5450
5451 case '\\':
5452 case 'e':
5453 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005454 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005455 break;
5456 }
5457
5458 case 'f':
5459 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005460 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005461 break;
5462 }
5463
5464 case 'n':
5465 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005466 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005467 *nchars = SIZE_MAX;
5468 break;
5469 }
5470
5471 case 'r':
5472 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005473 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005474 break;
5475 }
5476
5477 case 'q':
5478 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005479 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005480 break;
5481 }
5482
5483 case 't':
5484 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005485 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005486 break;
5487 }
5488
5489 default:
5490 {
5491 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005492 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005493 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005494 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005495 break;
5496 }
5497 }
5498 }
5499 }
5500}
5501
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005502static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005503{
5504 BcStatus s = BC_STATUS_SUCCESS;
5505 BcResult *r;
5506 size_t len, i;
5507 char *str;
5508 BcNum *num = NULL;
5509 bool pop = inst != BC_INST_PRINT;
5510
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005511 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005512 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005513
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005514 r = bc_vec_item_rev(&G.prog.results, idx);
5515 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005516 if (s) return s;
5517
5518 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005519 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5520 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005521 }
5522 else {
5523
5524 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005525 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005526
5527 if (inst == BC_INST_PRINT_STR) {
5528 for (i = 0, len = strlen(str); i < len; ++i) {
5529 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005530 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005531 if (c == '\n') G.prog.nchars = SIZE_MAX;
5532 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005533 }
5534 }
5535 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005536 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005537 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005538 }
5539 }
5540
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005541 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005542
5543 return s;
5544}
5545
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005546static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005547{
5548 BcStatus s;
5549 BcResult res, *ptr;
5550 BcNum *num = NULL;
5551
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005552 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005553 if (s) return s;
5554
5555 bc_num_init(&res.d.n, num->len);
5556 bc_num_copy(&res.d.n, num);
5557 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5558
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005559 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005560
5561 return s;
5562}
5563
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005564static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005565{
5566 BcStatus s;
5567 BcResult *opd1, *opd2, res;
5568 BcNum *n1, *n2;
5569 bool cond = 0;
5570 ssize_t cmp;
5571
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005572 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005573 if (s) return s;
5574 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5575
5576 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005577 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005578 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005579 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005580 else {
5581
5582 cmp = bc_num_cmp(n1, n2);
5583
5584 switch (inst) {
5585
5586 case BC_INST_REL_EQ:
5587 {
5588 cond = cmp == 0;
5589 break;
5590 }
5591
5592 case BC_INST_REL_LE:
5593 {
5594 cond = cmp <= 0;
5595 break;
5596 }
5597
5598 case BC_INST_REL_GE:
5599 {
5600 cond = cmp >= 0;
5601 break;
5602 }
5603
5604 case BC_INST_REL_NE:
5605 {
5606 cond = cmp != 0;
5607 break;
5608 }
5609
5610 case BC_INST_REL_LT:
5611 {
5612 cond = cmp < 0;
5613 break;
5614 }
5615
5616 case BC_INST_REL_GT:
5617 {
5618 cond = cmp > 0;
5619 break;
5620 }
5621 }
5622 }
5623
5624 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5625
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005626 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005627
5628 return s;
5629}
5630
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005631#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005632static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005633 bool push)
5634{
5635 BcNum n2;
5636 BcResult res;
5637
5638 memset(&n2, 0, sizeof(BcNum));
5639 n2.rdx = res.d.id.idx = r->d.id.idx;
5640 res.t = BC_RESULT_STR;
5641
5642 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005643 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005644 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005645 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005646 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005647 }
5648
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005650
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005651 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005652 bc_vec_push(v, &n2);
5653
5654 return BC_STATUS_SUCCESS;
5655}
5656#endif // ENABLE_DC
5657
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005658static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005659{
5660 BcStatus s;
5661 BcResult *ptr, r;
5662 BcVec *v;
5663 BcNum *n;
5664
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005665 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005666 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005667
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005668 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005669 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005670 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005671 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005672
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005673#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005674 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005675 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005676 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005677#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005678
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005679 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005680 if (s) return s;
5681
5682 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005683 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005684
5685 if (var) {
5686 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5687 bc_num_copy(&r.d.n, n);
5688 }
5689 else {
5690 bc_array_init(&r.d.v, true);
5691 bc_array_copy(&r.d.v, (BcVec *) n);
5692 }
5693
5694 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005695 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005696
5697 return s;
5698}
5699
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005700static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005701{
5702 BcStatus s;
5703 BcResult *left, *right, res;
5704 BcNum *l = NULL, *r = NULL;
5705 unsigned long val, max;
5706 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5707
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005708 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005709 if (s) return s;
5710
5711 ib = left->t == BC_RESULT_IBASE;
5712 sc = left->t == BC_RESULT_SCALE;
5713
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005714#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005715
5716 if (right->t == BC_RESULT_STR) {
5717
5718 BcVec *v;
5719
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005720 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005721 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005722 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005723
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005724 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005725 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005726#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005727
5728 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005729 return bc_error("bad assignment:"
5730 " left side must be scale,"
5731 " ibase, obase, last, var,"
5732 " or array element"
5733 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005735#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005736 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005737 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005738
5739 if (assign)
5740 bc_num_copy(l, r);
5741 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005742 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005743
5744 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005745#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005746 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005747#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005748
5749 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005750 static const char *const msg[] = {
5751 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5752 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5753 "?1", //BC_RESULT_LAST
5754 "?2", //BC_RESULT_CONSTANT
5755 "?3", //BC_RESULT_ONE
5756 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5757 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005758 size_t *ptr;
5759
5760 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005761 if (s)
5762 return s;
5763 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005764 if (sc) {
5765 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005766 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005767 }
5768 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005769 if (val < BC_NUM_MIN_BASE)
5770 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005771 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005772 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005773 }
5774
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005775 if (val > max)
5776 return bc_error(msg[s]);
5777 if (!sc)
5778 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005779
5780 *ptr = (size_t) val;
5781 s = BC_STATUS_SUCCESS;
5782 }
5783
5784 bc_num_init(&res.d.n, l->len);
5785 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005786 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005787
5788 return s;
5789}
5790
Denys Vlasenko416ce762018-12-02 20:57:17 +01005791#if !ENABLE_DC
5792#define bc_program_pushVar(code, bgn, pop, copy) \
5793 bc_program_pushVar(code, bgn)
5794// for bc, 'pop' and 'copy' are always false
5795#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005796static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005797 bool pop, bool copy)
5798{
5799 BcStatus s = BC_STATUS_SUCCESS;
5800 BcResult r;
5801 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005802
5803 r.t = BC_RESULT_VAR;
5804 r.d.id.name = name;
5805
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005806#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005807 {
5808 BcVec *v = bc_program_search(name, true);
5809 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005810
Denys Vlasenko416ce762018-12-02 20:57:17 +01005811 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005812
Denys Vlasenko416ce762018-12-02 20:57:17 +01005813 if (!BC_PROG_STACK(v, 2 - copy)) {
5814 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005815 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01005816 }
5817
Gavin Howard01055ba2018-11-03 11:00:21 -06005818 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005819 name = NULL;
5820
5821 if (!BC_PROG_STR(num)) {
5822
5823 r.t = BC_RESULT_TEMP;
5824
5825 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5826 bc_num_copy(&r.d.n, num);
5827 }
5828 else {
5829 r.t = BC_RESULT_STR;
5830 r.d.id.idx = num->rdx;
5831 }
5832
5833 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005834 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005835 }
5836#endif // ENABLE_DC
5837
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005838 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005839
5840 return s;
5841}
5842
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005843static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005844 char inst)
5845{
5846 BcStatus s = BC_STATUS_SUCCESS;
5847 BcResult r;
5848 BcNum *num;
5849
5850 r.d.id.name = bc_program_name(code, bgn);
5851
5852 if (inst == BC_INST_ARRAY) {
5853 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005854 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005855 }
5856 else {
5857
5858 BcResult *operand;
5859 unsigned long temp;
5860
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005861 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005862 if (s) goto err;
5863 s = bc_num_ulong(num, &temp);
5864 if (s) goto err;
5865
5866 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005867 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005868 goto err;
5869 }
5870
5871 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005872 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005873 }
5874
5875err:
5876 if (s) free(r.d.id.name);
5877 return s;
5878}
5879
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005880#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005881static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005882{
5883 BcStatus s;
5884 BcResult *ptr, res, copy;
5885 BcNum *num = NULL;
5886 char inst2 = inst;
5887
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005888 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005889 if (s) return s;
5890
5891 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5892 copy.t = BC_RESULT_TEMP;
5893 bc_num_init(&copy.d.n, num->len);
5894 bc_num_copy(&copy.d.n, num);
5895 }
5896
5897 res.t = BC_RESULT_ONE;
5898 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5899 BC_INST_ASSIGN_PLUS :
5900 BC_INST_ASSIGN_MINUS;
5901
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005902 bc_vec_push(&G.prog.results, &res);
5903 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005904
5905 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005906 bc_vec_pop(&G.prog.results);
5907 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005908 }
5909
5910 return s;
5911}
5912
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005913static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005914{
5915 BcStatus s = BC_STATUS_SUCCESS;
5916 BcInstPtr ip;
5917 size_t i, nparams = bc_program_index(code, idx);
5918 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005919 BcId *a;
5920 BcResultData param;
5921 BcResult *arg;
5922
5923 ip.idx = 0;
5924 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005925 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005926
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005927 if (func->code.len == 0) {
5928 return bc_error("undefined function");
5929 }
5930 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005931 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005932 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005933 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005934
5935 for (i = 0; i < nparams; ++i) {
5936
5937 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005938 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005939
5940 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005941 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005942
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005943 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005944 if (s) return s;
5945 }
5946
5947 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005948 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005949
5950 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005951 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005952
5953 if (a->idx) {
5954 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5955 bc_vec_push(v, &param.n);
5956 }
5957 else {
5958 bc_array_init(&param.v, true);
5959 bc_vec_push(v, &param.v);
5960 }
5961 }
5962
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005963 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005964
5965 return BC_STATUS_SUCCESS;
5966}
5967
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005968static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005969{
5970 BcStatus s;
5971 BcResult res;
5972 BcFunc *f;
5973 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005974 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06005975
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005976 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005977 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005978
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005979 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005980 res.t = BC_RESULT_TEMP;
5981
5982 if (inst == BC_INST_RET) {
5983
5984 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005985 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005986
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005987 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005988 if (s) return s;
5989 bc_num_init(&res.d.n, num->len);
5990 bc_num_copy(&res.d.n, num);
5991 }
5992 else {
5993 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5994 bc_num_zero(&res.d.n);
5995 }
5996
5997 // We need to pop arguments as well, so this takes that into account.
5998 for (i = 0; i < f->autos.len; ++i) {
5999
6000 BcVec *v;
6001 BcId *a = bc_vec_item(&f->autos, i);
6002
Denys Vlasenkodf515392018-12-02 19:27:48 +01006003 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006004 bc_vec_pop(v);
6005 }
6006
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006007 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6008 bc_vec_push(&G.prog.results, &res);
6009 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006010
6011 return BC_STATUS_SUCCESS;
6012}
6013#endif // ENABLE_BC
6014
6015static unsigned long bc_program_scale(BcNum *n)
6016{
6017 return (unsigned long) n->rdx;
6018}
6019
6020static unsigned long bc_program_len(BcNum *n)
6021{
6022 unsigned long len = n->len;
6023 size_t i;
6024
6025 if (n->rdx != n->len) return len;
6026 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6027
6028 return len;
6029}
6030
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006031static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006032{
6033 BcStatus s;
6034 BcResult *opnd;
6035 BcNum *num = NULL;
6036 BcResult res;
6037 bool len = inst == BC_INST_LENGTH;
6038
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006039 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006040 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006041 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006042
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006043 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006044 if (s) return s;
6045
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006046#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006047 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006048 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006049#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006050
6051 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6052
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006053 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006054#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006055 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006056 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006057 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006058#endif
6059#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006060 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6061
6062 char **str;
6063 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6064
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006065 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006066 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006067 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006068#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006069 else {
6070 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006071 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006072 }
6073
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006074 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006075
6076 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006077}
6078
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006079#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006080static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006081{
6082 BcStatus s;
6083 BcResult *opd1, *opd2, res, res2;
6084 BcNum *n1, *n2 = NULL;
6085
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006086 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006087 if (s) return s;
6088
6089 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6090 bc_num_init(&res2.d.n, n2->len);
6091
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006092 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006093 if (s) goto err;
6094
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006095 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006096 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006097 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006098
6099 return s;
6100
6101err:
6102 bc_num_free(&res2.d.n);
6103 bc_num_free(&res.d.n);
6104 return s;
6105}
6106
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006107static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006108{
6109 BcStatus s;
6110 BcResult *r1, *r2, *r3, res;
6111 BcNum *n1, *n2, *n3;
6112
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006113 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006114 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006115 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006116 if (s) return s;
6117
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006118 r1 = bc_vec_item_rev(&G.prog.results, 2);
6119 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006120 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006121 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006122 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006123
6124 // Make sure that the values have their pointers updated, if necessary.
6125 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6126
6127 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006128 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006129 if (s) return s;
6130 }
6131
6132 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006133 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006134 if (s) return s;
6135 }
6136 }
6137
6138 bc_num_init(&res.d.n, n3->len);
6139 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6140 if (s) goto err;
6141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 bc_vec_pop(&G.prog.results);
6143 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006144
6145 return s;
6146
6147err:
6148 bc_num_free(&res.d.n);
6149 return s;
6150}
6151
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006152static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006153{
Gavin Howard01055ba2018-11-03 11:00:21 -06006154 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006155 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006156
6157 res.t = BC_RESULT_TEMP;
6158
6159 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006160 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006161 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006162}
6163
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006164static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006165{
6166 BcStatus s;
6167 BcResult *r, res;
6168 BcNum *num = NULL, n;
6169 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006170 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006171 unsigned long val;
6172
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006173 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006174 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006175 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006176
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006177 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006178 if (s) return s;
6179
6180 if (BC_PROG_NUM(r, num)) {
6181
6182 bc_num_init(&n, BC_NUM_DEF_SIZE);
6183 bc_num_copy(&n, num);
6184 bc_num_truncate(&n, n.rdx);
6185
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006186 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006187 if (s) goto num_err;
6188 s = bc_num_ulong(&n, &val);
6189 if (s) goto num_err;
6190
6191 c = (char) val;
6192
6193 bc_num_free(&n);
6194 }
6195 else {
6196 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006197 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006198 c = str2[0];
6199 }
6200
6201 str = xmalloc(2);
6202 str[0] = c;
6203 str[1] = '\0';
6204
6205 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006206 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006207
6208 if (idx != len + BC_PROG_REQ_FUNCS) {
6209
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006210 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6211 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006212 len = idx;
6213 break;
6214 }
6215 }
6216
6217 free(str);
6218 }
6219 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006220 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006221
6222 res.t = BC_RESULT_STR;
6223 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006224 bc_vec_pop(&G.prog.results);
6225 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006226
6227 return BC_STATUS_SUCCESS;
6228
6229num_err:
6230 bc_num_free(&n);
6231 return s;
6232}
6233
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006234static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006235{
6236 BcStatus s;
6237 BcResult *r;
6238 BcNum *n = NULL;
6239 size_t idx;
6240 char *str;
6241
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006242 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006243 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006244 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006245
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006246 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006247 if (s) return s;
6248
6249 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006250 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006251 else {
6252 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006253 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006254 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006255 }
6256
6257 return s;
6258}
6259
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006260static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006261{
6262 BcStatus s;
6263 BcResult *opnd;
6264 BcNum *num = NULL;
6265 unsigned long val;
6266
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006267 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006268 if (s) return s;
6269 s = bc_num_ulong(num, &val);
6270 if (s) return s;
6271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006273
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006274 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006275 return bc_error_stack_has_too_few_elements();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006276 if (G.prog.stack.len == val)
6277 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006278
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006279 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006280
6281 return s;
6282}
6283
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006284static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006285 bool cond)
6286{
6287 BcStatus s = BC_STATUS_SUCCESS;
6288 BcResult *r;
6289 char **str;
6290 BcFunc *f;
6291 BcParse prs;
6292 BcInstPtr ip;
6293 size_t fidx, sidx;
6294 BcNum *n;
6295 bool exec;
6296
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006297 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006298 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006299
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006300 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006301
6302 if (cond) {
6303
Gavin Howard01055ba2018-11-03 11:00:21 -06006304 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6305
6306 if (code[*bgn] == BC_PARSE_STREND)
6307 (*bgn) += 1;
6308 else
6309 else_name = bc_program_name(code, bgn);
6310
6311 exec = r->d.n.len != 0;
6312
6313 if (exec)
6314 name = then_name;
6315 else if (else_name != NULL) {
6316 exec = true;
6317 name = else_name;
6318 }
6319
6320 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006321 BcVec *v;
6322 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006323 n = bc_vec_top(v);
6324 }
6325
6326 free(then_name);
6327 free(else_name);
6328
6329 if (!exec) goto exit;
6330 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006331 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006332 goto exit;
6333 }
6334
6335 sidx = n->rdx;
6336 }
6337 else {
6338
6339 if (r->t == BC_RESULT_STR)
6340 sidx = r->d.id.idx;
6341 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006342 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006343 if (s || !BC_PROG_STR(n)) goto exit;
6344 sidx = n->rdx;
6345 }
6346 else
6347 goto exit;
6348 }
6349
6350 fidx = sidx + BC_PROG_REQ_FUNCS;
6351
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006352 str = bc_vec_item(&G.prog.strs, sidx);
6353 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006354
6355 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006356 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006357 s = bc_parse_text(&prs, *str);
6358 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006359 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006360 if (s) goto err;
6361
6362 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006363 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006364 goto err;
6365 }
6366
6367 bc_parse_free(&prs);
6368 }
6369
6370 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006371 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006372 ip.func = fidx;
6373
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006374 bc_vec_pop(&G.prog.results);
6375 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006376
6377 return BC_STATUS_SUCCESS;
6378
6379err:
6380 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006381 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006382 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006383exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006384 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006385 return s;
6386}
6387#endif // ENABLE_DC
6388
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006389static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006390{
Gavin Howard01055ba2018-11-03 11:00:21 -06006391 BcResult res;
6392 unsigned long val;
6393
6394 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6395 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006396 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006397 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006398 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006399 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006400 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006401
6402 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006403 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006404 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006405}
6406
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006407static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006408{
Gavin Howard01055ba2018-11-03 11:00:21 -06006409 BcId entry, *entry_ptr;
6410 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006411 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006412
6413 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006414 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006415
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006416 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6417 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006418
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006419 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006420 *idx = entry_ptr->idx;
6421
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006422 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006423
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006424 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006425
6426 // We need to reset these, so the function can be repopulated.
6427 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006428 bc_vec_pop_all(&func->autos);
6429 bc_vec_pop_all(&func->code);
6430 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006431 }
6432 else {
6433 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006434 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006435 }
6436}
6437
Denys Vlasenkod38af482018-12-04 19:11:02 +01006438// Called when parsing or execution detects a failure,
6439// resets execution structures.
6440static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006441{
6442 BcFunc *f;
6443 BcInstPtr *ip;
6444
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006445 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006446 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006447
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006448 f = bc_vec_item(&G.prog.fns, 0);
6449 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006450 ip->idx = f->code.len;
6451
Denys Vlasenkod38af482018-12-04 19:11:02 +01006452 // If !tty, no need to check for ^C: we don't have ^C handler,
6453 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006454}
6455
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006456static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006457{
6458 BcStatus s = BC_STATUS_SUCCESS;
6459 size_t idx;
6460 BcResult r, *ptr;
6461 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006462 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6463 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 char *code = func->code.v;
6465 bool cond = false;
6466
6467 while (!s && ip->idx < func->code.len) {
6468
6469 char inst = code[(ip->idx)++];
6470
6471 switch (inst) {
6472
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006473#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006474 case BC_INST_JUMP_ZERO:
6475 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006476 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006477 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006478 cond = !bc_num_cmp(num, &G.prog.zero);
6479 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006480 }
6481 // Fallthrough.
6482 case BC_INST_JUMP:
6483 {
6484 size_t *addr;
6485 idx = bc_program_index(code, &ip->idx);
6486 addr = bc_vec_item(&func->labels, idx);
6487 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6488 break;
6489 }
6490
6491 case BC_INST_CALL:
6492 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006493 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006494 break;
6495 }
6496
6497 case BC_INST_INC_PRE:
6498 case BC_INST_DEC_PRE:
6499 case BC_INST_INC_POST:
6500 case BC_INST_DEC_POST:
6501 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006502 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006503 break;
6504 }
6505
6506 case BC_INST_HALT:
6507 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006508 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006509 break;
6510 }
6511
6512 case BC_INST_RET:
6513 case BC_INST_RET0:
6514 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006515 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006516 break;
6517 }
6518
6519 case BC_INST_BOOL_OR:
6520 case BC_INST_BOOL_AND:
6521#endif // ENABLE_BC
6522 case BC_INST_REL_EQ:
6523 case BC_INST_REL_LE:
6524 case BC_INST_REL_GE:
6525 case BC_INST_REL_NE:
6526 case BC_INST_REL_LT:
6527 case BC_INST_REL_GT:
6528 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006529 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530 break;
6531 }
6532
6533 case BC_INST_READ:
6534 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006535 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006536 break;
6537 }
6538
6539 case BC_INST_VAR:
6540 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006541 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006542 break;
6543 }
6544
6545 case BC_INST_ARRAY_ELEM:
6546 case BC_INST_ARRAY:
6547 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006548 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006549 break;
6550 }
6551
6552 case BC_INST_LAST:
6553 {
6554 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006555 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 break;
6557 }
6558
6559 case BC_INST_IBASE:
6560 case BC_INST_SCALE:
6561 case BC_INST_OBASE:
6562 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006563 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006564 break;
6565 }
6566
6567 case BC_INST_SCALE_FUNC:
6568 case BC_INST_LENGTH:
6569 case BC_INST_SQRT:
6570 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006571 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006572 break;
6573 }
6574
6575 case BC_INST_NUM:
6576 {
6577 r.t = BC_RESULT_CONSTANT;
6578 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006579 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 break;
6581 }
6582
6583 case BC_INST_POP:
6584 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006585 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006586 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006587 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006588 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006589 break;
6590 }
6591
6592 case BC_INST_POP_EXEC:
6593 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006594 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006595 break;
6596 }
6597
6598 case BC_INST_PRINT:
6599 case BC_INST_PRINT_POP:
6600 case BC_INST_PRINT_STR:
6601 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006602 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006603 break;
6604 }
6605
6606 case BC_INST_STR:
6607 {
6608 r.t = BC_RESULT_STR;
6609 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006610 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006611 break;
6612 }
6613
6614 case BC_INST_POWER:
6615 case BC_INST_MULTIPLY:
6616 case BC_INST_DIVIDE:
6617 case BC_INST_MODULUS:
6618 case BC_INST_PLUS:
6619 case BC_INST_MINUS:
6620 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006621 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006622 break;
6623 }
6624
6625 case BC_INST_BOOL_NOT:
6626 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006627 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006628 if (s) return s;
6629
6630 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006631 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6632 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006633
6634 break;
6635 }
6636
6637 case BC_INST_NEG:
6638 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006639 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006640 break;
6641 }
6642
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006643#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006644 case BC_INST_ASSIGN_POWER:
6645 case BC_INST_ASSIGN_MULTIPLY:
6646 case BC_INST_ASSIGN_DIVIDE:
6647 case BC_INST_ASSIGN_MODULUS:
6648 case BC_INST_ASSIGN_PLUS:
6649 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006650#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006651 case BC_INST_ASSIGN:
6652 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006653 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006654 break;
6655 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006656#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006657 case BC_INST_MODEXP:
6658 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006659 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006660 break;
6661 }
6662
6663 case BC_INST_DIVMOD:
6664 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006665 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006666 break;
6667 }
6668
6669 case BC_INST_EXECUTE:
6670 case BC_INST_EXEC_COND:
6671 {
6672 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006673 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006674 break;
6675 }
6676
6677 case BC_INST_PRINT_STACK:
6678 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006679 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6680 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006681 break;
6682 }
6683
6684 case BC_INST_CLEAR_STACK:
6685 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006686 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006687 break;
6688 }
6689
6690 case BC_INST_STACK_LEN:
6691 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006692 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006693 break;
6694 }
6695
6696 case BC_INST_DUPLICATE:
6697 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006698 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006699 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006700 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006701 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006702 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006703 break;
6704 }
6705
6706 case BC_INST_SWAP:
6707 {
6708 BcResult *ptr2;
6709
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006710 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006711 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006712
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006713 ptr = bc_vec_item_rev(&G.prog.results, 0);
6714 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006715 memcpy(&r, ptr, sizeof(BcResult));
6716 memcpy(ptr, ptr2, sizeof(BcResult));
6717 memcpy(ptr2, &r, sizeof(BcResult));
6718
6719 break;
6720 }
6721
6722 case BC_INST_ASCIIFY:
6723 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006724 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006725 break;
6726 }
6727
6728 case BC_INST_PRINT_STREAM:
6729 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006730 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006731 break;
6732 }
6733
6734 case BC_INST_LOAD:
6735 case BC_INST_PUSH_VAR:
6736 {
6737 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006738 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006739 break;
6740 }
6741
6742 case BC_INST_PUSH_TO_VAR:
6743 {
6744 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006745 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006746 free(name);
6747 break;
6748 }
6749
6750 case BC_INST_QUIT:
6751 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006752 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006753 quit();
6754 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006755 break;
6756 }
6757
6758 case BC_INST_NQUIT:
6759 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006760 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006761 break;
6762 }
6763#endif // ENABLE_DC
6764 }
6765
Denys Vlasenkod38af482018-12-04 19:11:02 +01006766 if (s || G_interrupt) {
6767 bc_program_reset();
6768 break;
6769 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006770
6771 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006772 ip = bc_vec_top(&G.prog.stack);
6773 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006774 code = func->code.v;
6775 }
6776
6777 return s;
6778}
6779
Denys Vlasenko00d77792018-11-30 23:13:42 +01006780static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006781{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006782 printf("%s "BB_VER"\n"
6783 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006784 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006785 "This is free software with ABSOLUTELY NO WARRANTY\n"
6786 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006787}
6788
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006789#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006790static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006791{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006792 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6793
Gavin Howard01055ba2018-11-03 11:00:21 -06006794 BcVec v;
6795 char *env_args = getenv(bc_args_env_name), *buf;
6796
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006797 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006798
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006799 G.env_args = xstrdup(env_args);
6800 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006801
6802 bc_vec_init(&v, sizeof(char *), NULL);
6803 bc_vec_push(&v, &bc_args_env_name);
6804
6805 while (*buf != 0) {
6806 if (!isspace(*buf)) {
6807 bc_vec_push(&v, &buf);
6808 while (*buf != 0 && !isspace(*buf)) ++buf;
6809 if (*buf != 0) (*(buf++)) = '\0';
6810 }
6811 else
6812 ++buf;
6813 }
6814
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006815 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816
6817 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006818}
6819#endif // ENABLE_BC
6820
6821static size_t bc_vm_envLen(const char *var)
6822{
6823 char *lenv = getenv(var);
6824 size_t i, len = BC_NUM_PRINT_WIDTH;
6825 int num;
6826
6827 if (!lenv) return len;
6828
6829 len = strlen(lenv);
6830
6831 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6832 if (num) {
6833 len = (size_t) atoi(lenv) - 1;
6834 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6835 }
6836 else
6837 len = BC_NUM_PRINT_WIDTH;
6838
6839 return len;
6840}
6841
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006842static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006843{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006844 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006845
Gavin Howard01055ba2018-11-03 11:00:21 -06006846 if (s) return s;
6847
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006848 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006849 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006850 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006851 }
6852
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006853 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006854 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006855 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006856 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006857 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006858 }
6859
6860 return s;
6861}
6862
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006863static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006864{
6865 BcStatus s;
6866 char *data;
6867 BcFunc *main_func;
6868 BcInstPtr *ip;
6869
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006870 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006871 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006872 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006873
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006874 bc_lex_file(&G.prs.l, file);
6875 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006876 if (s) goto err;
6877
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006878 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6879 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006880
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006881 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006882 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006883
6884err:
6885 free(data);
6886 return s;
6887}
6888
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006889static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006890{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006891 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006892 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006893 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006894 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006895
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006896 G.prog.file = bc_program_stdin_name;
6897 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006898
Denys Vlasenko7d628012018-12-04 21:46:47 +01006899 bc_char_vec_init(&buffer);
6900 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06006901 bc_vec_pushByte(&buffer, '\0');
6902
6903 // This loop is complex because the vm tries not to send any lines that end
6904 // with a backslash to the parser. The reason for that is because the parser
6905 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6906 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006907 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006908
6909 char *string = buf.v;
6910
6911 len = buf.len - 1;
6912
6913 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006914 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006915 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006916 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006917 str += 1;
6918 }
6919 else if (len > 1 || comment) {
6920
6921 for (i = 0; i < len; ++i) {
6922
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006923 bool notend = len > i + 1;
6924 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006925
6926 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006927 if (G.sbgn == G.send)
6928 str ^= c == G.sbgn;
6929 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006930 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006931 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006932 str += 1;
6933 }
6934
6935 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6936 comment = true;
6937 break;
6938 }
6939 else if (c == '*' && notend && comment && string[i + 1] == '/')
6940 comment = false;
6941 }
6942
6943 if (str || comment || string[len - 2] == '\\') {
6944 bc_vec_concat(&buffer, buf.v);
6945 continue;
6946 }
6947 }
6948
6949 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006950 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006951 if (s) {
6952 fflush_and_check();
6953 fputs("ready for more input\n", stderr);
6954 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006955
Denys Vlasenko7d628012018-12-04 21:46:47 +01006956 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06006957 }
6958
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006959 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006960 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006961 }
6962 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006963 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006964 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006965
Gavin Howard01055ba2018-11-03 11:00:21 -06006966 bc_vec_free(&buf);
6967 bc_vec_free(&buffer);
6968 return s;
6969}
6970
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01006971#if ENABLE_BC
6972static const char bc_lib[] = {
6973 "scale=20"
6974"\n" "define e(x){"
6975"\n" "auto b,s,n,r,d,i,p,f,v"
6976"\n" "b=ibase"
6977"\n" "ibase=A"
6978"\n" "if(x<0){"
6979"\n" "n=1"
6980"\n" "x=-x"
6981"\n" "}"
6982"\n" "s=scale"
6983"\n" "r=6+s+0.44*x"
6984"\n" "scale=scale(x)+1"
6985"\n" "while(x>1){"
6986"\n" "d+=1"
6987"\n" "x/=2"
6988"\n" "scale+=1"
6989"\n" "}"
6990"\n" "scale=r"
6991"\n" "r=x+1"
6992"\n" "p=x"
6993"\n" "f=v=1"
6994"\n" "for(i=2;v!=0;++i){"
6995"\n" "p*=x"
6996"\n" "f*=i"
6997"\n" "v=p/f"
6998"\n" "r+=v"
6999"\n" "}"
7000"\n" "while((d--)!=0)r*=r"
7001"\n" "scale=s"
7002"\n" "ibase=b"
7003"\n" "if(n!=0)return(1/r)"
7004"\n" "return(r/1)"
7005"\n" "}"
7006"\n" "define l(x){"
7007"\n" "auto b,s,r,p,a,q,i,v"
7008"\n" "b=ibase"
7009"\n" "ibase=A"
7010"\n" "if(x<=0){"
7011"\n" "r=(1-10^scale)/1"
7012"\n" "ibase=b"
7013"\n" "return(r)"
7014"\n" "}"
7015"\n" "s=scale"
7016"\n" "scale+=6"
7017"\n" "p=2"
7018"\n" "while(x>=2){"
7019"\n" "p*=2"
7020"\n" "x=sqrt(x)"
7021"\n" "}"
7022"\n" "while(x<=0.5){"
7023"\n" "p*=2"
7024"\n" "x=sqrt(x)"
7025"\n" "}"
7026"\n" "r=a=(x-1)/(x+1)"
7027"\n" "q=a*a"
7028"\n" "v=1"
7029"\n" "for(i=3;v!=0;i+=2){"
7030"\n" "a*=q"
7031"\n" "v=a/i"
7032"\n" "r+=v"
7033"\n" "}"
7034"\n" "r*=p"
7035"\n" "scale=s"
7036"\n" "ibase=b"
7037"\n" "return(r/1)"
7038"\n" "}"
7039"\n" "define s(x){"
7040"\n" "auto b,s,r,n,a,q,i"
7041"\n" "b=ibase"
7042"\n" "ibase=A"
7043"\n" "s=scale"
7044"\n" "scale=1.1*s+2"
7045"\n" "a=a(1)"
7046"\n" "if(x<0){"
7047"\n" "n=1"
7048"\n" "x=-x"
7049"\n" "}"
7050"\n" "scale=0"
7051"\n" "q=(x/a+2)/4"
7052"\n" "x=x-4*q*a"
7053"\n" "if(q%2!=0)x=-x"
7054"\n" "scale=s+2"
7055"\n" "r=a=x"
7056"\n" "q=-x*x"
7057"\n" "for(i=3;a!=0;i+=2){"
7058"\n" "a*=q/(i*(i-1))"
7059"\n" "r+=a"
7060"\n" "}"
7061"\n" "scale=s"
7062"\n" "ibase=b"
7063"\n" "if(n!=0)return(-r/1)"
7064"\n" "return(r/1)"
7065"\n" "}"
7066"\n" "define c(x){"
7067"\n" "auto b,s"
7068"\n" "b=ibase"
7069"\n" "ibase=A"
7070"\n" "s=scale"
7071"\n" "scale*=1.2"
7072"\n" "x=s(2*a(1)+x)"
7073"\n" "scale=s"
7074"\n" "ibase=b"
7075"\n" "return(x/1)"
7076"\n" "}"
7077"\n" "define a(x){"
7078"\n" "auto b,s,r,n,a,m,t,f,i,u"
7079"\n" "b=ibase"
7080"\n" "ibase=A"
7081"\n" "n=1"
7082"\n" "if(x<0){"
7083"\n" "n=-1"
7084"\n" "x=-x"
7085"\n" "}"
7086"\n" "if(x==1){"
7087"\n" "if(scale<65){"
7088"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7089"\n" "}"
7090"\n" "}"
7091"\n" "if(x==.2){"
7092"\n" "if(scale<65){"
7093"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7094"\n" "}"
7095"\n" "}"
7096"\n" "s=scale"
7097"\n" "if(x>.2){"
7098"\n" "scale+=5"
7099"\n" "a=a(.2)"
7100"\n" "}"
7101"\n" "scale=s+3"
7102"\n" "while(x>.2){"
7103"\n" "m+=1"
7104"\n" "x=(x-.2)/(1+.2*x)"
7105"\n" "}"
7106"\n" "r=u=x"
7107"\n" "f=-x*x"
7108"\n" "t=1"
7109"\n" "for(i=3;t!=0;i+=2){"
7110"\n" "u*=f"
7111"\n" "t=u/i"
7112"\n" "r+=t"
7113"\n" "}"
7114"\n" "scale=s"
7115"\n" "ibase=b"
7116"\n" "return((m*a+r)/n)"
7117"\n" "}"
7118"\n" "define j(n,x){"
7119"\n" "auto b,s,o,a,i,v,f"
7120"\n" "b=ibase"
7121"\n" "ibase=A"
7122"\n" "s=scale"
7123"\n" "scale=0"
7124"\n" "n/=1"
7125"\n" "if(n<0){"
7126"\n" "n=-n"
7127"\n" "if(n%2==1)o=1"
7128"\n" "}"
7129"\n" "a=1"
7130"\n" "for(i=2;i<=n;++i)a*=i"
7131"\n" "scale=1.5*s"
7132"\n" "a=(x^n)/2^n/a"
7133"\n" "r=v=1"
7134"\n" "f=-x*x/4"
7135"\n" "scale=scale+length(a)-scale(a)"
7136"\n" "for(i=1;v!=0;++i){"
7137"\n" "v=v*f/i/(n+i)"
7138"\n" "r+=v"
7139"\n" "}"
7140"\n" "scale=s"
7141"\n" "ibase=b"
7142"\n" "if(o!=0)a=-a"
7143"\n" "return(a*r/1)"
7144"\n" "}"
7145};
7146#endif // ENABLE_BC
7147
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007148static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007149{
7150 BcStatus s = BC_STATUS_SUCCESS;
7151 size_t i;
7152
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007153#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007154 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007155
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007156 // We know that internal library is not buggy,
7157 // thus error checking is normally disabled.
7158# define DEBUG_LIB 0
7159 bc_lex_file(&G.prs.l, "");
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007160 s = bc_parse_text(&G.prs, bc_lib);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007161 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007162
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007163 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007164 s = G.prs.parse(&G.prs);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007165 if (DEBUG_LIB && s) return s;
7166 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007167 s = bc_program_exec();
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007168 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007169 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007170#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007171
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007172 for (i = 0; !s && i < G.files.len; ++i)
7173 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007174 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007175 fflush_and_check();
7176 fputs("ready for more input\n", stderr);
7177 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007178
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007179 if (IS_BC || !G.files.len)
7180 s = bc_vm_stdin();
7181 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7182 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007183
Denys Vlasenko00d77792018-11-30 23:13:42 +01007184 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007185}
7186
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007187#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007188static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007189{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007190 bc_num_free(&G.prog.ib);
7191 bc_num_free(&G.prog.ob);
7192 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007193# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007194 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007195# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007196 bc_vec_free(&G.prog.fns);
7197 bc_vec_free(&G.prog.fn_map);
7198 bc_vec_free(&G.prog.vars);
7199 bc_vec_free(&G.prog.var_map);
7200 bc_vec_free(&G.prog.arrs);
7201 bc_vec_free(&G.prog.arr_map);
7202 bc_vec_free(&G.prog.strs);
7203 bc_vec_free(&G.prog.consts);
7204 bc_vec_free(&G.prog.results);
7205 bc_vec_free(&G.prog.stack);
7206 bc_num_free(&G.prog.last);
7207 bc_num_free(&G.prog.zero);
7208 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007209}
7210
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007211static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007212{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007213 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007214 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007215 bc_parse_free(&G.prs);
7216 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007217}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007218#endif
7219
7220static void bc_program_init(size_t line_len)
7221{
7222 size_t idx;
7223 BcInstPtr ip;
7224
7225 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7226 memset(&ip, 0, sizeof(BcInstPtr));
7227
7228 /* G.prog.nchars = G.prog.scale = 0; - already is */
7229 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007230
7231 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7232 bc_num_ten(&G.prog.ib);
7233 G.prog.ib_t = 10;
7234
7235 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7236 bc_num_ten(&G.prog.ob);
7237 G.prog.ob_t = 10;
7238
7239 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7240 bc_num_ten(&G.prog.hexb);
7241 G.prog.hexb.num[0] = 6;
7242
7243#if ENABLE_DC
7244 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7245 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7246#endif
7247
7248 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7249 bc_num_zero(&G.prog.last);
7250
7251 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7252 bc_num_zero(&G.prog.zero);
7253
7254 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7255 bc_num_one(&G.prog.one);
7256
7257 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007258 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007259
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007260 bc_program_addFunc(xstrdup("(main)"), &idx);
7261 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007262
7263 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007264 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007265
7266 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007267 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007268
7269 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7270 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7271 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7272 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7273 bc_vec_push(&G.prog.stack, &ip);
7274}
Gavin Howard01055ba2018-11-03 11:00:21 -06007275
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007276static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007277{
Gavin Howard01055ba2018-11-03 11:00:21 -06007278 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007279
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007280 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007281
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007282 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007283 bc_vm_envArgs();
7284 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007285
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007286 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007287 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007288 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007289 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007290 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007291 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007292}
7293
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007294static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007295 const char *env_len)
7296{
7297 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007298
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007299 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007300 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007301
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007302 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007303
Denys Vlasenkod38af482018-12-04 19:11:02 +01007304 if (G.ttyin) {
7305#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007306 // With SA_RESTART, most system calls will restart
7307 // (IOW: they won't fail with EINTR).
7308 // In particular, this means ^C won't cause
7309 // stdout to get into "error state" if SIGINT hits
7310 // within write() syscall.
7311 // The downside is that ^C while line input is taken
7312 // will only be handled after [Enter] since read()
7313 // from stdin is not interrupted by ^C either,
7314 // it restarts, thus fgetc() does not return on ^C.
7315 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7316
7317 // Without SA_RESTART, this exhibits a bug:
7318 // "while (1) print 1" and try ^C-ing it.
7319 // Intermittently, instead of returning to input line,
7320 // you'll get "output error: Interrupted system call"
7321 // and exit.
7322 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007323#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007324 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007325 bc_vm_info();
7326 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007327 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007328
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007329#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007330 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007331#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007332 return st;
7333}
7334
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007335#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007336int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7337int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007338{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007339 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007340 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007341
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007342 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007343}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007344#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007345
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007346#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007347int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7348int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007349{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007350 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007351 G.sbgn = '[';
7352 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007353
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007354 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007355}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007356#endif