blob: 6f2606c7944c3bf6578fa82171b1ad298829d54c [file] [log] [blame]
Gavin Howard01055ba2018-11-03 11:00:21 -06001/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
5 *
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
8 */
9//config:config BC
10//config: bool "bc (45 kb; 49 kb when combined with dc)"
11//config: default y
12//config: help
13//config: bc is a command-line, arbitrary-precision calculator with a
14//config: Turing-complete language. See the GNU bc manual
15//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17//config: for details.
18//config:
19//config: This bc has four differences to the GNU bc:
20//config:
21//config: 1) The period (.) can also be used as a shortcut for "last", as in
22//config: the BSD bc.
23//config: 2) Arrays are copied before being passed as arguments to
24//config: functions. This behavior is required by the bc spec.
25//config: 3) Arrays can be passed to the builtin "length" function to get
26//config: the number of elements currently in the array. The following
27//config: example prints "1":
28//config:
29//config: a[0] = 0
30//config: length(a[])
31//config:
32//config: 4) The precedence of the boolean "not" operator (!) is equal to
33//config: that of the unary minus (-), or negation, operator. This still
34//config: allows POSIX-compliant scripts to work while somewhat
35//config: preserving expected behavior (versus C) and making parsing
36//config: easier.
37//config:
38//config: Options:
39//config:
40//config: -i --interactive force interactive mode
41//config: -l --mathlib use predefined math routines:
42//config:
43//config: s(expr) = sine of expr in radians
44//config: c(expr) = cosine of expr in radians
45//config: a(expr) = arctangent of expr, returning
46//config: radians
47//config: l(expr) = natural log of expr
48//config: e(expr) = raises e to the power of expr
49//config: j(n, x) = Bessel function of integer order
50//config: n of x
51//config:
52//config: -q --quiet don't print version and copyright.
53//config: -s --standard error if any non-POSIX extensions are used.
54//config: -w --warn warn if any non-POSIX extensions are used.
55//config: -v --version print version and copyright and exit.
56//config:
57//config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
58//config: enabled.
59//config:
60//config:config DC
61//config: bool "dc (38 kb; 49 kb when combined with bc)"
62//config: default y
63//config: help
64//config: dc is a reverse-polish notation command-line calculator which
65//config: supports unlimited precision arithmetic. See the FreeBSD man page
66//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68//config: for details.
69//config:
70//config: This dc has a few differences from the two above:
71//config:
72//config: 1) When printing a byte stream (command "P"), this bc follows what
73//config: the FreeBSD dc does.
74//config: 2) This dc implements the GNU extensions for divmod ("~") and
75//config: modular exponentiation ("|").
76//config: 3) This dc implements all FreeBSD extensions, except for "J" and
77//config: "M".
78//config: 4) Like the FreeBSD dc, this dc supports extended registers.
79//config: However, they are implemented differently. When it encounters
80//config: whitespace where a register should be, it skips the whitespace.
81//config: If the character following is not a lowercase letter, an error
82//config: is issued. Otherwise, the register name is parsed by the
83//config: following regex:
84//config:
85//config: [a-z][a-z0-9_]*
86//config:
87//config: This generally means that register names will be surrounded by
88//config: whitespace.
89//config:
90//config: Examples:
91//config:
92//config: l idx s temp L index S temp2 < do_thing
93//config:
94//config: Also note that, like the FreeBSD dc, extended registers are not
95//config: allowed unless the "-x" option is given.
96//config:
97//config:config FEATURE_BC_SIGNALS
98//config: bool "Enable bc/dc signal handling"
99//config: default y
100//config: depends on BC || DC
101//config: help
102//config: Enable signal handling for bc and dc.
103//config:
104//config:config FEATURE_BC_LONG_OPTIONS
105//config: bool "Enable bc/dc long options"
106//config: default y
107//config: depends on BC || DC
108//config: help
109//config: Enable long options for bc and dc.
110
111//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
113
114//kbuild:lib-$(CONFIG_BC) += bc.o
115//kbuild:lib-$(CONFIG_DC) += bc.o
116
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100117//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600118//usage:#define bc_trivial_usage
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100119//usage: "[-sqli] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600120//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100121//usage:#define bc_full_usage "\n"
122//usage: "\nArbitrary precision calculator"
123//usage: "\n"
124//usage: "\n -i Interactive"
125//usage: "\n -l Load standard math library"
126//usage: "\n -s Be POSIX compatible"
127//usage: "\n -q Quiet"
128//usage: "\n -w Warn if extensions are used"
129///////: "\n -v Version"
Gavin Howard01055ba2018-11-03 11:00:21 -0600130//usage:
131//usage:#define bc_example_usage
132//usage: "3 + 4.129\n"
133//usage: "1903 - 2893\n"
134//usage: "-129 * 213.28935\n"
135//usage: "12 / -1932\n"
136//usage: "12 % 12\n"
137//usage: "34 ^ 189\n"
138//usage: "scale = 13\n"
139//usage: "ibase = 2\n"
140//usage: "obase = A\n"
141//usage:
142//usage:#define dc_trivial_usage
143//usage: "EXPRESSION..."
144//usage:
145//usage:#define dc_full_usage "\n\n"
146//usage: "Tiny RPN calculator. Operations:\n"
147//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148//usage: "modular exponentiation,\n"
149//usage: "p - print top of the stack (without popping),\n"
150//usage: "f - print entire stack,\n"
151//usage: "k - pop the value and set the precision.\n"
152//usage: "i - pop the value and set input radix.\n"
153//usage: "o - pop the value and set output radix.\n"
154//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
155//usage:
156//usage:#define dc_example_usage
157//usage: "$ dc 2 2 + p\n"
158//usage: "4\n"
159//usage: "$ dc 8 8 \\* 2 2 + / p\n"
160//usage: "16\n"
161//usage: "$ dc 0 1 and p\n"
162//usage: "0\n"
163//usage: "$ dc 0 1 or p\n"
164//usage: "1\n"
165//usage: "$ echo 72 9 div 8 mul p | dc\n"
166//usage: "64\n"
167
168#include "libbb.h"
169
170typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600174} BcStatus;
175
Gavin Howard01055ba2018-11-03 11:00:21 -0600176#define BC_VEC_INVALID_IDX ((size_t) -1)
177#define BC_VEC_START_CAP (1 << 5)
178
179typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600180
181typedef struct BcVec {
182 char *v;
183 size_t len;
184 size_t cap;
185 size_t size;
186 BcVecFree dtor;
187} BcVec;
188
189#define bc_vec_pop(v) (bc_vec_npop((v), 1))
190#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
191
Gavin Howard01055ba2018-11-03 11:00:21 -0600192typedef signed char BcDig;
193
194typedef struct BcNum {
195 BcDig *restrict num;
196 size_t rdx;
197 size_t len;
198 size_t cap;
199 bool neg;
200} BcNum;
201
202#define BC_NUM_MIN_BASE ((unsigned long) 2)
203#define BC_NUM_MAX_IBASE ((unsigned long) 16)
204#define BC_NUM_DEF_SIZE (16)
205#define BC_NUM_PRINT_WIDTH (69)
206
207#define BC_NUM_KARATSUBA_LEN (32)
208
209#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212#define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214#define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
216
217typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
219
220static void bc_num_init(BcNum *n, size_t req);
221static void bc_num_expand(BcNum *n, size_t req);
222static void bc_num_copy(BcNum *d, BcNum *s);
223static void bc_num_free(void *num);
224
225static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100226static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600227
228static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
236 size_t scale);
237
238typedef enum BcInst {
239
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100240#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600241 BC_INST_INC_PRE,
242 BC_INST_DEC_PRE,
243 BC_INST_INC_POST,
244 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100245#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600246
247 BC_INST_NEG,
248
249 BC_INST_POWER,
250 BC_INST_MULTIPLY,
251 BC_INST_DIVIDE,
252 BC_INST_MODULUS,
253 BC_INST_PLUS,
254 BC_INST_MINUS,
255
256 BC_INST_REL_EQ,
257 BC_INST_REL_LE,
258 BC_INST_REL_GE,
259 BC_INST_REL_NE,
260 BC_INST_REL_LT,
261 BC_INST_REL_GT,
262
263 BC_INST_BOOL_NOT,
264 BC_INST_BOOL_OR,
265 BC_INST_BOOL_AND,
266
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100267#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
272 BC_INST_ASSIGN_PLUS,
273 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100274#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600275 BC_INST_ASSIGN,
276
277 BC_INST_NUM,
278 BC_INST_VAR,
279 BC_INST_ARRAY_ELEM,
280 BC_INST_ARRAY,
281
282 BC_INST_SCALE_FUNC,
283 BC_INST_IBASE,
284 BC_INST_SCALE,
285 BC_INST_LAST,
286 BC_INST_LENGTH,
287 BC_INST_READ,
288 BC_INST_OBASE,
289 BC_INST_SQRT,
290
291 BC_INST_PRINT,
292 BC_INST_PRINT_POP,
293 BC_INST_STR,
294 BC_INST_PRINT_STR,
295
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100296#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600297 BC_INST_JUMP,
298 BC_INST_JUMP_ZERO,
299
300 BC_INST_CALL,
301
302 BC_INST_RET,
303 BC_INST_RET0,
304
305 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100306#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600307
308 BC_INST_POP,
309 BC_INST_POP_EXEC,
310
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100311#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600312 BC_INST_MODEXP,
313 BC_INST_DIVMOD,
314
315 BC_INST_EXECUTE,
316 BC_INST_EXEC_COND,
317
318 BC_INST_ASCIIFY,
319 BC_INST_PRINT_STREAM,
320
321 BC_INST_PRINT_STACK,
322 BC_INST_CLEAR_STACK,
323 BC_INST_STACK_LEN,
324 BC_INST_DUPLICATE,
325 BC_INST_SWAP,
326
327 BC_INST_LOAD,
328 BC_INST_PUSH_VAR,
329 BC_INST_PUSH_TO_VAR,
330
331 BC_INST_QUIT,
332 BC_INST_NQUIT,
333
334 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100335#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600336
337} BcInst;
338
339typedef struct BcId {
340 char *name;
341 size_t idx;
342} BcId;
343
344typedef struct BcFunc {
345 BcVec code;
346 BcVec labels;
347 size_t nparams;
348 BcVec autos;
349} BcFunc;
350
351typedef enum BcResultType {
352
353 BC_RESULT_TEMP,
354
355 BC_RESULT_VAR,
356 BC_RESULT_ARRAY_ELEM,
357 BC_RESULT_ARRAY,
358
359 BC_RESULT_STR,
360
361 BC_RESULT_IBASE,
362 BC_RESULT_SCALE,
363 BC_RESULT_LAST,
364
365 // These are between to calculate ibase, obase, and last from instructions.
366 BC_RESULT_CONSTANT,
367 BC_RESULT_ONE,
368
369 BC_RESULT_OBASE,
370
371} BcResultType;
372
373typedef union BcResultData {
374 BcNum n;
375 BcVec v;
376 BcId id;
377} BcResultData;
378
379typedef struct BcResult {
380 BcResultType t;
381 BcResultData d;
382} BcResult;
383
384typedef struct BcInstPtr {
385 size_t func;
386 size_t idx;
387 size_t len;
388} BcInstPtr;
389
390static void bc_array_expand(BcVec *a, size_t len);
391static int bc_id_cmp(const void *e1, const void *e2);
392
393// BC_LEX_NEG is not used in lexing; it is only for parsing.
394typedef enum BcLexType {
395
396 BC_LEX_EOF,
397 BC_LEX_INVALID,
398
399 BC_LEX_OP_INC,
400 BC_LEX_OP_DEC,
401
402 BC_LEX_NEG,
403
404 BC_LEX_OP_POWER,
405 BC_LEX_OP_MULTIPLY,
406 BC_LEX_OP_DIVIDE,
407 BC_LEX_OP_MODULUS,
408 BC_LEX_OP_PLUS,
409 BC_LEX_OP_MINUS,
410
411 BC_LEX_OP_REL_EQ,
412 BC_LEX_OP_REL_LE,
413 BC_LEX_OP_REL_GE,
414 BC_LEX_OP_REL_NE,
415 BC_LEX_OP_REL_LT,
416 BC_LEX_OP_REL_GT,
417
418 BC_LEX_OP_BOOL_NOT,
419 BC_LEX_OP_BOOL_OR,
420 BC_LEX_OP_BOOL_AND,
421
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
428 BC_LEX_OP_ASSIGN,
429
430 BC_LEX_NLINE,
431 BC_LEX_WHITESPACE,
432
433 BC_LEX_LPAREN,
434 BC_LEX_RPAREN,
435
436 BC_LEX_LBRACKET,
437 BC_LEX_COMMA,
438 BC_LEX_RBRACKET,
439
440 BC_LEX_LBRACE,
441 BC_LEX_SCOLON,
442 BC_LEX_RBRACE,
443
444 BC_LEX_STR,
445 BC_LEX_NAME,
446 BC_LEX_NUMBER,
447
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600450 BC_LEX_KEY_BREAK,
451 BC_LEX_KEY_CONTINUE,
452 BC_LEX_KEY_DEFINE,
453 BC_LEX_KEY_ELSE,
454 BC_LEX_KEY_FOR,
455 BC_LEX_KEY_HALT,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600458 BC_LEX_KEY_IF,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600460 BC_LEX_KEY_LENGTH,
461 BC_LEX_KEY_LIMITS,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600463 BC_LEX_KEY_PRINT,
464 BC_LEX_KEY_QUIT,
465 BC_LEX_KEY_READ,
466 BC_LEX_KEY_RETURN,
467 BC_LEX_KEY_SCALE,
468 BC_LEX_KEY_SQRT,
469 BC_LEX_KEY_WHILE,
470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100471#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_EQ_NO_REG,
473 BC_LEX_OP_MODEXP,
474 BC_LEX_OP_DIVMOD,
475
476 BC_LEX_COLON,
477 BC_LEX_ELSE,
478 BC_LEX_EXECUTE,
479 BC_LEX_PRINT_STACK,
480 BC_LEX_CLEAR_STACK,
481 BC_LEX_STACK_LEVEL,
482 BC_LEX_DUPLICATE,
483 BC_LEX_SWAP,
484 BC_LEX_POP,
485
486 BC_LEX_ASCIIFY,
487 BC_LEX_PRINT_STREAM,
488
489 BC_LEX_STORE_IBASE,
490 BC_LEX_STORE_SCALE,
491 BC_LEX_LOAD,
492 BC_LEX_LOAD_POP,
493 BC_LEX_STORE_PUSH,
494 BC_LEX_STORE_OBASE,
495 BC_LEX_PRINT_POP,
496 BC_LEX_NQUIT,
497 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100498#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600499} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100500// must match order of BC_LEX_KEY_foo etc above
501#if ENABLE_BC
502struct BcLexKeyword {
503 char name8[8];
504};
505#define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
512
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
517
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
522
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
527
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
532};
533enum {
534 POSIX_KWORD_MASK = 0
535 | (1 << 0)
536 | (1 << 1)
537 | (0 << 2)
538 | (1 << 3)
539 \
540 | (0 << 4)
541 | (1 << 5)
542 | (0 << 6)
543 | (1 << 7)
544 \
545 | (1 << 8)
546 | (0 << 9)
547 | (1 << 10)
548 | (0 << 11)
549 \
550 | (1 << 12)
551 | (0 << 13)
552 | (1 << 14)
553 | (0 << 15)
554 \
555 | (1 << 16)
556 | (1 << 17)
557 | (1 << 18)
558 | (1 << 19)
559};
560#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600561
562struct BcLex;
563typedef BcStatus (*BcLexNext)(struct BcLex *);
564
565typedef struct BcLex {
566
567 const char *buf;
568 size_t i;
569 size_t line;
570 const char *f;
571 size_t len;
572 bool newline;
573
574 struct {
575 BcLexType t;
576 BcLexType last;
577 BcVec v;
578 } t;
579
580 BcLexNext next;
581
582} BcLex;
583
584#define BC_PARSE_STREND ((char) UCHAR_MAX)
585
586#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
587#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100588 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600589
590#define BC_PARSE_REL (1 << 0)
591#define BC_PARSE_PRINT (1 << 1)
592#define BC_PARSE_NOCALL (1 << 2)
593#define BC_PARSE_NOREAD (1 << 3)
594#define BC_PARSE_ARRAY (1 << 4)
595
596#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
597#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
598
599#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
600#define BC_PARSE_FUNC_INNER(parse) \
601 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
602
603#define BC_PARSE_FLAG_FUNC (1 << 1)
604#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
605
606#define BC_PARSE_FLAG_BODY (1 << 2)
607#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
608
609#define BC_PARSE_FLAG_LOOP (1 << 3)
610#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
611
612#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
613#define BC_PARSE_LOOP_INNER(parse) \
614 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
615
616#define BC_PARSE_FLAG_IF (1 << 5)
617#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
618
619#define BC_PARSE_FLAG_ELSE (1 << 6)
620#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
621
622#define BC_PARSE_FLAG_IF_END (1 << 7)
623#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
624
625#define BC_PARSE_CAN_EXEC(parse) \
626 (!(BC_PARSE_TOP_FLAG(parse) & \
627 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
628 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
629 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
630
631typedef struct BcOp {
632 char prec;
633 bool left;
634} BcOp;
635
636typedef struct BcParseNext {
637 uint32_t len;
638 BcLexType tokens[4];
639} BcParseNext;
640
641#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
642#define BC_PARSE_NEXT(a, ...) \
643 { \
644 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
645 }
646
647struct BcParse;
648
649struct BcProgram;
650
Gavin Howard01055ba2018-11-03 11:00:21 -0600651typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600652
653typedef struct BcParse {
654
655 BcParseParse parse;
656
657 BcLex l;
658
659 BcVec flags;
660
661 BcVec exits;
662 BcVec conds;
663
664 BcVec ops;
665
Gavin Howard01055ba2018-11-03 11:00:21 -0600666 BcFunc *func;
667 size_t fidx;
668
669 size_t nbraces;
670 bool auto_part;
671
672} BcParse;
673
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100674#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600675
Gavin Howard01055ba2018-11-03 11:00:21 -0600676static BcStatus bc_lex_token(BcLex *l);
677
678#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
679#define BC_PARSE_LEAF(p, rparen) \
680 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
681 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
682
683// We can calculate the conversion between tokens and exprs by subtracting the
684// position of the first operator in the lex enum and adding the position of the
685// first in the expr enum. Note: This only works for binary operators.
686#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
687
Gavin Howard01055ba2018-11-03 11:00:21 -0600688static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
689
Denys Vlasenko00d77792018-11-30 23:13:42 +0100690#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600691
Denys Vlasenko00d77792018-11-30 23:13:42 +0100692#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600693
694#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
695
Gavin Howard01055ba2018-11-03 11:00:21 -0600696static BcStatus dc_lex_token(BcLex *l);
697
Gavin Howard01055ba2018-11-03 11:00:21 -0600698static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
699
700#endif // ENABLE_DC
701
702typedef struct BcProgram {
703
704 size_t len;
705 size_t scale;
706
707 BcNum ib;
708 size_t ib_t;
709 BcNum ob;
710 size_t ob_t;
711
712 BcNum hexb;
713
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100714#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600715 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100716#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600717
718 BcVec results;
719 BcVec stack;
720
721 BcVec fns;
722 BcVec fn_map;
723
724 BcVec vars;
725 BcVec var_map;
726
727 BcVec arrs;
728 BcVec arr_map;
729
730 BcVec strs;
731 BcVec consts;
732
733 const char *file;
734
735 BcNum last;
736 BcNum zero;
737 BcNum one;
738
739 size_t nchars;
740
Gavin Howard01055ba2018-11-03 11:00:21 -0600741} BcProgram;
742
743#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
744
745#define BC_PROG_MAIN (0)
746#define BC_PROG_READ (1)
747
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100748#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600749#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100750#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600751
752#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
753#define BC_PROG_NUM(r, n) \
754 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
755
756typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
757
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100758static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100759static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600760
761#define BC_FLAG_X (1 << 0)
762#define BC_FLAG_W (1 << 1)
763#define BC_FLAG_V (1 << 2)
764#define BC_FLAG_S (1 << 3)
765#define BC_FLAG_Q (1 << 4)
766#define BC_FLAG_L (1 << 5)
767#define BC_FLAG_I (1 << 6)
768
769#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
770#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
771
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100772#define BC_MAX_OBASE ((unsigned) 999)
773#define BC_MAX_DIM ((unsigned) INT_MAX)
774#define BC_MAX_SCALE ((unsigned) UINT_MAX)
775#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
776#define BC_MAX_NAME BC_MAX_STRING
777#define BC_MAX_NUM BC_MAX_STRING
778#define BC_MAX_EXP ((unsigned long) LONG_MAX)
779#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600780
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100781struct globals {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100782 smallint ttyin;
783 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600784 char sbgn;
785 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600786
787 BcParse prs;
788 BcProgram prog;
789
Gavin Howard01055ba2018-11-03 11:00:21 -0600790 BcVec files;
791
792 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100793} FIX_ALIASING;
794#define G (*ptr_to_globals)
795#define INIT_G() do { \
796 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
797} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100798#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
799#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
800#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100801#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600802
Gavin Howard01055ba2018-11-03 11:00:21 -0600803
Denys Vlasenko00d77792018-11-30 23:13:42 +0100804#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
805
Denys Vlasenko00d77792018-11-30 23:13:42 +0100806static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600807
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100808#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600809
810// This is an array that corresponds to token types. An entry is
811// true if the token is valid in an expression, false otherwise.
812static const bool bc_parse_exprs[] = {
813 false, false, true, true, true, true, true, true, true, true, true, true,
814 true, true, true, true, true, true, true, true, true, true, true, true,
815 true, true, true, false, false, true, true, false, false, false, false,
816 false, false, false, true, true, false, false, false, false, false, false,
817 false, true, false, true, true, true, true, false, false, true, false, true,
818 true, false,
819};
820
821// This is an array of data for operators that correspond to token types.
822static const BcOp bc_parse_ops[] = {
823 { 0, false }, { 0, false },
824 { 1, false },
825 { 2, false },
826 { 3, true }, { 3, true }, { 3, true },
827 { 4, true }, { 4, true },
828 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
829 { 1, false },
830 { 7, true }, { 7, true },
831 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
832 { 5, false }, { 5, false },
833};
834
835// These identify what tokens can come after expressions in certain cases.
836static const BcParseNext bc_parse_next_expr =
837 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
838static const BcParseNext bc_parse_next_param =
839 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
840static const BcParseNext bc_parse_next_print =
841 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
842static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
843static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
844static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
845static const BcParseNext bc_parse_next_read =
846 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
847#endif // ENABLE_BC
848
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100849#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600850static const BcLexType dc_lex_regs[] = {
851 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
852 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
853 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
854 BC_LEX_STORE_PUSH,
855};
856
Gavin Howard01055ba2018-11-03 11:00:21 -0600857static const BcLexType dc_lex_tokens[] = {
858 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
859 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
860 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
861 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
862 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
863 BC_LEX_INVALID, BC_LEX_INVALID,
864 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
865 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
868 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
869 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
870 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
871 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
872 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
873 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
874 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
875 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
877 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
878 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
879 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
880 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
881 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
882 BC_LEX_INVALID
883};
884
885static const BcInst dc_parse_insts[] = {
886 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
887 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
888 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
890 BC_INST_INVALID, BC_INST_INVALID,
891 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
896 BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
899 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
901 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
903 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
904 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
905 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
906 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
908 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
909};
910#endif // ENABLE_DC
911
Gavin Howard01055ba2018-11-03 11:00:21 -0600912static const BcNumBinaryOp bc_program_ops[] = {
913 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
914};
915
916static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600917
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100918#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600919static const char *bc_lib_name = "gen/lib.bc";
920
921static const char bc_lib[] = {
Denys Vlasenko68cc0a62018-12-05 00:35:49 +0100922 "scale=20"
923"\n" "define e(x){"
924"\n" "auto b,s,n,r,d,i,p,f,v"
925"\n" "b=ibase"
926"\n" "ibase=A"
927"\n" "if(x<0){"
928"\n" "n=1"
929"\n" "x=-x"
930"\n" "}"
931"\n" "s=scale"
932"\n" "r=6+s+0.44*x"
933"\n" "scale=scale(x)+1"
934"\n" "while(x>1){"
935"\n" "d+=1"
936"\n" "x/=2"
937"\n" "scale+=1"
938"\n" "}"
939"\n" "scale=r"
940"\n" "r=x+1"
941"\n" "p=x"
942"\n" "f=v=1"
943"\n" "for(i=2;v!=0;++i){"
944"\n" "p*=x"
945"\n" "f*=i"
946"\n" "v=p/f"
947"\n" "r+=v"
948"\n" "}"
949"\n" "while((d--)!=0)r*=r"
950"\n" "scale=s"
951"\n" "ibase=b"
952"\n" "if(n!=0)return(1/r)"
953"\n" "return(r/1)"
954"\n" "}"
955"\n" "define l(x){"
956"\n" "auto b,s,r,p,a,q,i,v"
957"\n" "b=ibase"
958"\n" "ibase=A"
959"\n" "if(x<=0){"
960"\n" "r=(1-10^scale)/1"
961"\n" "ibase=b"
962"\n" "return(r)"
963"\n" "}"
964"\n" "s=scale"
965"\n" "scale+=6"
966"\n" "p=2"
967"\n" "while(x>=2){"
968"\n" "p*=2"
969"\n" "x=sqrt(x)"
970"\n" "}"
971"\n" "while(x<=0.5){"
972"\n" "p*=2"
973"\n" "x=sqrt(x)"
974"\n" "}"
975"\n" "r=a=(x-1)/(x+1)"
976"\n" "q=a*a"
977"\n" "v=1"
978"\n" "for(i=3;v!=0;i+=2){"
979"\n" "a*=q"
980"\n" "v=a/i"
981"\n" "r+=v"
982"\n" "}"
983"\n" "r*=p"
984"\n" "scale=s"
985"\n" "ibase=b"
986"\n" "return(r/1)"
987"\n" "}"
988"\n" "define s(x){"
989"\n" "auto b,s,r,n,a,q,i"
990"\n" "b=ibase"
991"\n" "ibase=A"
992"\n" "s=scale"
993"\n" "scale=1.1*s+2"
994"\n" "a=a(1)"
995"\n" "if(x<0){"
996"\n" "n=1"
997"\n" "x=-x"
998"\n" "}"
999"\n" "scale=0"
1000"\n" "q=(x/a+2)/4"
1001"\n" "x=x-4*q*a"
1002"\n" "if(q%2!=0)x=-x"
1003"\n" "scale=s+2"
1004"\n" "r=a=x"
1005"\n" "q=-x*x"
1006"\n" "for(i=3;a!=0;i+=2){"
1007"\n" "a*=q/(i*(i-1))"
1008"\n" "r+=a"
1009"\n" "}"
1010"\n" "scale=s"
1011"\n" "ibase=b"
1012"\n" "if(n!=0)return(-r/1)"
1013"\n" "return(r/1)"
1014"\n" "}"
1015"\n" "define c(x){"
1016"\n" "auto b,s"
1017"\n" "b=ibase"
1018"\n" "ibase=A"
1019"\n" "s=scale"
1020"\n" "scale*=1.2"
1021"\n" "x=s(2*a(1)+x)"
1022"\n" "scale=s"
1023"\n" "ibase=b"
1024"\n" "return(x/1)"
1025"\n" "}"
1026"\n" "define a(x){"
1027"\n" "auto b,s,r,n,a,m,t,f,i,u"
1028"\n" "b=ibase"
1029"\n" "ibase=A"
1030"\n" "n=1"
1031"\n" "if(x<0){"
1032"\n" "n=-1"
1033"\n" "x=-x"
1034"\n" "}"
1035"\n" "if(x==1){"
1036"\n" "if(scale<65){"
1037"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
1038"\n" "}"
1039"\n" "}"
1040"\n" "if(x==.2){"
1041"\n" "if(scale<65){"
1042"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
1043"\n" "}"
1044"\n" "}"
1045"\n" "s=scale"
1046"\n" "if(x>.2){"
1047"\n" "scale+=5"
1048"\n" "a=a(.2)"
1049"\n" "}"
1050"\n" "scale=s+3"
1051"\n" "while(x>.2){"
1052"\n" "m+=1"
1053"\n" "x=(x-.2)/(1+.2*x)"
1054"\n" "}"
1055"\n" "r=u=x"
1056"\n" "f=-x*x"
1057"\n" "t=1"
1058"\n" "for(i=3;t!=0;i+=2){"
1059"\n" "u*=f"
1060"\n" "t=u/i"
1061"\n" "r+=t"
1062"\n" "}"
1063"\n" "scale=s"
1064"\n" "ibase=b"
1065"\n" "return((m*a+r)/n)"
1066"\n" "}"
1067"\n" "define j(n,x){"
1068"\n" "auto b,s,o,a,i,v,f"
1069"\n" "b=ibase"
1070"\n" "ibase=A"
1071"\n" "s=scale"
1072"\n" "scale=0"
1073"\n" "n/=1"
1074"\n" "if(n<0){"
1075"\n" "n=-n"
1076"\n" "if(n%2==1)o=1"
1077"\n" "}"
1078"\n" "a=1"
1079"\n" "for(i=2;i<=n;++i)a*=i"
1080"\n" "scale=1.5*s"
1081"\n" "a=(x^n)/2^n/a"
1082"\n" "r=v=1"
1083"\n" "f=-x*x/4"
1084"\n" "scale=scale+length(a)-scale(a)"
1085"\n" "for(i=1;v!=0;++i){"
1086"\n" "v=v*f/i/(n+i)"
1087"\n" "r+=v"
1088"\n" "}"
1089"\n" "scale=s"
1090"\n" "ibase=b"
1091"\n" "if(o!=0)a=-a"
1092"\n" "return(a*r/1)"
1093"\n" "}"
Gavin Howard01055ba2018-11-03 11:00:21 -06001094};
1095#endif // ENABLE_BC
1096
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001097static void fflush_and_check(void)
1098{
1099 fflush_all();
1100 if (ferror(stdout) || ferror(stderr))
1101 bb_perror_msg_and_die("output error");
1102}
1103
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001104static void quit(void) NORETURN;
1105static void quit(void)
1106{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001107 if (ferror(stdin))
1108 bb_perror_msg_and_die("input error");
1109 fflush_and_check();
1110 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001111}
1112
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001113static NOINLINE int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001114{
1115 va_list p;
1116
1117 va_start(p, fmt);
1118 bb_verror_msg(fmt, p, NULL);
1119 va_end(p);
1120 if (!G.ttyin)
1121 exit(1);
1122 return BC_STATUS_FAILURE;
1123}
1124
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001125static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001126{
1127 va_list p;
1128
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001129 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001130 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001131 return BC_STATUS_SUCCESS; // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001132
1133 va_start(p, fmt);
1134 bb_verror_msg(fmt, p, NULL);
1135 va_end(p);
1136
1137 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001138 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001139 return BC_STATUS_SUCCESS; // no, it's a warning
1140 if (!G.ttyin)
1141 exit(1);
1142 return BC_STATUS_FAILURE;
1143}
1144
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001145// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
1146// This idiom begs for tail-call optimization, but for it to work,
1147// function must not have calller-cleaned parameters on stack.
1148// Unfortunately, vararg functions do exactly that on most arches.
1149// Thus, these shims for the cases when we have no PARAMS:
1150static int bc_error(const char *msg)
1151{
1152 return bc_error_fmt("%s", msg);
1153}
1154static int bc_posix_error(const char *msg)
1155{
1156 return bc_posix_error_fmt("%s", msg);
1157}
1158static int bc_error_bad_character(char c)
1159{
1160 return bc_error_fmt("bad character '%c'", c);
1161}
1162static int bc_error_bad_expression(void)
1163{
1164 return bc_error("bad expression");
1165}
1166static int bc_error_bad_token(void)
1167{
1168 return bc_error("bad token");
1169}
1170static int bc_error_stack_has_too_few_elements(void)
1171{
1172 return bc_error("stack has too few elements");
1173}
1174static int bc_error_variable_is_wrong_type(void)
1175{
1176 return bc_error("variable is wrong type");
1177}
1178static int bc_error_nested_read_call(void)
1179{
1180 return bc_error("read() call inside of a read() call");
1181}
1182
Gavin Howard01055ba2018-11-03 11:00:21 -06001183static void bc_vec_grow(BcVec *v, size_t n)
1184{
1185 size_t cap = v->cap * 2;
1186 while (cap < v->len + n) cap *= 2;
1187 v->v = xrealloc(v->v, v->size * cap);
1188 v->cap = cap;
1189}
1190
1191static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1192{
1193 v->size = esize;
1194 v->cap = BC_VEC_START_CAP;
1195 v->len = 0;
1196 v->dtor = dtor;
1197 v->v = xmalloc(esize * BC_VEC_START_CAP);
1198}
1199
Denys Vlasenko7d628012018-12-04 21:46:47 +01001200static void bc_char_vec_init(BcVec *v)
1201{
1202 bc_vec_init(v, sizeof(char), NULL);
1203}
1204
Gavin Howard01055ba2018-11-03 11:00:21 -06001205static void bc_vec_expand(BcVec *v, size_t req)
1206{
1207 if (v->cap < req) {
1208 v->v = xrealloc(v->v, v->size * req);
1209 v->cap = req;
1210 }
1211}
1212
1213static void bc_vec_npop(BcVec *v, size_t n)
1214{
1215 if (!v->dtor)
1216 v->len -= n;
1217 else {
1218 size_t len = v->len - n;
1219 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1220 }
1221}
1222
Denys Vlasenko7d628012018-12-04 21:46:47 +01001223static void bc_vec_pop_all(BcVec *v)
1224{
1225 bc_vec_npop(v, v->len);
1226}
1227
Gavin Howard01055ba2018-11-03 11:00:21 -06001228static void bc_vec_push(BcVec *v, const void *data)
1229{
1230 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1231 memmove(v->v + (v->size * v->len), data, v->size);
1232 v->len += 1;
1233}
1234
1235static void bc_vec_pushByte(BcVec *v, char data)
1236{
1237 bc_vec_push(v, &data);
1238}
1239
1240static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1241{
1242 if (idx == v->len)
1243 bc_vec_push(v, data);
1244 else {
1245
1246 char *ptr;
1247
1248 if (v->len == v->cap) bc_vec_grow(v, 1);
1249
1250 ptr = v->v + v->size * idx;
1251
1252 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1253 memmove(ptr, data, v->size);
1254 }
1255}
1256
1257static void bc_vec_string(BcVec *v, size_t len, const char *str)
1258{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001259 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001260 bc_vec_expand(v, len + 1);
1261 memcpy(v->v, str, len);
1262 v->len = len;
1263
1264 bc_vec_pushByte(v, '\0');
1265}
1266
1267static void bc_vec_concat(BcVec *v, const char *str)
1268{
1269 size_t len;
1270
1271 if (v->len == 0) bc_vec_pushByte(v, '\0');
1272
1273 len = v->len + strlen(str);
1274
1275 if (v->cap < len) bc_vec_grow(v, len - v->len);
1276 strcat(v->v, str);
1277
1278 v->len = len;
1279}
1280
1281static void *bc_vec_item(const BcVec *v, size_t idx)
1282{
1283 return v->v + v->size * idx;
1284}
1285
1286static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1287{
1288 return v->v + v->size * (v->len - idx - 1);
1289}
1290
1291static void bc_vec_free(void *vec)
1292{
1293 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001294 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001295 free(v->v);
1296}
1297
1298static size_t bc_map_find(const BcVec *v, const void *ptr)
1299{
1300 size_t low = 0, high = v->len;
1301
1302 while (low < high) {
1303
1304 size_t mid = (low + high) / 2;
1305 BcId *id = bc_vec_item(v, mid);
1306 int result = bc_id_cmp(ptr, id);
1307
1308 if (result == 0)
1309 return mid;
1310 else if (result < 0)
1311 high = mid;
1312 else
1313 low = mid + 1;
1314 }
1315
1316 return low;
1317}
1318
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001319static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001320{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001321 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001322
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001323 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001324 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001325 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1326 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001327 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001328 bc_vec_pushAt(v, ptr, n);
1329 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001330}
1331
1332static size_t bc_map_index(const BcVec *v, const void *ptr)
1333{
1334 size_t i = bc_map_find(v, ptr);
1335 if (i >= v->len) return BC_VEC_INVALID_IDX;
1336 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1337}
1338
1339static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1340{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001341 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001342
Denys Vlasenko00d77792018-11-30 23:13:42 +01001343 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001344 int i;
1345 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001346
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001347 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001348 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001349
1350 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001351#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001352 if (bb_got_signal) { // ^C was pressed
1353 intr:
1354 bb_got_signal = 0; // resets G_interrupt to zero
1355 fputs(IS_BC
1356 ? "\ninterrupt (type \"quit\" to exit)\n"
1357 : "\ninterrupt (type \"q\" to exit)\n"
1358 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001359 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001360#endif
1361 if (G.ttyin && !G_posix)
1362 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001363
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001364#if ENABLE_FEATURE_BC_SIGNALS
1365 errno = 0;
1366#endif
1367 do {
1368 i = fgetc(stdin);
1369 if (i == EOF) {
1370#if ENABLE_FEATURE_BC_SIGNALS
1371 // Both conditions appear simultaneously, check both just in case
1372 if (errno == EINTR || bb_got_signal) {
1373 // ^C was pressed
1374 clearerr(stdin);
1375 goto intr;
1376 }
1377#endif
1378 if (ferror(stdin))
1379 quit(); // this emits error message
1380 G.eof = 1;
1381 // Note: EOF does not append '\n', therefore:
1382 // printf 'print 123\n' | bc - works
1383 // printf 'print 123' | bc - fails (syntax error)
1384 break;
1385 }
1386
1387 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1388 || i > 0x7e
1389 ) {
1390 // Bad chars on this line, ignore entire line
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001391 bc_error_fmt("illegal character 0x%02x", i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001392 bad_chars = 1;
1393 }
1394 c = (char) i;
1395 bc_vec_push(vec, &c);
1396 } while (i != '\n');
1397 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001398
1399 bc_vec_pushByte(vec, '\0');
1400
1401 return BC_STATUS_SUCCESS;
1402}
1403
Denys Vlasenkodf515392018-12-02 19:27:48 +01001404static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001405{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001406 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001407 size_t size = ((size_t) -1);
1408 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001409
Denys Vlasenkodf515392018-12-02 19:27:48 +01001410 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001411
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001412 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001413 char c = buf[i];
1414 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1415 || c > 0x7e
1416 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001417 free(buf);
1418 buf = NULL;
1419 break;
1420 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001421 }
1422
Denys Vlasenkodf515392018-12-02 19:27:48 +01001423 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001424}
1425
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001426static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001427{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001428 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001429 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001430
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001431 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001432#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001433 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001434 "extended-register\0" No_argument "x"
1435 "warn\0" No_argument "w"
1436 "version\0" No_argument "v"
1437 "standard\0" No_argument "s"
1438 "quiet\0" No_argument "q"
1439 "mathlib\0" No_argument "l"
1440 "interactive\0" No_argument "i"
1441 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001442#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001443 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001444#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001445 if (getenv("POSIXLY_CORRECT"))
1446 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001447
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001448 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001449 // should not be necessary, getopt32() handles this??
1450 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001451
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001452 for (i = optind; i < argc; ++i)
1453 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001454}
1455
1456static void bc_num_setToZero(BcNum *n, size_t scale)
1457{
1458 n->len = 0;
1459 n->neg = false;
1460 n->rdx = scale;
1461}
1462
1463static void bc_num_zero(BcNum *n)
1464{
1465 bc_num_setToZero(n, 0);
1466}
1467
1468static void bc_num_one(BcNum *n)
1469{
1470 bc_num_setToZero(n, 0);
1471 n->len = 1;
1472 n->num[0] = 1;
1473}
1474
1475static void bc_num_ten(BcNum *n)
1476{
1477 bc_num_setToZero(n, 0);
1478 n->len = 2;
1479 n->num[0] = 0;
1480 n->num[1] = 1;
1481}
1482
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001483static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001484 size_t len)
1485{
1486 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001487 for (i = 0; i < len; ++i) {
1488 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001489 a[i + j++] += 10;
1490 a[i + j] -= 1;
1491 }
1492 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001493}
1494
1495static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1496{
1497 size_t i;
1498 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001499 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001500 return BC_NUM_NEG(i + 1, c < 0);
1501}
1502
1503static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1504{
1505 size_t i, min, a_int, b_int, diff;
1506 BcDig *max_num, *min_num;
1507 bool a_max, neg = false;
1508 ssize_t cmp;
1509
1510 if (a == b) return 0;
1511 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1512 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1513 if (a->neg) {
1514 if (b->neg)
1515 neg = true;
1516 else
1517 return -1;
1518 }
1519 else if (b->neg)
1520 return 1;
1521
1522 a_int = BC_NUM_INT(a);
1523 b_int = BC_NUM_INT(b);
1524 a_int -= b_int;
1525 a_max = (a->rdx > b->rdx);
1526
1527 if (a_int != 0) return (ssize_t) a_int;
1528
1529 if (a_max) {
1530 min = b->rdx;
1531 diff = a->rdx - b->rdx;
1532 max_num = a->num + diff;
1533 min_num = b->num;
1534 }
1535 else {
1536 min = a->rdx;
1537 diff = b->rdx - a->rdx;
1538 max_num = b->num + diff;
1539 min_num = a->num;
1540 }
1541
1542 cmp = bc_num_compare(max_num, min_num, b_int + min);
1543 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1544
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001545 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001546 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1547 }
1548
1549 return 0;
1550}
1551
1552static void bc_num_truncate(BcNum *n, size_t places)
1553{
1554 if (places == 0) return;
1555
1556 n->rdx -= places;
1557
1558 if (n->len != 0) {
1559 n->len -= places;
1560 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1561 }
1562}
1563
1564static void bc_num_extend(BcNum *n, size_t places)
1565{
1566 size_t len = n->len + places;
1567
1568 if (places != 0) {
1569
1570 if (n->cap < len) bc_num_expand(n, len);
1571
1572 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1573 memset(n->num, 0, sizeof(BcDig) * places);
1574
1575 n->len += places;
1576 n->rdx += places;
1577 }
1578}
1579
1580static void bc_num_clean(BcNum *n)
1581{
1582 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1583 if (n->len == 0)
1584 n->neg = false;
1585 else if (n->len < n->rdx)
1586 n->len = n->rdx;
1587}
1588
1589static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1590{
1591 if (n->rdx < scale)
1592 bc_num_extend(n, scale - n->rdx);
1593 else
1594 bc_num_truncate(n, n->rdx - scale);
1595
1596 bc_num_clean(n);
1597 if (n->len != 0) n->neg = !neg1 != !neg2;
1598}
1599
1600static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1601 BcNum *restrict b)
1602{
1603 if (idx < n->len) {
1604
1605 b->len = n->len - idx;
1606 a->len = idx;
1607 a->rdx = b->rdx = 0;
1608
1609 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1610 memcpy(a->num, n->num, idx * sizeof(BcDig));
1611 }
1612 else {
1613 bc_num_zero(b);
1614 bc_num_copy(a, n);
1615 }
1616
1617 bc_num_clean(a);
1618 bc_num_clean(b);
1619}
1620
1621static BcStatus bc_num_shift(BcNum *n, size_t places)
1622{
1623 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001624 if (places + n->len > BC_MAX_NUM)
1625 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001626
1627 if (n->rdx >= places)
1628 n->rdx -= places;
1629 else {
1630 bc_num_extend(n, places - n->rdx);
1631 n->rdx = 0;
1632 }
1633
1634 bc_num_clean(n);
1635
1636 return BC_STATUS_SUCCESS;
1637}
1638
1639static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1640{
1641 BcNum one;
1642 BcDig num[2];
1643
1644 one.cap = 2;
1645 one.num = num;
1646 bc_num_one(&one);
1647
1648 return bc_num_div(&one, a, b, scale);
1649}
1650
1651static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1652{
1653 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1654 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1655 int carry, in;
1656
1657 // Because this function doesn't need to use scale (per the bc spec),
1658 // I am hijacking it to say whether it's doing an add or a subtract.
1659
1660 if (a->len == 0) {
1661 bc_num_copy(c, b);
1662 if (sub && c->len) c->neg = !c->neg;
1663 return BC_STATUS_SUCCESS;
1664 }
1665 else if (b->len == 0) {
1666 bc_num_copy(c, a);
1667 return BC_STATUS_SUCCESS;
1668 }
1669
1670 c->neg = a->neg;
1671 c->rdx = BC_MAX(a->rdx, b->rdx);
1672 min_rdx = BC_MIN(a->rdx, b->rdx);
1673 c->len = 0;
1674
1675 if (a->rdx > b->rdx) {
1676 diff = a->rdx - b->rdx;
1677 ptr = a->num;
1678 ptr_a = a->num + diff;
1679 ptr_b = b->num;
1680 }
1681 else {
1682 diff = b->rdx - a->rdx;
1683 ptr = b->num;
1684 ptr_a = a->num;
1685 ptr_b = b->num + diff;
1686 }
1687
1688 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1689
1690 ptr_c += diff;
1691 a_int = BC_NUM_INT(a);
1692 b_int = BC_NUM_INT(b);
1693
1694 if (a_int > b_int) {
1695 min_int = b_int;
1696 max = a_int;
1697 ptr = ptr_a;
1698 }
1699 else {
1700 min_int = a_int;
1701 max = b_int;
1702 ptr = ptr_b;
1703 }
1704
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001705 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001706 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1707 carry = in / 10;
1708 ptr_c[i] = (BcDig)(in % 10);
1709 }
1710
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001711 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001712 in = ((int) ptr[i]) + carry;
1713 carry = in / 10;
1714 ptr_c[i] = (BcDig)(in % 10);
1715 }
1716
1717 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1718
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001719 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001720}
1721
1722static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1723{
Gavin Howard01055ba2018-11-03 11:00:21 -06001724 ssize_t cmp;
1725 BcNum *minuend, *subtrahend;
1726 size_t start;
1727 bool aneg, bneg, neg;
1728
1729 // Because this function doesn't need to use scale (per the bc spec),
1730 // I am hijacking it to say whether it's doing an add or a subtract.
1731
1732 if (a->len == 0) {
1733 bc_num_copy(c, b);
1734 if (sub && c->len) c->neg = !c->neg;
1735 return BC_STATUS_SUCCESS;
1736 }
1737 else if (b->len == 0) {
1738 bc_num_copy(c, a);
1739 return BC_STATUS_SUCCESS;
1740 }
1741
1742 aneg = a->neg;
1743 bneg = b->neg;
1744 a->neg = b->neg = false;
1745
1746 cmp = bc_num_cmp(a, b);
1747
1748 a->neg = aneg;
1749 b->neg = bneg;
1750
1751 if (cmp == 0) {
1752 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1753 return BC_STATUS_SUCCESS;
1754 }
1755 else if (cmp > 0) {
1756 neg = a->neg;
1757 minuend = a;
1758 subtrahend = b;
1759 }
1760 else {
1761 neg = b->neg;
1762 if (sub) neg = !neg;
1763 minuend = b;
1764 subtrahend = a;
1765 }
1766
1767 bc_num_copy(c, minuend);
1768 c->neg = neg;
1769
1770 if (c->rdx < subtrahend->rdx) {
1771 bc_num_extend(c, subtrahend->rdx - c->rdx);
1772 start = 0;
1773 }
1774 else
1775 start = c->rdx - subtrahend->rdx;
1776
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001777 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001778
1779 bc_num_clean(c);
1780
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001781 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001782}
1783
1784static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1785 BcNum *restrict c)
1786{
1787 BcStatus s;
1788 int carry;
1789 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1790 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1791 bool aone = BC_NUM_ONE(a);
1792
Gavin Howard01055ba2018-11-03 11:00:21 -06001793 if (a->len == 0 || b->len == 0) {
1794 bc_num_zero(c);
1795 return BC_STATUS_SUCCESS;
1796 }
1797 else if (aone || BC_NUM_ONE(b)) {
1798 bc_num_copy(c, aone ? b : a);
1799 return BC_STATUS_SUCCESS;
1800 }
1801
1802 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1803 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1804 {
1805 bc_num_expand(c, a->len + b->len + 1);
1806
1807 memset(c->num, 0, sizeof(BcDig) * c->cap);
1808 c->len = carry = len = 0;
1809
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001810 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001811
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001812 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001813 int in = (int) c->num[i + j];
1814 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1815 carry = in / 10;
1816 c->num[i + j] = (BcDig)(in % 10);
1817 }
1818
1819 c->num[i + j] += (BcDig) carry;
1820 len = BC_MAX(len, i + j + !!carry);
1821 carry = 0;
1822 }
1823
1824 c->len = len;
1825
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001826 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001827 }
1828
1829 bc_num_init(&l1, max);
1830 bc_num_init(&h1, max);
1831 bc_num_init(&l2, max);
1832 bc_num_init(&h2, max);
1833 bc_num_init(&m1, max);
1834 bc_num_init(&m2, max);
1835 bc_num_init(&z0, max);
1836 bc_num_init(&z1, max);
1837 bc_num_init(&z2, max);
1838 bc_num_init(&temp, max + max);
1839
1840 bc_num_split(a, max2, &l1, &h1);
1841 bc_num_split(b, max2, &l2, &h2);
1842
1843 s = bc_num_add(&h1, &l1, &m1, 0);
1844 if (s) goto err;
1845 s = bc_num_add(&h2, &l2, &m2, 0);
1846 if (s) goto err;
1847
1848 s = bc_num_k(&h1, &h2, &z0);
1849 if (s) goto err;
1850 s = bc_num_k(&m1, &m2, &z1);
1851 if (s) goto err;
1852 s = bc_num_k(&l1, &l2, &z2);
1853 if (s) goto err;
1854
1855 s = bc_num_sub(&z1, &z0, &temp, 0);
1856 if (s) goto err;
1857 s = bc_num_sub(&temp, &z2, &z1, 0);
1858 if (s) goto err;
1859
1860 s = bc_num_shift(&z0, max2 * 2);
1861 if (s) goto err;
1862 s = bc_num_shift(&z1, max2);
1863 if (s) goto err;
1864 s = bc_num_add(&z0, &z1, &temp, 0);
1865 if (s) goto err;
1866 s = bc_num_add(&temp, &z2, c, 0);
1867
1868err:
1869 bc_num_free(&temp);
1870 bc_num_free(&z2);
1871 bc_num_free(&z1);
1872 bc_num_free(&z0);
1873 bc_num_free(&m2);
1874 bc_num_free(&m1);
1875 bc_num_free(&h2);
1876 bc_num_free(&l2);
1877 bc_num_free(&h1);
1878 bc_num_free(&l1);
1879 return s;
1880}
1881
1882static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1883{
1884 BcStatus s;
1885 BcNum cpa, cpb;
1886 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1887
1888 scale = BC_MAX(scale, a->rdx);
1889 scale = BC_MAX(scale, b->rdx);
1890 scale = BC_MIN(a->rdx + b->rdx, scale);
1891 maxrdx = BC_MAX(maxrdx, scale);
1892
1893 bc_num_init(&cpa, a->len);
1894 bc_num_init(&cpb, b->len);
1895
1896 bc_num_copy(&cpa, a);
1897 bc_num_copy(&cpb, b);
1898 cpa.neg = cpb.neg = false;
1899
1900 s = bc_num_shift(&cpa, maxrdx);
1901 if (s) goto err;
1902 s = bc_num_shift(&cpb, maxrdx);
1903 if (s) goto err;
1904 s = bc_num_k(&cpa, &cpb, c);
1905 if (s) goto err;
1906
1907 maxrdx += scale;
1908 bc_num_expand(c, c->len + maxrdx);
1909
1910 if (c->len < maxrdx) {
1911 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1912 c->len += maxrdx;
1913 }
1914
1915 c->rdx = maxrdx;
1916 bc_num_retireMul(c, scale, a->neg, b->neg);
1917
1918err:
1919 bc_num_free(&cpb);
1920 bc_num_free(&cpa);
1921 return s;
1922}
1923
1924static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1925{
1926 BcStatus s = BC_STATUS_SUCCESS;
1927 BcDig *n, *p, q;
1928 size_t len, end, i;
1929 BcNum cp;
1930 bool zero = true;
1931
1932 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001933 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001934 else if (a->len == 0) {
1935 bc_num_setToZero(c, scale);
1936 return BC_STATUS_SUCCESS;
1937 }
1938 else if (BC_NUM_ONE(b)) {
1939 bc_num_copy(c, a);
1940 bc_num_retireMul(c, scale, a->neg, b->neg);
1941 return BC_STATUS_SUCCESS;
1942 }
1943
1944 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1945 bc_num_copy(&cp, a);
1946 len = b->len;
1947
1948 if (len > cp.len) {
1949 bc_num_expand(&cp, len + 2);
1950 bc_num_extend(&cp, len - cp.len);
1951 }
1952
1953 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1954 cp.rdx -= b->rdx;
1955 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1956
1957 if (b->rdx == b->len) {
1958 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1959 len -= i - 1;
1960 }
1961
1962 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1963
1964 // We want an extra zero in front to make things simpler.
1965 cp.num[cp.len++] = 0;
1966 end = cp.len - len;
1967
1968 bc_num_expand(c, cp.len);
1969
1970 bc_num_zero(c);
1971 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1972 c->rdx = cp.rdx;
1973 c->len = cp.len;
1974 p = b->num;
1975
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001976 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001977 n = cp.num + i;
1978 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001979 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001980 c->num[i] = q;
1981 }
1982
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001983 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001984 bc_num_free(&cp);
1985
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001986 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001987}
1988
1989static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1990 BcNum *restrict d, size_t scale, size_t ts)
1991{
1992 BcStatus s;
1993 BcNum temp;
1994 bool neg;
1995
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001996 if (b->len == 0)
1997 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001998
1999 if (a->len == 0) {
2000 bc_num_setToZero(d, ts);
2001 return BC_STATUS_SUCCESS;
2002 }
2003
2004 bc_num_init(&temp, d->cap);
2005 bc_num_d(a, b, c, scale);
2006
2007 if (scale != 0) scale = ts;
2008
2009 s = bc_num_m(c, b, &temp, scale);
2010 if (s) goto err;
2011 s = bc_num_sub(a, &temp, d, scale);
2012 if (s) goto err;
2013
2014 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2015
2016 neg = d->neg;
2017 bc_num_retireMul(d, ts, a->neg, b->neg);
2018 d->neg = neg;
2019
2020err:
2021 bc_num_free(&temp);
2022 return s;
2023}
2024
2025static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2026{
2027 BcStatus s;
2028 BcNum c1;
2029 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2030
2031 bc_num_init(&c1, len);
2032 s = bc_num_r(a, b, &c1, c, scale, ts);
2033 bc_num_free(&c1);
2034
2035 return s;
2036}
2037
2038static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2039{
2040 BcStatus s = BC_STATUS_SUCCESS;
2041 BcNum copy;
2042 unsigned long pow;
2043 size_t i, powrdx, resrdx;
2044 bool neg, zero;
2045
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002046 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002047
2048 if (b->len == 0) {
2049 bc_num_one(c);
2050 return BC_STATUS_SUCCESS;
2051 }
2052 else if (a->len == 0) {
2053 bc_num_setToZero(c, scale);
2054 return BC_STATUS_SUCCESS;
2055 }
2056 else if (BC_NUM_ONE(b)) {
2057 if (!b->neg)
2058 bc_num_copy(c, a);
2059 else
2060 s = bc_num_inv(a, c, scale);
2061 return s;
2062 }
2063
2064 neg = b->neg;
2065 b->neg = false;
2066
2067 s = bc_num_ulong(b, &pow);
2068 if (s) return s;
2069
2070 bc_num_init(&copy, a->len);
2071 bc_num_copy(&copy, a);
2072
2073 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2074
2075 b->neg = neg;
2076
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002077 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002078 powrdx <<= 1;
2079 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2080 if (s) goto err;
Denys Vlasenkof359e002018-12-05 01:21:59 +01002081 // It is too slow to handle ^C only after entire "2^1000000" completes
2082 if (G_interrupt) {
2083 s = BC_STATUS_FAILURE;
2084 goto err;
2085 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002086 }
2087
Gavin Howard01055ba2018-11-03 11:00:21 -06002088 bc_num_copy(c, &copy);
2089
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002090 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002091
2092 powrdx <<= 1;
2093 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2094 if (s) goto err;
2095
2096 if (pow & 1) {
2097 resrdx += powrdx;
2098 s = bc_num_mul(c, &copy, c, resrdx);
2099 if (s) goto err;
2100 }
Denys Vlasenkof359e002018-12-05 01:21:59 +01002101 // It is too slow to handle ^C only after entire "2^1000000" completes
2102 if (G_interrupt) {
2103 s = BC_STATUS_FAILURE;
2104 goto err;
2105 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002106 }
2107
2108 if (neg) {
2109 s = bc_num_inv(c, c, scale);
2110 if (s) goto err;
2111 }
2112
Gavin Howard01055ba2018-11-03 11:00:21 -06002113 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2114
2115 // We can't use bc_num_clean() here.
2116 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2117 if (zero) bc_num_setToZero(c, scale);
2118
2119err:
2120 bc_num_free(&copy);
2121 return s;
2122}
2123
2124static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2125 BcNumBinaryOp op, size_t req)
2126{
2127 BcStatus s;
2128 BcNum num2, *ptr_a, *ptr_b;
2129 bool init = false;
2130
2131 if (c == a) {
2132 ptr_a = &num2;
2133 memcpy(ptr_a, c, sizeof(BcNum));
2134 init = true;
2135 }
2136 else
2137 ptr_a = a;
2138
2139 if (c == b) {
2140 ptr_b = &num2;
2141 if (c != a) {
2142 memcpy(ptr_b, c, sizeof(BcNum));
2143 init = true;
2144 }
2145 }
2146 else
2147 ptr_b = b;
2148
2149 if (init)
2150 bc_num_init(c, req);
2151 else
2152 bc_num_expand(c, req);
2153
2154 s = op(ptr_a, ptr_b, c, scale);
2155
2156 if (init) bc_num_free(&num2);
2157
2158 return s;
2159}
2160
2161static bool bc_num_strValid(const char *val, size_t base)
2162{
2163 BcDig b;
2164 bool small, radix = false;
2165 size_t i, len = strlen(val);
2166
2167 if (!len) return true;
2168
2169 small = base <= 10;
2170 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2171
2172 for (i = 0; i < len; ++i) {
2173
2174 BcDig c = val[i];
2175
2176 if (c == '.') {
2177
2178 if (radix) return false;
2179
2180 radix = true;
2181 continue;
2182 }
2183
2184 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2185 return false;
2186 }
2187
2188 return true;
2189}
2190
2191static void bc_num_parseDecimal(BcNum *n, const char *val)
2192{
2193 size_t len, i;
2194 const char *ptr;
2195 bool zero = true;
2196
2197 for (i = 0; val[i] == '0'; ++i);
2198
2199 val += i;
2200 len = strlen(val);
2201 bc_num_zero(n);
2202
2203 if (len != 0) {
2204 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2205 bc_num_expand(n, len);
2206 }
2207
2208 ptr = strchr(val, '.');
2209
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002210 n->rdx = 0;
2211 if (ptr != NULL)
2212 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002213
2214 if (!zero) {
2215 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2216 n->num[n->len] = val[i] - '0';
2217 }
2218}
2219
2220static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2221{
2222 BcStatus s;
2223 BcNum temp, mult, result;
2224 BcDig c = '\0';
2225 bool zero = true;
2226 unsigned long v;
2227 size_t i, digits, len = strlen(val);
2228
2229 bc_num_zero(n);
2230
2231 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2232 if (zero) return;
2233
2234 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2235 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2236
2237 for (i = 0; i < len; ++i) {
2238
2239 c = val[i];
2240 if (c == '.') break;
2241
2242 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2243
2244 s = bc_num_mul(n, base, &mult, 0);
2245 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002246 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002247 s = bc_num_add(&mult, &temp, n, 0);
2248 if (s) goto int_err;
2249 }
2250
2251 if (i == len) {
2252 c = val[i];
2253 if (c == 0) goto int_err;
2254 }
2255
2256 bc_num_init(&result, base->len);
2257 bc_num_zero(&result);
2258 bc_num_one(&mult);
2259
2260 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2261
2262 c = val[i];
2263 if (c == 0) break;
2264
2265 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2266
2267 s = bc_num_mul(&result, base, &result, 0);
2268 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002269 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002270 s = bc_num_add(&result, &temp, &result, 0);
2271 if (s) goto err;
2272 s = bc_num_mul(&mult, base, &mult, 0);
2273 if (s) goto err;
2274 }
2275
2276 s = bc_num_div(&result, &mult, &result, digits);
2277 if (s) goto err;
2278 s = bc_num_add(n, &result, n, digits);
2279 if (s) goto err;
2280
2281 if (n->len != 0) {
2282 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2283 }
2284 else
2285 bc_num_zero(n);
2286
2287err:
2288 bc_num_free(&result);
2289int_err:
2290 bc_num_free(&mult);
2291 bc_num_free(&temp);
2292}
2293
2294static void bc_num_printNewline(size_t *nchars, size_t line_len)
2295{
2296 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002297 bb_putchar('\\');
2298 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002299 *nchars = 0;
2300 }
2301}
2302
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002303#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002304static void bc_num_printChar(size_t num, size_t width, bool radix,
2305 size_t *nchars, size_t line_len)
2306{
2307 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002308 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002309 *nchars = *nchars + width;
2310}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002311#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002312
2313static void bc_num_printDigits(size_t num, size_t width, bool radix,
2314 size_t *nchars, size_t line_len)
2315{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002316 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002317
2318 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002319 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002320 ++(*nchars);
2321
2322 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002323 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2324 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002325
2326 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002327 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002328 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002329 dig = num / pow;
2330 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002331 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002332 }
2333}
2334
2335static void bc_num_printHex(size_t num, size_t width, bool radix,
2336 size_t *nchars, size_t line_len)
2337{
2338 if (radix) {
2339 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002340 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002341 *nchars += 1;
2342 }
2343
2344 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002345 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002346 *nchars = *nchars + width;
2347}
2348
2349static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2350{
2351 size_t i, rdx = n->rdx - 1;
2352
Denys Vlasenko00d77792018-11-30 23:13:42 +01002353 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002354 (*nchars) += n->neg;
2355
2356 for (i = n->len - 1; i < n->len; --i)
2357 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2358}
2359
2360static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2361 size_t *nchars, size_t len, BcNumDigitOp print)
2362{
2363 BcStatus s;
2364 BcVec stack;
2365 BcNum intp, fracp, digit, frac_len;
2366 unsigned long dig, *ptr;
2367 size_t i;
2368 bool radix;
2369
2370 if (n->len == 0) {
2371 print(0, width, false, nchars, len);
2372 return BC_STATUS_SUCCESS;
2373 }
2374
2375 bc_vec_init(&stack, sizeof(long), NULL);
2376 bc_num_init(&intp, n->len);
2377 bc_num_init(&fracp, n->rdx);
2378 bc_num_init(&digit, width);
2379 bc_num_init(&frac_len, BC_NUM_INT(n));
2380 bc_num_copy(&intp, n);
2381 bc_num_one(&frac_len);
2382
2383 bc_num_truncate(&intp, intp.rdx);
2384 s = bc_num_sub(n, &intp, &fracp, 0);
2385 if (s) goto err;
2386
2387 while (intp.len != 0) {
2388 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2389 if (s) goto err;
2390 s = bc_num_ulong(&digit, &dig);
2391 if (s) goto err;
2392 bc_vec_push(&stack, &dig);
2393 }
2394
2395 for (i = 0; i < stack.len; ++i) {
2396 ptr = bc_vec_item_rev(&stack, i);
2397 print(*ptr, width, false, nchars, len);
2398 }
2399
2400 if (!n->rdx) goto err;
2401
2402 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2403 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2404 if (s) goto err;
2405 s = bc_num_ulong(&fracp, &dig);
2406 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002407 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002408 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2409 if (s) goto err;
2410 print(dig, width, radix, nchars, len);
2411 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2412 if (s) goto err;
2413 }
2414
2415err:
2416 bc_num_free(&frac_len);
2417 bc_num_free(&digit);
2418 bc_num_free(&fracp);
2419 bc_num_free(&intp);
2420 bc_vec_free(&stack);
2421 return s;
2422}
2423
2424static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2425 size_t *nchars, size_t line_len)
2426{
2427 BcStatus s;
2428 size_t width, i;
2429 BcNumDigitOp print;
2430 bool neg = n->neg;
2431
Denys Vlasenko00d77792018-11-30 23:13:42 +01002432 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002433 (*nchars) += neg;
2434
2435 n->neg = false;
2436
2437 if (base_t <= BC_NUM_MAX_IBASE) {
2438 width = 1;
2439 print = bc_num_printHex;
2440 }
2441 else {
2442 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2443 print = bc_num_printDigits;
2444 }
2445
2446 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2447 n->neg = neg;
2448
2449 return s;
2450}
2451
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002452#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002453static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2454{
2455 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2456}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002457#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002458
2459static void bc_num_init(BcNum *n, size_t req)
2460{
2461 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2462 memset(n, 0, sizeof(BcNum));
2463 n->num = xmalloc(req);
2464 n->cap = req;
2465}
2466
2467static void bc_num_expand(BcNum *n, size_t req)
2468{
2469 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2470 if (req > n->cap) {
2471 n->num = xrealloc(n->num, req);
2472 n->cap = req;
2473 }
2474}
2475
2476static void bc_num_free(void *num)
2477{
2478 free(((BcNum *) num)->num);
2479}
2480
2481static void bc_num_copy(BcNum *d, BcNum *s)
2482{
2483 if (d != s) {
2484 bc_num_expand(d, s->cap);
2485 d->len = s->len;
2486 d->neg = s->neg;
2487 d->rdx = s->rdx;
2488 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2489 }
2490}
2491
2492static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2493 size_t base_t)
2494{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002495 if (!bc_num_strValid(val, base_t))
2496 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002497
2498 if (base_t == 10)
2499 bc_num_parseDecimal(n, val);
2500 else
2501 bc_num_parseBase(n, val, base);
2502
2503 return BC_STATUS_SUCCESS;
2504}
2505
2506static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2507 size_t *nchars, size_t line_len)
2508{
2509 BcStatus s = BC_STATUS_SUCCESS;
2510
2511 bc_num_printNewline(nchars, line_len);
2512
2513 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002514 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002515 ++(*nchars);
2516 }
2517 else if (base_t == 10)
2518 bc_num_printDecimal(n, nchars, line_len);
2519 else
2520 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2521
2522 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002523 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002524 *nchars = 0;
2525 }
2526
2527 return s;
2528}
2529
2530static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2531{
2532 size_t i;
2533 unsigned long pow;
2534
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002535 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002536
2537 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2538
2539 unsigned long prev = *result, powprev = pow;
2540
2541 *result += ((unsigned long) n->num[i]) * pow;
2542 pow *= 10;
2543
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002544 if (*result < prev || pow < powprev)
2545 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002546 }
2547
2548 return BC_STATUS_SUCCESS;
2549}
2550
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002551static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002552{
2553 size_t len;
2554 BcDig *ptr;
2555 unsigned long i;
2556
2557 bc_num_zero(n);
2558
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002559 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002560
2561 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2562 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002563}
2564
2565static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2566{
2567 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2568 (void) scale;
2569 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2570}
2571
2572static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2573{
2574 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2575 (void) scale;
2576 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2577}
2578
2579static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2580{
2581 size_t req = BC_NUM_MREQ(a, b, scale);
2582 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2583}
2584
2585static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2586{
2587 size_t req = BC_NUM_MREQ(a, b, scale);
2588 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2589}
2590
2591static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2592{
2593 size_t req = BC_NUM_MREQ(a, b, scale);
2594 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2595}
2596
2597static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2598{
2599 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2600}
2601
2602static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2603{
2604 BcStatus s;
2605 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2606 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2607 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2608
2609 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2610 bc_num_expand(b, req);
2611
2612 if (a->len == 0) {
2613 bc_num_setToZero(b, scale);
2614 return BC_STATUS_SUCCESS;
2615 }
2616 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002617 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002618 else if (BC_NUM_ONE(a)) {
2619 bc_num_one(b);
2620 bc_num_extend(b, scale);
2621 return BC_STATUS_SUCCESS;
2622 }
2623
2624 scale = BC_MAX(scale, a->rdx) + 1;
2625 len = a->len + scale;
2626
2627 bc_num_init(&num1, len);
2628 bc_num_init(&num2, len);
2629 bc_num_init(&half, BC_NUM_DEF_SIZE);
2630
2631 bc_num_one(&half);
2632 half.num[0] = 5;
2633 half.rdx = 1;
2634
2635 bc_num_init(&f, len);
2636 bc_num_init(&fprime, len);
2637
2638 x0 = &num1;
2639 x1 = &num2;
2640
2641 bc_num_one(x0);
2642 pow = BC_NUM_INT(a);
2643
2644 if (pow) {
2645
2646 if (pow & 1)
2647 x0->num[0] = 2;
2648 else
2649 x0->num[0] = 6;
2650
2651 pow -= 2 - (pow & 1);
2652
2653 bc_num_extend(x0, pow);
2654
2655 // Make sure to move the radix back.
2656 x0->rdx -= pow;
2657 }
2658
2659 x0->rdx = digs = digs1 = 0;
2660 resrdx = scale + 2;
2661 len = BC_NUM_INT(x0) + resrdx - 1;
2662
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002663 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002664
2665 s = bc_num_div(a, x0, &f, resrdx);
2666 if (s) goto err;
2667 s = bc_num_add(x0, &f, &fprime, resrdx);
2668 if (s) goto err;
2669 s = bc_num_mul(&fprime, &half, x1, resrdx);
2670 if (s) goto err;
2671
2672 cmp = bc_num_cmp(x1, x0);
2673 digs = x1->len - (unsigned long long) llabs(cmp);
2674
2675 if (cmp == cmp2 && digs == digs1)
2676 times += 1;
2677 else
2678 times = 0;
2679
2680 resrdx += times > 4;
2681
2682 cmp2 = cmp1;
2683 cmp1 = cmp;
2684 digs1 = digs;
2685
2686 temp = x0;
2687 x0 = x1;
2688 x1 = temp;
2689 }
2690
Gavin Howard01055ba2018-11-03 11:00:21 -06002691 bc_num_copy(b, x0);
2692 scale -= 1;
2693 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2694
2695err:
2696 bc_num_free(&fprime);
2697 bc_num_free(&f);
2698 bc_num_free(&half);
2699 bc_num_free(&num2);
2700 bc_num_free(&num1);
2701 return s;
2702}
2703
2704static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2705 size_t scale)
2706{
2707 BcStatus s;
2708 BcNum num2, *ptr_a;
2709 bool init = false;
2710 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2711
2712 if (c == a) {
2713 memcpy(&num2, c, sizeof(BcNum));
2714 ptr_a = &num2;
2715 bc_num_init(c, len);
2716 init = true;
2717 }
2718 else {
2719 ptr_a = a;
2720 bc_num_expand(c, len);
2721 }
2722
2723 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2724
2725 if (init) bc_num_free(&num2);
2726
2727 return s;
2728}
2729
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002730#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002731static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2732{
2733 BcStatus s;
2734 BcNum base, exp, two, temp;
2735
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002736 if (c->len == 0)
2737 return bc_error("divide by zero");
2738 if (a->rdx || b->rdx || c->rdx)
2739 return bc_error("non integer number");
2740 if (b->neg)
2741 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002742
2743 bc_num_expand(d, c->len);
2744 bc_num_init(&base, c->len);
2745 bc_num_init(&exp, b->len);
2746 bc_num_init(&two, BC_NUM_DEF_SIZE);
2747 bc_num_init(&temp, b->len);
2748
2749 bc_num_one(&two);
2750 two.num[0] = 2;
2751 bc_num_one(d);
2752
2753 s = bc_num_rem(a, c, &base, 0);
2754 if (s) goto err;
2755 bc_num_copy(&exp, b);
2756
2757 while (exp.len != 0) {
2758
2759 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2760 if (s) goto err;
2761
2762 if (BC_NUM_ONE(&temp)) {
2763 s = bc_num_mul(d, &base, &temp, 0);
2764 if (s) goto err;
2765 s = bc_num_rem(&temp, c, d, 0);
2766 if (s) goto err;
2767 }
2768
2769 s = bc_num_mul(&base, &base, &temp, 0);
2770 if (s) goto err;
2771 s = bc_num_rem(&temp, c, &base, 0);
2772 if (s) goto err;
2773 }
2774
2775err:
2776 bc_num_free(&temp);
2777 bc_num_free(&two);
2778 bc_num_free(&exp);
2779 bc_num_free(&base);
2780 return s;
2781}
2782#endif // ENABLE_DC
2783
2784static int bc_id_cmp(const void *e1, const void *e2)
2785{
2786 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2787}
2788
2789static void bc_id_free(void *id)
2790{
2791 free(((BcId *) id)->name);
2792}
2793
2794static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2795{
2796 BcId a;
2797 size_t i;
2798
2799 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002800 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2801 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002802 }
2803
2804 a.idx = var;
2805 a.name = name;
2806
2807 bc_vec_push(&f->autos, &a);
2808
2809 return BC_STATUS_SUCCESS;
2810}
2811
2812static void bc_func_init(BcFunc *f)
2813{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002814 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002815 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2816 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2817 f->nparams = 0;
2818}
2819
2820static void bc_func_free(void *func)
2821{
2822 BcFunc *f = (BcFunc *) func;
2823 bc_vec_free(&f->code);
2824 bc_vec_free(&f->autos);
2825 bc_vec_free(&f->labels);
2826}
2827
2828static void bc_array_init(BcVec *a, bool nums)
2829{
2830 if (nums)
2831 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2832 else
2833 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2834 bc_array_expand(a, 1);
2835}
2836
2837static void bc_array_copy(BcVec *d, const BcVec *s)
2838{
2839 size_t i;
2840
Denys Vlasenko7d628012018-12-04 21:46:47 +01002841 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002842 bc_vec_expand(d, s->cap);
2843 d->len = s->len;
2844
2845 for (i = 0; i < s->len; ++i) {
2846 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2847 bc_num_init(dnum, snum->len);
2848 bc_num_copy(dnum, snum);
2849 }
2850}
2851
2852static void bc_array_expand(BcVec *a, size_t len)
2853{
2854 BcResultData data;
2855
2856 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2857 while (len > a->len) {
2858 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2859 bc_vec_push(a, &data.n);
2860 }
2861 }
2862 else {
2863 while (len > a->len) {
2864 bc_array_init(&data.v, true);
2865 bc_vec_push(a, &data.v);
2866 }
2867 }
2868}
2869
2870static void bc_string_free(void *string)
2871{
2872 free(*((char **) string));
2873}
2874
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002875#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002876static void bc_result_copy(BcResult *d, BcResult *src)
2877{
2878 d->t = src->t;
2879
2880 switch (d->t) {
2881
2882 case BC_RESULT_TEMP:
2883 case BC_RESULT_IBASE:
2884 case BC_RESULT_SCALE:
2885 case BC_RESULT_OBASE:
2886 {
2887 bc_num_init(&d->d.n, src->d.n.len);
2888 bc_num_copy(&d->d.n, &src->d.n);
2889 break;
2890 }
2891
2892 case BC_RESULT_VAR:
2893 case BC_RESULT_ARRAY:
2894 case BC_RESULT_ARRAY_ELEM:
2895 {
2896 d->d.id.name = xstrdup(src->d.id.name);
2897 break;
2898 }
2899
2900 case BC_RESULT_CONSTANT:
2901 case BC_RESULT_LAST:
2902 case BC_RESULT_ONE:
2903 case BC_RESULT_STR:
2904 {
2905 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2906 break;
2907 }
2908 }
2909}
2910#endif // ENABLE_DC
2911
2912static void bc_result_free(void *result)
2913{
2914 BcResult *r = (BcResult *) result;
2915
2916 switch (r->t) {
2917
2918 case BC_RESULT_TEMP:
2919 case BC_RESULT_IBASE:
2920 case BC_RESULT_SCALE:
2921 case BC_RESULT_OBASE:
2922 {
2923 bc_num_free(&r->d.n);
2924 break;
2925 }
2926
2927 case BC_RESULT_VAR:
2928 case BC_RESULT_ARRAY:
2929 case BC_RESULT_ARRAY_ELEM:
2930 {
2931 free(r->d.id.name);
2932 break;
2933 }
2934
2935 default:
2936 {
2937 // Do nothing.
2938 break;
2939 }
2940 }
2941}
2942
2943static void bc_lex_lineComment(BcLex *l)
2944{
2945 l->t.t = BC_LEX_WHITESPACE;
2946 while (l->i < l->len && l->buf[l->i++] != '\n');
2947 --l->i;
2948}
2949
2950static void bc_lex_whitespace(BcLex *l)
2951{
2952 char c;
2953 l->t.t = BC_LEX_WHITESPACE;
2954 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2955}
2956
2957static BcStatus bc_lex_number(BcLex *l, char start)
2958{
2959 const char *buf = l->buf + l->i;
2960 size_t len, hits = 0, bslashes = 0, i = 0, j;
2961 char c = buf[i];
2962 bool last_pt, pt = start == '.';
2963
2964 last_pt = pt;
2965 l->t.t = BC_LEX_NUMBER;
2966
2967 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2968 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2969 {
2970 if (c != '\\') {
2971 last_pt = c == '.';
2972 pt = pt || last_pt;
2973 }
2974 else {
2975 ++i;
2976 bslashes += 1;
2977 }
2978
2979 c = buf[++i];
2980 }
2981
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002982 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002983 if (len > BC_MAX_NUM)
2984 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002985
Denys Vlasenko7d628012018-12-04 21:46:47 +01002986 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002987 bc_vec_expand(&l->t.v, len + 1);
2988 bc_vec_push(&l->t.v, &start);
2989
2990 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2991
2992 c = buf[j];
2993
2994 // If we have hit a backslash, skip it. We don't have
2995 // to check for a newline because it's guaranteed.
2996 if (hits < bslashes && c == '\\') {
2997 ++hits;
2998 ++j;
2999 continue;
3000 }
3001
3002 bc_vec_push(&l->t.v, &c);
3003 }
3004
3005 bc_vec_pushByte(&l->t.v, '\0');
3006 l->i += i;
3007
3008 return BC_STATUS_SUCCESS;
3009}
3010
3011static BcStatus bc_lex_name(BcLex *l)
3012{
3013 size_t i = 0;
3014 const char *buf = l->buf + l->i - 1;
3015 char c = buf[i];
3016
3017 l->t.t = BC_LEX_NAME;
3018
3019 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3020
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003021 if (i > BC_MAX_STRING)
3022 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003023 bc_vec_string(&l->t.v, i, buf);
3024
3025 // Increment the index. We minus 1 because it has already been incremented.
3026 l->i += i - 1;
3027
3028 return BC_STATUS_SUCCESS;
3029}
3030
3031static void bc_lex_init(BcLex *l, BcLexNext next)
3032{
3033 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003034 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003035}
3036
3037static void bc_lex_free(BcLex *l)
3038{
3039 bc_vec_free(&l->t.v);
3040}
3041
3042static void bc_lex_file(BcLex *l, const char *file)
3043{
3044 l->line = 1;
3045 l->newline = false;
3046 l->f = file;
3047}
3048
3049static BcStatus bc_lex_next(BcLex *l)
3050{
3051 BcStatus s;
3052
3053 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003054 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06003055
3056 l->line += l->newline;
3057 l->t.t = BC_LEX_EOF;
3058
3059 l->newline = (l->i == l->len);
3060 if (l->newline) return BC_STATUS_SUCCESS;
3061
3062 // Loop until failure or we don't have whitespace. This
3063 // is so the parser doesn't get inundated with whitespace.
3064 do {
3065 s = l->next(l);
3066 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3067
3068 return s;
3069}
3070
3071static BcStatus bc_lex_text(BcLex *l, const char *text)
3072{
3073 l->buf = text;
3074 l->i = 0;
3075 l->len = strlen(text);
3076 l->t.t = l->t.last = BC_LEX_INVALID;
3077 return bc_lex_next(l);
3078}
3079
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003080#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003081static BcStatus bc_lex_identifier(BcLex *l)
3082{
3083 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003084 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06003085 const char *buf = l->buf + l->i - 1;
3086
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003087 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3088 const char *keyword8 = bc_lex_kws[i].name8;
3089 unsigned j = 0;
3090 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3091 j++;
3092 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06003093 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003094 if (keyword8[j] != '\0')
3095 continue;
3096 match:
3097 // buf starts with keyword bc_lex_kws[i]
3098 l->t.t = BC_LEX_KEY_1st_keyword + i;
3099 if ((1 << i) & POSIX_KWORD_MASK) {
3100 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
3101 if (s) return s;
3102 }
3103
3104 // We minus 1 because the index has already been incremented.
3105 l->i += j - 1;
3106 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003107 }
3108
3109 s = bc_lex_name(l);
3110 if (s) return s;
3111
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003112 if (l->t.v.len > 2)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003113 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06003114
3115 return s;
3116}
3117
3118static BcStatus bc_lex_string(BcLex *l)
3119{
3120 size_t len, nls = 0, i = l->i;
3121 char c;
3122
3123 l->t.t = BC_LEX_STR;
3124
3125 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3126
3127 if (c == '\0') {
3128 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003129 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003130 }
3131
3132 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003133 if (len > BC_MAX_STRING)
3134 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003135 bc_vec_string(&l->t.v, len, l->buf + l->i);
3136
3137 l->i = i + 1;
3138 l->line += nls;
3139
3140 return BC_STATUS_SUCCESS;
3141}
3142
3143static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3144{
3145 if (l->buf[l->i] == '=') {
3146 ++l->i;
3147 l->t.t = with;
3148 }
3149 else
3150 l->t.t = without;
3151}
3152
3153static BcStatus bc_lex_comment(BcLex *l)
3154{
3155 size_t i, nls = 0;
3156 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003157
3158 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003159 i = ++l->i;
3160 for (;;) {
3161 char c = buf[i];
3162 check_star:
3163 if (c == '*') {
3164 c = buf[++i];
3165 if (c == '/')
3166 break;
3167 goto check_star;
3168 }
3169 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003170 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003171 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003172 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003173 nls += (c == '\n');
3174 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003175 }
3176
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003177 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003178 l->line += nls;
3179
3180 return BC_STATUS_SUCCESS;
3181}
3182
3183static BcStatus bc_lex_token(BcLex *l)
3184{
3185 BcStatus s = BC_STATUS_SUCCESS;
3186 char c = l->buf[l->i++], c2;
3187
3188 // This is the workhorse of the lexer.
3189 switch (c) {
3190
3191 case '\0':
3192 case '\n':
3193 {
3194 l->newline = true;
3195 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3196 break;
3197 }
3198
3199 case '\t':
3200 case '\v':
3201 case '\f':
3202 case '\r':
3203 case ' ':
3204 {
3205 bc_lex_whitespace(l);
3206 break;
3207 }
3208
3209 case '!':
3210 {
3211 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3212
3213 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003214 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003215 if (s) return s;
3216 }
3217
3218 break;
3219 }
3220
3221 case '"':
3222 {
3223 s = bc_lex_string(l);
3224 break;
3225 }
3226
3227 case '#':
3228 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003229 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003230 if (s) return s;
3231
3232 bc_lex_lineComment(l);
3233
3234 break;
3235 }
3236
3237 case '%':
3238 {
3239 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3240 break;
3241 }
3242
3243 case '&':
3244 {
3245 c2 = l->buf[l->i];
3246 if (c2 == '&') {
3247
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003248 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003249 if (s) return s;
3250
3251 ++l->i;
3252 l->t.t = BC_LEX_OP_BOOL_AND;
3253 }
3254 else {
3255 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003256 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003257 }
3258
3259 break;
3260 }
3261
3262 case '(':
3263 case ')':
3264 {
3265 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3266 break;
3267 }
3268
3269 case '*':
3270 {
3271 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3272 break;
3273 }
3274
3275 case '+':
3276 {
3277 c2 = l->buf[l->i];
3278 if (c2 == '+') {
3279 ++l->i;
3280 l->t.t = BC_LEX_OP_INC;
3281 }
3282 else
3283 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3284 break;
3285 }
3286
3287 case ',':
3288 {
3289 l->t.t = BC_LEX_COMMA;
3290 break;
3291 }
3292
3293 case '-':
3294 {
3295 c2 = l->buf[l->i];
3296 if (c2 == '-') {
3297 ++l->i;
3298 l->t.t = BC_LEX_OP_DEC;
3299 }
3300 else
3301 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3302 break;
3303 }
3304
3305 case '.':
3306 {
3307 if (isdigit(l->buf[l->i]))
3308 s = bc_lex_number(l, c);
3309 else {
3310 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003311 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003312 }
3313 break;
3314 }
3315
3316 case '/':
3317 {
3318 c2 = l->buf[l->i];
3319 if (c2 == '*')
3320 s = bc_lex_comment(l);
3321 else
3322 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3323 break;
3324 }
3325
3326 case '0':
3327 case '1':
3328 case '2':
3329 case '3':
3330 case '4':
3331 case '5':
3332 case '6':
3333 case '7':
3334 case '8':
3335 case '9':
3336 case 'A':
3337 case 'B':
3338 case 'C':
3339 case 'D':
3340 case 'E':
3341 case 'F':
3342 {
3343 s = bc_lex_number(l, c);
3344 break;
3345 }
3346
3347 case ';':
3348 {
3349 l->t.t = BC_LEX_SCOLON;
3350 break;
3351 }
3352
3353 case '<':
3354 {
3355 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3356 break;
3357 }
3358
3359 case '=':
3360 {
3361 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3362 break;
3363 }
3364
3365 case '>':
3366 {
3367 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3368 break;
3369 }
3370
3371 case '[':
3372 case ']':
3373 {
3374 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3375 break;
3376 }
3377
3378 case '\\':
3379 {
3380 if (l->buf[l->i] == '\n') {
3381 l->t.t = BC_LEX_WHITESPACE;
3382 ++l->i;
3383 }
3384 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003385 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003386 break;
3387 }
3388
3389 case '^':
3390 {
3391 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3392 break;
3393 }
3394
3395 case 'a':
3396 case 'b':
3397 case 'c':
3398 case 'd':
3399 case 'e':
3400 case 'f':
3401 case 'g':
3402 case 'h':
3403 case 'i':
3404 case 'j':
3405 case 'k':
3406 case 'l':
3407 case 'm':
3408 case 'n':
3409 case 'o':
3410 case 'p':
3411 case 'q':
3412 case 'r':
3413 case 's':
3414 case 't':
3415 case 'u':
3416 case 'v':
3417 case 'w':
3418 case 'x':
3419 case 'y':
3420 case 'z':
3421 {
3422 s = bc_lex_identifier(l);
3423 break;
3424 }
3425
3426 case '{':
3427 case '}':
3428 {
3429 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3430 break;
3431 }
3432
3433 case '|':
3434 {
3435 c2 = l->buf[l->i];
3436
3437 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003438 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003439 if (s) return s;
3440
3441 ++l->i;
3442 l->t.t = BC_LEX_OP_BOOL_OR;
3443 }
3444 else {
3445 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003446 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003447 }
3448
3449 break;
3450 }
3451
3452 default:
3453 {
3454 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003455 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003456 break;
3457 }
3458 }
3459
3460 return s;
3461}
3462#endif // ENABLE_BC
3463
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003464#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003465static BcStatus dc_lex_register(BcLex *l)
3466{
3467 BcStatus s = BC_STATUS_SUCCESS;
3468
3469 if (isspace(l->buf[l->i - 1])) {
3470 bc_lex_whitespace(l);
3471 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003472 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003473 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003474 else
3475 s = bc_lex_name(l);
3476 }
3477 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003478 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003479 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3480 bc_vec_pushByte(&l->t.v, '\0');
3481 l->t.t = BC_LEX_NAME;
3482 }
3483
3484 return s;
3485}
3486
3487static BcStatus dc_lex_string(BcLex *l)
3488{
3489 size_t depth = 1, nls = 0, i = l->i;
3490 char c;
3491
3492 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003493 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003494
3495 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3496
3497 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3498 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3499 nls += (c == '\n');
3500
3501 if (depth) bc_vec_push(&l->t.v, &c);
3502 }
3503
3504 if (c == '\0') {
3505 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003506 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003507 }
3508
3509 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003510 if (i - l->i > BC_MAX_STRING)
3511 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003512
3513 l->i = i;
3514 l->line += nls;
3515
3516 return BC_STATUS_SUCCESS;
3517}
3518
3519static BcStatus dc_lex_token(BcLex *l)
3520{
3521 BcStatus s = BC_STATUS_SUCCESS;
3522 char c = l->buf[l->i++], c2;
3523 size_t i;
3524
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003525 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3526 if (l->t.last == dc_lex_regs[i])
3527 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003528 }
3529
3530 if (c >= '%' && c <= '~' &&
3531 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3532 {
3533 return s;
3534 }
3535
3536 // This is the workhorse of the lexer.
3537 switch (c) {
3538
3539 case '\0':
3540 {
3541 l->t.t = BC_LEX_EOF;
3542 break;
3543 }
3544
3545 case '\n':
3546 case '\t':
3547 case '\v':
3548 case '\f':
3549 case '\r':
3550 case ' ':
3551 {
3552 l->newline = (c == '\n');
3553 bc_lex_whitespace(l);
3554 break;
3555 }
3556
3557 case '!':
3558 {
3559 c2 = l->buf[l->i];
3560
3561 if (c2 == '=')
3562 l->t.t = BC_LEX_OP_REL_NE;
3563 else if (c2 == '<')
3564 l->t.t = BC_LEX_OP_REL_LE;
3565 else if (c2 == '>')
3566 l->t.t = BC_LEX_OP_REL_GE;
3567 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003568 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003569
3570 ++l->i;
3571 break;
3572 }
3573
3574 case '#':
3575 {
3576 bc_lex_lineComment(l);
3577 break;
3578 }
3579
3580 case '.':
3581 {
3582 if (isdigit(l->buf[l->i]))
3583 s = bc_lex_number(l, c);
3584 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003585 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003586 break;
3587 }
3588
3589 case '0':
3590 case '1':
3591 case '2':
3592 case '3':
3593 case '4':
3594 case '5':
3595 case '6':
3596 case '7':
3597 case '8':
3598 case '9':
3599 case 'A':
3600 case 'B':
3601 case 'C':
3602 case 'D':
3603 case 'E':
3604 case 'F':
3605 {
3606 s = bc_lex_number(l, c);
3607 break;
3608 }
3609
3610 case '[':
3611 {
3612 s = dc_lex_string(l);
3613 break;
3614 }
3615
3616 default:
3617 {
3618 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003619 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003620 break;
3621 }
3622 }
3623
3624 return s;
3625}
3626#endif // ENABLE_DC
3627
3628static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3629{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003630 bc_program_addFunc(name, idx);
3631 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003632}
3633
3634static void bc_parse_pushName(BcParse *p, char *name)
3635{
3636 size_t i = 0, len = strlen(name);
3637
3638 for (; i < len; ++i) bc_parse_push(p, name[i]);
3639 bc_parse_push(p, BC_PARSE_STREND);
3640
3641 free(name);
3642}
3643
3644static void bc_parse_pushIndex(BcParse *p, size_t idx)
3645{
3646 unsigned char amt, i, nums[sizeof(size_t)];
3647
3648 for (amt = 0; idx; ++amt) {
3649 nums[amt] = (char) idx;
3650 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3651 }
3652
3653 bc_parse_push(p, amt);
3654 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3655}
3656
3657static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3658{
3659 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003660 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003661
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003662 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003663
3664 bc_parse_push(p, BC_INST_NUM);
3665 bc_parse_pushIndex(p, idx);
3666
3667 ++(*nexs);
3668 (*prev) = BC_INST_NUM;
3669}
3670
3671static BcStatus bc_parse_text(BcParse *p, const char *text)
3672{
3673 BcStatus s;
3674
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003675 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003676
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003677 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003678 p->l.t.t = BC_LEX_INVALID;
3679 s = p->parse(p);
3680 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003681 if (!BC_PARSE_CAN_EXEC(p))
3682 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003683 }
3684
3685 return bc_lex_text(&p->l, text);
3686}
3687
Denys Vlasenkod38af482018-12-04 19:11:02 +01003688// Called when bc/dc_parse_parse() detects a failure,
3689// resets parsing structures.
3690static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003691{
3692 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003693 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003694 bc_vec_pop_all(&p->func->code);
3695 bc_vec_pop_all(&p->func->autos);
3696 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003697
3698 bc_parse_updateFunc(p, BC_PROG_MAIN);
3699 }
3700
3701 p->l.i = p->l.len;
3702 p->l.t.t = BC_LEX_EOF;
3703 p->auto_part = (p->nbraces = 0);
3704
3705 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003706 bc_vec_pop_all(&p->exits);
3707 bc_vec_pop_all(&p->conds);
3708 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003709
Denys Vlasenkod38af482018-12-04 19:11:02 +01003710 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003711}
3712
3713static void bc_parse_free(BcParse *p)
3714{
3715 bc_vec_free(&p->flags);
3716 bc_vec_free(&p->exits);
3717 bc_vec_free(&p->conds);
3718 bc_vec_free(&p->ops);
3719 bc_lex_free(&p->l);
3720}
3721
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003722static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003723 BcParseParse parse, BcLexNext next)
3724{
3725 memset(p, 0, sizeof(BcParse));
3726
3727 bc_lex_init(&p->l, next);
3728 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3729 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3730 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3731 bc_vec_pushByte(&p->flags, 0);
3732 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3733
3734 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003735 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003736 bc_parse_updateFunc(p, func);
3737}
3738
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003739#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003740static BcStatus bc_parse_else(BcParse *p);
3741static BcStatus bc_parse_stmt(BcParse *p);
3742
3743static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3744 size_t *nexprs, bool next)
3745{
3746 BcStatus s = BC_STATUS_SUCCESS;
3747 BcLexType t;
3748 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3749 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3750
3751 while (p->ops.len > start) {
3752
3753 t = BC_PARSE_TOP_OP(p);
3754 if (t == BC_LEX_LPAREN) break;
3755
3756 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3757 if (l >= r && (l != r || !left)) break;
3758
3759 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3760 bc_vec_pop(&p->ops);
3761 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3762 }
3763
3764 bc_vec_push(&p->ops, &type);
3765 if (next) s = bc_lex_next(&p->l);
3766
3767 return s;
3768}
3769
3770static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3771{
3772 BcLexType top;
3773
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003774 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003775 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003776 top = BC_PARSE_TOP_OP(p);
3777
3778 while (top != BC_LEX_LPAREN) {
3779
3780 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3781
3782 bc_vec_pop(&p->ops);
3783 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3784
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003785 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003786 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003787 top = BC_PARSE_TOP_OP(p);
3788 }
3789
3790 bc_vec_pop(&p->ops);
3791
3792 return bc_lex_next(&p->l);
3793}
3794
3795static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3796{
3797 BcStatus s;
3798 bool comma = false;
3799 size_t nparams;
3800
3801 s = bc_lex_next(&p->l);
3802 if (s) return s;
3803
3804 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3805
3806 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3807 s = bc_parse_expr(p, flags, bc_parse_next_param);
3808 if (s) return s;
3809
3810 comma = p->l.t.t == BC_LEX_COMMA;
3811 if (comma) {
3812 s = bc_lex_next(&p->l);
3813 if (s) return s;
3814 }
3815 }
3816
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003817 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003818 bc_parse_push(p, BC_INST_CALL);
3819 bc_parse_pushIndex(p, nparams);
3820
3821 return BC_STATUS_SUCCESS;
3822}
3823
3824static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3825{
3826 BcStatus s;
3827 BcId entry, *entry_ptr;
3828 size_t idx;
3829
3830 entry.name = name;
3831
3832 s = bc_parse_params(p, flags);
3833 if (s) goto err;
3834
3835 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003836 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003837 goto err;
3838 }
3839
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003840 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003841
3842 if (idx == BC_VEC_INVALID_IDX) {
3843 name = xstrdup(entry.name);
3844 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003845 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003846 free(entry.name);
3847 }
3848 else
3849 free(name);
3850
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003851 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003852 bc_parse_pushIndex(p, entry_ptr->idx);
3853
3854 return bc_lex_next(&p->l);
3855
3856err:
3857 free(name);
3858 return s;
3859}
3860
3861static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3862{
3863 BcStatus s;
3864 char *name;
3865
3866 name = xstrdup(p->l.t.v.v);
3867 s = bc_lex_next(&p->l);
3868 if (s) goto err;
3869
3870 if (p->l.t.t == BC_LEX_LBRACKET) {
3871
3872 s = bc_lex_next(&p->l);
3873 if (s) goto err;
3874
3875 if (p->l.t.t == BC_LEX_RBRACKET) {
3876
3877 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003878 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003879 goto err;
3880 }
3881
3882 *type = BC_INST_ARRAY;
3883 }
3884 else {
3885
3886 *type = BC_INST_ARRAY_ELEM;
3887
3888 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3889 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3890 if (s) goto err;
3891 }
3892
3893 s = bc_lex_next(&p->l);
3894 if (s) goto err;
3895 bc_parse_push(p, *type);
3896 bc_parse_pushName(p, name);
3897 }
3898 else if (p->l.t.t == BC_LEX_LPAREN) {
3899
3900 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003901 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003902 goto err;
3903 }
3904
3905 *type = BC_INST_CALL;
3906 s = bc_parse_call(p, name, flags);
3907 }
3908 else {
3909 *type = BC_INST_VAR;
3910 bc_parse_push(p, BC_INST_VAR);
3911 bc_parse_pushName(p, name);
3912 }
3913
3914 return s;
3915
3916err:
3917 free(name);
3918 return s;
3919}
3920
3921static BcStatus bc_parse_read(BcParse *p)
3922{
3923 BcStatus s;
3924
3925 s = bc_lex_next(&p->l);
3926 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003927 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003928
3929 s = bc_lex_next(&p->l);
3930 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003931 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003932
3933 bc_parse_push(p, BC_INST_READ);
3934
3935 return bc_lex_next(&p->l);
3936}
3937
3938static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3939 BcInst *prev)
3940{
3941 BcStatus s;
3942
3943 s = bc_lex_next(&p->l);
3944 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003945 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003946
3947 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3948
3949 s = bc_lex_next(&p->l);
3950 if (s) return s;
3951
3952 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3953 if (s) return s;
3954
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003955 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003956
3957 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3958 bc_parse_push(p, *prev);
3959
3960 return bc_lex_next(&p->l);
3961}
3962
3963static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3964{
3965 BcStatus s;
3966
3967 s = bc_lex_next(&p->l);
3968 if (s) return s;
3969
3970 if (p->l.t.t != BC_LEX_LPAREN) {
3971 *type = BC_INST_SCALE;
3972 bc_parse_push(p, BC_INST_SCALE);
3973 return BC_STATUS_SUCCESS;
3974 }
3975
3976 *type = BC_INST_SCALE_FUNC;
3977 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3978
3979 s = bc_lex_next(&p->l);
3980 if (s) return s;
3981
3982 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3983 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003984 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003985 bc_parse_push(p, BC_INST_SCALE_FUNC);
3986
3987 return bc_lex_next(&p->l);
3988}
3989
3990static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3991 size_t *nexprs, uint8_t flags)
3992{
3993 BcStatus s;
3994 BcLexType type;
3995 char inst;
3996 BcInst etype = *prev;
3997
3998 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3999 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
4000 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
4001 {
4002 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
4003 bc_parse_push(p, inst);
4004 s = bc_lex_next(&p->l);
4005 }
4006 else {
4007
4008 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
4009 *paren_expr = true;
4010
4011 s = bc_lex_next(&p->l);
4012 if (s) return s;
4013 type = p->l.t.t;
4014
4015 // Because we parse the next part of the expression
4016 // right here, we need to increment this.
4017 *nexprs = *nexprs + 1;
4018
4019 switch (type) {
4020
4021 case BC_LEX_NAME:
4022 {
4023 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4024 break;
4025 }
4026
4027 case BC_LEX_KEY_IBASE:
4028 case BC_LEX_KEY_LAST:
4029 case BC_LEX_KEY_OBASE:
4030 {
4031 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4032 s = bc_lex_next(&p->l);
4033 break;
4034 }
4035
4036 case BC_LEX_KEY_SCALE:
4037 {
4038 s = bc_lex_next(&p->l);
4039 if (s) return s;
4040 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004041 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004042 else
4043 bc_parse_push(p, BC_INST_SCALE);
4044 break;
4045 }
4046
4047 default:
4048 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004049 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004050 break;
4051 }
4052 }
4053
4054 if (!s) bc_parse_push(p, inst);
4055 }
4056
4057 return s;
4058}
4059
4060static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4061 bool rparen, size_t *nexprs)
4062{
4063 BcStatus s;
4064 BcLexType type;
4065 BcInst etype = *prev;
4066
4067 s = bc_lex_next(&p->l);
4068 if (s) return s;
4069
4070 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4071 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4072 BC_LEX_OP_MINUS :
4073 BC_LEX_NEG;
4074 *prev = BC_PARSE_TOKEN_INST(type);
4075
4076 // We can just push onto the op stack because this is the largest
4077 // precedence operator that gets pushed. Inc/dec does not.
4078 if (type != BC_LEX_OP_MINUS)
4079 bc_vec_push(&p->ops, &type);
4080 else
4081 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4082
4083 return s;
4084}
4085
4086static BcStatus bc_parse_string(BcParse *p, char inst)
4087{
4088 char *str = xstrdup(p->l.t.v.v);
4089
4090 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004091 bc_parse_pushIndex(p, G.prog.strs.len);
4092 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004093 bc_parse_push(p, inst);
4094
4095 return bc_lex_next(&p->l);
4096}
4097
4098static BcStatus bc_parse_print(BcParse *p)
4099{
4100 BcStatus s;
4101 BcLexType type;
4102 bool comma = false;
4103
4104 s = bc_lex_next(&p->l);
4105 if (s) return s;
4106
4107 type = p->l.t.t;
4108
4109 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004110 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06004111
4112 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4113
4114 if (type == BC_LEX_STR)
4115 s = bc_parse_string(p, BC_INST_PRINT_POP);
4116 else {
4117 s = bc_parse_expr(p, 0, bc_parse_next_print);
4118 if (s) return s;
4119 bc_parse_push(p, BC_INST_PRINT_POP);
4120 }
4121
4122 if (s) return s;
4123
4124 comma = p->l.t.t == BC_LEX_COMMA;
4125 if (comma) s = bc_lex_next(&p->l);
4126 type = p->l.t.t;
4127 }
4128
4129 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004130 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004131
4132 return bc_lex_next(&p->l);
4133}
4134
4135static BcStatus bc_parse_return(BcParse *p)
4136{
4137 BcStatus s;
4138 BcLexType t;
4139 bool paren;
4140
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004141 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004142
4143 s = bc_lex_next(&p->l);
4144 if (s) return s;
4145
4146 t = p->l.t.t;
4147 paren = t == BC_LEX_LPAREN;
4148
4149 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4150 bc_parse_push(p, BC_INST_RET0);
4151 else {
4152
4153 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4154 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4155 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004156
4157 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004158 bc_parse_push(p, BC_INST_RET0);
4159 s = bc_lex_next(&p->l);
4160 if (s) return s;
4161 }
4162
4163 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004164 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004165 if (s) return s;
4166 }
4167
4168 bc_parse_push(p, BC_INST_RET);
4169 }
4170
4171 return s;
4172}
4173
4174static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4175{
4176 BcStatus s = BC_STATUS_SUCCESS;
4177
4178 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004179 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004180
4181 if (brace) {
4182
4183 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004184 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004185 --p->nbraces;
4186 s = bc_lex_next(&p->l);
4187 if (s) return s;
4188 }
4189 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004190 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004191 }
4192
4193 if (BC_PARSE_IF(p)) {
4194
4195 uint8_t *flag_ptr;
4196
4197 while (p->l.t.t == BC_LEX_NLINE) {
4198 s = bc_lex_next(&p->l);
4199 if (s) return s;
4200 }
4201
4202 bc_vec_pop(&p->flags);
4203
4204 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4205 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4206
4207 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4208 }
4209 else if (BC_PARSE_ELSE(p)) {
4210
4211 BcInstPtr *ip;
4212 size_t *label;
4213
4214 bc_vec_pop(&p->flags);
4215
4216 ip = bc_vec_top(&p->exits);
4217 label = bc_vec_item(&p->func->labels, ip->idx);
4218 *label = p->func->code.len;
4219
4220 bc_vec_pop(&p->exits);
4221 }
4222 else if (BC_PARSE_FUNC_INNER(p)) {
4223 bc_parse_push(p, BC_INST_RET0);
4224 bc_parse_updateFunc(p, BC_PROG_MAIN);
4225 bc_vec_pop(&p->flags);
4226 }
4227 else {
4228
4229 BcInstPtr *ip = bc_vec_top(&p->exits);
4230 size_t *label = bc_vec_top(&p->conds);
4231
4232 bc_parse_push(p, BC_INST_JUMP);
4233 bc_parse_pushIndex(p, *label);
4234
4235 label = bc_vec_item(&p->func->labels, ip->idx);
4236 *label = p->func->code.len;
4237
4238 bc_vec_pop(&p->flags);
4239 bc_vec_pop(&p->exits);
4240 bc_vec_pop(&p->conds);
4241 }
4242
4243 return s;
4244}
4245
4246static void bc_parse_startBody(BcParse *p, uint8_t flags)
4247{
4248 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4249 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4250 flags |= BC_PARSE_FLAG_BODY;
4251 bc_vec_push(&p->flags, &flags);
4252}
4253
4254static void bc_parse_noElse(BcParse *p)
4255{
4256 BcInstPtr *ip;
4257 size_t *label;
4258 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4259
4260 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4261
4262 ip = bc_vec_top(&p->exits);
4263 label = bc_vec_item(&p->func->labels, ip->idx);
4264 *label = p->func->code.len;
4265
4266 bc_vec_pop(&p->exits);
4267}
4268
4269static BcStatus bc_parse_if(BcParse *p)
4270{
4271 BcStatus s;
4272 BcInstPtr ip;
4273
4274 s = bc_lex_next(&p->l);
4275 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004276 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004277
4278 s = bc_lex_next(&p->l);
4279 if (s) return s;
4280 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4281 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004282 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004283
4284 s = bc_lex_next(&p->l);
4285 if (s) return s;
4286 bc_parse_push(p, BC_INST_JUMP_ZERO);
4287
4288 ip.idx = p->func->labels.len;
4289 ip.func = ip.len = 0;
4290
4291 bc_parse_pushIndex(p, ip.idx);
4292 bc_vec_push(&p->exits, &ip);
4293 bc_vec_push(&p->func->labels, &ip.idx);
4294 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4295
4296 return BC_STATUS_SUCCESS;
4297}
4298
4299static BcStatus bc_parse_else(BcParse *p)
4300{
4301 BcInstPtr ip;
4302
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004303 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004304
4305 ip.idx = p->func->labels.len;
4306 ip.func = ip.len = 0;
4307
4308 bc_parse_push(p, BC_INST_JUMP);
4309 bc_parse_pushIndex(p, ip.idx);
4310
4311 bc_parse_noElse(p);
4312
4313 bc_vec_push(&p->exits, &ip);
4314 bc_vec_push(&p->func->labels, &ip.idx);
4315 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4316
4317 return bc_lex_next(&p->l);
4318}
4319
4320static BcStatus bc_parse_while(BcParse *p)
4321{
4322 BcStatus s;
4323 BcInstPtr ip;
4324
4325 s = bc_lex_next(&p->l);
4326 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004327 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004328 s = bc_lex_next(&p->l);
4329 if (s) return s;
4330
4331 ip.idx = p->func->labels.len;
4332
4333 bc_vec_push(&p->func->labels, &p->func->code.len);
4334 bc_vec_push(&p->conds, &ip.idx);
4335
4336 ip.idx = p->func->labels.len;
4337 ip.func = 1;
4338 ip.len = 0;
4339
4340 bc_vec_push(&p->exits, &ip);
4341 bc_vec_push(&p->func->labels, &ip.idx);
4342
4343 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4344 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004345 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004346 s = bc_lex_next(&p->l);
4347 if (s) return s;
4348
4349 bc_parse_push(p, BC_INST_JUMP_ZERO);
4350 bc_parse_pushIndex(p, ip.idx);
4351 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4352
4353 return BC_STATUS_SUCCESS;
4354}
4355
4356static BcStatus bc_parse_for(BcParse *p)
4357{
4358 BcStatus s;
4359 BcInstPtr ip;
4360 size_t cond_idx, exit_idx, body_idx, update_idx;
4361
4362 s = bc_lex_next(&p->l);
4363 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004364 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004365 s = bc_lex_next(&p->l);
4366 if (s) return s;
4367
4368 if (p->l.t.t != BC_LEX_SCOLON)
4369 s = bc_parse_expr(p, 0, bc_parse_next_for);
4370 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004371 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004372
4373 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004374 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004375 s = bc_lex_next(&p->l);
4376 if (s) return s;
4377
4378 cond_idx = p->func->labels.len;
4379 update_idx = cond_idx + 1;
4380 body_idx = update_idx + 1;
4381 exit_idx = body_idx + 1;
4382
4383 bc_vec_push(&p->func->labels, &p->func->code.len);
4384
4385 if (p->l.t.t != BC_LEX_SCOLON)
4386 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4387 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004388 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004389
4390 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004391 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004392
4393 s = bc_lex_next(&p->l);
4394 if (s) return s;
4395
4396 bc_parse_push(p, BC_INST_JUMP_ZERO);
4397 bc_parse_pushIndex(p, exit_idx);
4398 bc_parse_push(p, BC_INST_JUMP);
4399 bc_parse_pushIndex(p, body_idx);
4400
4401 ip.idx = p->func->labels.len;
4402
4403 bc_vec_push(&p->conds, &update_idx);
4404 bc_vec_push(&p->func->labels, &p->func->code.len);
4405
4406 if (p->l.t.t != BC_LEX_RPAREN)
4407 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4408 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004409 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004410
4411 if (s) return s;
4412
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004413 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004414 bc_parse_push(p, BC_INST_JUMP);
4415 bc_parse_pushIndex(p, cond_idx);
4416 bc_vec_push(&p->func->labels, &p->func->code.len);
4417
4418 ip.idx = exit_idx;
4419 ip.func = 1;
4420 ip.len = 0;
4421
4422 bc_vec_push(&p->exits, &ip);
4423 bc_vec_push(&p->func->labels, &ip.idx);
4424 bc_lex_next(&p->l);
4425 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4426
4427 return BC_STATUS_SUCCESS;
4428}
4429
4430static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4431{
4432 BcStatus s;
4433 size_t i;
4434 BcInstPtr *ip;
4435
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004436 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004437
4438 if (type == BC_LEX_KEY_BREAK) {
4439
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004440 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004441
4442 i = p->exits.len - 1;
4443 ip = bc_vec_item(&p->exits, i);
4444
4445 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004446 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004447
4448 i = ip->idx;
4449 }
4450 else
4451 i = *((size_t *) bc_vec_top(&p->conds));
4452
4453 bc_parse_push(p, BC_INST_JUMP);
4454 bc_parse_pushIndex(p, i);
4455
4456 s = bc_lex_next(&p->l);
4457 if (s) return s;
4458
4459 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004460 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004461
4462 return bc_lex_next(&p->l);
4463}
4464
4465static BcStatus bc_parse_func(BcParse *p)
4466{
4467 BcStatus s;
4468 bool var, comma = false;
4469 uint8_t flags;
4470 char *name;
4471
4472 s = bc_lex_next(&p->l);
4473 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004474 if (p->l.t.t != BC_LEX_NAME)
4475 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004476
4477 name = xstrdup(p->l.t.v.v);
4478 bc_parse_addFunc(p, name, &p->fidx);
4479
4480 s = bc_lex_next(&p->l);
4481 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004482 if (p->l.t.t != BC_LEX_LPAREN)
4483 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004484 s = bc_lex_next(&p->l);
4485 if (s) return s;
4486
4487 while (p->l.t.t != BC_LEX_RPAREN) {
4488
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004489 if (p->l.t.t != BC_LEX_NAME)
4490 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004491
4492 ++p->func->nparams;
4493
4494 name = xstrdup(p->l.t.v.v);
4495 s = bc_lex_next(&p->l);
4496 if (s) goto err;
4497
4498 var = p->l.t.t != BC_LEX_LBRACKET;
4499
4500 if (!var) {
4501
4502 s = bc_lex_next(&p->l);
4503 if (s) goto err;
4504
4505 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004506 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004507 goto err;
4508 }
4509
4510 s = bc_lex_next(&p->l);
4511 if (s) goto err;
4512 }
4513
4514 comma = p->l.t.t == BC_LEX_COMMA;
4515 if (comma) {
4516 s = bc_lex_next(&p->l);
4517 if (s) goto err;
4518 }
4519
4520 s = bc_func_insert(p->func, name, var);
4521 if (s) goto err;
4522 }
4523
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004524 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004525
4526 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4527 bc_parse_startBody(p, flags);
4528
4529 s = bc_lex_next(&p->l);
4530 if (s) return s;
4531
4532 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004533 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 -06004534
4535 return s;
4536
4537err:
4538 free(name);
4539 return s;
4540}
4541
4542static BcStatus bc_parse_auto(BcParse *p)
4543{
4544 BcStatus s;
4545 bool comma, var, one;
4546 char *name;
4547
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004548 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004549 s = bc_lex_next(&p->l);
4550 if (s) return s;
4551
4552 p->auto_part = comma = false;
4553 one = p->l.t.t == BC_LEX_NAME;
4554
4555 while (p->l.t.t == BC_LEX_NAME) {
4556
4557 name = xstrdup(p->l.t.v.v);
4558 s = bc_lex_next(&p->l);
4559 if (s) goto err;
4560
4561 var = p->l.t.t != BC_LEX_LBRACKET;
4562 if (!var) {
4563
4564 s = bc_lex_next(&p->l);
4565 if (s) goto err;
4566
4567 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004568 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004569 goto err;
4570 }
4571
4572 s = bc_lex_next(&p->l);
4573 if (s) goto err;
4574 }
4575
4576 comma = p->l.t.t == BC_LEX_COMMA;
4577 if (comma) {
4578 s = bc_lex_next(&p->l);
4579 if (s) goto err;
4580 }
4581
4582 s = bc_func_insert(p->func, name, var);
4583 if (s) goto err;
4584 }
4585
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004586 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004587 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004588
4589 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004590 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004591
4592 return bc_lex_next(&p->l);
4593
4594err:
4595 free(name);
4596 return s;
4597}
4598
4599static BcStatus bc_parse_body(BcParse *p, bool brace)
4600{
4601 BcStatus s = BC_STATUS_SUCCESS;
4602 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4603
4604 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4605
4606 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4607
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004608 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004609 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4610
4611 if (!p->auto_part) {
4612 s = bc_parse_auto(p);
4613 if (s) return s;
4614 }
4615
4616 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4617 }
4618 else {
4619 s = bc_parse_stmt(p);
4620 if (!s && !brace) s = bc_parse_endBody(p, false);
4621 }
4622
4623 return s;
4624}
4625
4626static BcStatus bc_parse_stmt(BcParse *p)
4627{
4628 BcStatus s = BC_STATUS_SUCCESS;
4629
4630 switch (p->l.t.t) {
4631
4632 case BC_LEX_NLINE:
4633 {
4634 return bc_lex_next(&p->l);
4635 }
4636
4637 case BC_LEX_KEY_ELSE:
4638 {
4639 p->auto_part = false;
4640 break;
4641 }
4642
4643 case BC_LEX_LBRACE:
4644 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004645 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004646
4647 ++p->nbraces;
4648 s = bc_lex_next(&p->l);
4649 if (s) return s;
4650
4651 return bc_parse_body(p, true);
4652 }
4653
4654 case BC_LEX_KEY_AUTO:
4655 {
4656 return bc_parse_auto(p);
4657 }
4658
4659 default:
4660 {
4661 p->auto_part = false;
4662
4663 if (BC_PARSE_IF_END(p)) {
4664 bc_parse_noElse(p);
4665 return BC_STATUS_SUCCESS;
4666 }
4667 else if (BC_PARSE_BODY(p))
4668 return bc_parse_body(p, false);
4669
4670 break;
4671 }
4672 }
4673
4674 switch (p->l.t.t) {
4675
4676 case BC_LEX_OP_INC:
4677 case BC_LEX_OP_DEC:
4678 case BC_LEX_OP_MINUS:
4679 case BC_LEX_OP_BOOL_NOT:
4680 case BC_LEX_LPAREN:
4681 case BC_LEX_NAME:
4682 case BC_LEX_NUMBER:
4683 case BC_LEX_KEY_IBASE:
4684 case BC_LEX_KEY_LAST:
4685 case BC_LEX_KEY_LENGTH:
4686 case BC_LEX_KEY_OBASE:
4687 case BC_LEX_KEY_READ:
4688 case BC_LEX_KEY_SCALE:
4689 case BC_LEX_KEY_SQRT:
4690 {
4691 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4692 break;
4693 }
4694
4695 case BC_LEX_KEY_ELSE:
4696 {
4697 s = bc_parse_else(p);
4698 break;
4699 }
4700
4701 case BC_LEX_SCOLON:
4702 {
4703 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4704 break;
4705 }
4706
4707 case BC_LEX_RBRACE:
4708 {
4709 s = bc_parse_endBody(p, true);
4710 break;
4711 }
4712
4713 case BC_LEX_STR:
4714 {
4715 s = bc_parse_string(p, BC_INST_PRINT_STR);
4716 break;
4717 }
4718
4719 case BC_LEX_KEY_BREAK:
4720 case BC_LEX_KEY_CONTINUE:
4721 {
4722 s = bc_parse_loopExit(p, p->l.t.t);
4723 break;
4724 }
4725
4726 case BC_LEX_KEY_FOR:
4727 {
4728 s = bc_parse_for(p);
4729 break;
4730 }
4731
4732 case BC_LEX_KEY_HALT:
4733 {
4734 bc_parse_push(p, BC_INST_HALT);
4735 s = bc_lex_next(&p->l);
4736 break;
4737 }
4738
4739 case BC_LEX_KEY_IF:
4740 {
4741 s = bc_parse_if(p);
4742 break;
4743 }
4744
4745 case BC_LEX_KEY_LIMITS:
4746 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004747 // "limits" is a compile-time command,
4748 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004749 s = bc_lex_next(&p->l);
4750 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004751 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4752 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4753 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4754 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4755 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4756 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4757 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4758 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004759 break;
4760 }
4761
4762 case BC_LEX_KEY_PRINT:
4763 {
4764 s = bc_parse_print(p);
4765 break;
4766 }
4767
4768 case BC_LEX_KEY_QUIT:
4769 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004770 // "quit" is a compile-time command. For example,
4771 // "if (0 == 1) quit" terminates when parsing the statement,
4772 // not when it is executed
4773 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004774 }
4775
4776 case BC_LEX_KEY_RETURN:
4777 {
4778 s = bc_parse_return(p);
4779 break;
4780 }
4781
4782 case BC_LEX_KEY_WHILE:
4783 {
4784 s = bc_parse_while(p);
4785 break;
4786 }
4787
4788 default:
4789 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004790 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004791 break;
4792 }
4793 }
4794
4795 return s;
4796}
4797
4798static BcStatus bc_parse_parse(BcParse *p)
4799{
4800 BcStatus s;
4801
4802 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004803 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 -06004804 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004805 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004806 s = bc_parse_func(p);
4807 }
4808 else
4809 s = bc_parse_stmt(p);
4810
Denys Vlasenkod38af482018-12-04 19:11:02 +01004811 if (s || G_interrupt) {
4812 bc_parse_reset(p);
4813 s = BC_STATUS_FAILURE;
4814 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004815
4816 return s;
4817}
4818
4819static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4820{
4821 BcStatus s = BC_STATUS_SUCCESS;
4822 BcInst prev = BC_INST_PRINT;
4823 BcLexType top, t = p->l.t.t;
4824 size_t nexprs = 0, ops_bgn = p->ops.len;
4825 uint32_t i, nparens, nrelops;
4826 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4827
4828 paren_first = p->l.t.t == BC_LEX_LPAREN;
4829 nparens = nrelops = 0;
4830 paren_expr = rprn = done = get_token = assign = false;
4831 bin_last = true;
4832
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004833 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004834 switch (t) {
4835
4836 case BC_LEX_OP_INC:
4837 case BC_LEX_OP_DEC:
4838 {
4839 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4840 rprn = get_token = bin_last = false;
4841 break;
4842 }
4843
4844 case BC_LEX_OP_MINUS:
4845 {
4846 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4847 rprn = get_token = false;
4848 bin_last = prev == BC_INST_MINUS;
4849 break;
4850 }
4851
4852 case BC_LEX_OP_ASSIGN_POWER:
4853 case BC_LEX_OP_ASSIGN_MULTIPLY:
4854 case BC_LEX_OP_ASSIGN_DIVIDE:
4855 case BC_LEX_OP_ASSIGN_MODULUS:
4856 case BC_LEX_OP_ASSIGN_PLUS:
4857 case BC_LEX_OP_ASSIGN_MINUS:
4858 case BC_LEX_OP_ASSIGN:
4859 {
4860 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4861 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4862 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4863 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004864 s = bc_error("bad assignment:"
4865 " left side must be scale,"
4866 " ibase, obase, last, var,"
4867 " or array element"
4868 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004869 break;
4870 }
4871 }
4872 // Fallthrough.
4873 case BC_LEX_OP_POWER:
4874 case BC_LEX_OP_MULTIPLY:
4875 case BC_LEX_OP_DIVIDE:
4876 case BC_LEX_OP_MODULUS:
4877 case BC_LEX_OP_PLUS:
4878 case BC_LEX_OP_REL_EQ:
4879 case BC_LEX_OP_REL_LE:
4880 case BC_LEX_OP_REL_GE:
4881 case BC_LEX_OP_REL_NE:
4882 case BC_LEX_OP_REL_LT:
4883 case BC_LEX_OP_REL_GT:
4884 case BC_LEX_OP_BOOL_NOT:
4885 case BC_LEX_OP_BOOL_OR:
4886 case BC_LEX_OP_BOOL_AND:
4887 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004888 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4889 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4890 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004891 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004892 }
4893
4894 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4895 prev = BC_PARSE_TOKEN_INST(t);
4896 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4897 rprn = get_token = false;
4898 bin_last = t != BC_LEX_OP_BOOL_NOT;
4899
4900 break;
4901 }
4902
4903 case BC_LEX_LPAREN:
4904 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004905 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004906 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004907 ++nparens;
4908 paren_expr = rprn = bin_last = false;
4909 get_token = true;
4910 bc_vec_push(&p->ops, &t);
4911
4912 break;
4913 }
4914
4915 case BC_LEX_RPAREN:
4916 {
4917 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004918 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004919
4920 if (nparens == 0) {
4921 s = BC_STATUS_SUCCESS;
4922 done = true;
4923 get_token = false;
4924 break;
4925 }
4926 else if (!paren_expr)
4927 return BC_STATUS_PARSE_EMPTY_EXP;
4928
4929 --nparens;
4930 paren_expr = rprn = true;
4931 get_token = bin_last = false;
4932
4933 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4934
4935 break;
4936 }
4937
4938 case BC_LEX_NAME:
4939 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004940 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004941 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004942 paren_expr = true;
4943 rprn = get_token = bin_last = false;
4944 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4945 ++nexprs;
4946
4947 break;
4948 }
4949
4950 case BC_LEX_NUMBER:
4951 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004952 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004953 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004954 bc_parse_number(p, &prev, &nexprs);
4955 paren_expr = get_token = true;
4956 rprn = bin_last = false;
4957
4958 break;
4959 }
4960
4961 case BC_LEX_KEY_IBASE:
4962 case BC_LEX_KEY_LAST:
4963 case BC_LEX_KEY_OBASE:
4964 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004965 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004966 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004967 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4968 bc_parse_push(p, (char) prev);
4969
4970 paren_expr = get_token = true;
4971 rprn = bin_last = false;
4972 ++nexprs;
4973
4974 break;
4975 }
4976
4977 case BC_LEX_KEY_LENGTH:
4978 case BC_LEX_KEY_SQRT:
4979 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004980 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004981 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004982 s = bc_parse_builtin(p, t, flags, &prev);
4983 paren_expr = true;
4984 rprn = get_token = bin_last = false;
4985 ++nexprs;
4986
4987 break;
4988 }
4989
4990 case BC_LEX_KEY_READ:
4991 {
4992 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004993 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004994 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004995 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06004996 else
4997 s = bc_parse_read(p);
4998
4999 paren_expr = true;
5000 rprn = get_token = bin_last = false;
5001 ++nexprs;
5002 prev = BC_INST_READ;
5003
5004 break;
5005 }
5006
5007 case BC_LEX_KEY_SCALE:
5008 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005009 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005010 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005011 s = bc_parse_scale(p, &prev, flags);
5012 paren_expr = true;
5013 rprn = get_token = bin_last = false;
5014 ++nexprs;
5015 prev = BC_INST_SCALE;
5016
5017 break;
5018 }
5019
5020 default:
5021 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005022 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005023 break;
5024 }
5025 }
5026
5027 if (!s && get_token) s = bc_lex_next(&p->l);
5028 }
5029
5030 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01005031 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06005032
5033 while (p->ops.len > ops_bgn) {
5034
5035 top = BC_PARSE_TOP_OP(p);
5036 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5037
5038 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005039 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005040
5041 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5042
5043 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5044 bc_vec_pop(&p->ops);
5045 }
5046
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005047 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005048 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005049
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005050 for (i = 0; i < next.len; ++i)
5051 if (t == next.tokens[i])
5052 goto ok;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005053 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005054 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06005055
5056 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01005057 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06005058 if (s) return s;
5059 }
5060 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01005061 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06005062 if (s) return s;
5063 }
5064
5065 if (flags & BC_PARSE_PRINT) {
5066 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5067 bc_parse_push(p, BC_INST_POP);
5068 }
5069
5070 return s;
5071}
5072
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005073static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005074{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005075 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005076}
5077
5078static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5079{
5080 return bc_parse_expr(p, flags, bc_parse_next_read);
5081}
5082#endif // ENABLE_BC
5083
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005084#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005085static BcStatus dc_parse_register(BcParse *p)
5086{
5087 BcStatus s;
5088 char *name;
5089
5090 s = bc_lex_next(&p->l);
5091 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005092 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005093
5094 name = xstrdup(p->l.t.v.v);
5095 bc_parse_pushName(p, name);
5096
5097 return s;
5098}
5099
5100static BcStatus dc_parse_string(BcParse *p)
5101{
5102 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005103 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005104
5105 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5106 name = xstrdup(b);
5107
5108 str = xstrdup(p->l.t.v.v);
5109 bc_parse_push(p, BC_INST_STR);
5110 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005111 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005112 bc_parse_addFunc(p, name, &idx);
5113
5114 return bc_lex_next(&p->l);
5115}
5116
5117static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5118{
5119 BcStatus s;
5120
5121 bc_parse_push(p, inst);
5122 if (name) {
5123 s = dc_parse_register(p);
5124 if (s) return s;
5125 }
5126
5127 if (store) {
5128 bc_parse_push(p, BC_INST_SWAP);
5129 bc_parse_push(p, BC_INST_ASSIGN);
5130 bc_parse_push(p, BC_INST_POP);
5131 }
5132
5133 return bc_lex_next(&p->l);
5134}
5135
5136static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5137{
5138 BcStatus s;
5139
5140 bc_parse_push(p, inst);
5141 bc_parse_push(p, BC_INST_EXEC_COND);
5142
5143 s = dc_parse_register(p);
5144 if (s) return s;
5145
5146 s = bc_lex_next(&p->l);
5147 if (s) return s;
5148
5149 if (p->l.t.t == BC_LEX_ELSE) {
5150 s = dc_parse_register(p);
5151 if (s) return s;
5152 s = bc_lex_next(&p->l);
5153 }
5154 else
5155 bc_parse_push(p, BC_PARSE_STREND);
5156
5157 return s;
5158}
5159
5160static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5161{
5162 BcStatus s = BC_STATUS_SUCCESS;
5163 BcInst prev;
5164 uint8_t inst;
5165 bool assign, get_token = false;
5166
5167 switch (t) {
5168
5169 case BC_LEX_OP_REL_EQ:
5170 case BC_LEX_OP_REL_LE:
5171 case BC_LEX_OP_REL_GE:
5172 case BC_LEX_OP_REL_NE:
5173 case BC_LEX_OP_REL_LT:
5174 case BC_LEX_OP_REL_GT:
5175 {
5176 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5177 break;
5178 }
5179
5180 case BC_LEX_SCOLON:
5181 case BC_LEX_COLON:
5182 {
5183 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5184 break;
5185 }
5186
5187 case BC_LEX_STR:
5188 {
5189 s = dc_parse_string(p);
5190 break;
5191 }
5192
5193 case BC_LEX_NEG:
5194 case BC_LEX_NUMBER:
5195 {
5196 if (t == BC_LEX_NEG) {
5197 s = bc_lex_next(&p->l);
5198 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005199 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005200 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005201 }
5202
5203 bc_parse_number(p, &prev, &p->nbraces);
5204
5205 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5206 get_token = true;
5207
5208 break;
5209 }
5210
5211 case BC_LEX_KEY_READ:
5212 {
5213 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005214 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005215 else
5216 bc_parse_push(p, BC_INST_READ);
5217 get_token = true;
5218 break;
5219 }
5220
5221 case BC_LEX_OP_ASSIGN:
5222 case BC_LEX_STORE_PUSH:
5223 {
5224 assign = t == BC_LEX_OP_ASSIGN;
5225 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5226 s = dc_parse_mem(p, inst, true, assign);
5227 break;
5228 }
5229
5230 case BC_LEX_LOAD:
5231 case BC_LEX_LOAD_POP:
5232 {
5233 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5234 s = dc_parse_mem(p, inst, true, false);
5235 break;
5236 }
5237
5238 case BC_LEX_STORE_IBASE:
5239 case BC_LEX_STORE_SCALE:
5240 case BC_LEX_STORE_OBASE:
5241 {
5242 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5243 s = dc_parse_mem(p, inst, false, true);
5244 break;
5245 }
5246
5247 default:
5248 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005249 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005250 get_token = true;
5251 break;
5252 }
5253 }
5254
5255 if (!s && get_token) s = bc_lex_next(&p->l);
5256
5257 return s;
5258}
5259
5260static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5261{
5262 BcStatus s = BC_STATUS_SUCCESS;
5263 BcInst inst;
5264 BcLexType t;
5265
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005266 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005267
5268 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5269
5270 inst = dc_parse_insts[t];
5271
5272 if (inst != BC_INST_INVALID) {
5273 bc_parse_push(p, inst);
5274 s = bc_lex_next(&p->l);
5275 }
5276 else
5277 s = dc_parse_token(p, t, flags);
5278 }
5279
5280 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5281 bc_parse_push(p, BC_INST_POP_EXEC);
5282
5283 return s;
5284}
5285
5286static BcStatus dc_parse_parse(BcParse *p)
5287{
5288 BcStatus s;
5289
5290 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005291 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005292 else
5293 s = dc_parse_expr(p, 0);
5294
Denys Vlasenkod38af482018-12-04 19:11:02 +01005295 if (s || G_interrupt) {
5296 bc_parse_reset(p);
5297 s = BC_STATUS_FAILURE;
5298 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005299
5300 return s;
5301}
5302
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005303static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005304{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005305 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005306}
5307#endif // ENABLE_DC
5308
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005309static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005310{
5311 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005312 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005313 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005314 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005315 }
5316}
5317
5318static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5319{
5320 if (IS_BC) {
5321 return bc_parse_expression(p, flags);
5322 } else {
5323 return dc_parse_expr(p, flags);
5324 }
5325}
5326
Denys Vlasenkodf515392018-12-02 19:27:48 +01005327static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005328{
Gavin Howard01055ba2018-11-03 11:00:21 -06005329 BcId e, *ptr;
5330 BcVec *v, *map;
5331 size_t i;
5332 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005333 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005334
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005335 v = var ? &G.prog.vars : &G.prog.arrs;
5336 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005337
5338 e.name = id;
5339 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005340 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005341
5342 if (new) {
5343 bc_array_init(&data.v, var);
5344 bc_vec_push(v, &data.v);
5345 }
5346
5347 ptr = bc_vec_item(map, i);
5348 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005349 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005350}
5351
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005352static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005353{
5354 BcStatus s = BC_STATUS_SUCCESS;
5355
5356 switch (r->t) {
5357
5358 case BC_RESULT_STR:
5359 case BC_RESULT_TEMP:
5360 case BC_RESULT_IBASE:
5361 case BC_RESULT_SCALE:
5362 case BC_RESULT_OBASE:
5363 {
5364 *num = &r->d.n;
5365 break;
5366 }
5367
5368 case BC_RESULT_CONSTANT:
5369 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005370 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005371 size_t base_t, len = strlen(*str);
5372 BcNum *base;
5373
5374 bc_num_init(&r->d.n, len);
5375
5376 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005377 base = hex ? &G.prog.hexb : &G.prog.ib;
5378 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005379 s = bc_num_parse(&r->d.n, *str, base, base_t);
5380
5381 if (s) {
5382 bc_num_free(&r->d.n);
5383 return s;
5384 }
5385
5386 *num = &r->d.n;
5387 r->t = BC_RESULT_TEMP;
5388
5389 break;
5390 }
5391
5392 case BC_RESULT_VAR:
5393 case BC_RESULT_ARRAY:
5394 case BC_RESULT_ARRAY_ELEM:
5395 {
5396 BcVec *v;
5397
Denys Vlasenkodf515392018-12-02 19:27:48 +01005398 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005399
5400 if (r->t == BC_RESULT_ARRAY_ELEM) {
5401 v = bc_vec_top(v);
5402 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5403 *num = bc_vec_item(v, r->d.id.idx);
5404 }
5405 else
5406 *num = bc_vec_top(v);
5407
5408 break;
5409 }
5410
5411 case BC_RESULT_LAST:
5412 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005413 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005414 break;
5415 }
5416
5417 case BC_RESULT_ONE:
5418 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005419 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005420 break;
5421 }
5422 }
5423
5424 return s;
5425}
5426
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005427static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005428 BcResult **r, BcNum **rn, bool assign)
5429{
5430 BcStatus s;
5431 bool hex;
5432 BcResultType lt, rt;
5433
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005434 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005435 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005436
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005437 *r = bc_vec_item_rev(&G.prog.results, 0);
5438 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005439
5440 lt = (*l)->t;
5441 rt = (*r)->t;
5442 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5443
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005444 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005445 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005446 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005447 if (s) return s;
5448
5449 // We run this again under these conditions in case any vector has been
5450 // reallocated out from under the BcNums or arrays we had.
5451 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005452 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005453 if (s) return s;
5454 }
5455
5456 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005457 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005458 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005459 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005460
Gavin Howard01055ba2018-11-03 11:00:21 -06005461 return s;
5462}
5463
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005464static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005465{
5466 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005467 bc_vec_pop(&G.prog.results);
5468 bc_vec_pop(&G.prog.results);
5469 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005470}
5471
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005472static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005473{
5474 BcStatus s;
5475
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005476 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005477 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005478 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005479
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005480 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005481 if (s) return s;
5482
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005483 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005484 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005485
5486 return s;
5487}
5488
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005489static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005490{
5491 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005492 bc_vec_pop(&G.prog.results);
5493 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005494}
5495
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005496static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005497{
5498 BcStatus s;
5499 BcResult *opd1, *opd2, res;
5500 BcNum *n1, *n2 = NULL;
5501
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005502 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005503 if (s) return s;
5504 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5505
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005506 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005507 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005508 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005509
5510 return s;
5511
5512err:
5513 bc_num_free(&res.d.n);
5514 return s;
5515}
5516
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005517static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005518{
5519 BcStatus s;
5520 BcParse parse;
5521 BcVec buf;
5522 BcInstPtr ip;
5523 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005524 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005525
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005526 for (i = 0; i < G.prog.stack.len; ++i) {
5527 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005528 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005529 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005530 }
5531
Denys Vlasenko7d628012018-12-04 21:46:47 +01005532 bc_vec_pop_all(&f->code);
5533 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005534
5535 s = bc_read_line(&buf, "read> ");
5536 if (s) goto io_err;
5537
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005538 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005539 bc_lex_file(&parse.l, bc_program_stdin_name);
5540
5541 s = bc_parse_text(&parse, buf.v);
5542 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005543 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005544 if (s) goto exec_err;
5545
5546 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005547 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005548 goto exec_err;
5549 }
5550
5551 ip.func = BC_PROG_READ;
5552 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005553 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005554
5555 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005556 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005557
5558 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005559 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005560
5561exec_err:
5562 bc_parse_free(&parse);
5563io_err:
5564 bc_vec_free(&buf);
5565 return s;
5566}
5567
5568static size_t bc_program_index(char *code, size_t *bgn)
5569{
5570 char amt = code[(*bgn)++], i = 0;
5571 size_t res = 0;
5572
5573 for (; i < amt; ++i, ++(*bgn))
5574 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5575
5576 return res;
5577}
5578
5579static char *bc_program_name(char *code, size_t *bgn)
5580{
5581 size_t i;
5582 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5583
5584 s = xmalloc(ptr - str + 1);
5585 c = code[(*bgn)++];
5586
5587 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5588 s[i] = c;
5589
5590 s[i] = '\0';
5591
5592 return s;
5593}
5594
5595static void bc_program_printString(const char *str, size_t *nchars)
5596{
5597 size_t i, len = strlen(str);
5598
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005599#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005600 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005601 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005602 return;
5603 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005604#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005605
5606 for (i = 0; i < len; ++i, ++(*nchars)) {
5607
5608 int c = str[i];
5609
5610 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005611 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005612 else {
5613
5614 c = str[++i];
5615
5616 switch (c) {
5617
5618 case 'a':
5619 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005620 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005621 break;
5622 }
5623
5624 case 'b':
5625 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005626 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005627 break;
5628 }
5629
5630 case '\\':
5631 case 'e':
5632 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005633 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005634 break;
5635 }
5636
5637 case 'f':
5638 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005639 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005640 break;
5641 }
5642
5643 case 'n':
5644 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005645 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005646 *nchars = SIZE_MAX;
5647 break;
5648 }
5649
5650 case 'r':
5651 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005652 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005653 break;
5654 }
5655
5656 case 'q':
5657 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005658 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005659 break;
5660 }
5661
5662 case 't':
5663 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005664 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005665 break;
5666 }
5667
5668 default:
5669 {
5670 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005671 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005672 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005673 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005674 break;
5675 }
5676 }
5677 }
5678 }
5679}
5680
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005681static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005682{
5683 BcStatus s = BC_STATUS_SUCCESS;
5684 BcResult *r;
5685 size_t len, i;
5686 char *str;
5687 BcNum *num = NULL;
5688 bool pop = inst != BC_INST_PRINT;
5689
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005690 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005691 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005692
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005693 r = bc_vec_item_rev(&G.prog.results, idx);
5694 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005695 if (s) return s;
5696
5697 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005698 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5699 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005700 }
5701 else {
5702
5703 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005704 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005705
5706 if (inst == BC_INST_PRINT_STR) {
5707 for (i = 0, len = strlen(str); i < len; ++i) {
5708 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005709 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005710 if (c == '\n') G.prog.nchars = SIZE_MAX;
5711 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005712 }
5713 }
5714 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005715 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005716 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005717 }
5718 }
5719
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005720 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005721
5722 return s;
5723}
5724
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005725static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005726{
5727 BcStatus s;
5728 BcResult res, *ptr;
5729 BcNum *num = NULL;
5730
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005731 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005732 if (s) return s;
5733
5734 bc_num_init(&res.d.n, num->len);
5735 bc_num_copy(&res.d.n, num);
5736 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5737
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005738 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005739
5740 return s;
5741}
5742
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005743static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005744{
5745 BcStatus s;
5746 BcResult *opd1, *opd2, res;
5747 BcNum *n1, *n2;
5748 bool cond = 0;
5749 ssize_t cmp;
5750
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005751 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005752 if (s) return s;
5753 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5754
5755 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005756 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005757 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005758 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005759 else {
5760
5761 cmp = bc_num_cmp(n1, n2);
5762
5763 switch (inst) {
5764
5765 case BC_INST_REL_EQ:
5766 {
5767 cond = cmp == 0;
5768 break;
5769 }
5770
5771 case BC_INST_REL_LE:
5772 {
5773 cond = cmp <= 0;
5774 break;
5775 }
5776
5777 case BC_INST_REL_GE:
5778 {
5779 cond = cmp >= 0;
5780 break;
5781 }
5782
5783 case BC_INST_REL_NE:
5784 {
5785 cond = cmp != 0;
5786 break;
5787 }
5788
5789 case BC_INST_REL_LT:
5790 {
5791 cond = cmp < 0;
5792 break;
5793 }
5794
5795 case BC_INST_REL_GT:
5796 {
5797 cond = cmp > 0;
5798 break;
5799 }
5800 }
5801 }
5802
5803 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5804
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005805 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005806
5807 return s;
5808}
5809
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005810#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005811static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005812 bool push)
5813{
5814 BcNum n2;
5815 BcResult res;
5816
5817 memset(&n2, 0, sizeof(BcNum));
5818 n2.rdx = res.d.id.idx = r->d.id.idx;
5819 res.t = BC_RESULT_STR;
5820
5821 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005822 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005823 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005824 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005825 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005826 }
5827
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005828 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005829
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005830 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005831 bc_vec_push(v, &n2);
5832
5833 return BC_STATUS_SUCCESS;
5834}
5835#endif // ENABLE_DC
5836
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005837static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005838{
5839 BcStatus s;
5840 BcResult *ptr, r;
5841 BcVec *v;
5842 BcNum *n;
5843
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005844 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005845 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005846
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005847 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005848 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005849 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005850 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005851
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005852#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005853 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005854 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005855 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005856#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005857
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005858 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005859 if (s) return s;
5860
5861 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005862 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005863
5864 if (var) {
5865 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5866 bc_num_copy(&r.d.n, n);
5867 }
5868 else {
5869 bc_array_init(&r.d.v, true);
5870 bc_array_copy(&r.d.v, (BcVec *) n);
5871 }
5872
5873 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005874 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005875
5876 return s;
5877}
5878
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005879static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005880{
5881 BcStatus s;
5882 BcResult *left, *right, res;
5883 BcNum *l = NULL, *r = NULL;
5884 unsigned long val, max;
5885 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5886
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005887 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005888 if (s) return s;
5889
5890 ib = left->t == BC_RESULT_IBASE;
5891 sc = left->t == BC_RESULT_SCALE;
5892
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005893#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005894
5895 if (right->t == BC_RESULT_STR) {
5896
5897 BcVec *v;
5898
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005899 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005900 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005901 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005902
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005903 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005904 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005905#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005906
5907 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005908 return bc_error("bad assignment:"
5909 " left side must be scale,"
5910 " ibase, obase, last, var,"
5911 " or array element"
5912 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005913
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005914#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005915 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005916 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005917
5918 if (assign)
5919 bc_num_copy(l, r);
5920 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005921 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005922
5923 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005924#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005925 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005926#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005927
5928 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005929 static const char *const msg[] = {
5930 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5931 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5932 "?1", //BC_RESULT_LAST
5933 "?2", //BC_RESULT_CONSTANT
5934 "?3", //BC_RESULT_ONE
5935 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5936 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005937 size_t *ptr;
5938
5939 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005940 if (s)
5941 return s;
5942 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005943 if (sc) {
5944 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005945 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005946 }
5947 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005948 if (val < BC_NUM_MIN_BASE)
5949 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005950 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005951 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005952 }
5953
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005954 if (val > max)
5955 return bc_error(msg[s]);
5956 if (!sc)
5957 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005958
5959 *ptr = (size_t) val;
5960 s = BC_STATUS_SUCCESS;
5961 }
5962
5963 bc_num_init(&res.d.n, l->len);
5964 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005965 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005966
5967 return s;
5968}
5969
Denys Vlasenko416ce762018-12-02 20:57:17 +01005970#if !ENABLE_DC
5971#define bc_program_pushVar(code, bgn, pop, copy) \
5972 bc_program_pushVar(code, bgn)
5973// for bc, 'pop' and 'copy' are always false
5974#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005975static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005976 bool pop, bool copy)
5977{
5978 BcStatus s = BC_STATUS_SUCCESS;
5979 BcResult r;
5980 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005981
5982 r.t = BC_RESULT_VAR;
5983 r.d.id.name = name;
5984
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005985#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005986 {
5987 BcVec *v = bc_program_search(name, true);
5988 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005989
Denys Vlasenko416ce762018-12-02 20:57:17 +01005990 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005991
Denys Vlasenko416ce762018-12-02 20:57:17 +01005992 if (!BC_PROG_STACK(v, 2 - copy)) {
5993 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005994 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01005995 }
5996
Gavin Howard01055ba2018-11-03 11:00:21 -06005997 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005998 name = NULL;
5999
6000 if (!BC_PROG_STR(num)) {
6001
6002 r.t = BC_RESULT_TEMP;
6003
6004 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6005 bc_num_copy(&r.d.n, num);
6006 }
6007 else {
6008 r.t = BC_RESULT_STR;
6009 r.d.id.idx = num->rdx;
6010 }
6011
6012 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006013 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006014 }
6015#endif // ENABLE_DC
6016
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006017 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006018
6019 return s;
6020}
6021
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006022static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006023 char inst)
6024{
6025 BcStatus s = BC_STATUS_SUCCESS;
6026 BcResult r;
6027 BcNum *num;
6028
6029 r.d.id.name = bc_program_name(code, bgn);
6030
6031 if (inst == BC_INST_ARRAY) {
6032 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006033 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006034 }
6035 else {
6036
6037 BcResult *operand;
6038 unsigned long temp;
6039
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006040 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006041 if (s) goto err;
6042 s = bc_num_ulong(num, &temp);
6043 if (s) goto err;
6044
6045 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006046 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06006047 goto err;
6048 }
6049
6050 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006051 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06006052 }
6053
6054err:
6055 if (s) free(r.d.id.name);
6056 return s;
6057}
6058
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006059#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006060static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006061{
6062 BcStatus s;
6063 BcResult *ptr, res, copy;
6064 BcNum *num = NULL;
6065 char inst2 = inst;
6066
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006067 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006068 if (s) return s;
6069
6070 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6071 copy.t = BC_RESULT_TEMP;
6072 bc_num_init(&copy.d.n, num->len);
6073 bc_num_copy(&copy.d.n, num);
6074 }
6075
6076 res.t = BC_RESULT_ONE;
6077 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6078 BC_INST_ASSIGN_PLUS :
6079 BC_INST_ASSIGN_MINUS;
6080
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006081 bc_vec_push(&G.prog.results, &res);
6082 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006083
6084 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006085 bc_vec_pop(&G.prog.results);
6086 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006087 }
6088
6089 return s;
6090}
6091
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006092static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006093{
6094 BcStatus s = BC_STATUS_SUCCESS;
6095 BcInstPtr ip;
6096 size_t i, nparams = bc_program_index(code, idx);
6097 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006098 BcId *a;
6099 BcResultData param;
6100 BcResult *arg;
6101
6102 ip.idx = 0;
6103 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006104 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006105
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006106 if (func->code.len == 0) {
6107 return bc_error("undefined function");
6108 }
6109 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006110 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006111 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006112 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006113
6114 for (i = 0; i < nparams; ++i) {
6115
6116 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006117 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006118
6119 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006120 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006121
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006122 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006123 if (s) return s;
6124 }
6125
6126 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006127 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006128
6129 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006130 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006131
6132 if (a->idx) {
6133 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6134 bc_vec_push(v, &param.n);
6135 }
6136 else {
6137 bc_array_init(&param.v, true);
6138 bc_vec_push(v, &param.v);
6139 }
6140 }
6141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006143
6144 return BC_STATUS_SUCCESS;
6145}
6146
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006147static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006148{
6149 BcStatus s;
6150 BcResult res;
6151 BcFunc *f;
6152 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006153 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006154
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006155 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006156 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006157
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006158 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006159 res.t = BC_RESULT_TEMP;
6160
6161 if (inst == BC_INST_RET) {
6162
6163 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006164 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006165
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006166 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006167 if (s) return s;
6168 bc_num_init(&res.d.n, num->len);
6169 bc_num_copy(&res.d.n, num);
6170 }
6171 else {
6172 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6173 bc_num_zero(&res.d.n);
6174 }
6175
6176 // We need to pop arguments as well, so this takes that into account.
6177 for (i = 0; i < f->autos.len; ++i) {
6178
6179 BcVec *v;
6180 BcId *a = bc_vec_item(&f->autos, i);
6181
Denys Vlasenkodf515392018-12-02 19:27:48 +01006182 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006183 bc_vec_pop(v);
6184 }
6185
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006186 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6187 bc_vec_push(&G.prog.results, &res);
6188 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006189
6190 return BC_STATUS_SUCCESS;
6191}
6192#endif // ENABLE_BC
6193
6194static unsigned long bc_program_scale(BcNum *n)
6195{
6196 return (unsigned long) n->rdx;
6197}
6198
6199static unsigned long bc_program_len(BcNum *n)
6200{
6201 unsigned long len = n->len;
6202 size_t i;
6203
6204 if (n->rdx != n->len) return len;
6205 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6206
6207 return len;
6208}
6209
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006210static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006211{
6212 BcStatus s;
6213 BcResult *opnd;
6214 BcNum *num = NULL;
6215 BcResult res;
6216 bool len = inst == BC_INST_LENGTH;
6217
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006218 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006219 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006220 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006221
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006222 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006223 if (s) return s;
6224
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006225#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006226 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006227 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006228#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006229
6230 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6231
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006232 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006233#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006234 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006235 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006236 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006237#endif
6238#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006239 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6240
6241 char **str;
6242 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6243
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006244 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006245 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006246 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006247#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006248 else {
6249 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006250 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006251 }
6252
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006253 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006254
6255 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006256}
6257
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006258#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006259static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006260{
6261 BcStatus s;
6262 BcResult *opd1, *opd2, res, res2;
6263 BcNum *n1, *n2 = NULL;
6264
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006265 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006266 if (s) return s;
6267
6268 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6269 bc_num_init(&res2.d.n, n2->len);
6270
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006271 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006272 if (s) goto err;
6273
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006274 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006275 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006276 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006277
6278 return s;
6279
6280err:
6281 bc_num_free(&res2.d.n);
6282 bc_num_free(&res.d.n);
6283 return s;
6284}
6285
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006286static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006287{
6288 BcStatus s;
6289 BcResult *r1, *r2, *r3, res;
6290 BcNum *n1, *n2, *n3;
6291
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006292 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006293 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006294 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006295 if (s) return s;
6296
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006297 r1 = bc_vec_item_rev(&G.prog.results, 2);
6298 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006299 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006300 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006301 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006302
6303 // Make sure that the values have their pointers updated, if necessary.
6304 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6305
6306 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006307 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006308 if (s) return s;
6309 }
6310
6311 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006312 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006313 if (s) return s;
6314 }
6315 }
6316
6317 bc_num_init(&res.d.n, n3->len);
6318 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6319 if (s) goto err;
6320
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006321 bc_vec_pop(&G.prog.results);
6322 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006323
6324 return s;
6325
6326err:
6327 bc_num_free(&res.d.n);
6328 return s;
6329}
6330
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006331static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006332{
Gavin Howard01055ba2018-11-03 11:00:21 -06006333 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006334 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006335
6336 res.t = BC_RESULT_TEMP;
6337
6338 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006339 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006340 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006341}
6342
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006343static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006344{
6345 BcStatus s;
6346 BcResult *r, res;
6347 BcNum *num = NULL, n;
6348 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006349 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006350 unsigned long val;
6351
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006352 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006353 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006354 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006355
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006356 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006357 if (s) return s;
6358
6359 if (BC_PROG_NUM(r, num)) {
6360
6361 bc_num_init(&n, BC_NUM_DEF_SIZE);
6362 bc_num_copy(&n, num);
6363 bc_num_truncate(&n, n.rdx);
6364
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006365 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006366 if (s) goto num_err;
6367 s = bc_num_ulong(&n, &val);
6368 if (s) goto num_err;
6369
6370 c = (char) val;
6371
6372 bc_num_free(&n);
6373 }
6374 else {
6375 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006376 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006377 c = str2[0];
6378 }
6379
6380 str = xmalloc(2);
6381 str[0] = c;
6382 str[1] = '\0';
6383
6384 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006385 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006386
6387 if (idx != len + BC_PROG_REQ_FUNCS) {
6388
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006389 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6390 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006391 len = idx;
6392 break;
6393 }
6394 }
6395
6396 free(str);
6397 }
6398 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006399 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006400
6401 res.t = BC_RESULT_STR;
6402 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006403 bc_vec_pop(&G.prog.results);
6404 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006405
6406 return BC_STATUS_SUCCESS;
6407
6408num_err:
6409 bc_num_free(&n);
6410 return s;
6411}
6412
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006413static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006414{
6415 BcStatus s;
6416 BcResult *r;
6417 BcNum *n = NULL;
6418 size_t idx;
6419 char *str;
6420
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006421 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006422 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006423 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006424
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006425 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006426 if (s) return s;
6427
6428 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006429 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006430 else {
6431 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006432 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006433 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006434 }
6435
6436 return s;
6437}
6438
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006439static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006440{
6441 BcStatus s;
6442 BcResult *opnd;
6443 BcNum *num = NULL;
6444 unsigned long val;
6445
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006446 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006447 if (s) return s;
6448 s = bc_num_ulong(num, &val);
6449 if (s) return s;
6450
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006451 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006452
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006453 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006454 return bc_error_stack_has_too_few_elements();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006455 if (G.prog.stack.len == val)
6456 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006457
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006458 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006459
6460 return s;
6461}
6462
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006463static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 bool cond)
6465{
6466 BcStatus s = BC_STATUS_SUCCESS;
6467 BcResult *r;
6468 char **str;
6469 BcFunc *f;
6470 BcParse prs;
6471 BcInstPtr ip;
6472 size_t fidx, sidx;
6473 BcNum *n;
6474 bool exec;
6475
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006476 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006477 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006478
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006479 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006480
6481 if (cond) {
6482
Gavin Howard01055ba2018-11-03 11:00:21 -06006483 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6484
6485 if (code[*bgn] == BC_PARSE_STREND)
6486 (*bgn) += 1;
6487 else
6488 else_name = bc_program_name(code, bgn);
6489
6490 exec = r->d.n.len != 0;
6491
6492 if (exec)
6493 name = then_name;
6494 else if (else_name != NULL) {
6495 exec = true;
6496 name = else_name;
6497 }
6498
6499 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006500 BcVec *v;
6501 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006502 n = bc_vec_top(v);
6503 }
6504
6505 free(then_name);
6506 free(else_name);
6507
6508 if (!exec) goto exit;
6509 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006510 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006511 goto exit;
6512 }
6513
6514 sidx = n->rdx;
6515 }
6516 else {
6517
6518 if (r->t == BC_RESULT_STR)
6519 sidx = r->d.id.idx;
6520 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006521 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006522 if (s || !BC_PROG_STR(n)) goto exit;
6523 sidx = n->rdx;
6524 }
6525 else
6526 goto exit;
6527 }
6528
6529 fidx = sidx + BC_PROG_REQ_FUNCS;
6530
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006531 str = bc_vec_item(&G.prog.strs, sidx);
6532 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006533
6534 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006535 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006536 s = bc_parse_text(&prs, *str);
6537 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006538 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006539 if (s) goto err;
6540
6541 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006542 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006543 goto err;
6544 }
6545
6546 bc_parse_free(&prs);
6547 }
6548
6549 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006550 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006551 ip.func = fidx;
6552
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006553 bc_vec_pop(&G.prog.results);
6554 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006555
6556 return BC_STATUS_SUCCESS;
6557
6558err:
6559 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006560 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006561 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006562exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006563 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006564 return s;
6565}
6566#endif // ENABLE_DC
6567
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006568static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006569{
Gavin Howard01055ba2018-11-03 11:00:21 -06006570 BcResult res;
6571 unsigned long val;
6572
6573 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6574 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006575 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006576 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006577 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006578 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006579 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006580
6581 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006582 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006583 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006584}
6585
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006586static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006587{
Gavin Howard01055ba2018-11-03 11:00:21 -06006588 BcId entry, *entry_ptr;
6589 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006590 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006591
6592 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006593 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006594
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006595 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6596 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006597
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006598 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006599 *idx = entry_ptr->idx;
6600
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006601 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006602
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006603 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006604
6605 // We need to reset these, so the function can be repopulated.
6606 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006607 bc_vec_pop_all(&func->autos);
6608 bc_vec_pop_all(&func->code);
6609 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 }
6611 else {
6612 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006613 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006614 }
6615}
6616
Denys Vlasenkod38af482018-12-04 19:11:02 +01006617// Called when parsing or execution detects a failure,
6618// resets execution structures.
6619static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006620{
6621 BcFunc *f;
6622 BcInstPtr *ip;
6623
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006624 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006625 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006626
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006627 f = bc_vec_item(&G.prog.fns, 0);
6628 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006629 ip->idx = f->code.len;
6630
Denys Vlasenkod38af482018-12-04 19:11:02 +01006631 // If !tty, no need to check for ^C: we don't have ^C handler,
6632 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006633}
6634
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006635static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006636{
6637 BcStatus s = BC_STATUS_SUCCESS;
6638 size_t idx;
6639 BcResult r, *ptr;
6640 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006641 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6642 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006643 char *code = func->code.v;
6644 bool cond = false;
6645
6646 while (!s && ip->idx < func->code.len) {
6647
6648 char inst = code[(ip->idx)++];
6649
6650 switch (inst) {
6651
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006652#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006653 case BC_INST_JUMP_ZERO:
6654 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006655 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006656 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006657 cond = !bc_num_cmp(num, &G.prog.zero);
6658 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006659 }
6660 // Fallthrough.
6661 case BC_INST_JUMP:
6662 {
6663 size_t *addr;
6664 idx = bc_program_index(code, &ip->idx);
6665 addr = bc_vec_item(&func->labels, idx);
6666 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6667 break;
6668 }
6669
6670 case BC_INST_CALL:
6671 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006672 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006673 break;
6674 }
6675
6676 case BC_INST_INC_PRE:
6677 case BC_INST_DEC_PRE:
6678 case BC_INST_INC_POST:
6679 case BC_INST_DEC_POST:
6680 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006681 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006682 break;
6683 }
6684
6685 case BC_INST_HALT:
6686 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006687 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006688 break;
6689 }
6690
6691 case BC_INST_RET:
6692 case BC_INST_RET0:
6693 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006694 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006695 break;
6696 }
6697
6698 case BC_INST_BOOL_OR:
6699 case BC_INST_BOOL_AND:
6700#endif // ENABLE_BC
6701 case BC_INST_REL_EQ:
6702 case BC_INST_REL_LE:
6703 case BC_INST_REL_GE:
6704 case BC_INST_REL_NE:
6705 case BC_INST_REL_LT:
6706 case BC_INST_REL_GT:
6707 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006708 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006709 break;
6710 }
6711
6712 case BC_INST_READ:
6713 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006714 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006715 break;
6716 }
6717
6718 case BC_INST_VAR:
6719 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006720 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006721 break;
6722 }
6723
6724 case BC_INST_ARRAY_ELEM:
6725 case BC_INST_ARRAY:
6726 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006727 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006728 break;
6729 }
6730
6731 case BC_INST_LAST:
6732 {
6733 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006734 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006735 break;
6736 }
6737
6738 case BC_INST_IBASE:
6739 case BC_INST_SCALE:
6740 case BC_INST_OBASE:
6741 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006742 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006743 break;
6744 }
6745
6746 case BC_INST_SCALE_FUNC:
6747 case BC_INST_LENGTH:
6748 case BC_INST_SQRT:
6749 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006750 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006751 break;
6752 }
6753
6754 case BC_INST_NUM:
6755 {
6756 r.t = BC_RESULT_CONSTANT;
6757 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006758 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006759 break;
6760 }
6761
6762 case BC_INST_POP:
6763 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006764 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006765 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006766 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006767 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006768 break;
6769 }
6770
6771 case BC_INST_POP_EXEC:
6772 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006773 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006774 break;
6775 }
6776
6777 case BC_INST_PRINT:
6778 case BC_INST_PRINT_POP:
6779 case BC_INST_PRINT_STR:
6780 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006781 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006782 break;
6783 }
6784
6785 case BC_INST_STR:
6786 {
6787 r.t = BC_RESULT_STR;
6788 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006789 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 break;
6791 }
6792
6793 case BC_INST_POWER:
6794 case BC_INST_MULTIPLY:
6795 case BC_INST_DIVIDE:
6796 case BC_INST_MODULUS:
6797 case BC_INST_PLUS:
6798 case BC_INST_MINUS:
6799 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006800 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006801 break;
6802 }
6803
6804 case BC_INST_BOOL_NOT:
6805 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006806 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006807 if (s) return s;
6808
6809 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006810 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6811 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006812
6813 break;
6814 }
6815
6816 case BC_INST_NEG:
6817 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006818 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006819 break;
6820 }
6821
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006822#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006823 case BC_INST_ASSIGN_POWER:
6824 case BC_INST_ASSIGN_MULTIPLY:
6825 case BC_INST_ASSIGN_DIVIDE:
6826 case BC_INST_ASSIGN_MODULUS:
6827 case BC_INST_ASSIGN_PLUS:
6828 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006829#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006830 case BC_INST_ASSIGN:
6831 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006832 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006833 break;
6834 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006835#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006836 case BC_INST_MODEXP:
6837 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006838 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006839 break;
6840 }
6841
6842 case BC_INST_DIVMOD:
6843 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006844 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006845 break;
6846 }
6847
6848 case BC_INST_EXECUTE:
6849 case BC_INST_EXEC_COND:
6850 {
6851 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006852 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006853 break;
6854 }
6855
6856 case BC_INST_PRINT_STACK:
6857 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006858 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6859 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006860 break;
6861 }
6862
6863 case BC_INST_CLEAR_STACK:
6864 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006865 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006866 break;
6867 }
6868
6869 case BC_INST_STACK_LEN:
6870 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006871 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006872 break;
6873 }
6874
6875 case BC_INST_DUPLICATE:
6876 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006877 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006878 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006879 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006880 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006881 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006882 break;
6883 }
6884
6885 case BC_INST_SWAP:
6886 {
6887 BcResult *ptr2;
6888
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006889 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006890 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006891
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006892 ptr = bc_vec_item_rev(&G.prog.results, 0);
6893 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006894 memcpy(&r, ptr, sizeof(BcResult));
6895 memcpy(ptr, ptr2, sizeof(BcResult));
6896 memcpy(ptr2, &r, sizeof(BcResult));
6897
6898 break;
6899 }
6900
6901 case BC_INST_ASCIIFY:
6902 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006903 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006904 break;
6905 }
6906
6907 case BC_INST_PRINT_STREAM:
6908 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006909 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006910 break;
6911 }
6912
6913 case BC_INST_LOAD:
6914 case BC_INST_PUSH_VAR:
6915 {
6916 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006917 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006918 break;
6919 }
6920
6921 case BC_INST_PUSH_TO_VAR:
6922 {
6923 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006924 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006925 free(name);
6926 break;
6927 }
6928
6929 case BC_INST_QUIT:
6930 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006931 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006932 quit();
6933 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006934 break;
6935 }
6936
6937 case BC_INST_NQUIT:
6938 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006939 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006940 break;
6941 }
6942#endif // ENABLE_DC
6943 }
6944
Denys Vlasenkod38af482018-12-04 19:11:02 +01006945 if (s || G_interrupt) {
6946 bc_program_reset();
6947 break;
6948 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006949
6950 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006951 ip = bc_vec_top(&G.prog.stack);
6952 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006953 code = func->code.v;
6954 }
6955
6956 return s;
6957}
6958
Denys Vlasenko00d77792018-11-30 23:13:42 +01006959static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006960{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006961 printf("%s "BB_VER"\n"
6962 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006963 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006964 "This is free software with ABSOLUTELY NO WARRANTY\n"
6965 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006966}
6967
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006968#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006969static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006970{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006971 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6972
Gavin Howard01055ba2018-11-03 11:00:21 -06006973 BcVec v;
6974 char *env_args = getenv(bc_args_env_name), *buf;
6975
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006976 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006977
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006978 G.env_args = xstrdup(env_args);
6979 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006980
6981 bc_vec_init(&v, sizeof(char *), NULL);
6982 bc_vec_push(&v, &bc_args_env_name);
6983
6984 while (*buf != 0) {
6985 if (!isspace(*buf)) {
6986 bc_vec_push(&v, &buf);
6987 while (*buf != 0 && !isspace(*buf)) ++buf;
6988 if (*buf != 0) (*(buf++)) = '\0';
6989 }
6990 else
6991 ++buf;
6992 }
6993
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006994 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006995
6996 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006997}
6998#endif // ENABLE_BC
6999
7000static size_t bc_vm_envLen(const char *var)
7001{
7002 char *lenv = getenv(var);
7003 size_t i, len = BC_NUM_PRINT_WIDTH;
7004 int num;
7005
7006 if (!lenv) return len;
7007
7008 len = strlen(lenv);
7009
7010 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7011 if (num) {
7012 len = (size_t) atoi(lenv) - 1;
7013 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7014 }
7015 else
7016 len = BC_NUM_PRINT_WIDTH;
7017
7018 return len;
7019}
7020
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007021static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06007022{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007023 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06007024
Gavin Howard01055ba2018-11-03 11:00:21 -06007025 if (s) return s;
7026
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007027 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007028 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01007029 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007030 }
7031
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007032 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007033 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01007034 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007035 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01007036 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06007037 }
7038
7039 return s;
7040}
7041
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007042static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06007043{
7044 BcStatus s;
7045 char *data;
7046 BcFunc *main_func;
7047 BcInstPtr *ip;
7048
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007049 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01007050 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01007051 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007052
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007053 bc_lex_file(&G.prs.l, file);
7054 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007055 if (s) goto err;
7056
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007057 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7058 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007059
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007060 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01007061 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007062
7063err:
7064 free(data);
7065 return s;
7066}
7067
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007068static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007069{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007070 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007071 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007072 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007073 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007074
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007075 G.prog.file = bc_program_stdin_name;
7076 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007077
Denys Vlasenko7d628012018-12-04 21:46:47 +01007078 bc_char_vec_init(&buffer);
7079 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06007080 bc_vec_pushByte(&buffer, '\0');
7081
7082 // This loop is complex because the vm tries not to send any lines that end
7083 // with a backslash to the parser. The reason for that is because the parser
7084 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7085 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01007086 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007087
7088 char *string = buf.v;
7089
7090 len = buf.len - 1;
7091
7092 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007093 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007094 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007095 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007096 str += 1;
7097 }
7098 else if (len > 1 || comment) {
7099
7100 for (i = 0; i < len; ++i) {
7101
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007102 bool notend = len > i + 1;
7103 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007104
7105 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007106 if (G.sbgn == G.send)
7107 str ^= c == G.sbgn;
7108 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007109 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007110 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007111 str += 1;
7112 }
7113
7114 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7115 comment = true;
7116 break;
7117 }
7118 else if (c == '*' && notend && comment && string[i + 1] == '/')
7119 comment = false;
7120 }
7121
7122 if (str || comment || string[len - 2] == '\\') {
7123 bc_vec_concat(&buffer, buf.v);
7124 continue;
7125 }
7126 }
7127
7128 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007129 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007130 if (s) {
7131 fflush_and_check();
7132 fputs("ready for more input\n", stderr);
7133 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007134
Denys Vlasenko7d628012018-12-04 21:46:47 +01007135 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007136 }
7137
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007138 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007139 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007140 }
7141 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007142 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007143 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007144
Gavin Howard01055ba2018-11-03 11:00:21 -06007145 bc_vec_free(&buf);
7146 bc_vec_free(&buffer);
7147 return s;
7148}
7149
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007150static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007151{
7152 BcStatus s = BC_STATUS_SUCCESS;
7153 size_t i;
7154
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007155#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007156 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007157
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007158 bc_lex_file(&G.prs.l, bc_lib_name);
7159 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007160
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007161 while (!s && G.prs.l.t.t != BC_LEX_EOF)
7162 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007163
7164 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007165 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007166 if (s) return s;
7167 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007168#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007169
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007170 for (i = 0; !s && i < G.files.len; ++i)
7171 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007172 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007173 fflush_and_check();
7174 fputs("ready for more input\n", stderr);
7175 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007176
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007177 if (IS_BC || !G.files.len)
7178 s = bc_vm_stdin();
7179 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7180 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007181
Denys Vlasenko00d77792018-11-30 23:13:42 +01007182 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007183}
7184
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007185#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007186static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007187{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007188 bc_num_free(&G.prog.ib);
7189 bc_num_free(&G.prog.ob);
7190 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007191# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007192 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007193# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007194 bc_vec_free(&G.prog.fns);
7195 bc_vec_free(&G.prog.fn_map);
7196 bc_vec_free(&G.prog.vars);
7197 bc_vec_free(&G.prog.var_map);
7198 bc_vec_free(&G.prog.arrs);
7199 bc_vec_free(&G.prog.arr_map);
7200 bc_vec_free(&G.prog.strs);
7201 bc_vec_free(&G.prog.consts);
7202 bc_vec_free(&G.prog.results);
7203 bc_vec_free(&G.prog.stack);
7204 bc_num_free(&G.prog.last);
7205 bc_num_free(&G.prog.zero);
7206 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007207}
7208
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007209static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007210{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007211 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007212 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007213 bc_parse_free(&G.prs);
7214 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007215}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007216#endif
7217
7218static void bc_program_init(size_t line_len)
7219{
7220 size_t idx;
7221 BcInstPtr ip;
7222
7223 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7224 memset(&ip, 0, sizeof(BcInstPtr));
7225
7226 /* G.prog.nchars = G.prog.scale = 0; - already is */
7227 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007228
7229 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7230 bc_num_ten(&G.prog.ib);
7231 G.prog.ib_t = 10;
7232
7233 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7234 bc_num_ten(&G.prog.ob);
7235 G.prog.ob_t = 10;
7236
7237 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7238 bc_num_ten(&G.prog.hexb);
7239 G.prog.hexb.num[0] = 6;
7240
7241#if ENABLE_DC
7242 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7243 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7244#endif
7245
7246 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7247 bc_num_zero(&G.prog.last);
7248
7249 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7250 bc_num_zero(&G.prog.zero);
7251
7252 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7253 bc_num_one(&G.prog.one);
7254
7255 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007256 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007257
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007258 bc_program_addFunc(xstrdup("(main)"), &idx);
7259 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007260
7261 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007262 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007263
7264 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007265 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007266
7267 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7268 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7269 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7270 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7271 bc_vec_push(&G.prog.stack, &ip);
7272}
Gavin Howard01055ba2018-11-03 11:00:21 -06007273
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007274static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007275{
Gavin Howard01055ba2018-11-03 11:00:21 -06007276 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007277
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007278 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007279
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007280 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007281 bc_vm_envArgs();
7282 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007283
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007284 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007285 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007286 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007287 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007288 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007289 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007290}
7291
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007292static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007293 const char *env_len)
7294{
7295 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007296
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007297 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007298 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007299
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007300 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007301
Denys Vlasenkod38af482018-12-04 19:11:02 +01007302 if (G.ttyin) {
7303#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007304 // With SA_RESTART, most system calls will restart
7305 // (IOW: they won't fail with EINTR).
7306 // In particular, this means ^C won't cause
7307 // stdout to get into "error state" if SIGINT hits
7308 // within write() syscall.
7309 // The downside is that ^C while line input is taken
7310 // will only be handled after [Enter] since read()
7311 // from stdin is not interrupted by ^C either,
7312 // it restarts, thus fgetc() does not return on ^C.
7313 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7314
7315 // Without SA_RESTART, this exhibits a bug:
7316 // "while (1) print 1" and try ^C-ing it.
7317 // Intermittently, instead of returning to input line,
7318 // you'll get "output error: Interrupted system call"
7319 // and exit.
7320 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007321#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007322 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007323 bc_vm_info();
7324 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007325 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007326
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007327#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007328 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007329#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007330 return st;
7331}
7332
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007333#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007334int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7335int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007336{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007337 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007338 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007339
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007340 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007341}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007342#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007343
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007344#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007345int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7346int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007347{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007348 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007349 G.sbgn = '[';
7350 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007351
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007352 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007353}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007354#endif