blob: 685427e58a5283ee54f539cd52860824d96f4fd2 [file] [log] [blame]
Gavin Howard01055ba2018-11-03 11:00:21 -06001/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
5 *
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
8 */
9//config:config BC
10//config: bool "bc (45 kb; 49 kb when combined with dc)"
11//config: default y
12//config: help
13//config: bc is a command-line, arbitrary-precision calculator with a
14//config: Turing-complete language. See the GNU bc manual
15//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17//config: for details.
18//config:
19//config: This bc has four differences to the GNU bc:
20//config:
21//config: 1) The period (.) can also be used as a shortcut for "last", as in
22//config: the BSD bc.
23//config: 2) Arrays are copied before being passed as arguments to
24//config: functions. This behavior is required by the bc spec.
25//config: 3) Arrays can be passed to the builtin "length" function to get
26//config: the number of elements currently in the array. The following
27//config: example prints "1":
28//config:
29//config: a[0] = 0
30//config: length(a[])
31//config:
32//config: 4) The precedence of the boolean "not" operator (!) is equal to
33//config: that of the unary minus (-), or negation, operator. This still
34//config: allows POSIX-compliant scripts to work while somewhat
35//config: preserving expected behavior (versus C) and making parsing
36//config: easier.
37//config:
38//config: Options:
39//config:
40//config: -i --interactive force interactive mode
41//config: -l --mathlib use predefined math routines:
42//config:
43//config: s(expr) = sine of expr in radians
44//config: c(expr) = cosine of expr in radians
45//config: a(expr) = arctangent of expr, returning
46//config: radians
47//config: l(expr) = natural log of expr
48//config: e(expr) = raises e to the power of expr
49//config: j(n, x) = Bessel function of integer order
50//config: n of x
51//config:
52//config: -q --quiet don't print version and copyright.
53//config: -s --standard error if any non-POSIX extensions are used.
54//config: -w --warn warn if any non-POSIX extensions are used.
55//config: -v --version print version and copyright and exit.
56//config:
57//config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
58//config: enabled.
59//config:
60//config:config DC
61//config: bool "dc (38 kb; 49 kb when combined with bc)"
62//config: default y
63//config: help
64//config: dc is a reverse-polish notation command-line calculator which
65//config: supports unlimited precision arithmetic. See the FreeBSD man page
66//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68//config: for details.
69//config:
70//config: This dc has a few differences from the two above:
71//config:
72//config: 1) When printing a byte stream (command "P"), this bc follows what
73//config: the FreeBSD dc does.
74//config: 2) This dc implements the GNU extensions for divmod ("~") and
75//config: modular exponentiation ("|").
76//config: 3) This dc implements all FreeBSD extensions, except for "J" and
77//config: "M".
78//config: 4) Like the FreeBSD dc, this dc supports extended registers.
79//config: However, they are implemented differently. When it encounters
80//config: whitespace where a register should be, it skips the whitespace.
81//config: If the character following is not a lowercase letter, an error
82//config: is issued. Otherwise, the register name is parsed by the
83//config: following regex:
84//config:
85//config: [a-z][a-z0-9_]*
86//config:
87//config: This generally means that register names will be surrounded by
88//config: whitespace.
89//config:
90//config: Examples:
91//config:
92//config: l idx s temp L index S temp2 < do_thing
93//config:
94//config: Also note that, like the FreeBSD dc, extended registers are not
95//config: allowed unless the "-x" option is given.
96//config:
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +010097//config:config FEATURE_DC_SMALL
98//config: bool "Minimal dc implementation (4.2 kb), not using bc code base"
99//config: depends on DC && !BC
100//config: default y
101//config:
102//config:config FEATURE_DC_LIBM
103//config: bool "Enable power and exp functions (requires libm)"
104//config: default y
105//config: depends on FEATURE_DC_SMALL
106//config: help
107//config: Enable power and exp functions.
108//config: NOTE: This will require libm to be present for linking.
109//config:
Gavin Howard01055ba2018-11-03 11:00:21 -0600110//config:config FEATURE_BC_SIGNALS
111//config: bool "Enable bc/dc signal handling"
112//config: default y
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100113//config: depends on (BC || DC) && !FEATURE_DC_SMALL
Gavin Howard01055ba2018-11-03 11:00:21 -0600114//config: help
115//config: Enable signal handling for bc and dc.
116//config:
117//config:config FEATURE_BC_LONG_OPTIONS
118//config: bool "Enable bc/dc long options"
119//config: default y
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100120//config: depends on (BC || DC) && !FEATURE_DC_SMALL
Gavin Howard01055ba2018-11-03 11:00:21 -0600121//config: help
122//config: Enable long options for bc and dc.
123
124//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
125//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
126
127//kbuild:lib-$(CONFIG_BC) += bc.o
128//kbuild:lib-$(CONFIG_DC) += bc.o
129
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100130//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600131//usage:#define bc_trivial_usage
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100132//usage: "[-sqliw] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600133//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100134//usage:#define bc_full_usage "\n"
135//usage: "\nArbitrary precision calculator"
136//usage: "\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100137///////: "\n -i Interactive" - has no effect for now
138//usage: "\n -q Quiet"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100139//usage: "\n -l Load standard math library"
140//usage: "\n -s Be POSIX compatible"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100141//usage: "\n -w Warn if extensions are used"
142///////: "\n -v Version"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100143//usage: "\n"
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100144//usage: "\n$BC_LINE_LENGTH changes output width"
Gavin Howard01055ba2018-11-03 11:00:21 -0600145//usage:
146//usage:#define bc_example_usage
147//usage: "3 + 4.129\n"
148//usage: "1903 - 2893\n"
149//usage: "-129 * 213.28935\n"
150//usage: "12 / -1932\n"
151//usage: "12 % 12\n"
152//usage: "34 ^ 189\n"
153//usage: "scale = 13\n"
154//usage: "ibase = 2\n"
155//usage: "obase = A\n"
156//usage:
157//usage:#define dc_trivial_usage
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100158//usage: "[-eSCRIPT]... [-fFILE]... [FILE]..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600159//usage:
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100160//usage:#define dc_full_usage "\n"
161//usage: "\nTiny RPN calculator. Operations:"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100162//usage: "\n+, -, *, /, %, ^, exp, ~, divmod, |, "
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100163//usage: "modular exponentiation,"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100164//usage: "\np - print top of the stack (without popping)"
165//usage: "\nf - print entire stack"
166//usage: "\nk - pop the value and set the precision"
167//usage: "\ni - pop the value and set input radix"
168//usage: "\no - pop the value and set output radix"
169//usage: "\nExamples: dc -e'2 2 + p' -> 4, dc -e'8 8 * 2 2 + / p' -> 16"
Gavin Howard01055ba2018-11-03 11:00:21 -0600170//usage:
171//usage:#define dc_example_usage
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100172//usage: "$ dc -e'2 2 + p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600173//usage: "4\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100174//usage: "$ dc -e'8 8 \\* 2 2 + / p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600175//usage: "16\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100176//usage: "$ dc -e'0 1 & p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600177//usage: "0\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100178//usage: "$ dc -e'0 1 | p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600179//usage: "1\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100180//usage: "$ echo '72 9 / 8 * p' | dc\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600181//usage: "64\n"
182
183#include "libbb.h"
Denys Vlasenko95f93bd2018-12-06 10:29:12 +0100184#include "common_bufsiz.h"
Gavin Howard01055ba2018-11-03 11:00:21 -0600185
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100186#if ENABLE_FEATURE_DC_SMALL
187# include "dc.c"
188#else
189
Gavin Howard01055ba2018-11-03 11:00:21 -0600190typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100191 BC_STATUS_SUCCESS = 0,
192 BC_STATUS_FAILURE = 1,
193 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600194} BcStatus;
195
Gavin Howard01055ba2018-11-03 11:00:21 -0600196#define BC_VEC_INVALID_IDX ((size_t) -1)
197#define BC_VEC_START_CAP (1 << 5)
198
199typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600200
201typedef struct BcVec {
202 char *v;
203 size_t len;
204 size_t cap;
205 size_t size;
206 BcVecFree dtor;
207} BcVec;
208
Gavin Howard01055ba2018-11-03 11:00:21 -0600209typedef signed char BcDig;
210
211typedef struct BcNum {
212 BcDig *restrict num;
213 size_t rdx;
214 size_t len;
215 size_t cap;
216 bool neg;
217} BcNum;
218
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100219#define BC_NUM_MIN_BASE ((unsigned long) 2)
220#define BC_NUM_MAX_IBASE ((unsigned long) 16)
221// larger value might speed up BIGNUM calculations a bit:
222#define BC_NUM_DEF_SIZE (16)
223#define BC_NUM_PRINT_WIDTH (69)
Gavin Howard01055ba2018-11-03 11:00:21 -0600224
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100225#define BC_NUM_KARATSUBA_LEN (32)
Gavin Howard01055ba2018-11-03 11:00:21 -0600226
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100227#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
228#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
229#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
Gavin Howard01055ba2018-11-03 11:00:21 -0600230#define BC_NUM_AREQ(a, b) \
231 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
232#define BC_NUM_MREQ(a, b, scale) \
233 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
234
235typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
236typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
237
Gavin Howard01055ba2018-11-03 11:00:21 -0600238static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
239static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
240static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
241static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
242static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
243static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
244static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
245static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
246 size_t scale);
247
248typedef enum BcInst {
249
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100250#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600251 BC_INST_INC_PRE,
252 BC_INST_DEC_PRE,
253 BC_INST_INC_POST,
254 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100255#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600256
257 BC_INST_NEG,
258
259 BC_INST_POWER,
260 BC_INST_MULTIPLY,
261 BC_INST_DIVIDE,
262 BC_INST_MODULUS,
263 BC_INST_PLUS,
264 BC_INST_MINUS,
265
266 BC_INST_REL_EQ,
267 BC_INST_REL_LE,
268 BC_INST_REL_GE,
269 BC_INST_REL_NE,
270 BC_INST_REL_LT,
271 BC_INST_REL_GT,
272
273 BC_INST_BOOL_NOT,
274 BC_INST_BOOL_OR,
275 BC_INST_BOOL_AND,
276
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100277#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600278 BC_INST_ASSIGN_POWER,
279 BC_INST_ASSIGN_MULTIPLY,
280 BC_INST_ASSIGN_DIVIDE,
281 BC_INST_ASSIGN_MODULUS,
282 BC_INST_ASSIGN_PLUS,
283 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100284#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600285 BC_INST_ASSIGN,
286
287 BC_INST_NUM,
288 BC_INST_VAR,
289 BC_INST_ARRAY_ELEM,
290 BC_INST_ARRAY,
291
292 BC_INST_SCALE_FUNC,
293 BC_INST_IBASE,
294 BC_INST_SCALE,
295 BC_INST_LAST,
296 BC_INST_LENGTH,
297 BC_INST_READ,
298 BC_INST_OBASE,
299 BC_INST_SQRT,
300
301 BC_INST_PRINT,
302 BC_INST_PRINT_POP,
303 BC_INST_STR,
304 BC_INST_PRINT_STR,
305
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100306#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600307 BC_INST_JUMP,
308 BC_INST_JUMP_ZERO,
309
310 BC_INST_CALL,
311
312 BC_INST_RET,
313 BC_INST_RET0,
314
315 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100316#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600317
318 BC_INST_POP,
319 BC_INST_POP_EXEC,
320
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100321#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600322 BC_INST_MODEXP,
323 BC_INST_DIVMOD,
324
325 BC_INST_EXECUTE,
326 BC_INST_EXEC_COND,
327
328 BC_INST_ASCIIFY,
329 BC_INST_PRINT_STREAM,
330
331 BC_INST_PRINT_STACK,
332 BC_INST_CLEAR_STACK,
333 BC_INST_STACK_LEN,
334 BC_INST_DUPLICATE,
335 BC_INST_SWAP,
336
337 BC_INST_LOAD,
338 BC_INST_PUSH_VAR,
339 BC_INST_PUSH_TO_VAR,
340
341 BC_INST_QUIT,
342 BC_INST_NQUIT,
343
344 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100345#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600346
347} BcInst;
348
349typedef struct BcId {
350 char *name;
351 size_t idx;
352} BcId;
353
354typedef struct BcFunc {
355 BcVec code;
356 BcVec labels;
357 size_t nparams;
358 BcVec autos;
359} BcFunc;
360
361typedef enum BcResultType {
362
363 BC_RESULT_TEMP,
364
365 BC_RESULT_VAR,
366 BC_RESULT_ARRAY_ELEM,
367 BC_RESULT_ARRAY,
368
369 BC_RESULT_STR,
370
371 BC_RESULT_IBASE,
372 BC_RESULT_SCALE,
373 BC_RESULT_LAST,
374
375 // These are between to calculate ibase, obase, and last from instructions.
376 BC_RESULT_CONSTANT,
377 BC_RESULT_ONE,
378
379 BC_RESULT_OBASE,
380
381} BcResultType;
382
383typedef union BcResultData {
384 BcNum n;
385 BcVec v;
386 BcId id;
387} BcResultData;
388
389typedef struct BcResult {
390 BcResultType t;
391 BcResultData d;
392} BcResult;
393
394typedef struct BcInstPtr {
395 size_t func;
396 size_t idx;
397 size_t len;
398} BcInstPtr;
399
Gavin Howard01055ba2018-11-03 11:00:21 -0600400// BC_LEX_NEG is not used in lexing; it is only for parsing.
401typedef enum BcLexType {
402
403 BC_LEX_EOF,
404 BC_LEX_INVALID,
405
406 BC_LEX_OP_INC,
407 BC_LEX_OP_DEC,
408
409 BC_LEX_NEG,
410
411 BC_LEX_OP_POWER,
412 BC_LEX_OP_MULTIPLY,
413 BC_LEX_OP_DIVIDE,
414 BC_LEX_OP_MODULUS,
415 BC_LEX_OP_PLUS,
416 BC_LEX_OP_MINUS,
417
418 BC_LEX_OP_REL_EQ,
419 BC_LEX_OP_REL_LE,
420 BC_LEX_OP_REL_GE,
421 BC_LEX_OP_REL_NE,
422 BC_LEX_OP_REL_LT,
423 BC_LEX_OP_REL_GT,
424
425 BC_LEX_OP_BOOL_NOT,
426 BC_LEX_OP_BOOL_OR,
427 BC_LEX_OP_BOOL_AND,
428
429 BC_LEX_OP_ASSIGN_POWER,
430 BC_LEX_OP_ASSIGN_MULTIPLY,
431 BC_LEX_OP_ASSIGN_DIVIDE,
432 BC_LEX_OP_ASSIGN_MODULUS,
433 BC_LEX_OP_ASSIGN_PLUS,
434 BC_LEX_OP_ASSIGN_MINUS,
435 BC_LEX_OP_ASSIGN,
436
437 BC_LEX_NLINE,
438 BC_LEX_WHITESPACE,
439
440 BC_LEX_LPAREN,
441 BC_LEX_RPAREN,
442
443 BC_LEX_LBRACKET,
444 BC_LEX_COMMA,
445 BC_LEX_RBRACKET,
446
447 BC_LEX_LBRACE,
448 BC_LEX_SCOLON,
449 BC_LEX_RBRACE,
450
451 BC_LEX_STR,
452 BC_LEX_NAME,
453 BC_LEX_NUMBER,
454
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100455 BC_LEX_KEY_1st_keyword,
456 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600457 BC_LEX_KEY_BREAK,
458 BC_LEX_KEY_CONTINUE,
459 BC_LEX_KEY_DEFINE,
460 BC_LEX_KEY_ELSE,
461 BC_LEX_KEY_FOR,
462 BC_LEX_KEY_HALT,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100463 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
464 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600465 BC_LEX_KEY_IF,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100466 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600467 BC_LEX_KEY_LENGTH,
468 BC_LEX_KEY_LIMITS,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100469 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600470 BC_LEX_KEY_PRINT,
471 BC_LEX_KEY_QUIT,
472 BC_LEX_KEY_READ,
473 BC_LEX_KEY_RETURN,
474 BC_LEX_KEY_SCALE,
475 BC_LEX_KEY_SQRT,
476 BC_LEX_KEY_WHILE,
477
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100478#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600479 BC_LEX_EQ_NO_REG,
480 BC_LEX_OP_MODEXP,
481 BC_LEX_OP_DIVMOD,
482
483 BC_LEX_COLON,
484 BC_LEX_ELSE,
485 BC_LEX_EXECUTE,
486 BC_LEX_PRINT_STACK,
487 BC_LEX_CLEAR_STACK,
488 BC_LEX_STACK_LEVEL,
489 BC_LEX_DUPLICATE,
490 BC_LEX_SWAP,
491 BC_LEX_POP,
492
493 BC_LEX_ASCIIFY,
494 BC_LEX_PRINT_STREAM,
495
496 BC_LEX_STORE_IBASE,
497 BC_LEX_STORE_SCALE,
498 BC_LEX_LOAD,
499 BC_LEX_LOAD_POP,
500 BC_LEX_STORE_PUSH,
501 BC_LEX_STORE_OBASE,
502 BC_LEX_PRINT_POP,
503 BC_LEX_NQUIT,
504 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100505#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600506} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100507// must match order of BC_LEX_KEY_foo etc above
508#if ENABLE_BC
509struct BcLexKeyword {
510 char name8[8];
511};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100512#define BC_LEX_KW_ENTRY(a, b) \
513 { .name8 = a /*, .posix = b */ }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100514static const struct BcLexKeyword bc_lex_kws[20] = {
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100515 BC_LEX_KW_ENTRY("auto" , 1), // 0
516 BC_LEX_KW_ENTRY("break" , 1), // 1
517 BC_LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
518 BC_LEX_KW_ENTRY("define" , 1), // 3
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100519
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100520 BC_LEX_KW_ENTRY("else" , 0), // 4
521 BC_LEX_KW_ENTRY("for" , 1), // 5
522 BC_LEX_KW_ENTRY("halt" , 0), // 6
523 BC_LEX_KW_ENTRY("ibase" , 1), // 7
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100524
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100525 BC_LEX_KW_ENTRY("if" , 1), // 8
526 BC_LEX_KW_ENTRY("last" , 0), // 9
527 BC_LEX_KW_ENTRY("length" , 1), // 10
528 BC_LEX_KW_ENTRY("limits" , 0), // 11
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100529
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100530 BC_LEX_KW_ENTRY("obase" , 1), // 12
531 BC_LEX_KW_ENTRY("print" , 0), // 13
532 BC_LEX_KW_ENTRY("quit" , 1), // 14
533 BC_LEX_KW_ENTRY("read" , 0), // 15
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100534
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100535 BC_LEX_KW_ENTRY("return" , 1), // 16
536 BC_LEX_KW_ENTRY("scale" , 1), // 17
537 BC_LEX_KW_ENTRY("sqrt" , 1), // 18
538 BC_LEX_KW_ENTRY("while" , 1), // 19
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100539};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100540#undef BC_LEX_KW_ENTRY
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100541enum {
542 POSIX_KWORD_MASK = 0
543 | (1 << 0)
544 | (1 << 1)
545 | (0 << 2)
546 | (1 << 3)
547 \
548 | (0 << 4)
549 | (1 << 5)
550 | (0 << 6)
551 | (1 << 7)
552 \
553 | (1 << 8)
554 | (0 << 9)
555 | (1 << 10)
556 | (0 << 11)
557 \
558 | (1 << 12)
559 | (0 << 13)
560 | (1 << 14)
561 | (0 << 15)
562 \
563 | (1 << 16)
564 | (1 << 17)
565 | (1 << 18)
566 | (1 << 19)
567};
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100568#define bc_lex_kws_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100569#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600570
571struct BcLex;
572typedef BcStatus (*BcLexNext)(struct BcLex *);
573
574typedef struct BcLex {
575
576 const char *buf;
577 size_t i;
578 size_t line;
Gavin Howard01055ba2018-11-03 11:00:21 -0600579 size_t len;
580 bool newline;
581
582 struct {
583 BcLexType t;
584 BcLexType last;
585 BcVec v;
586 } t;
587
588 BcLexNext next;
589
590} BcLex;
591
592#define BC_PARSE_STREND ((char) UCHAR_MAX)
593
Denys Vlasenkoe55a5722018-12-06 12:47:17 +0100594#define BC_PARSE_REL (1 << 0)
595#define BC_PARSE_PRINT (1 << 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600596#define BC_PARSE_NOCALL (1 << 2)
597#define BC_PARSE_NOREAD (1 << 3)
Denys Vlasenkoe55a5722018-12-06 12:47:17 +0100598#define BC_PARSE_ARRAY (1 << 4)
Gavin Howard01055ba2018-11-03 11:00:21 -0600599
600#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
601#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
602
603#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
604#define BC_PARSE_FUNC_INNER(parse) \
605 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
606
607#define BC_PARSE_FLAG_FUNC (1 << 1)
608#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
609
610#define BC_PARSE_FLAG_BODY (1 << 2)
611#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
612
613#define BC_PARSE_FLAG_LOOP (1 << 3)
614#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
615
616#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
617#define BC_PARSE_LOOP_INNER(parse) \
618 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
619
620#define BC_PARSE_FLAG_IF (1 << 5)
621#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
622
623#define BC_PARSE_FLAG_ELSE (1 << 6)
624#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
625
626#define BC_PARSE_FLAG_IF_END (1 << 7)
627#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
628
629#define BC_PARSE_CAN_EXEC(parse) \
630 (!(BC_PARSE_TOP_FLAG(parse) & \
631 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
632 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
633 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
634
Gavin Howard01055ba2018-11-03 11:00:21 -0600635struct BcParse;
636
637struct BcProgram;
638
Gavin Howard01055ba2018-11-03 11:00:21 -0600639typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600640
641typedef struct BcParse {
642
643 BcParseParse parse;
644
645 BcLex l;
646
647 BcVec flags;
648
649 BcVec exits;
650 BcVec conds;
651
652 BcVec ops;
653
Gavin Howard01055ba2018-11-03 11:00:21 -0600654 BcFunc *func;
655 size_t fidx;
656
657 size_t nbraces;
658 bool auto_part;
659
660} BcParse;
661
Gavin Howard01055ba2018-11-03 11:00:21 -0600662typedef struct BcProgram {
663
664 size_t len;
665 size_t scale;
666
667 BcNum ib;
668 size_t ib_t;
669 BcNum ob;
670 size_t ob_t;
671
672 BcNum hexb;
673
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100674#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600675 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100676#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600677
678 BcVec results;
679 BcVec stack;
680
681 BcVec fns;
682 BcVec fn_map;
683
684 BcVec vars;
685 BcVec var_map;
686
687 BcVec arrs;
688 BcVec arr_map;
689
690 BcVec strs;
691 BcVec consts;
692
693 const char *file;
694
695 BcNum last;
696 BcNum zero;
697 BcNum one;
698
699 size_t nchars;
700
Gavin Howard01055ba2018-11-03 11:00:21 -0600701} BcProgram;
702
703#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
704
705#define BC_PROG_MAIN (0)
706#define BC_PROG_READ (1)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100707#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600708#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100709#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600710
711#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
712#define BC_PROG_NUM(r, n) \
713 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
714
715typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
716
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100717#define BC_FLAG_W (1 << 0)
718#define BC_FLAG_V (1 << 1)
719#define BC_FLAG_S (1 << 2)
720#define BC_FLAG_Q (1 << 3)
721#define BC_FLAG_L (1 << 4)
722#define BC_FLAG_I (1 << 5)
723#define DC_FLAG_X (1 << 6)
Gavin Howard01055ba2018-11-03 11:00:21 -0600724
725#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
726#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
727
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100728#define BC_MAX_OBASE ((unsigned) 999)
729#define BC_MAX_DIM ((unsigned) INT_MAX)
730#define BC_MAX_SCALE ((unsigned) UINT_MAX)
731#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
732#define BC_MAX_NAME BC_MAX_STRING
733#define BC_MAX_NUM BC_MAX_STRING
734#define BC_MAX_EXP ((unsigned long) LONG_MAX)
735#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600736
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100737struct globals {
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100738 IF_FEATURE_BC_SIGNALS(smallint ttyin;)
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100739 IF_FEATURE_CLEAN_UP(smallint exiting;)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100740 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600741 char sbgn;
742 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600743
744 BcParse prs;
745 BcProgram prog;
746
Denys Vlasenko5318f812018-12-05 17:48:01 +0100747 // For error messages. Can be set to current parsed line,
748 // or [TODO] to current executing line (can be before last parsed one)
749 unsigned err_line;
750
Gavin Howard01055ba2018-11-03 11:00:21 -0600751 BcVec files;
752
753 char *env_args;
Denys Vlasenko95f93bd2018-12-06 10:29:12 +0100754
755#if ENABLE_FEATURE_EDITING
756 line_input_t *line_input_state;
757#endif
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100758} FIX_ALIASING;
759#define G (*ptr_to_globals)
760#define INIT_G() do { \
761 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
762} while (0)
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100763#define FREE_G() do { \
764 FREE_PTR_TO_GLOBALS(); \
765} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100766#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
767#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100768#define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100769#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkob9c321d2018-12-07 12:41:42 +0100770# define G_interrupt bb_got_signal
771# define G_ttyin G.ttyin
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100772#else
Denys Vlasenkob9c321d2018-12-07 12:41:42 +0100773# define G_interrupt 0
774# define G_ttyin 0
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100775#endif
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100776#if ENABLE_FEATURE_CLEAN_UP
777# define G_exiting G.exiting
778#else
779# define G_exiting 0
780#endif
Denys Vlasenko00d77792018-11-30 23:13:42 +0100781#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
782
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100783#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600784
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100785// This is a bit array that corresponds to token types. An entry is
Gavin Howard01055ba2018-11-03 11:00:21 -0600786// true if the token is valid in an expression, false otherwise.
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100787enum {
788 BC_PARSE_EXPRS_BITS = 0
789 + ((uint64_t)((0 << 0)+(0 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (0*8))
790 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (1*8))
791 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(1 << 5)+(1 << 6)+(1 << 7)) << (2*8))
792 + ((uint64_t)((1 << 0)+(1 << 1)+(1 << 2)+(0 << 3)+(0 << 4)+(1 << 5)+(1 << 6)+(0 << 7)) << (3*8))
793 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(1 << 6)+(1 << 7)) << (4*8))
794 + ((uint64_t)((0 << 0)+(0 << 1)+(0 << 2)+(0 << 3)+(0 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (5*8))
795 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(1 << 3)+(1 << 4)+(0 << 5)+(0 << 6)+(1 << 7)) << (6*8))
796 + ((uint64_t)((0 << 0)+(1 << 1)+(1 << 2)+(0 << 3) ) << (7*8))
Gavin Howard01055ba2018-11-03 11:00:21 -0600797};
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100798static ALWAYS_INLINE long bc_parse_exprs(unsigned i)
799{
800#if ULONG_MAX > 0xffffffff
801 // 64-bit version (will not work correctly for 32-bit longs!)
802 return BC_PARSE_EXPRS_BITS & (1UL << i);
803#else
804 // 32-bit version
805 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
806 if (i >= 32) {
807 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
808 i &= 31;
809 }
810 return m & (1UL << i);
811#endif
812}
Gavin Howard01055ba2018-11-03 11:00:21 -0600813
814// This is an array of data for operators that correspond to token types.
Denys Vlasenko65437582018-12-05 19:37:19 +0100815static const uint8_t bc_parse_ops[] = {
816#define OP(p,l) ((int)(l) * 0x10 + (p))
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100817 OP(0, false), OP( 0, false ), // inc dec
818 OP(1, false), // neg
Denys Vlasenko65437582018-12-05 19:37:19 +0100819 OP(2, false),
Denys Vlasenkobcb62a72018-12-05 20:17:48 +0100820 OP(3, true ), OP( 3, true ), OP( 3, true ), // pow mul div
821 OP(4, true ), OP( 4, true ), // mod + -
822 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), // == <= >= != < >
823 OP(1, false), // not
824 OP(7, true ), OP( 7, true ), // or and
825 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ), // ^= *= /= %= +=
826 OP(5, false), OP( 5, false ), // -= =
Denys Vlasenko65437582018-12-05 19:37:19 +0100827#undef OP
Gavin Howard01055ba2018-11-03 11:00:21 -0600828};
Denys Vlasenko65437582018-12-05 19:37:19 +0100829#define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
830#define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
Gavin Howard01055ba2018-11-03 11:00:21 -0600831
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100832// Byte array of up to 4 BC_LEX's, packed into 32-bit word
833typedef uint32_t BcParseNext;
834
Gavin Howard01055ba2018-11-03 11:00:21 -0600835// These identify what tokens can come after expressions in certain cases.
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100836enum {
837#define BC_PARSE_NEXT4(a,b,c,d) ( (a) | ((b)<<8) | ((c)<<16) | ((((d)|0x80)<<24)) )
838#define BC_PARSE_NEXT2(a,b) BC_PARSE_NEXT4(a,b,0xff,0xff)
839#define BC_PARSE_NEXT1(a) BC_PARSE_NEXT4(a,0xff,0xff,0xff)
840 bc_parse_next_expr = BC_PARSE_NEXT4(BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF),
841 bc_parse_next_param = BC_PARSE_NEXT2(BC_LEX_RPAREN, BC_LEX_COMMA),
842 bc_parse_next_print = BC_PARSE_NEXT4(BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF),
843 bc_parse_next_rel = BC_PARSE_NEXT1(BC_LEX_RPAREN),
844 bc_parse_next_elem = BC_PARSE_NEXT1(BC_LEX_RBRACKET),
845 bc_parse_next_for = BC_PARSE_NEXT1(BC_LEX_SCOLON),
846 bc_parse_next_read = BC_PARSE_NEXT2(BC_LEX_NLINE, BC_LEX_EOF),
847#undef BC_PARSE_NEXT4
848#undef BC_PARSE_NEXT2
849#undef BC_PARSE_NEXT1
850};
Gavin Howard01055ba2018-11-03 11:00:21 -0600851#endif // ENABLE_BC
852
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100853#if ENABLE_DC
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100854static const //BcLexType - should be this type, but narrower type saves size:
855uint8_t
856dc_lex_regs[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600857 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
858 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
859 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
860 BC_LEX_STORE_PUSH,
861};
862
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100863static const //BcLexType - should be this type
864uint8_t
865dc_lex_tokens[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600866 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
867 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
868 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
871 BC_LEX_INVALID, BC_LEX_INVALID,
872 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
873 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
875 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
876 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
877 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
878 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
880 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
881 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
882 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
883 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
884 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
885 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
886 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
887 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
888 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
889 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
890 BC_LEX_INVALID
891};
892
Denys Vlasenko18c6b542018-12-07 12:57:32 +0100893static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1
894int8_t
895dc_parse_insts[] = {
Gavin Howard01055ba2018-11-03 11:00:21 -0600896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
897 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
898 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
899 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
904 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
906 BC_INST_INVALID, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
908 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
909 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
911 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
912 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
913 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
914 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
915 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
916 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
917 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
918 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
919};
920#endif // ENABLE_DC
921
Gavin Howard01055ba2018-11-03 11:00:21 -0600922static const BcNumBinaryOp bc_program_ops[] = {
923 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
924};
925
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100926static void fflush_and_check(void)
927{
928 fflush_all();
929 if (ferror(stdout) || ferror(stderr))
930 bb_perror_msg_and_die("output error");
931}
932
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100933#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100934#define QUIT_OR_RETURN_TO_MAIN \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100935do { \
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100936 IF_FEATURE_BC_SIGNALS(G_ttyin = 0;) /* do not loop in main loop anymore */ \
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100937 G_exiting = 1; \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100938 return BC_STATUS_FAILURE; \
939} while (0)
940#else
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100941#define QUIT_OR_RETURN_TO_MAIN quit()
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100942#endif
943
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100944static void quit(void) NORETURN;
945static void quit(void)
946{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100947 if (ferror(stdin))
948 bb_perror_msg_and_die("input error");
949 fflush_and_check();
950 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100951}
952
Denys Vlasenko5318f812018-12-05 17:48:01 +0100953static void bc_verror_msg(const char *fmt, va_list p)
954{
955 const char *sv = sv; /* for compiler */
956 if (G.prog.file) {
957 sv = applet_name;
958 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
959 }
960 bb_verror_msg(fmt, p, NULL);
961 if (G.prog.file) {
962 free((char*)applet_name);
963 applet_name = sv;
964 }
965}
966
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100967static NOINLINE int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100968{
969 va_list p;
970
971 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100972 bc_verror_msg(fmt, p);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100973 va_end(p);
Denys Vlasenko0409ad32018-12-05 16:39:22 +0100974
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100975 if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100976 exit(1);
977 return BC_STATUS_FAILURE;
978}
979
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +0100980#if ENABLE_BC
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100981static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100982{
983 va_list p;
984
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100985 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100986 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100987 return BC_STATUS_SUCCESS; // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100988
989 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100990 bc_verror_msg(fmt, p);
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100991 va_end(p);
992
993 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100994 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100995 return BC_STATUS_SUCCESS; // no, it's a warning
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100996 if (!ENABLE_FEATURE_CLEAN_UP && !G_ttyin)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100997 exit(1);
998 return BC_STATUS_FAILURE;
999}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001000#endif
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001001
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001002// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
1003// This idiom begs for tail-call optimization, but for it to work,
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001004// function must not have caller-cleaned parameters on stack.
1005// Unfortunately, vararg function API does exactly that on most arches.
1006// Thus, use these shims for the cases when we have no vararg PARAMS:
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001007static int bc_error(const char *msg)
1008{
1009 return bc_error_fmt("%s", msg);
1010}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001011#if ENABLE_BC
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01001012static int bc_POSIX_requires(const char *msg)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001013{
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01001014 return bc_posix_error_fmt("POSIX requires %s", msg);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001015}
Denys Vlasenko00646792018-12-05 18:12:27 +01001016static int bc_POSIX_does_not_allow(const char *msg)
1017{
1018 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
1019}
1020static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1021{
1022 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1023}
1024static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1025{
1026 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1027}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001028#endif
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001029static int bc_error_bad_character(char c)
1030{
1031 return bc_error_fmt("bad character '%c'", c);
1032}
1033static int bc_error_bad_expression(void)
1034{
1035 return bc_error("bad expression");
1036}
1037static int bc_error_bad_token(void)
1038{
1039 return bc_error("bad token");
1040}
1041static int bc_error_stack_has_too_few_elements(void)
1042{
1043 return bc_error("stack has too few elements");
1044}
1045static int bc_error_variable_is_wrong_type(void)
1046{
1047 return bc_error("variable is wrong type");
1048}
1049static int bc_error_nested_read_call(void)
1050{
1051 return bc_error("read() call inside of a read() call");
1052}
1053
Gavin Howard01055ba2018-11-03 11:00:21 -06001054static void bc_vec_grow(BcVec *v, size_t n)
1055{
1056 size_t cap = v->cap * 2;
1057 while (cap < v->len + n) cap *= 2;
1058 v->v = xrealloc(v->v, v->size * cap);
1059 v->cap = cap;
1060}
1061
1062static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1063{
1064 v->size = esize;
1065 v->cap = BC_VEC_START_CAP;
1066 v->len = 0;
1067 v->dtor = dtor;
1068 v->v = xmalloc(esize * BC_VEC_START_CAP);
1069}
1070
Denys Vlasenko7d628012018-12-04 21:46:47 +01001071static void bc_char_vec_init(BcVec *v)
1072{
1073 bc_vec_init(v, sizeof(char), NULL);
1074}
1075
Gavin Howard01055ba2018-11-03 11:00:21 -06001076static void bc_vec_expand(BcVec *v, size_t req)
1077{
1078 if (v->cap < req) {
1079 v->v = xrealloc(v->v, v->size * req);
1080 v->cap = req;
1081 }
1082}
1083
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001084static void bc_vec_pop(BcVec *v)
1085{
1086 v->len--;
1087 if (v->dtor)
1088 v->dtor(v->v + (v->size * v->len));
1089}
Denys Vlasenko2fa11b62018-12-06 12:34:39 +01001090
Gavin Howard01055ba2018-11-03 11:00:21 -06001091static void bc_vec_npop(BcVec *v, size_t n)
1092{
1093 if (!v->dtor)
1094 v->len -= n;
1095 else {
1096 size_t len = v->len - n;
1097 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1098 }
1099}
1100
Denys Vlasenko7d628012018-12-04 21:46:47 +01001101static void bc_vec_pop_all(BcVec *v)
1102{
1103 bc_vec_npop(v, v->len);
1104}
1105
Gavin Howard01055ba2018-11-03 11:00:21 -06001106static void bc_vec_push(BcVec *v, const void *data)
1107{
1108 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1109 memmove(v->v + (v->size * v->len), data, v->size);
1110 v->len += 1;
1111}
1112
1113static void bc_vec_pushByte(BcVec *v, char data)
1114{
1115 bc_vec_push(v, &data);
1116}
1117
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001118static void bc_vec_pushZeroByte(BcVec *v)
1119{
1120 //bc_vec_pushByte(v, '\0');
1121 // better:
1122 bc_vec_push(v, &const_int_0);
1123}
1124
Gavin Howard01055ba2018-11-03 11:00:21 -06001125static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1126{
1127 if (idx == v->len)
1128 bc_vec_push(v, data);
1129 else {
1130
1131 char *ptr;
1132
1133 if (v->len == v->cap) bc_vec_grow(v, 1);
1134
1135 ptr = v->v + v->size * idx;
1136
1137 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1138 memmove(ptr, data, v->size);
1139 }
1140}
1141
1142static void bc_vec_string(BcVec *v, size_t len, const char *str)
1143{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001144 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001145 bc_vec_expand(v, len + 1);
1146 memcpy(v->v, str, len);
1147 v->len = len;
1148
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001149 bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001150}
1151
1152static void bc_vec_concat(BcVec *v, const char *str)
1153{
1154 size_t len;
1155
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001156 if (v->len == 0) bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001157
1158 len = v->len + strlen(str);
1159
1160 if (v->cap < len) bc_vec_grow(v, len - v->len);
Denys Vlasenko1ff88622018-12-06 12:06:16 +01001161 strcpy(v->v + v->len - 1, str);
Gavin Howard01055ba2018-11-03 11:00:21 -06001162
1163 v->len = len;
1164}
1165
1166static void *bc_vec_item(const BcVec *v, size_t idx)
1167{
1168 return v->v + v->size * idx;
1169}
1170
1171static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1172{
1173 return v->v + v->size * (v->len - idx - 1);
1174}
1175
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001176static void *bc_vec_top(const BcVec *v)
1177{
1178 return v->v + v->size * (v->len - 1);
1179}
1180
Gavin Howard01055ba2018-11-03 11:00:21 -06001181static void bc_vec_free(void *vec)
1182{
1183 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001184 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001185 free(v->v);
1186}
1187
Denys Vlasenkocca79a02018-12-05 21:15:46 +01001188static int bc_id_cmp(const void *e1, const void *e2)
1189{
1190 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
1191}
1192
1193static void bc_id_free(void *id)
1194{
1195 free(((BcId *) id)->name);
1196}
1197
Gavin Howard01055ba2018-11-03 11:00:21 -06001198static size_t bc_map_find(const BcVec *v, const void *ptr)
1199{
1200 size_t low = 0, high = v->len;
1201
1202 while (low < high) {
1203
1204 size_t mid = (low + high) / 2;
1205 BcId *id = bc_vec_item(v, mid);
1206 int result = bc_id_cmp(ptr, id);
1207
1208 if (result == 0)
1209 return mid;
1210 else if (result < 0)
1211 high = mid;
1212 else
1213 low = mid + 1;
1214 }
1215
1216 return low;
1217}
1218
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001219static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001220{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001221 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001222
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001223 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001224 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001225 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1226 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001227 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001228 bc_vec_pushAt(v, ptr, n);
1229 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001230}
1231
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001232#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001233static size_t bc_map_index(const BcVec *v, const void *ptr)
1234{
1235 size_t i = bc_map_find(v, ptr);
1236 if (i >= v->len) return BC_VEC_INVALID_IDX;
1237 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1238}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001239#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001240
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001241static int push_input_byte(BcVec *vec, char c)
1242{
1243 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1244 || c > 0x7e
1245 ) {
1246 // Bad chars on this line, ignore entire line
1247 bc_error_fmt("illegal character 0x%02x", c);
1248 return 1;
1249 }
1250 bc_vec_pushByte(vec, (char)c);
1251 return 0;
1252}
1253
Gavin Howard01055ba2018-11-03 11:00:21 -06001254static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1255{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001256 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001257
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001258 if (G_posix) prompt = "";
1259
Denys Vlasenko00d77792018-11-30 23:13:42 +01001260 do {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001261 int c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001262
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001263 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001264 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001265
1266 fflush_and_check();
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001267
Gavin Howard01055ba2018-11-03 11:00:21 -06001268#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001269 if (G_interrupt) { // ^C was pressed
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001270 intr:
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001271 G_interrupt = 0;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001272 fputs(IS_BC
1273 ? "\ninterrupt (type \"quit\" to exit)\n"
1274 : "\ninterrupt (type \"q\" to exit)\n"
1275 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001276 }
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001277# if ENABLE_FEATURE_EDITING
1278 if (G_ttyin) {
1279 int n, i;
1280# define line_buf bb_common_bufsiz1
1281 n = read_line_input(G.line_input_state, prompt, line_buf, COMMON_BUFSIZE);
1282 if (n <= 0) { // read errors or EOF, or ^D, or ^C
1283 if (n == 0) // ^C
1284 goto intr;
1285 G.eof = 1;
1286 break;
1287 }
1288 i = 0;
1289 for (;;) {
1290 c = line_buf[i++];
1291 if (!c) break;
1292 bad_chars |= push_input_byte(vec, c);
1293 }
1294# undef line_buf
1295 } else
1296# endif
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001297#endif
Denys Vlasenkoed849352018-12-06 10:26:13 +01001298 {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001299 if (G_ttyin)
Denys Vlasenkoed849352018-12-06 10:26:13 +01001300 fputs(prompt, stderr);
Denys Vlasenkoed849352018-12-06 10:26:13 +01001301 IF_FEATURE_BC_SIGNALS(errno = 0;)
1302 do {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001303 c = fgetc(stdin);
1304#if ENABLE_FEATURE_BC_SIGNALS && !ENABLE_FEATURE_EDITING
1305 // Both conditions appear simultaneously, check both just in case
Denys Vlasenkob9c321d2018-12-07 12:41:42 +01001306 if (errno == EINTR || G_interrupt) {
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001307 // ^C was pressed
1308 clearerr(stdin);
1309 goto intr;
1310 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001311#endif
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001312 if (c == EOF) {
Denys Vlasenkoed849352018-12-06 10:26:13 +01001313 if (ferror(stdin))
1314 quit(); // this emits error message
1315 G.eof = 1;
1316 // Note: EOF does not append '\n', therefore:
1317 // printf 'print 123\n' | bc - works
1318 // printf 'print 123' | bc - fails (syntax error)
1319 break;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001320 }
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001321 bad_chars |= push_input_byte(vec, c);
1322 } while (c != '\n');
Denys Vlasenkoed849352018-12-06 10:26:13 +01001323 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001324 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001325
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001326 bc_vec_pushZeroByte(vec);
Gavin Howard01055ba2018-11-03 11:00:21 -06001327
1328 return BC_STATUS_SUCCESS;
1329}
1330
Denys Vlasenkodf515392018-12-02 19:27:48 +01001331static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001332{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001333 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001334 size_t size = ((size_t) -1);
1335 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001336
Denys Vlasenko4c9455f2018-12-06 15:21:39 +01001337 // Never returns NULL (dies on errors)
1338 buf = xmalloc_xopen_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001339
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001340 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001341 char c = buf[i];
1342 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1343 || c > 0x7e
1344 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001345 free(buf);
1346 buf = NULL;
1347 break;
1348 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001349 }
1350
Denys Vlasenkodf515392018-12-02 19:27:48 +01001351 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001352}
1353
Gavin Howard01055ba2018-11-03 11:00:21 -06001354static void bc_num_setToZero(BcNum *n, size_t scale)
1355{
1356 n->len = 0;
1357 n->neg = false;
1358 n->rdx = scale;
1359}
1360
1361static void bc_num_zero(BcNum *n)
1362{
1363 bc_num_setToZero(n, 0);
1364}
1365
1366static void bc_num_one(BcNum *n)
1367{
1368 bc_num_setToZero(n, 0);
1369 n->len = 1;
1370 n->num[0] = 1;
1371}
1372
1373static void bc_num_ten(BcNum *n)
1374{
1375 bc_num_setToZero(n, 0);
1376 n->len = 2;
1377 n->num[0] = 0;
1378 n->num[1] = 1;
1379}
1380
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001381static void bc_num_init(BcNum *n, size_t req)
1382{
1383 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1384 memset(n, 0, sizeof(BcNum));
1385 n->num = xmalloc(req);
1386 n->cap = req;
1387}
1388
1389static void bc_num_expand(BcNum *n, size_t req)
1390{
1391 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1392 if (req > n->cap) {
1393 n->num = xrealloc(n->num, req);
1394 n->cap = req;
1395 }
1396}
1397
1398static void bc_num_free(void *num)
1399{
1400 free(((BcNum *) num)->num);
1401}
1402
1403static void bc_num_copy(BcNum *d, BcNum *s)
1404{
1405 if (d != s) {
1406 bc_num_expand(d, s->cap);
1407 d->len = s->len;
1408 d->neg = s->neg;
1409 d->rdx = s->rdx;
1410 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
1411 }
1412}
1413
1414static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
1415{
1416 size_t i;
1417 unsigned long pow;
1418
1419 if (n->neg) return bc_error("negative number");
1420
1421 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
1422
1423 unsigned long prev = *result, powprev = pow;
1424
1425 *result += ((unsigned long) n->num[i]) * pow;
1426 pow *= 10;
1427
1428 if (*result < prev || pow < powprev)
1429 return bc_error("overflow");
1430 }
1431
1432 return BC_STATUS_SUCCESS;
1433}
1434
1435static void bc_num_ulong2num(BcNum *n, unsigned long val)
1436{
1437 size_t len;
1438 BcDig *ptr;
1439 unsigned long i;
1440
1441 bc_num_zero(n);
1442
1443 if (val == 0) return;
1444
1445 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
1446 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
1447}
1448
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001449static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001450 size_t len)
1451{
1452 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001453 for (i = 0; i < len; ++i) {
1454 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001455 a[i + j++] += 10;
1456 a[i + j] -= 1;
1457 }
1458 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001459}
1460
1461static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1462{
1463 size_t i;
1464 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001465 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001466 return BC_NUM_NEG(i + 1, c < 0);
1467}
1468
1469static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1470{
1471 size_t i, min, a_int, b_int, diff;
1472 BcDig *max_num, *min_num;
1473 bool a_max, neg = false;
1474 ssize_t cmp;
1475
1476 if (a == b) return 0;
1477 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1478 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1479 if (a->neg) {
1480 if (b->neg)
1481 neg = true;
1482 else
1483 return -1;
1484 }
1485 else if (b->neg)
1486 return 1;
1487
1488 a_int = BC_NUM_INT(a);
1489 b_int = BC_NUM_INT(b);
1490 a_int -= b_int;
1491 a_max = (a->rdx > b->rdx);
1492
1493 if (a_int != 0) return (ssize_t) a_int;
1494
1495 if (a_max) {
1496 min = b->rdx;
1497 diff = a->rdx - b->rdx;
1498 max_num = a->num + diff;
1499 min_num = b->num;
1500 }
1501 else {
1502 min = a->rdx;
1503 diff = b->rdx - a->rdx;
1504 max_num = b->num + diff;
1505 min_num = a->num;
1506 }
1507
1508 cmp = bc_num_compare(max_num, min_num, b_int + min);
1509 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1510
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001511 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001512 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1513 }
1514
1515 return 0;
1516}
1517
1518static void bc_num_truncate(BcNum *n, size_t places)
1519{
1520 if (places == 0) return;
1521
1522 n->rdx -= places;
1523
1524 if (n->len != 0) {
1525 n->len -= places;
1526 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1527 }
1528}
1529
1530static void bc_num_extend(BcNum *n, size_t places)
1531{
1532 size_t len = n->len + places;
1533
1534 if (places != 0) {
1535
1536 if (n->cap < len) bc_num_expand(n, len);
1537
1538 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1539 memset(n->num, 0, sizeof(BcDig) * places);
1540
1541 n->len += places;
1542 n->rdx += places;
1543 }
1544}
1545
1546static void bc_num_clean(BcNum *n)
1547{
1548 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1549 if (n->len == 0)
1550 n->neg = false;
1551 else if (n->len < n->rdx)
1552 n->len = n->rdx;
1553}
1554
1555static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1556{
1557 if (n->rdx < scale)
1558 bc_num_extend(n, scale - n->rdx);
1559 else
1560 bc_num_truncate(n, n->rdx - scale);
1561
1562 bc_num_clean(n);
1563 if (n->len != 0) n->neg = !neg1 != !neg2;
1564}
1565
1566static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1567 BcNum *restrict b)
1568{
1569 if (idx < n->len) {
1570
1571 b->len = n->len - idx;
1572 a->len = idx;
1573 a->rdx = b->rdx = 0;
1574
1575 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1576 memcpy(a->num, n->num, idx * sizeof(BcDig));
1577 }
1578 else {
1579 bc_num_zero(b);
1580 bc_num_copy(a, n);
1581 }
1582
1583 bc_num_clean(a);
1584 bc_num_clean(b);
1585}
1586
1587static BcStatus bc_num_shift(BcNum *n, size_t places)
1588{
1589 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001590 if (places + n->len > BC_MAX_NUM)
1591 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001592
1593 if (n->rdx >= places)
1594 n->rdx -= places;
1595 else {
1596 bc_num_extend(n, places - n->rdx);
1597 n->rdx = 0;
1598 }
1599
1600 bc_num_clean(n);
1601
1602 return BC_STATUS_SUCCESS;
1603}
1604
1605static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1606{
1607 BcNum one;
1608 BcDig num[2];
1609
1610 one.cap = 2;
1611 one.num = num;
1612 bc_num_one(&one);
1613
1614 return bc_num_div(&one, a, b, scale);
1615}
1616
1617static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1618{
1619 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1620 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1621 int carry, in;
1622
1623 // Because this function doesn't need to use scale (per the bc spec),
1624 // I am hijacking it to say whether it's doing an add or a subtract.
1625
1626 if (a->len == 0) {
1627 bc_num_copy(c, b);
1628 if (sub && c->len) c->neg = !c->neg;
1629 return BC_STATUS_SUCCESS;
1630 }
1631 else if (b->len == 0) {
1632 bc_num_copy(c, a);
1633 return BC_STATUS_SUCCESS;
1634 }
1635
1636 c->neg = a->neg;
1637 c->rdx = BC_MAX(a->rdx, b->rdx);
1638 min_rdx = BC_MIN(a->rdx, b->rdx);
1639 c->len = 0;
1640
1641 if (a->rdx > b->rdx) {
1642 diff = a->rdx - b->rdx;
1643 ptr = a->num;
1644 ptr_a = a->num + diff;
1645 ptr_b = b->num;
1646 }
1647 else {
1648 diff = b->rdx - a->rdx;
1649 ptr = b->num;
1650 ptr_a = a->num;
1651 ptr_b = b->num + diff;
1652 }
1653
1654 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1655
1656 ptr_c += diff;
1657 a_int = BC_NUM_INT(a);
1658 b_int = BC_NUM_INT(b);
1659
1660 if (a_int > b_int) {
1661 min_int = b_int;
1662 max = a_int;
1663 ptr = ptr_a;
1664 }
1665 else {
1666 min_int = a_int;
1667 max = b_int;
1668 ptr = ptr_b;
1669 }
1670
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001671 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001672 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1673 carry = in / 10;
1674 ptr_c[i] = (BcDig)(in % 10);
1675 }
1676
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001677 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001678 in = ((int) ptr[i]) + carry;
1679 carry = in / 10;
1680 ptr_c[i] = (BcDig)(in % 10);
1681 }
1682
1683 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1684
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001685 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001686}
1687
1688static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1689{
Gavin Howard01055ba2018-11-03 11:00:21 -06001690 ssize_t cmp;
1691 BcNum *minuend, *subtrahend;
1692 size_t start;
1693 bool aneg, bneg, neg;
1694
1695 // Because this function doesn't need to use scale (per the bc spec),
1696 // I am hijacking it to say whether it's doing an add or a subtract.
1697
1698 if (a->len == 0) {
1699 bc_num_copy(c, b);
1700 if (sub && c->len) c->neg = !c->neg;
1701 return BC_STATUS_SUCCESS;
1702 }
1703 else if (b->len == 0) {
1704 bc_num_copy(c, a);
1705 return BC_STATUS_SUCCESS;
1706 }
1707
1708 aneg = a->neg;
1709 bneg = b->neg;
1710 a->neg = b->neg = false;
1711
1712 cmp = bc_num_cmp(a, b);
1713
1714 a->neg = aneg;
1715 b->neg = bneg;
1716
1717 if (cmp == 0) {
1718 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1719 return BC_STATUS_SUCCESS;
1720 }
1721 else if (cmp > 0) {
1722 neg = a->neg;
1723 minuend = a;
1724 subtrahend = b;
1725 }
1726 else {
1727 neg = b->neg;
1728 if (sub) neg = !neg;
1729 minuend = b;
1730 subtrahend = a;
1731 }
1732
1733 bc_num_copy(c, minuend);
1734 c->neg = neg;
1735
1736 if (c->rdx < subtrahend->rdx) {
1737 bc_num_extend(c, subtrahend->rdx - c->rdx);
1738 start = 0;
1739 }
1740 else
1741 start = c->rdx - subtrahend->rdx;
1742
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001743 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001744
1745 bc_num_clean(c);
1746
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001747 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001748}
1749
1750static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1751 BcNum *restrict c)
1752{
1753 BcStatus s;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001754 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
Gavin Howard01055ba2018-11-03 11:00:21 -06001755 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001756 bool aone;
Gavin Howard01055ba2018-11-03 11:00:21 -06001757
Gavin Howard01055ba2018-11-03 11:00:21 -06001758 if (a->len == 0 || b->len == 0) {
1759 bc_num_zero(c);
1760 return BC_STATUS_SUCCESS;
1761 }
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001762 aone = BC_NUM_ONE(a);
1763 if (aone || BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001764 bc_num_copy(c, aone ? b : a);
1765 return BC_STATUS_SUCCESS;
1766 }
1767
1768 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1769 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1770 {
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001771 size_t i, j, len;
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001772 unsigned carry;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001773
Gavin Howard01055ba2018-11-03 11:00:21 -06001774 bc_num_expand(c, a->len + b->len + 1);
1775
1776 memset(c->num, 0, sizeof(BcDig) * c->cap);
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001777 c->len = len = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06001778
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001779 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001780
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001781 carry = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001782 for (j = 0; j < a->len; ++j) {
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001783 unsigned in = c->num[i + j];
1784 in += ((unsigned) a->num[j]) * ((unsigned) b->num[i]) + carry;
1785 // note: compilers prefer _unsigned_ div/const
Gavin Howard01055ba2018-11-03 11:00:21 -06001786 carry = in / 10;
1787 c->num[i + j] = (BcDig)(in % 10);
1788 }
1789
1790 c->num[i + j] += (BcDig) carry;
1791 len = BC_MAX(len, i + j + !!carry);
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01001792
1793 // a=2^1000000
1794 // a*a <- without check below, this will not be interruptible
1795 if (G_interrupt) return BC_STATUS_FAILURE;
Gavin Howard01055ba2018-11-03 11:00:21 -06001796 }
1797
1798 c->len = len;
1799
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001800 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001801 }
1802
1803 bc_num_init(&l1, max);
1804 bc_num_init(&h1, max);
1805 bc_num_init(&l2, max);
1806 bc_num_init(&h2, max);
1807 bc_num_init(&m1, max);
1808 bc_num_init(&m2, max);
1809 bc_num_init(&z0, max);
1810 bc_num_init(&z1, max);
1811 bc_num_init(&z2, max);
1812 bc_num_init(&temp, max + max);
1813
1814 bc_num_split(a, max2, &l1, &h1);
1815 bc_num_split(b, max2, &l2, &h2);
1816
1817 s = bc_num_add(&h1, &l1, &m1, 0);
1818 if (s) goto err;
1819 s = bc_num_add(&h2, &l2, &m2, 0);
1820 if (s) goto err;
1821
1822 s = bc_num_k(&h1, &h2, &z0);
1823 if (s) goto err;
1824 s = bc_num_k(&m1, &m2, &z1);
1825 if (s) goto err;
1826 s = bc_num_k(&l1, &l2, &z2);
1827 if (s) goto err;
1828
1829 s = bc_num_sub(&z1, &z0, &temp, 0);
1830 if (s) goto err;
1831 s = bc_num_sub(&temp, &z2, &z1, 0);
1832 if (s) goto err;
1833
1834 s = bc_num_shift(&z0, max2 * 2);
1835 if (s) goto err;
1836 s = bc_num_shift(&z1, max2);
1837 if (s) goto err;
1838 s = bc_num_add(&z0, &z1, &temp, 0);
1839 if (s) goto err;
1840 s = bc_num_add(&temp, &z2, c, 0);
1841
1842err:
1843 bc_num_free(&temp);
1844 bc_num_free(&z2);
1845 bc_num_free(&z1);
1846 bc_num_free(&z0);
1847 bc_num_free(&m2);
1848 bc_num_free(&m1);
1849 bc_num_free(&h2);
1850 bc_num_free(&l2);
1851 bc_num_free(&h1);
1852 bc_num_free(&l1);
1853 return s;
1854}
1855
1856static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1857{
1858 BcStatus s;
1859 BcNum cpa, cpb;
1860 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1861
1862 scale = BC_MAX(scale, a->rdx);
1863 scale = BC_MAX(scale, b->rdx);
1864 scale = BC_MIN(a->rdx + b->rdx, scale);
1865 maxrdx = BC_MAX(maxrdx, scale);
1866
1867 bc_num_init(&cpa, a->len);
1868 bc_num_init(&cpb, b->len);
1869
1870 bc_num_copy(&cpa, a);
1871 bc_num_copy(&cpb, b);
1872 cpa.neg = cpb.neg = false;
1873
1874 s = bc_num_shift(&cpa, maxrdx);
1875 if (s) goto err;
1876 s = bc_num_shift(&cpb, maxrdx);
1877 if (s) goto err;
1878 s = bc_num_k(&cpa, &cpb, c);
1879 if (s) goto err;
1880
1881 maxrdx += scale;
1882 bc_num_expand(c, c->len + maxrdx);
1883
1884 if (c->len < maxrdx) {
1885 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1886 c->len += maxrdx;
1887 }
1888
1889 c->rdx = maxrdx;
1890 bc_num_retireMul(c, scale, a->neg, b->neg);
1891
1892err:
1893 bc_num_free(&cpb);
1894 bc_num_free(&cpa);
1895 return s;
1896}
1897
1898static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1899{
1900 BcStatus s = BC_STATUS_SUCCESS;
1901 BcDig *n, *p, q;
1902 size_t len, end, i;
1903 BcNum cp;
1904 bool zero = true;
1905
1906 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001907 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001908 else if (a->len == 0) {
1909 bc_num_setToZero(c, scale);
1910 return BC_STATUS_SUCCESS;
1911 }
1912 else if (BC_NUM_ONE(b)) {
1913 bc_num_copy(c, a);
1914 bc_num_retireMul(c, scale, a->neg, b->neg);
1915 return BC_STATUS_SUCCESS;
1916 }
1917
1918 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1919 bc_num_copy(&cp, a);
1920 len = b->len;
1921
1922 if (len > cp.len) {
1923 bc_num_expand(&cp, len + 2);
1924 bc_num_extend(&cp, len - cp.len);
1925 }
1926
1927 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1928 cp.rdx -= b->rdx;
1929 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1930
1931 if (b->rdx == b->len) {
1932 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1933 len -= i - 1;
1934 }
1935
1936 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1937
1938 // We want an extra zero in front to make things simpler.
1939 cp.num[cp.len++] = 0;
1940 end = cp.len - len;
1941
1942 bc_num_expand(c, cp.len);
1943
1944 bc_num_zero(c);
1945 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1946 c->rdx = cp.rdx;
1947 c->len = cp.len;
1948 p = b->num;
1949
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001950 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001951 n = cp.num + i;
1952 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001953 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001954 c->num[i] = q;
Denys Vlasenkof381a882018-12-05 19:21:34 +01001955 // a=2^100000
1956 // scale=40000
1957 // 1/a <- without check below, this will not be interruptible
1958 if (G_interrupt) {
1959 s = BC_STATUS_FAILURE;
1960 break;
1961 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001962 }
1963
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001964 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001965 bc_num_free(&cp);
1966
Denys Vlasenkof381a882018-12-05 19:21:34 +01001967 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06001968}
1969
1970static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1971 BcNum *restrict d, size_t scale, size_t ts)
1972{
1973 BcStatus s;
1974 BcNum temp;
1975 bool neg;
1976
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001977 if (b->len == 0)
1978 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001979
1980 if (a->len == 0) {
1981 bc_num_setToZero(d, ts);
1982 return BC_STATUS_SUCCESS;
1983 }
1984
1985 bc_num_init(&temp, d->cap);
Denys Vlasenkof381a882018-12-05 19:21:34 +01001986 s = bc_num_d(a, b, c, scale);
1987 if (s) goto err;
Gavin Howard01055ba2018-11-03 11:00:21 -06001988
1989 if (scale != 0) scale = ts;
1990
1991 s = bc_num_m(c, b, &temp, scale);
1992 if (s) goto err;
1993 s = bc_num_sub(a, &temp, d, scale);
1994 if (s) goto err;
1995
1996 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1997
1998 neg = d->neg;
1999 bc_num_retireMul(d, ts, a->neg, b->neg);
2000 d->neg = neg;
2001
2002err:
2003 bc_num_free(&temp);
2004 return s;
2005}
2006
2007static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2008{
2009 BcStatus s;
2010 BcNum c1;
2011 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2012
2013 bc_num_init(&c1, len);
2014 s = bc_num_r(a, b, &c1, c, scale, ts);
2015 bc_num_free(&c1);
2016
2017 return s;
2018}
2019
2020static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2021{
2022 BcStatus s = BC_STATUS_SUCCESS;
2023 BcNum copy;
2024 unsigned long pow;
2025 size_t i, powrdx, resrdx;
2026 bool neg, zero;
2027
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002028 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002029
2030 if (b->len == 0) {
2031 bc_num_one(c);
2032 return BC_STATUS_SUCCESS;
2033 }
2034 else if (a->len == 0) {
2035 bc_num_setToZero(c, scale);
2036 return BC_STATUS_SUCCESS;
2037 }
2038 else if (BC_NUM_ONE(b)) {
2039 if (!b->neg)
2040 bc_num_copy(c, a);
2041 else
2042 s = bc_num_inv(a, c, scale);
2043 return s;
2044 }
2045
2046 neg = b->neg;
2047 b->neg = false;
2048
2049 s = bc_num_ulong(b, &pow);
2050 if (s) return s;
2051
2052 bc_num_init(&copy, a->len);
2053 bc_num_copy(&copy, a);
2054
2055 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2056
2057 b->neg = neg;
2058
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002059 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002060 powrdx <<= 1;
2061 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2062 if (s) goto err;
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002063 // Not needed: bc_num_mul() has a check for ^C:
2064 //if (G_interrupt) {
2065 // s = BC_STATUS_FAILURE;
2066 // goto err;
2067 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002068 }
2069
Gavin Howard01055ba2018-11-03 11:00:21 -06002070 bc_num_copy(c, &copy);
2071
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002072 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002073
2074 powrdx <<= 1;
2075 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2076 if (s) goto err;
2077
2078 if (pow & 1) {
2079 resrdx += powrdx;
2080 s = bc_num_mul(c, &copy, c, resrdx);
2081 if (s) goto err;
2082 }
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002083 // Not needed: bc_num_mul() has a check for ^C:
2084 //if (G_interrupt) {
2085 // s = BC_STATUS_FAILURE;
2086 // goto err;
2087 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002088 }
2089
2090 if (neg) {
2091 s = bc_num_inv(c, c, scale);
2092 if (s) goto err;
2093 }
2094
Gavin Howard01055ba2018-11-03 11:00:21 -06002095 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2096
2097 // We can't use bc_num_clean() here.
2098 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2099 if (zero) bc_num_setToZero(c, scale);
2100
2101err:
2102 bc_num_free(&copy);
2103 return s;
2104}
2105
2106static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2107 BcNumBinaryOp op, size_t req)
2108{
2109 BcStatus s;
2110 BcNum num2, *ptr_a, *ptr_b;
2111 bool init = false;
2112
2113 if (c == a) {
2114 ptr_a = &num2;
2115 memcpy(ptr_a, c, sizeof(BcNum));
2116 init = true;
2117 }
2118 else
2119 ptr_a = a;
2120
2121 if (c == b) {
2122 ptr_b = &num2;
2123 if (c != a) {
2124 memcpy(ptr_b, c, sizeof(BcNum));
2125 init = true;
2126 }
2127 }
2128 else
2129 ptr_b = b;
2130
2131 if (init)
2132 bc_num_init(c, req);
2133 else
2134 bc_num_expand(c, req);
2135
2136 s = op(ptr_a, ptr_b, c, scale);
2137
2138 if (init) bc_num_free(&num2);
2139
2140 return s;
2141}
2142
2143static bool bc_num_strValid(const char *val, size_t base)
2144{
2145 BcDig b;
2146 bool small, radix = false;
2147 size_t i, len = strlen(val);
2148
2149 if (!len) return true;
2150
2151 small = base <= 10;
2152 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2153
2154 for (i = 0; i < len; ++i) {
2155
2156 BcDig c = val[i];
2157
2158 if (c == '.') {
2159
2160 if (radix) return false;
2161
2162 radix = true;
2163 continue;
2164 }
2165
2166 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2167 return false;
2168 }
2169
2170 return true;
2171}
2172
2173static void bc_num_parseDecimal(BcNum *n, const char *val)
2174{
2175 size_t len, i;
2176 const char *ptr;
2177 bool zero = true;
2178
2179 for (i = 0; val[i] == '0'; ++i);
2180
2181 val += i;
2182 len = strlen(val);
2183 bc_num_zero(n);
2184
2185 if (len != 0) {
2186 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2187 bc_num_expand(n, len);
2188 }
2189
2190 ptr = strchr(val, '.');
2191
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002192 n->rdx = 0;
2193 if (ptr != NULL)
2194 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002195
2196 if (!zero) {
2197 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2198 n->num[n->len] = val[i] - '0';
2199 }
2200}
2201
2202static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2203{
2204 BcStatus s;
2205 BcNum temp, mult, result;
2206 BcDig c = '\0';
2207 bool zero = true;
2208 unsigned long v;
2209 size_t i, digits, len = strlen(val);
2210
2211 bc_num_zero(n);
2212
2213 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2214 if (zero) return;
2215
2216 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2217 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2218
2219 for (i = 0; i < len; ++i) {
2220
2221 c = val[i];
2222 if (c == '.') break;
2223
2224 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2225
2226 s = bc_num_mul(n, base, &mult, 0);
2227 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002228 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002229 s = bc_num_add(&mult, &temp, n, 0);
2230 if (s) goto int_err;
2231 }
2232
2233 if (i == len) {
2234 c = val[i];
2235 if (c == 0) goto int_err;
2236 }
2237
2238 bc_num_init(&result, base->len);
2239 bc_num_zero(&result);
2240 bc_num_one(&mult);
2241
2242 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2243
2244 c = val[i];
2245 if (c == 0) break;
2246
2247 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2248
2249 s = bc_num_mul(&result, base, &result, 0);
2250 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002251 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002252 s = bc_num_add(&result, &temp, &result, 0);
2253 if (s) goto err;
2254 s = bc_num_mul(&mult, base, &mult, 0);
2255 if (s) goto err;
2256 }
2257
2258 s = bc_num_div(&result, &mult, &result, digits);
2259 if (s) goto err;
2260 s = bc_num_add(n, &result, n, digits);
2261 if (s) goto err;
2262
2263 if (n->len != 0) {
2264 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2265 }
2266 else
2267 bc_num_zero(n);
2268
2269err:
2270 bc_num_free(&result);
2271int_err:
2272 bc_num_free(&mult);
2273 bc_num_free(&temp);
2274}
2275
2276static void bc_num_printNewline(size_t *nchars, size_t line_len)
2277{
2278 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002279 bb_putchar('\\');
2280 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002281 *nchars = 0;
2282 }
2283}
2284
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002285#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002286static void bc_num_printChar(size_t num, size_t width, bool radix,
2287 size_t *nchars, size_t line_len)
2288{
2289 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002290 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002291 *nchars = *nchars + width;
2292}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002293#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002294
2295static void bc_num_printDigits(size_t num, size_t width, bool radix,
2296 size_t *nchars, size_t line_len)
2297{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002298 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002299
2300 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002301 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002302 ++(*nchars);
2303
2304 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002305 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2306 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002307
2308 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002309 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002310 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002311 dig = num / pow;
2312 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002313 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002314 }
2315}
2316
2317static void bc_num_printHex(size_t num, size_t width, bool radix,
2318 size_t *nchars, size_t line_len)
2319{
2320 if (radix) {
2321 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002322 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002323 *nchars += 1;
2324 }
2325
2326 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002327 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002328 *nchars = *nchars + width;
2329}
2330
2331static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2332{
2333 size_t i, rdx = n->rdx - 1;
2334
Denys Vlasenko00d77792018-11-30 23:13:42 +01002335 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002336 (*nchars) += n->neg;
2337
2338 for (i = n->len - 1; i < n->len; --i)
2339 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2340}
2341
2342static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2343 size_t *nchars, size_t len, BcNumDigitOp print)
2344{
2345 BcStatus s;
2346 BcVec stack;
2347 BcNum intp, fracp, digit, frac_len;
2348 unsigned long dig, *ptr;
2349 size_t i;
2350 bool radix;
2351
2352 if (n->len == 0) {
2353 print(0, width, false, nchars, len);
2354 return BC_STATUS_SUCCESS;
2355 }
2356
2357 bc_vec_init(&stack, sizeof(long), NULL);
2358 bc_num_init(&intp, n->len);
2359 bc_num_init(&fracp, n->rdx);
2360 bc_num_init(&digit, width);
2361 bc_num_init(&frac_len, BC_NUM_INT(n));
2362 bc_num_copy(&intp, n);
2363 bc_num_one(&frac_len);
2364
2365 bc_num_truncate(&intp, intp.rdx);
2366 s = bc_num_sub(n, &intp, &fracp, 0);
2367 if (s) goto err;
2368
2369 while (intp.len != 0) {
2370 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2371 if (s) goto err;
2372 s = bc_num_ulong(&digit, &dig);
2373 if (s) goto err;
2374 bc_vec_push(&stack, &dig);
2375 }
2376
2377 for (i = 0; i < stack.len; ++i) {
2378 ptr = bc_vec_item_rev(&stack, i);
2379 print(*ptr, width, false, nchars, len);
2380 }
2381
2382 if (!n->rdx) goto err;
2383
2384 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2385 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2386 if (s) goto err;
2387 s = bc_num_ulong(&fracp, &dig);
2388 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002389 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002390 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2391 if (s) goto err;
2392 print(dig, width, radix, nchars, len);
2393 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2394 if (s) goto err;
2395 }
2396
2397err:
2398 bc_num_free(&frac_len);
2399 bc_num_free(&digit);
2400 bc_num_free(&fracp);
2401 bc_num_free(&intp);
2402 bc_vec_free(&stack);
2403 return s;
2404}
2405
2406static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2407 size_t *nchars, size_t line_len)
2408{
2409 BcStatus s;
2410 size_t width, i;
2411 BcNumDigitOp print;
2412 bool neg = n->neg;
2413
Denys Vlasenko00d77792018-11-30 23:13:42 +01002414 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002415 (*nchars) += neg;
2416
2417 n->neg = false;
2418
2419 if (base_t <= BC_NUM_MAX_IBASE) {
2420 width = 1;
2421 print = bc_num_printHex;
2422 }
2423 else {
2424 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2425 print = bc_num_printDigits;
2426 }
2427
2428 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2429 n->neg = neg;
2430
2431 return s;
2432}
2433
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002434#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002435static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2436{
2437 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2438}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002439#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002440
Gavin Howard01055ba2018-11-03 11:00:21 -06002441static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2442 size_t base_t)
2443{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002444 if (!bc_num_strValid(val, base_t))
2445 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002446
2447 if (base_t == 10)
2448 bc_num_parseDecimal(n, val);
2449 else
2450 bc_num_parseBase(n, val, base);
2451
2452 return BC_STATUS_SUCCESS;
2453}
2454
2455static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2456 size_t *nchars, size_t line_len)
2457{
2458 BcStatus s = BC_STATUS_SUCCESS;
2459
2460 bc_num_printNewline(nchars, line_len);
2461
2462 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002463 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002464 ++(*nchars);
2465 }
2466 else if (base_t == 10)
2467 bc_num_printDecimal(n, nchars, line_len);
2468 else
2469 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2470
2471 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002472 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002473 *nchars = 0;
2474 }
2475
2476 return s;
2477}
2478
Gavin Howard01055ba2018-11-03 11:00:21 -06002479static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2480{
2481 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2482 (void) scale;
2483 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2484}
2485
2486static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2487{
2488 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2489 (void) scale;
2490 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2491}
2492
2493static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2494{
2495 size_t req = BC_NUM_MREQ(a, b, scale);
2496 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2497}
2498
2499static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2500{
2501 size_t req = BC_NUM_MREQ(a, b, scale);
2502 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2503}
2504
2505static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2506{
2507 size_t req = BC_NUM_MREQ(a, b, scale);
2508 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2509}
2510
2511static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2512{
2513 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2514}
2515
2516static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2517{
2518 BcStatus s;
2519 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2520 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2521 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2522
2523 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2524 bc_num_expand(b, req);
2525
2526 if (a->len == 0) {
2527 bc_num_setToZero(b, scale);
2528 return BC_STATUS_SUCCESS;
2529 }
2530 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002531 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002532 else if (BC_NUM_ONE(a)) {
2533 bc_num_one(b);
2534 bc_num_extend(b, scale);
2535 return BC_STATUS_SUCCESS;
2536 }
2537
2538 scale = BC_MAX(scale, a->rdx) + 1;
2539 len = a->len + scale;
2540
2541 bc_num_init(&num1, len);
2542 bc_num_init(&num2, len);
2543 bc_num_init(&half, BC_NUM_DEF_SIZE);
2544
2545 bc_num_one(&half);
2546 half.num[0] = 5;
2547 half.rdx = 1;
2548
2549 bc_num_init(&f, len);
2550 bc_num_init(&fprime, len);
2551
2552 x0 = &num1;
2553 x1 = &num2;
2554
2555 bc_num_one(x0);
2556 pow = BC_NUM_INT(a);
2557
2558 if (pow) {
2559
2560 if (pow & 1)
2561 x0->num[0] = 2;
2562 else
2563 x0->num[0] = 6;
2564
2565 pow -= 2 - (pow & 1);
2566
2567 bc_num_extend(x0, pow);
2568
2569 // Make sure to move the radix back.
2570 x0->rdx -= pow;
2571 }
2572
2573 x0->rdx = digs = digs1 = 0;
2574 resrdx = scale + 2;
2575 len = BC_NUM_INT(x0) + resrdx - 1;
2576
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002577 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002578
2579 s = bc_num_div(a, x0, &f, resrdx);
2580 if (s) goto err;
2581 s = bc_num_add(x0, &f, &fprime, resrdx);
2582 if (s) goto err;
2583 s = bc_num_mul(&fprime, &half, x1, resrdx);
2584 if (s) goto err;
2585
2586 cmp = bc_num_cmp(x1, x0);
2587 digs = x1->len - (unsigned long long) llabs(cmp);
2588
2589 if (cmp == cmp2 && digs == digs1)
2590 times += 1;
2591 else
2592 times = 0;
2593
2594 resrdx += times > 4;
2595
2596 cmp2 = cmp1;
2597 cmp1 = cmp;
2598 digs1 = digs;
2599
2600 temp = x0;
2601 x0 = x1;
2602 x1 = temp;
2603 }
2604
Gavin Howard01055ba2018-11-03 11:00:21 -06002605 bc_num_copy(b, x0);
2606 scale -= 1;
2607 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2608
2609err:
2610 bc_num_free(&fprime);
2611 bc_num_free(&f);
2612 bc_num_free(&half);
2613 bc_num_free(&num2);
2614 bc_num_free(&num1);
2615 return s;
2616}
2617
2618static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2619 size_t scale)
2620{
2621 BcStatus s;
2622 BcNum num2, *ptr_a;
2623 bool init = false;
2624 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2625
2626 if (c == a) {
2627 memcpy(&num2, c, sizeof(BcNum));
2628 ptr_a = &num2;
2629 bc_num_init(c, len);
2630 init = true;
2631 }
2632 else {
2633 ptr_a = a;
2634 bc_num_expand(c, len);
2635 }
2636
2637 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2638
2639 if (init) bc_num_free(&num2);
2640
2641 return s;
2642}
2643
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002644#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002645static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2646{
2647 BcStatus s;
2648 BcNum base, exp, two, temp;
2649
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002650 if (c->len == 0)
2651 return bc_error("divide by zero");
2652 if (a->rdx || b->rdx || c->rdx)
2653 return bc_error("non integer number");
2654 if (b->neg)
2655 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002656
2657 bc_num_expand(d, c->len);
2658 bc_num_init(&base, c->len);
2659 bc_num_init(&exp, b->len);
2660 bc_num_init(&two, BC_NUM_DEF_SIZE);
2661 bc_num_init(&temp, b->len);
2662
2663 bc_num_one(&two);
2664 two.num[0] = 2;
2665 bc_num_one(d);
2666
2667 s = bc_num_rem(a, c, &base, 0);
2668 if (s) goto err;
2669 bc_num_copy(&exp, b);
2670
2671 while (exp.len != 0) {
2672
2673 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2674 if (s) goto err;
2675
2676 if (BC_NUM_ONE(&temp)) {
2677 s = bc_num_mul(d, &base, &temp, 0);
2678 if (s) goto err;
2679 s = bc_num_rem(&temp, c, d, 0);
2680 if (s) goto err;
2681 }
2682
2683 s = bc_num_mul(&base, &base, &temp, 0);
2684 if (s) goto err;
2685 s = bc_num_rem(&temp, c, &base, 0);
2686 if (s) goto err;
2687 }
2688
2689err:
2690 bc_num_free(&temp);
2691 bc_num_free(&two);
2692 bc_num_free(&exp);
2693 bc_num_free(&base);
2694 return s;
2695}
2696#endif // ENABLE_DC
2697
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01002698#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002699static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2700{
2701 BcId a;
2702 size_t i;
2703
2704 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002705 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2706 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002707 }
2708
2709 a.idx = var;
2710 a.name = name;
2711
2712 bc_vec_push(&f->autos, &a);
2713
2714 return BC_STATUS_SUCCESS;
2715}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01002716#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002717
2718static void bc_func_init(BcFunc *f)
2719{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002720 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002721 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2722 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2723 f->nparams = 0;
2724}
2725
2726static void bc_func_free(void *func)
2727{
2728 BcFunc *f = (BcFunc *) func;
2729 bc_vec_free(&f->code);
2730 bc_vec_free(&f->autos);
2731 bc_vec_free(&f->labels);
2732}
2733
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002734static void bc_array_expand(BcVec *a, size_t len);
2735
Gavin Howard01055ba2018-11-03 11:00:21 -06002736static void bc_array_init(BcVec *a, bool nums)
2737{
2738 if (nums)
2739 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2740 else
2741 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2742 bc_array_expand(a, 1);
2743}
2744
Gavin Howard01055ba2018-11-03 11:00:21 -06002745static void bc_array_expand(BcVec *a, size_t len)
2746{
2747 BcResultData data;
2748
2749 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2750 while (len > a->len) {
2751 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2752 bc_vec_push(a, &data.n);
2753 }
2754 }
2755 else {
2756 while (len > a->len) {
2757 bc_array_init(&data.v, true);
2758 bc_vec_push(a, &data.v);
2759 }
2760 }
2761}
2762
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002763static void bc_array_copy(BcVec *d, const BcVec *s)
2764{
2765 size_t i;
2766
2767 bc_vec_pop_all(d);
2768 bc_vec_expand(d, s->cap);
2769 d->len = s->len;
2770
2771 for (i = 0; i < s->len; ++i) {
2772 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2773 bc_num_init(dnum, snum->len);
2774 bc_num_copy(dnum, snum);
2775 }
2776}
2777
Gavin Howard01055ba2018-11-03 11:00:21 -06002778static void bc_string_free(void *string)
2779{
2780 free(*((char **) string));
2781}
2782
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002783#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002784static void bc_result_copy(BcResult *d, BcResult *src)
2785{
2786 d->t = src->t;
2787
2788 switch (d->t) {
2789
2790 case BC_RESULT_TEMP:
2791 case BC_RESULT_IBASE:
2792 case BC_RESULT_SCALE:
2793 case BC_RESULT_OBASE:
2794 {
2795 bc_num_init(&d->d.n, src->d.n.len);
2796 bc_num_copy(&d->d.n, &src->d.n);
2797 break;
2798 }
2799
2800 case BC_RESULT_VAR:
2801 case BC_RESULT_ARRAY:
2802 case BC_RESULT_ARRAY_ELEM:
2803 {
2804 d->d.id.name = xstrdup(src->d.id.name);
2805 break;
2806 }
2807
2808 case BC_RESULT_CONSTANT:
2809 case BC_RESULT_LAST:
2810 case BC_RESULT_ONE:
2811 case BC_RESULT_STR:
2812 {
2813 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2814 break;
2815 }
2816 }
2817}
2818#endif // ENABLE_DC
2819
2820static void bc_result_free(void *result)
2821{
2822 BcResult *r = (BcResult *) result;
2823
2824 switch (r->t) {
2825
2826 case BC_RESULT_TEMP:
2827 case BC_RESULT_IBASE:
2828 case BC_RESULT_SCALE:
2829 case BC_RESULT_OBASE:
2830 {
2831 bc_num_free(&r->d.n);
2832 break;
2833 }
2834
2835 case BC_RESULT_VAR:
2836 case BC_RESULT_ARRAY:
2837 case BC_RESULT_ARRAY_ELEM:
2838 {
2839 free(r->d.id.name);
2840 break;
2841 }
2842
2843 default:
2844 {
2845 // Do nothing.
2846 break;
2847 }
2848 }
2849}
2850
2851static void bc_lex_lineComment(BcLex *l)
2852{
2853 l->t.t = BC_LEX_WHITESPACE;
2854 while (l->i < l->len && l->buf[l->i++] != '\n');
2855 --l->i;
2856}
2857
2858static void bc_lex_whitespace(BcLex *l)
2859{
2860 char c;
2861 l->t.t = BC_LEX_WHITESPACE;
2862 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2863}
2864
2865static BcStatus bc_lex_number(BcLex *l, char start)
2866{
2867 const char *buf = l->buf + l->i;
2868 size_t len, hits = 0, bslashes = 0, i = 0, j;
2869 char c = buf[i];
2870 bool last_pt, pt = start == '.';
2871
2872 last_pt = pt;
2873 l->t.t = BC_LEX_NUMBER;
2874
2875 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2876 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2877 {
2878 if (c != '\\') {
2879 last_pt = c == '.';
2880 pt = pt || last_pt;
2881 }
2882 else {
2883 ++i;
2884 bslashes += 1;
2885 }
2886
2887 c = buf[++i];
2888 }
2889
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002890 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002891 if (len > BC_MAX_NUM)
2892 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002893
Denys Vlasenko7d628012018-12-04 21:46:47 +01002894 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002895 bc_vec_expand(&l->t.v, len + 1);
2896 bc_vec_push(&l->t.v, &start);
2897
2898 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2899
2900 c = buf[j];
2901
2902 // If we have hit a backslash, skip it. We don't have
2903 // to check for a newline because it's guaranteed.
2904 if (hits < bslashes && c == '\\') {
2905 ++hits;
2906 ++j;
2907 continue;
2908 }
2909
2910 bc_vec_push(&l->t.v, &c);
2911 }
2912
Denys Vlasenko08c033c2018-12-05 16:55:08 +01002913 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002914 l->i += i;
2915
2916 return BC_STATUS_SUCCESS;
2917}
2918
2919static BcStatus bc_lex_name(BcLex *l)
2920{
2921 size_t i = 0;
2922 const char *buf = l->buf + l->i - 1;
2923 char c = buf[i];
2924
2925 l->t.t = BC_LEX_NAME;
2926
2927 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2928
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002929 if (i > BC_MAX_STRING)
2930 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002931 bc_vec_string(&l->t.v, i, buf);
2932
2933 // Increment the index. We minus 1 because it has already been incremented.
2934 l->i += i - 1;
2935
2936 return BC_STATUS_SUCCESS;
2937}
2938
2939static void bc_lex_init(BcLex *l, BcLexNext next)
2940{
2941 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002942 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002943}
2944
2945static void bc_lex_free(BcLex *l)
2946{
2947 bc_vec_free(&l->t.v);
2948}
2949
Denys Vlasenko0409ad32018-12-05 16:39:22 +01002950static void bc_lex_file(BcLex *l)
Gavin Howard01055ba2018-11-03 11:00:21 -06002951{
Denys Vlasenko5318f812018-12-05 17:48:01 +01002952 G.err_line = l->line = 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002953 l->newline = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06002954}
2955
2956static BcStatus bc_lex_next(BcLex *l)
2957{
2958 BcStatus s;
2959
2960 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002961 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002962
2963 l->line += l->newline;
Denys Vlasenko5318f812018-12-05 17:48:01 +01002964 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06002965 l->t.t = BC_LEX_EOF;
2966
2967 l->newline = (l->i == l->len);
2968 if (l->newline) return BC_STATUS_SUCCESS;
2969
2970 // Loop until failure or we don't have whitespace. This
2971 // is so the parser doesn't get inundated with whitespace.
2972 do {
2973 s = l->next(l);
2974 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2975
2976 return s;
2977}
2978
2979static BcStatus bc_lex_text(BcLex *l, const char *text)
2980{
2981 l->buf = text;
2982 l->i = 0;
2983 l->len = strlen(text);
2984 l->t.t = l->t.last = BC_LEX_INVALID;
2985 return bc_lex_next(l);
2986}
2987
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002988#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002989static BcStatus bc_lex_identifier(BcLex *l)
2990{
2991 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002992 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06002993 const char *buf = l->buf + l->i - 1;
2994
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002995 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2996 const char *keyword8 = bc_lex_kws[i].name8;
2997 unsigned j = 0;
2998 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2999 j++;
3000 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06003001 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003002 if (keyword8[j] != '\0')
3003 continue;
3004 match:
3005 // buf starts with keyword bc_lex_kws[i]
3006 l->t.t = BC_LEX_KEY_1st_keyword + i;
Denys Vlasenkod00d2f92018-12-06 12:59:40 +01003007 if (!bc_lex_kws_POSIX(i)) {
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003008 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003009 if (s) return s;
3010 }
3011
3012 // We minus 1 because the index has already been incremented.
3013 l->i += j - 1;
3014 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003015 }
3016
3017 s = bc_lex_name(l);
3018 if (s) return s;
3019
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003020 if (l->t.v.len > 2) {
3021 // Prevent this:
3022 // >>> qwe=1
3023 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
3024 // '
3025 unsigned len = strchrnul(buf, '\n') - buf;
3026 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
3027 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003028
3029 return s;
3030}
3031
3032static BcStatus bc_lex_string(BcLex *l)
3033{
3034 size_t len, nls = 0, i = l->i;
3035 char c;
3036
3037 l->t.t = BC_LEX_STR;
3038
3039 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3040
3041 if (c == '\0') {
3042 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003043 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003044 }
3045
3046 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003047 if (len > BC_MAX_STRING)
3048 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003049 bc_vec_string(&l->t.v, len, l->buf + l->i);
3050
3051 l->i = i + 1;
3052 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003053 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003054
3055 return BC_STATUS_SUCCESS;
3056}
3057
3058static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3059{
3060 if (l->buf[l->i] == '=') {
3061 ++l->i;
3062 l->t.t = with;
3063 }
3064 else
3065 l->t.t = without;
3066}
3067
3068static BcStatus bc_lex_comment(BcLex *l)
3069{
3070 size_t i, nls = 0;
3071 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003072
3073 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003074 i = ++l->i;
3075 for (;;) {
3076 char c = buf[i];
3077 check_star:
3078 if (c == '*') {
3079 c = buf[++i];
3080 if (c == '/')
3081 break;
3082 goto check_star;
3083 }
3084 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003085 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003086 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003087 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003088 nls += (c == '\n');
3089 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003090 }
3091
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003092 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003093 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003094 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003095
3096 return BC_STATUS_SUCCESS;
3097}
3098
3099static BcStatus bc_lex_token(BcLex *l)
3100{
3101 BcStatus s = BC_STATUS_SUCCESS;
3102 char c = l->buf[l->i++], c2;
3103
3104 // This is the workhorse of the lexer.
3105 switch (c) {
3106
3107 case '\0':
3108 case '\n':
3109 {
3110 l->newline = true;
3111 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3112 break;
3113 }
3114
3115 case '\t':
3116 case '\v':
3117 case '\f':
3118 case '\r':
3119 case ' ':
3120 {
3121 bc_lex_whitespace(l);
3122 break;
3123 }
3124
3125 case '!':
3126 {
3127 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3128
3129 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko00646792018-12-05 18:12:27 +01003130 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
Gavin Howard01055ba2018-11-03 11:00:21 -06003131 if (s) return s;
3132 }
3133
3134 break;
3135 }
3136
3137 case '"':
3138 {
3139 s = bc_lex_string(l);
3140 break;
3141 }
3142
3143 case '#':
3144 {
Denys Vlasenko00646792018-12-05 18:12:27 +01003145 s = bc_POSIX_does_not_allow("'#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003146 if (s) return s;
3147
3148 bc_lex_lineComment(l);
3149
3150 break;
3151 }
3152
3153 case '%':
3154 {
3155 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3156 break;
3157 }
3158
3159 case '&':
3160 {
3161 c2 = l->buf[l->i];
3162 if (c2 == '&') {
3163
Denys Vlasenko00646792018-12-05 18:12:27 +01003164 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
Gavin Howard01055ba2018-11-03 11:00:21 -06003165 if (s) return s;
3166
3167 ++l->i;
3168 l->t.t = BC_LEX_OP_BOOL_AND;
3169 }
3170 else {
3171 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003172 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003173 }
3174
3175 break;
3176 }
3177
3178 case '(':
3179 case ')':
3180 {
3181 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3182 break;
3183 }
3184
3185 case '*':
3186 {
3187 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3188 break;
3189 }
3190
3191 case '+':
3192 {
3193 c2 = l->buf[l->i];
3194 if (c2 == '+') {
3195 ++l->i;
3196 l->t.t = BC_LEX_OP_INC;
3197 }
3198 else
3199 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3200 break;
3201 }
3202
3203 case ',':
3204 {
3205 l->t.t = BC_LEX_COMMA;
3206 break;
3207 }
3208
3209 case '-':
3210 {
3211 c2 = l->buf[l->i];
3212 if (c2 == '-') {
3213 ++l->i;
3214 l->t.t = BC_LEX_OP_DEC;
3215 }
3216 else
3217 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3218 break;
3219 }
3220
3221 case '.':
3222 {
3223 if (isdigit(l->buf[l->i]))
3224 s = bc_lex_number(l, c);
3225 else {
3226 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko00646792018-12-05 18:12:27 +01003227 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003228 }
3229 break;
3230 }
3231
3232 case '/':
3233 {
3234 c2 = l->buf[l->i];
3235 if (c2 == '*')
3236 s = bc_lex_comment(l);
3237 else
3238 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3239 break;
3240 }
3241
3242 case '0':
3243 case '1':
3244 case '2':
3245 case '3':
3246 case '4':
3247 case '5':
3248 case '6':
3249 case '7':
3250 case '8':
3251 case '9':
3252 case 'A':
3253 case 'B':
3254 case 'C':
3255 case 'D':
3256 case 'E':
3257 case 'F':
3258 {
3259 s = bc_lex_number(l, c);
3260 break;
3261 }
3262
3263 case ';':
3264 {
3265 l->t.t = BC_LEX_SCOLON;
3266 break;
3267 }
3268
3269 case '<':
3270 {
3271 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3272 break;
3273 }
3274
3275 case '=':
3276 {
3277 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3278 break;
3279 }
3280
3281 case '>':
3282 {
3283 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3284 break;
3285 }
3286
3287 case '[':
3288 case ']':
3289 {
3290 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3291 break;
3292 }
3293
3294 case '\\':
3295 {
3296 if (l->buf[l->i] == '\n') {
3297 l->t.t = BC_LEX_WHITESPACE;
3298 ++l->i;
3299 }
3300 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003301 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003302 break;
3303 }
3304
3305 case '^':
3306 {
3307 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3308 break;
3309 }
3310
3311 case 'a':
3312 case 'b':
3313 case 'c':
3314 case 'd':
3315 case 'e':
3316 case 'f':
3317 case 'g':
3318 case 'h':
3319 case 'i':
3320 case 'j':
3321 case 'k':
3322 case 'l':
3323 case 'm':
3324 case 'n':
3325 case 'o':
3326 case 'p':
3327 case 'q':
3328 case 'r':
3329 case 's':
3330 case 't':
3331 case 'u':
3332 case 'v':
3333 case 'w':
3334 case 'x':
3335 case 'y':
3336 case 'z':
3337 {
3338 s = bc_lex_identifier(l);
3339 break;
3340 }
3341
3342 case '{':
3343 case '}':
3344 {
3345 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3346 break;
3347 }
3348
3349 case '|':
3350 {
3351 c2 = l->buf[l->i];
3352
3353 if (c2 == '|') {
Denys Vlasenko00646792018-12-05 18:12:27 +01003354 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
Gavin Howard01055ba2018-11-03 11:00:21 -06003355 if (s) return s;
3356
3357 ++l->i;
3358 l->t.t = BC_LEX_OP_BOOL_OR;
3359 }
3360 else {
3361 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003362 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003363 }
3364
3365 break;
3366 }
3367
3368 default:
3369 {
3370 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003371 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003372 break;
3373 }
3374 }
3375
3376 return s;
3377}
3378#endif // ENABLE_BC
3379
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003380#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003381static BcStatus dc_lex_register(BcLex *l)
3382{
3383 BcStatus s = BC_STATUS_SUCCESS;
3384
3385 if (isspace(l->buf[l->i - 1])) {
3386 bc_lex_whitespace(l);
3387 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003388 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003389 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003390 else
3391 s = bc_lex_name(l);
3392 }
3393 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003394 bc_vec_pop_all(&l->t.v);
Denys Vlasenkoe55a5722018-12-06 12:47:17 +01003395 bc_vec_push(&l->t.v, &l->buf[l->i - 1]);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003396 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003397 l->t.t = BC_LEX_NAME;
3398 }
3399
3400 return s;
3401}
3402
3403static BcStatus dc_lex_string(BcLex *l)
3404{
3405 size_t depth = 1, nls = 0, i = l->i;
3406 char c;
3407
3408 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003409 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003410
3411 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3412
3413 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3414 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3415 nls += (c == '\n');
3416
3417 if (depth) bc_vec_push(&l->t.v, &c);
3418 }
3419
3420 if (c == '\0') {
3421 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003422 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003423 }
3424
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003425 bc_vec_pushZeroByte(&l->t.v);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003426 if (i - l->i > BC_MAX_STRING)
3427 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003428
3429 l->i = i;
3430 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003431 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003432
3433 return BC_STATUS_SUCCESS;
3434}
3435
3436static BcStatus dc_lex_token(BcLex *l)
3437{
3438 BcStatus s = BC_STATUS_SUCCESS;
3439 char c = l->buf[l->i++], c2;
3440 size_t i;
3441
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003442 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3443 if (l->t.last == dc_lex_regs[i])
3444 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003445 }
3446
3447 if (c >= '%' && c <= '~' &&
3448 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3449 {
3450 return s;
3451 }
3452
3453 // This is the workhorse of the lexer.
3454 switch (c) {
3455
3456 case '\0':
3457 {
3458 l->t.t = BC_LEX_EOF;
3459 break;
3460 }
3461
3462 case '\n':
3463 case '\t':
3464 case '\v':
3465 case '\f':
3466 case '\r':
3467 case ' ':
3468 {
3469 l->newline = (c == '\n');
3470 bc_lex_whitespace(l);
3471 break;
3472 }
3473
3474 case '!':
3475 {
3476 c2 = l->buf[l->i];
3477
3478 if (c2 == '=')
3479 l->t.t = BC_LEX_OP_REL_NE;
3480 else if (c2 == '<')
3481 l->t.t = BC_LEX_OP_REL_LE;
3482 else if (c2 == '>')
3483 l->t.t = BC_LEX_OP_REL_GE;
3484 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003485 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003486
3487 ++l->i;
3488 break;
3489 }
3490
3491 case '#':
3492 {
3493 bc_lex_lineComment(l);
3494 break;
3495 }
3496
3497 case '.':
3498 {
3499 if (isdigit(l->buf[l->i]))
3500 s = bc_lex_number(l, c);
3501 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003502 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003503 break;
3504 }
3505
3506 case '0':
3507 case '1':
3508 case '2':
3509 case '3':
3510 case '4':
3511 case '5':
3512 case '6':
3513 case '7':
3514 case '8':
3515 case '9':
3516 case 'A':
3517 case 'B':
3518 case 'C':
3519 case 'D':
3520 case 'E':
3521 case 'F':
3522 {
3523 s = bc_lex_number(l, c);
3524 break;
3525 }
3526
3527 case '[':
3528 {
3529 s = dc_lex_string(l);
3530 break;
3531 }
3532
3533 default:
3534 {
3535 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003536 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003537 break;
3538 }
3539 }
3540
3541 return s;
3542}
3543#endif // ENABLE_DC
3544
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003545static void bc_program_addFunc(char *name, size_t *idx);
3546
Gavin Howard01055ba2018-11-03 11:00:21 -06003547static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3548{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003549 bc_program_addFunc(name, idx);
3550 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003551}
3552
Denys Vlasenkob23ac512018-12-06 13:10:56 +01003553#define bc_parse_push(p, i) bc_vec_pushByte(&(p)->func->code, (char) (i))
3554
Gavin Howard01055ba2018-11-03 11:00:21 -06003555static void bc_parse_pushName(BcParse *p, char *name)
3556{
3557 size_t i = 0, len = strlen(name);
3558
3559 for (; i < len; ++i) bc_parse_push(p, name[i]);
3560 bc_parse_push(p, BC_PARSE_STREND);
3561
3562 free(name);
3563}
3564
3565static void bc_parse_pushIndex(BcParse *p, size_t idx)
3566{
3567 unsigned char amt, i, nums[sizeof(size_t)];
3568
3569 for (amt = 0; idx; ++amt) {
3570 nums[amt] = (char) idx;
3571 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3572 }
3573
3574 bc_parse_push(p, amt);
3575 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3576}
3577
3578static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3579{
3580 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003581 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003582
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003583 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003584
3585 bc_parse_push(p, BC_INST_NUM);
3586 bc_parse_pushIndex(p, idx);
3587
3588 ++(*nexs);
3589 (*prev) = BC_INST_NUM;
3590}
3591
3592static BcStatus bc_parse_text(BcParse *p, const char *text)
3593{
3594 BcStatus s;
3595
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003596 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003597
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003598 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003599 p->l.t.t = BC_LEX_INVALID;
3600 s = p->parse(p);
3601 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003602 if (!BC_PARSE_CAN_EXEC(p))
3603 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003604 }
3605
3606 return bc_lex_text(&p->l, text);
3607}
3608
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003609// Called when parsing or execution detects a failure,
3610// resets execution structures.
3611static void bc_program_reset(void)
3612{
3613 BcFunc *f;
3614 BcInstPtr *ip;
3615
3616 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
3617 bc_vec_pop_all(&G.prog.results);
3618
3619 f = bc_vec_item(&G.prog.fns, 0);
3620 ip = bc_vec_top(&G.prog.stack);
3621 ip->idx = f->code.len;
3622}
3623
Denys Vlasenkoe55a5722018-12-06 12:47:17 +01003624#define bc_parse_updateFunc(p, f) \
3625 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
3626
Denys Vlasenkod38af482018-12-04 19:11:02 +01003627// Called when bc/dc_parse_parse() detects a failure,
3628// resets parsing structures.
3629static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003630{
3631 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003632 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003633 bc_vec_pop_all(&p->func->code);
3634 bc_vec_pop_all(&p->func->autos);
3635 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003636
3637 bc_parse_updateFunc(p, BC_PROG_MAIN);
3638 }
3639
3640 p->l.i = p->l.len;
3641 p->l.t.t = BC_LEX_EOF;
3642 p->auto_part = (p->nbraces = 0);
3643
3644 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003645 bc_vec_pop_all(&p->exits);
3646 bc_vec_pop_all(&p->conds);
3647 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003648
Denys Vlasenkod38af482018-12-04 19:11:02 +01003649 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003650}
3651
3652static void bc_parse_free(BcParse *p)
3653{
3654 bc_vec_free(&p->flags);
3655 bc_vec_free(&p->exits);
3656 bc_vec_free(&p->conds);
3657 bc_vec_free(&p->ops);
3658 bc_lex_free(&p->l);
3659}
3660
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003661static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003662 BcParseParse parse, BcLexNext next)
3663{
3664 memset(p, 0, sizeof(BcParse));
3665
3666 bc_lex_init(&p->l, next);
3667 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3668 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3669 bc_vec_init(&p->conds, sizeof(size_t), NULL);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003670 bc_vec_pushZeroByte(&p->flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003671 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3672
3673 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003674 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003675 bc_parse_updateFunc(p, func);
3676}
3677
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003678#if ENABLE_BC
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003679
3680#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
3681#define BC_PARSE_LEAF(p, rparen) \
3682 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
3683 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
3684
3685// We can calculate the conversion between tokens and exprs by subtracting the
3686// position of the first operator in the lex enum and adding the position of the
3687// first in the expr enum. Note: This only works for binary operators.
3688#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
3689
Gavin Howard01055ba2018-11-03 11:00:21 -06003690static BcStatus bc_parse_else(BcParse *p);
3691static BcStatus bc_parse_stmt(BcParse *p);
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003692static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01003693static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next);
Gavin Howard01055ba2018-11-03 11:00:21 -06003694
3695static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3696 size_t *nexprs, bool next)
3697{
3698 BcStatus s = BC_STATUS_SUCCESS;
3699 BcLexType t;
Denys Vlasenko65437582018-12-05 19:37:19 +01003700 char l, r = bc_parse_op_PREC(type - BC_LEX_OP_INC);
3701 bool left = bc_parse_op_LEFT(type - BC_LEX_OP_INC);
Gavin Howard01055ba2018-11-03 11:00:21 -06003702
3703 while (p->ops.len > start) {
3704
3705 t = BC_PARSE_TOP_OP(p);
3706 if (t == BC_LEX_LPAREN) break;
3707
Denys Vlasenko65437582018-12-05 19:37:19 +01003708 l = bc_parse_op_PREC(t - BC_LEX_OP_INC);
Gavin Howard01055ba2018-11-03 11:00:21 -06003709 if (l >= r && (l != r || !left)) break;
3710
3711 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3712 bc_vec_pop(&p->ops);
3713 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3714 }
3715
3716 bc_vec_push(&p->ops, &type);
3717 if (next) s = bc_lex_next(&p->l);
3718
3719 return s;
3720}
3721
3722static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3723{
3724 BcLexType top;
3725
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003726 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003727 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003728 top = BC_PARSE_TOP_OP(p);
3729
3730 while (top != BC_LEX_LPAREN) {
3731
3732 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3733
3734 bc_vec_pop(&p->ops);
3735 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3736
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003737 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003738 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003739 top = BC_PARSE_TOP_OP(p);
3740 }
3741
3742 bc_vec_pop(&p->ops);
3743
3744 return bc_lex_next(&p->l);
3745}
3746
3747static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3748{
3749 BcStatus s;
3750 bool comma = false;
3751 size_t nparams;
3752
3753 s = bc_lex_next(&p->l);
3754 if (s) return s;
3755
3756 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3757
3758 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3759 s = bc_parse_expr(p, flags, bc_parse_next_param);
3760 if (s) return s;
3761
3762 comma = p->l.t.t == BC_LEX_COMMA;
3763 if (comma) {
3764 s = bc_lex_next(&p->l);
3765 if (s) return s;
3766 }
3767 }
3768
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003769 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003770 bc_parse_push(p, BC_INST_CALL);
3771 bc_parse_pushIndex(p, nparams);
3772
3773 return BC_STATUS_SUCCESS;
3774}
3775
3776static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3777{
3778 BcStatus s;
3779 BcId entry, *entry_ptr;
3780 size_t idx;
3781
3782 entry.name = name;
3783
3784 s = bc_parse_params(p, flags);
3785 if (s) goto err;
3786
3787 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003788 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003789 goto err;
3790 }
3791
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003792 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003793
3794 if (idx == BC_VEC_INVALID_IDX) {
3795 name = xstrdup(entry.name);
3796 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003797 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003798 free(entry.name);
3799 }
3800 else
3801 free(name);
3802
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003803 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003804 bc_parse_pushIndex(p, entry_ptr->idx);
3805
3806 return bc_lex_next(&p->l);
3807
3808err:
3809 free(name);
3810 return s;
3811}
3812
3813static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3814{
3815 BcStatus s;
3816 char *name;
3817
3818 name = xstrdup(p->l.t.v.v);
3819 s = bc_lex_next(&p->l);
3820 if (s) goto err;
3821
3822 if (p->l.t.t == BC_LEX_LBRACKET) {
3823
3824 s = bc_lex_next(&p->l);
3825 if (s) goto err;
3826
3827 if (p->l.t.t == BC_LEX_RBRACKET) {
3828
3829 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003830 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003831 goto err;
3832 }
3833
3834 *type = BC_INST_ARRAY;
3835 }
3836 else {
3837
3838 *type = BC_INST_ARRAY_ELEM;
3839
3840 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3841 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3842 if (s) goto err;
3843 }
3844
3845 s = bc_lex_next(&p->l);
3846 if (s) goto err;
3847 bc_parse_push(p, *type);
3848 bc_parse_pushName(p, name);
3849 }
3850 else if (p->l.t.t == BC_LEX_LPAREN) {
3851
3852 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003853 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003854 goto err;
3855 }
3856
3857 *type = BC_INST_CALL;
3858 s = bc_parse_call(p, name, flags);
3859 }
3860 else {
3861 *type = BC_INST_VAR;
3862 bc_parse_push(p, BC_INST_VAR);
3863 bc_parse_pushName(p, name);
3864 }
3865
3866 return s;
3867
3868err:
3869 free(name);
3870 return s;
3871}
3872
3873static BcStatus bc_parse_read(BcParse *p)
3874{
3875 BcStatus s;
3876
3877 s = bc_lex_next(&p->l);
3878 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003879 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003880
3881 s = bc_lex_next(&p->l);
3882 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003883 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003884
3885 bc_parse_push(p, BC_INST_READ);
3886
3887 return bc_lex_next(&p->l);
3888}
3889
3890static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3891 BcInst *prev)
3892{
3893 BcStatus s;
3894
3895 s = bc_lex_next(&p->l);
3896 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003897 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003898
3899 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3900
3901 s = bc_lex_next(&p->l);
3902 if (s) return s;
3903
3904 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3905 if (s) return s;
3906
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003907 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003908
3909 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3910 bc_parse_push(p, *prev);
3911
3912 return bc_lex_next(&p->l);
3913}
3914
3915static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3916{
3917 BcStatus s;
3918
3919 s = bc_lex_next(&p->l);
3920 if (s) return s;
3921
3922 if (p->l.t.t != BC_LEX_LPAREN) {
3923 *type = BC_INST_SCALE;
3924 bc_parse_push(p, BC_INST_SCALE);
3925 return BC_STATUS_SUCCESS;
3926 }
3927
3928 *type = BC_INST_SCALE_FUNC;
3929 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3930
3931 s = bc_lex_next(&p->l);
3932 if (s) return s;
3933
3934 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3935 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003936 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003937 bc_parse_push(p, BC_INST_SCALE_FUNC);
3938
3939 return bc_lex_next(&p->l);
3940}
3941
3942static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3943 size_t *nexprs, uint8_t flags)
3944{
3945 BcStatus s;
3946 BcLexType type;
3947 char inst;
3948 BcInst etype = *prev;
3949
3950 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3951 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3952 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3953 {
3954 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3955 bc_parse_push(p, inst);
3956 s = bc_lex_next(&p->l);
3957 }
3958 else {
3959
3960 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3961 *paren_expr = true;
3962
3963 s = bc_lex_next(&p->l);
3964 if (s) return s;
3965 type = p->l.t.t;
3966
3967 // Because we parse the next part of the expression
3968 // right here, we need to increment this.
3969 *nexprs = *nexprs + 1;
3970
3971 switch (type) {
3972
3973 case BC_LEX_NAME:
3974 {
3975 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3976 break;
3977 }
3978
3979 case BC_LEX_KEY_IBASE:
3980 case BC_LEX_KEY_LAST:
3981 case BC_LEX_KEY_OBASE:
3982 {
3983 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3984 s = bc_lex_next(&p->l);
3985 break;
3986 }
3987
3988 case BC_LEX_KEY_SCALE:
3989 {
3990 s = bc_lex_next(&p->l);
3991 if (s) return s;
3992 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003993 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003994 else
3995 bc_parse_push(p, BC_INST_SCALE);
3996 break;
3997 }
3998
3999 default:
4000 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004001 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004002 break;
4003 }
4004 }
4005
4006 if (!s) bc_parse_push(p, inst);
4007 }
4008
4009 return s;
4010}
4011
4012static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4013 bool rparen, size_t *nexprs)
4014{
4015 BcStatus s;
4016 BcLexType type;
4017 BcInst etype = *prev;
4018
4019 s = bc_lex_next(&p->l);
4020 if (s) return s;
4021
4022 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4023 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4024 BC_LEX_OP_MINUS :
4025 BC_LEX_NEG;
4026 *prev = BC_PARSE_TOKEN_INST(type);
4027
4028 // We can just push onto the op stack because this is the largest
4029 // precedence operator that gets pushed. Inc/dec does not.
4030 if (type != BC_LEX_OP_MINUS)
4031 bc_vec_push(&p->ops, &type);
4032 else
4033 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4034
4035 return s;
4036}
4037
4038static BcStatus bc_parse_string(BcParse *p, char inst)
4039{
4040 char *str = xstrdup(p->l.t.v.v);
4041
4042 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004043 bc_parse_pushIndex(p, G.prog.strs.len);
4044 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004045 bc_parse_push(p, inst);
4046
4047 return bc_lex_next(&p->l);
4048}
4049
4050static BcStatus bc_parse_print(BcParse *p)
4051{
4052 BcStatus s;
4053 BcLexType type;
4054 bool comma = false;
4055
4056 s = bc_lex_next(&p->l);
4057 if (s) return s;
4058
4059 type = p->l.t.t;
4060
4061 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004062 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06004063
4064 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4065
4066 if (type == BC_LEX_STR)
4067 s = bc_parse_string(p, BC_INST_PRINT_POP);
4068 else {
4069 s = bc_parse_expr(p, 0, bc_parse_next_print);
4070 if (s) return s;
4071 bc_parse_push(p, BC_INST_PRINT_POP);
4072 }
4073
4074 if (s) return s;
4075
4076 comma = p->l.t.t == BC_LEX_COMMA;
4077 if (comma) s = bc_lex_next(&p->l);
4078 type = p->l.t.t;
4079 }
4080
4081 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004082 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004083
4084 return bc_lex_next(&p->l);
4085}
4086
4087static BcStatus bc_parse_return(BcParse *p)
4088{
4089 BcStatus s;
4090 BcLexType t;
4091 bool paren;
4092
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004093 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004094
4095 s = bc_lex_next(&p->l);
4096 if (s) return s;
4097
4098 t = p->l.t.t;
4099 paren = t == BC_LEX_LPAREN;
4100
4101 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4102 bc_parse_push(p, BC_INST_RET0);
4103 else {
4104
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01004105 s = bc_parse_expr_empty_ok(p, 0, bc_parse_next_expr);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004106 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004107 bc_parse_push(p, BC_INST_RET0);
4108 s = bc_lex_next(&p->l);
Gavin Howard01055ba2018-11-03 11:00:21 -06004109 }
Denys Vlasenko452df922018-12-05 20:28:26 +01004110 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06004111
4112 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01004113 s = bc_POSIX_requires("parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004114 if (s) return s;
4115 }
4116
4117 bc_parse_push(p, BC_INST_RET);
4118 }
4119
4120 return s;
4121}
4122
4123static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4124{
4125 BcStatus s = BC_STATUS_SUCCESS;
4126
4127 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004128 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004129
4130 if (brace) {
4131
4132 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004133 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004134 --p->nbraces;
4135 s = bc_lex_next(&p->l);
4136 if (s) return s;
4137 }
4138 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004139 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004140 }
4141
4142 if (BC_PARSE_IF(p)) {
4143
4144 uint8_t *flag_ptr;
4145
4146 while (p->l.t.t == BC_LEX_NLINE) {
4147 s = bc_lex_next(&p->l);
4148 if (s) return s;
4149 }
4150
4151 bc_vec_pop(&p->flags);
4152
4153 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4154 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4155
4156 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4157 }
4158 else if (BC_PARSE_ELSE(p)) {
4159
4160 BcInstPtr *ip;
4161 size_t *label;
4162
4163 bc_vec_pop(&p->flags);
4164
4165 ip = bc_vec_top(&p->exits);
4166 label = bc_vec_item(&p->func->labels, ip->idx);
4167 *label = p->func->code.len;
4168
4169 bc_vec_pop(&p->exits);
4170 }
4171 else if (BC_PARSE_FUNC_INNER(p)) {
4172 bc_parse_push(p, BC_INST_RET0);
4173 bc_parse_updateFunc(p, BC_PROG_MAIN);
4174 bc_vec_pop(&p->flags);
4175 }
4176 else {
4177
4178 BcInstPtr *ip = bc_vec_top(&p->exits);
4179 size_t *label = bc_vec_top(&p->conds);
4180
4181 bc_parse_push(p, BC_INST_JUMP);
4182 bc_parse_pushIndex(p, *label);
4183
4184 label = bc_vec_item(&p->func->labels, ip->idx);
4185 *label = p->func->code.len;
4186
4187 bc_vec_pop(&p->flags);
4188 bc_vec_pop(&p->exits);
4189 bc_vec_pop(&p->conds);
4190 }
4191
4192 return s;
4193}
4194
4195static void bc_parse_startBody(BcParse *p, uint8_t flags)
4196{
4197 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4198 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4199 flags |= BC_PARSE_FLAG_BODY;
4200 bc_vec_push(&p->flags, &flags);
4201}
4202
4203static void bc_parse_noElse(BcParse *p)
4204{
4205 BcInstPtr *ip;
4206 size_t *label;
4207 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4208
4209 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4210
4211 ip = bc_vec_top(&p->exits);
4212 label = bc_vec_item(&p->func->labels, ip->idx);
4213 *label = p->func->code.len;
4214
4215 bc_vec_pop(&p->exits);
4216}
4217
4218static BcStatus bc_parse_if(BcParse *p)
4219{
4220 BcStatus s;
4221 BcInstPtr ip;
4222
4223 s = bc_lex_next(&p->l);
4224 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004225 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004226
4227 s = bc_lex_next(&p->l);
4228 if (s) return s;
4229 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4230 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004231 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004232
4233 s = bc_lex_next(&p->l);
4234 if (s) return s;
4235 bc_parse_push(p, BC_INST_JUMP_ZERO);
4236
4237 ip.idx = p->func->labels.len;
4238 ip.func = ip.len = 0;
4239
4240 bc_parse_pushIndex(p, ip.idx);
4241 bc_vec_push(&p->exits, &ip);
4242 bc_vec_push(&p->func->labels, &ip.idx);
4243 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4244
4245 return BC_STATUS_SUCCESS;
4246}
4247
4248static BcStatus bc_parse_else(BcParse *p)
4249{
4250 BcInstPtr ip;
4251
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004252 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004253
4254 ip.idx = p->func->labels.len;
4255 ip.func = ip.len = 0;
4256
4257 bc_parse_push(p, BC_INST_JUMP);
4258 bc_parse_pushIndex(p, ip.idx);
4259
4260 bc_parse_noElse(p);
4261
4262 bc_vec_push(&p->exits, &ip);
4263 bc_vec_push(&p->func->labels, &ip.idx);
4264 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4265
4266 return bc_lex_next(&p->l);
4267}
4268
4269static BcStatus bc_parse_while(BcParse *p)
4270{
4271 BcStatus s;
4272 BcInstPtr ip;
4273
4274 s = bc_lex_next(&p->l);
4275 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004276 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004277 s = bc_lex_next(&p->l);
4278 if (s) return s;
4279
4280 ip.idx = p->func->labels.len;
4281
4282 bc_vec_push(&p->func->labels, &p->func->code.len);
4283 bc_vec_push(&p->conds, &ip.idx);
4284
4285 ip.idx = p->func->labels.len;
4286 ip.func = 1;
4287 ip.len = 0;
4288
4289 bc_vec_push(&p->exits, &ip);
4290 bc_vec_push(&p->func->labels, &ip.idx);
4291
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 s = bc_lex_next(&p->l);
4296 if (s) return s;
4297
4298 bc_parse_push(p, BC_INST_JUMP_ZERO);
4299 bc_parse_pushIndex(p, ip.idx);
4300 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4301
4302 return BC_STATUS_SUCCESS;
4303}
4304
4305static BcStatus bc_parse_for(BcParse *p)
4306{
4307 BcStatus s;
4308 BcInstPtr ip;
4309 size_t cond_idx, exit_idx, body_idx, update_idx;
4310
4311 s = bc_lex_next(&p->l);
4312 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004313 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004314 s = bc_lex_next(&p->l);
4315 if (s) return s;
4316
4317 if (p->l.t.t != BC_LEX_SCOLON)
4318 s = bc_parse_expr(p, 0, bc_parse_next_for);
4319 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004320 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
Gavin Howard01055ba2018-11-03 11:00:21 -06004321
4322 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004323 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004324 s = bc_lex_next(&p->l);
4325 if (s) return s;
4326
4327 cond_idx = p->func->labels.len;
4328 update_idx = cond_idx + 1;
4329 body_idx = update_idx + 1;
4330 exit_idx = body_idx + 1;
4331
4332 bc_vec_push(&p->func->labels, &p->func->code.len);
4333
4334 if (p->l.t.t != BC_LEX_SCOLON)
4335 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4336 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004337 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004338
4339 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004340 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004341
4342 s = bc_lex_next(&p->l);
4343 if (s) return s;
4344
4345 bc_parse_push(p, BC_INST_JUMP_ZERO);
4346 bc_parse_pushIndex(p, exit_idx);
4347 bc_parse_push(p, BC_INST_JUMP);
4348 bc_parse_pushIndex(p, body_idx);
4349
4350 ip.idx = p->func->labels.len;
4351
4352 bc_vec_push(&p->conds, &update_idx);
4353 bc_vec_push(&p->func->labels, &p->func->code.len);
4354
4355 if (p->l.t.t != BC_LEX_RPAREN)
4356 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4357 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004358 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
Gavin Howard01055ba2018-11-03 11:00:21 -06004359
4360 if (s) return s;
4361
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004362 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004363 bc_parse_push(p, BC_INST_JUMP);
4364 bc_parse_pushIndex(p, cond_idx);
4365 bc_vec_push(&p->func->labels, &p->func->code.len);
4366
4367 ip.idx = exit_idx;
4368 ip.func = 1;
4369 ip.len = 0;
4370
4371 bc_vec_push(&p->exits, &ip);
4372 bc_vec_push(&p->func->labels, &ip.idx);
4373 bc_lex_next(&p->l);
4374 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4375
4376 return BC_STATUS_SUCCESS;
4377}
4378
4379static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4380{
4381 BcStatus s;
4382 size_t i;
4383 BcInstPtr *ip;
4384
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004385 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004386
4387 if (type == BC_LEX_KEY_BREAK) {
4388
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004389 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004390
4391 i = p->exits.len - 1;
4392 ip = bc_vec_item(&p->exits, i);
4393
4394 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004395 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004396
4397 i = ip->idx;
4398 }
4399 else
4400 i = *((size_t *) bc_vec_top(&p->conds));
4401
4402 bc_parse_push(p, BC_INST_JUMP);
4403 bc_parse_pushIndex(p, i);
4404
4405 s = bc_lex_next(&p->l);
4406 if (s) return s;
4407
4408 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004409 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004410
4411 return bc_lex_next(&p->l);
4412}
4413
4414static BcStatus bc_parse_func(BcParse *p)
4415{
4416 BcStatus s;
4417 bool var, comma = false;
4418 uint8_t flags;
4419 char *name;
4420
4421 s = bc_lex_next(&p->l);
4422 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004423 if (p->l.t.t != BC_LEX_NAME)
4424 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004425
4426 name = xstrdup(p->l.t.v.v);
4427 bc_parse_addFunc(p, name, &p->fidx);
4428
4429 s = bc_lex_next(&p->l);
4430 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004431 if (p->l.t.t != BC_LEX_LPAREN)
4432 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004433 s = bc_lex_next(&p->l);
4434 if (s) return s;
4435
4436 while (p->l.t.t != BC_LEX_RPAREN) {
4437
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004438 if (p->l.t.t != BC_LEX_NAME)
4439 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004440
4441 ++p->func->nparams;
4442
4443 name = xstrdup(p->l.t.v.v);
4444 s = bc_lex_next(&p->l);
4445 if (s) goto err;
4446
4447 var = p->l.t.t != BC_LEX_LBRACKET;
4448
4449 if (!var) {
4450
4451 s = bc_lex_next(&p->l);
4452 if (s) goto err;
4453
4454 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004455 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004456 goto err;
4457 }
4458
4459 s = bc_lex_next(&p->l);
4460 if (s) goto err;
4461 }
4462
4463 comma = p->l.t.t == BC_LEX_COMMA;
4464 if (comma) {
4465 s = bc_lex_next(&p->l);
4466 if (s) goto err;
4467 }
4468
4469 s = bc_func_insert(p->func, name, var);
4470 if (s) goto err;
4471 }
4472
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004473 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004474
4475 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4476 bc_parse_startBody(p, flags);
4477
4478 s = bc_lex_next(&p->l);
4479 if (s) return s;
4480
4481 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01004482 s = bc_POSIX_requires("the left brace be on the same line as the function header");
Gavin Howard01055ba2018-11-03 11:00:21 -06004483
4484 return s;
4485
4486err:
4487 free(name);
4488 return s;
4489}
4490
4491static BcStatus bc_parse_auto(BcParse *p)
4492{
4493 BcStatus s;
4494 bool comma, var, one;
4495 char *name;
4496
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004497 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004498 s = bc_lex_next(&p->l);
4499 if (s) return s;
4500
4501 p->auto_part = comma = false;
4502 one = p->l.t.t == BC_LEX_NAME;
4503
4504 while (p->l.t.t == BC_LEX_NAME) {
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 if (!var) {
4512
4513 s = bc_lex_next(&p->l);
4514 if (s) goto err;
4515
4516 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004517 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004518 goto err;
4519 }
4520
4521 s = bc_lex_next(&p->l);
4522 if (s) goto err;
4523 }
4524
4525 comma = p->l.t.t == BC_LEX_COMMA;
4526 if (comma) {
4527 s = bc_lex_next(&p->l);
4528 if (s) goto err;
4529 }
4530
4531 s = bc_func_insert(p->func, name, var);
4532 if (s) goto err;
4533 }
4534
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004535 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004536 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004537
4538 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004539 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004540
4541 return bc_lex_next(&p->l);
4542
4543err:
4544 free(name);
4545 return s;
4546}
4547
4548static BcStatus bc_parse_body(BcParse *p, bool brace)
4549{
4550 BcStatus s = BC_STATUS_SUCCESS;
4551 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4552
4553 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4554
4555 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4556
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004557 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004558 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4559
4560 if (!p->auto_part) {
4561 s = bc_parse_auto(p);
4562 if (s) return s;
4563 }
4564
4565 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4566 }
4567 else {
4568 s = bc_parse_stmt(p);
4569 if (!s && !brace) s = bc_parse_endBody(p, false);
4570 }
4571
4572 return s;
4573}
4574
4575static BcStatus bc_parse_stmt(BcParse *p)
4576{
4577 BcStatus s = BC_STATUS_SUCCESS;
4578
4579 switch (p->l.t.t) {
4580
4581 case BC_LEX_NLINE:
4582 {
4583 return bc_lex_next(&p->l);
4584 }
4585
4586 case BC_LEX_KEY_ELSE:
4587 {
4588 p->auto_part = false;
4589 break;
4590 }
4591
4592 case BC_LEX_LBRACE:
4593 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004594 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004595
4596 ++p->nbraces;
4597 s = bc_lex_next(&p->l);
4598 if (s) return s;
4599
4600 return bc_parse_body(p, true);
4601 }
4602
4603 case BC_LEX_KEY_AUTO:
4604 {
4605 return bc_parse_auto(p);
4606 }
4607
4608 default:
4609 {
4610 p->auto_part = false;
4611
4612 if (BC_PARSE_IF_END(p)) {
4613 bc_parse_noElse(p);
4614 return BC_STATUS_SUCCESS;
4615 }
4616 else if (BC_PARSE_BODY(p))
4617 return bc_parse_body(p, false);
4618
4619 break;
4620 }
4621 }
4622
4623 switch (p->l.t.t) {
4624
4625 case BC_LEX_OP_INC:
4626 case BC_LEX_OP_DEC:
4627 case BC_LEX_OP_MINUS:
4628 case BC_LEX_OP_BOOL_NOT:
4629 case BC_LEX_LPAREN:
4630 case BC_LEX_NAME:
4631 case BC_LEX_NUMBER:
4632 case BC_LEX_KEY_IBASE:
4633 case BC_LEX_KEY_LAST:
4634 case BC_LEX_KEY_LENGTH:
4635 case BC_LEX_KEY_OBASE:
4636 case BC_LEX_KEY_READ:
4637 case BC_LEX_KEY_SCALE:
4638 case BC_LEX_KEY_SQRT:
4639 {
4640 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4641 break;
4642 }
4643
4644 case BC_LEX_KEY_ELSE:
4645 {
4646 s = bc_parse_else(p);
4647 break;
4648 }
4649
4650 case BC_LEX_SCOLON:
4651 {
4652 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4653 break;
4654 }
4655
4656 case BC_LEX_RBRACE:
4657 {
4658 s = bc_parse_endBody(p, true);
4659 break;
4660 }
4661
4662 case BC_LEX_STR:
4663 {
4664 s = bc_parse_string(p, BC_INST_PRINT_STR);
4665 break;
4666 }
4667
4668 case BC_LEX_KEY_BREAK:
4669 case BC_LEX_KEY_CONTINUE:
4670 {
4671 s = bc_parse_loopExit(p, p->l.t.t);
4672 break;
4673 }
4674
4675 case BC_LEX_KEY_FOR:
4676 {
4677 s = bc_parse_for(p);
4678 break;
4679 }
4680
4681 case BC_LEX_KEY_HALT:
4682 {
4683 bc_parse_push(p, BC_INST_HALT);
4684 s = bc_lex_next(&p->l);
4685 break;
4686 }
4687
4688 case BC_LEX_KEY_IF:
4689 {
4690 s = bc_parse_if(p);
4691 break;
4692 }
4693
4694 case BC_LEX_KEY_LIMITS:
4695 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004696 // "limits" is a compile-time command,
4697 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004698 s = bc_lex_next(&p->l);
4699 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004700 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4701 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4702 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4703 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4704 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4705 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4706 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4707 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004708 break;
4709 }
4710
4711 case BC_LEX_KEY_PRINT:
4712 {
4713 s = bc_parse_print(p);
4714 break;
4715 }
4716
4717 case BC_LEX_KEY_QUIT:
4718 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004719 // "quit" is a compile-time command. For example,
4720 // "if (0 == 1) quit" terminates when parsing the statement,
4721 // not when it is executed
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01004722 QUIT_OR_RETURN_TO_MAIN;
Gavin Howard01055ba2018-11-03 11:00:21 -06004723 }
4724
4725 case BC_LEX_KEY_RETURN:
4726 {
4727 s = bc_parse_return(p);
4728 break;
4729 }
4730
4731 case BC_LEX_KEY_WHILE:
4732 {
4733 s = bc_parse_while(p);
4734 break;
4735 }
4736
4737 default:
4738 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004739 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004740 break;
4741 }
4742 }
4743
4744 return s;
4745}
4746
4747static BcStatus bc_parse_parse(BcParse *p)
4748{
4749 BcStatus s;
4750
4751 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004752 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 -06004753 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004754 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004755 s = bc_parse_func(p);
4756 }
4757 else
4758 s = bc_parse_stmt(p);
4759
Denys Vlasenkod38af482018-12-04 19:11:02 +01004760 if (s || G_interrupt) {
4761 bc_parse_reset(p);
4762 s = BC_STATUS_FAILURE;
4763 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004764
4765 return s;
4766}
4767
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01004768static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext next)
Gavin Howard01055ba2018-11-03 11:00:21 -06004769{
4770 BcStatus s = BC_STATUS_SUCCESS;
4771 BcInst prev = BC_INST_PRINT;
4772 BcLexType top, t = p->l.t.t;
4773 size_t nexprs = 0, ops_bgn = p->ops.len;
Denys Vlasenko18c6b542018-12-07 12:57:32 +01004774 unsigned nparens, nrelops;
Gavin Howard01055ba2018-11-03 11:00:21 -06004775 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4776
4777 paren_first = p->l.t.t == BC_LEX_LPAREN;
4778 nparens = nrelops = 0;
4779 paren_expr = rprn = done = get_token = assign = false;
4780 bin_last = true;
4781
Denys Vlasenkobcb62a72018-12-05 20:17:48 +01004782 for (; !G_interrupt && !s && !done && bc_parse_exprs(t); t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004783 switch (t) {
4784
4785 case BC_LEX_OP_INC:
4786 case BC_LEX_OP_DEC:
4787 {
4788 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4789 rprn = get_token = bin_last = false;
4790 break;
4791 }
4792
4793 case BC_LEX_OP_MINUS:
4794 {
4795 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4796 rprn = get_token = false;
4797 bin_last = prev == BC_INST_MINUS;
4798 break;
4799 }
4800
4801 case BC_LEX_OP_ASSIGN_POWER:
4802 case BC_LEX_OP_ASSIGN_MULTIPLY:
4803 case BC_LEX_OP_ASSIGN_DIVIDE:
4804 case BC_LEX_OP_ASSIGN_MODULUS:
4805 case BC_LEX_OP_ASSIGN_PLUS:
4806 case BC_LEX_OP_ASSIGN_MINUS:
4807 case BC_LEX_OP_ASSIGN:
4808 {
4809 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4810 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4811 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4812 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004813 s = bc_error("bad assignment:"
4814 " left side must be scale,"
4815 " ibase, obase, last, var,"
4816 " or array element"
4817 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004818 break;
4819 }
4820 }
4821 // Fallthrough.
4822 case BC_LEX_OP_POWER:
4823 case BC_LEX_OP_MULTIPLY:
4824 case BC_LEX_OP_DIVIDE:
4825 case BC_LEX_OP_MODULUS:
4826 case BC_LEX_OP_PLUS:
4827 case BC_LEX_OP_REL_EQ:
4828 case BC_LEX_OP_REL_LE:
4829 case BC_LEX_OP_REL_GE:
4830 case BC_LEX_OP_REL_NE:
4831 case BC_LEX_OP_REL_LT:
4832 case BC_LEX_OP_REL_GT:
4833 case BC_LEX_OP_BOOL_NOT:
4834 case BC_LEX_OP_BOOL_OR:
4835 case BC_LEX_OP_BOOL_AND:
4836 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004837 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4838 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4839 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004840 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004841 }
4842
4843 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4844 prev = BC_PARSE_TOKEN_INST(t);
4845 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4846 rprn = get_token = false;
4847 bin_last = t != BC_LEX_OP_BOOL_NOT;
4848
4849 break;
4850 }
4851
4852 case BC_LEX_LPAREN:
4853 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004854 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004855 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004856 ++nparens;
4857 paren_expr = rprn = bin_last = false;
4858 get_token = true;
4859 bc_vec_push(&p->ops, &t);
4860
4861 break;
4862 }
4863
4864 case BC_LEX_RPAREN:
4865 {
4866 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004867 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004868
4869 if (nparens == 0) {
4870 s = BC_STATUS_SUCCESS;
4871 done = true;
4872 get_token = false;
4873 break;
4874 }
4875 else if (!paren_expr)
4876 return BC_STATUS_PARSE_EMPTY_EXP;
4877
4878 --nparens;
4879 paren_expr = rprn = true;
4880 get_token = bin_last = false;
4881
4882 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4883
4884 break;
4885 }
4886
4887 case BC_LEX_NAME:
4888 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004889 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004890 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004891 paren_expr = true;
4892 rprn = get_token = bin_last = false;
4893 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4894 ++nexprs;
4895
4896 break;
4897 }
4898
4899 case BC_LEX_NUMBER:
4900 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004901 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004902 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004903 bc_parse_number(p, &prev, &nexprs);
4904 paren_expr = get_token = true;
4905 rprn = bin_last = false;
4906
4907 break;
4908 }
4909
4910 case BC_LEX_KEY_IBASE:
4911 case BC_LEX_KEY_LAST:
4912 case BC_LEX_KEY_OBASE:
4913 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004914 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004915 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004916 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4917 bc_parse_push(p, (char) prev);
4918
4919 paren_expr = get_token = true;
4920 rprn = bin_last = false;
4921 ++nexprs;
4922
4923 break;
4924 }
4925
4926 case BC_LEX_KEY_LENGTH:
4927 case BC_LEX_KEY_SQRT:
4928 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004929 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004930 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004931 s = bc_parse_builtin(p, t, flags, &prev);
4932 paren_expr = true;
4933 rprn = get_token = bin_last = false;
4934 ++nexprs;
4935
4936 break;
4937 }
4938
4939 case BC_LEX_KEY_READ:
4940 {
4941 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004942 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004943 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004944 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06004945 else
4946 s = bc_parse_read(p);
4947
4948 paren_expr = true;
4949 rprn = get_token = bin_last = false;
4950 ++nexprs;
4951 prev = BC_INST_READ;
4952
4953 break;
4954 }
4955
4956 case BC_LEX_KEY_SCALE:
4957 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004958 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004959 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004960 s = bc_parse_scale(p, &prev, flags);
4961 paren_expr = true;
4962 rprn = get_token = bin_last = false;
4963 ++nexprs;
4964 prev = BC_INST_SCALE;
4965
4966 break;
4967 }
4968
4969 default:
4970 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004971 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004972 break;
4973 }
4974 }
4975
4976 if (!s && get_token) s = bc_lex_next(&p->l);
4977 }
4978
4979 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004980 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004981
4982 while (p->ops.len > ops_bgn) {
4983
4984 top = BC_PARSE_TOP_OP(p);
4985 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4986
4987 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004988 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004989
4990 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4991
4992 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4993 bc_vec_pop(&p->ops);
4994 }
4995
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004996 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004997 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004998
Denys Vlasenko18c6b542018-12-07 12:57:32 +01004999 // next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word
5000 for (;;) {
5001 if (t == (next & 0x7f))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005002 goto ok;
Denys Vlasenko18c6b542018-12-07 12:57:32 +01005003 if (next & 0x80) // last element?
5004 break;
5005 next >>= 8;
5006 }
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005007 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005008 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06005009
5010 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko00646792018-12-05 18:12:27 +01005011 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06005012 if (s) return s;
5013 }
5014 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenkoa6f84e12018-12-06 11:10:11 +01005015 s = bc_POSIX_requires("exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06005016 if (s) return s;
5017 }
5018
5019 if (flags & BC_PARSE_PRINT) {
5020 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5021 bc_parse_push(p, BC_INST_POP);
5022 }
5023
5024 return s;
5025}
5026
Denys Vlasenko050b0fe2018-12-05 22:40:44 +01005027static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
5028{
5029 BcStatus s;
5030
5031 s = bc_parse_expr_empty_ok(p, flags, next);
5032 if (s == BC_STATUS_PARSE_EMPTY_EXP)
5033 return bc_error("empty expression");
5034 return s;
5035}
5036
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005037static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005038{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005039 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005040}
5041
5042static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5043{
5044 return bc_parse_expr(p, flags, bc_parse_next_read);
5045}
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005046
Gavin Howard01055ba2018-11-03 11:00:21 -06005047#endif // ENABLE_BC
5048
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005049#if ENABLE_DC
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005050
5051#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
5052
Gavin Howard01055ba2018-11-03 11:00:21 -06005053static BcStatus dc_parse_register(BcParse *p)
5054{
5055 BcStatus s;
5056 char *name;
5057
5058 s = bc_lex_next(&p->l);
5059 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005060 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005061
5062 name = xstrdup(p->l.t.v.v);
5063 bc_parse_pushName(p, name);
5064
5065 return s;
5066}
5067
5068static BcStatus dc_parse_string(BcParse *p)
5069{
5070 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005071 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005072
5073 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5074 name = xstrdup(b);
5075
5076 str = xstrdup(p->l.t.v.v);
5077 bc_parse_push(p, BC_INST_STR);
5078 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005079 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005080 bc_parse_addFunc(p, name, &idx);
5081
5082 return bc_lex_next(&p->l);
5083}
5084
5085static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5086{
5087 BcStatus s;
5088
5089 bc_parse_push(p, inst);
5090 if (name) {
5091 s = dc_parse_register(p);
5092 if (s) return s;
5093 }
5094
5095 if (store) {
5096 bc_parse_push(p, BC_INST_SWAP);
5097 bc_parse_push(p, BC_INST_ASSIGN);
5098 bc_parse_push(p, BC_INST_POP);
5099 }
5100
5101 return bc_lex_next(&p->l);
5102}
5103
5104static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5105{
5106 BcStatus s;
5107
5108 bc_parse_push(p, inst);
5109 bc_parse_push(p, BC_INST_EXEC_COND);
5110
5111 s = dc_parse_register(p);
5112 if (s) return s;
5113
5114 s = bc_lex_next(&p->l);
5115 if (s) return s;
5116
5117 if (p->l.t.t == BC_LEX_ELSE) {
5118 s = dc_parse_register(p);
5119 if (s) return s;
5120 s = bc_lex_next(&p->l);
5121 }
5122 else
5123 bc_parse_push(p, BC_PARSE_STREND);
5124
5125 return s;
5126}
5127
5128static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5129{
5130 BcStatus s = BC_STATUS_SUCCESS;
5131 BcInst prev;
5132 uint8_t inst;
5133 bool assign, get_token = false;
5134
5135 switch (t) {
5136
5137 case BC_LEX_OP_REL_EQ:
5138 case BC_LEX_OP_REL_LE:
5139 case BC_LEX_OP_REL_GE:
5140 case BC_LEX_OP_REL_NE:
5141 case BC_LEX_OP_REL_LT:
5142 case BC_LEX_OP_REL_GT:
5143 {
5144 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5145 break;
5146 }
5147
5148 case BC_LEX_SCOLON:
5149 case BC_LEX_COLON:
5150 {
5151 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5152 break;
5153 }
5154
5155 case BC_LEX_STR:
5156 {
5157 s = dc_parse_string(p);
5158 break;
5159 }
5160
5161 case BC_LEX_NEG:
5162 case BC_LEX_NUMBER:
5163 {
5164 if (t == BC_LEX_NEG) {
5165 s = bc_lex_next(&p->l);
5166 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005167 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005168 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005169 }
5170
5171 bc_parse_number(p, &prev, &p->nbraces);
5172
5173 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5174 get_token = true;
5175
5176 break;
5177 }
5178
5179 case BC_LEX_KEY_READ:
5180 {
5181 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005182 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005183 else
5184 bc_parse_push(p, BC_INST_READ);
5185 get_token = true;
5186 break;
5187 }
5188
5189 case BC_LEX_OP_ASSIGN:
5190 case BC_LEX_STORE_PUSH:
5191 {
5192 assign = t == BC_LEX_OP_ASSIGN;
5193 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5194 s = dc_parse_mem(p, inst, true, assign);
5195 break;
5196 }
5197
5198 case BC_LEX_LOAD:
5199 case BC_LEX_LOAD_POP:
5200 {
5201 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5202 s = dc_parse_mem(p, inst, true, false);
5203 break;
5204 }
5205
5206 case BC_LEX_STORE_IBASE:
5207 case BC_LEX_STORE_SCALE:
5208 case BC_LEX_STORE_OBASE:
5209 {
5210 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5211 s = dc_parse_mem(p, inst, false, true);
5212 break;
5213 }
5214
5215 default:
5216 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005217 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005218 get_token = true;
5219 break;
5220 }
5221 }
5222
5223 if (!s && get_token) s = bc_lex_next(&p->l);
5224
5225 return s;
5226}
5227
5228static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5229{
5230 BcStatus s = BC_STATUS_SUCCESS;
5231 BcInst inst;
5232 BcLexType t;
5233
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005234 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005235
5236 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5237
5238 inst = dc_parse_insts[t];
5239
5240 if (inst != BC_INST_INVALID) {
5241 bc_parse_push(p, inst);
5242 s = bc_lex_next(&p->l);
5243 }
5244 else
5245 s = dc_parse_token(p, t, flags);
5246 }
5247
5248 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5249 bc_parse_push(p, BC_INST_POP_EXEC);
5250
5251 return s;
5252}
5253
5254static BcStatus dc_parse_parse(BcParse *p)
5255{
5256 BcStatus s;
5257
5258 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005259 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005260 else
5261 s = dc_parse_expr(p, 0);
5262
Denys Vlasenkod38af482018-12-04 19:11:02 +01005263 if (s || G_interrupt) {
5264 bc_parse_reset(p);
5265 s = BC_STATUS_FAILURE;
5266 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005267
5268 return s;
5269}
5270
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005271static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005272{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005273 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005274}
Denys Vlasenkocca79a02018-12-05 21:15:46 +01005275
Gavin Howard01055ba2018-11-03 11:00:21 -06005276#endif // ENABLE_DC
5277
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005278static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005279{
5280 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005281 IF_BC(bc_parse_init(p, func);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005282 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005283 IF_DC(dc_parse_init(p, func);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005284 }
5285}
5286
5287static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5288{
5289 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005290 IF_BC(return bc_parse_expression(p, flags);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005291 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01005292 IF_DC(return dc_parse_expr(p, flags);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005293 }
5294}
5295
Denys Vlasenkodf515392018-12-02 19:27:48 +01005296static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005297{
Gavin Howard01055ba2018-11-03 11:00:21 -06005298 BcId e, *ptr;
5299 BcVec *v, *map;
5300 size_t i;
5301 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005302 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005303
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005304 v = var ? &G.prog.vars : &G.prog.arrs;
5305 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005306
5307 e.name = id;
5308 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005309 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005310
5311 if (new) {
5312 bc_array_init(&data.v, var);
5313 bc_vec_push(v, &data.v);
5314 }
5315
5316 ptr = bc_vec_item(map, i);
5317 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005318 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005319}
5320
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005321static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005322{
5323 BcStatus s = BC_STATUS_SUCCESS;
5324
5325 switch (r->t) {
5326
5327 case BC_RESULT_STR:
5328 case BC_RESULT_TEMP:
5329 case BC_RESULT_IBASE:
5330 case BC_RESULT_SCALE:
5331 case BC_RESULT_OBASE:
5332 {
5333 *num = &r->d.n;
5334 break;
5335 }
5336
5337 case BC_RESULT_CONSTANT:
5338 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005339 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005340 size_t base_t, len = strlen(*str);
5341 BcNum *base;
5342
5343 bc_num_init(&r->d.n, len);
5344
5345 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005346 base = hex ? &G.prog.hexb : &G.prog.ib;
5347 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005348 s = bc_num_parse(&r->d.n, *str, base, base_t);
5349
5350 if (s) {
5351 bc_num_free(&r->d.n);
5352 return s;
5353 }
5354
5355 *num = &r->d.n;
5356 r->t = BC_RESULT_TEMP;
5357
5358 break;
5359 }
5360
5361 case BC_RESULT_VAR:
5362 case BC_RESULT_ARRAY:
5363 case BC_RESULT_ARRAY_ELEM:
5364 {
5365 BcVec *v;
5366
Denys Vlasenkodf515392018-12-02 19:27:48 +01005367 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005368
5369 if (r->t == BC_RESULT_ARRAY_ELEM) {
5370 v = bc_vec_top(v);
5371 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5372 *num = bc_vec_item(v, r->d.id.idx);
5373 }
5374 else
5375 *num = bc_vec_top(v);
5376
5377 break;
5378 }
5379
5380 case BC_RESULT_LAST:
5381 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005382 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005383 break;
5384 }
5385
5386 case BC_RESULT_ONE:
5387 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005388 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005389 break;
5390 }
5391 }
5392
5393 return s;
5394}
5395
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005396static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005397 BcResult **r, BcNum **rn, bool assign)
5398{
5399 BcStatus s;
5400 bool hex;
5401 BcResultType lt, rt;
5402
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005403 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005404 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005405
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005406 *r = bc_vec_item_rev(&G.prog.results, 0);
5407 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005408
5409 lt = (*l)->t;
5410 rt = (*r)->t;
5411 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5412
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005413 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005414 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005415 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005416 if (s) return s;
5417
5418 // We run this again under these conditions in case any vector has been
5419 // reallocated out from under the BcNums or arrays we had.
5420 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005421 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005422 if (s) return s;
5423 }
5424
5425 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005426 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005427 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005428 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005429
Gavin Howard01055ba2018-11-03 11:00:21 -06005430 return s;
5431}
5432
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005433static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005434{
5435 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005436 bc_vec_pop(&G.prog.results);
5437 bc_vec_pop(&G.prog.results);
5438 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005439}
5440
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005441static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005442{
5443 BcStatus s;
5444
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005445 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005446 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005447 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005448
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005449 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005450 if (s) return s;
5451
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005452 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005453 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005454
5455 return s;
5456}
5457
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005458static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005459{
5460 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005461 bc_vec_pop(&G.prog.results);
5462 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005463}
5464
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005465static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005466{
5467 BcStatus s;
5468 BcResult *opd1, *opd2, res;
5469 BcNum *n1, *n2 = NULL;
5470
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005471 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005472 if (s) return s;
5473 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5474
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005475 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005476 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005477 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005478
5479 return s;
5480
5481err:
5482 bc_num_free(&res.d.n);
5483 return s;
5484}
5485
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005486static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005487{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005488 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005489 BcStatus s;
5490 BcParse parse;
5491 BcVec buf;
5492 BcInstPtr ip;
5493 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005494 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005495
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005496 for (i = 0; i < G.prog.stack.len; ++i) {
5497 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005498 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005499 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005500 }
5501
Denys Vlasenko7d628012018-12-04 21:46:47 +01005502 bc_vec_pop_all(&f->code);
5503 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005504
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005505 sv_file = G.prog.file;
5506 G.prog.file = NULL;
5507
Gavin Howard01055ba2018-11-03 11:00:21 -06005508 s = bc_read_line(&buf, "read> ");
5509 if (s) goto io_err;
5510
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005511 common_parse_init(&parse, BC_PROG_READ);
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005512 bc_lex_file(&parse.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005513
5514 s = bc_parse_text(&parse, buf.v);
5515 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005516 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005517 if (s) goto exec_err;
5518
5519 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005520 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005521 goto exec_err;
5522 }
5523
5524 ip.func = BC_PROG_READ;
5525 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005526 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005527
5528 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005529 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005530
5531 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005532 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005533
5534exec_err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005535 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005536 bc_parse_free(&parse);
5537io_err:
5538 bc_vec_free(&buf);
5539 return s;
5540}
5541
5542static size_t bc_program_index(char *code, size_t *bgn)
5543{
5544 char amt = code[(*bgn)++], i = 0;
5545 size_t res = 0;
5546
5547 for (; i < amt; ++i, ++(*bgn))
5548 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5549
5550 return res;
5551}
5552
5553static char *bc_program_name(char *code, size_t *bgn)
5554{
5555 size_t i;
5556 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5557
5558 s = xmalloc(ptr - str + 1);
5559 c = code[(*bgn)++];
5560
5561 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5562 s[i] = c;
5563
5564 s[i] = '\0';
5565
5566 return s;
5567}
5568
5569static void bc_program_printString(const char *str, size_t *nchars)
5570{
5571 size_t i, len = strlen(str);
5572
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005573#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005574 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005575 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005576 return;
5577 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005578#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005579
5580 for (i = 0; i < len; ++i, ++(*nchars)) {
5581
5582 int c = str[i];
5583
5584 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005585 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005586 else {
5587
5588 c = str[++i];
5589
5590 switch (c) {
5591
5592 case 'a':
5593 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005594 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005595 break;
5596 }
5597
5598 case 'b':
5599 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005600 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005601 break;
5602 }
5603
5604 case '\\':
5605 case 'e':
5606 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005607 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005608 break;
5609 }
5610
5611 case 'f':
5612 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005613 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005614 break;
5615 }
5616
5617 case 'n':
5618 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005619 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005620 *nchars = SIZE_MAX;
5621 break;
5622 }
5623
5624 case 'r':
5625 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005626 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005627 break;
5628 }
5629
5630 case 'q':
5631 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005632 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005633 break;
5634 }
5635
5636 case 't':
5637 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005638 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005639 break;
5640 }
5641
5642 default:
5643 {
5644 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005645 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005646 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005647 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005648 break;
5649 }
5650 }
5651 }
5652 }
5653}
5654
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005655static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005656{
5657 BcStatus s = BC_STATUS_SUCCESS;
5658 BcResult *r;
5659 size_t len, i;
5660 char *str;
5661 BcNum *num = NULL;
5662 bool pop = inst != BC_INST_PRINT;
5663
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005664 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005665 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005666
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005667 r = bc_vec_item_rev(&G.prog.results, idx);
5668 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005669 if (s) return s;
5670
5671 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005672 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5673 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005674 }
5675 else {
5676
5677 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005678 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005679
5680 if (inst == BC_INST_PRINT_STR) {
5681 for (i = 0, len = strlen(str); i < len; ++i) {
5682 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005683 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005684 if (c == '\n') G.prog.nchars = SIZE_MAX;
5685 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005686 }
5687 }
5688 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005689 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005690 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005691 }
5692 }
5693
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005694 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005695
5696 return s;
5697}
5698
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005699static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005700{
5701 BcStatus s;
5702 BcResult res, *ptr;
5703 BcNum *num = NULL;
5704
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005705 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005706 if (s) return s;
5707
5708 bc_num_init(&res.d.n, num->len);
5709 bc_num_copy(&res.d.n, num);
5710 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5711
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005712 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005713
5714 return s;
5715}
5716
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005717static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005718{
5719 BcStatus s;
5720 BcResult *opd1, *opd2, res;
5721 BcNum *n1, *n2;
5722 bool cond = 0;
5723 ssize_t cmp;
5724
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005725 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005726 if (s) return s;
5727 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5728
5729 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005730 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005731 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005732 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005733 else {
5734
5735 cmp = bc_num_cmp(n1, n2);
5736
5737 switch (inst) {
5738
5739 case BC_INST_REL_EQ:
5740 {
5741 cond = cmp == 0;
5742 break;
5743 }
5744
5745 case BC_INST_REL_LE:
5746 {
5747 cond = cmp <= 0;
5748 break;
5749 }
5750
5751 case BC_INST_REL_GE:
5752 {
5753 cond = cmp >= 0;
5754 break;
5755 }
5756
5757 case BC_INST_REL_NE:
5758 {
5759 cond = cmp != 0;
5760 break;
5761 }
5762
5763 case BC_INST_REL_LT:
5764 {
5765 cond = cmp < 0;
5766 break;
5767 }
5768
5769 case BC_INST_REL_GT:
5770 {
5771 cond = cmp > 0;
5772 break;
5773 }
5774 }
5775 }
5776
5777 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5778
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005779 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005780
5781 return s;
5782}
5783
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005784#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005785static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005786 bool push)
5787{
5788 BcNum n2;
5789 BcResult res;
5790
5791 memset(&n2, 0, sizeof(BcNum));
5792 n2.rdx = res.d.id.idx = r->d.id.idx;
5793 res.t = BC_RESULT_STR;
5794
5795 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005796 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005797 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005798 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005799 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005800 }
5801
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005802 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005803
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005804 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005805 bc_vec_push(v, &n2);
5806
5807 return BC_STATUS_SUCCESS;
5808}
5809#endif // ENABLE_DC
5810
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005811static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005812{
5813 BcStatus s;
5814 BcResult *ptr, r;
5815 BcVec *v;
5816 BcNum *n;
5817
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005818 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005819 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005820
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005821 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005822 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005823 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005824 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005825
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005826#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005827 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005828 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005829 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005830#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005831
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005832 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005833 if (s) return s;
5834
5835 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005836 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005837
5838 if (var) {
5839 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5840 bc_num_copy(&r.d.n, n);
5841 }
5842 else {
5843 bc_array_init(&r.d.v, true);
5844 bc_array_copy(&r.d.v, (BcVec *) n);
5845 }
5846
5847 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005848 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005849
5850 return s;
5851}
5852
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005853static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005854{
5855 BcStatus s;
5856 BcResult *left, *right, res;
5857 BcNum *l = NULL, *r = NULL;
5858 unsigned long val, max;
5859 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5860
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005861 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005862 if (s) return s;
5863
5864 ib = left->t == BC_RESULT_IBASE;
5865 sc = left->t == BC_RESULT_SCALE;
5866
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005867#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005868
5869 if (right->t == BC_RESULT_STR) {
5870
5871 BcVec *v;
5872
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005873 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005874 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005875 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005876
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005877 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005878 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005879#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005880
5881 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005882 return bc_error("bad assignment:"
5883 " left side must be scale,"
5884 " ibase, obase, last, var,"
5885 " or array element"
5886 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005887
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005888#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005889 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005890 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005891
5892 if (assign)
5893 bc_num_copy(l, r);
5894 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005895 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005896
5897 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005898#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005899 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005900#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005901
5902 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005903 static const char *const msg[] = {
5904 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5905 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
Denys Vlasenkoaad652a2018-12-05 20:33:23 +01005906 NULL, //can't happen //BC_RESULT_LAST
5907 NULL, //can't happen //BC_RESULT_CONSTANT
5908 NULL, //can't happen //BC_RESULT_ONE
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005909 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5910 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005911 size_t *ptr;
5912
5913 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005914 if (s)
5915 return s;
5916 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005917 if (sc) {
5918 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005919 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005920 }
5921 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005922 if (val < BC_NUM_MIN_BASE)
5923 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005924 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005925 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005926 }
5927
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005928 if (val > max)
5929 return bc_error(msg[s]);
5930 if (!sc)
5931 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005932
5933 *ptr = (size_t) val;
5934 s = BC_STATUS_SUCCESS;
5935 }
5936
5937 bc_num_init(&res.d.n, l->len);
5938 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005939 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005940
5941 return s;
5942}
5943
Denys Vlasenko416ce762018-12-02 20:57:17 +01005944#if !ENABLE_DC
5945#define bc_program_pushVar(code, bgn, pop, copy) \
5946 bc_program_pushVar(code, bgn)
5947// for bc, 'pop' and 'copy' are always false
5948#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005949static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005950 bool pop, bool copy)
5951{
5952 BcStatus s = BC_STATUS_SUCCESS;
5953 BcResult r;
5954 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005955
5956 r.t = BC_RESULT_VAR;
5957 r.d.id.name = name;
5958
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005959#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005960 {
5961 BcVec *v = bc_program_search(name, true);
5962 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005963
Denys Vlasenko416ce762018-12-02 20:57:17 +01005964 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005965
Denys Vlasenko416ce762018-12-02 20:57:17 +01005966 if (!BC_PROG_STACK(v, 2 - copy)) {
5967 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005968 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01005969 }
5970
Gavin Howard01055ba2018-11-03 11:00:21 -06005971 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005972 name = NULL;
5973
5974 if (!BC_PROG_STR(num)) {
5975
5976 r.t = BC_RESULT_TEMP;
5977
5978 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5979 bc_num_copy(&r.d.n, num);
5980 }
5981 else {
5982 r.t = BC_RESULT_STR;
5983 r.d.id.idx = num->rdx;
5984 }
5985
5986 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005987 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005988 }
5989#endif // ENABLE_DC
5990
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005991 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005992
5993 return s;
5994}
5995
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005996static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005997 char inst)
5998{
5999 BcStatus s = BC_STATUS_SUCCESS;
6000 BcResult r;
6001 BcNum *num;
6002
6003 r.d.id.name = bc_program_name(code, bgn);
6004
6005 if (inst == BC_INST_ARRAY) {
6006 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006007 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006008 }
6009 else {
6010
6011 BcResult *operand;
6012 unsigned long temp;
6013
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006014 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006015 if (s) goto err;
6016 s = bc_num_ulong(num, &temp);
6017 if (s) goto err;
6018
6019 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006020 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06006021 goto err;
6022 }
6023
6024 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006025 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06006026 }
6027
6028err:
6029 if (s) free(r.d.id.name);
6030 return s;
6031}
6032
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006033#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006034static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006035{
6036 BcStatus s;
6037 BcResult *ptr, res, copy;
6038 BcNum *num = NULL;
6039 char inst2 = inst;
6040
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006041 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006042 if (s) return s;
6043
6044 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
6045 copy.t = BC_RESULT_TEMP;
6046 bc_num_init(&copy.d.n, num->len);
6047 bc_num_copy(&copy.d.n, num);
6048 }
6049
6050 res.t = BC_RESULT_ONE;
6051 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
6052 BC_INST_ASSIGN_PLUS :
6053 BC_INST_ASSIGN_MINUS;
6054
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006055 bc_vec_push(&G.prog.results, &res);
6056 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006057
6058 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006059 bc_vec_pop(&G.prog.results);
6060 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006061 }
6062
6063 return s;
6064}
6065
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006066static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006067{
6068 BcStatus s = BC_STATUS_SUCCESS;
6069 BcInstPtr ip;
6070 size_t i, nparams = bc_program_index(code, idx);
6071 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006072 BcId *a;
6073 BcResultData param;
6074 BcResult *arg;
6075
6076 ip.idx = 0;
6077 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006078 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006079
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006080 if (func->code.len == 0) {
6081 return bc_error("undefined function");
6082 }
6083 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006084 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006085 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006086 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006087
6088 for (i = 0; i < nparams; ++i) {
6089
6090 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006091 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006092
6093 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006094 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006095
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006096 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006097 if (s) return s;
6098 }
6099
6100 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006101 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006102
6103 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006104 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006105
6106 if (a->idx) {
6107 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6108 bc_vec_push(v, &param.n);
6109 }
6110 else {
6111 bc_array_init(&param.v, true);
6112 bc_vec_push(v, &param.v);
6113 }
6114 }
6115
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006116 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006117
6118 return BC_STATUS_SUCCESS;
6119}
6120
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006121static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006122{
6123 BcStatus s;
6124 BcResult res;
6125 BcFunc *f;
6126 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006127 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006128
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006129 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006130 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006131
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006132 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006133 res.t = BC_RESULT_TEMP;
6134
6135 if (inst == BC_INST_RET) {
6136
6137 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006138 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006139
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006140 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006141 if (s) return s;
6142 bc_num_init(&res.d.n, num->len);
6143 bc_num_copy(&res.d.n, num);
6144 }
6145 else {
6146 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6147 bc_num_zero(&res.d.n);
6148 }
6149
6150 // We need to pop arguments as well, so this takes that into account.
6151 for (i = 0; i < f->autos.len; ++i) {
6152
6153 BcVec *v;
6154 BcId *a = bc_vec_item(&f->autos, i);
6155
Denys Vlasenkodf515392018-12-02 19:27:48 +01006156 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006157 bc_vec_pop(v);
6158 }
6159
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006160 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6161 bc_vec_push(&G.prog.results, &res);
6162 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006163
6164 return BC_STATUS_SUCCESS;
6165}
6166#endif // ENABLE_BC
6167
6168static unsigned long bc_program_scale(BcNum *n)
6169{
6170 return (unsigned long) n->rdx;
6171}
6172
6173static unsigned long bc_program_len(BcNum *n)
6174{
6175 unsigned long len = n->len;
6176 size_t i;
6177
6178 if (n->rdx != n->len) return len;
6179 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6180
6181 return len;
6182}
6183
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006185{
6186 BcStatus s;
6187 BcResult *opnd;
6188 BcNum *num = NULL;
6189 BcResult res;
6190 bool len = inst == BC_INST_LENGTH;
6191
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006192 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006193 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006194 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006195
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006196 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006197 if (s) return s;
6198
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006199#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006200 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006201 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006202#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006203
6204 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6205
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006206 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006207#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006208 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006209 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006210 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006211#endif
6212#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006213 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6214
6215 char **str;
6216 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6217
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006218 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006219 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006220 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006221#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006222 else {
6223 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006224 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006225 }
6226
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006227 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006228
6229 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006230}
6231
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006232#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006233static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006234{
6235 BcStatus s;
6236 BcResult *opd1, *opd2, res, res2;
6237 BcNum *n1, *n2 = NULL;
6238
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006239 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006240 if (s) return s;
6241
6242 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6243 bc_num_init(&res2.d.n, n2->len);
6244
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006245 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006246 if (s) goto err;
6247
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006248 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006249 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006250 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006251
6252 return s;
6253
6254err:
6255 bc_num_free(&res2.d.n);
6256 bc_num_free(&res.d.n);
6257 return s;
6258}
6259
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006260static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006261{
6262 BcStatus s;
6263 BcResult *r1, *r2, *r3, res;
6264 BcNum *n1, *n2, *n3;
6265
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006266 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006267 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006268 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006269 if (s) return s;
6270
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006271 r1 = bc_vec_item_rev(&G.prog.results, 2);
6272 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006273 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006274 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006275 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006276
6277 // Make sure that the values have their pointers updated, if necessary.
6278 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6279
6280 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006281 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006282 if (s) return s;
6283 }
6284
6285 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006286 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006287 if (s) return s;
6288 }
6289 }
6290
6291 bc_num_init(&res.d.n, n3->len);
6292 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6293 if (s) goto err;
6294
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006295 bc_vec_pop(&G.prog.results);
6296 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006297
6298 return s;
6299
6300err:
6301 bc_num_free(&res.d.n);
6302 return s;
6303}
6304
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006305static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006306{
Gavin Howard01055ba2018-11-03 11:00:21 -06006307 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006308 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006309
6310 res.t = BC_RESULT_TEMP;
6311
6312 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006313 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006314 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006315}
6316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006317static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006318{
6319 BcStatus s;
6320 BcResult *r, res;
6321 BcNum *num = NULL, n;
6322 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006323 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006324 unsigned long val;
6325
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006326 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006327 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006328 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006329
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006330 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006331 if (s) return s;
6332
6333 if (BC_PROG_NUM(r, num)) {
6334
6335 bc_num_init(&n, BC_NUM_DEF_SIZE);
6336 bc_num_copy(&n, num);
6337 bc_num_truncate(&n, n.rdx);
6338
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006339 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006340 if (s) goto num_err;
6341 s = bc_num_ulong(&n, &val);
6342 if (s) goto num_err;
6343
6344 c = (char) val;
6345
6346 bc_num_free(&n);
6347 }
6348 else {
6349 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006350 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006351 c = str2[0];
6352 }
6353
6354 str = xmalloc(2);
6355 str[0] = c;
6356 str[1] = '\0';
6357
6358 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006359 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006360
6361 if (idx != len + BC_PROG_REQ_FUNCS) {
6362
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006363 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6364 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006365 len = idx;
6366 break;
6367 }
6368 }
6369
6370 free(str);
6371 }
6372 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006373 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006374
6375 res.t = BC_RESULT_STR;
6376 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006377 bc_vec_pop(&G.prog.results);
6378 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006379
6380 return BC_STATUS_SUCCESS;
6381
6382num_err:
6383 bc_num_free(&n);
6384 return s;
6385}
6386
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006387static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006388{
6389 BcStatus s;
6390 BcResult *r;
6391 BcNum *n = NULL;
6392 size_t idx;
6393 char *str;
6394
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006395 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006396 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006397 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006398
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006399 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006400 if (s) return s;
6401
6402 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006403 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006404 else {
6405 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006406 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006407 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006408 }
6409
6410 return s;
6411}
6412
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006413static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006414{
6415 BcStatus s;
6416 BcResult *opnd;
6417 BcNum *num = NULL;
6418 unsigned long val;
6419
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006420 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006421 if (s) return s;
6422 s = bc_num_ulong(num, &val);
6423 if (s) return s;
6424
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006425 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006426
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006427 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006428 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01006429 if (G.prog.stack.len == val) {
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006430 QUIT_OR_RETURN_TO_MAIN;
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01006431 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006432
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006433 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006434
6435 return s;
6436}
6437
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006438static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006439 bool cond)
6440{
6441 BcStatus s = BC_STATUS_SUCCESS;
6442 BcResult *r;
6443 char **str;
6444 BcFunc *f;
6445 BcParse prs;
6446 BcInstPtr ip;
6447 size_t fidx, sidx;
6448 BcNum *n;
6449 bool exec;
6450
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006451 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006452 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006453
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006454 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006455
6456 if (cond) {
6457
Gavin Howard01055ba2018-11-03 11:00:21 -06006458 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6459
6460 if (code[*bgn] == BC_PARSE_STREND)
6461 (*bgn) += 1;
6462 else
6463 else_name = bc_program_name(code, bgn);
6464
6465 exec = r->d.n.len != 0;
6466
6467 if (exec)
6468 name = then_name;
6469 else if (else_name != NULL) {
6470 exec = true;
6471 name = else_name;
6472 }
6473
6474 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006475 BcVec *v;
6476 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006477 n = bc_vec_top(v);
6478 }
6479
6480 free(then_name);
6481 free(else_name);
6482
6483 if (!exec) goto exit;
6484 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006485 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006486 goto exit;
6487 }
6488
6489 sidx = n->rdx;
6490 }
6491 else {
6492
6493 if (r->t == BC_RESULT_STR)
6494 sidx = r->d.id.idx;
6495 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006496 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006497 if (s || !BC_PROG_STR(n)) goto exit;
6498 sidx = n->rdx;
6499 }
6500 else
6501 goto exit;
6502 }
6503
6504 fidx = sidx + BC_PROG_REQ_FUNCS;
6505
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006506 str = bc_vec_item(&G.prog.strs, sidx);
6507 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006508
6509 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006510 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006511 s = bc_parse_text(&prs, *str);
6512 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006513 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006514 if (s) goto err;
6515
6516 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006517 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006518 goto err;
6519 }
6520
6521 bc_parse_free(&prs);
6522 }
6523
6524 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006525 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006526 ip.func = fidx;
6527
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006528 bc_vec_pop(&G.prog.results);
6529 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530
6531 return BC_STATUS_SUCCESS;
6532
6533err:
6534 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006535 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006536 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006537exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006538 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006539 return s;
6540}
6541#endif // ENABLE_DC
6542
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006543static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006544{
Gavin Howard01055ba2018-11-03 11:00:21 -06006545 BcResult res;
6546 unsigned long val;
6547
6548 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6549 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006550 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006551 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006552 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006553 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006554 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006555
6556 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006557 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006558 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006559}
6560
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006561static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006562{
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 BcId entry, *entry_ptr;
6564 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006565 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006566
6567 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006568 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006569
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006570 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6571 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006572
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006573 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006574 *idx = entry_ptr->idx;
6575
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006576 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006577
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006578 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006579
6580 // We need to reset these, so the function can be repopulated.
6581 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006582 bc_vec_pop_all(&func->autos);
6583 bc_vec_pop_all(&func->code);
6584 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006585 }
6586 else {
6587 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006588 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006589 }
6590}
6591
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006592static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006593{
6594 BcStatus s = BC_STATUS_SUCCESS;
6595 size_t idx;
6596 BcResult r, *ptr;
6597 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006598 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6599 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006600 char *code = func->code.v;
6601 bool cond = false;
6602
6603 while (!s && ip->idx < func->code.len) {
6604
6605 char inst = code[(ip->idx)++];
6606
6607 switch (inst) {
6608
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006609#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 case BC_INST_JUMP_ZERO:
6611 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006612 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006613 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006614 cond = !bc_num_cmp(num, &G.prog.zero);
6615 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006616 }
6617 // Fallthrough.
6618 case BC_INST_JUMP:
6619 {
6620 size_t *addr;
6621 idx = bc_program_index(code, &ip->idx);
6622 addr = bc_vec_item(&func->labels, idx);
6623 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6624 break;
6625 }
6626
6627 case BC_INST_CALL:
6628 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006629 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006630 break;
6631 }
6632
6633 case BC_INST_INC_PRE:
6634 case BC_INST_DEC_PRE:
6635 case BC_INST_INC_POST:
6636 case BC_INST_DEC_POST:
6637 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006638 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
6642 case BC_INST_HALT:
6643 {
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006644 QUIT_OR_RETURN_TO_MAIN;
Gavin Howard01055ba2018-11-03 11:00:21 -06006645 break;
6646 }
6647
6648 case BC_INST_RET:
6649 case BC_INST_RET0:
6650 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006651 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006652 break;
6653 }
6654
6655 case BC_INST_BOOL_OR:
6656 case BC_INST_BOOL_AND:
6657#endif // ENABLE_BC
6658 case BC_INST_REL_EQ:
6659 case BC_INST_REL_LE:
6660 case BC_INST_REL_GE:
6661 case BC_INST_REL_NE:
6662 case BC_INST_REL_LT:
6663 case BC_INST_REL_GT:
6664 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006665 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006666 break;
6667 }
6668
6669 case BC_INST_READ:
6670 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006671 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006672 break;
6673 }
6674
6675 case BC_INST_VAR:
6676 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006677 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006678 break;
6679 }
6680
6681 case BC_INST_ARRAY_ELEM:
6682 case BC_INST_ARRAY:
6683 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006684 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006685 break;
6686 }
6687
6688 case BC_INST_LAST:
6689 {
6690 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006691 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006692 break;
6693 }
6694
6695 case BC_INST_IBASE:
6696 case BC_INST_SCALE:
6697 case BC_INST_OBASE:
6698 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006699 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006700 break;
6701 }
6702
6703 case BC_INST_SCALE_FUNC:
6704 case BC_INST_LENGTH:
6705 case BC_INST_SQRT:
6706 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006707 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006708 break;
6709 }
6710
6711 case BC_INST_NUM:
6712 {
6713 r.t = BC_RESULT_CONSTANT;
6714 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006715 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006716 break;
6717 }
6718
6719 case BC_INST_POP:
6720 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006721 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006722 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006723 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006724 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006725 break;
6726 }
6727
6728 case BC_INST_POP_EXEC:
6729 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006730 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006731 break;
6732 }
6733
6734 case BC_INST_PRINT:
6735 case BC_INST_PRINT_POP:
6736 case BC_INST_PRINT_STR:
6737 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006738 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006739 break;
6740 }
6741
6742 case BC_INST_STR:
6743 {
6744 r.t = BC_RESULT_STR;
6745 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006746 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006747 break;
6748 }
6749
6750 case BC_INST_POWER:
6751 case BC_INST_MULTIPLY:
6752 case BC_INST_DIVIDE:
6753 case BC_INST_MODULUS:
6754 case BC_INST_PLUS:
6755 case BC_INST_MINUS:
6756 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006757 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006758 break;
6759 }
6760
6761 case BC_INST_BOOL_NOT:
6762 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006763 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006764 if (s) return s;
6765
6766 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006767 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6768 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006769
6770 break;
6771 }
6772
6773 case BC_INST_NEG:
6774 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006775 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006776 break;
6777 }
6778
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006779#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006780 case BC_INST_ASSIGN_POWER:
6781 case BC_INST_ASSIGN_MULTIPLY:
6782 case BC_INST_ASSIGN_DIVIDE:
6783 case BC_INST_ASSIGN_MODULUS:
6784 case BC_INST_ASSIGN_PLUS:
6785 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006786#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006787 case BC_INST_ASSIGN:
6788 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006789 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 break;
6791 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006792#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006793 case BC_INST_MODEXP:
6794 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006795 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 break;
6797 }
6798
6799 case BC_INST_DIVMOD:
6800 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006801 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006802 break;
6803 }
6804
6805 case BC_INST_EXECUTE:
6806 case BC_INST_EXEC_COND:
6807 {
6808 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006809 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006810 break;
6811 }
6812
6813 case BC_INST_PRINT_STACK:
6814 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006815 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6816 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006817 break;
6818 }
6819
6820 case BC_INST_CLEAR_STACK:
6821 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006822 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006823 break;
6824 }
6825
6826 case BC_INST_STACK_LEN:
6827 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006828 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006829 break;
6830 }
6831
6832 case BC_INST_DUPLICATE:
6833 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006834 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006835 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006836 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006837 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006838 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006839 break;
6840 }
6841
6842 case BC_INST_SWAP:
6843 {
6844 BcResult *ptr2;
6845
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006846 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006847 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006848
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006849 ptr = bc_vec_item_rev(&G.prog.results, 0);
6850 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006851 memcpy(&r, ptr, sizeof(BcResult));
6852 memcpy(ptr, ptr2, sizeof(BcResult));
6853 memcpy(ptr2, &r, sizeof(BcResult));
6854
6855 break;
6856 }
6857
6858 case BC_INST_ASCIIFY:
6859 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006860 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006861 break;
6862 }
6863
6864 case BC_INST_PRINT_STREAM:
6865 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006866 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006867 break;
6868 }
6869
6870 case BC_INST_LOAD:
6871 case BC_INST_PUSH_VAR:
6872 {
6873 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006874 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006875 break;
6876 }
6877
6878 case BC_INST_PUSH_TO_VAR:
6879 {
6880 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006881 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006882 free(name);
6883 break;
6884 }
6885
6886 case BC_INST_QUIT:
6887 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006888 if (G.prog.stack.len <= 2)
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006889 QUIT_OR_RETURN_TO_MAIN;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006890 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006891 break;
6892 }
6893
6894 case BC_INST_NQUIT:
6895 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006896 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006897 break;
6898 }
6899#endif // ENABLE_DC
6900 }
6901
Denys Vlasenkod38af482018-12-04 19:11:02 +01006902 if (s || G_interrupt) {
6903 bc_program_reset();
6904 break;
6905 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006906
6907 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006908 ip = bc_vec_top(&G.prog.stack);
6909 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006910 code = func->code.v;
6911 }
6912
6913 return s;
6914}
6915
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006916#if ENABLE_BC
Denys Vlasenko54214c32018-12-06 09:07:06 +01006917static void bc_vm_info(void)
6918{
6919 printf("%s "BB_VER"\n"
6920 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6921 "Report bugs at: https://github.com/gavinhoward/bc\n"
6922 "This is free software with ABSOLUTELY NO WARRANTY\n"
6923 , applet_name);
6924}
6925
6926static void bc_args(char **argv)
6927{
6928 unsigned opts;
6929 int i;
6930
6931 GETOPT_RESET();
6932#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006933 opts = option_mask32 |= getopt32long(argv, "wvsqli",
Denys Vlasenko54214c32018-12-06 09:07:06 +01006934 "warn\0" No_argument "w"
6935 "version\0" No_argument "v"
6936 "standard\0" No_argument "s"
6937 "quiet\0" No_argument "q"
6938 "mathlib\0" No_argument "l"
6939 "interactive\0" No_argument "i"
6940 );
6941#else
Denys Vlasenko6d0be102018-12-06 18:41:59 +01006942 opts = option_mask32 |= getopt32(argv, "wvsqli");
Denys Vlasenko54214c32018-12-06 09:07:06 +01006943#endif
6944 if (getenv("POSIXLY_CORRECT"))
6945 option_mask32 |= BC_FLAG_S;
6946
6947///should be in bc_vm_run() instead??
6948 if (opts & BC_FLAG_V) {
6949 bc_vm_info();
6950 exit(0);
6951 }
6952
6953 for (i = optind; argv[i]; ++i)
6954 bc_vec_push(&G.files, argv + i);
6955}
6956
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006957static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006958{
Gavin Howard01055ba2018-11-03 11:00:21 -06006959 BcVec v;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006960 char *buf;
Denys Vlasenko54214c32018-12-06 09:07:06 +01006961 char *env_args = getenv("BC_ENV_ARGS");
Gavin Howard01055ba2018-11-03 11:00:21 -06006962
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006963 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006964
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006965 G.env_args = xstrdup(env_args);
6966 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006967
6968 bc_vec_init(&v, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006969
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006970 while (*(buf = skip_whitespace(buf)) != '\0') {
6971 bc_vec_push(&v, &buf);
6972 buf = skip_non_whitespace(buf);
6973 if (!*buf)
6974 break;
6975 *buf++ = '\0';
Gavin Howard01055ba2018-11-03 11:00:21 -06006976 }
6977
Denys Vlasenko54214c32018-12-06 09:07:06 +01006978 // NULL terminate, and pass argv[] so that first arg is argv[1]
6979 if (sizeof(int) == sizeof(char*)) {
6980 bc_vec_push(&v, &const_int_0);
6981 } else {
6982 static char *const nullptr = NULL;
6983 bc_vec_push(&v, &nullptr);
6984 }
6985 bc_args(((char **)v.v) - 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006986
6987 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006988}
6989#endif // ENABLE_BC
6990
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006991static unsigned bc_vm_envLen(const char *var)
Gavin Howard01055ba2018-11-03 11:00:21 -06006992{
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006993 char *lenv;
6994 unsigned len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006995
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01006996 lenv = getenv(var);
6997 len = BC_NUM_PRINT_WIDTH;
Gavin Howard01055ba2018-11-03 11:00:21 -06006998 if (!lenv) return len;
6999
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007000 len = bb_strtou(lenv, NULL, 10) - 1;
7001 if (errno || len < 2 || len >= INT_MAX)
Gavin Howard01055ba2018-11-03 11:00:21 -06007002 len = BC_NUM_PRINT_WIDTH;
7003
7004 return len;
7005}
7006
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007007static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06007008{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007009 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06007010
Gavin Howard01055ba2018-11-03 11:00:21 -06007011 if (s) return s;
7012
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007013 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007014 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01007015 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007016 }
7017
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007018 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007019 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01007020 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007021 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01007022 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06007023 }
7024
7025 return s;
7026}
7027
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007028static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06007029{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007030 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06007031 char *data;
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007032 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007033 BcFunc *main_func;
7034 BcInstPtr *ip;
7035
Denys Vlasenkodf515392018-12-02 19:27:48 +01007036 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01007037 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007038
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007039 sv_file = G.prog.file;
7040 G.prog.file = file;
7041 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007042 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007043 if (s) goto err;
7044
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007045 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7046 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007047
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007048 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01007049 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06007050
7051err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007052 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06007053 free(data);
7054 return s;
7055}
7056
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007057static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007058{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007059 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007060 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06007061 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007062 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06007063
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007064 G.prog.file = NULL;
7065 bc_lex_file(&G.prs.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06007066
Denys Vlasenko7d628012018-12-04 21:46:47 +01007067 bc_char_vec_init(&buffer);
7068 bc_char_vec_init(&buf);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01007069 bc_vec_pushZeroByte(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007070
7071 // This loop is complex because the vm tries not to send any lines that end
7072 // with a backslash to the parser. The reason for that is because the parser
7073 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7074 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenko657d6bb2018-12-05 20:25:03 +01007075 s = BC_STATUS_SUCCESS;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01007076 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007077
7078 char *string = buf.v;
7079
7080 len = buf.len - 1;
7081
7082 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007083 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007084 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007085 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007086 str += 1;
7087 }
7088 else if (len > 1 || comment) {
7089
7090 for (i = 0; i < len; ++i) {
7091
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007092 bool notend = len > i + 1;
7093 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007094
7095 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007096 if (G.sbgn == G.send)
7097 str ^= c == G.sbgn;
7098 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007099 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007100 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007101 str += 1;
7102 }
7103
7104 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7105 comment = true;
7106 break;
7107 }
7108 else if (c == '*' && notend && comment && string[i + 1] == '/')
7109 comment = false;
7110 }
7111
7112 if (str || comment || string[len - 2] == '\\') {
7113 bc_vec_concat(&buffer, buf.v);
7114 continue;
7115 }
7116 }
7117
7118 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007119 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007120 if (s) {
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007121 if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin) {
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007122 // Debug config, non-interactive mode:
7123 // return all the way back to main.
7124 // Non-debug builds do not come here, they exit.
7125 break;
7126 }
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007127 fflush_and_check();
7128 fputs("ready for more input\n", stderr);
7129 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007130
Denys Vlasenko7d628012018-12-04 21:46:47 +01007131 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007132 }
7133
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007134 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007135 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007136 }
7137 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007138 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007139 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007140
Gavin Howard01055ba2018-11-03 11:00:21 -06007141 bc_vec_free(&buf);
7142 bc_vec_free(&buffer);
7143 return s;
7144}
7145
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007146#if ENABLE_BC
7147static const char bc_lib[] = {
7148 "scale=20"
7149"\n" "define e(x){"
7150"\n" "auto b,s,n,r,d,i,p,f,v"
7151"\n" "b=ibase"
7152"\n" "ibase=A"
7153"\n" "if(x<0){"
7154"\n" "n=1"
7155"\n" "x=-x"
7156"\n" "}"
7157"\n" "s=scale"
7158"\n" "r=6+s+0.44*x"
7159"\n" "scale=scale(x)+1"
7160"\n" "while(x>1){"
7161"\n" "d+=1"
7162"\n" "x/=2"
7163"\n" "scale+=1"
7164"\n" "}"
7165"\n" "scale=r"
7166"\n" "r=x+1"
7167"\n" "p=x"
7168"\n" "f=v=1"
7169"\n" "for(i=2;v!=0;++i){"
7170"\n" "p*=x"
7171"\n" "f*=i"
7172"\n" "v=p/f"
7173"\n" "r+=v"
7174"\n" "}"
7175"\n" "while((d--)!=0)r*=r"
7176"\n" "scale=s"
7177"\n" "ibase=b"
7178"\n" "if(n!=0)return(1/r)"
7179"\n" "return(r/1)"
7180"\n" "}"
7181"\n" "define l(x){"
7182"\n" "auto b,s,r,p,a,q,i,v"
7183"\n" "b=ibase"
7184"\n" "ibase=A"
7185"\n" "if(x<=0){"
7186"\n" "r=(1-10^scale)/1"
7187"\n" "ibase=b"
7188"\n" "return(r)"
7189"\n" "}"
7190"\n" "s=scale"
7191"\n" "scale+=6"
7192"\n" "p=2"
7193"\n" "while(x>=2){"
7194"\n" "p*=2"
7195"\n" "x=sqrt(x)"
7196"\n" "}"
7197"\n" "while(x<=0.5){"
7198"\n" "p*=2"
7199"\n" "x=sqrt(x)"
7200"\n" "}"
7201"\n" "r=a=(x-1)/(x+1)"
7202"\n" "q=a*a"
7203"\n" "v=1"
7204"\n" "for(i=3;v!=0;i+=2){"
7205"\n" "a*=q"
7206"\n" "v=a/i"
7207"\n" "r+=v"
7208"\n" "}"
7209"\n" "r*=p"
7210"\n" "scale=s"
7211"\n" "ibase=b"
7212"\n" "return(r/1)"
7213"\n" "}"
7214"\n" "define s(x){"
7215"\n" "auto b,s,r,n,a,q,i"
7216"\n" "b=ibase"
7217"\n" "ibase=A"
7218"\n" "s=scale"
7219"\n" "scale=1.1*s+2"
7220"\n" "a=a(1)"
7221"\n" "if(x<0){"
7222"\n" "n=1"
7223"\n" "x=-x"
7224"\n" "}"
7225"\n" "scale=0"
7226"\n" "q=(x/a+2)/4"
7227"\n" "x=x-4*q*a"
7228"\n" "if(q%2!=0)x=-x"
7229"\n" "scale=s+2"
7230"\n" "r=a=x"
7231"\n" "q=-x*x"
7232"\n" "for(i=3;a!=0;i+=2){"
7233"\n" "a*=q/(i*(i-1))"
7234"\n" "r+=a"
7235"\n" "}"
7236"\n" "scale=s"
7237"\n" "ibase=b"
7238"\n" "if(n!=0)return(-r/1)"
7239"\n" "return(r/1)"
7240"\n" "}"
7241"\n" "define c(x){"
7242"\n" "auto b,s"
7243"\n" "b=ibase"
7244"\n" "ibase=A"
7245"\n" "s=scale"
7246"\n" "scale*=1.2"
7247"\n" "x=s(2*a(1)+x)"
7248"\n" "scale=s"
7249"\n" "ibase=b"
7250"\n" "return(x/1)"
7251"\n" "}"
7252"\n" "define a(x){"
7253"\n" "auto b,s,r,n,a,m,t,f,i,u"
7254"\n" "b=ibase"
7255"\n" "ibase=A"
7256"\n" "n=1"
7257"\n" "if(x<0){"
7258"\n" "n=-1"
7259"\n" "x=-x"
7260"\n" "}"
7261"\n" "if(x==1){"
7262"\n" "if(scale<65){"
7263"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7264"\n" "}"
7265"\n" "}"
7266"\n" "if(x==.2){"
7267"\n" "if(scale<65){"
7268"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7269"\n" "}"
7270"\n" "}"
7271"\n" "s=scale"
7272"\n" "if(x>.2){"
7273"\n" "scale+=5"
7274"\n" "a=a(.2)"
7275"\n" "}"
7276"\n" "scale=s+3"
7277"\n" "while(x>.2){"
7278"\n" "m+=1"
7279"\n" "x=(x-.2)/(1+.2*x)"
7280"\n" "}"
7281"\n" "r=u=x"
7282"\n" "f=-x*x"
7283"\n" "t=1"
7284"\n" "for(i=3;t!=0;i+=2){"
7285"\n" "u*=f"
7286"\n" "t=u/i"
7287"\n" "r+=t"
7288"\n" "}"
7289"\n" "scale=s"
7290"\n" "ibase=b"
7291"\n" "return((m*a+r)/n)"
7292"\n" "}"
7293"\n" "define j(n,x){"
7294"\n" "auto b,s,o,a,i,v,f"
7295"\n" "b=ibase"
7296"\n" "ibase=A"
7297"\n" "s=scale"
7298"\n" "scale=0"
7299"\n" "n/=1"
7300"\n" "if(n<0){"
7301"\n" "n=-n"
7302"\n" "if(n%2==1)o=1"
7303"\n" "}"
7304"\n" "a=1"
7305"\n" "for(i=2;i<=n;++i)a*=i"
7306"\n" "scale=1.5*s"
7307"\n" "a=(x^n)/2^n/a"
7308"\n" "r=v=1"
7309"\n" "f=-x*x/4"
7310"\n" "scale=scale+length(a)-scale(a)"
7311"\n" "for(i=1;v!=0;++i){"
7312"\n" "v=v*f/i/(n+i)"
7313"\n" "r+=v"
7314"\n" "}"
7315"\n" "scale=s"
7316"\n" "ibase=b"
7317"\n" "if(o!=0)a=-a"
7318"\n" "return(a*r/1)"
7319"\n" "}"
7320};
7321#endif // ENABLE_BC
7322
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007323static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007324{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007325 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007326 size_t i;
7327
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007328#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007329 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007330
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007331 // We know that internal library is not buggy,
7332 // thus error checking is normally disabled.
7333# define DEBUG_LIB 0
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007334 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007335 s = bc_parse_text(&G.prs, bc_lib);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007336 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007337
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007338 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007339 s = G.prs.parse(&G.prs);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007340 if (DEBUG_LIB && s) return s;
7341 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007342 s = bc_program_exec();
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007343 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007344 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007345#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007346
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007347 s = BC_STATUS_SUCCESS;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007348 for (i = 0; !s && i < G.files.len; ++i)
7349 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007350 if (ENABLE_FEATURE_CLEAN_UP && s && !G_ttyin) {
7351 // Debug config, non-interactive mode:
7352 // return all the way back to main.
7353 // Non-debug builds do not come here, they exit.
7354 return s;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007355 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007356
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007357 if (IS_BC || (option_mask32 & BC_FLAG_I)) {
7358 if (s) {
7359 fflush_and_check();
7360 fputs("ready for more input\n", stderr);
7361 }
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007362 s = bc_vm_stdin();
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007363 }
7364
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007365 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7366 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007367
Denys Vlasenko00d77792018-11-30 23:13:42 +01007368 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007369}
7370
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007371#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007372static void bc_program_free(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007373{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007374 bc_num_free(&G.prog.ib);
7375 bc_num_free(&G.prog.ob);
7376 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007377# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007378 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007379# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007380 bc_vec_free(&G.prog.fns);
7381 bc_vec_free(&G.prog.fn_map);
7382 bc_vec_free(&G.prog.vars);
7383 bc_vec_free(&G.prog.var_map);
7384 bc_vec_free(&G.prog.arrs);
7385 bc_vec_free(&G.prog.arr_map);
7386 bc_vec_free(&G.prog.strs);
7387 bc_vec_free(&G.prog.consts);
7388 bc_vec_free(&G.prog.results);
7389 bc_vec_free(&G.prog.stack);
7390 bc_num_free(&G.prog.last);
7391 bc_num_free(&G.prog.zero);
7392 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007393}
7394
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007395static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007396{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007397 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007398 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007399 bc_parse_free(&G.prs);
7400 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007401}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007402#endif
7403
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007404static void bc_program_init(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007405{
7406 size_t idx;
7407 BcInstPtr ip;
7408
7409 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7410 memset(&ip, 0, sizeof(BcInstPtr));
7411
7412 /* G.prog.nchars = G.prog.scale = 0; - already is */
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007413
7414 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7415 bc_num_ten(&G.prog.ib);
7416 G.prog.ib_t = 10;
7417
7418 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7419 bc_num_ten(&G.prog.ob);
7420 G.prog.ob_t = 10;
7421
7422 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7423 bc_num_ten(&G.prog.hexb);
7424 G.prog.hexb.num[0] = 6;
7425
7426#if ENABLE_DC
7427 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7428 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7429#endif
7430
7431 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7432 bc_num_zero(&G.prog.last);
7433
7434 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7435 bc_num_zero(&G.prog.zero);
7436
7437 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7438 bc_num_one(&G.prog.one);
7439
7440 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007441 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007442
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007443 bc_program_addFunc(xstrdup("(main)"), &idx);
7444 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007445
7446 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007447 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007448
7449 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007450 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007451
7452 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7453 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7454 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7455 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7456 bc_vec_push(&G.prog.stack, &ip);
7457}
Gavin Howard01055ba2018-11-03 11:00:21 -06007458
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007459static int bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007460{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007461#if ENABLE_FEATURE_EDITING
7462 G.line_input_state = new_line_input_t(DO_HISTORY);
7463#endif
7464 G.prog.len = bc_vm_envLen(env_len);
7465
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007466 bc_vec_init(&G.files, sizeof(char *), NULL);
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007467 if (IS_BC)
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007468 IF_BC(bc_vm_envArgs();)
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007469 bc_program_init();
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007470 if (IS_BC) {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007471 IF_BC(bc_parse_init(&G.prs, BC_PROG_MAIN);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007472 } else {
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01007473 IF_DC(dc_parse_init(&G.prs, BC_PROG_MAIN);)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007474 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007475
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007476 if (isatty(0)) {
Denys Vlasenkod38af482018-12-04 19:11:02 +01007477#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007478 G_ttyin = 1;
Denys Vlasenko17c54722018-12-04 21:21:32 +01007479 // With SA_RESTART, most system calls will restart
7480 // (IOW: they won't fail with EINTR).
7481 // In particular, this means ^C won't cause
7482 // stdout to get into "error state" if SIGINT hits
7483 // within write() syscall.
7484 // The downside is that ^C while line input is taken
7485 // will only be handled after [Enter] since read()
7486 // from stdin is not interrupted by ^C either,
7487 // it restarts, thus fgetc() does not return on ^C.
7488 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7489
7490 // Without SA_RESTART, this exhibits a bug:
7491 // "while (1) print 1" and try ^C-ing it.
7492 // Intermittently, instead of returning to input line,
7493 // you'll get "output error: Interrupted system call"
7494 // and exit.
7495 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007496#endif
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007497 return 1; // "tty"
Denys Vlasenkod38af482018-12-04 19:11:02 +01007498 }
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007499 return 0; // "not a tty"
7500}
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007501
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007502static BcStatus bc_vm_run(void)
7503{
7504 BcStatus st = bc_vm_exec();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007505#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01007506 if (G_exiting) // it was actually "halt" or "quit"
7507 st = EXIT_SUCCESS;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007508 bc_vm_free();
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01007509# if ENABLE_FEATURE_EDITING
7510 free_line_input_t(G.line_input_state);
7511# endif
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007512 FREE_G();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007513#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007514 return st;
7515}
7516
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007517#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007518int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007519int bc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007520{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007521 int is_tty;
7522
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007523 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007524 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007525
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007526 is_tty = bc_vm_init("BC_LINE_LENGTH");
7527
7528 bc_args(argv);
7529
7530 if (is_tty && !(option_mask32 & BC_FLAG_Q))
7531 bc_vm_info();
7532
7533 return bc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007534}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007535#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007536
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007537#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007538int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007539int dc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007540{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007541 int noscript;
7542
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007543 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007544 G.sbgn = '[';
7545 G.send = ']';
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007546 // TODO: dc (GNU bc 1.07.1) 1.4.1 seems to use default width
7547 // 1 char narrower than bc from the same package. Do the same?
7548 bc_vm_init("DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007549
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007550 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
7551 noscript = BC_FLAG_I;
7552 for (;;) {
7553 int n = getopt(argc, argv, "e:f:x");
7554 if (n <= 0)
7555 break;
7556 switch (n) {
7557 case 'e':
7558 noscript = 0;
7559 n = bc_vm_process(optarg);
7560 if (n) return n;
7561 break;
7562 case 'f':
7563 noscript = 0;
7564 bc_vm_file(optarg);
7565 break;
7566 case 'x':
7567 option_mask32 |= DC_FLAG_X;
7568 break;
7569 default:
7570 bb_show_usage();
7571 }
7572 }
7573 argv += optind;
7574
7575 while (*argv) {
7576 noscript = 0;
7577 bc_vec_push(&G.files, argv++);
7578 }
7579
7580 option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin
7581
7582 return bc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007583}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007584#endif
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +01007585
7586#endif // not DC_SMALL