blob: 2e3c4139e53167bd204cd7e1143843865a5b27da [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.
Gavin Howard01055ba2018-11-03 11:00:21 -06005 */
6//config:config BC
7//config: bool "bc (45 kb; 49 kb when combined with dc)"
8//config: default y
9//config: help
10//config: bc is a command-line, arbitrary-precision calculator with a
11//config: Turing-complete language. See the GNU bc manual
12//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
13//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
14//config: for details.
15//config:
16//config: This bc has four differences to the GNU bc:
17//config:
18//config: 1) The period (.) can also be used as a shortcut for "last", as in
19//config: the BSD bc.
20//config: 2) Arrays are copied before being passed as arguments to
21//config: functions. This behavior is required by the bc spec.
22//config: 3) Arrays can be passed to the builtin "length" function to get
23//config: the number of elements currently in the array. The following
24//config: example prints "1":
25//config:
26//config: a[0] = 0
27//config: length(a[])
28//config:
29//config: 4) The precedence of the boolean "not" operator (!) is equal to
30//config: that of the unary minus (-), or negation, operator. This still
31//config: allows POSIX-compliant scripts to work while somewhat
32//config: preserving expected behavior (versus C) and making parsing
33//config: easier.
34//config:
35//config: Options:
36//config:
37//config: -i --interactive force interactive mode
38//config: -l --mathlib use predefined math routines:
39//config:
40//config: s(expr) = sine of expr in radians
41//config: c(expr) = cosine of expr in radians
42//config: a(expr) = arctangent of expr, returning
43//config: radians
44//config: l(expr) = natural log of expr
45//config: e(expr) = raises e to the power of expr
46//config: j(n, x) = Bessel function of integer order
47//config: n of x
48//config:
49//config: -q --quiet don't print version and copyright.
50//config: -s --standard error if any non-POSIX extensions are used.
51//config: -w --warn warn if any non-POSIX extensions are used.
52//config: -v --version print version and copyright and exit.
53//config:
54//config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
55//config: enabled.
56//config:
57//config:config DC
58//config: bool "dc (38 kb; 49 kb when combined with bc)"
59//config: default y
60//config: help
61//config: dc is a reverse-polish notation command-line calculator which
62//config: supports unlimited precision arithmetic. See the FreeBSD man page
63//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
64//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
65//config: for details.
66//config:
67//config: This dc has a few differences from the two above:
68//config:
69//config: 1) When printing a byte stream (command "P"), this bc follows what
70//config: the FreeBSD dc does.
71//config: 2) This dc implements the GNU extensions for divmod ("~") and
72//config: modular exponentiation ("|").
73//config: 3) This dc implements all FreeBSD extensions, except for "J" and
74//config: "M".
75//config: 4) Like the FreeBSD dc, this dc supports extended registers.
76//config: However, they are implemented differently. When it encounters
77//config: whitespace where a register should be, it skips the whitespace.
78//config: If the character following is not a lowercase letter, an error
79//config: is issued. Otherwise, the register name is parsed by the
80//config: following regex:
81//config:
82//config: [a-z][a-z0-9_]*
83//config:
84//config: This generally means that register names will be surrounded by
85//config: whitespace.
86//config:
87//config: Examples:
88//config:
89//config: l idx s temp L index S temp2 < do_thing
90//config:
91//config: Also note that, like the FreeBSD dc, extended registers are not
92//config: allowed unless the "-x" option is given.
93//config:
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +010094//config:config FEATURE_DC_SMALL
95//config: bool "Minimal dc implementation (4.2 kb), not using bc code base"
96//config: depends on DC && !BC
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +010097//config: default n
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +010098//config:
99//config:config FEATURE_DC_LIBM
100//config: bool "Enable power and exp functions (requires libm)"
101//config: default y
102//config: depends on FEATURE_DC_SMALL
103//config: help
104//config: Enable power and exp functions.
105//config: NOTE: This will require libm to be present for linking.
106//config:
Gavin Howard01055ba2018-11-03 11:00:21 -0600107//config:config FEATURE_BC_SIGNALS
108//config: bool "Enable bc/dc signal handling"
109//config: default y
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100110//config: depends on (BC || DC) && !FEATURE_DC_SMALL
Gavin Howard01055ba2018-11-03 11:00:21 -0600111//config: help
112//config: Enable signal handling for bc and dc.
113//config:
114//config:config FEATURE_BC_LONG_OPTIONS
115//config: bool "Enable bc/dc long options"
116//config: default y
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100117//config: depends on (BC || DC) && !FEATURE_DC_SMALL
Gavin Howard01055ba2018-11-03 11:00:21 -0600118//config: help
119//config: Enable long options for bc and dc.
120
121//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
122//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
123
124//kbuild:lib-$(CONFIG_BC) += bc.o
125//kbuild:lib-$(CONFIG_DC) += bc.o
126
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100127//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600128//usage:#define bc_trivial_usage
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100129//usage: "[-sqliw] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600130//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100131//usage:#define bc_full_usage "\n"
132//usage: "\nArbitrary precision calculator"
133//usage: "\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100134///////: "\n -i Interactive" - has no effect for now
135//usage: "\n -q Quiet"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100136//usage: "\n -l Load standard math library"
137//usage: "\n -s Be POSIX compatible"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100138//usage: "\n -w Warn if extensions are used"
139///////: "\n -v Version"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100140//usage: "\n"
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100141//usage: "\n$BC_LINE_LENGTH changes output width"
Gavin Howard01055ba2018-11-03 11:00:21 -0600142//usage:
143//usage:#define bc_example_usage
144//usage: "3 + 4.129\n"
145//usage: "1903 - 2893\n"
146//usage: "-129 * 213.28935\n"
147//usage: "12 / -1932\n"
148//usage: "12 % 12\n"
149//usage: "34 ^ 189\n"
150//usage: "scale = 13\n"
151//usage: "ibase = 2\n"
152//usage: "obase = A\n"
153//usage:
154//usage:#define dc_trivial_usage
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +0100155//usage: IF_NOT_FEATURE_DC_SMALL("[-x] ")"[-eSCRIPT]... [-fFILE]... [FILE]..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600156//usage:
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100157//usage:#define dc_full_usage "\n"
158//usage: "\nTiny RPN calculator. Operations:"
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +0100159//usage: "\n+, -, *, /, %, ~, ^," IF_NOT_FEATURE_DC_SMALL(" |,")
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100160//usage: "\np - print top of the stack (without popping)"
161//usage: "\nf - print entire stack"
162//usage: "\nk - pop the value and set the precision"
163//usage: "\ni - pop the value and set input radix"
164//usage: "\no - pop the value and set output radix"
165//usage: "\nExamples: dc -e'2 2 + p' -> 4, dc -e'8 8 * 2 2 + / p' -> 16"
Gavin Howard01055ba2018-11-03 11:00:21 -0600166//usage:
167//usage:#define dc_example_usage
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100168//usage: "$ dc -e'2 2 + p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600169//usage: "4\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100170//usage: "$ dc -e'8 8 \\* 2 2 + / p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600171//usage: "16\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100172//usage: "$ dc -e'0 1 & p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600173//usage: "0\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100174//usage: "$ dc -e'0 1 | p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600175//usage: "1\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100176//usage: "$ echo '72 9 / 8 * p' | dc\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600177//usage: "64\n"
178
179#include "libbb.h"
Denys Vlasenko95f93bd2018-12-06 10:29:12 +0100180#include "common_bufsiz.h"
Gavin Howard01055ba2018-11-03 11:00:21 -0600181
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100182#if ENABLE_FEATURE_DC_SMALL
183# include "dc.c"
184#else
185
Gavin Howard01055ba2018-11-03 11:00:21 -0600186typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100187 BC_STATUS_SUCCESS = 0,
188 BC_STATUS_FAILURE = 1,
189 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Denys Vlasenkof522dd92018-12-07 16:35:43 +0100190 BC_STATUS_EOF = 3, // bc_vm_stdin() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600191} BcStatus;
192
Gavin Howard01055ba2018-11-03 11:00:21 -0600193#define BC_VEC_INVALID_IDX ((size_t) -1)
194#define BC_VEC_START_CAP (1 << 5)
195
196typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600197
198typedef struct BcVec {
199 char *v;
200 size_t len;
201 size_t cap;
202 size_t size;
203 BcVecFree dtor;
204} BcVec;
205
Gavin Howard01055ba2018-11-03 11:00:21 -0600206typedef signed char BcDig;
207
208typedef struct BcNum {
209 BcDig *restrict num;
210 size_t rdx;
211 size_t len;
212 size_t cap;
213 bool neg;
214} BcNum;
215
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100216#define BC_NUM_MIN_BASE ((unsigned long) 2)
217#define BC_NUM_MAX_IBASE ((unsigned long) 16)
218// larger value might speed up BIGNUM calculations a bit:
219#define BC_NUM_DEF_SIZE (16)
220#define BC_NUM_PRINT_WIDTH (69)
Gavin Howard01055ba2018-11-03 11:00:21 -0600221
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100222#define BC_NUM_KARATSUBA_LEN (32)
Gavin Howard01055ba2018-11-03 11:00:21 -0600223
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +0100224typedef void (*BcNumDigitOp)(size_t, size_t, bool);
Denys Vlasenko2a8ad482018-12-08 21:56:37 +0100225
Gavin Howard01055ba2018-11-03 11:00:21 -0600226typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
Gavin Howard01055ba2018-11-03 11:00:21 -0600227
Gavin Howard01055ba2018-11-03 11:00:21 -0600228static 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
Gavin Howard01055ba2018-11-03 11:00:21 -0600390// BC_LEX_NEG is not used in lexing; it is only for parsing.
391typedef enum BcLexType {
392
393 BC_LEX_EOF,
394 BC_LEX_INVALID,
395
396 BC_LEX_OP_INC,
397 BC_LEX_OP_DEC,
398
399 BC_LEX_NEG,
400
401 BC_LEX_OP_POWER,
402 BC_LEX_OP_MULTIPLY,
403 BC_LEX_OP_DIVIDE,
404 BC_LEX_OP_MODULUS,
405 BC_LEX_OP_PLUS,
406 BC_LEX_OP_MINUS,
407
408 BC_LEX_OP_REL_EQ,
409 BC_LEX_OP_REL_LE,
410 BC_LEX_OP_REL_GE,
411 BC_LEX_OP_REL_NE,
412 BC_LEX_OP_REL_LT,
413 BC_LEX_OP_REL_GT,
414
415 BC_LEX_OP_BOOL_NOT,
416 BC_LEX_OP_BOOL_OR,
417 BC_LEX_OP_BOOL_AND,
418
419 BC_LEX_OP_ASSIGN_POWER,
420 BC_LEX_OP_ASSIGN_MULTIPLY,
421 BC_LEX_OP_ASSIGN_DIVIDE,
422 BC_LEX_OP_ASSIGN_MODULUS,
423 BC_LEX_OP_ASSIGN_PLUS,
424 BC_LEX_OP_ASSIGN_MINUS,
425 BC_LEX_OP_ASSIGN,
426
427 BC_LEX_NLINE,
428 BC_LEX_WHITESPACE,
429
430 BC_LEX_LPAREN,
431 BC_LEX_RPAREN,
432
433 BC_LEX_LBRACKET,
434 BC_LEX_COMMA,
435 BC_LEX_RBRACKET,
436
437 BC_LEX_LBRACE,
438 BC_LEX_SCOLON,
439 BC_LEX_RBRACE,
440
441 BC_LEX_STR,
442 BC_LEX_NAME,
443 BC_LEX_NUMBER,
444
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100445 BC_LEX_KEY_1st_keyword,
446 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600447 BC_LEX_KEY_BREAK,
448 BC_LEX_KEY_CONTINUE,
449 BC_LEX_KEY_DEFINE,
450 BC_LEX_KEY_ELSE,
451 BC_LEX_KEY_FOR,
452 BC_LEX_KEY_HALT,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100453 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
454 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600455 BC_LEX_KEY_IF,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100456 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600457 BC_LEX_KEY_LENGTH,
458 BC_LEX_KEY_LIMITS,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100459 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600460 BC_LEX_KEY_PRINT,
461 BC_LEX_KEY_QUIT,
462 BC_LEX_KEY_READ,
463 BC_LEX_KEY_RETURN,
464 BC_LEX_KEY_SCALE,
465 BC_LEX_KEY_SQRT,
466 BC_LEX_KEY_WHILE,
467
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100468#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600469 BC_LEX_EQ_NO_REG,
470 BC_LEX_OP_MODEXP,
471 BC_LEX_OP_DIVMOD,
472
473 BC_LEX_COLON,
474 BC_LEX_ELSE,
475 BC_LEX_EXECUTE,
476 BC_LEX_PRINT_STACK,
477 BC_LEX_CLEAR_STACK,
478 BC_LEX_STACK_LEVEL,
479 BC_LEX_DUPLICATE,
480 BC_LEX_SWAP,
481 BC_LEX_POP,
482
483 BC_LEX_ASCIIFY,
484 BC_LEX_PRINT_STREAM,
485
486 BC_LEX_STORE_IBASE,
487 BC_LEX_STORE_SCALE,
488 BC_LEX_LOAD,
489 BC_LEX_LOAD_POP,
490 BC_LEX_STORE_PUSH,
491 BC_LEX_STORE_OBASE,
492 BC_LEX_PRINT_POP,
493 BC_LEX_NQUIT,
494 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100495#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600496} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100497// must match order of BC_LEX_KEY_foo etc above
498#if ENABLE_BC
499struct BcLexKeyword {
500 char name8[8];
501};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100502#define BC_LEX_KW_ENTRY(a, b) \
503 { .name8 = a /*, .posix = b */ }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100504static const struct BcLexKeyword bc_lex_kws[20] = {
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100505 BC_LEX_KW_ENTRY("auto" , 1), // 0
506 BC_LEX_KW_ENTRY("break" , 1), // 1
507 BC_LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
508 BC_LEX_KW_ENTRY("define" , 1), // 3
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100509
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100510 BC_LEX_KW_ENTRY("else" , 0), // 4
511 BC_LEX_KW_ENTRY("for" , 1), // 5
512 BC_LEX_KW_ENTRY("halt" , 0), // 6
513 BC_LEX_KW_ENTRY("ibase" , 1), // 7
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100514
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100515 BC_LEX_KW_ENTRY("if" , 1), // 8
516 BC_LEX_KW_ENTRY("last" , 0), // 9
517 BC_LEX_KW_ENTRY("length" , 1), // 10
518 BC_LEX_KW_ENTRY("limits" , 0), // 11
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100519
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100520 BC_LEX_KW_ENTRY("obase" , 1), // 12
521 BC_LEX_KW_ENTRY("print" , 0), // 13
522 BC_LEX_KW_ENTRY("quit" , 1), // 14
523 BC_LEX_KW_ENTRY("read" , 0), // 15
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100524
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100525 BC_LEX_KW_ENTRY("return" , 1), // 16
526 BC_LEX_KW_ENTRY("scale" , 1), // 17
527 BC_LEX_KW_ENTRY("sqrt" , 1), // 18
528 BC_LEX_KW_ENTRY("while" , 1), // 19
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100529};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100530#undef BC_LEX_KW_ENTRY
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100531enum {
532 POSIX_KWORD_MASK = 0
533 | (1 << 0)
534 | (1 << 1)
535 | (0 << 2)
536 | (1 << 3)
537 \
538 | (0 << 4)
539 | (1 << 5)
540 | (0 << 6)
541 | (1 << 7)
542 \
543 | (1 << 8)
544 | (0 << 9)
545 | (1 << 10)
546 | (0 << 11)
547 \
548 | (1 << 12)
549 | (0 << 13)
550 | (1 << 14)
551 | (0 << 15)
552 \
553 | (1 << 16)
554 | (1 << 17)
555 | (1 << 18)
556 | (1 << 19)
557};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100558#define bc_lex_kws_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100559#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600560
561struct BcLex;
562typedef BcStatus (*BcLexNext)(struct BcLex *);
563
564typedef struct BcLex {
565
566 const char *buf;
567 size_t i;
568 size_t line;
Gavin Howard01055ba2018-11-03 11:00:21 -0600569 size_t len;
570 bool newline;
571
572 struct {
573 BcLexType t;
574 BcLexType last;
575 BcVec v;
576 } t;
577
578 BcLexNext next;
579
580} BcLex;
581
582#define BC_PARSE_STREND ((char) UCHAR_MAX)
583
Denys Vlasenkoe55a5722018-12-06 12:47:17 +0100584#define BC_PARSE_REL (1 << 0)
585#define BC_PARSE_PRINT (1 << 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600586#define BC_PARSE_NOCALL (1 << 2)
587#define BC_PARSE_NOREAD (1 << 3)
Denys Vlasenkoe55a5722018-12-06 12:47:17 +0100588#define BC_PARSE_ARRAY (1 << 4)
Gavin Howard01055ba2018-11-03 11:00:21 -0600589
590#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
591#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
592
593#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
594#define BC_PARSE_FUNC_INNER(parse) \
595 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
596
597#define BC_PARSE_FLAG_FUNC (1 << 1)
598#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
599
600#define BC_PARSE_FLAG_BODY (1 << 2)
601#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
602
603#define BC_PARSE_FLAG_LOOP (1 << 3)
604#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
605
606#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
607#define BC_PARSE_LOOP_INNER(parse) \
608 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
609
610#define BC_PARSE_FLAG_IF (1 << 5)
611#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
612
613#define BC_PARSE_FLAG_ELSE (1 << 6)
614#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
615
616#define BC_PARSE_FLAG_IF_END (1 << 7)
617#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
618
619#define BC_PARSE_CAN_EXEC(parse) \
620 (!(BC_PARSE_TOP_FLAG(parse) & \
621 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
622 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
623 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
624
Gavin Howard01055ba2018-11-03 11:00:21 -0600625struct BcParse;
626
627struct BcProgram;
628
Gavin Howard01055ba2018-11-03 11:00:21 -0600629typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600630
631typedef struct BcParse {
632
633 BcParseParse parse;
634
635 BcLex l;
636
637 BcVec flags;
638
639 BcVec exits;
640 BcVec conds;
641
642 BcVec ops;
643
Gavin Howard01055ba2018-11-03 11:00:21 -0600644 BcFunc *func;
645 size_t fidx;
646
647 size_t nbraces;
648 bool auto_part;
649
650} BcParse;
651
Gavin Howard01055ba2018-11-03 11:00:21 -0600652typedef struct BcProgram {
653
654 size_t len;
655 size_t scale;
656
657 BcNum ib;
658 size_t ib_t;
659 BcNum ob;
660 size_t ob_t;
661
662 BcNum hexb;
663
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100664#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600665 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100666#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600667
668 BcVec results;
669 BcVec stack;
670
671 BcVec fns;
672 BcVec fn_map;
673
674 BcVec vars;
675 BcVec var_map;
676
677 BcVec arrs;
678 BcVec arr_map;
679
680 BcVec strs;
681 BcVec consts;
682
683 const char *file;
684
685 BcNum last;
686 BcNum zero;
687 BcNum one;
688
689 size_t nchars;
690
Gavin Howard01055ba2018-11-03 11:00:21 -0600691} BcProgram;
692
693#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
694
695#define BC_PROG_MAIN (0)
696#define BC_PROG_READ (1)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100697#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600698#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100699#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600700
701#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
702#define BC_PROG_NUM(r, n) \
703 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
704
705typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
706
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100707#define BC_FLAG_W (1 << 0)
708#define BC_FLAG_V (1 << 1)
709#define BC_FLAG_S (1 << 2)
710#define BC_FLAG_Q (1 << 3)
711#define BC_FLAG_L (1 << 4)
712#define BC_FLAG_I (1 << 5)
713#define DC_FLAG_X (1 << 6)
Gavin Howard01055ba2018-11-03 11:00:21 -0600714
715#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
716#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
717
Denys Vlasenko64074a12018-12-07 15:50:14 +0100718#define BC_MAX_OBASE ((unsigned) 999)
719#define BC_MAX_DIM ((unsigned) INT_MAX)
720#define BC_MAX_SCALE ((unsigned) UINT_MAX)
721#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
722#define BC_MAX_NUM BC_MAX_STRING
723// Unused apart from "limits" message. Just show a "biggish number" there.
724//#define BC_MAX_NAME BC_MAX_STRING
725//#define BC_MAX_EXP ((unsigned long) LONG_MAX)
726//#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
727#define BC_MAX_NAME_STR "999999999"
728#define BC_MAX_EXP_STR "999999999"
729#define BC_MAX_VARS_STR "999999999"
730
731#define BC_MAX_OBASE_STR "999"
732
733#if INT_MAX == 2147483647
734# define BC_MAX_DIM_STR "2147483647"
735#elif INT_MAX == 9223372036854775807
736# define BC_MAX_DIM_STR "9223372036854775807"
737#else
738# error Strange INT_MAX
739#endif
740
741#if UINT_MAX == 4294967295
742# define BC_MAX_SCALE_STR "4294967295"
743# define BC_MAX_STRING_STR "4294967294"
744#elif UINT_MAX == 18446744073709551615
745# define BC_MAX_SCALE_STR "18446744073709551615"
746# define BC_MAX_STRING_STR "18446744073709551614"
747#else
748# error Strange UINT_MAX
749#endif
750#define BC_MAX_NUM_STR BC_MAX_STRING_STR
Gavin Howard01055ba2018-11-03 11:00:21 -0600751
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100752struct globals {
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100753 IF_FEATURE_BC_SIGNALS(smallint ttyin;)
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100754 IF_FEATURE_CLEAN_UP(smallint exiting;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600755 char sbgn;
756 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600757
758 BcParse prs;
759 BcProgram prog;
760
Denys Vlasenko5318f812018-12-05 17:48:01 +0100761 // For error messages. Can be set to current parsed line,
762 // or [TODO] to current executing line (can be before last parsed one)
763 unsigned err_line;
764
Gavin Howard01055ba2018-11-03 11:00:21 -0600765 BcVec files;
766
767 char *env_args;
Denys Vlasenko95f93bd2018-12-06 10:29:12 +0100768
769#if ENABLE_FEATURE_EDITING
770 line_input_t *line_input_state;
771#endif
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100772} FIX_ALIASING;
773#define G (*ptr_to_globals)
774#define INIT_G() do { \
775 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
776} while (0)
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100777#define FREE_G() do { \
778 FREE_PTR_TO_GLOBALS(); \
779} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100780#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
781#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100782#define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100783#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkob9c321d2018-12-07 12:41:42 +0100784# define G_interrupt bb_got_signal
785# define G_ttyin G.ttyin
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100786#else
Denys Vlasenkob9c321d2018-12-07 12:41:42 +0100787# define G_interrupt 0
788# define G_ttyin 0
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100789#endif
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100790#if ENABLE_FEATURE_CLEAN_UP
791# define G_exiting G.exiting
792#else
793# define G_exiting 0
794#endif
Denys Vlasenko00d77792018-11-30 23:13:42 +0100795#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
796
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100797#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600798
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100799// This is a bit array that corresponds to token types. An entry is
Gavin Howard01055ba2018-11-03 11:00:21 -0600800// true if the token is valid in an expression, false otherwise.
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100801enum {
802 BC_PARSE_EXPRS_BITS = 0
803 + ((uint64_t)((0 << 0)+(0 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (0*8))
804 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (1*8))
805 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (2*8))
806 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(0 << 3)+(0 << 4)+(1 << 5)+(1 << 6)+(0 << 7)) << (3*8))
807 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(1 << 6)+(1 << 7)) << (4*8))
808 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (5*8))
809 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (6*8))
810 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(0 << 3) ) << (7*8))
Gavin Howard01055ba2018-11-03 11:00:21 -0600811};
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100812static ALWAYS_INLINE long bc_parse_exprs(unsigned i)
813{
814#if ULONG_MAX > 0xffffffff
815 // 64-bit version (will not work correctly for 32-bit longs!)
816 return BC_PARSE_EXPRS_BITS & (1UL << i);
817#else
818 // 32-bit version
819 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
820 if (i >= 32) {
821 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
822 i &= 31;
823 }
824 return m & (1UL << i);
825#endif
826}
Gavin Howard01055ba2018-11-03 11:00:21 -0600827
828// This is an array of data for operators that correspond to token types.
Denys Vlasenko65437582018-12-05 19:37:19 +0100829static const uint8_t bc_parse_ops[] = {
830#define OP(p,l) ((int)(l) * 0x10 + (p))
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100831 OP(0, false), OP( 0, false ), // inc dec
832 OP(1, false), // neg
Denys Vlasenko65437582018-12-05 19:37:19 +0100833 OP(2, false),
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100834 OP(3, true ), OP( 3, true ), OP( 3, true ), // pow mul div
835 OP(4, true ), OP( 4, true ), // mod + -
836 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), // == <= >= != < >
837 OP(1, false), // not
838 OP(7, true ), OP( 7, true ), // or and
839 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ), // ^= *= /= %= +=
840 OP(5, false), OP( 5, false ), // -= =
Denys Vlasenko65437582018-12-05 19:37:19 +0100841#undef OP
Gavin Howard01055ba2018-11-03 11:00:21 -0600842};
Denys Vlasenko65437582018-12-05 19:37:19 +0100843#define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
844#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
Gavin Howard01055ba2018-11-03 11:00:21 -0600845
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100846// Byte array of up to 4 BC_LEX's, packed into 32-bit word
847typedef uint32_t BcParseNext;
848
Gavin Howard01055ba2018-11-03 11:00:21 -0600849// These identify what tokens can come after expressions in certain cases.
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100850enum {
851#define BC_PARSE_NEXT4(a,b,c,d) ( (a) | ((b)<<8) | ((c)<<16) | ((((d)|0x80)<<24)) )
852#define BC_PARSE_NEXT2(a,b) BC_PARSE_NEXT4(a,b,0xff,0xff)
853#define BC_PARSE_NEXT1(a) BC_PARSE_NEXT4(a,0xff,0xff,0xff)
854 bc_parse_next_expr = BC_PARSE_NEXT4(BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF),
855 bc_parse_next_param = BC_PARSE_NEXT2(BC_LEX_RPAREN, BC_LEX_COMMA),
856 bc_parse_next_print = BC_PARSE_NEXT4(BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF),
857 bc_parse_next_rel = BC_PARSE_NEXT1(BC_LEX_RPAREN),
858 bc_parse_next_elem = BC_PARSE_NEXT1(BC_LEX_RBRACKET),
859 bc_parse_next_for = BC_PARSE_NEXT1(BC_LEX_SCOLON),
860 bc_parse_next_read = BC_PARSE_NEXT2(BC_LEX_NLINE, BC_LEX_EOF),
861#undef BC_PARSE_NEXT4
862#undef BC_PARSE_NEXT2
863#undef BC_PARSE_NEXT1
864};
Gavin Howard01055ba2018-11-03 11:00:21 -0600865#endif // ENABLE_BC
866
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100867#if ENABLE_DC
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100868static const //BcLexType - should be this type, but narrower type saves size:
869uint8_t
870dc_lex_regs[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600871 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
872 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
873 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
874 BC_LEX_STORE_PUSH,
875};
876
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100877static const //BcLexType - should be this type
878uint8_t
879dc_lex_tokens[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600880 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
881 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
882 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
883 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
884 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
885 BC_LEX_INVALID, BC_LEX_INVALID,
886 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
887 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
888 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
889 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
890 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
891 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
892 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
893 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
894 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
895 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
896 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
897 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
898 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
899 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
900 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
901 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
902 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
903 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
904 BC_LEX_INVALID
905};
906
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100907static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1
908int8_t
909dc_parse_insts[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
911 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
912 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
913 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
914 BC_INST_INVALID, BC_INST_INVALID,
915 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
916 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
917 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
918 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
919 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
920 BC_INST_INVALID, BC_INST_INVALID,
921 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
922 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
923 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
924 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
925 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
926 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
927 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
928 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
929 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
930 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
931 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
932 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
933};
934#endif // ENABLE_DC
935
Gavin Howard01055ba2018-11-03 11:00:21 -0600936static const BcNumBinaryOp bc_program_ops[] = {
937 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
938};
939
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100940static void fflush_and_check(void)
941{
942 fflush_all();
943 if (ferror(stdout) || ferror(stderr))
944 bb_perror_msg_and_die("output error");
945}
946
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100947#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100948#define QUIT_OR_RETURN_TO_MAIN \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100949do { \
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100950 IF_FEATURE_BC_SIGNALS(G_ttyin = 0;) /* do not loop in main loop anymore */ \
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100951 G_exiting = 1; \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100952 return BC_STATUS_FAILURE; \
953} while (0)
954#else
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100955#define QUIT_OR_RETURN_TO_MAIN quit()
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100956#endif
957
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100958static void quit(void) NORETURN;
959static void quit(void)
960{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100961 if (ferror(stdin))
962 bb_perror_msg_and_die("input error");
963 fflush_and_check();
964 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100965}
966
Denys Vlasenko5318f812018-12-05 17:48:01 +0100967static void bc_verror_msg(const char *fmt, va_list p)
968{
969 const char *sv = sv; /* for compiler */
970 if (G.prog.file) {
971 sv = applet_name;
972 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
973 }
974 bb_verror_msg(fmt, p, NULL);
975 if (G.prog.file) {
976 free((char*)applet_name);
977 applet_name = sv;
978 }
979}
980
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100981static NOINLINE int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100982{
983 va_list p;
984
985 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100986 bc_verror_msg(fmt, p);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100987 va_end(p);
Denys Vlasenko0409ad32018-12-05 16:39:22 +0100988
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100989 if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100990 exit(1);
991 return BC_STATUS_FAILURE;
992}
993
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +0100994#if ENABLE_BC
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100995static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100996{
997 va_list p;
998
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100999 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001000 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001001 return BC_STATUS_SUCCESS; // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001002
1003 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +01001004 bc_verror_msg(fmt, p);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001005 va_end(p);
1006
1007 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001008 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001009 return BC_STATUS_SUCCESS; // no, it's a warning
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01001010 if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001011 exit(1);
1012 return BC_STATUS_FAILURE;
1013}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001014#endif
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001015
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001016// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
1017// This idiom begs for tail-call optimization, but for it to work,
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001018// function must not have caller-cleaned parameters on stack.
1019// Unfortunately, vararg function API does exactly that on most arches.
1020// Thus, use these shims for the cases when we have no vararg PARAMS:
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001021static int bc_error(const char *msg)
1022{
1023 return bc_error_fmt("%s", msg);
1024}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001025#if ENABLE_BC
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01001026static int bc_POSIX_requires(const char *msg)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001027{
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01001028 return bc_posix_error_fmt("POSIX requires %s", msg);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001029}
Denys Vlasenko00646792018-12-05 18:12:27 +01001030static int bc_POSIX_does_not_allow(const char *msg)
1031{
1032 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
1033}
1034static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1035{
1036 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1037}
1038static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1039{
1040 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1041}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001042#endif
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001043static int bc_error_bad_character(char c)
1044{
1045 return bc_error_fmt("bad character '%c'", c);
1046}
1047static int bc_error_bad_expression(void)
1048{
1049 return bc_error("bad expression");
1050}
1051static int bc_error_bad_token(void)
1052{
1053 return bc_error("bad token");
1054}
1055static int bc_error_stack_has_too_few_elements(void)
1056{
1057 return bc_error("stack has too few elements");
1058}
1059static int bc_error_variable_is_wrong_type(void)
1060{
1061 return bc_error("variable is wrong type");
1062}
1063static int bc_error_nested_read_call(void)
1064{
1065 return bc_error("read() call inside of a read() call");
1066}
1067
Gavin Howard01055ba2018-11-03 11:00:21 -06001068static void bc_vec_grow(BcVec *v, size_t n)
1069{
1070 size_t cap = v->cap * 2;
1071 while (cap < v->len + n) cap *= 2;
1072 v->v = xrealloc(v->v, v->size * cap);
1073 v->cap = cap;
1074}
1075
1076static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1077{
1078 v->size = esize;
1079 v->cap = BC_VEC_START_CAP;
1080 v->len = 0;
1081 v->dtor = dtor;
1082 v->v = xmalloc(esize * BC_VEC_START_CAP);
1083}
1084
Denys Vlasenko7d628012018-12-04 21:46:47 +01001085static void bc_char_vec_init(BcVec *v)
1086{
1087 bc_vec_init(v, sizeof(char), NULL);
1088}
1089
Gavin Howard01055ba2018-11-03 11:00:21 -06001090static void bc_vec_expand(BcVec *v, size_t req)
1091{
1092 if (v->cap < req) {
1093 v->v = xrealloc(v->v, v->size * req);
1094 v->cap = req;
1095 }
1096}
1097
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001098static void bc_vec_pop(BcVec *v)
1099{
1100 v->len--;
1101 if (v->dtor)
1102 v->dtor(v->v + (v->size * v->len));
1103}
Denys Vlasenko2fa11b62018-12-06 12:34:39 +01001104
Gavin Howard01055ba2018-11-03 11:00:21 -06001105static void bc_vec_npop(BcVec *v, size_t n)
1106{
1107 if (!v->dtor)
1108 v->len -= n;
1109 else {
1110 size_t len = v->len - n;
1111 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1112 }
1113}
1114
Denys Vlasenko7d628012018-12-04 21:46:47 +01001115static void bc_vec_pop_all(BcVec *v)
1116{
1117 bc_vec_npop(v, v->len);
1118}
1119
Gavin Howard01055ba2018-11-03 11:00:21 -06001120static void bc_vec_push(BcVec *v, const void *data)
1121{
1122 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1123 memmove(v->v + (v->size * v->len), data, v->size);
1124 v->len += 1;
1125}
1126
1127static void bc_vec_pushByte(BcVec *v, char data)
1128{
1129 bc_vec_push(v, &data);
1130}
1131
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001132static void bc_vec_pushZeroByte(BcVec *v)
1133{
1134 //bc_vec_pushByte(v, '\0');
1135 // better:
1136 bc_vec_push(v, &const_int_0);
1137}
1138
Gavin Howard01055ba2018-11-03 11:00:21 -06001139static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1140{
1141 if (idx == v->len)
1142 bc_vec_push(v, data);
1143 else {
1144
1145 char *ptr;
1146
1147 if (v->len == v->cap) bc_vec_grow(v, 1);
1148
1149 ptr = v->v + v->size * idx;
1150
1151 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1152 memmove(ptr, data, v->size);
1153 }
1154}
1155
1156static void bc_vec_string(BcVec *v, size_t len, const char *str)
1157{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001158 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001159 bc_vec_expand(v, len + 1);
1160 memcpy(v->v, str, len);
1161 v->len = len;
1162
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001163 bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001164}
1165
1166static void bc_vec_concat(BcVec *v, const char *str)
1167{
1168 size_t len;
1169
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001170 if (v->len == 0) bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001171
1172 len = v->len + strlen(str);
1173
1174 if (v->cap < len) bc_vec_grow(v, len - v->len);
Denys Vlasenko1ff88622018-12-06 12:06:16 +01001175 strcpy(v->v + v->len - 1, str);
Gavin Howard01055ba2018-11-03 11:00:21 -06001176
1177 v->len = len;
1178}
1179
1180static void *bc_vec_item(const BcVec *v, size_t idx)
1181{
1182 return v->v + v->size * idx;
1183}
1184
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01001185static char** bc_program_str(size_t idx)
1186{
1187 return bc_vec_item(&G.prog.strs, idx);
1188}
1189
1190static BcFunc* bc_program_func(size_t idx)
1191{
1192 return bc_vec_item(&G.prog.fns, idx);
1193}
1194
Gavin Howard01055ba2018-11-03 11:00:21 -06001195static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1196{
1197 return v->v + v->size * (v->len - idx - 1);
1198}
1199
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001200static void *bc_vec_top(const BcVec *v)
1201{
1202 return v->v + v->size * (v->len - 1);
1203}
1204
Gavin Howard01055ba2018-11-03 11:00:21 -06001205static void bc_vec_free(void *vec)
1206{
1207 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001208 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001209 free(v->v);
1210}
1211
Denys Vlasenkocca79a02018-12-05 21:15:46 +01001212static int bc_id_cmp(const void *e1, const void *e2)
1213{
1214 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
1215}
1216
1217static void bc_id_free(void *id)
1218{
1219 free(((BcId *) id)->name);
1220}
1221
Gavin Howard01055ba2018-11-03 11:00:21 -06001222static size_t bc_map_find(const BcVec *v, const void *ptr)
1223{
1224 size_t low = 0, high = v->len;
1225
1226 while (low < high) {
1227
1228 size_t mid = (low + high) / 2;
1229 BcId *id = bc_vec_item(v, mid);
1230 int result = bc_id_cmp(ptr, id);
1231
1232 if (result == 0)
1233 return mid;
1234 else if (result < 0)
1235 high = mid;
1236 else
1237 low = mid + 1;
1238 }
1239
1240 return low;
1241}
1242
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001243static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001244{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001245 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001246
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001247 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001248 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001249 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1250 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001251 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001252 bc_vec_pushAt(v, ptr, n);
1253 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001254}
1255
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001256#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001257static size_t bc_map_index(const BcVec *v, const void *ptr)
1258{
1259 size_t i = bc_map_find(v, ptr);
1260 if (i >= v->len) return BC_VEC_INVALID_IDX;
1261 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1262}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001263#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001264
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001265static int push_input_byte(BcVec *vec, char c)
1266{
1267 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1268 || c > 0x7e
1269 ) {
1270 // Bad chars on this line, ignore entire line
1271 bc_error_fmt("illegal character 0x%02x", c);
1272 return 1;
1273 }
1274 bc_vec_pushByte(vec, (char)c);
1275 return 0;
1276}
1277
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +01001278static BcStatus bc_read_line(BcVec *vec)
Gavin Howard01055ba2018-11-03 11:00:21 -06001279{
Denys Vlasenkof522dd92018-12-07 16:35:43 +01001280 BcStatus s;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001281 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001282
Denys Vlasenkof522dd92018-12-07 16:35:43 +01001283 s = BC_STATUS_SUCCESS;
Denys Vlasenko00d77792018-11-30 23:13:42 +01001284 do {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001285 int c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001286
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001287 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001288 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001289
1290 fflush_and_check();
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001291
Gavin Howard01055ba2018-11-03 11:00:21 -06001292#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001293 if (G_interrupt) { // ^C was pressed
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001294 intr:
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001295 G_interrupt = 0;
Denys Vlasenkoac6ed112018-12-08 21:39:10 +01001296 // GNU bc says "interrupted execution."
1297 // GNU dc says "Interrupt!"
1298 fputs("\ninterrupted execution\n", stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001299 }
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001300# if ENABLE_FEATURE_EDITING
1301 if (G_ttyin) {
1302 int n, i;
1303# define line_buf bb_common_bufsiz1
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +01001304 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001305 if (n <= 0) { // read errors or EOF, or ^D, or ^C
1306 if (n == 0) // ^C
1307 goto intr;
Denys Vlasenkof522dd92018-12-07 16:35:43 +01001308 s = BC_STATUS_EOF;
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001309 break;
1310 }
1311 i = 0;
1312 for (;;) {
1313 c = line_buf[i++];
1314 if (!c) break;
1315 bad_chars |= push_input_byte(vec, c);
1316 }
1317# undef line_buf
1318 } else
1319# endif
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001320#endif
Denys Vlasenkoed849352018-12-06 10:26:13 +01001321 {
Denys Vlasenkoed849352018-12-06 10:26:13 +01001322 IF_FEATURE_BC_SIGNALS(errno = 0;)
1323 do {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001324 c = fgetc(stdin);
1325#if ENABLE_FEATURE_BC_SIGNALS && !ENABLE_FEATURE_EDITING
1326 // Both conditions appear simultaneously, check both just in case
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001327 if (errno == EINTR || G_interrupt) {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001328 // ^C was pressed
1329 clearerr(stdin);
1330 goto intr;
1331 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001332#endif
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001333 if (c == EOF) {
Denys Vlasenkoed849352018-12-06 10:26:13 +01001334 if (ferror(stdin))
1335 quit(); // this emits error message
Denys Vlasenkof522dd92018-12-07 16:35:43 +01001336 s = BC_STATUS_EOF;
Denys Vlasenkoed849352018-12-06 10:26:13 +01001337 // Note: EOF does not append '\n', therefore:
1338 // printf 'print 123\n' | bc - works
1339 // printf 'print 123' | bc - fails (syntax error)
1340 break;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001341 }
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001342 bad_chars |= push_input_byte(vec, c);
1343 } while (c != '\n');
Denys Vlasenkoed849352018-12-06 10:26:13 +01001344 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001345 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001346
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001347 bc_vec_pushZeroByte(vec);
Gavin Howard01055ba2018-11-03 11:00:21 -06001348
Denys Vlasenkof522dd92018-12-07 16:35:43 +01001349 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06001350}
1351
Denys Vlasenkodf515392018-12-02 19:27:48 +01001352static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001353{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001354 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001355 size_t size = ((size_t) -1);
1356 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001357
Denys Vlasenko4c9455f2018-12-06 15:21:39 +01001358 // Never returns NULL (dies on errors)
1359 buf = xmalloc_xopen_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001360
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001361 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001362 char c = buf[i];
1363 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1364 || c > 0x7e
1365 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001366 free(buf);
1367 buf = NULL;
1368 break;
1369 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001370 }
1371
Denys Vlasenkodf515392018-12-02 19:27:48 +01001372 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001373}
1374
Gavin Howard01055ba2018-11-03 11:00:21 -06001375static void bc_num_setToZero(BcNum *n, size_t scale)
1376{
1377 n->len = 0;
1378 n->neg = false;
1379 n->rdx = scale;
1380}
1381
1382static void bc_num_zero(BcNum *n)
1383{
1384 bc_num_setToZero(n, 0);
1385}
1386
1387static void bc_num_one(BcNum *n)
1388{
1389 bc_num_setToZero(n, 0);
1390 n->len = 1;
1391 n->num[0] = 1;
1392}
1393
1394static void bc_num_ten(BcNum *n)
1395{
1396 bc_num_setToZero(n, 0);
1397 n->len = 2;
1398 n->num[0] = 0;
1399 n->num[1] = 1;
1400}
1401
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001402static void bc_num_init(BcNum *n, size_t req)
1403{
1404 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1405 memset(n, 0, sizeof(BcNum));
1406 n->num = xmalloc(req);
1407 n->cap = req;
1408}
1409
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01001410static void bc_num_init_DEF_SIZE(BcNum *n)
1411{
1412 bc_num_init(n, BC_NUM_DEF_SIZE);
1413}
1414
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001415static void bc_num_expand(BcNum *n, size_t req)
1416{
1417 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1418 if (req > n->cap) {
1419 n->num = xrealloc(n->num, req);
1420 n->cap = req;
1421 }
1422}
1423
1424static void bc_num_free(void *num)
1425{
1426 free(((BcNum *) num)->num);
1427}
1428
1429static void bc_num_copy(BcNum *d, BcNum *s)
1430{
1431 if (d != s) {
1432 bc_num_expand(d, s->cap);
1433 d->len = s->len;
1434 d->neg = s->neg;
1435 d->rdx = s->rdx;
1436 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
1437 }
1438}
1439
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001440static BcStatus bc_num_ulong(BcNum *n, unsigned long *result_p)
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001441{
1442 size_t i;
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001443 unsigned long pow, result;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001444
1445 if (n->neg) return bc_error("negative number");
1446
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001447 for (result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001448
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001449 unsigned long prev = result, powprev = pow;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001450
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001451 result += ((unsigned long) n->num[i]) * pow;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001452 pow *= 10;
1453
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001454 if (result < prev || pow < powprev)
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001455 return bc_error("overflow");
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001456 prev = result;
1457 powprev = pow;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001458 }
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001459 *result_p = result;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001460
1461 return BC_STATUS_SUCCESS;
1462}
1463
1464static void bc_num_ulong2num(BcNum *n, unsigned long val)
1465{
1466 size_t len;
1467 BcDig *ptr;
1468 unsigned long i;
1469
1470 bc_num_zero(n);
1471
1472 if (val == 0) return;
1473
1474 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
1475 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
1476}
1477
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001478static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001479 size_t len)
1480{
1481 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001482 for (i = 0; i < len; ++i) {
1483 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001484 a[i + j++] += 10;
1485 a[i + j] -= 1;
1486 }
1487 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001488}
1489
Denys Vlasenko2d615fe2018-12-07 16:22:45 +01001490#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
1491#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
1492#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
1493//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
1494static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
1495{
1496 return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
1497}
1498//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
1499static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
1500{
1501 return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
1502}
1503
Gavin Howard01055ba2018-11-03 11:00:21 -06001504static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1505{
1506 size_t i;
1507 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001508 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001509 return BC_NUM_NEG(i + 1, c < 0);
1510}
1511
1512static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1513{
1514 size_t i, min, a_int, b_int, diff;
1515 BcDig *max_num, *min_num;
1516 bool a_max, neg = false;
1517 ssize_t cmp;
1518
1519 if (a == b) return 0;
1520 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1521 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1522 if (a->neg) {
1523 if (b->neg)
1524 neg = true;
1525 else
1526 return -1;
1527 }
1528 else if (b->neg)
1529 return 1;
1530
1531 a_int = BC_NUM_INT(a);
1532 b_int = BC_NUM_INT(b);
1533 a_int -= b_int;
1534 a_max = (a->rdx > b->rdx);
1535
1536 if (a_int != 0) return (ssize_t) a_int;
1537
1538 if (a_max) {
1539 min = b->rdx;
1540 diff = a->rdx - b->rdx;
1541 max_num = a->num + diff;
1542 min_num = b->num;
1543 }
1544 else {
1545 min = a->rdx;
1546 diff = b->rdx - a->rdx;
1547 max_num = b->num + diff;
1548 min_num = a->num;
1549 }
1550
1551 cmp = bc_num_compare(max_num, min_num, b_int + min);
1552 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1553
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001554 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001555 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1556 }
1557
1558 return 0;
1559}
1560
1561static void bc_num_truncate(BcNum *n, size_t places)
1562{
1563 if (places == 0) return;
1564
1565 n->rdx -= places;
1566
1567 if (n->len != 0) {
1568 n->len -= places;
1569 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1570 }
1571}
1572
1573static void bc_num_extend(BcNum *n, size_t places)
1574{
1575 size_t len = n->len + places;
1576
1577 if (places != 0) {
1578
1579 if (n->cap < len) bc_num_expand(n, len);
1580
1581 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1582 memset(n->num, 0, sizeof(BcDig) * places);
1583
1584 n->len += places;
1585 n->rdx += places;
1586 }
1587}
1588
1589static void bc_num_clean(BcNum *n)
1590{
1591 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1592 if (n->len == 0)
1593 n->neg = false;
1594 else if (n->len < n->rdx)
1595 n->len = n->rdx;
1596}
1597
1598static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1599{
1600 if (n->rdx < scale)
1601 bc_num_extend(n, scale - n->rdx);
1602 else
1603 bc_num_truncate(n, n->rdx - scale);
1604
1605 bc_num_clean(n);
1606 if (n->len != 0) n->neg = !neg1 != !neg2;
1607}
1608
1609static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1610 BcNum *restrict b)
1611{
1612 if (idx < n->len) {
1613
1614 b->len = n->len - idx;
1615 a->len = idx;
1616 a->rdx = b->rdx = 0;
1617
1618 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1619 memcpy(a->num, n->num, idx * sizeof(BcDig));
1620 }
1621 else {
1622 bc_num_zero(b);
1623 bc_num_copy(a, n);
1624 }
1625
1626 bc_num_clean(a);
1627 bc_num_clean(b);
1628}
1629
1630static BcStatus bc_num_shift(BcNum *n, size_t places)
1631{
1632 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko64074a12018-12-07 15:50:14 +01001633
1634 // This check makes sense only if size_t is (much) larger than BC_MAX_NUM.
1635 if (SIZE_MAX > (BC_MAX_NUM | 0xff)) {
1636 if (places + n->len > BC_MAX_NUM)
1637 return bc_error("number too long: must be [1,"BC_MAX_NUM_STR"]");
1638 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001639
1640 if (n->rdx >= places)
1641 n->rdx -= places;
1642 else {
1643 bc_num_extend(n, places - n->rdx);
1644 n->rdx = 0;
1645 }
1646
1647 bc_num_clean(n);
1648
1649 return BC_STATUS_SUCCESS;
1650}
1651
1652static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1653{
1654 BcNum one;
1655 BcDig num[2];
1656
1657 one.cap = 2;
1658 one.num = num;
1659 bc_num_one(&one);
1660
1661 return bc_num_div(&one, a, b, scale);
1662}
1663
1664static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1665{
1666 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1667 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1668 int carry, in;
1669
1670 // Because this function doesn't need to use scale (per the bc spec),
1671 // I am hijacking it to say whether it's doing an add or a subtract.
1672
1673 if (a->len == 0) {
1674 bc_num_copy(c, b);
1675 if (sub && c->len) c->neg = !c->neg;
1676 return BC_STATUS_SUCCESS;
1677 }
1678 else if (b->len == 0) {
1679 bc_num_copy(c, a);
1680 return BC_STATUS_SUCCESS;
1681 }
1682
1683 c->neg = a->neg;
1684 c->rdx = BC_MAX(a->rdx, b->rdx);
1685 min_rdx = BC_MIN(a->rdx, b->rdx);
1686 c->len = 0;
1687
1688 if (a->rdx > b->rdx) {
1689 diff = a->rdx - b->rdx;
1690 ptr = a->num;
1691 ptr_a = a->num + diff;
1692 ptr_b = b->num;
1693 }
1694 else {
1695 diff = b->rdx - a->rdx;
1696 ptr = b->num;
1697 ptr_a = a->num;
1698 ptr_b = b->num + diff;
1699 }
1700
1701 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1702
1703 ptr_c += diff;
1704 a_int = BC_NUM_INT(a);
1705 b_int = BC_NUM_INT(b);
1706
1707 if (a_int > b_int) {
1708 min_int = b_int;
1709 max = a_int;
1710 ptr = ptr_a;
1711 }
1712 else {
1713 min_int = a_int;
1714 max = b_int;
1715 ptr = ptr_b;
1716 }
1717
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001718 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001719 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1720 carry = in / 10;
1721 ptr_c[i] = (BcDig)(in % 10);
1722 }
1723
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001724 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001725 in = ((int) ptr[i]) + carry;
1726 carry = in / 10;
1727 ptr_c[i] = (BcDig)(in % 10);
1728 }
1729
1730 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1731
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001732 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001733}
1734
1735static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1736{
Gavin Howard01055ba2018-11-03 11:00:21 -06001737 ssize_t cmp;
1738 BcNum *minuend, *subtrahend;
1739 size_t start;
1740 bool aneg, bneg, neg;
1741
1742 // Because this function doesn't need to use scale (per the bc spec),
1743 // I am hijacking it to say whether it's doing an add or a subtract.
1744
1745 if (a->len == 0) {
1746 bc_num_copy(c, b);
1747 if (sub && c->len) c->neg = !c->neg;
1748 return BC_STATUS_SUCCESS;
1749 }
1750 else if (b->len == 0) {
1751 bc_num_copy(c, a);
1752 return BC_STATUS_SUCCESS;
1753 }
1754
1755 aneg = a->neg;
1756 bneg = b->neg;
1757 a->neg = b->neg = false;
1758
1759 cmp = bc_num_cmp(a, b);
1760
1761 a->neg = aneg;
1762 b->neg = bneg;
1763
1764 if (cmp == 0) {
1765 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1766 return BC_STATUS_SUCCESS;
1767 }
1768 else if (cmp > 0) {
1769 neg = a->neg;
1770 minuend = a;
1771 subtrahend = b;
1772 }
1773 else {
1774 neg = b->neg;
1775 if (sub) neg = !neg;
1776 minuend = b;
1777 subtrahend = a;
1778 }
1779
1780 bc_num_copy(c, minuend);
1781 c->neg = neg;
1782
1783 if (c->rdx < subtrahend->rdx) {
1784 bc_num_extend(c, subtrahend->rdx - c->rdx);
1785 start = 0;
1786 }
1787 else
1788 start = c->rdx - subtrahend->rdx;
1789
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001790 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001791
1792 bc_num_clean(c);
1793
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001794 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001795}
1796
1797static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1798 BcNum *restrict c)
1799{
1800 BcStatus s;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001801 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
Gavin Howard01055ba2018-11-03 11:00:21 -06001802 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001803 bool aone;
Gavin Howard01055ba2018-11-03 11:00:21 -06001804
Gavin Howard01055ba2018-11-03 11:00:21 -06001805 if (a->len == 0 || b->len == 0) {
1806 bc_num_zero(c);
1807 return BC_STATUS_SUCCESS;
1808 }
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001809 aone = BC_NUM_ONE(a);
1810 if (aone || BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001811 bc_num_copy(c, aone ? b : a);
1812 return BC_STATUS_SUCCESS;
1813 }
1814
1815 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1816 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1817 {
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001818 size_t i, j, len;
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001819 unsigned carry;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001820
Gavin Howard01055ba2018-11-03 11:00:21 -06001821 bc_num_expand(c, a->len + b->len + 1);
1822
1823 memset(c->num, 0, sizeof(BcDig) * c->cap);
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001824 c->len = len = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06001825
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001826 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001827
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001828 carry = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001829 for (j = 0; j < a->len; ++j) {
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001830 unsigned in = c->num[i + j];
1831 in += ((unsigned) a->num[j]) * ((unsigned) b->num[i]) + carry;
1832 // note: compilers prefer _unsigned_ div/const
Gavin Howard01055ba2018-11-03 11:00:21 -06001833 carry = in / 10;
1834 c->num[i + j] = (BcDig)(in % 10);
1835 }
1836
1837 c->num[i + j] += (BcDig) carry;
1838 len = BC_MAX(len, i + j + !!carry);
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01001839
1840 // a=2^1000000
1841 // a*a <- without check below, this will not be interruptible
1842 if (G_interrupt) return BC_STATUS_FAILURE;
Gavin Howard01055ba2018-11-03 11:00:21 -06001843 }
1844
1845 c->len = len;
1846
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001847 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001848 }
1849
1850 bc_num_init(&l1, max);
1851 bc_num_init(&h1, max);
1852 bc_num_init(&l2, max);
1853 bc_num_init(&h2, max);
1854 bc_num_init(&m1, max);
1855 bc_num_init(&m2, max);
1856 bc_num_init(&z0, max);
1857 bc_num_init(&z1, max);
1858 bc_num_init(&z2, max);
1859 bc_num_init(&temp, max + max);
1860
1861 bc_num_split(a, max2, &l1, &h1);
1862 bc_num_split(b, max2, &l2, &h2);
1863
1864 s = bc_num_add(&h1, &l1, &m1, 0);
1865 if (s) goto err;
1866 s = bc_num_add(&h2, &l2, &m2, 0);
1867 if (s) goto err;
1868
1869 s = bc_num_k(&h1, &h2, &z0);
1870 if (s) goto err;
1871 s = bc_num_k(&m1, &m2, &z1);
1872 if (s) goto err;
1873 s = bc_num_k(&l1, &l2, &z2);
1874 if (s) goto err;
1875
1876 s = bc_num_sub(&z1, &z0, &temp, 0);
1877 if (s) goto err;
1878 s = bc_num_sub(&temp, &z2, &z1, 0);
1879 if (s) goto err;
1880
1881 s = bc_num_shift(&z0, max2 * 2);
1882 if (s) goto err;
1883 s = bc_num_shift(&z1, max2);
1884 if (s) goto err;
1885 s = bc_num_add(&z0, &z1, &temp, 0);
1886 if (s) goto err;
1887 s = bc_num_add(&temp, &z2, c, 0);
1888
1889err:
1890 bc_num_free(&temp);
1891 bc_num_free(&z2);
1892 bc_num_free(&z1);
1893 bc_num_free(&z0);
1894 bc_num_free(&m2);
1895 bc_num_free(&m1);
1896 bc_num_free(&h2);
1897 bc_num_free(&l2);
1898 bc_num_free(&h1);
1899 bc_num_free(&l1);
1900 return s;
1901}
1902
1903static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1904{
1905 BcStatus s;
1906 BcNum cpa, cpb;
1907 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1908
1909 scale = BC_MAX(scale, a->rdx);
1910 scale = BC_MAX(scale, b->rdx);
1911 scale = BC_MIN(a->rdx + b->rdx, scale);
1912 maxrdx = BC_MAX(maxrdx, scale);
1913
1914 bc_num_init(&cpa, a->len);
1915 bc_num_init(&cpb, b->len);
1916
1917 bc_num_copy(&cpa, a);
1918 bc_num_copy(&cpb, b);
1919 cpa.neg = cpb.neg = false;
1920
1921 s = bc_num_shift(&cpa, maxrdx);
1922 if (s) goto err;
1923 s = bc_num_shift(&cpb, maxrdx);
1924 if (s) goto err;
1925 s = bc_num_k(&cpa, &cpb, c);
1926 if (s) goto err;
1927
1928 maxrdx += scale;
1929 bc_num_expand(c, c->len + maxrdx);
1930
1931 if (c->len < maxrdx) {
1932 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1933 c->len += maxrdx;
1934 }
1935
1936 c->rdx = maxrdx;
1937 bc_num_retireMul(c, scale, a->neg, b->neg);
1938
1939err:
1940 bc_num_free(&cpb);
1941 bc_num_free(&cpa);
1942 return s;
1943}
1944
1945static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1946{
1947 BcStatus s = BC_STATUS_SUCCESS;
1948 BcDig *n, *p, q;
1949 size_t len, end, i;
1950 BcNum cp;
1951 bool zero = true;
1952
1953 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001954 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001955 else if (a->len == 0) {
1956 bc_num_setToZero(c, scale);
1957 return BC_STATUS_SUCCESS;
1958 }
1959 else if (BC_NUM_ONE(b)) {
1960 bc_num_copy(c, a);
1961 bc_num_retireMul(c, scale, a->neg, b->neg);
1962 return BC_STATUS_SUCCESS;
1963 }
1964
1965 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1966 bc_num_copy(&cp, a);
1967 len = b->len;
1968
1969 if (len > cp.len) {
1970 bc_num_expand(&cp, len + 2);
1971 bc_num_extend(&cp, len - cp.len);
1972 }
1973
1974 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1975 cp.rdx -= b->rdx;
1976 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1977
1978 if (b->rdx == b->len) {
1979 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1980 len -= i - 1;
1981 }
1982
1983 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1984
1985 // We want an extra zero in front to make things simpler.
1986 cp.num[cp.len++] = 0;
1987 end = cp.len - len;
1988
1989 bc_num_expand(c, cp.len);
1990
1991 bc_num_zero(c);
1992 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1993 c->rdx = cp.rdx;
1994 c->len = cp.len;
1995 p = b->num;
1996
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001997 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001998 n = cp.num + i;
1999 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002000 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06002001 c->num[i] = q;
Denys Vlasenkof381a882018-12-05 19:21:34 +01002002 // a=2^100000
2003 // scale=40000
2004 // 1/a <- without check below, this will not be interruptible
2005 if (G_interrupt) {
2006 s = BC_STATUS_FAILURE;
2007 break;
2008 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002009 }
2010
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002011 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06002012 bc_num_free(&cp);
2013
Denys Vlasenkof381a882018-12-05 19:21:34 +01002014 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06002015}
2016
2017static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
2018 BcNum *restrict d, size_t scale, size_t ts)
2019{
2020 BcStatus s;
2021 BcNum temp;
2022 bool neg;
2023
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002024 if (b->len == 0)
2025 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06002026
2027 if (a->len == 0) {
2028 bc_num_setToZero(d, ts);
2029 return BC_STATUS_SUCCESS;
2030 }
2031
2032 bc_num_init(&temp, d->cap);
Denys Vlasenkof381a882018-12-05 19:21:34 +01002033 s = bc_num_d(a, b, c, scale);
2034 if (s) goto err;
Gavin Howard01055ba2018-11-03 11:00:21 -06002035
2036 if (scale != 0) scale = ts;
2037
2038 s = bc_num_m(c, b, &temp, scale);
2039 if (s) goto err;
2040 s = bc_num_sub(a, &temp, d, scale);
2041 if (s) goto err;
2042
2043 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2044
2045 neg = d->neg;
2046 bc_num_retireMul(d, ts, a->neg, b->neg);
2047 d->neg = neg;
2048
2049err:
2050 bc_num_free(&temp);
2051 return s;
2052}
2053
2054static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2055{
2056 BcStatus s;
2057 BcNum c1;
2058 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2059
2060 bc_num_init(&c1, len);
2061 s = bc_num_r(a, b, &c1, c, scale, ts);
2062 bc_num_free(&c1);
2063
2064 return s;
2065}
2066
2067static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2068{
2069 BcStatus s = BC_STATUS_SUCCESS;
2070 BcNum copy;
2071 unsigned long pow;
2072 size_t i, powrdx, resrdx;
2073 bool neg, zero;
2074
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002075 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002076
2077 if (b->len == 0) {
2078 bc_num_one(c);
2079 return BC_STATUS_SUCCESS;
2080 }
2081 else if (a->len == 0) {
2082 bc_num_setToZero(c, scale);
2083 return BC_STATUS_SUCCESS;
2084 }
2085 else if (BC_NUM_ONE(b)) {
2086 if (!b->neg)
2087 bc_num_copy(c, a);
2088 else
2089 s = bc_num_inv(a, c, scale);
2090 return s;
2091 }
2092
2093 neg = b->neg;
2094 b->neg = false;
2095
2096 s = bc_num_ulong(b, &pow);
2097 if (s) return s;
2098
2099 bc_num_init(&copy, a->len);
2100 bc_num_copy(&copy, a);
2101
Denys Vlasenko2d615fe2018-12-07 16:22:45 +01002102 if (!neg) {
2103 if (a->rdx > scale)
2104 scale = a->rdx;
2105 if (a->rdx * pow < scale)
2106 scale = a->rdx * pow;
2107 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002108
2109 b->neg = neg;
2110
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002111 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002112 powrdx <<= 1;
2113 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2114 if (s) goto err;
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002115 // Not needed: bc_num_mul() has a check for ^C:
2116 //if (G_interrupt) {
2117 // s = BC_STATUS_FAILURE;
2118 // goto err;
2119 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002120 }
2121
Gavin Howard01055ba2018-11-03 11:00:21 -06002122 bc_num_copy(c, &copy);
2123
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002124 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002125
2126 powrdx <<= 1;
2127 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2128 if (s) goto err;
2129
2130 if (pow & 1) {
2131 resrdx += powrdx;
2132 s = bc_num_mul(c, &copy, c, resrdx);
2133 if (s) goto err;
2134 }
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002135 // Not needed: bc_num_mul() has a check for ^C:
2136 //if (G_interrupt) {
2137 // s = BC_STATUS_FAILURE;
2138 // goto err;
2139 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002140 }
2141
2142 if (neg) {
2143 s = bc_num_inv(c, c, scale);
2144 if (s) goto err;
2145 }
2146
Gavin Howard01055ba2018-11-03 11:00:21 -06002147 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2148
2149 // We can't use bc_num_clean() here.
2150 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2151 if (zero) bc_num_setToZero(c, scale);
2152
2153err:
2154 bc_num_free(&copy);
2155 return s;
2156}
2157
2158static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2159 BcNumBinaryOp op, size_t req)
2160{
2161 BcStatus s;
2162 BcNum num2, *ptr_a, *ptr_b;
2163 bool init = false;
2164
2165 if (c == a) {
2166 ptr_a = &num2;
2167 memcpy(ptr_a, c, sizeof(BcNum));
2168 init = true;
2169 }
2170 else
2171 ptr_a = a;
2172
2173 if (c == b) {
2174 ptr_b = &num2;
2175 if (c != a) {
2176 memcpy(ptr_b, c, sizeof(BcNum));
2177 init = true;
2178 }
2179 }
2180 else
2181 ptr_b = b;
2182
2183 if (init)
2184 bc_num_init(c, req);
2185 else
2186 bc_num_expand(c, req);
2187
2188 s = op(ptr_a, ptr_b, c, scale);
2189
2190 if (init) bc_num_free(&num2);
2191
2192 return s;
2193}
2194
2195static bool bc_num_strValid(const char *val, size_t base)
2196{
2197 BcDig b;
2198 bool small, radix = false;
2199 size_t i, len = strlen(val);
2200
2201 if (!len) return true;
2202
2203 small = base <= 10;
2204 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2205
2206 for (i = 0; i < len; ++i) {
2207
2208 BcDig c = val[i];
2209
2210 if (c == '.') {
2211
2212 if (radix) return false;
2213
2214 radix = true;
2215 continue;
2216 }
2217
2218 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2219 return false;
2220 }
2221
2222 return true;
2223}
2224
2225static void bc_num_parseDecimal(BcNum *n, const char *val)
2226{
2227 size_t len, i;
2228 const char *ptr;
2229 bool zero = true;
2230
2231 for (i = 0; val[i] == '0'; ++i);
2232
2233 val += i;
2234 len = strlen(val);
2235 bc_num_zero(n);
2236
2237 if (len != 0) {
2238 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2239 bc_num_expand(n, len);
2240 }
2241
2242 ptr = strchr(val, '.');
2243
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002244 n->rdx = 0;
2245 if (ptr != NULL)
2246 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002247
2248 if (!zero) {
2249 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2250 n->num[n->len] = val[i] - '0';
2251 }
2252}
2253
2254static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2255{
2256 BcStatus s;
2257 BcNum temp, mult, result;
2258 BcDig c = '\0';
2259 bool zero = true;
2260 unsigned long v;
2261 size_t i, digits, len = strlen(val);
2262
2263 bc_num_zero(n);
2264
2265 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2266 if (zero) return;
2267
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01002268 bc_num_init_DEF_SIZE(&temp);
2269 bc_num_init_DEF_SIZE(&mult);
Gavin Howard01055ba2018-11-03 11:00:21 -06002270
2271 for (i = 0; i < len; ++i) {
2272
2273 c = val[i];
2274 if (c == '.') break;
2275
2276 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2277
2278 s = bc_num_mul(n, base, &mult, 0);
2279 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002280 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002281 s = bc_num_add(&mult, &temp, n, 0);
2282 if (s) goto int_err;
2283 }
2284
2285 if (i == len) {
2286 c = val[i];
2287 if (c == 0) goto int_err;
2288 }
2289
2290 bc_num_init(&result, base->len);
2291 bc_num_zero(&result);
2292 bc_num_one(&mult);
2293
2294 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2295
2296 c = val[i];
2297 if (c == 0) break;
2298
2299 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2300
2301 s = bc_num_mul(&result, base, &result, 0);
2302 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002303 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002304 s = bc_num_add(&result, &temp, &result, 0);
2305 if (s) goto err;
2306 s = bc_num_mul(&mult, base, &mult, 0);
2307 if (s) goto err;
2308 }
2309
2310 s = bc_num_div(&result, &mult, &result, digits);
2311 if (s) goto err;
2312 s = bc_num_add(n, &result, n, digits);
2313 if (s) goto err;
2314
2315 if (n->len != 0) {
2316 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2317 }
2318 else
2319 bc_num_zero(n);
2320
2321err:
2322 bc_num_free(&result);
2323int_err:
2324 bc_num_free(&mult);
2325 bc_num_free(&temp);
2326}
2327
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002328static void bc_num_printNewline(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06002329{
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002330 if (G.prog.nchars == G.prog.len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002331 bb_putchar('\\');
2332 bb_putchar('\n');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002333 G.prog.nchars = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06002334 }
2335}
2336
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002337#if ENABLE_DC
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002338static void bc_num_printChar(size_t num, size_t width, bool radix)
Gavin Howard01055ba2018-11-03 11:00:21 -06002339{
Denys Vlasenko2a8ad482018-12-08 21:56:37 +01002340 (void) radix;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002341 bb_putchar((char) num);
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002342 G.prog.nchars += width;
Gavin Howard01055ba2018-11-03 11:00:21 -06002343}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002344#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002345
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002346static void bc_num_printDigits(size_t num, size_t width, bool radix)
Gavin Howard01055ba2018-11-03 11:00:21 -06002347{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002348 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002349
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002350 bc_num_printNewline();
Denys Vlasenko00d77792018-11-30 23:13:42 +01002351 bb_putchar(radix ? '.' : ' ');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002352 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06002353
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002354 bc_num_printNewline();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002355 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2356 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002357
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002358 for (exp = 0; exp < width; pow /= 10, ++G.prog.nchars, ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002359 size_t dig;
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002360 bc_num_printNewline();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002361 dig = num / pow;
2362 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002363 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002364 }
2365}
2366
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002367static void bc_num_printHex(size_t num, size_t width, bool radix)
Gavin Howard01055ba2018-11-03 11:00:21 -06002368{
2369 if (radix) {
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002370 bc_num_printNewline();
Denys Vlasenko00d77792018-11-30 23:13:42 +01002371 bb_putchar('.');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002372 G.prog.nchars += 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002373 }
2374
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002375 bc_num_printNewline();
Denys Vlasenko00d77792018-11-30 23:13:42 +01002376 bb_putchar(bb_hexdigits_upcase[num]);
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002377 G.prog.nchars += width;
Gavin Howard01055ba2018-11-03 11:00:21 -06002378}
2379
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002380static void bc_num_printDecimal(BcNum *n)
Gavin Howard01055ba2018-11-03 11:00:21 -06002381{
2382 size_t i, rdx = n->rdx - 1;
2383
Denys Vlasenko00d77792018-11-30 23:13:42 +01002384 if (n->neg) bb_putchar('-');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002385 G.prog.nchars += n->neg;
Gavin Howard01055ba2018-11-03 11:00:21 -06002386
2387 for (i = n->len - 1; i < n->len; --i)
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002388 bc_num_printHex((size_t) n->num[i], 1, i == rdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002389}
2390
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002391static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width, BcNumDigitOp print)
Gavin Howard01055ba2018-11-03 11:00:21 -06002392{
2393 BcStatus s;
2394 BcVec stack;
2395 BcNum intp, fracp, digit, frac_len;
2396 unsigned long dig, *ptr;
2397 size_t i;
2398 bool radix;
2399
2400 if (n->len == 0) {
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002401 print(0, width, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06002402 return BC_STATUS_SUCCESS;
2403 }
2404
2405 bc_vec_init(&stack, sizeof(long), NULL);
2406 bc_num_init(&intp, n->len);
2407 bc_num_init(&fracp, n->rdx);
2408 bc_num_init(&digit, width);
2409 bc_num_init(&frac_len, BC_NUM_INT(n));
2410 bc_num_copy(&intp, n);
2411 bc_num_one(&frac_len);
2412
2413 bc_num_truncate(&intp, intp.rdx);
2414 s = bc_num_sub(n, &intp, &fracp, 0);
2415 if (s) goto err;
2416
2417 while (intp.len != 0) {
2418 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2419 if (s) goto err;
2420 s = bc_num_ulong(&digit, &dig);
2421 if (s) goto err;
2422 bc_vec_push(&stack, &dig);
2423 }
2424
2425 for (i = 0; i < stack.len; ++i) {
2426 ptr = bc_vec_item_rev(&stack, i);
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002427 print(*ptr, width, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06002428 }
2429
2430 if (!n->rdx) goto err;
2431
2432 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2433 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2434 if (s) goto err;
2435 s = bc_num_ulong(&fracp, &dig);
2436 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002437 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002438 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2439 if (s) goto err;
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002440 print(dig, width, radix);
Gavin Howard01055ba2018-11-03 11:00:21 -06002441 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2442 if (s) goto err;
2443 }
2444
2445err:
2446 bc_num_free(&frac_len);
2447 bc_num_free(&digit);
2448 bc_num_free(&fracp);
2449 bc_num_free(&intp);
2450 bc_vec_free(&stack);
2451 return s;
2452}
2453
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002454static BcStatus bc_num_printBase(BcNum *n)
Gavin Howard01055ba2018-11-03 11:00:21 -06002455{
2456 BcStatus s;
2457 size_t width, i;
2458 BcNumDigitOp print;
2459 bool neg = n->neg;
2460
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002461 if (neg) {
2462 bb_putchar('-');
2463 G.prog.nchars++;
2464 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002465
2466 n->neg = false;
2467
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002468 if (G.prog.ob_t <= BC_NUM_MAX_IBASE) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002469 width = 1;
2470 print = bc_num_printHex;
2471 }
2472 else {
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002473 for (i = G.prog.ob_t - 1, width = 0; i != 0; i /= 10, ++width)
2474 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002475 print = bc_num_printDigits;
2476 }
2477
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002478 s = bc_num_printNum(n, &G.prog.ob, width, print);
Gavin Howard01055ba2018-11-03 11:00:21 -06002479 n->neg = neg;
2480
2481 return s;
2482}
2483
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002484#if ENABLE_DC
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002485static BcStatus bc_num_stream(BcNum *n, BcNum *base)
Gavin Howard01055ba2018-11-03 11:00:21 -06002486{
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002487 return bc_num_printNum(n, base, 1, bc_num_printChar);
Gavin Howard01055ba2018-11-03 11:00:21 -06002488}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002489#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002490
Gavin Howard01055ba2018-11-03 11:00:21 -06002491static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2492 size_t base_t)
2493{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002494 if (!bc_num_strValid(val, base_t))
2495 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002496
2497 if (base_t == 10)
2498 bc_num_parseDecimal(n, val);
2499 else
2500 bc_num_parseBase(n, val, base);
2501
2502 return BC_STATUS_SUCCESS;
2503}
2504
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002505static BcStatus bc_num_print(BcNum *n, bool newline)
Gavin Howard01055ba2018-11-03 11:00:21 -06002506{
2507 BcStatus s = BC_STATUS_SUCCESS;
2508
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002509 bc_num_printNewline();
Gavin Howard01055ba2018-11-03 11:00:21 -06002510
2511 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002512 bb_putchar('0');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002513 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06002514 }
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002515 else if (G.prog.ob_t == 10)
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002516 bc_num_printDecimal(n);
Gavin Howard01055ba2018-11-03 11:00:21 -06002517 else
Denys Vlasenko0f37b322018-12-08 23:48:53 +01002518 s = bc_num_printBase(n);
Gavin Howard01055ba2018-11-03 11:00:21 -06002519
2520 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002521 bb_putchar('\n');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01002522 G.prog.nchars = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06002523 }
2524
2525 return s;
2526}
2527
Gavin Howard01055ba2018-11-03 11:00:21 -06002528static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2529{
2530 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2531 (void) scale;
2532 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2533}
2534
2535static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2536{
2537 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2538 (void) scale;
2539 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2540}
2541
2542static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2543{
2544 size_t req = BC_NUM_MREQ(a, b, scale);
2545 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2546}
2547
2548static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2549{
2550 size_t req = BC_NUM_MREQ(a, b, scale);
2551 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2552}
2553
2554static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2555{
2556 size_t req = BC_NUM_MREQ(a, b, scale);
2557 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2558}
2559
2560static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2561{
2562 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2563}
2564
2565static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2566{
2567 BcStatus s;
2568 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2569 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2570 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2571
2572 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2573 bc_num_expand(b, req);
2574
2575 if (a->len == 0) {
2576 bc_num_setToZero(b, scale);
2577 return BC_STATUS_SUCCESS;
2578 }
2579 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002580 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002581 else if (BC_NUM_ONE(a)) {
2582 bc_num_one(b);
2583 bc_num_extend(b, scale);
2584 return BC_STATUS_SUCCESS;
2585 }
2586
2587 scale = BC_MAX(scale, a->rdx) + 1;
2588 len = a->len + scale;
2589
2590 bc_num_init(&num1, len);
2591 bc_num_init(&num2, len);
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01002592 bc_num_init_DEF_SIZE(&half);
Gavin Howard01055ba2018-11-03 11:00:21 -06002593
2594 bc_num_one(&half);
2595 half.num[0] = 5;
2596 half.rdx = 1;
2597
2598 bc_num_init(&f, len);
2599 bc_num_init(&fprime, len);
2600
2601 x0 = &num1;
2602 x1 = &num2;
2603
2604 bc_num_one(x0);
2605 pow = BC_NUM_INT(a);
2606
2607 if (pow) {
2608
2609 if (pow & 1)
2610 x0->num[0] = 2;
2611 else
2612 x0->num[0] = 6;
2613
2614 pow -= 2 - (pow & 1);
2615
2616 bc_num_extend(x0, pow);
2617
2618 // Make sure to move the radix back.
2619 x0->rdx -= pow;
2620 }
2621
2622 x0->rdx = digs = digs1 = 0;
2623 resrdx = scale + 2;
2624 len = BC_NUM_INT(x0) + resrdx - 1;
2625
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002626 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002627
2628 s = bc_num_div(a, x0, &f, resrdx);
2629 if (s) goto err;
2630 s = bc_num_add(x0, &f, &fprime, resrdx);
2631 if (s) goto err;
2632 s = bc_num_mul(&fprime, &half, x1, resrdx);
2633 if (s) goto err;
2634
2635 cmp = bc_num_cmp(x1, x0);
2636 digs = x1->len - (unsigned long long) llabs(cmp);
2637
2638 if (cmp == cmp2 && digs == digs1)
2639 times += 1;
2640 else
2641 times = 0;
2642
2643 resrdx += times > 4;
2644
2645 cmp2 = cmp1;
2646 cmp1 = cmp;
2647 digs1 = digs;
2648
2649 temp = x0;
2650 x0 = x1;
2651 x1 = temp;
2652 }
2653
Gavin Howard01055ba2018-11-03 11:00:21 -06002654 bc_num_copy(b, x0);
2655 scale -= 1;
2656 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2657
2658err:
2659 bc_num_free(&fprime);
2660 bc_num_free(&f);
2661 bc_num_free(&half);
2662 bc_num_free(&num2);
2663 bc_num_free(&num1);
2664 return s;
2665}
2666
2667static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2668 size_t scale)
2669{
2670 BcStatus s;
2671 BcNum num2, *ptr_a;
2672 bool init = false;
2673 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2674
2675 if (c == a) {
2676 memcpy(&num2, c, sizeof(BcNum));
2677 ptr_a = &num2;
2678 bc_num_init(c, len);
2679 init = true;
2680 }
2681 else {
2682 ptr_a = a;
2683 bc_num_expand(c, len);
2684 }
2685
2686 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2687
2688 if (init) bc_num_free(&num2);
2689
2690 return s;
2691}
2692
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002693#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002694static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2695{
2696 BcStatus s;
2697 BcNum base, exp, two, temp;
2698
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002699 if (c->len == 0)
2700 return bc_error("divide by zero");
2701 if (a->rdx || b->rdx || c->rdx)
2702 return bc_error("non integer number");
2703 if (b->neg)
2704 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002705
2706 bc_num_expand(d, c->len);
2707 bc_num_init(&base, c->len);
2708 bc_num_init(&exp, b->len);
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01002709 bc_num_init_DEF_SIZE(&two);
Gavin Howard01055ba2018-11-03 11:00:21 -06002710 bc_num_init(&temp, b->len);
2711
2712 bc_num_one(&two);
2713 two.num[0] = 2;
2714 bc_num_one(d);
2715
2716 s = bc_num_rem(a, c, &base, 0);
2717 if (s) goto err;
2718 bc_num_copy(&exp, b);
2719
2720 while (exp.len != 0) {
2721
2722 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2723 if (s) goto err;
2724
2725 if (BC_NUM_ONE(&temp)) {
2726 s = bc_num_mul(d, &base, &temp, 0);
2727 if (s) goto err;
2728 s = bc_num_rem(&temp, c, d, 0);
2729 if (s) goto err;
2730 }
2731
2732 s = bc_num_mul(&base, &base, &temp, 0);
2733 if (s) goto err;
2734 s = bc_num_rem(&temp, c, &base, 0);
2735 if (s) goto err;
2736 }
2737
2738err:
2739 bc_num_free(&temp);
2740 bc_num_free(&two);
2741 bc_num_free(&exp);
2742 bc_num_free(&base);
2743 return s;
2744}
2745#endif // ENABLE_DC
2746
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01002747#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002748static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2749{
2750 BcId a;
2751 size_t i;
2752
2753 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002754 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2755 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002756 }
2757
2758 a.idx = var;
2759 a.name = name;
2760
2761 bc_vec_push(&f->autos, &a);
2762
2763 return BC_STATUS_SUCCESS;
2764}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01002765#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002766
2767static void bc_func_init(BcFunc *f)
2768{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002769 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002770 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2771 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2772 f->nparams = 0;
2773}
2774
2775static void bc_func_free(void *func)
2776{
2777 BcFunc *f = (BcFunc *) func;
2778 bc_vec_free(&f->code);
2779 bc_vec_free(&f->autos);
2780 bc_vec_free(&f->labels);
2781}
2782
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002783static void bc_array_expand(BcVec *a, size_t len);
2784
Gavin Howard01055ba2018-11-03 11:00:21 -06002785static void bc_array_init(BcVec *a, bool nums)
2786{
2787 if (nums)
2788 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2789 else
2790 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2791 bc_array_expand(a, 1);
2792}
2793
Gavin Howard01055ba2018-11-03 11:00:21 -06002794static void bc_array_expand(BcVec *a, size_t len)
2795{
2796 BcResultData data;
2797
2798 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2799 while (len > a->len) {
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01002800 bc_num_init_DEF_SIZE(&data.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06002801 bc_vec_push(a, &data.n);
2802 }
2803 }
2804 else {
2805 while (len > a->len) {
2806 bc_array_init(&data.v, true);
2807 bc_vec_push(a, &data.v);
2808 }
2809 }
2810}
2811
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002812static void bc_array_copy(BcVec *d, const BcVec *s)
2813{
2814 size_t i;
2815
2816 bc_vec_pop_all(d);
2817 bc_vec_expand(d, s->cap);
2818 d->len = s->len;
2819
2820 for (i = 0; i < s->len; ++i) {
2821 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2822 bc_num_init(dnum, snum->len);
2823 bc_num_copy(dnum, snum);
2824 }
2825}
2826
Gavin Howard01055ba2018-11-03 11:00:21 -06002827static void bc_string_free(void *string)
2828{
2829 free(*((char **) string));
2830}
2831
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002832#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002833static void bc_result_copy(BcResult *d, BcResult *src)
2834{
2835 d->t = src->t;
2836
2837 switch (d->t) {
2838
2839 case BC_RESULT_TEMP:
2840 case BC_RESULT_IBASE:
2841 case BC_RESULT_SCALE:
2842 case BC_RESULT_OBASE:
2843 {
2844 bc_num_init(&d->d.n, src->d.n.len);
2845 bc_num_copy(&d->d.n, &src->d.n);
2846 break;
2847 }
2848
2849 case BC_RESULT_VAR:
2850 case BC_RESULT_ARRAY:
2851 case BC_RESULT_ARRAY_ELEM:
2852 {
2853 d->d.id.name = xstrdup(src->d.id.name);
2854 break;
2855 }
2856
2857 case BC_RESULT_CONSTANT:
2858 case BC_RESULT_LAST:
2859 case BC_RESULT_ONE:
2860 case BC_RESULT_STR:
2861 {
2862 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2863 break;
2864 }
2865 }
2866}
2867#endif // ENABLE_DC
2868
2869static void bc_result_free(void *result)
2870{
2871 BcResult *r = (BcResult *) result;
2872
2873 switch (r->t) {
2874
2875 case BC_RESULT_TEMP:
2876 case BC_RESULT_IBASE:
2877 case BC_RESULT_SCALE:
2878 case BC_RESULT_OBASE:
2879 {
2880 bc_num_free(&r->d.n);
2881 break;
2882 }
2883
2884 case BC_RESULT_VAR:
2885 case BC_RESULT_ARRAY:
2886 case BC_RESULT_ARRAY_ELEM:
2887 {
2888 free(r->d.id.name);
2889 break;
2890 }
2891
2892 default:
2893 {
2894 // Do nothing.
2895 break;
2896 }
2897 }
2898}
2899
2900static void bc_lex_lineComment(BcLex *l)
2901{
2902 l->t.t = BC_LEX_WHITESPACE;
2903 while (l->i < l->len && l->buf[l->i++] != '\n');
2904 --l->i;
2905}
2906
2907static void bc_lex_whitespace(BcLex *l)
2908{
2909 char c;
2910 l->t.t = BC_LEX_WHITESPACE;
2911 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2912}
2913
2914static BcStatus bc_lex_number(BcLex *l, char start)
2915{
2916 const char *buf = l->buf + l->i;
2917 size_t len, hits = 0, bslashes = 0, i = 0, j;
2918 char c = buf[i];
2919 bool last_pt, pt = start == '.';
2920
2921 last_pt = pt;
2922 l->t.t = BC_LEX_NUMBER;
2923
2924 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2925 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2926 {
2927 if (c != '\\') {
2928 last_pt = c == '.';
2929 pt = pt || last_pt;
2930 }
2931 else {
2932 ++i;
2933 bslashes += 1;
2934 }
2935
2936 c = buf[++i];
2937 }
2938
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002939 len = i + !last_pt - bslashes * 2;
Denys Vlasenko64074a12018-12-07 15:50:14 +01002940 // This check makes sense only if size_t is (much) larger than BC_MAX_NUM.
2941 if (SIZE_MAX > (BC_MAX_NUM | 0xff)) {
2942 if (len > BC_MAX_NUM)
2943 return bc_error("number too long: must be [1,"BC_MAX_NUM_STR"]");
2944 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002945
Denys Vlasenko7d628012018-12-04 21:46:47 +01002946 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002947 bc_vec_expand(&l->t.v, len + 1);
2948 bc_vec_push(&l->t.v, &start);
2949
2950 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2951
2952 c = buf[j];
2953
2954 // If we have hit a backslash, skip it. We don't have
2955 // to check for a newline because it's guaranteed.
2956 if (hits < bslashes && c == '\\') {
2957 ++hits;
2958 ++j;
2959 continue;
2960 }
2961
2962 bc_vec_push(&l->t.v, &c);
2963 }
2964
Denys Vlasenko08c033c2018-12-05 16:55:08 +01002965 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002966 l->i += i;
2967
2968 return BC_STATUS_SUCCESS;
2969}
2970
2971static BcStatus bc_lex_name(BcLex *l)
2972{
2973 size_t i = 0;
2974 const char *buf = l->buf + l->i - 1;
2975 char c = buf[i];
2976
2977 l->t.t = BC_LEX_NAME;
2978
2979 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2980
Denys Vlasenko64074a12018-12-07 15:50:14 +01002981 // This check makes sense only if size_t is (much) larger than BC_MAX_STRING.
2982 if (SIZE_MAX > (BC_MAX_STRING | 0xff)) {
2983 if (i > BC_MAX_STRING)
2984 return bc_error("name too long: must be [1,"BC_MAX_STRING_STR"]");
2985 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002986 bc_vec_string(&l->t.v, i, buf);
2987
2988 // Increment the index. We minus 1 because it has already been incremented.
2989 l->i += i - 1;
2990
2991 return BC_STATUS_SUCCESS;
2992}
2993
2994static void bc_lex_init(BcLex *l, BcLexNext next)
2995{
2996 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002997 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002998}
2999
3000static void bc_lex_free(BcLex *l)
3001{
3002 bc_vec_free(&l->t.v);
3003}
3004
Denys Vlasenko0409ad32018-12-05 16:39:22 +01003005static void bc_lex_file(BcLex *l)
Gavin Howard01055ba2018-11-03 11:00:21 -06003006{
Denys Vlasenko5318f812018-12-05 17:48:01 +01003007 G.err_line = l->line = 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003008 l->newline = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06003009}
3010
3011static BcStatus bc_lex_next(BcLex *l)
3012{
3013 BcStatus s;
3014
3015 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003016 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06003017
3018 l->line += l->newline;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003019 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003020 l->t.t = BC_LEX_EOF;
3021
3022 l->newline = (l->i == l->len);
3023 if (l->newline) return BC_STATUS_SUCCESS;
3024
3025 // Loop until failure or we don't have whitespace. This
3026 // is so the parser doesn't get inundated with whitespace.
3027 do {
3028 s = l->next(l);
3029 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3030
3031 return s;
3032}
3033
3034static BcStatus bc_lex_text(BcLex *l, const char *text)
3035{
3036 l->buf = text;
3037 l->i = 0;
3038 l->len = strlen(text);
3039 l->t.t = l->t.last = BC_LEX_INVALID;
3040 return bc_lex_next(l);
3041}
3042
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003043#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003044static BcStatus bc_lex_identifier(BcLex *l)
3045{
3046 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003047 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06003048 const char *buf = l->buf + l->i - 1;
3049
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003050 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3051 const char *keyword8 = bc_lex_kws[i].name8;
3052 unsigned j = 0;
3053 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3054 j++;
3055 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06003056 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003057 if (keyword8[j] != '\0')
3058 continue;
3059 match:
3060 // buf starts with keyword bc_lex_kws[i]
3061 l->t.t = BC_LEX_KEY_1st_keyword + i;
Denys Vlasenkod00d2f92018-12-06 12:59:40 +01003062 if (!bc_lex_kws_POSIX(i)) {
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003063 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003064 if (s) return s;
3065 }
3066
3067 // We minus 1 because the index has already been incremented.
3068 l->i += j - 1;
3069 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003070 }
3071
3072 s = bc_lex_name(l);
3073 if (s) return s;
3074
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003075 if (l->t.v.len > 2) {
3076 // Prevent this:
3077 // >>> qwe=1
3078 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
3079 // '
3080 unsigned len = strchrnul(buf, '\n') - buf;
3081 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
3082 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003083
3084 return s;
3085}
3086
3087static BcStatus bc_lex_string(BcLex *l)
3088{
3089 size_t len, nls = 0, i = l->i;
3090 char c;
3091
3092 l->t.t = BC_LEX_STR;
3093
3094 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3095
3096 if (c == '\0') {
3097 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003098 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003099 }
3100
3101 len = i - l->i;
Denys Vlasenko64074a12018-12-07 15:50:14 +01003102 // This check makes sense only if size_t is (much) larger than BC_MAX_STRING.
3103 if (SIZE_MAX > (BC_MAX_STRING | 0xff)) {
3104 if (len > BC_MAX_STRING)
3105 return bc_error("string too long: must be [1,"BC_MAX_STRING_STR"]");
3106 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003107 bc_vec_string(&l->t.v, len, l->buf + l->i);
3108
3109 l->i = i + 1;
3110 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003111 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003112
3113 return BC_STATUS_SUCCESS;
3114}
3115
3116static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3117{
3118 if (l->buf[l->i] == '=') {
3119 ++l->i;
3120 l->t.t = with;
3121 }
3122 else
3123 l->t.t = without;
3124}
3125
3126static BcStatus bc_lex_comment(BcLex *l)
3127{
3128 size_t i, nls = 0;
3129 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003130
3131 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003132 i = ++l->i;
3133 for (;;) {
3134 char c = buf[i];
3135 check_star:
3136 if (c == '*') {
3137 c = buf[++i];
3138 if (c == '/')
3139 break;
3140 goto check_star;
3141 }
3142 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003143 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003144 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003145 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003146 nls += (c == '\n');
3147 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003148 }
3149
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003150 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003151 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003152 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003153
3154 return BC_STATUS_SUCCESS;
3155}
3156
3157static BcStatus bc_lex_token(BcLex *l)
3158{
3159 BcStatus s = BC_STATUS_SUCCESS;
3160 char c = l->buf[l->i++], c2;
3161
3162 // This is the workhorse of the lexer.
3163 switch (c) {
3164
3165 case '\0':
3166 case '\n':
3167 {
3168 l->newline = true;
3169 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3170 break;
3171 }
3172
3173 case '\t':
3174 case '\v':
3175 case '\f':
3176 case '\r':
3177 case ' ':
3178 {
3179 bc_lex_whitespace(l);
3180 break;
3181 }
3182
3183 case '!':
3184 {
3185 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3186
3187 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko00646792018-12-05 18:12:27 +01003188 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
Gavin Howard01055ba2018-11-03 11:00:21 -06003189 if (s) return s;
3190 }
3191
3192 break;
3193 }
3194
3195 case '"':
3196 {
3197 s = bc_lex_string(l);
3198 break;
3199 }
3200
3201 case '#':
3202 {
Denys Vlasenko00646792018-12-05 18:12:27 +01003203 s = bc_POSIX_does_not_allow("'#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003204 if (s) return s;
3205
3206 bc_lex_lineComment(l);
3207
3208 break;
3209 }
3210
3211 case '%':
3212 {
3213 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3214 break;
3215 }
3216
3217 case '&':
3218 {
3219 c2 = l->buf[l->i];
3220 if (c2 == '&') {
3221
Denys Vlasenko00646792018-12-05 18:12:27 +01003222 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
Gavin Howard01055ba2018-11-03 11:00:21 -06003223 if (s) return s;
3224
3225 ++l->i;
3226 l->t.t = BC_LEX_OP_BOOL_AND;
3227 }
3228 else {
3229 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003230 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003231 }
3232
3233 break;
3234 }
3235
3236 case '(':
3237 case ')':
3238 {
3239 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3240 break;
3241 }
3242
3243 case '*':
3244 {
3245 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3246 break;
3247 }
3248
3249 case '+':
3250 {
3251 c2 = l->buf[l->i];
3252 if (c2 == '+') {
3253 ++l->i;
3254 l->t.t = BC_LEX_OP_INC;
3255 }
3256 else
3257 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3258 break;
3259 }
3260
3261 case ',':
3262 {
3263 l->t.t = BC_LEX_COMMA;
3264 break;
3265 }
3266
3267 case '-':
3268 {
3269 c2 = l->buf[l->i];
3270 if (c2 == '-') {
3271 ++l->i;
3272 l->t.t = BC_LEX_OP_DEC;
3273 }
3274 else
3275 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3276 break;
3277 }
3278
3279 case '.':
3280 {
3281 if (isdigit(l->buf[l->i]))
3282 s = bc_lex_number(l, c);
3283 else {
3284 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko00646792018-12-05 18:12:27 +01003285 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003286 }
3287 break;
3288 }
3289
3290 case '/':
3291 {
3292 c2 = l->buf[l->i];
3293 if (c2 == '*')
3294 s = bc_lex_comment(l);
3295 else
3296 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3297 break;
3298 }
3299
3300 case '0':
3301 case '1':
3302 case '2':
3303 case '3':
3304 case '4':
3305 case '5':
3306 case '6':
3307 case '7':
3308 case '8':
3309 case '9':
3310 case 'A':
3311 case 'B':
3312 case 'C':
3313 case 'D':
3314 case 'E':
3315 case 'F':
3316 {
3317 s = bc_lex_number(l, c);
3318 break;
3319 }
3320
3321 case ';':
3322 {
3323 l->t.t = BC_LEX_SCOLON;
3324 break;
3325 }
3326
3327 case '<':
3328 {
3329 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3330 break;
3331 }
3332
3333 case '=':
3334 {
3335 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3336 break;
3337 }
3338
3339 case '>':
3340 {
3341 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3342 break;
3343 }
3344
3345 case '[':
3346 case ']':
3347 {
3348 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3349 break;
3350 }
3351
3352 case '\\':
3353 {
3354 if (l->buf[l->i] == '\n') {
3355 l->t.t = BC_LEX_WHITESPACE;
3356 ++l->i;
3357 }
3358 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003359 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003360 break;
3361 }
3362
3363 case '^':
3364 {
3365 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3366 break;
3367 }
3368
3369 case 'a':
3370 case 'b':
3371 case 'c':
3372 case 'd':
3373 case 'e':
3374 case 'f':
3375 case 'g':
3376 case 'h':
3377 case 'i':
3378 case 'j':
3379 case 'k':
3380 case 'l':
3381 case 'm':
3382 case 'n':
3383 case 'o':
3384 case 'p':
3385 case 'q':
3386 case 'r':
3387 case 's':
3388 case 't':
3389 case 'u':
3390 case 'v':
3391 case 'w':
3392 case 'x':
3393 case 'y':
3394 case 'z':
3395 {
3396 s = bc_lex_identifier(l);
3397 break;
3398 }
3399
3400 case '{':
3401 case '}':
3402 {
3403 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3404 break;
3405 }
3406
3407 case '|':
3408 {
3409 c2 = l->buf[l->i];
3410
3411 if (c2 == '|') {
Denys Vlasenko00646792018-12-05 18:12:27 +01003412 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
Gavin Howard01055ba2018-11-03 11:00:21 -06003413 if (s) return s;
3414
3415 ++l->i;
3416 l->t.t = BC_LEX_OP_BOOL_OR;
3417 }
3418 else {
3419 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003420 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003421 }
3422
3423 break;
3424 }
3425
3426 default:
3427 {
3428 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003429 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003430 break;
3431 }
3432 }
3433
3434 return s;
3435}
3436#endif // ENABLE_BC
3437
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003438#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003439static BcStatus dc_lex_register(BcLex *l)
3440{
3441 BcStatus s = BC_STATUS_SUCCESS;
3442
3443 if (isspace(l->buf[l->i - 1])) {
3444 bc_lex_whitespace(l);
3445 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003446 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003447 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003448 else
3449 s = bc_lex_name(l);
3450 }
3451 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003452 bc_vec_pop_all(&l->t.v);
Denys Vlasenkoe55a5722018-12-06 12:47:17 +01003453 bc_vec_push(&l->t.v, &l->buf[l->i - 1]);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003454 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003455 l->t.t = BC_LEX_NAME;
3456 }
3457
3458 return s;
3459}
3460
3461static BcStatus dc_lex_string(BcLex *l)
3462{
3463 size_t depth = 1, nls = 0, i = l->i;
3464 char c;
3465
3466 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003467 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003468
3469 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3470
3471 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3472 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3473 nls += (c == '\n');
3474
3475 if (depth) bc_vec_push(&l->t.v, &c);
3476 }
3477
3478 if (c == '\0') {
3479 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003480 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003481 }
3482
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003483 bc_vec_pushZeroByte(&l->t.v);
Denys Vlasenko64074a12018-12-07 15:50:14 +01003484 // This check makes sense only if size_t is (much) larger than BC_MAX_STRING.
3485 if (SIZE_MAX > (BC_MAX_STRING | 0xff)) {
3486 if (i - l->i > BC_MAX_STRING)
3487 return bc_error("string too long: must be [1,"BC_MAX_STRING_STR"]");
3488 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003489
3490 l->i = i;
3491 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003492 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003493
3494 return BC_STATUS_SUCCESS;
3495}
3496
3497static BcStatus dc_lex_token(BcLex *l)
3498{
3499 BcStatus s = BC_STATUS_SUCCESS;
3500 char c = l->buf[l->i++], c2;
3501 size_t i;
3502
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003503 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3504 if (l->t.last == dc_lex_regs[i])
3505 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003506 }
3507
3508 if (c >= '%' && c <= '~' &&
3509 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3510 {
3511 return s;
3512 }
3513
3514 // This is the workhorse of the lexer.
3515 switch (c) {
3516
3517 case '\0':
3518 {
3519 l->t.t = BC_LEX_EOF;
3520 break;
3521 }
3522
3523 case '\n':
3524 case '\t':
3525 case '\v':
3526 case '\f':
3527 case '\r':
3528 case ' ':
3529 {
3530 l->newline = (c == '\n');
3531 bc_lex_whitespace(l);
3532 break;
3533 }
3534
3535 case '!':
3536 {
3537 c2 = l->buf[l->i];
3538
3539 if (c2 == '=')
3540 l->t.t = BC_LEX_OP_REL_NE;
3541 else if (c2 == '<')
3542 l->t.t = BC_LEX_OP_REL_LE;
3543 else if (c2 == '>')
3544 l->t.t = BC_LEX_OP_REL_GE;
3545 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003546 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003547
3548 ++l->i;
3549 break;
3550 }
3551
3552 case '#':
3553 {
3554 bc_lex_lineComment(l);
3555 break;
3556 }
3557
3558 case '.':
3559 {
3560 if (isdigit(l->buf[l->i]))
3561 s = bc_lex_number(l, c);
3562 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003563 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003564 break;
3565 }
3566
3567 case '0':
3568 case '1':
3569 case '2':
3570 case '3':
3571 case '4':
3572 case '5':
3573 case '6':
3574 case '7':
3575 case '8':
3576 case '9':
3577 case 'A':
3578 case 'B':
3579 case 'C':
3580 case 'D':
3581 case 'E':
3582 case 'F':
3583 {
3584 s = bc_lex_number(l, c);
3585 break;
3586 }
3587
3588 case '[':
3589 {
3590 s = dc_lex_string(l);
3591 break;
3592 }
3593
3594 default:
3595 {
3596 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003597 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003598 break;
3599 }
3600 }
3601
3602 return s;
3603}
3604#endif // ENABLE_DC
3605
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003606static void bc_program_addFunc(char *name, size_t *idx);
3607
Gavin Howard01055ba2018-11-03 11:00:21 -06003608static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3609{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003610 bc_program_addFunc(name, idx);
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01003611 p->func = bc_program_func(p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003612}
3613
Denys Vlasenkob23ac512018-12-06 13:10:56 +01003614#define bc_parse_push(p, i) bc_vec_pushByte(&(p)->func->code, (char) (i))
3615
Gavin Howard01055ba2018-11-03 11:00:21 -06003616static void bc_parse_pushName(BcParse *p, char *name)
3617{
3618 size_t i = 0, len = strlen(name);
3619
3620 for (; i < len; ++i) bc_parse_push(p, name[i]);
3621 bc_parse_push(p, BC_PARSE_STREND);
3622
3623 free(name);
3624}
3625
3626static void bc_parse_pushIndex(BcParse *p, size_t idx)
3627{
3628 unsigned char amt, i, nums[sizeof(size_t)];
3629
3630 for (amt = 0; idx; ++amt) {
3631 nums[amt] = (char) idx;
3632 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3633 }
3634
3635 bc_parse_push(p, amt);
3636 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3637}
3638
3639static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3640{
3641 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003642 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003643
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003644 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003645
3646 bc_parse_push(p, BC_INST_NUM);
3647 bc_parse_pushIndex(p, idx);
3648
3649 ++(*nexs);
3650 (*prev) = BC_INST_NUM;
3651}
3652
3653static BcStatus bc_parse_text(BcParse *p, const char *text)
3654{
3655 BcStatus s;
3656
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01003657 p->func = bc_program_func(p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003658
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003659 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003660 p->l.t.t = BC_LEX_INVALID;
3661 s = p->parse(p);
3662 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003663 if (!BC_PARSE_CAN_EXEC(p))
3664 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003665 }
3666
3667 return bc_lex_text(&p->l, text);
3668}
3669
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003670// Called when parsing or execution detects a failure,
3671// resets execution structures.
3672static void bc_program_reset(void)
3673{
3674 BcFunc *f;
3675 BcInstPtr *ip;
3676
3677 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
3678 bc_vec_pop_all(&G.prog.results);
3679
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01003680 f = bc_program_func(0);
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003681 ip = bc_vec_top(&G.prog.stack);
3682 ip->idx = f->code.len;
3683}
3684
Denys Vlasenkoe55a5722018-12-06 12:47:17 +01003685#define bc_parse_updateFunc(p, f) \
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01003686 ((p)->func = bc_program_func((p)->fidx = (f)))
Denys Vlasenkoe55a5722018-12-06 12:47:17 +01003687
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);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003731 bc_vec_pushZeroByte(&p->flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003732 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
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003740
3741#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
3742#define BC_PARSE_LEAF(p, rparen) \
3743 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
3744 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
3745
3746// We can calculate the conversion between tokens and exprs by subtracting the
3747// position of the first operator in the lex enum and adding the position of the
3748// first in the expr enum. Note: This only works for binary operators.
3749#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
3750
Gavin Howard01055ba2018-11-03 11:00:21 -06003751static BcStatus bc_parse_else(BcParse *p);
3752static BcStatus bc_parse_stmt(BcParse *p);
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003753static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01003754static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next);
Gavin Howard01055ba2018-11-03 11:00:21 -06003755
3756static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3757 size_t *nexprs, bool next)
3758{
3759 BcStatus s = BC_STATUS_SUCCESS;
3760 BcLexType t;
Denys Vlasenko65437582018-12-05 19:37:19 +01003761 char l, r = bc_parse_op_PREC(type - BC_LEX_OP_INC);
3762 bool left = bc_parse_op_LEFT(type - BC_LEX_OP_INC);
Gavin Howard01055ba2018-11-03 11:00:21 -06003763
3764 while (p->ops.len > start) {
3765
3766 t = BC_PARSE_TOP_OP(p);
3767 if (t == BC_LEX_LPAREN) break;
3768
Denys Vlasenko65437582018-12-05 19:37:19 +01003769 l = bc_parse_op_PREC(t - BC_LEX_OP_INC);
Gavin Howard01055ba2018-11-03 11:00:21 -06003770 if (l >= r && (l != r || !left)) break;
3771
3772 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3773 bc_vec_pop(&p->ops);
3774 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3775 }
3776
3777 bc_vec_push(&p->ops, &type);
3778 if (next) s = bc_lex_next(&p->l);
3779
3780 return s;
3781}
3782
3783static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3784{
3785 BcLexType top;
3786
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003787 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003788 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003789 top = BC_PARSE_TOP_OP(p);
3790
3791 while (top != BC_LEX_LPAREN) {
3792
3793 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3794
3795 bc_vec_pop(&p->ops);
3796 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3797
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003798 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003799 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003800 top = BC_PARSE_TOP_OP(p);
3801 }
3802
3803 bc_vec_pop(&p->ops);
3804
3805 return bc_lex_next(&p->l);
3806}
3807
3808static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3809{
3810 BcStatus s;
3811 bool comma = false;
3812 size_t nparams;
3813
3814 s = bc_lex_next(&p->l);
3815 if (s) return s;
3816
3817 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3818
3819 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3820 s = bc_parse_expr(p, flags, bc_parse_next_param);
3821 if (s) return s;
3822
3823 comma = p->l.t.t == BC_LEX_COMMA;
3824 if (comma) {
3825 s = bc_lex_next(&p->l);
3826 if (s) return s;
3827 }
3828 }
3829
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003830 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003831 bc_parse_push(p, BC_INST_CALL);
3832 bc_parse_pushIndex(p, nparams);
3833
3834 return BC_STATUS_SUCCESS;
3835}
3836
3837static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3838{
3839 BcStatus s;
3840 BcId entry, *entry_ptr;
3841 size_t idx;
3842
3843 entry.name = name;
3844
3845 s = bc_parse_params(p, flags);
3846 if (s) goto err;
3847
3848 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003849 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003850 goto err;
3851 }
3852
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003853 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003854
3855 if (idx == BC_VEC_INVALID_IDX) {
3856 name = xstrdup(entry.name);
3857 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003858 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003859 free(entry.name);
3860 }
3861 else
3862 free(name);
3863
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003864 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003865 bc_parse_pushIndex(p, entry_ptr->idx);
3866
3867 return bc_lex_next(&p->l);
3868
3869err:
3870 free(name);
3871 return s;
3872}
3873
3874static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3875{
3876 BcStatus s;
3877 char *name;
3878
3879 name = xstrdup(p->l.t.v.v);
3880 s = bc_lex_next(&p->l);
3881 if (s) goto err;
3882
3883 if (p->l.t.t == BC_LEX_LBRACKET) {
3884
3885 s = bc_lex_next(&p->l);
3886 if (s) goto err;
3887
3888 if (p->l.t.t == BC_LEX_RBRACKET) {
3889
3890 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003891 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003892 goto err;
3893 }
3894
3895 *type = BC_INST_ARRAY;
3896 }
3897 else {
3898
3899 *type = BC_INST_ARRAY_ELEM;
3900
3901 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3902 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3903 if (s) goto err;
3904 }
3905
3906 s = bc_lex_next(&p->l);
3907 if (s) goto err;
3908 bc_parse_push(p, *type);
3909 bc_parse_pushName(p, name);
3910 }
3911 else if (p->l.t.t == BC_LEX_LPAREN) {
3912
3913 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003914 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003915 goto err;
3916 }
3917
3918 *type = BC_INST_CALL;
3919 s = bc_parse_call(p, name, flags);
3920 }
3921 else {
3922 *type = BC_INST_VAR;
3923 bc_parse_push(p, BC_INST_VAR);
3924 bc_parse_pushName(p, name);
3925 }
3926
3927 return s;
3928
3929err:
3930 free(name);
3931 return s;
3932}
3933
3934static BcStatus bc_parse_read(BcParse *p)
3935{
3936 BcStatus s;
3937
3938 s = bc_lex_next(&p->l);
3939 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003940 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003941
3942 s = bc_lex_next(&p->l);
3943 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003944 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003945
3946 bc_parse_push(p, BC_INST_READ);
3947
3948 return bc_lex_next(&p->l);
3949}
3950
3951static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3952 BcInst *prev)
3953{
3954 BcStatus s;
3955
3956 s = bc_lex_next(&p->l);
3957 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003958 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003959
3960 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3961
3962 s = bc_lex_next(&p->l);
3963 if (s) return s;
3964
3965 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3966 if (s) return s;
3967
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003968 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003969
3970 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3971 bc_parse_push(p, *prev);
3972
3973 return bc_lex_next(&p->l);
3974}
3975
3976static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3977{
3978 BcStatus s;
3979
3980 s = bc_lex_next(&p->l);
3981 if (s) return s;
3982
3983 if (p->l.t.t != BC_LEX_LPAREN) {
3984 *type = BC_INST_SCALE;
3985 bc_parse_push(p, BC_INST_SCALE);
3986 return BC_STATUS_SUCCESS;
3987 }
3988
3989 *type = BC_INST_SCALE_FUNC;
3990 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3991
3992 s = bc_lex_next(&p->l);
3993 if (s) return s;
3994
3995 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3996 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003997 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003998 bc_parse_push(p, BC_INST_SCALE_FUNC);
3999
4000 return bc_lex_next(&p->l);
4001}
4002
4003static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
4004 size_t *nexprs, uint8_t flags)
4005{
4006 BcStatus s;
4007 BcLexType type;
4008 char inst;
4009 BcInst etype = *prev;
4010
4011 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
4012 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
4013 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
4014 {
4015 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
4016 bc_parse_push(p, inst);
4017 s = bc_lex_next(&p->l);
4018 }
4019 else {
4020
4021 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
4022 *paren_expr = true;
4023
4024 s = bc_lex_next(&p->l);
4025 if (s) return s;
4026 type = p->l.t.t;
4027
4028 // Because we parse the next part of the expression
4029 // right here, we need to increment this.
4030 *nexprs = *nexprs + 1;
4031
4032 switch (type) {
4033
4034 case BC_LEX_NAME:
4035 {
4036 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4037 break;
4038 }
4039
4040 case BC_LEX_KEY_IBASE:
4041 case BC_LEX_KEY_LAST:
4042 case BC_LEX_KEY_OBASE:
4043 {
4044 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4045 s = bc_lex_next(&p->l);
4046 break;
4047 }
4048
4049 case BC_LEX_KEY_SCALE:
4050 {
4051 s = bc_lex_next(&p->l);
4052 if (s) return s;
4053 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004054 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004055 else
4056 bc_parse_push(p, BC_INST_SCALE);
4057 break;
4058 }
4059
4060 default:
4061 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004062 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004063 break;
4064 }
4065 }
4066
4067 if (!s) bc_parse_push(p, inst);
4068 }
4069
4070 return s;
4071}
4072
4073static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4074 bool rparen, size_t *nexprs)
4075{
4076 BcStatus s;
4077 BcLexType type;
4078 BcInst etype = *prev;
4079
4080 s = bc_lex_next(&p->l);
4081 if (s) return s;
4082
4083 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4084 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4085 BC_LEX_OP_MINUS :
4086 BC_LEX_NEG;
4087 *prev = BC_PARSE_TOKEN_INST(type);
4088
4089 // We can just push onto the op stack because this is the largest
4090 // precedence operator that gets pushed. Inc/dec does not.
4091 if (type != BC_LEX_OP_MINUS)
4092 bc_vec_push(&p->ops, &type);
4093 else
4094 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4095
4096 return s;
4097}
4098
4099static BcStatus bc_parse_string(BcParse *p, char inst)
4100{
4101 char *str = xstrdup(p->l.t.v.v);
4102
4103 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004104 bc_parse_pushIndex(p, G.prog.strs.len);
4105 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004106 bc_parse_push(p, inst);
4107
4108 return bc_lex_next(&p->l);
4109}
4110
4111static BcStatus bc_parse_print(BcParse *p)
4112{
4113 BcStatus s;
4114 BcLexType type;
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004115 bool comma;
Gavin Howard01055ba2018-11-03 11:00:21 -06004116
4117 s = bc_lex_next(&p->l);
4118 if (s) return s;
4119
4120 type = p->l.t.t;
4121
4122 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004123 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06004124
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004125 comma = false;
4126 while (type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004127
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004128 if (type == BC_LEX_STR) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004129 s = bc_parse_string(p, BC_INST_PRINT_POP);
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004130 if (s) return s;
4131 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06004132 s = bc_parse_expr(p, 0, bc_parse_next_print);
4133 if (s) return s;
4134 bc_parse_push(p, BC_INST_PRINT_POP);
4135 }
4136
Gavin Howard01055ba2018-11-03 11:00:21 -06004137 comma = p->l.t.t == BC_LEX_COMMA;
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004138 if (comma) {
4139 s = bc_lex_next(&p->l);
4140 if (s) return s;
4141 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004142 type = p->l.t.t;
4143 }
4144
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004145 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004146
4147 return bc_lex_next(&p->l);
4148}
4149
4150static BcStatus bc_parse_return(BcParse *p)
4151{
4152 BcStatus s;
4153 BcLexType t;
4154 bool paren;
4155
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004156 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004157
4158 s = bc_lex_next(&p->l);
4159 if (s) return s;
4160
4161 t = p->l.t.t;
4162 paren = t == BC_LEX_LPAREN;
4163
4164 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4165 bc_parse_push(p, BC_INST_RET0);
4166 else {
4167
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01004168 s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004169 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004170 bc_parse_push(p, BC_INST_RET0);
4171 s = bc_lex_next(&p->l);
Gavin Howard01055ba2018-11-03 11:00:21 -06004172 }
Denys Vlasenko452df922018-12-05 20:28:26 +01004173 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06004174
4175 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01004176 s = bc_POSIX_requires("parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004177 if (s) return s;
4178 }
4179
4180 bc_parse_push(p, BC_INST_RET);
4181 }
4182
4183 return s;
4184}
4185
4186static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4187{
4188 BcStatus s = BC_STATUS_SUCCESS;
4189
4190 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004191 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004192
4193 if (brace) {
4194
4195 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004196 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004197 --p->nbraces;
4198 s = bc_lex_next(&p->l);
4199 if (s) return s;
4200 }
4201 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004202 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004203 }
4204
4205 if (BC_PARSE_IF(p)) {
4206
4207 uint8_t *flag_ptr;
4208
4209 while (p->l.t.t == BC_LEX_NLINE) {
4210 s = bc_lex_next(&p->l);
4211 if (s) return s;
4212 }
4213
4214 bc_vec_pop(&p->flags);
4215
4216 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4217 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4218
4219 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4220 }
4221 else if (BC_PARSE_ELSE(p)) {
4222
4223 BcInstPtr *ip;
4224 size_t *label;
4225
4226 bc_vec_pop(&p->flags);
4227
4228 ip = bc_vec_top(&p->exits);
4229 label = bc_vec_item(&p->func->labels, ip->idx);
4230 *label = p->func->code.len;
4231
4232 bc_vec_pop(&p->exits);
4233 }
4234 else if (BC_PARSE_FUNC_INNER(p)) {
4235 bc_parse_push(p, BC_INST_RET0);
4236 bc_parse_updateFunc(p, BC_PROG_MAIN);
4237 bc_vec_pop(&p->flags);
4238 }
4239 else {
4240
4241 BcInstPtr *ip = bc_vec_top(&p->exits);
4242 size_t *label = bc_vec_top(&p->conds);
4243
4244 bc_parse_push(p, BC_INST_JUMP);
4245 bc_parse_pushIndex(p, *label);
4246
4247 label = bc_vec_item(&p->func->labels, ip->idx);
4248 *label = p->func->code.len;
4249
4250 bc_vec_pop(&p->flags);
4251 bc_vec_pop(&p->exits);
4252 bc_vec_pop(&p->conds);
4253 }
4254
4255 return s;
4256}
4257
4258static void bc_parse_startBody(BcParse *p, uint8_t flags)
4259{
4260 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4261 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4262 flags |= BC_PARSE_FLAG_BODY;
4263 bc_vec_push(&p->flags, &flags);
4264}
4265
4266static void bc_parse_noElse(BcParse *p)
4267{
4268 BcInstPtr *ip;
4269 size_t *label;
4270 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4271
4272 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4273
4274 ip = bc_vec_top(&p->exits);
4275 label = bc_vec_item(&p->func->labels, ip->idx);
4276 *label = p->func->code.len;
4277
4278 bc_vec_pop(&p->exits);
4279}
4280
4281static BcStatus bc_parse_if(BcParse *p)
4282{
4283 BcStatus s;
4284 BcInstPtr ip;
4285
4286 s = bc_lex_next(&p->l);
4287 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004288 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004289
4290 s = bc_lex_next(&p->l);
4291 if (s) return s;
4292 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4293 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004294 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004295
4296 s = bc_lex_next(&p->l);
4297 if (s) return s;
4298 bc_parse_push(p, BC_INST_JUMP_ZERO);
4299
4300 ip.idx = p->func->labels.len;
4301 ip.func = ip.len = 0;
4302
4303 bc_parse_pushIndex(p, ip.idx);
4304 bc_vec_push(&p->exits, &ip);
4305 bc_vec_push(&p->func->labels, &ip.idx);
4306 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4307
4308 return BC_STATUS_SUCCESS;
4309}
4310
4311static BcStatus bc_parse_else(BcParse *p)
4312{
4313 BcInstPtr ip;
4314
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004315 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004316
4317 ip.idx = p->func->labels.len;
4318 ip.func = ip.len = 0;
4319
4320 bc_parse_push(p, BC_INST_JUMP);
4321 bc_parse_pushIndex(p, ip.idx);
4322
4323 bc_parse_noElse(p);
4324
4325 bc_vec_push(&p->exits, &ip);
4326 bc_vec_push(&p->func->labels, &ip.idx);
4327 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4328
4329 return bc_lex_next(&p->l);
4330}
4331
4332static BcStatus bc_parse_while(BcParse *p)
4333{
4334 BcStatus s;
4335 BcInstPtr ip;
4336
4337 s = bc_lex_next(&p->l);
4338 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004339 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004340 s = bc_lex_next(&p->l);
4341 if (s) return s;
4342
4343 ip.idx = p->func->labels.len;
4344
4345 bc_vec_push(&p->func->labels, &p->func->code.len);
4346 bc_vec_push(&p->conds, &ip.idx);
4347
4348 ip.idx = p->func->labels.len;
4349 ip.func = 1;
4350 ip.len = 0;
4351
4352 bc_vec_push(&p->exits, &ip);
4353 bc_vec_push(&p->func->labels, &ip.idx);
4354
4355 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4356 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004357 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004358 s = bc_lex_next(&p->l);
4359 if (s) return s;
4360
4361 bc_parse_push(p, BC_INST_JUMP_ZERO);
4362 bc_parse_pushIndex(p, ip.idx);
4363 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4364
4365 return BC_STATUS_SUCCESS;
4366}
4367
4368static BcStatus bc_parse_for(BcParse *p)
4369{
4370 BcStatus s;
4371 BcInstPtr ip;
4372 size_t cond_idx, exit_idx, body_idx, update_idx;
4373
4374 s = bc_lex_next(&p->l);
4375 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004376 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004377 s = bc_lex_next(&p->l);
4378 if (s) return s;
4379
4380 if (p->l.t.t != BC_LEX_SCOLON)
4381 s = bc_parse_expr(p, 0, bc_parse_next_for);
4382 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004383 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
Gavin Howard01055ba2018-11-03 11:00:21 -06004384
4385 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004386 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004387 s = bc_lex_next(&p->l);
4388 if (s) return s;
4389
4390 cond_idx = p->func->labels.len;
4391 update_idx = cond_idx + 1;
4392 body_idx = update_idx + 1;
4393 exit_idx = body_idx + 1;
4394
4395 bc_vec_push(&p->func->labels, &p->func->code.len);
4396
4397 if (p->l.t.t != BC_LEX_SCOLON)
4398 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4399 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004400 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004401
4402 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004403 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004404
4405 s = bc_lex_next(&p->l);
4406 if (s) return s;
4407
4408 bc_parse_push(p, BC_INST_JUMP_ZERO);
4409 bc_parse_pushIndex(p, exit_idx);
4410 bc_parse_push(p, BC_INST_JUMP);
4411 bc_parse_pushIndex(p, body_idx);
4412
4413 ip.idx = p->func->labels.len;
4414
4415 bc_vec_push(&p->conds, &update_idx);
4416 bc_vec_push(&p->func->labels, &p->func->code.len);
4417
4418 if (p->l.t.t != BC_LEX_RPAREN)
4419 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4420 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004421 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
Gavin Howard01055ba2018-11-03 11:00:21 -06004422
4423 if (s) return s;
4424
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004425 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004426 bc_parse_push(p, BC_INST_JUMP);
4427 bc_parse_pushIndex(p, cond_idx);
4428 bc_vec_push(&p->func->labels, &p->func->code.len);
4429
4430 ip.idx = exit_idx;
4431 ip.func = 1;
4432 ip.len = 0;
4433
4434 bc_vec_push(&p->exits, &ip);
4435 bc_vec_push(&p->func->labels, &ip.idx);
4436 bc_lex_next(&p->l);
4437 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4438
4439 return BC_STATUS_SUCCESS;
4440}
4441
4442static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4443{
4444 BcStatus s;
4445 size_t i;
4446 BcInstPtr *ip;
4447
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004448 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004449
4450 if (type == BC_LEX_KEY_BREAK) {
4451
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004452 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004453
4454 i = p->exits.len - 1;
4455 ip = bc_vec_item(&p->exits, i);
4456
4457 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004458 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004459
4460 i = ip->idx;
4461 }
4462 else
4463 i = *((size_t *) bc_vec_top(&p->conds));
4464
4465 bc_parse_push(p, BC_INST_JUMP);
4466 bc_parse_pushIndex(p, i);
4467
4468 s = bc_lex_next(&p->l);
4469 if (s) return s;
4470
4471 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004472 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004473
4474 return bc_lex_next(&p->l);
4475}
4476
4477static BcStatus bc_parse_func(BcParse *p)
4478{
4479 BcStatus s;
4480 bool var, comma = false;
4481 uint8_t flags;
4482 char *name;
4483
4484 s = bc_lex_next(&p->l);
4485 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004486 if (p->l.t.t != BC_LEX_NAME)
4487 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004488
4489 name = xstrdup(p->l.t.v.v);
4490 bc_parse_addFunc(p, name, &p->fidx);
4491
4492 s = bc_lex_next(&p->l);
4493 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004494 if (p->l.t.t != BC_LEX_LPAREN)
4495 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004496 s = bc_lex_next(&p->l);
4497 if (s) return s;
4498
4499 while (p->l.t.t != BC_LEX_RPAREN) {
4500
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004501 if (p->l.t.t != BC_LEX_NAME)
4502 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004503
4504 ++p->func->nparams;
4505
4506 name = xstrdup(p->l.t.v.v);
4507 s = bc_lex_next(&p->l);
4508 if (s) goto err;
4509
4510 var = p->l.t.t != BC_LEX_LBRACKET;
4511
4512 if (!var) {
4513
4514 s = bc_lex_next(&p->l);
4515 if (s) goto err;
4516
4517 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004518 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004519 goto err;
4520 }
4521
4522 s = bc_lex_next(&p->l);
4523 if (s) goto err;
4524 }
4525
4526 comma = p->l.t.t == BC_LEX_COMMA;
4527 if (comma) {
4528 s = bc_lex_next(&p->l);
4529 if (s) goto err;
4530 }
4531
4532 s = bc_func_insert(p->func, name, var);
4533 if (s) goto err;
4534 }
4535
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004536 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004537
4538 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4539 bc_parse_startBody(p, flags);
4540
4541 s = bc_lex_next(&p->l);
4542 if (s) return s;
4543
4544 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01004545 s = bc_POSIX_requires("the left brace be on the same line as the function header");
Gavin Howard01055ba2018-11-03 11:00:21 -06004546
4547 return s;
4548
4549err:
4550 free(name);
4551 return s;
4552}
4553
4554static BcStatus bc_parse_auto(BcParse *p)
4555{
4556 BcStatus s;
4557 bool comma, var, one;
4558 char *name;
4559
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004560 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004561 s = bc_lex_next(&p->l);
4562 if (s) return s;
4563
4564 p->auto_part = comma = false;
4565 one = p->l.t.t == BC_LEX_NAME;
4566
4567 while (p->l.t.t == BC_LEX_NAME) {
4568
4569 name = xstrdup(p->l.t.v.v);
4570 s = bc_lex_next(&p->l);
4571 if (s) goto err;
4572
4573 var = p->l.t.t != BC_LEX_LBRACKET;
4574 if (!var) {
4575
4576 s = bc_lex_next(&p->l);
4577 if (s) goto err;
4578
4579 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004580 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004581 goto err;
4582 }
4583
4584 s = bc_lex_next(&p->l);
4585 if (s) goto err;
4586 }
4587
4588 comma = p->l.t.t == BC_LEX_COMMA;
4589 if (comma) {
4590 s = bc_lex_next(&p->l);
4591 if (s) goto err;
4592 }
4593
4594 s = bc_func_insert(p->func, name, var);
4595 if (s) goto err;
4596 }
4597
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004598 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004599 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004600
4601 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004602 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004603
4604 return bc_lex_next(&p->l);
4605
4606err:
4607 free(name);
4608 return s;
4609}
4610
4611static BcStatus bc_parse_body(BcParse *p, bool brace)
4612{
4613 BcStatus s = BC_STATUS_SUCCESS;
4614 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4615
4616 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4617
4618 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4619
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004620 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004621 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4622
4623 if (!p->auto_part) {
4624 s = bc_parse_auto(p);
4625 if (s) return s;
4626 }
4627
4628 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4629 }
4630 else {
4631 s = bc_parse_stmt(p);
4632 if (!s && !brace) s = bc_parse_endBody(p, false);
4633 }
4634
4635 return s;
4636}
4637
4638static BcStatus bc_parse_stmt(BcParse *p)
4639{
4640 BcStatus s = BC_STATUS_SUCCESS;
4641
4642 switch (p->l.t.t) {
4643
4644 case BC_LEX_NLINE:
4645 {
4646 return bc_lex_next(&p->l);
4647 }
4648
4649 case BC_LEX_KEY_ELSE:
4650 {
4651 p->auto_part = false;
4652 break;
4653 }
4654
4655 case BC_LEX_LBRACE:
4656 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004657 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004658
4659 ++p->nbraces;
4660 s = bc_lex_next(&p->l);
4661 if (s) return s;
4662
4663 return bc_parse_body(p, true);
4664 }
4665
4666 case BC_LEX_KEY_AUTO:
4667 {
4668 return bc_parse_auto(p);
4669 }
4670
4671 default:
4672 {
4673 p->auto_part = false;
4674
4675 if (BC_PARSE_IF_END(p)) {
4676 bc_parse_noElse(p);
4677 return BC_STATUS_SUCCESS;
4678 }
4679 else if (BC_PARSE_BODY(p))
4680 return bc_parse_body(p, false);
4681
4682 break;
4683 }
4684 }
4685
4686 switch (p->l.t.t) {
4687
4688 case BC_LEX_OP_INC:
4689 case BC_LEX_OP_DEC:
4690 case BC_LEX_OP_MINUS:
4691 case BC_LEX_OP_BOOL_NOT:
4692 case BC_LEX_LPAREN:
4693 case BC_LEX_NAME:
4694 case BC_LEX_NUMBER:
4695 case BC_LEX_KEY_IBASE:
4696 case BC_LEX_KEY_LAST:
4697 case BC_LEX_KEY_LENGTH:
4698 case BC_LEX_KEY_OBASE:
4699 case BC_LEX_KEY_READ:
4700 case BC_LEX_KEY_SCALE:
4701 case BC_LEX_KEY_SQRT:
4702 {
4703 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4704 break;
4705 }
4706
4707 case BC_LEX_KEY_ELSE:
4708 {
4709 s = bc_parse_else(p);
4710 break;
4711 }
4712
4713 case BC_LEX_SCOLON:
4714 {
4715 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4716 break;
4717 }
4718
4719 case BC_LEX_RBRACE:
4720 {
4721 s = bc_parse_endBody(p, true);
4722 break;
4723 }
4724
4725 case BC_LEX_STR:
4726 {
4727 s = bc_parse_string(p, BC_INST_PRINT_STR);
4728 break;
4729 }
4730
4731 case BC_LEX_KEY_BREAK:
4732 case BC_LEX_KEY_CONTINUE:
4733 {
4734 s = bc_parse_loopExit(p, p->l.t.t);
4735 break;
4736 }
4737
4738 case BC_LEX_KEY_FOR:
4739 {
4740 s = bc_parse_for(p);
4741 break;
4742 }
4743
4744 case BC_LEX_KEY_HALT:
4745 {
4746 bc_parse_push(p, BC_INST_HALT);
4747 s = bc_lex_next(&p->l);
4748 break;
4749 }
4750
4751 case BC_LEX_KEY_IF:
4752 {
4753 s = bc_parse_if(p);
4754 break;
4755 }
4756
4757 case BC_LEX_KEY_LIMITS:
4758 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004759 // "limits" is a compile-time command,
4760 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004761 s = bc_lex_next(&p->l);
4762 if (s) return s;
Denys Vlasenko64074a12018-12-07 15:50:14 +01004763 printf(
4764 "BC_BASE_MAX = "BC_MAX_OBASE_STR "\n"
4765 "BC_DIM_MAX = "BC_MAX_DIM_STR "\n"
4766 "BC_SCALE_MAX = "BC_MAX_SCALE_STR "\n"
4767 "BC_STRING_MAX = "BC_MAX_STRING_STR"\n"
4768 "BC_NAME_MAX = "BC_MAX_NAME_STR "\n"
4769 "BC_NUM_MAX = "BC_MAX_NUM_STR "\n"
4770 "MAX Exponent = "BC_MAX_EXP_STR "\n"
4771 "Number of vars = "BC_MAX_VARS_STR "\n"
4772 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004773 break;
4774 }
4775
4776 case BC_LEX_KEY_PRINT:
4777 {
4778 s = bc_parse_print(p);
4779 break;
4780 }
4781
4782 case BC_LEX_KEY_QUIT:
4783 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004784 // "quit" is a compile-time command. For example,
4785 // "if (0 == 1) quit" terminates when parsing the statement,
4786 // not when it is executed
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01004787 QUIT_OR_RETURN_TO_MAIN;
Gavin Howard01055ba2018-11-03 11:00:21 -06004788 }
4789
4790 case BC_LEX_KEY_RETURN:
4791 {
4792 s = bc_parse_return(p);
4793 break;
4794 }
4795
4796 case BC_LEX_KEY_WHILE:
4797 {
4798 s = bc_parse_while(p);
4799 break;
4800 }
4801
4802 default:
4803 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004804 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004805 break;
4806 }
4807 }
4808
4809 return s;
4810}
4811
4812static BcStatus bc_parse_parse(BcParse *p)
4813{
4814 BcStatus s;
4815
4816 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004817 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 -06004818 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004819 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004820 s = bc_parse_func(p);
4821 }
4822 else
4823 s = bc_parse_stmt(p);
4824
Denys Vlasenkod38af482018-12-04 19:11:02 +01004825 if (s || G_interrupt) {
4826 bc_parse_reset(p);
4827 s = BC_STATUS_FAILURE;
4828 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004829
4830 return s;
4831}
4832
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01004833static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next)
Gavin Howard01055ba2018-11-03 11:00:21 -06004834{
4835 BcStatus s = BC_STATUS_SUCCESS;
4836 BcInst prev = BC_INST_PRINT;
4837 BcLexType top, t = p->l.t.t;
4838 size_t nexprs = 0, ops_bgn = p->ops.len;
Denys Vlasenko18c6b542018-12-07 12:57:32 +01004839 unsigned nparens, nrelops;
Gavin Howard01055ba2018-11-03 11:00:21 -06004840 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4841
4842 paren_first = p->l.t.t == BC_LEX_LPAREN;
4843 nparens = nrelops = 0;
4844 paren_expr = rprn = done = get_token = assign = false;
4845 bin_last = true;
4846
Denys Vlasenkobcb62a72018-12-05 20:17:48 +01004847 for (; !G_interrupt && !s && !done && bc_parse_exprs(t); t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004848 switch (t) {
4849
4850 case BC_LEX_OP_INC:
4851 case BC_LEX_OP_DEC:
4852 {
4853 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4854 rprn = get_token = bin_last = false;
4855 break;
4856 }
4857
4858 case BC_LEX_OP_MINUS:
4859 {
4860 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4861 rprn = get_token = false;
4862 bin_last = prev == BC_INST_MINUS;
4863 break;
4864 }
4865
4866 case BC_LEX_OP_ASSIGN_POWER:
4867 case BC_LEX_OP_ASSIGN_MULTIPLY:
4868 case BC_LEX_OP_ASSIGN_DIVIDE:
4869 case BC_LEX_OP_ASSIGN_MODULUS:
4870 case BC_LEX_OP_ASSIGN_PLUS:
4871 case BC_LEX_OP_ASSIGN_MINUS:
4872 case BC_LEX_OP_ASSIGN:
4873 {
4874 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4875 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4876 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4877 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004878 s = bc_error("bad assignment:"
4879 " left side must be scale,"
4880 " ibase, obase, last, var,"
4881 " or array element"
4882 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004883 break;
4884 }
4885 }
4886 // Fallthrough.
4887 case BC_LEX_OP_POWER:
4888 case BC_LEX_OP_MULTIPLY:
4889 case BC_LEX_OP_DIVIDE:
4890 case BC_LEX_OP_MODULUS:
4891 case BC_LEX_OP_PLUS:
4892 case BC_LEX_OP_REL_EQ:
4893 case BC_LEX_OP_REL_LE:
4894 case BC_LEX_OP_REL_GE:
4895 case BC_LEX_OP_REL_NE:
4896 case BC_LEX_OP_REL_LT:
4897 case BC_LEX_OP_REL_GT:
4898 case BC_LEX_OP_BOOL_NOT:
4899 case BC_LEX_OP_BOOL_OR:
4900 case BC_LEX_OP_BOOL_AND:
4901 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004902 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4903 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4904 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004905 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004906 }
4907
4908 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4909 prev = BC_PARSE_TOKEN_INST(t);
4910 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4911 rprn = get_token = false;
4912 bin_last = t != BC_LEX_OP_BOOL_NOT;
4913
4914 break;
4915 }
4916
4917 case BC_LEX_LPAREN:
4918 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004919 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004920 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004921 ++nparens;
4922 paren_expr = rprn = bin_last = false;
4923 get_token = true;
4924 bc_vec_push(&p->ops, &t);
4925
4926 break;
4927 }
4928
4929 case BC_LEX_RPAREN:
4930 {
4931 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004932 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004933
4934 if (nparens == 0) {
4935 s = BC_STATUS_SUCCESS;
4936 done = true;
4937 get_token = false;
4938 break;
4939 }
4940 else if (!paren_expr)
4941 return BC_STATUS_PARSE_EMPTY_EXP;
4942
4943 --nparens;
4944 paren_expr = rprn = true;
4945 get_token = bin_last = false;
4946
4947 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4948
4949 break;
4950 }
4951
4952 case BC_LEX_NAME:
4953 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004954 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004955 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004956 paren_expr = true;
4957 rprn = get_token = bin_last = false;
4958 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4959 ++nexprs;
4960
4961 break;
4962 }
4963
4964 case BC_LEX_NUMBER:
4965 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004966 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004967 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004968 bc_parse_number(p, &prev, &nexprs);
4969 paren_expr = get_token = true;
4970 rprn = bin_last = false;
4971
4972 break;
4973 }
4974
4975 case BC_LEX_KEY_IBASE:
4976 case BC_LEX_KEY_LAST:
4977 case BC_LEX_KEY_OBASE:
4978 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004979 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004980 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004981 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4982 bc_parse_push(p, (char) prev);
4983
4984 paren_expr = get_token = true;
4985 rprn = bin_last = false;
4986 ++nexprs;
4987
4988 break;
4989 }
4990
4991 case BC_LEX_KEY_LENGTH:
4992 case BC_LEX_KEY_SQRT:
4993 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004994 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004995 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004996 s = bc_parse_builtin(p, t, flags, &prev);
4997 paren_expr = true;
4998 rprn = get_token = bin_last = false;
4999 ++nexprs;
5000
5001 break;
5002 }
5003
5004 case BC_LEX_KEY_READ:
5005 {
5006 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005007 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005008 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005009 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005010 else
5011 s = bc_parse_read(p);
5012
5013 paren_expr = true;
5014 rprn = get_token = bin_last = false;
5015 ++nexprs;
5016 prev = BC_INST_READ;
5017
5018 break;
5019 }
5020
5021 case BC_LEX_KEY_SCALE:
5022 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005023 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005024 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005025 s = bc_parse_scale(p, &prev, flags);
5026 paren_expr = true;
5027 rprn = get_token = bin_last = false;
5028 ++nexprs;
5029 prev = BC_INST_SCALE;
5030
5031 break;
5032 }
5033
5034 default:
5035 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005036 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005037 break;
5038 }
5039 }
5040
5041 if (!s && get_token) s = bc_lex_next(&p->l);
5042 }
5043
5044 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01005045 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06005046
5047 while (p->ops.len > ops_bgn) {
5048
5049 top = BC_PARSE_TOP_OP(p);
5050 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
5051
5052 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005053 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005054
5055 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5056
5057 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5058 bc_vec_pop(&p->ops);
5059 }
5060
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005061 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005062 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06005063
Denys Vlasenko18c6b542018-12-07 12:57:32 +01005064 // next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word
5065 for (;;) {
5066 if (t == (next & 0x7f))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005067 goto ok;
Denys Vlasenko18c6b542018-12-07 12:57:32 +01005068 if (next & 0x80) // last element?
5069 break;
5070 next >>= 8;
5071 }
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005072 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005073 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06005074
5075 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko00646792018-12-05 18:12:27 +01005076 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06005077 if (s) return s;
5078 }
5079 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01005080 s = bc_POSIX_requires("exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06005081 if (s) return s;
5082 }
5083
5084 if (flags & BC_PARSE_PRINT) {
5085 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5086 bc_parse_push(p, BC_INST_POP);
5087 }
5088
5089 return s;
5090}
5091
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01005092static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
5093{
5094 BcStatus s;
5095
5096 s = bc_parse_expr_empty_ok(p, flags, next);
5097 if (s == BC_STATUS_PARSE_EMPTY_EXP)
5098 return bc_error("empty expression");
5099 return s;
5100}
5101
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005102static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005103{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005104 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005105}
5106
5107static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5108{
5109 return bc_parse_expr(p, flags, bc_parse_next_read);
5110}
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005111
Gavin Howard01055ba2018-11-03 11:00:21 -06005112#endif // ENABLE_BC
5113
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005114#if ENABLE_DC
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005115
5116#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
5117
Gavin Howard01055ba2018-11-03 11:00:21 -06005118static BcStatus dc_parse_register(BcParse *p)
5119{
5120 BcStatus s;
5121 char *name;
5122
5123 s = bc_lex_next(&p->l);
5124 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005125 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005126
5127 name = xstrdup(p->l.t.v.v);
5128 bc_parse_pushName(p, name);
5129
5130 return s;
5131}
5132
5133static BcStatus dc_parse_string(BcParse *p)
5134{
5135 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005136 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005137
5138 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5139 name = xstrdup(b);
5140
5141 str = xstrdup(p->l.t.v.v);
5142 bc_parse_push(p, BC_INST_STR);
5143 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005144 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005145 bc_parse_addFunc(p, name, &idx);
5146
5147 return bc_lex_next(&p->l);
5148}
5149
5150static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5151{
5152 BcStatus s;
5153
5154 bc_parse_push(p, inst);
5155 if (name) {
5156 s = dc_parse_register(p);
5157 if (s) return s;
5158 }
5159
5160 if (store) {
5161 bc_parse_push(p, BC_INST_SWAP);
5162 bc_parse_push(p, BC_INST_ASSIGN);
5163 bc_parse_push(p, BC_INST_POP);
5164 }
5165
5166 return bc_lex_next(&p->l);
5167}
5168
5169static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5170{
5171 BcStatus s;
5172
5173 bc_parse_push(p, inst);
5174 bc_parse_push(p, BC_INST_EXEC_COND);
5175
5176 s = dc_parse_register(p);
5177 if (s) return s;
5178
5179 s = bc_lex_next(&p->l);
5180 if (s) return s;
5181
5182 if (p->l.t.t == BC_LEX_ELSE) {
5183 s = dc_parse_register(p);
5184 if (s) return s;
5185 s = bc_lex_next(&p->l);
5186 }
5187 else
5188 bc_parse_push(p, BC_PARSE_STREND);
5189
5190 return s;
5191}
5192
5193static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5194{
5195 BcStatus s = BC_STATUS_SUCCESS;
5196 BcInst prev;
5197 uint8_t inst;
5198 bool assign, get_token = false;
5199
5200 switch (t) {
5201
5202 case BC_LEX_OP_REL_EQ:
5203 case BC_LEX_OP_REL_LE:
5204 case BC_LEX_OP_REL_GE:
5205 case BC_LEX_OP_REL_NE:
5206 case BC_LEX_OP_REL_LT:
5207 case BC_LEX_OP_REL_GT:
5208 {
5209 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5210 break;
5211 }
5212
5213 case BC_LEX_SCOLON:
5214 case BC_LEX_COLON:
5215 {
5216 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5217 break;
5218 }
5219
5220 case BC_LEX_STR:
5221 {
5222 s = dc_parse_string(p);
5223 break;
5224 }
5225
5226 case BC_LEX_NEG:
5227 case BC_LEX_NUMBER:
5228 {
5229 if (t == BC_LEX_NEG) {
5230 s = bc_lex_next(&p->l);
5231 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005232 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005233 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005234 }
5235
5236 bc_parse_number(p, &prev, &p->nbraces);
5237
5238 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5239 get_token = true;
5240
5241 break;
5242 }
5243
5244 case BC_LEX_KEY_READ:
5245 {
5246 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005247 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005248 else
5249 bc_parse_push(p, BC_INST_READ);
5250 get_token = true;
5251 break;
5252 }
5253
5254 case BC_LEX_OP_ASSIGN:
5255 case BC_LEX_STORE_PUSH:
5256 {
5257 assign = t == BC_LEX_OP_ASSIGN;
5258 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5259 s = dc_parse_mem(p, inst, true, assign);
5260 break;
5261 }
5262
5263 case BC_LEX_LOAD:
5264 case BC_LEX_LOAD_POP:
5265 {
5266 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5267 s = dc_parse_mem(p, inst, true, false);
5268 break;
5269 }
5270
5271 case BC_LEX_STORE_IBASE:
5272 case BC_LEX_STORE_SCALE:
5273 case BC_LEX_STORE_OBASE:
5274 {
5275 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5276 s = dc_parse_mem(p, inst, false, true);
5277 break;
5278 }
5279
5280 default:
5281 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005282 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005283 get_token = true;
5284 break;
5285 }
5286 }
5287
5288 if (!s && get_token) s = bc_lex_next(&p->l);
5289
5290 return s;
5291}
5292
5293static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5294{
5295 BcStatus s = BC_STATUS_SUCCESS;
5296 BcInst inst;
5297 BcLexType t;
5298
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005299 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005300
5301 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5302
5303 inst = dc_parse_insts[t];
5304
5305 if (inst != BC_INST_INVALID) {
5306 bc_parse_push(p, inst);
5307 s = bc_lex_next(&p->l);
5308 }
5309 else
5310 s = dc_parse_token(p, t, flags);
5311 }
5312
5313 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5314 bc_parse_push(p, BC_INST_POP_EXEC);
5315
5316 return s;
5317}
5318
5319static BcStatus dc_parse_parse(BcParse *p)
5320{
5321 BcStatus s;
5322
5323 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005324 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005325 else
5326 s = dc_parse_expr(p, 0);
5327
Denys Vlasenkod38af482018-12-04 19:11:02 +01005328 if (s || G_interrupt) {
5329 bc_parse_reset(p);
5330 s = BC_STATUS_FAILURE;
5331 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005332
5333 return s;
5334}
5335
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005336static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005337{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005338 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005339}
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005340
Gavin Howard01055ba2018-11-03 11:00:21 -06005341#endif // ENABLE_DC
5342
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005343static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005344{
5345 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005346 IF_BC(bc_parse_init(p, func);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005347 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005348 IF_DC(dc_parse_init(p, func);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005349 }
5350}
5351
5352static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5353{
5354 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005355 IF_BC(return bc_parse_expression(p, flags);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005356 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005357 IF_DC(return dc_parse_expr(p, flags);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005358 }
5359}
5360
Denys Vlasenkodf515392018-12-02 19:27:48 +01005361static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005362{
Gavin Howard01055ba2018-11-03 11:00:21 -06005363 BcId e, *ptr;
5364 BcVec *v, *map;
5365 size_t i;
5366 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005367 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005368
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005369 v = var ? &G.prog.vars : &G.prog.arrs;
5370 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005371
5372 e.name = id;
5373 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005374 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005375
5376 if (new) {
5377 bc_array_init(&data.v, var);
5378 bc_vec_push(v, &data.v);
5379 }
5380
5381 ptr = bc_vec_item(map, i);
5382 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005383 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005384}
5385
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005386static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005387{
5388 BcStatus s = BC_STATUS_SUCCESS;
5389
5390 switch (r->t) {
5391
5392 case BC_RESULT_STR:
5393 case BC_RESULT_TEMP:
5394 case BC_RESULT_IBASE:
5395 case BC_RESULT_SCALE:
5396 case BC_RESULT_OBASE:
5397 {
5398 *num = &r->d.n;
5399 break;
5400 }
5401
5402 case BC_RESULT_CONSTANT:
5403 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005404 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005405 size_t base_t, len = strlen(*str);
5406 BcNum *base;
5407
5408 bc_num_init(&r->d.n, len);
5409
5410 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005411 base = hex ? &G.prog.hexb : &G.prog.ib;
5412 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005413 s = bc_num_parse(&r->d.n, *str, base, base_t);
5414
5415 if (s) {
5416 bc_num_free(&r->d.n);
5417 return s;
5418 }
5419
5420 *num = &r->d.n;
5421 r->t = BC_RESULT_TEMP;
5422
5423 break;
5424 }
5425
5426 case BC_RESULT_VAR:
5427 case BC_RESULT_ARRAY:
5428 case BC_RESULT_ARRAY_ELEM:
5429 {
5430 BcVec *v;
5431
Denys Vlasenkodf515392018-12-02 19:27:48 +01005432 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005433
5434 if (r->t == BC_RESULT_ARRAY_ELEM) {
5435 v = bc_vec_top(v);
5436 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5437 *num = bc_vec_item(v, r->d.id.idx);
5438 }
5439 else
5440 *num = bc_vec_top(v);
5441
5442 break;
5443 }
5444
5445 case BC_RESULT_LAST:
5446 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005447 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005448 break;
5449 }
5450
5451 case BC_RESULT_ONE:
5452 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005453 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005454 break;
5455 }
5456 }
5457
5458 return s;
5459}
5460
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005461static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005462 BcResult **r, BcNum **rn, bool assign)
5463{
5464 BcStatus s;
5465 bool hex;
5466 BcResultType lt, rt;
5467
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005468 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005469 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005470
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005471 *r = bc_vec_item_rev(&G.prog.results, 0);
5472 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005473
5474 lt = (*l)->t;
5475 rt = (*r)->t;
5476 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5477
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005478 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005479 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005480 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005481 if (s) return s;
5482
5483 // We run this again under these conditions in case any vector has been
5484 // reallocated out from under the BcNums or arrays we had.
5485 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005486 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005487 if (s) return s;
5488 }
5489
5490 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005491 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005492 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005493 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005494
Gavin Howard01055ba2018-11-03 11:00:21 -06005495 return s;
5496}
5497
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005498static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005499{
5500 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005501 bc_vec_pop(&G.prog.results);
5502 bc_vec_pop(&G.prog.results);
5503 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005504}
5505
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005506static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005507{
5508 BcStatus s;
5509
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005510 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005511 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005512 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005513
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005514 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005515 if (s) return s;
5516
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005517 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005518 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005519
5520 return s;
5521}
5522
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005523static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005524{
5525 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005526 bc_vec_pop(&G.prog.results);
5527 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005528}
5529
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005530static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005531{
5532 BcStatus s;
5533 BcResult *opd1, *opd2, res;
5534 BcNum *n1, *n2 = NULL;
5535
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005536 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005537 if (s) return s;
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005538 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005539
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005540 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005541 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005542 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005543
5544 return s;
5545
5546err:
5547 bc_num_free(&res.d.n);
5548 return s;
5549}
5550
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005551static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005552{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005553 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005554 BcStatus s;
5555 BcParse parse;
5556 BcVec buf;
5557 BcInstPtr ip;
5558 size_t i;
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01005559 BcFunc *f = bc_program_func(BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005560
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005561 for (i = 0; i < G.prog.stack.len; ++i) {
5562 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005563 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005564 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005565 }
5566
Denys Vlasenko7d628012018-12-04 21:46:47 +01005567 bc_vec_pop_all(&f->code);
5568 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005569
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005570 sv_file = G.prog.file;
5571 G.prog.file = NULL;
5572
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +01005573 s = bc_read_line(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005574 if (s) goto io_err;
5575
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005576 common_parse_init(&parse, BC_PROG_READ);
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005577 bc_lex_file(&parse.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005578
5579 s = bc_parse_text(&parse, buf.v);
5580 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005581 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005582 if (s) goto exec_err;
5583
5584 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005585 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005586 goto exec_err;
5587 }
5588
5589 ip.func = BC_PROG_READ;
5590 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005591 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005592
5593 // Update this pointer, just in case.
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01005594 f = bc_program_func(BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005595
5596 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005597 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005598
5599exec_err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005600 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005601 bc_parse_free(&parse);
5602io_err:
5603 bc_vec_free(&buf);
5604 return s;
5605}
5606
5607static size_t bc_program_index(char *code, size_t *bgn)
5608{
5609 char amt = code[(*bgn)++], i = 0;
5610 size_t res = 0;
5611
5612 for (; i < amt; ++i, ++(*bgn))
5613 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5614
5615 return res;
5616}
5617
5618static char *bc_program_name(char *code, size_t *bgn)
5619{
5620 size_t i;
5621 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5622
5623 s = xmalloc(ptr - str + 1);
5624 c = code[(*bgn)++];
5625
5626 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5627 s[i] = c;
5628
5629 s[i] = '\0';
5630
5631 return s;
5632}
5633
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005634static void bc_program_printString(const char *str)
Gavin Howard01055ba2018-11-03 11:00:21 -06005635{
5636 size_t i, len = strlen(str);
5637
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005638#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005639 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005640 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005641 return;
5642 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005643#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005644
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005645 for (i = 0; i < len; ++i, ++G.prog.nchars) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005646
5647 int c = str[i];
5648
5649 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005650 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005651 else {
5652
5653 c = str[++i];
5654
5655 switch (c) {
5656
5657 case 'a':
5658 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005659 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005660 break;
5661 }
5662
5663 case 'b':
5664 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005665 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005666 break;
5667 }
5668
5669 case '\\':
5670 case 'e':
5671 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005672 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005673 break;
5674 }
5675
5676 case 'f':
5677 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005678 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005679 break;
5680 }
5681
5682 case 'n':
5683 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005684 bb_putchar('\n');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005685 G.prog.nchars = SIZE_MAX;
Gavin Howard01055ba2018-11-03 11:00:21 -06005686 break;
5687 }
5688
5689 case 'r':
5690 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005691 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005692 break;
5693 }
5694
5695 case 'q':
5696 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005697 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005698 break;
5699 }
5700
5701 case 't':
5702 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005703 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005704 break;
5705 }
5706
5707 default:
5708 {
5709 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005710 bb_putchar('\\');
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005711 ++G.prog.nchars;
Denys Vlasenko00d77792018-11-30 23:13:42 +01005712 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005713 break;
5714 }
5715 }
5716 }
5717 }
5718}
5719
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005720static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005721{
5722 BcStatus s = BC_STATUS_SUCCESS;
5723 BcResult *r;
5724 size_t len, i;
5725 char *str;
5726 BcNum *num = NULL;
5727 bool pop = inst != BC_INST_PRINT;
5728
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005729 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005730 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005731
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005732 r = bc_vec_item_rev(&G.prog.results, idx);
5733 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005734 if (s) return s;
5735
5736 if (BC_PROG_NUM(r, num)) {
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005737 s = bc_num_print(num, !pop);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005738 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005739 }
5740 else {
5741
5742 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01005743 str = *bc_program_str(idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005744
5745 if (inst == BC_INST_PRINT_STR) {
5746 for (i = 0, len = strlen(str); i < len; ++i) {
5747 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005748 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005749 if (c == '\n') G.prog.nchars = SIZE_MAX;
5750 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005751 }
5752 }
5753 else {
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01005754 bc_program_printString(str);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005755 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005756 }
5757 }
5758
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005759 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005760
5761 return s;
5762}
5763
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005764static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005765{
5766 BcStatus s;
5767 BcResult res, *ptr;
5768 BcNum *num = NULL;
5769
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005770 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005771 if (s) return s;
5772
5773 bc_num_init(&res.d.n, num->len);
5774 bc_num_copy(&res.d.n, num);
5775 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5776
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005777 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005778
5779 return s;
5780}
5781
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005782static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005783{
5784 BcStatus s;
5785 BcResult *opd1, *opd2, res;
5786 BcNum *n1, *n2;
5787 bool cond = 0;
5788 ssize_t cmp;
5789
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005790 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005791 if (s) return s;
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005792 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005793
5794 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005795 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005796 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005797 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005798 else {
5799
5800 cmp = bc_num_cmp(n1, n2);
5801
5802 switch (inst) {
5803
5804 case BC_INST_REL_EQ:
5805 {
5806 cond = cmp == 0;
5807 break;
5808 }
5809
5810 case BC_INST_REL_LE:
5811 {
5812 cond = cmp <= 0;
5813 break;
5814 }
5815
5816 case BC_INST_REL_GE:
5817 {
5818 cond = cmp >= 0;
5819 break;
5820 }
5821
5822 case BC_INST_REL_NE:
5823 {
5824 cond = cmp != 0;
5825 break;
5826 }
5827
5828 case BC_INST_REL_LT:
5829 {
5830 cond = cmp < 0;
5831 break;
5832 }
5833
5834 case BC_INST_REL_GT:
5835 {
5836 cond = cmp > 0;
5837 break;
5838 }
5839 }
5840 }
5841
5842 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5843
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005844 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005845
5846 return s;
5847}
5848
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005849#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005850static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005851 bool push)
5852{
5853 BcNum n2;
5854 BcResult res;
5855
5856 memset(&n2, 0, sizeof(BcNum));
5857 n2.rdx = res.d.id.idx = r->d.id.idx;
5858 res.t = BC_RESULT_STR;
5859
5860 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005861 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005862 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005863 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005864 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005865 }
5866
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005867 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005868
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005869 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005870 bc_vec_push(v, &n2);
5871
5872 return BC_STATUS_SUCCESS;
5873}
5874#endif // ENABLE_DC
5875
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005876static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005877{
5878 BcStatus s;
5879 BcResult *ptr, r;
5880 BcVec *v;
5881 BcNum *n;
5882
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005883 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005884 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005885
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005886 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005887 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005888 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005889 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005890
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005891#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005892 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005893 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005894 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005895#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005896
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005897 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005898 if (s) return s;
5899
5900 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005901 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005902
5903 if (var) {
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005904 bc_num_init_DEF_SIZE(&r.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005905 bc_num_copy(&r.d.n, n);
5906 }
5907 else {
5908 bc_array_init(&r.d.v, true);
5909 bc_array_copy(&r.d.v, (BcVec *) n);
5910 }
5911
5912 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005913 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005914
5915 return s;
5916}
5917
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005918static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005919{
5920 BcStatus s;
5921 BcResult *left, *right, res;
5922 BcNum *l = NULL, *r = NULL;
Gavin Howard01055ba2018-11-03 11:00:21 -06005923 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5924
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005925 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005926 if (s) return s;
5927
5928 ib = left->t == BC_RESULT_IBASE;
5929 sc = left->t == BC_RESULT_SCALE;
5930
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005931#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005932
5933 if (right->t == BC_RESULT_STR) {
5934
5935 BcVec *v;
5936
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005937 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005938 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005939 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005940
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005941 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005942 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005943#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005944
5945 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005946 return bc_error("bad assignment:"
5947 " left side must be scale,"
5948 " ibase, obase, last, var,"
5949 " or array element"
5950 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005951
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005952#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005953 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005954 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005955
5956 if (assign)
5957 bc_num_copy(l, r);
5958 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005959 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005960
5961 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005962#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005963 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005964#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005965
5966 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005967 static const char *const msg[] = {
Denys Vlasenko64074a12018-12-07 15:50:14 +01005968 "bad ibase; must be [2,16]", //BC_RESULT_IBASE
5969 "bad scale; must be [0,"BC_MAX_SCALE_STR"]", //BC_RESULT_SCALE
5970 NULL, //can't happen //BC_RESULT_LAST
5971 NULL, //can't happen //BC_RESULT_CONSTANT
5972 NULL, //can't happen //BC_RESULT_ONE
5973 "bad obase; must be [2,"BC_MAX_OBASE_STR"]", //BC_RESULT_OBASE
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005974 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005975 size_t *ptr;
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01005976 unsigned long val, max;
Gavin Howard01055ba2018-11-03 11:00:21 -06005977
5978 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005979 if (s)
5980 return s;
5981 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005982 if (sc) {
5983 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005984 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005985 }
5986 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005987 if (val < BC_NUM_MIN_BASE)
5988 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005989 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005990 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005991 }
5992
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005993 if (val > max)
5994 return bc_error(msg[s]);
5995 if (!sc)
5996 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005997
5998 *ptr = (size_t) val;
5999 s = BC_STATUS_SUCCESS;
6000 }
6001
6002 bc_num_init(&res.d.n, l->len);
6003 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006004 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006005
6006 return s;
6007}
6008
Denys Vlasenko416ce762018-12-02 20:57:17 +01006009#if !ENABLE_DC
6010#define bc_program_pushVar(code, bgn, pop, copy) \
6011 bc_program_pushVar(code, bgn)
6012// for bc, 'pop' and 'copy' are always false
6013#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006014static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006015 bool pop, bool copy)
6016{
6017 BcStatus s = BC_STATUS_SUCCESS;
6018 BcResult r;
6019 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06006020
6021 r.t = BC_RESULT_VAR;
6022 r.d.id.name = name;
6023
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006024#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01006025 {
6026 BcVec *v = bc_program_search(name, true);
6027 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006028
Denys Vlasenko416ce762018-12-02 20:57:17 +01006029 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006030
Denys Vlasenko416ce762018-12-02 20:57:17 +01006031 if (!BC_PROG_STACK(v, 2 - copy)) {
6032 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006033 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01006034 }
6035
Gavin Howard01055ba2018-11-03 11:00:21 -06006036 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01006037 name = NULL;
6038
6039 if (!BC_PROG_STR(num)) {
6040
6041 r.t = BC_RESULT_TEMP;
6042
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006043 bc_num_init_DEF_SIZE(&r.d.n);
Denys Vlasenko416ce762018-12-02 20:57:17 +01006044 bc_num_copy(&r.d.n, num);
6045 }
6046 else {
6047 r.t = BC_RESULT_STR;
6048 r.d.id.idx = num->rdx;
6049 }
6050
6051 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006052 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006053 }
6054#endif // ENABLE_DC
6055
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006056 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006057
6058 return s;
6059}
6060
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006061static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006062 char inst)
6063{
6064 BcStatus s = BC_STATUS_SUCCESS;
6065 BcResult r;
6066 BcNum *num;
6067
6068 r.d.id.name = bc_program_name(code, bgn);
6069
6070 if (inst == BC_INST_ARRAY) {
6071 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006072 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006073 }
6074 else {
6075
6076 BcResult *operand;
6077 unsigned long temp;
6078
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006079 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006080 if (s) goto err;
6081 s = bc_num_ulong(num, &temp);
6082 if (s) goto err;
6083
6084 if (temp > BC_MAX_DIM) {
Denys Vlasenko64074a12018-12-07 15:50:14 +01006085 s = bc_error("array too long; must be [1,"BC_MAX_DIM_STR"]");
Gavin Howard01055ba2018-11-03 11:00:21 -06006086 goto err;
6087 }
6088
6089 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006090 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06006091 }
6092
6093err:
6094 if (s) free(r.d.id.name);
6095 return s;
6096}
6097
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006098#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006099static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006100{
6101 BcStatus s;
6102 BcResult *ptr, res, copy;
6103 BcNum *num = NULL;
6104 char inst2 = inst;
6105
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006106 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006107 if (s) return s;
6108
6109 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6110 copy.t = BC_RESULT_TEMP;
6111 bc_num_init(&copy.d.n, num->len);
6112 bc_num_copy(&copy.d.n, num);
6113 }
6114
6115 res.t = BC_RESULT_ONE;
6116 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6117 BC_INST_ASSIGN_PLUS :
6118 BC_INST_ASSIGN_MINUS;
6119
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006120 bc_vec_push(&G.prog.results, &res);
6121 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006122
6123 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006124 bc_vec_pop(&G.prog.results);
6125 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006126 }
6127
6128 return s;
6129}
6130
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006131static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006132{
6133 BcStatus s = BC_STATUS_SUCCESS;
6134 BcInstPtr ip;
6135 size_t i, nparams = bc_program_index(code, idx);
6136 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006137 BcId *a;
6138 BcResultData param;
6139 BcResult *arg;
6140
6141 ip.idx = 0;
6142 ip.func = bc_program_index(code, idx);
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006143 func = bc_program_func(ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006144
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006145 if (func->code.len == 0) {
6146 return bc_error("undefined function");
6147 }
6148 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006149 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006150 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006151 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006152
6153 for (i = 0; i < nparams; ++i) {
6154
6155 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006156 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006157
6158 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006159 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006160
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006161 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006162 if (s) return s;
6163 }
6164
6165 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006166 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006167
6168 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006169 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006170
6171 if (a->idx) {
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006172 bc_num_init_DEF_SIZE(&param.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006173 bc_vec_push(v, &param.n);
6174 }
6175 else {
6176 bc_array_init(&param.v, true);
6177 bc_vec_push(v, &param.v);
6178 }
6179 }
6180
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006181 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006182
6183 return BC_STATUS_SUCCESS;
6184}
6185
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006186static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006187{
6188 BcStatus s;
6189 BcResult res;
6190 BcFunc *f;
6191 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006192 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006193
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006194 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006195 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006196
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006197 f = bc_program_func(ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006198 res.t = BC_RESULT_TEMP;
6199
6200 if (inst == BC_INST_RET) {
6201
6202 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006203 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006204
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006205 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006206 if (s) return s;
6207 bc_num_init(&res.d.n, num->len);
6208 bc_num_copy(&res.d.n, num);
6209 }
6210 else {
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006211 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006212 bc_num_zero(&res.d.n);
6213 }
6214
6215 // We need to pop arguments as well, so this takes that into account.
6216 for (i = 0; i < f->autos.len; ++i) {
6217
6218 BcVec *v;
6219 BcId *a = bc_vec_item(&f->autos, i);
6220
Denys Vlasenkodf515392018-12-02 19:27:48 +01006221 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006222 bc_vec_pop(v);
6223 }
6224
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006225 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6226 bc_vec_push(&G.prog.results, &res);
6227 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006228
6229 return BC_STATUS_SUCCESS;
6230}
6231#endif // ENABLE_BC
6232
6233static unsigned long bc_program_scale(BcNum *n)
6234{
6235 return (unsigned long) n->rdx;
6236}
6237
6238static unsigned long bc_program_len(BcNum *n)
6239{
6240 unsigned long len = n->len;
6241 size_t i;
6242
6243 if (n->rdx != n->len) return len;
6244 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6245
6246 return len;
6247}
6248
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006249static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006250{
6251 BcStatus s;
6252 BcResult *opnd;
6253 BcNum *num = NULL;
6254 BcResult res;
6255 bool len = inst == BC_INST_LENGTH;
6256
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006257 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006258 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006259 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006260
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006261 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006262 if (s) return s;
6263
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006264#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006265 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006266 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006267#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006268
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006269 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006270
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006271 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006272#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006273 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006274 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006275 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006276#endif
6277#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006278 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6279
6280 char **str;
6281 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6282
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006283 str = bc_program_str(idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006284 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006285 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006286#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006287 else {
6288 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006289 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006290 }
6291
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006292 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006293
6294 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006295}
6296
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006297#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006298static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006299{
6300 BcStatus s;
6301 BcResult *opd1, *opd2, res, res2;
6302 BcNum *n1, *n2 = NULL;
6303
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006304 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006305 if (s) return s;
6306
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006307 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006308 bc_num_init(&res2.d.n, n2->len);
6309
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006310 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006311 if (s) goto err;
6312
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006313 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006314 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006315 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006316
6317 return s;
6318
6319err:
6320 bc_num_free(&res2.d.n);
6321 bc_num_free(&res.d.n);
6322 return s;
6323}
6324
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006325static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006326{
6327 BcStatus s;
6328 BcResult *r1, *r2, *r3, res;
6329 BcNum *n1, *n2, *n3;
6330
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006331 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006332 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006333 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006334 if (s) return s;
6335
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006336 r1 = bc_vec_item_rev(&G.prog.results, 2);
6337 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006338 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006339 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006340 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006341
6342 // Make sure that the values have their pointers updated, if necessary.
6343 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6344
6345 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006346 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006347 if (s) return s;
6348 }
6349
6350 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006351 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006352 if (s) return s;
6353 }
6354 }
6355
6356 bc_num_init(&res.d.n, n3->len);
6357 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6358 if (s) goto err;
6359
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006360 bc_vec_pop(&G.prog.results);
6361 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006362
6363 return s;
6364
6365err:
6366 bc_num_free(&res.d.n);
6367 return s;
6368}
6369
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006370static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006371{
Gavin Howard01055ba2018-11-03 11:00:21 -06006372 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006373 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006374
6375 res.t = BC_RESULT_TEMP;
6376
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006377 bc_num_init_DEF_SIZE(&res.d.n);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006378 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006379 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006380}
6381
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006382static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006383{
6384 BcStatus s;
6385 BcResult *r, res;
6386 BcNum *num = NULL, n;
6387 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006388 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006389 unsigned long val;
6390
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006391 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006392 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006393 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006394
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006395 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006396 if (s) return s;
6397
6398 if (BC_PROG_NUM(r, num)) {
6399
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006400 bc_num_init_DEF_SIZE(&n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006401 bc_num_copy(&n, num);
6402 bc_num_truncate(&n, n.rdx);
6403
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006404 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006405 if (s) goto num_err;
6406 s = bc_num_ulong(&n, &val);
6407 if (s) goto num_err;
6408
6409 c = (char) val;
6410
6411 bc_num_free(&n);
6412 }
6413 else {
6414 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006415 str2 = *bc_program_str(idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006416 c = str2[0];
6417 }
6418
6419 str = xmalloc(2);
6420 str[0] = c;
6421 str[1] = '\0';
6422
6423 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006424 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006425
6426 if (idx != len + BC_PROG_REQ_FUNCS) {
6427
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006428 for (idx = 0; idx < G.prog.strs.len; ++idx) {
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006429 if (strcmp(*bc_program_str(idx), str) == 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006430 len = idx;
6431 break;
6432 }
6433 }
6434
6435 free(str);
6436 }
6437 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006438 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006439
6440 res.t = BC_RESULT_STR;
6441 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006442 bc_vec_pop(&G.prog.results);
6443 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006444
6445 return BC_STATUS_SUCCESS;
6446
6447num_err:
6448 bc_num_free(&n);
6449 return s;
6450}
6451
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006452static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006453{
6454 BcStatus s;
6455 BcResult *r;
6456 BcNum *n = NULL;
6457 size_t idx;
6458 char *str;
6459
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006460 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006461 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006462 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006463
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006464 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006465 if (s) return s;
6466
6467 if (BC_PROG_NUM(r, n))
Denys Vlasenko5f1b90b2018-12-08 23:18:06 +01006468 s = bc_num_stream(n, &G.prog.strmb);
Gavin Howard01055ba2018-11-03 11:00:21 -06006469 else {
6470 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006471 str = *bc_program_str(idx);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006472 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006473 }
6474
6475 return s;
6476}
6477
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006478static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006479{
6480 BcStatus s;
6481 BcResult *opnd;
6482 BcNum *num = NULL;
6483 unsigned long val;
6484
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006485 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006486 if (s) return s;
6487 s = bc_num_ulong(num, &val);
6488 if (s) return s;
6489
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006490 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006491
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006492 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006493 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01006494 if (G.prog.stack.len == val) {
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006495 QUIT_OR_RETURN_TO_MAIN;
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01006496 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006497
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006498 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006499
6500 return s;
6501}
6502
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006503static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006504 bool cond)
6505{
6506 BcStatus s = BC_STATUS_SUCCESS;
6507 BcResult *r;
6508 char **str;
6509 BcFunc *f;
6510 BcParse prs;
6511 BcInstPtr ip;
6512 size_t fidx, sidx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006513
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006514 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006515 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006516
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006517 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006518
6519 if (cond) {
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006520 BcNum *n = n; // for compiler
6521 bool exec;
6522 char *name;
6523 char *then_name = bc_program_name(code, bgn);
6524 char *else_name = NULL;
Gavin Howard01055ba2018-11-03 11:00:21 -06006525
6526 if (code[*bgn] == BC_PARSE_STREND)
6527 (*bgn) += 1;
6528 else
6529 else_name = bc_program_name(code, bgn);
6530
6531 exec = r->d.n.len != 0;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006532 name = then_name;
6533 if (!exec && else_name != NULL) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006534 exec = true;
6535 name = else_name;
6536 }
6537
6538 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006539 BcVec *v;
6540 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006541 n = bc_vec_top(v);
6542 }
6543
6544 free(then_name);
6545 free(else_name);
6546
6547 if (!exec) goto exit;
6548 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006549 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006550 goto exit;
6551 }
6552
6553 sidx = n->rdx;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006554 } else {
6555 if (r->t == BC_RESULT_STR) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 sidx = r->d.id.idx;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006557 } else if (r->t == BC_RESULT_VAR) {
6558 BcNum *n;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006559 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006560 if (s || !BC_PROG_STR(n)) goto exit;
6561 sidx = n->rdx;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006562 } else
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 goto exit;
6564 }
6565
6566 fidx = sidx + BC_PROG_REQ_FUNCS;
6567
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006568 str = bc_program_str(sidx);
6569 f = bc_program_func(fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006570
6571 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006572 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006573 s = bc_parse_text(&prs, *str);
6574 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006575 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006576 if (s) goto err;
6577
6578 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006579 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 goto err;
6581 }
6582
6583 bc_parse_free(&prs);
6584 }
6585
6586 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006587 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006588 ip.func = fidx;
6589
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006590 bc_vec_pop(&G.prog.results);
6591 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006592
6593 return BC_STATUS_SUCCESS;
6594
6595err:
6596 bc_parse_free(&prs);
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006597 f = bc_program_func(fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006598 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006599exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006600 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006601 return s;
6602}
6603#endif // ENABLE_DC
6604
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006605static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006606{
Gavin Howard01055ba2018-11-03 11:00:21 -06006607 BcResult res;
6608 unsigned long val;
6609
6610 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6611 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006612 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006613 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006614 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006615 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006616 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006617
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006618 bc_num_init_DEF_SIZE(&res.d.n);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006619 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006620 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006621}
6622
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006623static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006624{
Gavin Howard01055ba2018-11-03 11:00:21 -06006625 BcId entry, *entry_ptr;
6626 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006627 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006628
6629 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006630 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006631
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006632 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6633 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006634
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006635 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006636 *idx = entry_ptr->idx;
6637
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006638 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006639
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006640 BcFunc *func = bc_program_func(entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006641
6642 // We need to reset these, so the function can be repopulated.
6643 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006644 bc_vec_pop_all(&func->autos);
6645 bc_vec_pop_all(&func->code);
6646 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006647 }
6648 else {
6649 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006650 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006651 }
6652}
6653
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006654static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006655{
Gavin Howard01055ba2018-11-03 11:00:21 -06006656 BcResult r, *ptr;
6657 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006658 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006659 BcFunc *func = bc_program_func(ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006660 char *code = func->code.v;
6661 bool cond = false;
6662
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006663 while (ip->idx < func->code.len) {
6664 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006665 char inst = code[(ip->idx)++];
6666
6667 switch (inst) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006668#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006669 case BC_INST_JUMP_ZERO:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006670 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006671 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006672 cond = !bc_num_cmp(num, &G.prog.zero);
6673 bc_vec_pop(&G.prog.results);
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006674 // Fallthrough.
6675 case BC_INST_JUMP: {
Gavin Howard01055ba2018-11-03 11:00:21 -06006676 size_t *addr;
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006677 size_t idx = bc_program_index(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006678 addr = bc_vec_item(&func->labels, idx);
6679 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6680 break;
6681 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006682 case BC_INST_CALL:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006683 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006684 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006685 case BC_INST_INC_PRE:
6686 case BC_INST_DEC_PRE:
6687 case BC_INST_INC_POST:
6688 case BC_INST_DEC_POST:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006689 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006690 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006691 case BC_INST_HALT:
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006692 QUIT_OR_RETURN_TO_MAIN;
Gavin Howard01055ba2018-11-03 11:00:21 -06006693 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006694 case BC_INST_RET:
6695 case BC_INST_RET0:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006696 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006697 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006698 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:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006707 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006708 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006709 case BC_INST_READ:
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006710 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006711 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006712 case BC_INST_VAR:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006713 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006714 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006715 case BC_INST_ARRAY_ELEM:
6716 case BC_INST_ARRAY:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006717 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006718 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006719 case BC_INST_LAST:
Gavin Howard01055ba2018-11-03 11:00:21 -06006720 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006721 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006722 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006723 case BC_INST_IBASE:
6724 case BC_INST_SCALE:
6725 case BC_INST_OBASE:
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006726 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006727 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006728 case BC_INST_SCALE_FUNC:
6729 case BC_INST_LENGTH:
6730 case BC_INST_SQRT:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006731 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006732 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006733 case BC_INST_NUM:
Gavin Howard01055ba2018-11-03 11:00:21 -06006734 r.t = BC_RESULT_CONSTANT;
6735 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006736 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006737 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006738 case BC_INST_POP:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006739 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006740 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006741 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006742 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006743 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006744 case BC_INST_POP_EXEC:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006745 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006746 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006747 case BC_INST_PRINT:
6748 case BC_INST_PRINT_POP:
6749 case BC_INST_PRINT_STR:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006750 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006751 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006752 case BC_INST_STR:
Gavin Howard01055ba2018-11-03 11:00:21 -06006753 r.t = BC_RESULT_STR;
6754 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006755 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006756 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006757 case BC_INST_POWER:
6758 case BC_INST_MULTIPLY:
6759 case BC_INST_DIVIDE:
6760 case BC_INST_MODULUS:
6761 case BC_INST_PLUS:
6762 case BC_INST_MINUS:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006763 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006764 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006765 case BC_INST_BOOL_NOT:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006766 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006767 if (s) return s;
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006768 bc_num_init_DEF_SIZE(&r.d.n);
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006769 if (!bc_num_cmp(num, &G.prog.zero))
6770 bc_num_one(&r.d.n);
6771 else
6772 bc_num_zero(&r.d.n);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006773 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006774 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006775 case BC_INST_NEG:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006776 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006777 break;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006778#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006779 case BC_INST_ASSIGN_POWER:
6780 case BC_INST_ASSIGN_MULTIPLY:
6781 case BC_INST_ASSIGN_DIVIDE:
6782 case BC_INST_ASSIGN_MODULUS:
6783 case BC_INST_ASSIGN_PLUS:
6784 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006785#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006786 case BC_INST_ASSIGN:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006787 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006788 break;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006789#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 case BC_INST_MODEXP:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006791 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006792 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006793 case BC_INST_DIVMOD:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006794 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006795 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 case BC_INST_EXECUTE:
6797 case BC_INST_EXEC_COND:
Gavin Howard01055ba2018-11-03 11:00:21 -06006798 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006799 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006800 break;
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006801 case BC_INST_PRINT_STACK: {
6802 size_t idx;
6803 for (idx = 0; idx < G.prog.results.len; ++idx) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006804 s = bc_program_print(BC_INST_PRINT, idx);
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006805 if (s) break;
6806 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006807 break;
6808 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006809 case BC_INST_CLEAR_STACK:
Denys Vlasenko7d628012018-12-04 21:46:47 +01006810 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006811 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006812 case BC_INST_STACK_LEN:
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006813 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006814 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006815 case BC_INST_DUPLICATE:
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006816 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006817 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006818 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006819 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006820 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006821 break;
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006822 case BC_INST_SWAP: {
Gavin Howard01055ba2018-11-03 11:00:21 -06006823 BcResult *ptr2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006824 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006825 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006826 ptr = bc_vec_item_rev(&G.prog.results, 0);
6827 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006828 memcpy(&r, ptr, sizeof(BcResult));
6829 memcpy(ptr, ptr2, sizeof(BcResult));
6830 memcpy(ptr2, &r, sizeof(BcResult));
Gavin Howard01055ba2018-11-03 11:00:21 -06006831 break;
6832 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006833 case BC_INST_ASCIIFY:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006834 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006835 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006836 case BC_INST_PRINT_STREAM:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006837 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006838 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006839 case BC_INST_LOAD:
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006840 case BC_INST_PUSH_VAR: {
Gavin Howard01055ba2018-11-03 11:00:21 -06006841 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006842 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006843 break;
6844 }
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006845 case BC_INST_PUSH_TO_VAR: {
Gavin Howard01055ba2018-11-03 11:00:21 -06006846 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006847 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006848 free(name);
6849 break;
6850 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006851 case BC_INST_QUIT:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006852 if (G.prog.stack.len <= 2)
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006853 QUIT_OR_RETURN_TO_MAIN;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006854 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006855 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006856 case BC_INST_NQUIT:
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006857 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006858 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006859#endif // ENABLE_DC
6860 }
6861
Denys Vlasenkod38af482018-12-04 19:11:02 +01006862 if (s || G_interrupt) {
6863 bc_program_reset();
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006864 return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01006865 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006866
6867 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006868 ip = bc_vec_top(&G.prog.stack);
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01006869 func = bc_program_func(ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006870 code = func->code.v;
6871 }
6872
Denys Vlasenko927a7d62018-12-09 02:24:14 +01006873 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06006874}
6875
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006876#if ENABLE_BC
Denys Vlasenko54214c32018-12-06 09:07:06 +01006877static void bc_vm_info(void)
6878{
6879 printf("%s "BB_VER"\n"
6880 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko54214c32018-12-06 09:07:06 +01006881 , applet_name);
6882}
6883
6884static void bc_args(char **argv)
6885{
6886 unsigned opts;
6887 int i;
6888
6889 GETOPT_RESET();
6890#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006891 opts = option_mask32 |= getopt32long(argv, "wvsqli",
Denys Vlasenko54214c32018-12-06 09:07:06 +01006892 "warn\0" No_argument "w"
6893 "version\0" No_argument "v"
6894 "standard\0" No_argument "s"
6895 "quiet\0" No_argument "q"
6896 "mathlib\0" No_argument "l"
6897 "interactive\0" No_argument "i"
6898 );
6899#else
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006900 opts = option_mask32 |= getopt32(argv, "wvsqli");
Denys Vlasenko54214c32018-12-06 09:07:06 +01006901#endif
6902 if (getenv("POSIXLY_CORRECT"))
6903 option_mask32 |= BC_FLAG_S;
6904
Denys Vlasenko54214c32018-12-06 09:07:06 +01006905 if (opts & BC_FLAG_V) {
6906 bc_vm_info();
6907 exit(0);
6908 }
6909
6910 for (i = optind; argv[i]; ++i)
6911 bc_vec_push(&G.files, argv + i);
6912}
6913
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006914static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006915{
Gavin Howard01055ba2018-11-03 11:00:21 -06006916 BcVec v;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006917 char *buf;
Denys Vlasenko54214c32018-12-06 09:07:06 +01006918 char *env_args = getenv("BC_ENV_ARGS");
Gavin Howard01055ba2018-11-03 11:00:21 -06006919
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006920 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006921
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006922 G.env_args = xstrdup(env_args);
6923 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006924
6925 bc_vec_init(&v, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006926
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006927 while (*(buf = skip_whitespace(buf)) != '\0') {
6928 bc_vec_push(&v, &buf);
6929 buf = skip_non_whitespace(buf);
6930 if (!*buf)
6931 break;
6932 *buf++ = '\0';
Gavin Howard01055ba2018-11-03 11:00:21 -06006933 }
6934
Denys Vlasenko54214c32018-12-06 09:07:06 +01006935 // NULL terminate, and pass argv[] so that first arg is argv[1]
6936 if (sizeof(int) == sizeof(char*)) {
6937 bc_vec_push(&v, &const_int_0);
6938 } else {
6939 static char *const nullptr = NULL;
6940 bc_vec_push(&v, &nullptr);
6941 }
6942 bc_args(((char **)v.v) - 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006943
6944 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006945}
6946#endif // ENABLE_BC
6947
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006948static unsigned bc_vm_envLen(const char *var)
Gavin Howard01055ba2018-11-03 11:00:21 -06006949{
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006950 char *lenv;
6951 unsigned len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006952
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006953 lenv = getenv(var);
6954 len = BC_NUM_PRINT_WIDTH;
Gavin Howard01055ba2018-11-03 11:00:21 -06006955 if (!lenv) return len;
6956
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006957 len = bb_strtou(lenv, NULL, 10) - 1;
6958 if (errno || len < 2 || len >= INT_MAX)
Gavin Howard01055ba2018-11-03 11:00:21 -06006959 len = BC_NUM_PRINT_WIDTH;
6960
6961 return len;
6962}
6963
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006964static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006965{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006966 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006967
Gavin Howard01055ba2018-11-03 11:00:21 -06006968 if (s) return s;
6969
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006970 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006971 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006972 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006973 }
6974
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006975 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006976 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006977 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006978 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006979 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006980 }
6981
6982 return s;
6983}
6984
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006985static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006986{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006987 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06006988 char *data;
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006989 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006990 BcFunc *main_func;
6991 BcInstPtr *ip;
6992
Denys Vlasenkodf515392018-12-02 19:27:48 +01006993 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006994 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006995
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006996 sv_file = G.prog.file;
6997 G.prog.file = file;
6998 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006999 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007000 if (s) goto err;
7001
Denys Vlasenko8fa1e8e2018-12-09 00:03:57 +01007002 main_func = bc_program_func(BC_PROG_MAIN);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007003 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007004
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007005 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01007006 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007007
7008err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007009 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06007010 free(data);
7011 return s;
7012}
7013
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007014static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007015{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007016 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007017 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007018 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007019 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007020
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007021 G.prog.file = NULL;
7022 bc_lex_file(&G.prs.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06007023
Denys Vlasenko7d628012018-12-04 21:46:47 +01007024 bc_char_vec_init(&buffer);
7025 bc_char_vec_init(&buf);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01007026 bc_vec_pushZeroByte(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007027
7028 // This loop is complex because the vm tries not to send any lines that end
7029 // with a backslash to the parser. The reason for that is because the parser
7030 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7031 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +01007032 while ((s = bc_read_line(&buf)) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007033
7034 char *string = buf.v;
7035
7036 len = buf.len - 1;
7037
7038 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007039 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007040 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007041 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007042 str += 1;
7043 }
7044 else if (len > 1 || comment) {
7045
7046 for (i = 0; i < len; ++i) {
7047
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007048 bool notend = len > i + 1;
7049 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007050
7051 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007052 if (G.sbgn == G.send)
7053 str ^= c == G.sbgn;
7054 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007055 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007056 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007057 str += 1;
7058 }
7059
7060 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7061 comment = true;
7062 break;
7063 }
7064 else if (c == '*' && notend && comment && string[i + 1] == '/')
7065 comment = false;
7066 }
7067
7068 if (str || comment || string[len - 2] == '\\') {
7069 bc_vec_concat(&buffer, buf.v);
7070 continue;
7071 }
7072 }
7073
7074 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007075 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007076 if (s) {
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007077 if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin) {
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007078 // Debug config, non-interactive mode:
7079 // return all the way back to main.
7080 // Non-debug builds do not come here, they exit.
7081 break;
7082 }
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007083 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007084
Denys Vlasenko7d628012018-12-04 21:46:47 +01007085 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007086 }
Denys Vlasenkof522dd92018-12-07 16:35:43 +01007087 if (s == BC_STATUS_EOF) // input EOF (^D) is not an error
7088 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06007089
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007090 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007091 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007092 }
7093 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007094 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007095 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007096
Gavin Howard01055ba2018-11-03 11:00:21 -06007097 bc_vec_free(&buf);
7098 bc_vec_free(&buffer);
7099 return s;
7100}
7101
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007102#if ENABLE_BC
7103static const char bc_lib[] = {
7104 "scale=20"
7105"\n" "define e(x){"
7106"\n" "auto b,s,n,r,d,i,p,f,v"
7107"\n" "b=ibase"
7108"\n" "ibase=A"
7109"\n" "if(x<0){"
7110"\n" "n=1"
7111"\n" "x=-x"
7112"\n" "}"
7113"\n" "s=scale"
7114"\n" "r=6+s+0.44*x"
7115"\n" "scale=scale(x)+1"
7116"\n" "while(x>1){"
7117"\n" "d+=1"
7118"\n" "x/=2"
7119"\n" "scale+=1"
7120"\n" "}"
7121"\n" "scale=r"
7122"\n" "r=x+1"
7123"\n" "p=x"
7124"\n" "f=v=1"
7125"\n" "for(i=2;v!=0;++i){"
7126"\n" "p*=x"
7127"\n" "f*=i"
7128"\n" "v=p/f"
7129"\n" "r+=v"
7130"\n" "}"
7131"\n" "while((d--)!=0)r*=r"
7132"\n" "scale=s"
7133"\n" "ibase=b"
7134"\n" "if(n!=0)return(1/r)"
7135"\n" "return(r/1)"
7136"\n" "}"
7137"\n" "define l(x){"
7138"\n" "auto b,s,r,p,a,q,i,v"
7139"\n" "b=ibase"
7140"\n" "ibase=A"
7141"\n" "if(x<=0){"
7142"\n" "r=(1-10^scale)/1"
7143"\n" "ibase=b"
7144"\n" "return(r)"
7145"\n" "}"
7146"\n" "s=scale"
7147"\n" "scale+=6"
7148"\n" "p=2"
7149"\n" "while(x>=2){"
7150"\n" "p*=2"
7151"\n" "x=sqrt(x)"
7152"\n" "}"
7153"\n" "while(x<=0.5){"
7154"\n" "p*=2"
7155"\n" "x=sqrt(x)"
7156"\n" "}"
7157"\n" "r=a=(x-1)/(x+1)"
7158"\n" "q=a*a"
7159"\n" "v=1"
7160"\n" "for(i=3;v!=0;i+=2){"
7161"\n" "a*=q"
7162"\n" "v=a/i"
7163"\n" "r+=v"
7164"\n" "}"
7165"\n" "r*=p"
7166"\n" "scale=s"
7167"\n" "ibase=b"
7168"\n" "return(r/1)"
7169"\n" "}"
7170"\n" "define s(x){"
7171"\n" "auto b,s,r,n,a,q,i"
7172"\n" "b=ibase"
7173"\n" "ibase=A"
7174"\n" "s=scale"
7175"\n" "scale=1.1*s+2"
7176"\n" "a=a(1)"
7177"\n" "if(x<0){"
7178"\n" "n=1"
7179"\n" "x=-x"
7180"\n" "}"
7181"\n" "scale=0"
7182"\n" "q=(x/a+2)/4"
7183"\n" "x=x-4*q*a"
7184"\n" "if(q%2!=0)x=-x"
7185"\n" "scale=s+2"
7186"\n" "r=a=x"
7187"\n" "q=-x*x"
7188"\n" "for(i=3;a!=0;i+=2){"
7189"\n" "a*=q/(i*(i-1))"
7190"\n" "r+=a"
7191"\n" "}"
7192"\n" "scale=s"
7193"\n" "ibase=b"
7194"\n" "if(n!=0)return(-r/1)"
7195"\n" "return(r/1)"
7196"\n" "}"
7197"\n" "define c(x){"
7198"\n" "auto b,s"
7199"\n" "b=ibase"
7200"\n" "ibase=A"
7201"\n" "s=scale"
7202"\n" "scale*=1.2"
7203"\n" "x=s(2*a(1)+x)"
7204"\n" "scale=s"
7205"\n" "ibase=b"
7206"\n" "return(x/1)"
7207"\n" "}"
7208"\n" "define a(x){"
7209"\n" "auto b,s,r,n,a,m,t,f,i,u"
7210"\n" "b=ibase"
7211"\n" "ibase=A"
7212"\n" "n=1"
7213"\n" "if(x<0){"
7214"\n" "n=-1"
7215"\n" "x=-x"
7216"\n" "}"
7217"\n" "if(x==1){"
7218"\n" "if(scale<65){"
7219"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7220"\n" "}"
7221"\n" "}"
7222"\n" "if(x==.2){"
7223"\n" "if(scale<65){"
7224"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7225"\n" "}"
7226"\n" "}"
7227"\n" "s=scale"
7228"\n" "if(x>.2){"
7229"\n" "scale+=5"
7230"\n" "a=a(.2)"
7231"\n" "}"
7232"\n" "scale=s+3"
7233"\n" "while(x>.2){"
7234"\n" "m+=1"
7235"\n" "x=(x-.2)/(1+.2*x)"
7236"\n" "}"
7237"\n" "r=u=x"
7238"\n" "f=-x*x"
7239"\n" "t=1"
7240"\n" "for(i=3;t!=0;i+=2){"
7241"\n" "u*=f"
7242"\n" "t=u/i"
7243"\n" "r+=t"
7244"\n" "}"
7245"\n" "scale=s"
7246"\n" "ibase=b"
7247"\n" "return((m*a+r)/n)"
7248"\n" "}"
7249"\n" "define j(n,x){"
7250"\n" "auto b,s,o,a,i,v,f"
7251"\n" "b=ibase"
7252"\n" "ibase=A"
7253"\n" "s=scale"
7254"\n" "scale=0"
7255"\n" "n/=1"
7256"\n" "if(n<0){"
7257"\n" "n=-n"
7258"\n" "if(n%2==1)o=1"
7259"\n" "}"
7260"\n" "a=1"
7261"\n" "for(i=2;i<=n;++i)a*=i"
7262"\n" "scale=1.5*s"
7263"\n" "a=(x^n)/2^n/a"
7264"\n" "r=v=1"
7265"\n" "f=-x*x/4"
7266"\n" "scale=scale+length(a)-scale(a)"
7267"\n" "for(i=1;v!=0;++i){"
7268"\n" "v=v*f/i/(n+i)"
7269"\n" "r+=v"
7270"\n" "}"
7271"\n" "scale=s"
7272"\n" "ibase=b"
7273"\n" "if(o!=0)a=-a"
7274"\n" "return(a*r/1)"
7275"\n" "}"
7276};
7277#endif // ENABLE_BC
7278
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007279static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007280{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007281 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007282 size_t i;
7283
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007284#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007285 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007286
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007287 // We know that internal library is not buggy,
7288 // thus error checking is normally disabled.
7289# define DEBUG_LIB 0
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007290 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007291 s = bc_parse_text(&G.prs, bc_lib);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007292 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007293
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007294 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007295 s = G.prs.parse(&G.prs);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007296 if (DEBUG_LIB && s) return s;
7297 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007298 s = bc_program_exec();
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007299 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007300 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007301#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007302
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007303 s = BC_STATUS_SUCCESS;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007304 for (i = 0; !s && i < G.files.len; ++i)
7305 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007306 if (ENABLE_FEATURE_CLEAN_UP && s && !G_ttyin) {
7307 // Debug config, non-interactive mode:
7308 // return all the way back to main.
7309 // Non-debug builds do not come here, they exit.
7310 return s;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007311 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007312
Denys Vlasenkoac6ed112018-12-08 21:39:10 +01007313 if (IS_BC || (option_mask32 & BC_FLAG_I))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007314 s = bc_vm_stdin();
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007315
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007316 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7317 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007318
Denys Vlasenko00d77792018-11-30 23:13:42 +01007319 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007320}
7321
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007322#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007323static void bc_program_free(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007324{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007325 bc_num_free(&G.prog.ib);
7326 bc_num_free(&G.prog.ob);
7327 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007328# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007329 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007330# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007331 bc_vec_free(&G.prog.fns);
7332 bc_vec_free(&G.prog.fn_map);
7333 bc_vec_free(&G.prog.vars);
7334 bc_vec_free(&G.prog.var_map);
7335 bc_vec_free(&G.prog.arrs);
7336 bc_vec_free(&G.prog.arr_map);
7337 bc_vec_free(&G.prog.strs);
7338 bc_vec_free(&G.prog.consts);
7339 bc_vec_free(&G.prog.results);
7340 bc_vec_free(&G.prog.stack);
7341 bc_num_free(&G.prog.last);
7342 bc_num_free(&G.prog.zero);
7343 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007344}
7345
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007346static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007347{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007348 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007349 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007350 bc_parse_free(&G.prs);
7351 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007352}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007353#endif
7354
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007355static void bc_program_init(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007356{
7357 size_t idx;
7358 BcInstPtr ip;
7359
7360 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7361 memset(&ip, 0, sizeof(BcInstPtr));
7362
7363 /* G.prog.nchars = G.prog.scale = 0; - already is */
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007364 bc_num_init_DEF_SIZE(&G.prog.ib);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007365 bc_num_ten(&G.prog.ib);
7366 G.prog.ib_t = 10;
7367
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007368 bc_num_init_DEF_SIZE(&G.prog.ob);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007369 bc_num_ten(&G.prog.ob);
7370 G.prog.ob_t = 10;
7371
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007372 bc_num_init_DEF_SIZE(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007373 bc_num_ten(&G.prog.hexb);
7374 G.prog.hexb.num[0] = 6;
7375
7376#if ENABLE_DC
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007377 bc_num_init_DEF_SIZE(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007378 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7379#endif
7380
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007381 bc_num_init_DEF_SIZE(&G.prog.last);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007382 bc_num_zero(&G.prog.last);
7383
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007384 bc_num_init_DEF_SIZE(&G.prog.zero);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007385 bc_num_zero(&G.prog.zero);
7386
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01007387 bc_num_init_DEF_SIZE(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007388 bc_num_one(&G.prog.one);
7389
7390 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007391 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007392
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007393 bc_program_addFunc(xstrdup("(main)"), &idx);
7394 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007395
7396 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007397 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007398
7399 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007400 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007401
7402 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7403 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7404 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7405 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7406 bc_vec_push(&G.prog.stack, &ip);
7407}
Gavin Howard01055ba2018-11-03 11:00:21 -06007408
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007409static int bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007410{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007411#if ENABLE_FEATURE_EDITING
7412 G.line_input_state = new_line_input_t(DO_HISTORY);
7413#endif
7414 G.prog.len = bc_vm_envLen(env_len);
7415
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007416 bc_vec_init(&G.files, sizeof(char *), NULL);
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007417 if (IS_BC)
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007418 IF_BC(bc_vm_envArgs();)
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007419 bc_program_init();
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007420 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007421 IF_BC(bc_parse_init(&G.prs, BC_PROG_MAIN);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007422 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007423 IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007424 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007425
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007426 if (isatty(0)) {
Denys Vlasenkod38af482018-12-04 19:11:02 +01007427#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007428 G_ttyin = 1;
Denys Vlasenko17c54722018-12-04 21:21:32 +01007429 // With SA_RESTART, most system calls will restart
7430 // (IOW: they won't fail with EINTR).
7431 // In particular, this means ^C won't cause
7432 // stdout to get into "error state" if SIGINT hits
7433 // within write() syscall.
7434 // The downside is that ^C while line input is taken
7435 // will only be handled after [Enter] since read()
7436 // from stdin is not interrupted by ^C either,
7437 // it restarts, thus fgetc() does not return on ^C.
7438 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7439
7440 // Without SA_RESTART, this exhibits a bug:
7441 // "while (1) print 1" and try ^C-ing it.
7442 // Intermittently, instead of returning to input line,
7443 // you'll get "output error: Interrupted system call"
7444 // and exit.
7445 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007446#endif
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007447 return 1; // "tty"
Denys Vlasenkod38af482018-12-04 19:11:02 +01007448 }
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007449 return 0; // "not a tty"
7450}
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007451
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007452static BcStatus bc_vm_run(void)
7453{
7454 BcStatus st = bc_vm_exec();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007455#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01007456 if (G_exiting) // it was actually "halt" or "quit"
7457 st = EXIT_SUCCESS;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007458 bc_vm_free();
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01007459# if ENABLE_FEATURE_EDITING
7460 free_line_input_t(G.line_input_state);
7461# endif
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007462 FREE_G();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007463#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007464 return st;
7465}
7466
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007467#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007468int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007469int bc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007470{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007471 int is_tty;
7472
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007473 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007474 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007475
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007476 is_tty = bc_vm_init("BC_LINE_LENGTH");
7477
7478 bc_args(argv);
7479
7480 if (is_tty && !(option_mask32 & BC_FLAG_Q))
7481 bc_vm_info();
7482
7483 return bc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007484}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007485#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007486
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007487#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007488int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007489int dc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007490{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007491 int noscript;
7492
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007493 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007494 G.sbgn = '[';
7495 G.send = ']';
Denys Vlasenko6e7c65f2018-12-08 19:34:35 +01007496 /*
7497 * TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use width
7498 * 1 char wider than bc from the same package.
7499 * Both default width, and xC_LINE_LENGTH=N are wider:
7500 * "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7501 * 1234\
7502 * 56
7503 * "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7504 * 123\
7505 * 456
7506 * Do the same, or it's a bug?
7507 */
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007508 bc_vm_init("DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007509
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007510 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
7511 noscript = BC_FLAG_I;
7512 for (;;) {
7513 int n = getopt(argc, argv, "e:f:x");
7514 if (n <= 0)
7515 break;
7516 switch (n) {
7517 case 'e':
7518 noscript = 0;
7519 n = bc_vm_process(optarg);
7520 if (n) return n;
7521 break;
7522 case 'f':
7523 noscript = 0;
7524 bc_vm_file(optarg);
7525 break;
7526 case 'x':
7527 option_mask32 |= DC_FLAG_X;
7528 break;
7529 default:
7530 bb_show_usage();
7531 }
7532 }
7533 argv += optind;
7534
7535 while (*argv) {
7536 noscript = 0;
7537 bc_vec_push(&G.files, argv++);
7538 }
7539
7540 option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin
7541
7542 return bc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007543}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007544#endif
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +01007545
7546#endif // not DC_SMALL