blob: ea200ebda922884acc1235a9651066ac7fb17fa8 [file] [log] [blame]
Gavin Howard01055ba2018-11-03 11:00:21 -06001/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
5 *
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
8 */
9//config:config BC
10//config: bool "bc (45 kb; 49 kb when combined with dc)"
11//config: default y
12//config: help
13//config: bc is a command-line, arbitrary-precision calculator with a
14//config: Turing-complete language. See the GNU bc manual
15//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17//config: for details.
18//config:
19//config: This bc has four differences to the GNU bc:
20//config:
21//config: 1) The period (.) can also be used as a shortcut for "last", as in
22//config: the BSD bc.
23//config: 2) Arrays are copied before being passed as arguments to
24//config: functions. This behavior is required by the bc spec.
25//config: 3) Arrays can be passed to the builtin "length" function to get
26//config: the number of elements currently in the array. The following
27//config: example prints "1":
28//config:
29//config: a[0] = 0
30//config: length(a[])
31//config:
32//config: 4) The precedence of the boolean "not" operator (!) is equal to
33//config: that of the unary minus (-), or negation, operator. This still
34//config: allows POSIX-compliant scripts to work while somewhat
35//config: preserving expected behavior (versus C) and making parsing
36//config: easier.
37//config:
38//config: Options:
39//config:
40//config: -i --interactive force interactive mode
41//config: -l --mathlib use predefined math routines:
42//config:
43//config: s(expr) = sine of expr in radians
44//config: c(expr) = cosine of expr in radians
45//config: a(expr) = arctangent of expr, returning
46//config: radians
47//config: l(expr) = natural log of expr
48//config: e(expr) = raises e to the power of expr
49//config: j(n, x) = Bessel function of integer order
50//config: n of x
51//config:
52//config: -q --quiet don't print version and copyright.
53//config: -s --standard error if any non-POSIX extensions are used.
54//config: -w --warn warn if any non-POSIX extensions are used.
55//config: -v --version print version and copyright and exit.
56//config:
57//config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
58//config: enabled.
59//config:
60//config:config DC
61//config: bool "dc (38 kb; 49 kb when combined with bc)"
62//config: default y
63//config: help
64//config: dc is a reverse-polish notation command-line calculator which
65//config: supports unlimited precision arithmetic. See the FreeBSD man page
66//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68//config: for details.
69//config:
70//config: This dc has a few differences from the two above:
71//config:
72//config: 1) When printing a byte stream (command "P"), this bc follows what
73//config: the FreeBSD dc does.
74//config: 2) This dc implements the GNU extensions for divmod ("~") and
75//config: modular exponentiation ("|").
76//config: 3) This dc implements all FreeBSD extensions, except for "J" and
77//config: "M".
78//config: 4) Like the FreeBSD dc, this dc supports extended registers.
79//config: However, they are implemented differently. When it encounters
80//config: whitespace where a register should be, it skips the whitespace.
81//config: If the character following is not a lowercase letter, an error
82//config: is issued. Otherwise, the register name is parsed by the
83//config: following regex:
84//config:
85//config: [a-z][a-z0-9_]*
86//config:
87//config: This generally means that register names will be surrounded by
88//config: whitespace.
89//config:
90//config: Examples:
91//config:
92//config: l idx s temp L index S temp2 < do_thing
93//config:
94//config: Also note that, like the FreeBSD dc, extended registers are not
95//config: allowed unless the "-x" option is given.
96//config:
97//config:config FEATURE_BC_SIGNALS
98//config: bool "Enable bc/dc signal handling"
99//config: default y
100//config: depends on BC || DC
101//config: help
102//config: Enable signal handling for bc and dc.
103//config:
104//config:config FEATURE_BC_LONG_OPTIONS
105//config: bool "Enable bc/dc long options"
106//config: default y
107//config: depends on BC || DC
108//config: help
109//config: Enable long options for bc and dc.
110
111//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
113
114//kbuild:lib-$(CONFIG_BC) += bc.o
115//kbuild:lib-$(CONFIG_DC) += bc.o
116
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100117//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600118//usage:#define bc_trivial_usage
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100119//usage: "[-sqli] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600120//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100121//usage:#define bc_full_usage "\n"
122//usage: "\nArbitrary precision calculator"
123//usage: "\n"
124//usage: "\n -i Interactive"
125//usage: "\n -l Load standard math library"
126//usage: "\n -s Be POSIX compatible"
127//usage: "\n -q Quiet"
128//usage: "\n -w Warn if extensions are used"
129///////: "\n -v Version"
Gavin Howard01055ba2018-11-03 11:00:21 -0600130//usage:
131//usage:#define bc_example_usage
132//usage: "3 + 4.129\n"
133//usage: "1903 - 2893\n"
134//usage: "-129 * 213.28935\n"
135//usage: "12 / -1932\n"
136//usage: "12 % 12\n"
137//usage: "34 ^ 189\n"
138//usage: "scale = 13\n"
139//usage: "ibase = 2\n"
140//usage: "obase = A\n"
141//usage:
142//usage:#define dc_trivial_usage
143//usage: "EXPRESSION..."
144//usage:
145//usage:#define dc_full_usage "\n\n"
146//usage: "Tiny RPN calculator. Operations:\n"
147//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148//usage: "modular exponentiation,\n"
149//usage: "p - print top of the stack (without popping),\n"
150//usage: "f - print entire stack,\n"
151//usage: "k - pop the value and set the precision.\n"
152//usage: "i - pop the value and set input radix.\n"
153//usage: "o - pop the value and set output radix.\n"
154//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
155//usage:
156//usage:#define dc_example_usage
157//usage: "$ dc 2 2 + p\n"
158//usage: "4\n"
159//usage: "$ dc 8 8 \\* 2 2 + / p\n"
160//usage: "16\n"
161//usage: "$ dc 0 1 and p\n"
162//usage: "0\n"
163//usage: "$ dc 0 1 or p\n"
164//usage: "1\n"
165//usage: "$ echo 72 9 div 8 mul p | dc\n"
166//usage: "64\n"
167
168#include "libbb.h"
169
170typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600174} BcStatus;
175
Gavin Howard01055ba2018-11-03 11:00:21 -0600176#define BC_VEC_INVALID_IDX ((size_t) -1)
177#define BC_VEC_START_CAP (1 << 5)
178
179typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600180
181typedef struct BcVec {
182 char *v;
183 size_t len;
184 size_t cap;
185 size_t size;
186 BcVecFree dtor;
187} BcVec;
188
189#define bc_vec_pop(v) (bc_vec_npop((v), 1))
190#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
191
Gavin Howard01055ba2018-11-03 11:00:21 -0600192typedef signed char BcDig;
193
194typedef struct BcNum {
195 BcDig *restrict num;
196 size_t rdx;
197 size_t len;
198 size_t cap;
199 bool neg;
200} BcNum;
201
202#define BC_NUM_MIN_BASE ((unsigned long) 2)
203#define BC_NUM_MAX_IBASE ((unsigned long) 16)
204#define BC_NUM_DEF_SIZE (16)
205#define BC_NUM_PRINT_WIDTH (69)
206
207#define BC_NUM_KARATSUBA_LEN (32)
208
209#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
210#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
211#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
212#define BC_NUM_AREQ(a, b) \
213 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
214#define BC_NUM_MREQ(a, b, scale) \
215 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
216
217typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
218typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
219
220static void bc_num_init(BcNum *n, size_t req);
221static void bc_num_expand(BcNum *n, size_t req);
222static void bc_num_copy(BcNum *d, BcNum *s);
223static void bc_num_free(void *num);
224
225static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100226static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600227
228static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
229static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
230static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
235static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
236 size_t scale);
237
238typedef enum BcInst {
239
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100240#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600241 BC_INST_INC_PRE,
242 BC_INST_DEC_PRE,
243 BC_INST_INC_POST,
244 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100245#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600246
247 BC_INST_NEG,
248
249 BC_INST_POWER,
250 BC_INST_MULTIPLY,
251 BC_INST_DIVIDE,
252 BC_INST_MODULUS,
253 BC_INST_PLUS,
254 BC_INST_MINUS,
255
256 BC_INST_REL_EQ,
257 BC_INST_REL_LE,
258 BC_INST_REL_GE,
259 BC_INST_REL_NE,
260 BC_INST_REL_LT,
261 BC_INST_REL_GT,
262
263 BC_INST_BOOL_NOT,
264 BC_INST_BOOL_OR,
265 BC_INST_BOOL_AND,
266
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100267#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600268 BC_INST_ASSIGN_POWER,
269 BC_INST_ASSIGN_MULTIPLY,
270 BC_INST_ASSIGN_DIVIDE,
271 BC_INST_ASSIGN_MODULUS,
272 BC_INST_ASSIGN_PLUS,
273 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100274#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600275 BC_INST_ASSIGN,
276
277 BC_INST_NUM,
278 BC_INST_VAR,
279 BC_INST_ARRAY_ELEM,
280 BC_INST_ARRAY,
281
282 BC_INST_SCALE_FUNC,
283 BC_INST_IBASE,
284 BC_INST_SCALE,
285 BC_INST_LAST,
286 BC_INST_LENGTH,
287 BC_INST_READ,
288 BC_INST_OBASE,
289 BC_INST_SQRT,
290
291 BC_INST_PRINT,
292 BC_INST_PRINT_POP,
293 BC_INST_STR,
294 BC_INST_PRINT_STR,
295
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100296#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600297 BC_INST_JUMP,
298 BC_INST_JUMP_ZERO,
299
300 BC_INST_CALL,
301
302 BC_INST_RET,
303 BC_INST_RET0,
304
305 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100306#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600307
308 BC_INST_POP,
309 BC_INST_POP_EXEC,
310
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100311#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600312 BC_INST_MODEXP,
313 BC_INST_DIVMOD,
314
315 BC_INST_EXECUTE,
316 BC_INST_EXEC_COND,
317
318 BC_INST_ASCIIFY,
319 BC_INST_PRINT_STREAM,
320
321 BC_INST_PRINT_STACK,
322 BC_INST_CLEAR_STACK,
323 BC_INST_STACK_LEN,
324 BC_INST_DUPLICATE,
325 BC_INST_SWAP,
326
327 BC_INST_LOAD,
328 BC_INST_PUSH_VAR,
329 BC_INST_PUSH_TO_VAR,
330
331 BC_INST_QUIT,
332 BC_INST_NQUIT,
333
334 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100335#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600336
337} BcInst;
338
339typedef struct BcId {
340 char *name;
341 size_t idx;
342} BcId;
343
344typedef struct BcFunc {
345 BcVec code;
346 BcVec labels;
347 size_t nparams;
348 BcVec autos;
349} BcFunc;
350
351typedef enum BcResultType {
352
353 BC_RESULT_TEMP,
354
355 BC_RESULT_VAR,
356 BC_RESULT_ARRAY_ELEM,
357 BC_RESULT_ARRAY,
358
359 BC_RESULT_STR,
360
361 BC_RESULT_IBASE,
362 BC_RESULT_SCALE,
363 BC_RESULT_LAST,
364
365 // These are between to calculate ibase, obase, and last from instructions.
366 BC_RESULT_CONSTANT,
367 BC_RESULT_ONE,
368
369 BC_RESULT_OBASE,
370
371} BcResultType;
372
373typedef union BcResultData {
374 BcNum n;
375 BcVec v;
376 BcId id;
377} BcResultData;
378
379typedef struct BcResult {
380 BcResultType t;
381 BcResultData d;
382} BcResult;
383
384typedef struct BcInstPtr {
385 size_t func;
386 size_t idx;
387 size_t len;
388} BcInstPtr;
389
390static void bc_array_expand(BcVec *a, size_t len);
391static int bc_id_cmp(const void *e1, const void *e2);
392
393// BC_LEX_NEG is not used in lexing; it is only for parsing.
394typedef enum BcLexType {
395
396 BC_LEX_EOF,
397 BC_LEX_INVALID,
398
399 BC_LEX_OP_INC,
400 BC_LEX_OP_DEC,
401
402 BC_LEX_NEG,
403
404 BC_LEX_OP_POWER,
405 BC_LEX_OP_MULTIPLY,
406 BC_LEX_OP_DIVIDE,
407 BC_LEX_OP_MODULUS,
408 BC_LEX_OP_PLUS,
409 BC_LEX_OP_MINUS,
410
411 BC_LEX_OP_REL_EQ,
412 BC_LEX_OP_REL_LE,
413 BC_LEX_OP_REL_GE,
414 BC_LEX_OP_REL_NE,
415 BC_LEX_OP_REL_LT,
416 BC_LEX_OP_REL_GT,
417
418 BC_LEX_OP_BOOL_NOT,
419 BC_LEX_OP_BOOL_OR,
420 BC_LEX_OP_BOOL_AND,
421
422 BC_LEX_OP_ASSIGN_POWER,
423 BC_LEX_OP_ASSIGN_MULTIPLY,
424 BC_LEX_OP_ASSIGN_DIVIDE,
425 BC_LEX_OP_ASSIGN_MODULUS,
426 BC_LEX_OP_ASSIGN_PLUS,
427 BC_LEX_OP_ASSIGN_MINUS,
428 BC_LEX_OP_ASSIGN,
429
430 BC_LEX_NLINE,
431 BC_LEX_WHITESPACE,
432
433 BC_LEX_LPAREN,
434 BC_LEX_RPAREN,
435
436 BC_LEX_LBRACKET,
437 BC_LEX_COMMA,
438 BC_LEX_RBRACKET,
439
440 BC_LEX_LBRACE,
441 BC_LEX_SCOLON,
442 BC_LEX_RBRACE,
443
444 BC_LEX_STR,
445 BC_LEX_NAME,
446 BC_LEX_NUMBER,
447
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100448 BC_LEX_KEY_1st_keyword,
449 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600450 BC_LEX_KEY_BREAK,
451 BC_LEX_KEY_CONTINUE,
452 BC_LEX_KEY_DEFINE,
453 BC_LEX_KEY_ELSE,
454 BC_LEX_KEY_FOR,
455 BC_LEX_KEY_HALT,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100456 // code uses "type - BC_LEX_KEY_IBASE + BC_INST_IBASE" construct,
457 BC_LEX_KEY_IBASE, // relative order should match for: BC_INST_IBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600458 BC_LEX_KEY_IF,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100459 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600460 BC_LEX_KEY_LENGTH,
461 BC_LEX_KEY_LIMITS,
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100462 BC_LEX_KEY_OBASE, // relative order should match for: BC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600463 BC_LEX_KEY_PRINT,
464 BC_LEX_KEY_QUIT,
465 BC_LEX_KEY_READ,
466 BC_LEX_KEY_RETURN,
467 BC_LEX_KEY_SCALE,
468 BC_LEX_KEY_SQRT,
469 BC_LEX_KEY_WHILE,
470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100471#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_EQ_NO_REG,
473 BC_LEX_OP_MODEXP,
474 BC_LEX_OP_DIVMOD,
475
476 BC_LEX_COLON,
477 BC_LEX_ELSE,
478 BC_LEX_EXECUTE,
479 BC_LEX_PRINT_STACK,
480 BC_LEX_CLEAR_STACK,
481 BC_LEX_STACK_LEVEL,
482 BC_LEX_DUPLICATE,
483 BC_LEX_SWAP,
484 BC_LEX_POP,
485
486 BC_LEX_ASCIIFY,
487 BC_LEX_PRINT_STREAM,
488
489 BC_LEX_STORE_IBASE,
490 BC_LEX_STORE_SCALE,
491 BC_LEX_LOAD,
492 BC_LEX_LOAD_POP,
493 BC_LEX_STORE_PUSH,
494 BC_LEX_STORE_OBASE,
495 BC_LEX_PRINT_POP,
496 BC_LEX_NQUIT,
497 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100498#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600499} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100500// must match order of BC_LEX_KEY_foo etc above
501#if ENABLE_BC
502struct BcLexKeyword {
503 char name8[8];
504};
505#define BC_LEX_KW_ENTRY(a, b, c) \
506 { .name8 = a /*, .len = b, .posix = c*/ }
507static const struct BcLexKeyword bc_lex_kws[20] = {
508 BC_LEX_KW_ENTRY("auto" , 4, 1), // 0
509 BC_LEX_KW_ENTRY("break" , 5, 1), // 1
510 BC_LEX_KW_ENTRY("continue", 8, 0), // 2 note: this one has no terminating NUL
511 BC_LEX_KW_ENTRY("define" , 6, 1), // 3
512
513 BC_LEX_KW_ENTRY("else" , 4, 0), // 4
514 BC_LEX_KW_ENTRY("for" , 3, 1), // 5
515 BC_LEX_KW_ENTRY("halt" , 4, 0), // 6
516 BC_LEX_KW_ENTRY("ibase" , 5, 1), // 7
517
518 BC_LEX_KW_ENTRY("if" , 2, 1), // 8
519 BC_LEX_KW_ENTRY("last" , 4, 0), // 9
520 BC_LEX_KW_ENTRY("length" , 6, 1), // 10
521 BC_LEX_KW_ENTRY("limits" , 6, 0), // 11
522
523 BC_LEX_KW_ENTRY("obase" , 5, 1), // 12
524 BC_LEX_KW_ENTRY("print" , 5, 0), // 13
525 BC_LEX_KW_ENTRY("quit" , 4, 1), // 14
526 BC_LEX_KW_ENTRY("read" , 4, 0), // 15
527
528 BC_LEX_KW_ENTRY("return" , 6, 1), // 16
529 BC_LEX_KW_ENTRY("scale" , 5, 1), // 17
530 BC_LEX_KW_ENTRY("sqrt" , 4, 1), // 18
531 BC_LEX_KW_ENTRY("while" , 5, 1), // 19
532};
533enum {
534 POSIX_KWORD_MASK = 0
535 | (1 << 0)
536 | (1 << 1)
537 | (0 << 2)
538 | (1 << 3)
539 \
540 | (0 << 4)
541 | (1 << 5)
542 | (0 << 6)
543 | (1 << 7)
544 \
545 | (1 << 8)
546 | (0 << 9)
547 | (1 << 10)
548 | (0 << 11)
549 \
550 | (1 << 12)
551 | (0 << 13)
552 | (1 << 14)
553 | (0 << 15)
554 \
555 | (1 << 16)
556 | (1 << 17)
557 | (1 << 18)
558 | (1 << 19)
559};
560#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600561
562struct BcLex;
563typedef BcStatus (*BcLexNext)(struct BcLex *);
564
565typedef struct BcLex {
566
567 const char *buf;
568 size_t i;
569 size_t line;
Gavin Howard01055ba2018-11-03 11:00:21 -0600570 size_t len;
571 bool newline;
572
573 struct {
574 BcLexType t;
575 BcLexType last;
576 BcVec v;
577 } t;
578
579 BcLexNext next;
580
581} BcLex;
582
583#define BC_PARSE_STREND ((char) UCHAR_MAX)
584
585#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
586#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100587 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600588
589#define BC_PARSE_REL (1 << 0)
590#define BC_PARSE_PRINT (1 << 1)
591#define BC_PARSE_NOCALL (1 << 2)
592#define BC_PARSE_NOREAD (1 << 3)
593#define BC_PARSE_ARRAY (1 << 4)
594
595#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
596#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
597
598#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
599#define BC_PARSE_FUNC_INNER(parse) \
600 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
601
602#define BC_PARSE_FLAG_FUNC (1 << 1)
603#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
604
605#define BC_PARSE_FLAG_BODY (1 << 2)
606#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
607
608#define BC_PARSE_FLAG_LOOP (1 << 3)
609#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
610
611#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
612#define BC_PARSE_LOOP_INNER(parse) \
613 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
614
615#define BC_PARSE_FLAG_IF (1 << 5)
616#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
617
618#define BC_PARSE_FLAG_ELSE (1 << 6)
619#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
620
621#define BC_PARSE_FLAG_IF_END (1 << 7)
622#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
623
624#define BC_PARSE_CAN_EXEC(parse) \
625 (!(BC_PARSE_TOP_FLAG(parse) & \
626 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
627 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
628 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
629
630typedef struct BcOp {
631 char prec;
632 bool left;
633} BcOp;
634
635typedef struct BcParseNext {
636 uint32_t len;
637 BcLexType tokens[4];
638} BcParseNext;
639
640#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
641#define BC_PARSE_NEXT(a, ...) \
642 { \
643 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
644 }
645
646struct BcParse;
647
648struct BcProgram;
649
Gavin Howard01055ba2018-11-03 11:00:21 -0600650typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600651
652typedef struct BcParse {
653
654 BcParseParse parse;
655
656 BcLex l;
657
658 BcVec flags;
659
660 BcVec exits;
661 BcVec conds;
662
663 BcVec ops;
664
Gavin Howard01055ba2018-11-03 11:00:21 -0600665 BcFunc *func;
666 size_t fidx;
667
668 size_t nbraces;
669 bool auto_part;
670
671} BcParse;
672
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100673#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600674
Gavin Howard01055ba2018-11-03 11:00:21 -0600675static BcStatus bc_lex_token(BcLex *l);
676
677#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
678#define BC_PARSE_LEAF(p, rparen) \
679 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
680 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
681
682// We can calculate the conversion between tokens and exprs by subtracting the
683// position of the first operator in the lex enum and adding the position of the
684// first in the expr enum. Note: This only works for binary operators.
685#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
686
Gavin Howard01055ba2018-11-03 11:00:21 -0600687static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
688
Denys Vlasenko00d77792018-11-30 23:13:42 +0100689#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600690
Denys Vlasenko00d77792018-11-30 23:13:42 +0100691#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600692
693#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
694
Gavin Howard01055ba2018-11-03 11:00:21 -0600695static BcStatus dc_lex_token(BcLex *l);
696
Gavin Howard01055ba2018-11-03 11:00:21 -0600697static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
698
699#endif // ENABLE_DC
700
701typedef struct BcProgram {
702
703 size_t len;
704 size_t scale;
705
706 BcNum ib;
707 size_t ib_t;
708 BcNum ob;
709 size_t ob_t;
710
711 BcNum hexb;
712
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100713#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600714 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100715#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600716
717 BcVec results;
718 BcVec stack;
719
720 BcVec fns;
721 BcVec fn_map;
722
723 BcVec vars;
724 BcVec var_map;
725
726 BcVec arrs;
727 BcVec arr_map;
728
729 BcVec strs;
730 BcVec consts;
731
732 const char *file;
733
734 BcNum last;
735 BcNum zero;
736 BcNum one;
737
738 size_t nchars;
739
Gavin Howard01055ba2018-11-03 11:00:21 -0600740} BcProgram;
741
742#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
743
744#define BC_PROG_MAIN (0)
745#define BC_PROG_READ (1)
746
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100747#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600748#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100749#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600750
751#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
752#define BC_PROG_NUM(r, n) \
753 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
754
755typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
756
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100757static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100758static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600759
760#define BC_FLAG_X (1 << 0)
761#define BC_FLAG_W (1 << 1)
762#define BC_FLAG_V (1 << 2)
763#define BC_FLAG_S (1 << 3)
764#define BC_FLAG_Q (1 << 4)
765#define BC_FLAG_L (1 << 5)
766#define BC_FLAG_I (1 << 6)
767
768#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
769#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
770
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100771#define BC_MAX_OBASE ((unsigned) 999)
772#define BC_MAX_DIM ((unsigned) INT_MAX)
773#define BC_MAX_SCALE ((unsigned) UINT_MAX)
774#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
775#define BC_MAX_NAME BC_MAX_STRING
776#define BC_MAX_NUM BC_MAX_STRING
777#define BC_MAX_EXP ((unsigned long) LONG_MAX)
778#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600779
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100780struct globals {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100781 smallint ttyin;
782 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600783 char sbgn;
784 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600785
786 BcParse prs;
787 BcProgram prog;
788
Denys Vlasenko5318f812018-12-05 17:48:01 +0100789 // For error messages. Can be set to current parsed line,
790 // or [TODO] to current executing line (can be before last parsed one)
791 unsigned err_line;
792
Gavin Howard01055ba2018-11-03 11:00:21 -0600793 BcVec files;
794
795 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100796} FIX_ALIASING;
797#define G (*ptr_to_globals)
798#define INIT_G() do { \
799 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
800} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100801#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
802#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
803#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100804#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600805
Gavin Howard01055ba2018-11-03 11:00:21 -0600806
Denys Vlasenko00d77792018-11-30 23:13:42 +0100807#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
808
Denys Vlasenko00d77792018-11-30 23:13:42 +0100809static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600810
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100811#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600812
813// This is an array that corresponds to token types. An entry is
814// true if the token is valid in an expression, false otherwise.
815static const bool bc_parse_exprs[] = {
816 false, false, true, true, true, true, true, true, true, true, true, true,
817 true, true, true, true, true, true, true, true, true, true, true, true,
818 true, true, true, false, false, true, true, false, false, false, false,
819 false, false, false, true, true, false, false, false, false, false, false,
820 false, true, false, true, true, true, true, false, false, true, false, true,
821 true, false,
822};
823
824// This is an array of data for operators that correspond to token types.
825static const BcOp bc_parse_ops[] = {
826 { 0, false }, { 0, false },
827 { 1, false },
828 { 2, false },
829 { 3, true }, { 3, true }, { 3, true },
830 { 4, true }, { 4, true },
831 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
832 { 1, false },
833 { 7, true }, { 7, true },
834 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
835 { 5, false }, { 5, false },
836};
837
838// These identify what tokens can come after expressions in certain cases.
839static const BcParseNext bc_parse_next_expr =
840 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
841static const BcParseNext bc_parse_next_param =
842 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
843static const BcParseNext bc_parse_next_print =
844 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
845static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
846static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
847static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
848static const BcParseNext bc_parse_next_read =
849 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
850#endif // ENABLE_BC
851
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100852#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600853static const BcLexType dc_lex_regs[] = {
854 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
855 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
856 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
857 BC_LEX_STORE_PUSH,
858};
859
Gavin Howard01055ba2018-11-03 11:00:21 -0600860static const BcLexType dc_lex_tokens[] = {
861 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
862 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
863 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
864 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
865 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
866 BC_LEX_INVALID, BC_LEX_INVALID,
867 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
868 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
869 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
870 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
871 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
872 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
873 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
874 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
875 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
876 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
877 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
878 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
879 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
880 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
881 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
882 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
883 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
884 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
885 BC_LEX_INVALID
886};
887
888static const BcInst dc_parse_insts[] = {
889 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
890 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
891 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
892 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
893 BC_INST_INVALID, BC_INST_INVALID,
894 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
895 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
896 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
897 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
898 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
899 BC_INST_INVALID, BC_INST_INVALID,
900 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
901 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
902 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
903 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
904 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
905 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
906 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
907 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
908 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
909 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
910 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
911 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
912};
913#endif // ENABLE_DC
914
Gavin Howard01055ba2018-11-03 11:00:21 -0600915static const BcNumBinaryOp bc_program_ops[] = {
916 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
917};
918
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100919static void fflush_and_check(void)
920{
921 fflush_all();
922 if (ferror(stdout) || ferror(stderr))
923 bb_perror_msg_and_die("output error");
924}
925
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100926static void quit(void) NORETURN;
927static void quit(void)
928{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100929 if (ferror(stdin))
930 bb_perror_msg_and_die("input error");
931 fflush_and_check();
932 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100933}
934
Denys Vlasenko5318f812018-12-05 17:48:01 +0100935static void bc_verror_msg(const char *fmt, va_list p)
936{
937 const char *sv = sv; /* for compiler */
938 if (G.prog.file) {
939 sv = applet_name;
940 applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
941 }
942 bb_verror_msg(fmt, p, NULL);
943 if (G.prog.file) {
944 free((char*)applet_name);
945 applet_name = sv;
946 }
947}
948
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100949static NOINLINE int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100950{
951 va_list p;
952
953 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100954 bc_verror_msg(fmt, p);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100955 va_end(p);
Denys Vlasenko0409ad32018-12-05 16:39:22 +0100956
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100957 if (!G.ttyin)
958 exit(1);
959 return BC_STATUS_FAILURE;
960}
961
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100962static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100963{
964 va_list p;
965
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100966 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100967 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100968 return BC_STATUS_SUCCESS; // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100969
970 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100971 bc_verror_msg(fmt, p);
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100972 va_end(p);
973
974 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100975 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100976 return BC_STATUS_SUCCESS; // no, it's a warning
977 if (!G.ttyin)
978 exit(1);
979 return BC_STATUS_FAILURE;
980}
981
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100982// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
983// This idiom begs for tail-call optimization, but for it to work,
984// function must not have calller-cleaned parameters on stack.
985// Unfortunately, vararg functions do exactly that on most arches.
986// Thus, these shims for the cases when we have no PARAMS:
987static int bc_error(const char *msg)
988{
989 return bc_error_fmt("%s", msg);
990}
991static int bc_posix_error(const char *msg)
992{
993 return bc_posix_error_fmt("%s", msg);
994}
Denys Vlasenko00646792018-12-05 18:12:27 +0100995static int bc_POSIX_does_not_allow(const char *msg)
996{
997 return bc_posix_error_fmt("%s%s", "POSIX does not allow ", msg);
998}
999static int bc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
1000{
1001 return bc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; the following is bad:", msg);
1002}
1003static int bc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
1004{
1005 return bc_posix_error_fmt("%san empty %s expression in a for loop", "POSIX does not allow ", msg);
1006}
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001007static int bc_error_bad_character(char c)
1008{
1009 return bc_error_fmt("bad character '%c'", c);
1010}
1011static int bc_error_bad_expression(void)
1012{
1013 return bc_error("bad expression");
1014}
1015static int bc_error_bad_token(void)
1016{
1017 return bc_error("bad token");
1018}
1019static int bc_error_stack_has_too_few_elements(void)
1020{
1021 return bc_error("stack has too few elements");
1022}
1023static int bc_error_variable_is_wrong_type(void)
1024{
1025 return bc_error("variable is wrong type");
1026}
1027static int bc_error_nested_read_call(void)
1028{
1029 return bc_error("read() call inside of a read() call");
1030}
1031
Gavin Howard01055ba2018-11-03 11:00:21 -06001032static void bc_vec_grow(BcVec *v, size_t n)
1033{
1034 size_t cap = v->cap * 2;
1035 while (cap < v->len + n) cap *= 2;
1036 v->v = xrealloc(v->v, v->size * cap);
1037 v->cap = cap;
1038}
1039
1040static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1041{
1042 v->size = esize;
1043 v->cap = BC_VEC_START_CAP;
1044 v->len = 0;
1045 v->dtor = dtor;
1046 v->v = xmalloc(esize * BC_VEC_START_CAP);
1047}
1048
Denys Vlasenko7d628012018-12-04 21:46:47 +01001049static void bc_char_vec_init(BcVec *v)
1050{
1051 bc_vec_init(v, sizeof(char), NULL);
1052}
1053
Gavin Howard01055ba2018-11-03 11:00:21 -06001054static void bc_vec_expand(BcVec *v, size_t req)
1055{
1056 if (v->cap < req) {
1057 v->v = xrealloc(v->v, v->size * req);
1058 v->cap = req;
1059 }
1060}
1061
1062static void bc_vec_npop(BcVec *v, size_t n)
1063{
1064 if (!v->dtor)
1065 v->len -= n;
1066 else {
1067 size_t len = v->len - n;
1068 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1069 }
1070}
1071
Denys Vlasenko7d628012018-12-04 21:46:47 +01001072static void bc_vec_pop_all(BcVec *v)
1073{
1074 bc_vec_npop(v, v->len);
1075}
1076
Gavin Howard01055ba2018-11-03 11:00:21 -06001077static void bc_vec_push(BcVec *v, const void *data)
1078{
1079 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1080 memmove(v->v + (v->size * v->len), data, v->size);
1081 v->len += 1;
1082}
1083
1084static void bc_vec_pushByte(BcVec *v, char data)
1085{
1086 bc_vec_push(v, &data);
1087}
1088
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001089static void bc_vec_pushZeroByte(BcVec *v)
1090{
1091 //bc_vec_pushByte(v, '\0');
1092 // better:
1093 bc_vec_push(v, &const_int_0);
1094}
1095
Gavin Howard01055ba2018-11-03 11:00:21 -06001096static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1097{
1098 if (idx == v->len)
1099 bc_vec_push(v, data);
1100 else {
1101
1102 char *ptr;
1103
1104 if (v->len == v->cap) bc_vec_grow(v, 1);
1105
1106 ptr = v->v + v->size * idx;
1107
1108 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1109 memmove(ptr, data, v->size);
1110 }
1111}
1112
1113static void bc_vec_string(BcVec *v, size_t len, const char *str)
1114{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001115 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001116 bc_vec_expand(v, len + 1);
1117 memcpy(v->v, str, len);
1118 v->len = len;
1119
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001120 bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001121}
1122
1123static void bc_vec_concat(BcVec *v, const char *str)
1124{
1125 size_t len;
1126
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001127 if (v->len == 0) bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001128
1129 len = v->len + strlen(str);
1130
1131 if (v->cap < len) bc_vec_grow(v, len - v->len);
1132 strcat(v->v, str);
1133
1134 v->len = len;
1135}
1136
1137static void *bc_vec_item(const BcVec *v, size_t idx)
1138{
1139 return v->v + v->size * idx;
1140}
1141
1142static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1143{
1144 return v->v + v->size * (v->len - idx - 1);
1145}
1146
1147static void bc_vec_free(void *vec)
1148{
1149 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001150 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001151 free(v->v);
1152}
1153
1154static size_t bc_map_find(const BcVec *v, const void *ptr)
1155{
1156 size_t low = 0, high = v->len;
1157
1158 while (low < high) {
1159
1160 size_t mid = (low + high) / 2;
1161 BcId *id = bc_vec_item(v, mid);
1162 int result = bc_id_cmp(ptr, id);
1163
1164 if (result == 0)
1165 return mid;
1166 else if (result < 0)
1167 high = mid;
1168 else
1169 low = mid + 1;
1170 }
1171
1172 return low;
1173}
1174
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001175static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001176{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001177 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001178
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001179 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001180 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001181 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1182 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001183 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001184 bc_vec_pushAt(v, ptr, n);
1185 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001186}
1187
1188static size_t bc_map_index(const BcVec *v, const void *ptr)
1189{
1190 size_t i = bc_map_find(v, ptr);
1191 if (i >= v->len) return BC_VEC_INVALID_IDX;
1192 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1193}
1194
1195static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1196{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001197 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001198
Denys Vlasenko00d77792018-11-30 23:13:42 +01001199 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001200 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001201
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001202 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001203 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001204
1205 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001206#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001207 if (bb_got_signal) { // ^C was pressed
1208 intr:
1209 bb_got_signal = 0; // resets G_interrupt to zero
1210 fputs(IS_BC
1211 ? "\ninterrupt (type \"quit\" to exit)\n"
1212 : "\ninterrupt (type \"q\" to exit)\n"
1213 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001214 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001215#endif
1216 if (G.ttyin && !G_posix)
1217 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001218
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001219#if ENABLE_FEATURE_BC_SIGNALS
1220 errno = 0;
1221#endif
1222 do {
1223 i = fgetc(stdin);
1224 if (i == EOF) {
1225#if ENABLE_FEATURE_BC_SIGNALS
1226 // Both conditions appear simultaneously, check both just in case
1227 if (errno == EINTR || bb_got_signal) {
1228 // ^C was pressed
1229 clearerr(stdin);
1230 goto intr;
1231 }
1232#endif
1233 if (ferror(stdin))
1234 quit(); // this emits error message
1235 G.eof = 1;
1236 // Note: EOF does not append '\n', therefore:
1237 // printf 'print 123\n' | bc - works
1238 // printf 'print 123' | bc - fails (syntax error)
1239 break;
1240 }
1241
1242 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1243 || i > 0x7e
1244 ) {
1245 // Bad chars on this line, ignore entire line
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001246 bc_error_fmt("illegal character 0x%02x", i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001247 bad_chars = 1;
1248 }
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001249 bc_vec_pushByte(vec, (char)i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001250 } while (i != '\n');
1251 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001252
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001253 bc_vec_pushZeroByte(vec);
Gavin Howard01055ba2018-11-03 11:00:21 -06001254
1255 return BC_STATUS_SUCCESS;
1256}
1257
Denys Vlasenkodf515392018-12-02 19:27:48 +01001258static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001259{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001260 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001261 size_t size = ((size_t) -1);
1262 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001263
Denys Vlasenkodf515392018-12-02 19:27:48 +01001264 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001265
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001266 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001267 char c = buf[i];
1268 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1269 || c > 0x7e
1270 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001271 free(buf);
1272 buf = NULL;
1273 break;
1274 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001275 }
1276
Denys Vlasenkodf515392018-12-02 19:27:48 +01001277 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001278}
1279
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001280static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001281{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001282 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001283 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001284
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001285 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001286#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001287 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001288 "extended-register\0" No_argument "x"
1289 "warn\0" No_argument "w"
1290 "version\0" No_argument "v"
1291 "standard\0" No_argument "s"
1292 "quiet\0" No_argument "q"
1293 "mathlib\0" No_argument "l"
1294 "interactive\0" No_argument "i"
1295 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001296#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001297 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001298#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001299 if (getenv("POSIXLY_CORRECT"))
1300 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001301
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001302 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001303 // should not be necessary, getopt32() handles this??
1304 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001305
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001306 for (i = optind; i < argc; ++i)
1307 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001308}
1309
1310static void bc_num_setToZero(BcNum *n, size_t scale)
1311{
1312 n->len = 0;
1313 n->neg = false;
1314 n->rdx = scale;
1315}
1316
1317static void bc_num_zero(BcNum *n)
1318{
1319 bc_num_setToZero(n, 0);
1320}
1321
1322static void bc_num_one(BcNum *n)
1323{
1324 bc_num_setToZero(n, 0);
1325 n->len = 1;
1326 n->num[0] = 1;
1327}
1328
1329static void bc_num_ten(BcNum *n)
1330{
1331 bc_num_setToZero(n, 0);
1332 n->len = 2;
1333 n->num[0] = 0;
1334 n->num[1] = 1;
1335}
1336
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001337static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001338 size_t len)
1339{
1340 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001341 for (i = 0; i < len; ++i) {
1342 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001343 a[i + j++] += 10;
1344 a[i + j] -= 1;
1345 }
1346 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001347}
1348
1349static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1350{
1351 size_t i;
1352 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001353 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001354 return BC_NUM_NEG(i + 1, c < 0);
1355}
1356
1357static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1358{
1359 size_t i, min, a_int, b_int, diff;
1360 BcDig *max_num, *min_num;
1361 bool a_max, neg = false;
1362 ssize_t cmp;
1363
1364 if (a == b) return 0;
1365 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1366 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1367 if (a->neg) {
1368 if (b->neg)
1369 neg = true;
1370 else
1371 return -1;
1372 }
1373 else if (b->neg)
1374 return 1;
1375
1376 a_int = BC_NUM_INT(a);
1377 b_int = BC_NUM_INT(b);
1378 a_int -= b_int;
1379 a_max = (a->rdx > b->rdx);
1380
1381 if (a_int != 0) return (ssize_t) a_int;
1382
1383 if (a_max) {
1384 min = b->rdx;
1385 diff = a->rdx - b->rdx;
1386 max_num = a->num + diff;
1387 min_num = b->num;
1388 }
1389 else {
1390 min = a->rdx;
1391 diff = b->rdx - a->rdx;
1392 max_num = b->num + diff;
1393 min_num = a->num;
1394 }
1395
1396 cmp = bc_num_compare(max_num, min_num, b_int + min);
1397 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1398
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001399 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001400 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1401 }
1402
1403 return 0;
1404}
1405
1406static void bc_num_truncate(BcNum *n, size_t places)
1407{
1408 if (places == 0) return;
1409
1410 n->rdx -= places;
1411
1412 if (n->len != 0) {
1413 n->len -= places;
1414 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1415 }
1416}
1417
1418static void bc_num_extend(BcNum *n, size_t places)
1419{
1420 size_t len = n->len + places;
1421
1422 if (places != 0) {
1423
1424 if (n->cap < len) bc_num_expand(n, len);
1425
1426 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1427 memset(n->num, 0, sizeof(BcDig) * places);
1428
1429 n->len += places;
1430 n->rdx += places;
1431 }
1432}
1433
1434static void bc_num_clean(BcNum *n)
1435{
1436 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1437 if (n->len == 0)
1438 n->neg = false;
1439 else if (n->len < n->rdx)
1440 n->len = n->rdx;
1441}
1442
1443static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1444{
1445 if (n->rdx < scale)
1446 bc_num_extend(n, scale - n->rdx);
1447 else
1448 bc_num_truncate(n, n->rdx - scale);
1449
1450 bc_num_clean(n);
1451 if (n->len != 0) n->neg = !neg1 != !neg2;
1452}
1453
1454static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1455 BcNum *restrict b)
1456{
1457 if (idx < n->len) {
1458
1459 b->len = n->len - idx;
1460 a->len = idx;
1461 a->rdx = b->rdx = 0;
1462
1463 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1464 memcpy(a->num, n->num, idx * sizeof(BcDig));
1465 }
1466 else {
1467 bc_num_zero(b);
1468 bc_num_copy(a, n);
1469 }
1470
1471 bc_num_clean(a);
1472 bc_num_clean(b);
1473}
1474
1475static BcStatus bc_num_shift(BcNum *n, size_t places)
1476{
1477 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001478 if (places + n->len > BC_MAX_NUM)
1479 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001480
1481 if (n->rdx >= places)
1482 n->rdx -= places;
1483 else {
1484 bc_num_extend(n, places - n->rdx);
1485 n->rdx = 0;
1486 }
1487
1488 bc_num_clean(n);
1489
1490 return BC_STATUS_SUCCESS;
1491}
1492
1493static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1494{
1495 BcNum one;
1496 BcDig num[2];
1497
1498 one.cap = 2;
1499 one.num = num;
1500 bc_num_one(&one);
1501
1502 return bc_num_div(&one, a, b, scale);
1503}
1504
1505static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1506{
1507 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1508 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1509 int carry, in;
1510
1511 // Because this function doesn't need to use scale (per the bc spec),
1512 // I am hijacking it to say whether it's doing an add or a subtract.
1513
1514 if (a->len == 0) {
1515 bc_num_copy(c, b);
1516 if (sub && c->len) c->neg = !c->neg;
1517 return BC_STATUS_SUCCESS;
1518 }
1519 else if (b->len == 0) {
1520 bc_num_copy(c, a);
1521 return BC_STATUS_SUCCESS;
1522 }
1523
1524 c->neg = a->neg;
1525 c->rdx = BC_MAX(a->rdx, b->rdx);
1526 min_rdx = BC_MIN(a->rdx, b->rdx);
1527 c->len = 0;
1528
1529 if (a->rdx > b->rdx) {
1530 diff = a->rdx - b->rdx;
1531 ptr = a->num;
1532 ptr_a = a->num + diff;
1533 ptr_b = b->num;
1534 }
1535 else {
1536 diff = b->rdx - a->rdx;
1537 ptr = b->num;
1538 ptr_a = a->num;
1539 ptr_b = b->num + diff;
1540 }
1541
1542 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1543
1544 ptr_c += diff;
1545 a_int = BC_NUM_INT(a);
1546 b_int = BC_NUM_INT(b);
1547
1548 if (a_int > b_int) {
1549 min_int = b_int;
1550 max = a_int;
1551 ptr = ptr_a;
1552 }
1553 else {
1554 min_int = a_int;
1555 max = b_int;
1556 ptr = ptr_b;
1557 }
1558
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001559 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001560 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1561 carry = in / 10;
1562 ptr_c[i] = (BcDig)(in % 10);
1563 }
1564
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001565 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001566 in = ((int) ptr[i]) + carry;
1567 carry = in / 10;
1568 ptr_c[i] = (BcDig)(in % 10);
1569 }
1570
1571 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1572
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001573 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001574}
1575
1576static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1577{
Gavin Howard01055ba2018-11-03 11:00:21 -06001578 ssize_t cmp;
1579 BcNum *minuend, *subtrahend;
1580 size_t start;
1581 bool aneg, bneg, neg;
1582
1583 // Because this function doesn't need to use scale (per the bc spec),
1584 // I am hijacking it to say whether it's doing an add or a subtract.
1585
1586 if (a->len == 0) {
1587 bc_num_copy(c, b);
1588 if (sub && c->len) c->neg = !c->neg;
1589 return BC_STATUS_SUCCESS;
1590 }
1591 else if (b->len == 0) {
1592 bc_num_copy(c, a);
1593 return BC_STATUS_SUCCESS;
1594 }
1595
1596 aneg = a->neg;
1597 bneg = b->neg;
1598 a->neg = b->neg = false;
1599
1600 cmp = bc_num_cmp(a, b);
1601
1602 a->neg = aneg;
1603 b->neg = bneg;
1604
1605 if (cmp == 0) {
1606 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1607 return BC_STATUS_SUCCESS;
1608 }
1609 else if (cmp > 0) {
1610 neg = a->neg;
1611 minuend = a;
1612 subtrahend = b;
1613 }
1614 else {
1615 neg = b->neg;
1616 if (sub) neg = !neg;
1617 minuend = b;
1618 subtrahend = a;
1619 }
1620
1621 bc_num_copy(c, minuend);
1622 c->neg = neg;
1623
1624 if (c->rdx < subtrahend->rdx) {
1625 bc_num_extend(c, subtrahend->rdx - c->rdx);
1626 start = 0;
1627 }
1628 else
1629 start = c->rdx - subtrahend->rdx;
1630
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001631 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001632
1633 bc_num_clean(c);
1634
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001635 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001636}
1637
1638static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1639 BcNum *restrict c)
1640{
1641 BcStatus s;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001642 size_t max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
Gavin Howard01055ba2018-11-03 11:00:21 -06001643 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001644 bool aone;
Gavin Howard01055ba2018-11-03 11:00:21 -06001645
Gavin Howard01055ba2018-11-03 11:00:21 -06001646 if (a->len == 0 || b->len == 0) {
1647 bc_num_zero(c);
1648 return BC_STATUS_SUCCESS;
1649 }
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001650 aone = BC_NUM_ONE(a);
1651 if (aone || BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001652 bc_num_copy(c, aone ? b : a);
1653 return BC_STATUS_SUCCESS;
1654 }
1655
1656 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1657 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1658 {
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001659 size_t i, j, len;
1660 int carry;
1661
Gavin Howard01055ba2018-11-03 11:00:21 -06001662 bc_num_expand(c, a->len + b->len + 1);
1663
1664 memset(c->num, 0, sizeof(BcDig) * c->cap);
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001665 c->len = len = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06001666
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001667 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001668
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001669 carry = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001670 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001671 int in = (int) c->num[i + j];
1672 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1673 carry = in / 10;
1674 c->num[i + j] = (BcDig)(in % 10);
1675 }
1676
1677 c->num[i + j] += (BcDig) carry;
1678 len = BC_MAX(len, i + j + !!carry);
Gavin Howard01055ba2018-11-03 11:00:21 -06001679 }
1680
1681 c->len = len;
1682
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001683 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001684 }
1685
1686 bc_num_init(&l1, max);
1687 bc_num_init(&h1, max);
1688 bc_num_init(&l2, max);
1689 bc_num_init(&h2, max);
1690 bc_num_init(&m1, max);
1691 bc_num_init(&m2, max);
1692 bc_num_init(&z0, max);
1693 bc_num_init(&z1, max);
1694 bc_num_init(&z2, max);
1695 bc_num_init(&temp, max + max);
1696
1697 bc_num_split(a, max2, &l1, &h1);
1698 bc_num_split(b, max2, &l2, &h2);
1699
1700 s = bc_num_add(&h1, &l1, &m1, 0);
1701 if (s) goto err;
1702 s = bc_num_add(&h2, &l2, &m2, 0);
1703 if (s) goto err;
1704
1705 s = bc_num_k(&h1, &h2, &z0);
1706 if (s) goto err;
1707 s = bc_num_k(&m1, &m2, &z1);
1708 if (s) goto err;
1709 s = bc_num_k(&l1, &l2, &z2);
1710 if (s) goto err;
1711
1712 s = bc_num_sub(&z1, &z0, &temp, 0);
1713 if (s) goto err;
1714 s = bc_num_sub(&temp, &z2, &z1, 0);
1715 if (s) goto err;
1716
1717 s = bc_num_shift(&z0, max2 * 2);
1718 if (s) goto err;
1719 s = bc_num_shift(&z1, max2);
1720 if (s) goto err;
1721 s = bc_num_add(&z0, &z1, &temp, 0);
1722 if (s) goto err;
1723 s = bc_num_add(&temp, &z2, c, 0);
1724
1725err:
1726 bc_num_free(&temp);
1727 bc_num_free(&z2);
1728 bc_num_free(&z1);
1729 bc_num_free(&z0);
1730 bc_num_free(&m2);
1731 bc_num_free(&m1);
1732 bc_num_free(&h2);
1733 bc_num_free(&l2);
1734 bc_num_free(&h1);
1735 bc_num_free(&l1);
1736 return s;
1737}
1738
1739static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1740{
1741 BcStatus s;
1742 BcNum cpa, cpb;
1743 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1744
1745 scale = BC_MAX(scale, a->rdx);
1746 scale = BC_MAX(scale, b->rdx);
1747 scale = BC_MIN(a->rdx + b->rdx, scale);
1748 maxrdx = BC_MAX(maxrdx, scale);
1749
1750 bc_num_init(&cpa, a->len);
1751 bc_num_init(&cpb, b->len);
1752
1753 bc_num_copy(&cpa, a);
1754 bc_num_copy(&cpb, b);
1755 cpa.neg = cpb.neg = false;
1756
1757 s = bc_num_shift(&cpa, maxrdx);
1758 if (s) goto err;
1759 s = bc_num_shift(&cpb, maxrdx);
1760 if (s) goto err;
1761 s = bc_num_k(&cpa, &cpb, c);
1762 if (s) goto err;
1763
1764 maxrdx += scale;
1765 bc_num_expand(c, c->len + maxrdx);
1766
1767 if (c->len < maxrdx) {
1768 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1769 c->len += maxrdx;
1770 }
1771
1772 c->rdx = maxrdx;
1773 bc_num_retireMul(c, scale, a->neg, b->neg);
1774
1775err:
1776 bc_num_free(&cpb);
1777 bc_num_free(&cpa);
1778 return s;
1779}
1780
1781static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1782{
1783 BcStatus s = BC_STATUS_SUCCESS;
1784 BcDig *n, *p, q;
1785 size_t len, end, i;
1786 BcNum cp;
1787 bool zero = true;
1788
1789 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001790 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001791 else if (a->len == 0) {
1792 bc_num_setToZero(c, scale);
1793 return BC_STATUS_SUCCESS;
1794 }
1795 else if (BC_NUM_ONE(b)) {
1796 bc_num_copy(c, a);
1797 bc_num_retireMul(c, scale, a->neg, b->neg);
1798 return BC_STATUS_SUCCESS;
1799 }
1800
1801 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1802 bc_num_copy(&cp, a);
1803 len = b->len;
1804
1805 if (len > cp.len) {
1806 bc_num_expand(&cp, len + 2);
1807 bc_num_extend(&cp, len - cp.len);
1808 }
1809
1810 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1811 cp.rdx -= b->rdx;
1812 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1813
1814 if (b->rdx == b->len) {
1815 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1816 len -= i - 1;
1817 }
1818
1819 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1820
1821 // We want an extra zero in front to make things simpler.
1822 cp.num[cp.len++] = 0;
1823 end = cp.len - len;
1824
1825 bc_num_expand(c, cp.len);
1826
1827 bc_num_zero(c);
1828 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1829 c->rdx = cp.rdx;
1830 c->len = cp.len;
1831 p = b->num;
1832
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001833 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001834 n = cp.num + i;
1835 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001836 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001837 c->num[i] = q;
1838 }
1839
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001840 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001841 bc_num_free(&cp);
1842
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001843 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001844}
1845
1846static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1847 BcNum *restrict d, size_t scale, size_t ts)
1848{
1849 BcStatus s;
1850 BcNum temp;
1851 bool neg;
1852
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001853 if (b->len == 0)
1854 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001855
1856 if (a->len == 0) {
1857 bc_num_setToZero(d, ts);
1858 return BC_STATUS_SUCCESS;
1859 }
1860
1861 bc_num_init(&temp, d->cap);
1862 bc_num_d(a, b, c, scale);
1863
1864 if (scale != 0) scale = ts;
1865
1866 s = bc_num_m(c, b, &temp, scale);
1867 if (s) goto err;
1868 s = bc_num_sub(a, &temp, d, scale);
1869 if (s) goto err;
1870
1871 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1872
1873 neg = d->neg;
1874 bc_num_retireMul(d, ts, a->neg, b->neg);
1875 d->neg = neg;
1876
1877err:
1878 bc_num_free(&temp);
1879 return s;
1880}
1881
1882static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1883{
1884 BcStatus s;
1885 BcNum c1;
1886 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1887
1888 bc_num_init(&c1, len);
1889 s = bc_num_r(a, b, &c1, c, scale, ts);
1890 bc_num_free(&c1);
1891
1892 return s;
1893}
1894
1895static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1896{
1897 BcStatus s = BC_STATUS_SUCCESS;
1898 BcNum copy;
1899 unsigned long pow;
1900 size_t i, powrdx, resrdx;
1901 bool neg, zero;
1902
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001903 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001904
1905 if (b->len == 0) {
1906 bc_num_one(c);
1907 return BC_STATUS_SUCCESS;
1908 }
1909 else if (a->len == 0) {
1910 bc_num_setToZero(c, scale);
1911 return BC_STATUS_SUCCESS;
1912 }
1913 else if (BC_NUM_ONE(b)) {
1914 if (!b->neg)
1915 bc_num_copy(c, a);
1916 else
1917 s = bc_num_inv(a, c, scale);
1918 return s;
1919 }
1920
1921 neg = b->neg;
1922 b->neg = false;
1923
1924 s = bc_num_ulong(b, &pow);
1925 if (s) return s;
1926
1927 bc_num_init(&copy, a->len);
1928 bc_num_copy(&copy, a);
1929
1930 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1931
1932 b->neg = neg;
1933
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001934 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001935 powrdx <<= 1;
1936 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1937 if (s) goto err;
Denys Vlasenkof359e002018-12-05 01:21:59 +01001938 // It is too slow to handle ^C only after entire "2^1000000" completes
1939 if (G_interrupt) {
1940 s = BC_STATUS_FAILURE;
1941 goto err;
1942 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001943 }
1944
Gavin Howard01055ba2018-11-03 11:00:21 -06001945 bc_num_copy(c, &copy);
1946
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001947 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001948
1949 powrdx <<= 1;
1950 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1951 if (s) goto err;
1952
1953 if (pow & 1) {
1954 resrdx += powrdx;
1955 s = bc_num_mul(c, &copy, c, resrdx);
1956 if (s) goto err;
1957 }
Denys Vlasenkof359e002018-12-05 01:21:59 +01001958 // It is too slow to handle ^C only after entire "2^1000000" completes
1959 if (G_interrupt) {
1960 s = BC_STATUS_FAILURE;
1961 goto err;
1962 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001963 }
1964
1965 if (neg) {
1966 s = bc_num_inv(c, c, scale);
1967 if (s) goto err;
1968 }
1969
Gavin Howard01055ba2018-11-03 11:00:21 -06001970 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1971
1972 // We can't use bc_num_clean() here.
1973 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1974 if (zero) bc_num_setToZero(c, scale);
1975
1976err:
1977 bc_num_free(&copy);
1978 return s;
1979}
1980
1981static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1982 BcNumBinaryOp op, size_t req)
1983{
1984 BcStatus s;
1985 BcNum num2, *ptr_a, *ptr_b;
1986 bool init = false;
1987
1988 if (c == a) {
1989 ptr_a = &num2;
1990 memcpy(ptr_a, c, sizeof(BcNum));
1991 init = true;
1992 }
1993 else
1994 ptr_a = a;
1995
1996 if (c == b) {
1997 ptr_b = &num2;
1998 if (c != a) {
1999 memcpy(ptr_b, c, sizeof(BcNum));
2000 init = true;
2001 }
2002 }
2003 else
2004 ptr_b = b;
2005
2006 if (init)
2007 bc_num_init(c, req);
2008 else
2009 bc_num_expand(c, req);
2010
2011 s = op(ptr_a, ptr_b, c, scale);
2012
2013 if (init) bc_num_free(&num2);
2014
2015 return s;
2016}
2017
2018static bool bc_num_strValid(const char *val, size_t base)
2019{
2020 BcDig b;
2021 bool small, radix = false;
2022 size_t i, len = strlen(val);
2023
2024 if (!len) return true;
2025
2026 small = base <= 10;
2027 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2028
2029 for (i = 0; i < len; ++i) {
2030
2031 BcDig c = val[i];
2032
2033 if (c == '.') {
2034
2035 if (radix) return false;
2036
2037 radix = true;
2038 continue;
2039 }
2040
2041 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2042 return false;
2043 }
2044
2045 return true;
2046}
2047
2048static void bc_num_parseDecimal(BcNum *n, const char *val)
2049{
2050 size_t len, i;
2051 const char *ptr;
2052 bool zero = true;
2053
2054 for (i = 0; val[i] == '0'; ++i);
2055
2056 val += i;
2057 len = strlen(val);
2058 bc_num_zero(n);
2059
2060 if (len != 0) {
2061 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2062 bc_num_expand(n, len);
2063 }
2064
2065 ptr = strchr(val, '.');
2066
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002067 n->rdx = 0;
2068 if (ptr != NULL)
2069 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002070
2071 if (!zero) {
2072 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2073 n->num[n->len] = val[i] - '0';
2074 }
2075}
2076
2077static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2078{
2079 BcStatus s;
2080 BcNum temp, mult, result;
2081 BcDig c = '\0';
2082 bool zero = true;
2083 unsigned long v;
2084 size_t i, digits, len = strlen(val);
2085
2086 bc_num_zero(n);
2087
2088 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2089 if (zero) return;
2090
2091 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2092 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2093
2094 for (i = 0; i < len; ++i) {
2095
2096 c = val[i];
2097 if (c == '.') break;
2098
2099 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2100
2101 s = bc_num_mul(n, base, &mult, 0);
2102 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002103 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002104 s = bc_num_add(&mult, &temp, n, 0);
2105 if (s) goto int_err;
2106 }
2107
2108 if (i == len) {
2109 c = val[i];
2110 if (c == 0) goto int_err;
2111 }
2112
2113 bc_num_init(&result, base->len);
2114 bc_num_zero(&result);
2115 bc_num_one(&mult);
2116
2117 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2118
2119 c = val[i];
2120 if (c == 0) break;
2121
2122 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2123
2124 s = bc_num_mul(&result, base, &result, 0);
2125 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002126 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002127 s = bc_num_add(&result, &temp, &result, 0);
2128 if (s) goto err;
2129 s = bc_num_mul(&mult, base, &mult, 0);
2130 if (s) goto err;
2131 }
2132
2133 s = bc_num_div(&result, &mult, &result, digits);
2134 if (s) goto err;
2135 s = bc_num_add(n, &result, n, digits);
2136 if (s) goto err;
2137
2138 if (n->len != 0) {
2139 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2140 }
2141 else
2142 bc_num_zero(n);
2143
2144err:
2145 bc_num_free(&result);
2146int_err:
2147 bc_num_free(&mult);
2148 bc_num_free(&temp);
2149}
2150
2151static void bc_num_printNewline(size_t *nchars, size_t line_len)
2152{
2153 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002154 bb_putchar('\\');
2155 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002156 *nchars = 0;
2157 }
2158}
2159
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002160#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002161static void bc_num_printChar(size_t num, size_t width, bool radix,
2162 size_t *nchars, size_t line_len)
2163{
2164 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002165 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002166 *nchars = *nchars + width;
2167}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002168#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002169
2170static void bc_num_printDigits(size_t num, size_t width, bool radix,
2171 size_t *nchars, size_t line_len)
2172{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002173 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002174
2175 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002176 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002177 ++(*nchars);
2178
2179 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002180 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2181 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002182
2183 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002184 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002185 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002186 dig = num / pow;
2187 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002188 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002189 }
2190}
2191
2192static void bc_num_printHex(size_t num, size_t width, bool radix,
2193 size_t *nchars, size_t line_len)
2194{
2195 if (radix) {
2196 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002197 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002198 *nchars += 1;
2199 }
2200
2201 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002202 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002203 *nchars = *nchars + width;
2204}
2205
2206static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2207{
2208 size_t i, rdx = n->rdx - 1;
2209
Denys Vlasenko00d77792018-11-30 23:13:42 +01002210 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002211 (*nchars) += n->neg;
2212
2213 for (i = n->len - 1; i < n->len; --i)
2214 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2215}
2216
2217static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2218 size_t *nchars, size_t len, BcNumDigitOp print)
2219{
2220 BcStatus s;
2221 BcVec stack;
2222 BcNum intp, fracp, digit, frac_len;
2223 unsigned long dig, *ptr;
2224 size_t i;
2225 bool radix;
2226
2227 if (n->len == 0) {
2228 print(0, width, false, nchars, len);
2229 return BC_STATUS_SUCCESS;
2230 }
2231
2232 bc_vec_init(&stack, sizeof(long), NULL);
2233 bc_num_init(&intp, n->len);
2234 bc_num_init(&fracp, n->rdx);
2235 bc_num_init(&digit, width);
2236 bc_num_init(&frac_len, BC_NUM_INT(n));
2237 bc_num_copy(&intp, n);
2238 bc_num_one(&frac_len);
2239
2240 bc_num_truncate(&intp, intp.rdx);
2241 s = bc_num_sub(n, &intp, &fracp, 0);
2242 if (s) goto err;
2243
2244 while (intp.len != 0) {
2245 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2246 if (s) goto err;
2247 s = bc_num_ulong(&digit, &dig);
2248 if (s) goto err;
2249 bc_vec_push(&stack, &dig);
2250 }
2251
2252 for (i = 0; i < stack.len; ++i) {
2253 ptr = bc_vec_item_rev(&stack, i);
2254 print(*ptr, width, false, nchars, len);
2255 }
2256
2257 if (!n->rdx) goto err;
2258
2259 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2260 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2261 if (s) goto err;
2262 s = bc_num_ulong(&fracp, &dig);
2263 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002264 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002265 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2266 if (s) goto err;
2267 print(dig, width, radix, nchars, len);
2268 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2269 if (s) goto err;
2270 }
2271
2272err:
2273 bc_num_free(&frac_len);
2274 bc_num_free(&digit);
2275 bc_num_free(&fracp);
2276 bc_num_free(&intp);
2277 bc_vec_free(&stack);
2278 return s;
2279}
2280
2281static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2282 size_t *nchars, size_t line_len)
2283{
2284 BcStatus s;
2285 size_t width, i;
2286 BcNumDigitOp print;
2287 bool neg = n->neg;
2288
Denys Vlasenko00d77792018-11-30 23:13:42 +01002289 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002290 (*nchars) += neg;
2291
2292 n->neg = false;
2293
2294 if (base_t <= BC_NUM_MAX_IBASE) {
2295 width = 1;
2296 print = bc_num_printHex;
2297 }
2298 else {
2299 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2300 print = bc_num_printDigits;
2301 }
2302
2303 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2304 n->neg = neg;
2305
2306 return s;
2307}
2308
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002309#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002310static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2311{
2312 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2313}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002314#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002315
2316static void bc_num_init(BcNum *n, size_t req)
2317{
2318 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2319 memset(n, 0, sizeof(BcNum));
2320 n->num = xmalloc(req);
2321 n->cap = req;
2322}
2323
2324static void bc_num_expand(BcNum *n, size_t req)
2325{
2326 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2327 if (req > n->cap) {
2328 n->num = xrealloc(n->num, req);
2329 n->cap = req;
2330 }
2331}
2332
2333static void bc_num_free(void *num)
2334{
2335 free(((BcNum *) num)->num);
2336}
2337
2338static void bc_num_copy(BcNum *d, BcNum *s)
2339{
2340 if (d != s) {
2341 bc_num_expand(d, s->cap);
2342 d->len = s->len;
2343 d->neg = s->neg;
2344 d->rdx = s->rdx;
2345 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2346 }
2347}
2348
2349static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2350 size_t base_t)
2351{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002352 if (!bc_num_strValid(val, base_t))
2353 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002354
2355 if (base_t == 10)
2356 bc_num_parseDecimal(n, val);
2357 else
2358 bc_num_parseBase(n, val, base);
2359
2360 return BC_STATUS_SUCCESS;
2361}
2362
2363static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2364 size_t *nchars, size_t line_len)
2365{
2366 BcStatus s = BC_STATUS_SUCCESS;
2367
2368 bc_num_printNewline(nchars, line_len);
2369
2370 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002371 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002372 ++(*nchars);
2373 }
2374 else if (base_t == 10)
2375 bc_num_printDecimal(n, nchars, line_len);
2376 else
2377 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2378
2379 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002380 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002381 *nchars = 0;
2382 }
2383
2384 return s;
2385}
2386
2387static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2388{
2389 size_t i;
2390 unsigned long pow;
2391
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002392 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002393
2394 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2395
2396 unsigned long prev = *result, powprev = pow;
2397
2398 *result += ((unsigned long) n->num[i]) * pow;
2399 pow *= 10;
2400
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002401 if (*result < prev || pow < powprev)
2402 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002403 }
2404
2405 return BC_STATUS_SUCCESS;
2406}
2407
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002408static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002409{
2410 size_t len;
2411 BcDig *ptr;
2412 unsigned long i;
2413
2414 bc_num_zero(n);
2415
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002416 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002417
2418 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2419 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002420}
2421
2422static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2423{
2424 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2425 (void) scale;
2426 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2427}
2428
2429static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2430{
2431 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2432 (void) scale;
2433 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2434}
2435
2436static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2437{
2438 size_t req = BC_NUM_MREQ(a, b, scale);
2439 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2440}
2441
2442static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2443{
2444 size_t req = BC_NUM_MREQ(a, b, scale);
2445 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2446}
2447
2448static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2449{
2450 size_t req = BC_NUM_MREQ(a, b, scale);
2451 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2452}
2453
2454static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2455{
2456 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2457}
2458
2459static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2460{
2461 BcStatus s;
2462 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2463 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2464 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2465
2466 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2467 bc_num_expand(b, req);
2468
2469 if (a->len == 0) {
2470 bc_num_setToZero(b, scale);
2471 return BC_STATUS_SUCCESS;
2472 }
2473 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002474 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002475 else if (BC_NUM_ONE(a)) {
2476 bc_num_one(b);
2477 bc_num_extend(b, scale);
2478 return BC_STATUS_SUCCESS;
2479 }
2480
2481 scale = BC_MAX(scale, a->rdx) + 1;
2482 len = a->len + scale;
2483
2484 bc_num_init(&num1, len);
2485 bc_num_init(&num2, len);
2486 bc_num_init(&half, BC_NUM_DEF_SIZE);
2487
2488 bc_num_one(&half);
2489 half.num[0] = 5;
2490 half.rdx = 1;
2491
2492 bc_num_init(&f, len);
2493 bc_num_init(&fprime, len);
2494
2495 x0 = &num1;
2496 x1 = &num2;
2497
2498 bc_num_one(x0);
2499 pow = BC_NUM_INT(a);
2500
2501 if (pow) {
2502
2503 if (pow & 1)
2504 x0->num[0] = 2;
2505 else
2506 x0->num[0] = 6;
2507
2508 pow -= 2 - (pow & 1);
2509
2510 bc_num_extend(x0, pow);
2511
2512 // Make sure to move the radix back.
2513 x0->rdx -= pow;
2514 }
2515
2516 x0->rdx = digs = digs1 = 0;
2517 resrdx = scale + 2;
2518 len = BC_NUM_INT(x0) + resrdx - 1;
2519
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002520 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002521
2522 s = bc_num_div(a, x0, &f, resrdx);
2523 if (s) goto err;
2524 s = bc_num_add(x0, &f, &fprime, resrdx);
2525 if (s) goto err;
2526 s = bc_num_mul(&fprime, &half, x1, resrdx);
2527 if (s) goto err;
2528
2529 cmp = bc_num_cmp(x1, x0);
2530 digs = x1->len - (unsigned long long) llabs(cmp);
2531
2532 if (cmp == cmp2 && digs == digs1)
2533 times += 1;
2534 else
2535 times = 0;
2536
2537 resrdx += times > 4;
2538
2539 cmp2 = cmp1;
2540 cmp1 = cmp;
2541 digs1 = digs;
2542
2543 temp = x0;
2544 x0 = x1;
2545 x1 = temp;
2546 }
2547
Gavin Howard01055ba2018-11-03 11:00:21 -06002548 bc_num_copy(b, x0);
2549 scale -= 1;
2550 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2551
2552err:
2553 bc_num_free(&fprime);
2554 bc_num_free(&f);
2555 bc_num_free(&half);
2556 bc_num_free(&num2);
2557 bc_num_free(&num1);
2558 return s;
2559}
2560
2561static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2562 size_t scale)
2563{
2564 BcStatus s;
2565 BcNum num2, *ptr_a;
2566 bool init = false;
2567 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2568
2569 if (c == a) {
2570 memcpy(&num2, c, sizeof(BcNum));
2571 ptr_a = &num2;
2572 bc_num_init(c, len);
2573 init = true;
2574 }
2575 else {
2576 ptr_a = a;
2577 bc_num_expand(c, len);
2578 }
2579
2580 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2581
2582 if (init) bc_num_free(&num2);
2583
2584 return s;
2585}
2586
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002587#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002588static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2589{
2590 BcStatus s;
2591 BcNum base, exp, two, temp;
2592
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002593 if (c->len == 0)
2594 return bc_error("divide by zero");
2595 if (a->rdx || b->rdx || c->rdx)
2596 return bc_error("non integer number");
2597 if (b->neg)
2598 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002599
2600 bc_num_expand(d, c->len);
2601 bc_num_init(&base, c->len);
2602 bc_num_init(&exp, b->len);
2603 bc_num_init(&two, BC_NUM_DEF_SIZE);
2604 bc_num_init(&temp, b->len);
2605
2606 bc_num_one(&two);
2607 two.num[0] = 2;
2608 bc_num_one(d);
2609
2610 s = bc_num_rem(a, c, &base, 0);
2611 if (s) goto err;
2612 bc_num_copy(&exp, b);
2613
2614 while (exp.len != 0) {
2615
2616 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2617 if (s) goto err;
2618
2619 if (BC_NUM_ONE(&temp)) {
2620 s = bc_num_mul(d, &base, &temp, 0);
2621 if (s) goto err;
2622 s = bc_num_rem(&temp, c, d, 0);
2623 if (s) goto err;
2624 }
2625
2626 s = bc_num_mul(&base, &base, &temp, 0);
2627 if (s) goto err;
2628 s = bc_num_rem(&temp, c, &base, 0);
2629 if (s) goto err;
2630 }
2631
2632err:
2633 bc_num_free(&temp);
2634 bc_num_free(&two);
2635 bc_num_free(&exp);
2636 bc_num_free(&base);
2637 return s;
2638}
2639#endif // ENABLE_DC
2640
2641static int bc_id_cmp(const void *e1, const void *e2)
2642{
2643 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2644}
2645
2646static void bc_id_free(void *id)
2647{
2648 free(((BcId *) id)->name);
2649}
2650
2651static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2652{
2653 BcId a;
2654 size_t i;
2655
2656 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002657 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2658 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002659 }
2660
2661 a.idx = var;
2662 a.name = name;
2663
2664 bc_vec_push(&f->autos, &a);
2665
2666 return BC_STATUS_SUCCESS;
2667}
2668
2669static void bc_func_init(BcFunc *f)
2670{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002671 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002672 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2673 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2674 f->nparams = 0;
2675}
2676
2677static void bc_func_free(void *func)
2678{
2679 BcFunc *f = (BcFunc *) func;
2680 bc_vec_free(&f->code);
2681 bc_vec_free(&f->autos);
2682 bc_vec_free(&f->labels);
2683}
2684
2685static void bc_array_init(BcVec *a, bool nums)
2686{
2687 if (nums)
2688 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2689 else
2690 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2691 bc_array_expand(a, 1);
2692}
2693
2694static void bc_array_copy(BcVec *d, const BcVec *s)
2695{
2696 size_t i;
2697
Denys Vlasenko7d628012018-12-04 21:46:47 +01002698 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002699 bc_vec_expand(d, s->cap);
2700 d->len = s->len;
2701
2702 for (i = 0; i < s->len; ++i) {
2703 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2704 bc_num_init(dnum, snum->len);
2705 bc_num_copy(dnum, snum);
2706 }
2707}
2708
2709static void bc_array_expand(BcVec *a, size_t len)
2710{
2711 BcResultData data;
2712
2713 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2714 while (len > a->len) {
2715 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2716 bc_vec_push(a, &data.n);
2717 }
2718 }
2719 else {
2720 while (len > a->len) {
2721 bc_array_init(&data.v, true);
2722 bc_vec_push(a, &data.v);
2723 }
2724 }
2725}
2726
2727static void bc_string_free(void *string)
2728{
2729 free(*((char **) string));
2730}
2731
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002732#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002733static void bc_result_copy(BcResult *d, BcResult *src)
2734{
2735 d->t = src->t;
2736
2737 switch (d->t) {
2738
2739 case BC_RESULT_TEMP:
2740 case BC_RESULT_IBASE:
2741 case BC_RESULT_SCALE:
2742 case BC_RESULT_OBASE:
2743 {
2744 bc_num_init(&d->d.n, src->d.n.len);
2745 bc_num_copy(&d->d.n, &src->d.n);
2746 break;
2747 }
2748
2749 case BC_RESULT_VAR:
2750 case BC_RESULT_ARRAY:
2751 case BC_RESULT_ARRAY_ELEM:
2752 {
2753 d->d.id.name = xstrdup(src->d.id.name);
2754 break;
2755 }
2756
2757 case BC_RESULT_CONSTANT:
2758 case BC_RESULT_LAST:
2759 case BC_RESULT_ONE:
2760 case BC_RESULT_STR:
2761 {
2762 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2763 break;
2764 }
2765 }
2766}
2767#endif // ENABLE_DC
2768
2769static void bc_result_free(void *result)
2770{
2771 BcResult *r = (BcResult *) result;
2772
2773 switch (r->t) {
2774
2775 case BC_RESULT_TEMP:
2776 case BC_RESULT_IBASE:
2777 case BC_RESULT_SCALE:
2778 case BC_RESULT_OBASE:
2779 {
2780 bc_num_free(&r->d.n);
2781 break;
2782 }
2783
2784 case BC_RESULT_VAR:
2785 case BC_RESULT_ARRAY:
2786 case BC_RESULT_ARRAY_ELEM:
2787 {
2788 free(r->d.id.name);
2789 break;
2790 }
2791
2792 default:
2793 {
2794 // Do nothing.
2795 break;
2796 }
2797 }
2798}
2799
2800static void bc_lex_lineComment(BcLex *l)
2801{
2802 l->t.t = BC_LEX_WHITESPACE;
2803 while (l->i < l->len && l->buf[l->i++] != '\n');
2804 --l->i;
2805}
2806
2807static void bc_lex_whitespace(BcLex *l)
2808{
2809 char c;
2810 l->t.t = BC_LEX_WHITESPACE;
2811 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2812}
2813
2814static BcStatus bc_lex_number(BcLex *l, char start)
2815{
2816 const char *buf = l->buf + l->i;
2817 size_t len, hits = 0, bslashes = 0, i = 0, j;
2818 char c = buf[i];
2819 bool last_pt, pt = start == '.';
2820
2821 last_pt = pt;
2822 l->t.t = BC_LEX_NUMBER;
2823
2824 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2825 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2826 {
2827 if (c != '\\') {
2828 last_pt = c == '.';
2829 pt = pt || last_pt;
2830 }
2831 else {
2832 ++i;
2833 bslashes += 1;
2834 }
2835
2836 c = buf[++i];
2837 }
2838
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002839 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002840 if (len > BC_MAX_NUM)
2841 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002842
Denys Vlasenko7d628012018-12-04 21:46:47 +01002843 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002844 bc_vec_expand(&l->t.v, len + 1);
2845 bc_vec_push(&l->t.v, &start);
2846
2847 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2848
2849 c = buf[j];
2850
2851 // If we have hit a backslash, skip it. We don't have
2852 // to check for a newline because it's guaranteed.
2853 if (hits < bslashes && c == '\\') {
2854 ++hits;
2855 ++j;
2856 continue;
2857 }
2858
2859 bc_vec_push(&l->t.v, &c);
2860 }
2861
Denys Vlasenko08c033c2018-12-05 16:55:08 +01002862 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002863 l->i += i;
2864
2865 return BC_STATUS_SUCCESS;
2866}
2867
2868static BcStatus bc_lex_name(BcLex *l)
2869{
2870 size_t i = 0;
2871 const char *buf = l->buf + l->i - 1;
2872 char c = buf[i];
2873
2874 l->t.t = BC_LEX_NAME;
2875
2876 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2877
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002878 if (i > BC_MAX_STRING)
2879 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002880 bc_vec_string(&l->t.v, i, buf);
2881
2882 // Increment the index. We minus 1 because it has already been incremented.
2883 l->i += i - 1;
2884
2885 return BC_STATUS_SUCCESS;
2886}
2887
2888static void bc_lex_init(BcLex *l, BcLexNext next)
2889{
2890 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002891 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002892}
2893
2894static void bc_lex_free(BcLex *l)
2895{
2896 bc_vec_free(&l->t.v);
2897}
2898
Denys Vlasenko0409ad32018-12-05 16:39:22 +01002899static void bc_lex_file(BcLex *l)
Gavin Howard01055ba2018-11-03 11:00:21 -06002900{
Denys Vlasenko5318f812018-12-05 17:48:01 +01002901 G.err_line = l->line = 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002902 l->newline = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06002903}
2904
2905static BcStatus bc_lex_next(BcLex *l)
2906{
2907 BcStatus s;
2908
2909 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002910 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002911
2912 l->line += l->newline;
Denys Vlasenko5318f812018-12-05 17:48:01 +01002913 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06002914 l->t.t = BC_LEX_EOF;
2915
2916 l->newline = (l->i == l->len);
2917 if (l->newline) return BC_STATUS_SUCCESS;
2918
2919 // Loop until failure or we don't have whitespace. This
2920 // is so the parser doesn't get inundated with whitespace.
2921 do {
2922 s = l->next(l);
2923 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2924
2925 return s;
2926}
2927
2928static BcStatus bc_lex_text(BcLex *l, const char *text)
2929{
2930 l->buf = text;
2931 l->i = 0;
2932 l->len = strlen(text);
2933 l->t.t = l->t.last = BC_LEX_INVALID;
2934 return bc_lex_next(l);
2935}
2936
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002937#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002938static BcStatus bc_lex_identifier(BcLex *l)
2939{
2940 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002941 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06002942 const char *buf = l->buf + l->i - 1;
2943
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002944 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2945 const char *keyword8 = bc_lex_kws[i].name8;
2946 unsigned j = 0;
2947 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2948 j++;
2949 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06002950 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002951 if (keyword8[j] != '\0')
2952 continue;
2953 match:
2954 // buf starts with keyword bc_lex_kws[i]
2955 l->t.t = BC_LEX_KEY_1st_keyword + i;
Denys Vlasenko00646792018-12-05 18:12:27 +01002956 if (!((1 << i) & POSIX_KWORD_MASK)) {
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01002957 s = bc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002958 if (s) return s;
2959 }
2960
2961 // We minus 1 because the index has already been incremented.
2962 l->i += j - 1;
2963 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06002964 }
2965
2966 s = bc_lex_name(l);
2967 if (s) return s;
2968
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01002969 if (l->t.v.len > 2) {
2970 // Prevent this:
2971 // >>> qwe=1
2972 // bc: POSIX only allows one character names; the following is bad: 'qwe=1
2973 // '
2974 unsigned len = strchrnul(buf, '\n') - buf;
2975 s = bc_posix_error_fmt("POSIX only allows one character names; the following is bad: '%.*s'", len, buf);
2976 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002977
2978 return s;
2979}
2980
2981static BcStatus bc_lex_string(BcLex *l)
2982{
2983 size_t len, nls = 0, i = l->i;
2984 char c;
2985
2986 l->t.t = BC_LEX_STR;
2987
2988 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2989
2990 if (c == '\0') {
2991 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002992 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002993 }
2994
2995 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002996 if (len > BC_MAX_STRING)
2997 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002998 bc_vec_string(&l->t.v, len, l->buf + l->i);
2999
3000 l->i = i + 1;
3001 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003002 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003003
3004 return BC_STATUS_SUCCESS;
3005}
3006
3007static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3008{
3009 if (l->buf[l->i] == '=') {
3010 ++l->i;
3011 l->t.t = with;
3012 }
3013 else
3014 l->t.t = without;
3015}
3016
3017static BcStatus bc_lex_comment(BcLex *l)
3018{
3019 size_t i, nls = 0;
3020 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003021
3022 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003023 i = ++l->i;
3024 for (;;) {
3025 char c = buf[i];
3026 check_star:
3027 if (c == '*') {
3028 c = buf[++i];
3029 if (c == '/')
3030 break;
3031 goto check_star;
3032 }
3033 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003034 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003035 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003036 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003037 nls += (c == '\n');
3038 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003039 }
3040
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003041 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003042 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003043 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003044
3045 return BC_STATUS_SUCCESS;
3046}
3047
3048static BcStatus bc_lex_token(BcLex *l)
3049{
3050 BcStatus s = BC_STATUS_SUCCESS;
3051 char c = l->buf[l->i++], c2;
3052
3053 // This is the workhorse of the lexer.
3054 switch (c) {
3055
3056 case '\0':
3057 case '\n':
3058 {
3059 l->newline = true;
3060 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3061 break;
3062 }
3063
3064 case '\t':
3065 case '\v':
3066 case '\f':
3067 case '\r':
3068 case ' ':
3069 {
3070 bc_lex_whitespace(l);
3071 break;
3072 }
3073
3074 case '!':
3075 {
3076 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3077
3078 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko00646792018-12-05 18:12:27 +01003079 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
Gavin Howard01055ba2018-11-03 11:00:21 -06003080 if (s) return s;
3081 }
3082
3083 break;
3084 }
3085
3086 case '"':
3087 {
3088 s = bc_lex_string(l);
3089 break;
3090 }
3091
3092 case '#':
3093 {
Denys Vlasenko00646792018-12-05 18:12:27 +01003094 s = bc_POSIX_does_not_allow("'#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003095 if (s) return s;
3096
3097 bc_lex_lineComment(l);
3098
3099 break;
3100 }
3101
3102 case '%':
3103 {
3104 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3105 break;
3106 }
3107
3108 case '&':
3109 {
3110 c2 = l->buf[l->i];
3111 if (c2 == '&') {
3112
Denys Vlasenko00646792018-12-05 18:12:27 +01003113 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
Gavin Howard01055ba2018-11-03 11:00:21 -06003114 if (s) return s;
3115
3116 ++l->i;
3117 l->t.t = BC_LEX_OP_BOOL_AND;
3118 }
3119 else {
3120 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003121 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003122 }
3123
3124 break;
3125 }
3126
3127 case '(':
3128 case ')':
3129 {
3130 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3131 break;
3132 }
3133
3134 case '*':
3135 {
3136 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3137 break;
3138 }
3139
3140 case '+':
3141 {
3142 c2 = l->buf[l->i];
3143 if (c2 == '+') {
3144 ++l->i;
3145 l->t.t = BC_LEX_OP_INC;
3146 }
3147 else
3148 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3149 break;
3150 }
3151
3152 case ',':
3153 {
3154 l->t.t = BC_LEX_COMMA;
3155 break;
3156 }
3157
3158 case '-':
3159 {
3160 c2 = l->buf[l->i];
3161 if (c2 == '-') {
3162 ++l->i;
3163 l->t.t = BC_LEX_OP_DEC;
3164 }
3165 else
3166 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3167 break;
3168 }
3169
3170 case '.':
3171 {
3172 if (isdigit(l->buf[l->i]))
3173 s = bc_lex_number(l, c);
3174 else {
3175 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko00646792018-12-05 18:12:27 +01003176 s = bc_POSIX_does_not_allow("a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003177 }
3178 break;
3179 }
3180
3181 case '/':
3182 {
3183 c2 = l->buf[l->i];
3184 if (c2 == '*')
3185 s = bc_lex_comment(l);
3186 else
3187 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3188 break;
3189 }
3190
3191 case '0':
3192 case '1':
3193 case '2':
3194 case '3':
3195 case '4':
3196 case '5':
3197 case '6':
3198 case '7':
3199 case '8':
3200 case '9':
3201 case 'A':
3202 case 'B':
3203 case 'C':
3204 case 'D':
3205 case 'E':
3206 case 'F':
3207 {
3208 s = bc_lex_number(l, c);
3209 break;
3210 }
3211
3212 case ';':
3213 {
3214 l->t.t = BC_LEX_SCOLON;
3215 break;
3216 }
3217
3218 case '<':
3219 {
3220 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3221 break;
3222 }
3223
3224 case '=':
3225 {
3226 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3227 break;
3228 }
3229
3230 case '>':
3231 {
3232 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3233 break;
3234 }
3235
3236 case '[':
3237 case ']':
3238 {
3239 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3240 break;
3241 }
3242
3243 case '\\':
3244 {
3245 if (l->buf[l->i] == '\n') {
3246 l->t.t = BC_LEX_WHITESPACE;
3247 ++l->i;
3248 }
3249 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003250 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003251 break;
3252 }
3253
3254 case '^':
3255 {
3256 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3257 break;
3258 }
3259
3260 case 'a':
3261 case 'b':
3262 case 'c':
3263 case 'd':
3264 case 'e':
3265 case 'f':
3266 case 'g':
3267 case 'h':
3268 case 'i':
3269 case 'j':
3270 case 'k':
3271 case 'l':
3272 case 'm':
3273 case 'n':
3274 case 'o':
3275 case 'p':
3276 case 'q':
3277 case 'r':
3278 case 's':
3279 case 't':
3280 case 'u':
3281 case 'v':
3282 case 'w':
3283 case 'x':
3284 case 'y':
3285 case 'z':
3286 {
3287 s = bc_lex_identifier(l);
3288 break;
3289 }
3290
3291 case '{':
3292 case '}':
3293 {
3294 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3295 break;
3296 }
3297
3298 case '|':
3299 {
3300 c2 = l->buf[l->i];
3301
3302 if (c2 == '|') {
Denys Vlasenko00646792018-12-05 18:12:27 +01003303 s = bc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
Gavin Howard01055ba2018-11-03 11:00:21 -06003304 if (s) return s;
3305
3306 ++l->i;
3307 l->t.t = BC_LEX_OP_BOOL_OR;
3308 }
3309 else {
3310 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003311 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003312 }
3313
3314 break;
3315 }
3316
3317 default:
3318 {
3319 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003320 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003321 break;
3322 }
3323 }
3324
3325 return s;
3326}
3327#endif // ENABLE_BC
3328
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003329#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003330static BcStatus dc_lex_register(BcLex *l)
3331{
3332 BcStatus s = BC_STATUS_SUCCESS;
3333
3334 if (isspace(l->buf[l->i - 1])) {
3335 bc_lex_whitespace(l);
3336 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003337 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003338 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003339 else
3340 s = bc_lex_name(l);
3341 }
3342 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003343 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003344 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003345 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003346 l->t.t = BC_LEX_NAME;
3347 }
3348
3349 return s;
3350}
3351
3352static BcStatus dc_lex_string(BcLex *l)
3353{
3354 size_t depth = 1, nls = 0, i = l->i;
3355 char c;
3356
3357 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003358 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003359
3360 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3361
3362 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3363 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3364 nls += (c == '\n');
3365
3366 if (depth) bc_vec_push(&l->t.v, &c);
3367 }
3368
3369 if (c == '\0') {
3370 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003371 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003372 }
3373
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003374 bc_vec_pushZeroByte(&l->t.v);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003375 if (i - l->i > BC_MAX_STRING)
3376 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003377
3378 l->i = i;
3379 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003380 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003381
3382 return BC_STATUS_SUCCESS;
3383}
3384
3385static BcStatus dc_lex_token(BcLex *l)
3386{
3387 BcStatus s = BC_STATUS_SUCCESS;
3388 char c = l->buf[l->i++], c2;
3389 size_t i;
3390
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003391 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3392 if (l->t.last == dc_lex_regs[i])
3393 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003394 }
3395
3396 if (c >= '%' && c <= '~' &&
3397 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3398 {
3399 return s;
3400 }
3401
3402 // This is the workhorse of the lexer.
3403 switch (c) {
3404
3405 case '\0':
3406 {
3407 l->t.t = BC_LEX_EOF;
3408 break;
3409 }
3410
3411 case '\n':
3412 case '\t':
3413 case '\v':
3414 case '\f':
3415 case '\r':
3416 case ' ':
3417 {
3418 l->newline = (c == '\n');
3419 bc_lex_whitespace(l);
3420 break;
3421 }
3422
3423 case '!':
3424 {
3425 c2 = l->buf[l->i];
3426
3427 if (c2 == '=')
3428 l->t.t = BC_LEX_OP_REL_NE;
3429 else if (c2 == '<')
3430 l->t.t = BC_LEX_OP_REL_LE;
3431 else if (c2 == '>')
3432 l->t.t = BC_LEX_OP_REL_GE;
3433 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003434 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003435
3436 ++l->i;
3437 break;
3438 }
3439
3440 case '#':
3441 {
3442 bc_lex_lineComment(l);
3443 break;
3444 }
3445
3446 case '.':
3447 {
3448 if (isdigit(l->buf[l->i]))
3449 s = bc_lex_number(l, c);
3450 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003451 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003452 break;
3453 }
3454
3455 case '0':
3456 case '1':
3457 case '2':
3458 case '3':
3459 case '4':
3460 case '5':
3461 case '6':
3462 case '7':
3463 case '8':
3464 case '9':
3465 case 'A':
3466 case 'B':
3467 case 'C':
3468 case 'D':
3469 case 'E':
3470 case 'F':
3471 {
3472 s = bc_lex_number(l, c);
3473 break;
3474 }
3475
3476 case '[':
3477 {
3478 s = dc_lex_string(l);
3479 break;
3480 }
3481
3482 default:
3483 {
3484 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003485 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003486 break;
3487 }
3488 }
3489
3490 return s;
3491}
3492#endif // ENABLE_DC
3493
3494static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3495{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003496 bc_program_addFunc(name, idx);
3497 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003498}
3499
3500static void bc_parse_pushName(BcParse *p, char *name)
3501{
3502 size_t i = 0, len = strlen(name);
3503
3504 for (; i < len; ++i) bc_parse_push(p, name[i]);
3505 bc_parse_push(p, BC_PARSE_STREND);
3506
3507 free(name);
3508}
3509
3510static void bc_parse_pushIndex(BcParse *p, size_t idx)
3511{
3512 unsigned char amt, i, nums[sizeof(size_t)];
3513
3514 for (amt = 0; idx; ++amt) {
3515 nums[amt] = (char) idx;
3516 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3517 }
3518
3519 bc_parse_push(p, amt);
3520 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3521}
3522
3523static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3524{
3525 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003526 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003527
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003528 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003529
3530 bc_parse_push(p, BC_INST_NUM);
3531 bc_parse_pushIndex(p, idx);
3532
3533 ++(*nexs);
3534 (*prev) = BC_INST_NUM;
3535}
3536
3537static BcStatus bc_parse_text(BcParse *p, const char *text)
3538{
3539 BcStatus s;
3540
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003541 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003542
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003543 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003544 p->l.t.t = BC_LEX_INVALID;
3545 s = p->parse(p);
3546 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003547 if (!BC_PARSE_CAN_EXEC(p))
3548 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003549 }
3550
3551 return bc_lex_text(&p->l, text);
3552}
3553
Denys Vlasenkod38af482018-12-04 19:11:02 +01003554// Called when bc/dc_parse_parse() detects a failure,
3555// resets parsing structures.
3556static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003557{
3558 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003559 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003560 bc_vec_pop_all(&p->func->code);
3561 bc_vec_pop_all(&p->func->autos);
3562 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003563
3564 bc_parse_updateFunc(p, BC_PROG_MAIN);
3565 }
3566
3567 p->l.i = p->l.len;
3568 p->l.t.t = BC_LEX_EOF;
3569 p->auto_part = (p->nbraces = 0);
3570
3571 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003572 bc_vec_pop_all(&p->exits);
3573 bc_vec_pop_all(&p->conds);
3574 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003575
Denys Vlasenkod38af482018-12-04 19:11:02 +01003576 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003577}
3578
3579static void bc_parse_free(BcParse *p)
3580{
3581 bc_vec_free(&p->flags);
3582 bc_vec_free(&p->exits);
3583 bc_vec_free(&p->conds);
3584 bc_vec_free(&p->ops);
3585 bc_lex_free(&p->l);
3586}
3587
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003588static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003589 BcParseParse parse, BcLexNext next)
3590{
3591 memset(p, 0, sizeof(BcParse));
3592
3593 bc_lex_init(&p->l, next);
3594 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3595 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3596 bc_vec_init(&p->conds, sizeof(size_t), NULL);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003597 bc_vec_pushZeroByte(&p->flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003598 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3599
3600 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003601 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003602 bc_parse_updateFunc(p, func);
3603}
3604
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003605#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003606static BcStatus bc_parse_else(BcParse *p);
3607static BcStatus bc_parse_stmt(BcParse *p);
3608
3609static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3610 size_t *nexprs, bool next)
3611{
3612 BcStatus s = BC_STATUS_SUCCESS;
3613 BcLexType t;
3614 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3615 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3616
3617 while (p->ops.len > start) {
3618
3619 t = BC_PARSE_TOP_OP(p);
3620 if (t == BC_LEX_LPAREN) break;
3621
3622 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3623 if (l >= r && (l != r || !left)) break;
3624
3625 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3626 bc_vec_pop(&p->ops);
3627 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3628 }
3629
3630 bc_vec_push(&p->ops, &type);
3631 if (next) s = bc_lex_next(&p->l);
3632
3633 return s;
3634}
3635
3636static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3637{
3638 BcLexType top;
3639
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003640 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003641 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003642 top = BC_PARSE_TOP_OP(p);
3643
3644 while (top != BC_LEX_LPAREN) {
3645
3646 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3647
3648 bc_vec_pop(&p->ops);
3649 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3650
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003651 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003652 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003653 top = BC_PARSE_TOP_OP(p);
3654 }
3655
3656 bc_vec_pop(&p->ops);
3657
3658 return bc_lex_next(&p->l);
3659}
3660
3661static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3662{
3663 BcStatus s;
3664 bool comma = false;
3665 size_t nparams;
3666
3667 s = bc_lex_next(&p->l);
3668 if (s) return s;
3669
3670 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3671
3672 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3673 s = bc_parse_expr(p, flags, bc_parse_next_param);
3674 if (s) return s;
3675
3676 comma = p->l.t.t == BC_LEX_COMMA;
3677 if (comma) {
3678 s = bc_lex_next(&p->l);
3679 if (s) return s;
3680 }
3681 }
3682
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003683 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003684 bc_parse_push(p, BC_INST_CALL);
3685 bc_parse_pushIndex(p, nparams);
3686
3687 return BC_STATUS_SUCCESS;
3688}
3689
3690static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3691{
3692 BcStatus s;
3693 BcId entry, *entry_ptr;
3694 size_t idx;
3695
3696 entry.name = name;
3697
3698 s = bc_parse_params(p, flags);
3699 if (s) goto err;
3700
3701 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003702 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003703 goto err;
3704 }
3705
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003706 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003707
3708 if (idx == BC_VEC_INVALID_IDX) {
3709 name = xstrdup(entry.name);
3710 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003711 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003712 free(entry.name);
3713 }
3714 else
3715 free(name);
3716
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003717 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003718 bc_parse_pushIndex(p, entry_ptr->idx);
3719
3720 return bc_lex_next(&p->l);
3721
3722err:
3723 free(name);
3724 return s;
3725}
3726
3727static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3728{
3729 BcStatus s;
3730 char *name;
3731
3732 name = xstrdup(p->l.t.v.v);
3733 s = bc_lex_next(&p->l);
3734 if (s) goto err;
3735
3736 if (p->l.t.t == BC_LEX_LBRACKET) {
3737
3738 s = bc_lex_next(&p->l);
3739 if (s) goto err;
3740
3741 if (p->l.t.t == BC_LEX_RBRACKET) {
3742
3743 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003744 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003745 goto err;
3746 }
3747
3748 *type = BC_INST_ARRAY;
3749 }
3750 else {
3751
3752 *type = BC_INST_ARRAY_ELEM;
3753
3754 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3755 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3756 if (s) goto err;
3757 }
3758
3759 s = bc_lex_next(&p->l);
3760 if (s) goto err;
3761 bc_parse_push(p, *type);
3762 bc_parse_pushName(p, name);
3763 }
3764 else if (p->l.t.t == BC_LEX_LPAREN) {
3765
3766 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003767 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003768 goto err;
3769 }
3770
3771 *type = BC_INST_CALL;
3772 s = bc_parse_call(p, name, flags);
3773 }
3774 else {
3775 *type = BC_INST_VAR;
3776 bc_parse_push(p, BC_INST_VAR);
3777 bc_parse_pushName(p, name);
3778 }
3779
3780 return s;
3781
3782err:
3783 free(name);
3784 return s;
3785}
3786
3787static BcStatus bc_parse_read(BcParse *p)
3788{
3789 BcStatus s;
3790
3791 s = bc_lex_next(&p->l);
3792 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003793 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003794
3795 s = bc_lex_next(&p->l);
3796 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003797 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003798
3799 bc_parse_push(p, BC_INST_READ);
3800
3801 return bc_lex_next(&p->l);
3802}
3803
3804static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3805 BcInst *prev)
3806{
3807 BcStatus s;
3808
3809 s = bc_lex_next(&p->l);
3810 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003811 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003812
3813 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3814
3815 s = bc_lex_next(&p->l);
3816 if (s) return s;
3817
3818 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3819 if (s) return s;
3820
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003821 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003822
3823 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3824 bc_parse_push(p, *prev);
3825
3826 return bc_lex_next(&p->l);
3827}
3828
3829static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3830{
3831 BcStatus s;
3832
3833 s = bc_lex_next(&p->l);
3834 if (s) return s;
3835
3836 if (p->l.t.t != BC_LEX_LPAREN) {
3837 *type = BC_INST_SCALE;
3838 bc_parse_push(p, BC_INST_SCALE);
3839 return BC_STATUS_SUCCESS;
3840 }
3841
3842 *type = BC_INST_SCALE_FUNC;
3843 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3844
3845 s = bc_lex_next(&p->l);
3846 if (s) return s;
3847
3848 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3849 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003850 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003851 bc_parse_push(p, BC_INST_SCALE_FUNC);
3852
3853 return bc_lex_next(&p->l);
3854}
3855
3856static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3857 size_t *nexprs, uint8_t flags)
3858{
3859 BcStatus s;
3860 BcLexType type;
3861 char inst;
3862 BcInst etype = *prev;
3863
3864 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3865 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3866 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3867 {
3868 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3869 bc_parse_push(p, inst);
3870 s = bc_lex_next(&p->l);
3871 }
3872 else {
3873
3874 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3875 *paren_expr = true;
3876
3877 s = bc_lex_next(&p->l);
3878 if (s) return s;
3879 type = p->l.t.t;
3880
3881 // Because we parse the next part of the expression
3882 // right here, we need to increment this.
3883 *nexprs = *nexprs + 1;
3884
3885 switch (type) {
3886
3887 case BC_LEX_NAME:
3888 {
3889 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3890 break;
3891 }
3892
3893 case BC_LEX_KEY_IBASE:
3894 case BC_LEX_KEY_LAST:
3895 case BC_LEX_KEY_OBASE:
3896 {
3897 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3898 s = bc_lex_next(&p->l);
3899 break;
3900 }
3901
3902 case BC_LEX_KEY_SCALE:
3903 {
3904 s = bc_lex_next(&p->l);
3905 if (s) return s;
3906 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003907 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003908 else
3909 bc_parse_push(p, BC_INST_SCALE);
3910 break;
3911 }
3912
3913 default:
3914 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003915 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003916 break;
3917 }
3918 }
3919
3920 if (!s) bc_parse_push(p, inst);
3921 }
3922
3923 return s;
3924}
3925
3926static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3927 bool rparen, size_t *nexprs)
3928{
3929 BcStatus s;
3930 BcLexType type;
3931 BcInst etype = *prev;
3932
3933 s = bc_lex_next(&p->l);
3934 if (s) return s;
3935
3936 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3937 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3938 BC_LEX_OP_MINUS :
3939 BC_LEX_NEG;
3940 *prev = BC_PARSE_TOKEN_INST(type);
3941
3942 // We can just push onto the op stack because this is the largest
3943 // precedence operator that gets pushed. Inc/dec does not.
3944 if (type != BC_LEX_OP_MINUS)
3945 bc_vec_push(&p->ops, &type);
3946 else
3947 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3948
3949 return s;
3950}
3951
3952static BcStatus bc_parse_string(BcParse *p, char inst)
3953{
3954 char *str = xstrdup(p->l.t.v.v);
3955
3956 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003957 bc_parse_pushIndex(p, G.prog.strs.len);
3958 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003959 bc_parse_push(p, inst);
3960
3961 return bc_lex_next(&p->l);
3962}
3963
3964static BcStatus bc_parse_print(BcParse *p)
3965{
3966 BcStatus s;
3967 BcLexType type;
3968 bool comma = false;
3969
3970 s = bc_lex_next(&p->l);
3971 if (s) return s;
3972
3973 type = p->l.t.t;
3974
3975 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003976 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003977
3978 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3979
3980 if (type == BC_LEX_STR)
3981 s = bc_parse_string(p, BC_INST_PRINT_POP);
3982 else {
3983 s = bc_parse_expr(p, 0, bc_parse_next_print);
3984 if (s) return s;
3985 bc_parse_push(p, BC_INST_PRINT_POP);
3986 }
3987
3988 if (s) return s;
3989
3990 comma = p->l.t.t == BC_LEX_COMMA;
3991 if (comma) s = bc_lex_next(&p->l);
3992 type = p->l.t.t;
3993 }
3994
3995 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003996 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003997
3998 return bc_lex_next(&p->l);
3999}
4000
4001static BcStatus bc_parse_return(BcParse *p)
4002{
4003 BcStatus s;
4004 BcLexType t;
4005 bool paren;
4006
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004007 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004008
4009 s = bc_lex_next(&p->l);
4010 if (s) return s;
4011
4012 t = p->l.t.t;
4013 paren = t == BC_LEX_LPAREN;
4014
4015 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4016 bc_parse_push(p, BC_INST_RET0);
4017 else {
4018
4019 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4020 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4021 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004022
4023 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004024 bc_parse_push(p, BC_INST_RET0);
4025 s = bc_lex_next(&p->l);
4026 if (s) return s;
4027 }
4028
4029 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004030 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004031 if (s) return s;
4032 }
4033
4034 bc_parse_push(p, BC_INST_RET);
4035 }
4036
4037 return s;
4038}
4039
4040static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4041{
4042 BcStatus s = BC_STATUS_SUCCESS;
4043
4044 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004045 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004046
4047 if (brace) {
4048
4049 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004050 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004051 --p->nbraces;
4052 s = bc_lex_next(&p->l);
4053 if (s) return s;
4054 }
4055 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004056 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004057 }
4058
4059 if (BC_PARSE_IF(p)) {
4060
4061 uint8_t *flag_ptr;
4062
4063 while (p->l.t.t == BC_LEX_NLINE) {
4064 s = bc_lex_next(&p->l);
4065 if (s) return s;
4066 }
4067
4068 bc_vec_pop(&p->flags);
4069
4070 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4071 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4072
4073 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4074 }
4075 else if (BC_PARSE_ELSE(p)) {
4076
4077 BcInstPtr *ip;
4078 size_t *label;
4079
4080 bc_vec_pop(&p->flags);
4081
4082 ip = bc_vec_top(&p->exits);
4083 label = bc_vec_item(&p->func->labels, ip->idx);
4084 *label = p->func->code.len;
4085
4086 bc_vec_pop(&p->exits);
4087 }
4088 else if (BC_PARSE_FUNC_INNER(p)) {
4089 bc_parse_push(p, BC_INST_RET0);
4090 bc_parse_updateFunc(p, BC_PROG_MAIN);
4091 bc_vec_pop(&p->flags);
4092 }
4093 else {
4094
4095 BcInstPtr *ip = bc_vec_top(&p->exits);
4096 size_t *label = bc_vec_top(&p->conds);
4097
4098 bc_parse_push(p, BC_INST_JUMP);
4099 bc_parse_pushIndex(p, *label);
4100
4101 label = bc_vec_item(&p->func->labels, ip->idx);
4102 *label = p->func->code.len;
4103
4104 bc_vec_pop(&p->flags);
4105 bc_vec_pop(&p->exits);
4106 bc_vec_pop(&p->conds);
4107 }
4108
4109 return s;
4110}
4111
4112static void bc_parse_startBody(BcParse *p, uint8_t flags)
4113{
4114 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4115 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4116 flags |= BC_PARSE_FLAG_BODY;
4117 bc_vec_push(&p->flags, &flags);
4118}
4119
4120static void bc_parse_noElse(BcParse *p)
4121{
4122 BcInstPtr *ip;
4123 size_t *label;
4124 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4125
4126 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4127
4128 ip = bc_vec_top(&p->exits);
4129 label = bc_vec_item(&p->func->labels, ip->idx);
4130 *label = p->func->code.len;
4131
4132 bc_vec_pop(&p->exits);
4133}
4134
4135static BcStatus bc_parse_if(BcParse *p)
4136{
4137 BcStatus s;
4138 BcInstPtr ip;
4139
4140 s = bc_lex_next(&p->l);
4141 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004142 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004143
4144 s = bc_lex_next(&p->l);
4145 if (s) return s;
4146 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4147 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004148 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004149
4150 s = bc_lex_next(&p->l);
4151 if (s) return s;
4152 bc_parse_push(p, BC_INST_JUMP_ZERO);
4153
4154 ip.idx = p->func->labels.len;
4155 ip.func = ip.len = 0;
4156
4157 bc_parse_pushIndex(p, ip.idx);
4158 bc_vec_push(&p->exits, &ip);
4159 bc_vec_push(&p->func->labels, &ip.idx);
4160 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4161
4162 return BC_STATUS_SUCCESS;
4163}
4164
4165static BcStatus bc_parse_else(BcParse *p)
4166{
4167 BcInstPtr ip;
4168
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004169 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004170
4171 ip.idx = p->func->labels.len;
4172 ip.func = ip.len = 0;
4173
4174 bc_parse_push(p, BC_INST_JUMP);
4175 bc_parse_pushIndex(p, ip.idx);
4176
4177 bc_parse_noElse(p);
4178
4179 bc_vec_push(&p->exits, &ip);
4180 bc_vec_push(&p->func->labels, &ip.idx);
4181 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4182
4183 return bc_lex_next(&p->l);
4184}
4185
4186static BcStatus bc_parse_while(BcParse *p)
4187{
4188 BcStatus s;
4189 BcInstPtr ip;
4190
4191 s = bc_lex_next(&p->l);
4192 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004193 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004194 s = bc_lex_next(&p->l);
4195 if (s) return s;
4196
4197 ip.idx = p->func->labels.len;
4198
4199 bc_vec_push(&p->func->labels, &p->func->code.len);
4200 bc_vec_push(&p->conds, &ip.idx);
4201
4202 ip.idx = p->func->labels.len;
4203 ip.func = 1;
4204 ip.len = 0;
4205
4206 bc_vec_push(&p->exits, &ip);
4207 bc_vec_push(&p->func->labels, &ip.idx);
4208
4209 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4210 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004211 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004212 s = bc_lex_next(&p->l);
4213 if (s) return s;
4214
4215 bc_parse_push(p, BC_INST_JUMP_ZERO);
4216 bc_parse_pushIndex(p, ip.idx);
4217 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4218
4219 return BC_STATUS_SUCCESS;
4220}
4221
4222static BcStatus bc_parse_for(BcParse *p)
4223{
4224 BcStatus s;
4225 BcInstPtr ip;
4226 size_t cond_idx, exit_idx, body_idx, update_idx;
4227
4228 s = bc_lex_next(&p->l);
4229 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004230 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004231 s = bc_lex_next(&p->l);
4232 if (s) return s;
4233
4234 if (p->l.t.t != BC_LEX_SCOLON)
4235 s = bc_parse_expr(p, 0, bc_parse_next_for);
4236 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004237 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
Gavin Howard01055ba2018-11-03 11:00:21 -06004238
4239 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004240 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004241 s = bc_lex_next(&p->l);
4242 if (s) return s;
4243
4244 cond_idx = p->func->labels.len;
4245 update_idx = cond_idx + 1;
4246 body_idx = update_idx + 1;
4247 exit_idx = body_idx + 1;
4248
4249 bc_vec_push(&p->func->labels, &p->func->code.len);
4250
4251 if (p->l.t.t != BC_LEX_SCOLON)
4252 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4253 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004254 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004255
4256 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004257 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004258
4259 s = bc_lex_next(&p->l);
4260 if (s) return s;
4261
4262 bc_parse_push(p, BC_INST_JUMP_ZERO);
4263 bc_parse_pushIndex(p, exit_idx);
4264 bc_parse_push(p, BC_INST_JUMP);
4265 bc_parse_pushIndex(p, body_idx);
4266
4267 ip.idx = p->func->labels.len;
4268
4269 bc_vec_push(&p->conds, &update_idx);
4270 bc_vec_push(&p->func->labels, &p->func->code.len);
4271
4272 if (p->l.t.t != BC_LEX_RPAREN)
4273 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4274 else
Denys Vlasenko00646792018-12-05 18:12:27 +01004275 s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
Gavin Howard01055ba2018-11-03 11:00:21 -06004276
4277 if (s) return s;
4278
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004279 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004280 bc_parse_push(p, BC_INST_JUMP);
4281 bc_parse_pushIndex(p, cond_idx);
4282 bc_vec_push(&p->func->labels, &p->func->code.len);
4283
4284 ip.idx = exit_idx;
4285 ip.func = 1;
4286 ip.len = 0;
4287
4288 bc_vec_push(&p->exits, &ip);
4289 bc_vec_push(&p->func->labels, &ip.idx);
4290 bc_lex_next(&p->l);
4291 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4292
4293 return BC_STATUS_SUCCESS;
4294}
4295
4296static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4297{
4298 BcStatus s;
4299 size_t i;
4300 BcInstPtr *ip;
4301
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004302 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004303
4304 if (type == BC_LEX_KEY_BREAK) {
4305
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004306 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004307
4308 i = p->exits.len - 1;
4309 ip = bc_vec_item(&p->exits, i);
4310
4311 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004312 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004313
4314 i = ip->idx;
4315 }
4316 else
4317 i = *((size_t *) bc_vec_top(&p->conds));
4318
4319 bc_parse_push(p, BC_INST_JUMP);
4320 bc_parse_pushIndex(p, i);
4321
4322 s = bc_lex_next(&p->l);
4323 if (s) return s;
4324
4325 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004326 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004327
4328 return bc_lex_next(&p->l);
4329}
4330
4331static BcStatus bc_parse_func(BcParse *p)
4332{
4333 BcStatus s;
4334 bool var, comma = false;
4335 uint8_t flags;
4336 char *name;
4337
4338 s = bc_lex_next(&p->l);
4339 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004340 if (p->l.t.t != BC_LEX_NAME)
4341 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004342
4343 name = xstrdup(p->l.t.v.v);
4344 bc_parse_addFunc(p, name, &p->fidx);
4345
4346 s = bc_lex_next(&p->l);
4347 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004348 if (p->l.t.t != BC_LEX_LPAREN)
4349 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004350 s = bc_lex_next(&p->l);
4351 if (s) return s;
4352
4353 while (p->l.t.t != BC_LEX_RPAREN) {
4354
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004355 if (p->l.t.t != BC_LEX_NAME)
4356 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004357
4358 ++p->func->nparams;
4359
4360 name = xstrdup(p->l.t.v.v);
4361 s = bc_lex_next(&p->l);
4362 if (s) goto err;
4363
4364 var = p->l.t.t != BC_LEX_LBRACKET;
4365
4366 if (!var) {
4367
4368 s = bc_lex_next(&p->l);
4369 if (s) goto err;
4370
4371 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004372 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004373 goto err;
4374 }
4375
4376 s = bc_lex_next(&p->l);
4377 if (s) goto err;
4378 }
4379
4380 comma = p->l.t.t == BC_LEX_COMMA;
4381 if (comma) {
4382 s = bc_lex_next(&p->l);
4383 if (s) goto err;
4384 }
4385
4386 s = bc_func_insert(p->func, name, var);
4387 if (s) goto err;
4388 }
4389
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004390 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004391
4392 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4393 bc_parse_startBody(p, flags);
4394
4395 s = bc_lex_next(&p->l);
4396 if (s) return s;
4397
4398 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004399 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
Gavin Howard01055ba2018-11-03 11:00:21 -06004400
4401 return s;
4402
4403err:
4404 free(name);
4405 return s;
4406}
4407
4408static BcStatus bc_parse_auto(BcParse *p)
4409{
4410 BcStatus s;
4411 bool comma, var, one;
4412 char *name;
4413
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004414 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004415 s = bc_lex_next(&p->l);
4416 if (s) return s;
4417
4418 p->auto_part = comma = false;
4419 one = p->l.t.t == BC_LEX_NAME;
4420
4421 while (p->l.t.t == BC_LEX_NAME) {
4422
4423 name = xstrdup(p->l.t.v.v);
4424 s = bc_lex_next(&p->l);
4425 if (s) goto err;
4426
4427 var = p->l.t.t != BC_LEX_LBRACKET;
4428 if (!var) {
4429
4430 s = bc_lex_next(&p->l);
4431 if (s) goto err;
4432
4433 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004434 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004435 goto err;
4436 }
4437
4438 s = bc_lex_next(&p->l);
4439 if (s) goto err;
4440 }
4441
4442 comma = p->l.t.t == BC_LEX_COMMA;
4443 if (comma) {
4444 s = bc_lex_next(&p->l);
4445 if (s) goto err;
4446 }
4447
4448 s = bc_func_insert(p->func, name, var);
4449 if (s) goto err;
4450 }
4451
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004452 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004453 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004454
4455 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004456 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004457
4458 return bc_lex_next(&p->l);
4459
4460err:
4461 free(name);
4462 return s;
4463}
4464
4465static BcStatus bc_parse_body(BcParse *p, bool brace)
4466{
4467 BcStatus s = BC_STATUS_SUCCESS;
4468 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4469
4470 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4471
4472 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4473
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004474 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004475 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4476
4477 if (!p->auto_part) {
4478 s = bc_parse_auto(p);
4479 if (s) return s;
4480 }
4481
4482 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4483 }
4484 else {
4485 s = bc_parse_stmt(p);
4486 if (!s && !brace) s = bc_parse_endBody(p, false);
4487 }
4488
4489 return s;
4490}
4491
4492static BcStatus bc_parse_stmt(BcParse *p)
4493{
4494 BcStatus s = BC_STATUS_SUCCESS;
4495
4496 switch (p->l.t.t) {
4497
4498 case BC_LEX_NLINE:
4499 {
4500 return bc_lex_next(&p->l);
4501 }
4502
4503 case BC_LEX_KEY_ELSE:
4504 {
4505 p->auto_part = false;
4506 break;
4507 }
4508
4509 case BC_LEX_LBRACE:
4510 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004511 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004512
4513 ++p->nbraces;
4514 s = bc_lex_next(&p->l);
4515 if (s) return s;
4516
4517 return bc_parse_body(p, true);
4518 }
4519
4520 case BC_LEX_KEY_AUTO:
4521 {
4522 return bc_parse_auto(p);
4523 }
4524
4525 default:
4526 {
4527 p->auto_part = false;
4528
4529 if (BC_PARSE_IF_END(p)) {
4530 bc_parse_noElse(p);
4531 return BC_STATUS_SUCCESS;
4532 }
4533 else if (BC_PARSE_BODY(p))
4534 return bc_parse_body(p, false);
4535
4536 break;
4537 }
4538 }
4539
4540 switch (p->l.t.t) {
4541
4542 case BC_LEX_OP_INC:
4543 case BC_LEX_OP_DEC:
4544 case BC_LEX_OP_MINUS:
4545 case BC_LEX_OP_BOOL_NOT:
4546 case BC_LEX_LPAREN:
4547 case BC_LEX_NAME:
4548 case BC_LEX_NUMBER:
4549 case BC_LEX_KEY_IBASE:
4550 case BC_LEX_KEY_LAST:
4551 case BC_LEX_KEY_LENGTH:
4552 case BC_LEX_KEY_OBASE:
4553 case BC_LEX_KEY_READ:
4554 case BC_LEX_KEY_SCALE:
4555 case BC_LEX_KEY_SQRT:
4556 {
4557 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4558 break;
4559 }
4560
4561 case BC_LEX_KEY_ELSE:
4562 {
4563 s = bc_parse_else(p);
4564 break;
4565 }
4566
4567 case BC_LEX_SCOLON:
4568 {
4569 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4570 break;
4571 }
4572
4573 case BC_LEX_RBRACE:
4574 {
4575 s = bc_parse_endBody(p, true);
4576 break;
4577 }
4578
4579 case BC_LEX_STR:
4580 {
4581 s = bc_parse_string(p, BC_INST_PRINT_STR);
4582 break;
4583 }
4584
4585 case BC_LEX_KEY_BREAK:
4586 case BC_LEX_KEY_CONTINUE:
4587 {
4588 s = bc_parse_loopExit(p, p->l.t.t);
4589 break;
4590 }
4591
4592 case BC_LEX_KEY_FOR:
4593 {
4594 s = bc_parse_for(p);
4595 break;
4596 }
4597
4598 case BC_LEX_KEY_HALT:
4599 {
4600 bc_parse_push(p, BC_INST_HALT);
4601 s = bc_lex_next(&p->l);
4602 break;
4603 }
4604
4605 case BC_LEX_KEY_IF:
4606 {
4607 s = bc_parse_if(p);
4608 break;
4609 }
4610
4611 case BC_LEX_KEY_LIMITS:
4612 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004613 // "limits" is a compile-time command,
4614 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004615 s = bc_lex_next(&p->l);
4616 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004617 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4618 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4619 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4620 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4621 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4622 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4623 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4624 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004625 break;
4626 }
4627
4628 case BC_LEX_KEY_PRINT:
4629 {
4630 s = bc_parse_print(p);
4631 break;
4632 }
4633
4634 case BC_LEX_KEY_QUIT:
4635 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004636 // "quit" is a compile-time command. For example,
4637 // "if (0 == 1) quit" terminates when parsing the statement,
4638 // not when it is executed
4639 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004640 }
4641
4642 case BC_LEX_KEY_RETURN:
4643 {
4644 s = bc_parse_return(p);
4645 break;
4646 }
4647
4648 case BC_LEX_KEY_WHILE:
4649 {
4650 s = bc_parse_while(p);
4651 break;
4652 }
4653
4654 default:
4655 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004656 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004657 break;
4658 }
4659 }
4660
4661 return s;
4662}
4663
4664static BcStatus bc_parse_parse(BcParse *p)
4665{
4666 BcStatus s;
4667
4668 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004669 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 -06004670 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004671 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004672 s = bc_parse_func(p);
4673 }
4674 else
4675 s = bc_parse_stmt(p);
4676
Denys Vlasenkod38af482018-12-04 19:11:02 +01004677 if (s || G_interrupt) {
4678 bc_parse_reset(p);
4679 s = BC_STATUS_FAILURE;
4680 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004681
4682 return s;
4683}
4684
4685static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4686{
4687 BcStatus s = BC_STATUS_SUCCESS;
4688 BcInst prev = BC_INST_PRINT;
4689 BcLexType top, t = p->l.t.t;
4690 size_t nexprs = 0, ops_bgn = p->ops.len;
4691 uint32_t i, nparens, nrelops;
4692 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4693
4694 paren_first = p->l.t.t == BC_LEX_LPAREN;
4695 nparens = nrelops = 0;
4696 paren_expr = rprn = done = get_token = assign = false;
4697 bin_last = true;
4698
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004699 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004700 switch (t) {
4701
4702 case BC_LEX_OP_INC:
4703 case BC_LEX_OP_DEC:
4704 {
4705 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4706 rprn = get_token = bin_last = false;
4707 break;
4708 }
4709
4710 case BC_LEX_OP_MINUS:
4711 {
4712 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4713 rprn = get_token = false;
4714 bin_last = prev == BC_INST_MINUS;
4715 break;
4716 }
4717
4718 case BC_LEX_OP_ASSIGN_POWER:
4719 case BC_LEX_OP_ASSIGN_MULTIPLY:
4720 case BC_LEX_OP_ASSIGN_DIVIDE:
4721 case BC_LEX_OP_ASSIGN_MODULUS:
4722 case BC_LEX_OP_ASSIGN_PLUS:
4723 case BC_LEX_OP_ASSIGN_MINUS:
4724 case BC_LEX_OP_ASSIGN:
4725 {
4726 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4727 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4728 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4729 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004730 s = bc_error("bad assignment:"
4731 " left side must be scale,"
4732 " ibase, obase, last, var,"
4733 " or array element"
4734 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004735 break;
4736 }
4737 }
4738 // Fallthrough.
4739 case BC_LEX_OP_POWER:
4740 case BC_LEX_OP_MULTIPLY:
4741 case BC_LEX_OP_DIVIDE:
4742 case BC_LEX_OP_MODULUS:
4743 case BC_LEX_OP_PLUS:
4744 case BC_LEX_OP_REL_EQ:
4745 case BC_LEX_OP_REL_LE:
4746 case BC_LEX_OP_REL_GE:
4747 case BC_LEX_OP_REL_NE:
4748 case BC_LEX_OP_REL_LT:
4749 case BC_LEX_OP_REL_GT:
4750 case BC_LEX_OP_BOOL_NOT:
4751 case BC_LEX_OP_BOOL_OR:
4752 case BC_LEX_OP_BOOL_AND:
4753 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004754 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4755 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4756 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004757 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004758 }
4759
4760 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4761 prev = BC_PARSE_TOKEN_INST(t);
4762 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4763 rprn = get_token = false;
4764 bin_last = t != BC_LEX_OP_BOOL_NOT;
4765
4766 break;
4767 }
4768
4769 case BC_LEX_LPAREN:
4770 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004771 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004772 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004773 ++nparens;
4774 paren_expr = rprn = bin_last = false;
4775 get_token = true;
4776 bc_vec_push(&p->ops, &t);
4777
4778 break;
4779 }
4780
4781 case BC_LEX_RPAREN:
4782 {
4783 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004784 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004785
4786 if (nparens == 0) {
4787 s = BC_STATUS_SUCCESS;
4788 done = true;
4789 get_token = false;
4790 break;
4791 }
4792 else if (!paren_expr)
4793 return BC_STATUS_PARSE_EMPTY_EXP;
4794
4795 --nparens;
4796 paren_expr = rprn = true;
4797 get_token = bin_last = false;
4798
4799 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4800
4801 break;
4802 }
4803
4804 case BC_LEX_NAME:
4805 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004806 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004807 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004808 paren_expr = true;
4809 rprn = get_token = bin_last = false;
4810 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4811 ++nexprs;
4812
4813 break;
4814 }
4815
4816 case BC_LEX_NUMBER:
4817 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004818 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004819 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004820 bc_parse_number(p, &prev, &nexprs);
4821 paren_expr = get_token = true;
4822 rprn = bin_last = false;
4823
4824 break;
4825 }
4826
4827 case BC_LEX_KEY_IBASE:
4828 case BC_LEX_KEY_LAST:
4829 case BC_LEX_KEY_OBASE:
4830 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004831 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004832 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004833 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4834 bc_parse_push(p, (char) prev);
4835
4836 paren_expr = get_token = true;
4837 rprn = bin_last = false;
4838 ++nexprs;
4839
4840 break;
4841 }
4842
4843 case BC_LEX_KEY_LENGTH:
4844 case BC_LEX_KEY_SQRT:
4845 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004846 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004847 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004848 s = bc_parse_builtin(p, t, flags, &prev);
4849 paren_expr = true;
4850 rprn = get_token = bin_last = false;
4851 ++nexprs;
4852
4853 break;
4854 }
4855
4856 case BC_LEX_KEY_READ:
4857 {
4858 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004859 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004860 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004861 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06004862 else
4863 s = bc_parse_read(p);
4864
4865 paren_expr = true;
4866 rprn = get_token = bin_last = false;
4867 ++nexprs;
4868 prev = BC_INST_READ;
4869
4870 break;
4871 }
4872
4873 case BC_LEX_KEY_SCALE:
4874 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004875 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004876 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004877 s = bc_parse_scale(p, &prev, flags);
4878 paren_expr = true;
4879 rprn = get_token = bin_last = false;
4880 ++nexprs;
4881 prev = BC_INST_SCALE;
4882
4883 break;
4884 }
4885
4886 default:
4887 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004888 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004889 break;
4890 }
4891 }
4892
4893 if (!s && get_token) s = bc_lex_next(&p->l);
4894 }
4895
4896 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004897 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004898
4899 while (p->ops.len > ops_bgn) {
4900
4901 top = BC_PARSE_TOP_OP(p);
4902 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4903
4904 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004905 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004906
4907 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4908
4909 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4910 bc_vec_pop(&p->ops);
4911 }
4912
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004913 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004914 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004915
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004916 for (i = 0; i < next.len; ++i)
4917 if (t == next.tokens[i])
4918 goto ok;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004919 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004920 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004921
4922 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko00646792018-12-05 18:12:27 +01004923 s = bc_POSIX_does_not_allow("comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004924 if (s) return s;
4925 }
4926 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004927 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004928 if (s) return s;
4929 }
4930
4931 if (flags & BC_PARSE_PRINT) {
4932 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4933 bc_parse_push(p, BC_INST_POP);
4934 }
4935
4936 return s;
4937}
4938
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004939static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004940{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004941 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004942}
4943
4944static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4945{
4946 return bc_parse_expr(p, flags, bc_parse_next_read);
4947}
4948#endif // ENABLE_BC
4949
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004950#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004951static BcStatus dc_parse_register(BcParse *p)
4952{
4953 BcStatus s;
4954 char *name;
4955
4956 s = bc_lex_next(&p->l);
4957 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004958 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004959
4960 name = xstrdup(p->l.t.v.v);
4961 bc_parse_pushName(p, name);
4962
4963 return s;
4964}
4965
4966static BcStatus dc_parse_string(BcParse *p)
4967{
4968 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004969 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004970
4971 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4972 name = xstrdup(b);
4973
4974 str = xstrdup(p->l.t.v.v);
4975 bc_parse_push(p, BC_INST_STR);
4976 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004977 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004978 bc_parse_addFunc(p, name, &idx);
4979
4980 return bc_lex_next(&p->l);
4981}
4982
4983static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4984{
4985 BcStatus s;
4986
4987 bc_parse_push(p, inst);
4988 if (name) {
4989 s = dc_parse_register(p);
4990 if (s) return s;
4991 }
4992
4993 if (store) {
4994 bc_parse_push(p, BC_INST_SWAP);
4995 bc_parse_push(p, BC_INST_ASSIGN);
4996 bc_parse_push(p, BC_INST_POP);
4997 }
4998
4999 return bc_lex_next(&p->l);
5000}
5001
5002static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5003{
5004 BcStatus s;
5005
5006 bc_parse_push(p, inst);
5007 bc_parse_push(p, BC_INST_EXEC_COND);
5008
5009 s = dc_parse_register(p);
5010 if (s) return s;
5011
5012 s = bc_lex_next(&p->l);
5013 if (s) return s;
5014
5015 if (p->l.t.t == BC_LEX_ELSE) {
5016 s = dc_parse_register(p);
5017 if (s) return s;
5018 s = bc_lex_next(&p->l);
5019 }
5020 else
5021 bc_parse_push(p, BC_PARSE_STREND);
5022
5023 return s;
5024}
5025
5026static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5027{
5028 BcStatus s = BC_STATUS_SUCCESS;
5029 BcInst prev;
5030 uint8_t inst;
5031 bool assign, get_token = false;
5032
5033 switch (t) {
5034
5035 case BC_LEX_OP_REL_EQ:
5036 case BC_LEX_OP_REL_LE:
5037 case BC_LEX_OP_REL_GE:
5038 case BC_LEX_OP_REL_NE:
5039 case BC_LEX_OP_REL_LT:
5040 case BC_LEX_OP_REL_GT:
5041 {
5042 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5043 break;
5044 }
5045
5046 case BC_LEX_SCOLON:
5047 case BC_LEX_COLON:
5048 {
5049 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5050 break;
5051 }
5052
5053 case BC_LEX_STR:
5054 {
5055 s = dc_parse_string(p);
5056 break;
5057 }
5058
5059 case BC_LEX_NEG:
5060 case BC_LEX_NUMBER:
5061 {
5062 if (t == BC_LEX_NEG) {
5063 s = bc_lex_next(&p->l);
5064 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005065 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005066 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005067 }
5068
5069 bc_parse_number(p, &prev, &p->nbraces);
5070
5071 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5072 get_token = true;
5073
5074 break;
5075 }
5076
5077 case BC_LEX_KEY_READ:
5078 {
5079 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005080 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005081 else
5082 bc_parse_push(p, BC_INST_READ);
5083 get_token = true;
5084 break;
5085 }
5086
5087 case BC_LEX_OP_ASSIGN:
5088 case BC_LEX_STORE_PUSH:
5089 {
5090 assign = t == BC_LEX_OP_ASSIGN;
5091 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5092 s = dc_parse_mem(p, inst, true, assign);
5093 break;
5094 }
5095
5096 case BC_LEX_LOAD:
5097 case BC_LEX_LOAD_POP:
5098 {
5099 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5100 s = dc_parse_mem(p, inst, true, false);
5101 break;
5102 }
5103
5104 case BC_LEX_STORE_IBASE:
5105 case BC_LEX_STORE_SCALE:
5106 case BC_LEX_STORE_OBASE:
5107 {
5108 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5109 s = dc_parse_mem(p, inst, false, true);
5110 break;
5111 }
5112
5113 default:
5114 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005115 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005116 get_token = true;
5117 break;
5118 }
5119 }
5120
5121 if (!s && get_token) s = bc_lex_next(&p->l);
5122
5123 return s;
5124}
5125
5126static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5127{
5128 BcStatus s = BC_STATUS_SUCCESS;
5129 BcInst inst;
5130 BcLexType t;
5131
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005132 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005133
5134 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5135
5136 inst = dc_parse_insts[t];
5137
5138 if (inst != BC_INST_INVALID) {
5139 bc_parse_push(p, inst);
5140 s = bc_lex_next(&p->l);
5141 }
5142 else
5143 s = dc_parse_token(p, t, flags);
5144 }
5145
5146 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5147 bc_parse_push(p, BC_INST_POP_EXEC);
5148
5149 return s;
5150}
5151
5152static BcStatus dc_parse_parse(BcParse *p)
5153{
5154 BcStatus s;
5155
5156 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005157 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005158 else
5159 s = dc_parse_expr(p, 0);
5160
Denys Vlasenkod38af482018-12-04 19:11:02 +01005161 if (s || G_interrupt) {
5162 bc_parse_reset(p);
5163 s = BC_STATUS_FAILURE;
5164 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005165
5166 return s;
5167}
5168
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005169static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005170{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005171 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005172}
5173#endif // ENABLE_DC
5174
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005175static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005176{
5177 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005178 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005179 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005180 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005181 }
5182}
5183
5184static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5185{
5186 if (IS_BC) {
5187 return bc_parse_expression(p, flags);
5188 } else {
5189 return dc_parse_expr(p, flags);
5190 }
5191}
5192
Denys Vlasenkodf515392018-12-02 19:27:48 +01005193static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005194{
Gavin Howard01055ba2018-11-03 11:00:21 -06005195 BcId e, *ptr;
5196 BcVec *v, *map;
5197 size_t i;
5198 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005199 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005200
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005201 v = var ? &G.prog.vars : &G.prog.arrs;
5202 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005203
5204 e.name = id;
5205 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005206 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005207
5208 if (new) {
5209 bc_array_init(&data.v, var);
5210 bc_vec_push(v, &data.v);
5211 }
5212
5213 ptr = bc_vec_item(map, i);
5214 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005215 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005216}
5217
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005218static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005219{
5220 BcStatus s = BC_STATUS_SUCCESS;
5221
5222 switch (r->t) {
5223
5224 case BC_RESULT_STR:
5225 case BC_RESULT_TEMP:
5226 case BC_RESULT_IBASE:
5227 case BC_RESULT_SCALE:
5228 case BC_RESULT_OBASE:
5229 {
5230 *num = &r->d.n;
5231 break;
5232 }
5233
5234 case BC_RESULT_CONSTANT:
5235 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005236 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005237 size_t base_t, len = strlen(*str);
5238 BcNum *base;
5239
5240 bc_num_init(&r->d.n, len);
5241
5242 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005243 base = hex ? &G.prog.hexb : &G.prog.ib;
5244 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005245 s = bc_num_parse(&r->d.n, *str, base, base_t);
5246
5247 if (s) {
5248 bc_num_free(&r->d.n);
5249 return s;
5250 }
5251
5252 *num = &r->d.n;
5253 r->t = BC_RESULT_TEMP;
5254
5255 break;
5256 }
5257
5258 case BC_RESULT_VAR:
5259 case BC_RESULT_ARRAY:
5260 case BC_RESULT_ARRAY_ELEM:
5261 {
5262 BcVec *v;
5263
Denys Vlasenkodf515392018-12-02 19:27:48 +01005264 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005265
5266 if (r->t == BC_RESULT_ARRAY_ELEM) {
5267 v = bc_vec_top(v);
5268 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5269 *num = bc_vec_item(v, r->d.id.idx);
5270 }
5271 else
5272 *num = bc_vec_top(v);
5273
5274 break;
5275 }
5276
5277 case BC_RESULT_LAST:
5278 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005279 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005280 break;
5281 }
5282
5283 case BC_RESULT_ONE:
5284 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005285 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005286 break;
5287 }
5288 }
5289
5290 return s;
5291}
5292
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005293static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005294 BcResult **r, BcNum **rn, bool assign)
5295{
5296 BcStatus s;
5297 bool hex;
5298 BcResultType lt, rt;
5299
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005300 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005301 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005302
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005303 *r = bc_vec_item_rev(&G.prog.results, 0);
5304 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005305
5306 lt = (*l)->t;
5307 rt = (*r)->t;
5308 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5309
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005310 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005311 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005312 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005313 if (s) return s;
5314
5315 // We run this again under these conditions in case any vector has been
5316 // reallocated out from under the BcNums or arrays we had.
5317 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005318 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005319 if (s) return s;
5320 }
5321
5322 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005323 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005324 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005325 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005326
Gavin Howard01055ba2018-11-03 11:00:21 -06005327 return s;
5328}
5329
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005330static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005331{
5332 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005333 bc_vec_pop(&G.prog.results);
5334 bc_vec_pop(&G.prog.results);
5335 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005336}
5337
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005338static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005339{
5340 BcStatus s;
5341
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005342 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005343 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005344 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005345
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005346 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005347 if (s) return s;
5348
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005349 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005350 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005351
5352 return s;
5353}
5354
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005355static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005356{
5357 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005358 bc_vec_pop(&G.prog.results);
5359 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005360}
5361
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005362static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005363{
5364 BcStatus s;
5365 BcResult *opd1, *opd2, res;
5366 BcNum *n1, *n2 = NULL;
5367
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005368 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005369 if (s) return s;
5370 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5371
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005372 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005373 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005374 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005375
5376 return s;
5377
5378err:
5379 bc_num_free(&res.d.n);
5380 return s;
5381}
5382
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005383static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005384{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005385 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005386 BcStatus s;
5387 BcParse parse;
5388 BcVec buf;
5389 BcInstPtr ip;
5390 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005391 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005392
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005393 for (i = 0; i < G.prog.stack.len; ++i) {
5394 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005395 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005396 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005397 }
5398
Denys Vlasenko7d628012018-12-04 21:46:47 +01005399 bc_vec_pop_all(&f->code);
5400 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005401
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005402 sv_file = G.prog.file;
5403 G.prog.file = NULL;
5404
Gavin Howard01055ba2018-11-03 11:00:21 -06005405 s = bc_read_line(&buf, "read> ");
5406 if (s) goto io_err;
5407
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005408 common_parse_init(&parse, BC_PROG_READ);
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005409 bc_lex_file(&parse.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005410
5411 s = bc_parse_text(&parse, buf.v);
5412 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005413 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005414 if (s) goto exec_err;
5415
5416 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005417 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005418 goto exec_err;
5419 }
5420
5421 ip.func = BC_PROG_READ;
5422 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005423 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005424
5425 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005426 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005427
5428 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005429 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005430
5431exec_err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005432 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005433 bc_parse_free(&parse);
5434io_err:
5435 bc_vec_free(&buf);
5436 return s;
5437}
5438
5439static size_t bc_program_index(char *code, size_t *bgn)
5440{
5441 char amt = code[(*bgn)++], i = 0;
5442 size_t res = 0;
5443
5444 for (; i < amt; ++i, ++(*bgn))
5445 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5446
5447 return res;
5448}
5449
5450static char *bc_program_name(char *code, size_t *bgn)
5451{
5452 size_t i;
5453 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5454
5455 s = xmalloc(ptr - str + 1);
5456 c = code[(*bgn)++];
5457
5458 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5459 s[i] = c;
5460
5461 s[i] = '\0';
5462
5463 return s;
5464}
5465
5466static void bc_program_printString(const char *str, size_t *nchars)
5467{
5468 size_t i, len = strlen(str);
5469
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005470#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005471 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005472 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005473 return;
5474 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005475#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005476
5477 for (i = 0; i < len; ++i, ++(*nchars)) {
5478
5479 int c = str[i];
5480
5481 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005482 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005483 else {
5484
5485 c = str[++i];
5486
5487 switch (c) {
5488
5489 case 'a':
5490 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005491 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005492 break;
5493 }
5494
5495 case 'b':
5496 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005497 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005498 break;
5499 }
5500
5501 case '\\':
5502 case 'e':
5503 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005504 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005505 break;
5506 }
5507
5508 case 'f':
5509 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005510 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005511 break;
5512 }
5513
5514 case 'n':
5515 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005516 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005517 *nchars = SIZE_MAX;
5518 break;
5519 }
5520
5521 case 'r':
5522 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005523 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005524 break;
5525 }
5526
5527 case 'q':
5528 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005529 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005530 break;
5531 }
5532
5533 case 't':
5534 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005535 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005536 break;
5537 }
5538
5539 default:
5540 {
5541 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005542 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005543 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005544 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005545 break;
5546 }
5547 }
5548 }
5549 }
5550}
5551
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005552static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005553{
5554 BcStatus s = BC_STATUS_SUCCESS;
5555 BcResult *r;
5556 size_t len, i;
5557 char *str;
5558 BcNum *num = NULL;
5559 bool pop = inst != BC_INST_PRINT;
5560
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005561 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005562 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005563
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005564 r = bc_vec_item_rev(&G.prog.results, idx);
5565 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005566 if (s) return s;
5567
5568 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005569 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5570 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005571 }
5572 else {
5573
5574 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005575 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005576
5577 if (inst == BC_INST_PRINT_STR) {
5578 for (i = 0, len = strlen(str); i < len; ++i) {
5579 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005580 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005581 if (c == '\n') G.prog.nchars = SIZE_MAX;
5582 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005583 }
5584 }
5585 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005586 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005587 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005588 }
5589 }
5590
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005591 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005592
5593 return s;
5594}
5595
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005596static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005597{
5598 BcStatus s;
5599 BcResult res, *ptr;
5600 BcNum *num = NULL;
5601
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005602 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005603 if (s) return s;
5604
5605 bc_num_init(&res.d.n, num->len);
5606 bc_num_copy(&res.d.n, num);
5607 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5608
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005609 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005610
5611 return s;
5612}
5613
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005614static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005615{
5616 BcStatus s;
5617 BcResult *opd1, *opd2, res;
5618 BcNum *n1, *n2;
5619 bool cond = 0;
5620 ssize_t cmp;
5621
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005622 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005623 if (s) return s;
5624 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5625
5626 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005627 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005628 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005629 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005630 else {
5631
5632 cmp = bc_num_cmp(n1, n2);
5633
5634 switch (inst) {
5635
5636 case BC_INST_REL_EQ:
5637 {
5638 cond = cmp == 0;
5639 break;
5640 }
5641
5642 case BC_INST_REL_LE:
5643 {
5644 cond = cmp <= 0;
5645 break;
5646 }
5647
5648 case BC_INST_REL_GE:
5649 {
5650 cond = cmp >= 0;
5651 break;
5652 }
5653
5654 case BC_INST_REL_NE:
5655 {
5656 cond = cmp != 0;
5657 break;
5658 }
5659
5660 case BC_INST_REL_LT:
5661 {
5662 cond = cmp < 0;
5663 break;
5664 }
5665
5666 case BC_INST_REL_GT:
5667 {
5668 cond = cmp > 0;
5669 break;
5670 }
5671 }
5672 }
5673
5674 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5675
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005676 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005677
5678 return s;
5679}
5680
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005681#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005682static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005683 bool push)
5684{
5685 BcNum n2;
5686 BcResult res;
5687
5688 memset(&n2, 0, sizeof(BcNum));
5689 n2.rdx = res.d.id.idx = r->d.id.idx;
5690 res.t = BC_RESULT_STR;
5691
5692 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005693 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005694 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005695 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005696 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005697 }
5698
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005699 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005700
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005701 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005702 bc_vec_push(v, &n2);
5703
5704 return BC_STATUS_SUCCESS;
5705}
5706#endif // ENABLE_DC
5707
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005708static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005709{
5710 BcStatus s;
5711 BcResult *ptr, r;
5712 BcVec *v;
5713 BcNum *n;
5714
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005715 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005716 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005717
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005718 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005719 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005720 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005721 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005722
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005723#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005724 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005725 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005726 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005727#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005728
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005729 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005730 if (s) return s;
5731
5732 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005733 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
5735 if (var) {
5736 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5737 bc_num_copy(&r.d.n, n);
5738 }
5739 else {
5740 bc_array_init(&r.d.v, true);
5741 bc_array_copy(&r.d.v, (BcVec *) n);
5742 }
5743
5744 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005745 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005746
5747 return s;
5748}
5749
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005750static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005751{
5752 BcStatus s;
5753 BcResult *left, *right, res;
5754 BcNum *l = NULL, *r = NULL;
5755 unsigned long val, max;
5756 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5757
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005758 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005759 if (s) return s;
5760
5761 ib = left->t == BC_RESULT_IBASE;
5762 sc = left->t == BC_RESULT_SCALE;
5763
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005764#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005765
5766 if (right->t == BC_RESULT_STR) {
5767
5768 BcVec *v;
5769
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005770 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005771 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005772 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005773
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005774 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005775 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005776#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005777
5778 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005779 return bc_error("bad assignment:"
5780 " left side must be scale,"
5781 " ibase, obase, last, var,"
5782 " or array element"
5783 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005784
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005785#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005786 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005787 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005788
5789 if (assign)
5790 bc_num_copy(l, r);
5791 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005792 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005793
5794 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005795#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005796 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005797#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005798
5799 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005800 static const char *const msg[] = {
5801 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5802 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5803 "?1", //BC_RESULT_LAST
5804 "?2", //BC_RESULT_CONSTANT
5805 "?3", //BC_RESULT_ONE
5806 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5807 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005808 size_t *ptr;
5809
5810 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005811 if (s)
5812 return s;
5813 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005814 if (sc) {
5815 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005816 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005817 }
5818 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005819 if (val < BC_NUM_MIN_BASE)
5820 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005821 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005822 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005823 }
5824
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005825 if (val > max)
5826 return bc_error(msg[s]);
5827 if (!sc)
5828 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005829
5830 *ptr = (size_t) val;
5831 s = BC_STATUS_SUCCESS;
5832 }
5833
5834 bc_num_init(&res.d.n, l->len);
5835 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005836 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005837
5838 return s;
5839}
5840
Denys Vlasenko416ce762018-12-02 20:57:17 +01005841#if !ENABLE_DC
5842#define bc_program_pushVar(code, bgn, pop, copy) \
5843 bc_program_pushVar(code, bgn)
5844// for bc, 'pop' and 'copy' are always false
5845#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005846static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005847 bool pop, bool copy)
5848{
5849 BcStatus s = BC_STATUS_SUCCESS;
5850 BcResult r;
5851 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005852
5853 r.t = BC_RESULT_VAR;
5854 r.d.id.name = name;
5855
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005856#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005857 {
5858 BcVec *v = bc_program_search(name, true);
5859 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005860
Denys Vlasenko416ce762018-12-02 20:57:17 +01005861 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005862
Denys Vlasenko416ce762018-12-02 20:57:17 +01005863 if (!BC_PROG_STACK(v, 2 - copy)) {
5864 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005865 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01005866 }
5867
Gavin Howard01055ba2018-11-03 11:00:21 -06005868 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005869 name = NULL;
5870
5871 if (!BC_PROG_STR(num)) {
5872
5873 r.t = BC_RESULT_TEMP;
5874
5875 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5876 bc_num_copy(&r.d.n, num);
5877 }
5878 else {
5879 r.t = BC_RESULT_STR;
5880 r.d.id.idx = num->rdx;
5881 }
5882
5883 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005884 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005885 }
5886#endif // ENABLE_DC
5887
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005888 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005889
5890 return s;
5891}
5892
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005893static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005894 char inst)
5895{
5896 BcStatus s = BC_STATUS_SUCCESS;
5897 BcResult r;
5898 BcNum *num;
5899
5900 r.d.id.name = bc_program_name(code, bgn);
5901
5902 if (inst == BC_INST_ARRAY) {
5903 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005904 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005905 }
5906 else {
5907
5908 BcResult *operand;
5909 unsigned long temp;
5910
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005911 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005912 if (s) goto err;
5913 s = bc_num_ulong(num, &temp);
5914 if (s) goto err;
5915
5916 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005917 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005918 goto err;
5919 }
5920
5921 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005922 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005923 }
5924
5925err:
5926 if (s) free(r.d.id.name);
5927 return s;
5928}
5929
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005930#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005931static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005932{
5933 BcStatus s;
5934 BcResult *ptr, res, copy;
5935 BcNum *num = NULL;
5936 char inst2 = inst;
5937
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005938 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005939 if (s) return s;
5940
5941 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5942 copy.t = BC_RESULT_TEMP;
5943 bc_num_init(&copy.d.n, num->len);
5944 bc_num_copy(&copy.d.n, num);
5945 }
5946
5947 res.t = BC_RESULT_ONE;
5948 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5949 BC_INST_ASSIGN_PLUS :
5950 BC_INST_ASSIGN_MINUS;
5951
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005952 bc_vec_push(&G.prog.results, &res);
5953 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005954
5955 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005956 bc_vec_pop(&G.prog.results);
5957 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005958 }
5959
5960 return s;
5961}
5962
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005963static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005964{
5965 BcStatus s = BC_STATUS_SUCCESS;
5966 BcInstPtr ip;
5967 size_t i, nparams = bc_program_index(code, idx);
5968 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005969 BcId *a;
5970 BcResultData param;
5971 BcResult *arg;
5972
5973 ip.idx = 0;
5974 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005975 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005976
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005977 if (func->code.len == 0) {
5978 return bc_error("undefined function");
5979 }
5980 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005981 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005982 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005983 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005984
5985 for (i = 0; i < nparams; ++i) {
5986
5987 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005988 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005989
5990 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005991 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005992
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005993 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005994 if (s) return s;
5995 }
5996
5997 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005998 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005999
6000 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006001 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006002
6003 if (a->idx) {
6004 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6005 bc_vec_push(v, &param.n);
6006 }
6007 else {
6008 bc_array_init(&param.v, true);
6009 bc_vec_push(v, &param.v);
6010 }
6011 }
6012
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006013 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006014
6015 return BC_STATUS_SUCCESS;
6016}
6017
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006018static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006019{
6020 BcStatus s;
6021 BcResult res;
6022 BcFunc *f;
6023 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006024 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006025
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006026 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006027 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006028
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006029 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006030 res.t = BC_RESULT_TEMP;
6031
6032 if (inst == BC_INST_RET) {
6033
6034 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006035 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006036
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006037 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006038 if (s) return s;
6039 bc_num_init(&res.d.n, num->len);
6040 bc_num_copy(&res.d.n, num);
6041 }
6042 else {
6043 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6044 bc_num_zero(&res.d.n);
6045 }
6046
6047 // We need to pop arguments as well, so this takes that into account.
6048 for (i = 0; i < f->autos.len; ++i) {
6049
6050 BcVec *v;
6051 BcId *a = bc_vec_item(&f->autos, i);
6052
Denys Vlasenkodf515392018-12-02 19:27:48 +01006053 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006054 bc_vec_pop(v);
6055 }
6056
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006057 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6058 bc_vec_push(&G.prog.results, &res);
6059 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006060
6061 return BC_STATUS_SUCCESS;
6062}
6063#endif // ENABLE_BC
6064
6065static unsigned long bc_program_scale(BcNum *n)
6066{
6067 return (unsigned long) n->rdx;
6068}
6069
6070static unsigned long bc_program_len(BcNum *n)
6071{
6072 unsigned long len = n->len;
6073 size_t i;
6074
6075 if (n->rdx != n->len) return len;
6076 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6077
6078 return len;
6079}
6080
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006081static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006082{
6083 BcStatus s;
6084 BcResult *opnd;
6085 BcNum *num = NULL;
6086 BcResult res;
6087 bool len = inst == BC_INST_LENGTH;
6088
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006089 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006090 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006091 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006092
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006093 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006094 if (s) return s;
6095
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006096#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006097 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006098 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006099#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006100
6101 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6102
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006103 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006104#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006105 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006106 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006107 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006108#endif
6109#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006110 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6111
6112 char **str;
6113 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6114
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006115 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006116 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006117 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006118#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006119 else {
6120 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006121 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006122 }
6123
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006124 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006125
6126 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006127}
6128
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006129#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006130static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006131{
6132 BcStatus s;
6133 BcResult *opd1, *opd2, res, res2;
6134 BcNum *n1, *n2 = NULL;
6135
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006136 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006137 if (s) return s;
6138
6139 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6140 bc_num_init(&res2.d.n, n2->len);
6141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006143 if (s) goto err;
6144
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006145 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006146 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006147 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006148
6149 return s;
6150
6151err:
6152 bc_num_free(&res2.d.n);
6153 bc_num_free(&res.d.n);
6154 return s;
6155}
6156
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006157static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006158{
6159 BcStatus s;
6160 BcResult *r1, *r2, *r3, res;
6161 BcNum *n1, *n2, *n3;
6162
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006163 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006164 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006165 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006166 if (s) return s;
6167
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006168 r1 = bc_vec_item_rev(&G.prog.results, 2);
6169 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006170 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006171 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006172 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006173
6174 // Make sure that the values have their pointers updated, if necessary.
6175 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6176
6177 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006178 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006179 if (s) return s;
6180 }
6181
6182 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006183 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006184 if (s) return s;
6185 }
6186 }
6187
6188 bc_num_init(&res.d.n, n3->len);
6189 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6190 if (s) goto err;
6191
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006192 bc_vec_pop(&G.prog.results);
6193 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006194
6195 return s;
6196
6197err:
6198 bc_num_free(&res.d.n);
6199 return s;
6200}
6201
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006202static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006203{
Gavin Howard01055ba2018-11-03 11:00:21 -06006204 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006205 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006206
6207 res.t = BC_RESULT_TEMP;
6208
6209 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006210 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006211 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006212}
6213
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006214static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006215{
6216 BcStatus s;
6217 BcResult *r, res;
6218 BcNum *num = NULL, n;
6219 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006220 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006221 unsigned long val;
6222
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006223 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006224 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006225 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006226
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006227 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006228 if (s) return s;
6229
6230 if (BC_PROG_NUM(r, num)) {
6231
6232 bc_num_init(&n, BC_NUM_DEF_SIZE);
6233 bc_num_copy(&n, num);
6234 bc_num_truncate(&n, n.rdx);
6235
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006236 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006237 if (s) goto num_err;
6238 s = bc_num_ulong(&n, &val);
6239 if (s) goto num_err;
6240
6241 c = (char) val;
6242
6243 bc_num_free(&n);
6244 }
6245 else {
6246 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006247 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006248 c = str2[0];
6249 }
6250
6251 str = xmalloc(2);
6252 str[0] = c;
6253 str[1] = '\0';
6254
6255 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006256 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006257
6258 if (idx != len + BC_PROG_REQ_FUNCS) {
6259
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006260 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6261 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006262 len = idx;
6263 break;
6264 }
6265 }
6266
6267 free(str);
6268 }
6269 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006270 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006271
6272 res.t = BC_RESULT_STR;
6273 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006274 bc_vec_pop(&G.prog.results);
6275 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006276
6277 return BC_STATUS_SUCCESS;
6278
6279num_err:
6280 bc_num_free(&n);
6281 return s;
6282}
6283
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006284static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006285{
6286 BcStatus s;
6287 BcResult *r;
6288 BcNum *n = NULL;
6289 size_t idx;
6290 char *str;
6291
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006292 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006293 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006294 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006295
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006296 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006297 if (s) return s;
6298
6299 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006300 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006301 else {
6302 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006303 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006304 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006305 }
6306
6307 return s;
6308}
6309
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006310static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006311{
6312 BcStatus s;
6313 BcResult *opnd;
6314 BcNum *num = NULL;
6315 unsigned long val;
6316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006317 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006318 if (s) return s;
6319 s = bc_num_ulong(num, &val);
6320 if (s) return s;
6321
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006322 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006323
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006324 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006325 return bc_error_stack_has_too_few_elements();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006326 if (G.prog.stack.len == val)
6327 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006328
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006329 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006330
6331 return s;
6332}
6333
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006334static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006335 bool cond)
6336{
6337 BcStatus s = BC_STATUS_SUCCESS;
6338 BcResult *r;
6339 char **str;
6340 BcFunc *f;
6341 BcParse prs;
6342 BcInstPtr ip;
6343 size_t fidx, sidx;
6344 BcNum *n;
6345 bool exec;
6346
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006347 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006348 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006349
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006350 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006351
6352 if (cond) {
6353
Gavin Howard01055ba2018-11-03 11:00:21 -06006354 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6355
6356 if (code[*bgn] == BC_PARSE_STREND)
6357 (*bgn) += 1;
6358 else
6359 else_name = bc_program_name(code, bgn);
6360
6361 exec = r->d.n.len != 0;
6362
6363 if (exec)
6364 name = then_name;
6365 else if (else_name != NULL) {
6366 exec = true;
6367 name = else_name;
6368 }
6369
6370 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006371 BcVec *v;
6372 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006373 n = bc_vec_top(v);
6374 }
6375
6376 free(then_name);
6377 free(else_name);
6378
6379 if (!exec) goto exit;
6380 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006381 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006382 goto exit;
6383 }
6384
6385 sidx = n->rdx;
6386 }
6387 else {
6388
6389 if (r->t == BC_RESULT_STR)
6390 sidx = r->d.id.idx;
6391 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006392 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006393 if (s || !BC_PROG_STR(n)) goto exit;
6394 sidx = n->rdx;
6395 }
6396 else
6397 goto exit;
6398 }
6399
6400 fidx = sidx + BC_PROG_REQ_FUNCS;
6401
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006402 str = bc_vec_item(&G.prog.strs, sidx);
6403 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006404
6405 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006406 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006407 s = bc_parse_text(&prs, *str);
6408 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006409 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006410 if (s) goto err;
6411
6412 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006413 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006414 goto err;
6415 }
6416
6417 bc_parse_free(&prs);
6418 }
6419
6420 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006421 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006422 ip.func = fidx;
6423
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006424 bc_vec_pop(&G.prog.results);
6425 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006426
6427 return BC_STATUS_SUCCESS;
6428
6429err:
6430 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006431 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006432 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006433exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006434 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006435 return s;
6436}
6437#endif // ENABLE_DC
6438
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006439static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006440{
Gavin Howard01055ba2018-11-03 11:00:21 -06006441 BcResult res;
6442 unsigned long val;
6443
6444 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6445 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006446 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006447 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006448 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006449 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006450 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006451
6452 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006453 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006454 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006455}
6456
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006457static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006458{
Gavin Howard01055ba2018-11-03 11:00:21 -06006459 BcId entry, *entry_ptr;
6460 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006461 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006462
6463 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006464 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006465
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006466 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6467 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006468
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006469 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006470 *idx = entry_ptr->idx;
6471
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006472 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006473
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006474 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006475
6476 // We need to reset these, so the function can be repopulated.
6477 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006478 bc_vec_pop_all(&func->autos);
6479 bc_vec_pop_all(&func->code);
6480 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006481 }
6482 else {
6483 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006484 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006485 }
6486}
6487
Denys Vlasenkod38af482018-12-04 19:11:02 +01006488// Called when parsing or execution detects a failure,
6489// resets execution structures.
6490static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006491{
6492 BcFunc *f;
6493 BcInstPtr *ip;
6494
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006495 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006496 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006497
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006498 f = bc_vec_item(&G.prog.fns, 0);
6499 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006500 ip->idx = f->code.len;
6501
Denys Vlasenkod38af482018-12-04 19:11:02 +01006502 // If !tty, no need to check for ^C: we don't have ^C handler,
6503 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006504}
6505
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006506static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006507{
6508 BcStatus s = BC_STATUS_SUCCESS;
6509 size_t idx;
6510 BcResult r, *ptr;
6511 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006512 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6513 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006514 char *code = func->code.v;
6515 bool cond = false;
6516
6517 while (!s && ip->idx < func->code.len) {
6518
6519 char inst = code[(ip->idx)++];
6520
6521 switch (inst) {
6522
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006523#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006524 case BC_INST_JUMP_ZERO:
6525 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006526 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006527 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006528 cond = !bc_num_cmp(num, &G.prog.zero);
6529 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530 }
6531 // Fallthrough.
6532 case BC_INST_JUMP:
6533 {
6534 size_t *addr;
6535 idx = bc_program_index(code, &ip->idx);
6536 addr = bc_vec_item(&func->labels, idx);
6537 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6538 break;
6539 }
6540
6541 case BC_INST_CALL:
6542 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006543 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006544 break;
6545 }
6546
6547 case BC_INST_INC_PRE:
6548 case BC_INST_DEC_PRE:
6549 case BC_INST_INC_POST:
6550 case BC_INST_DEC_POST:
6551 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006552 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006553 break;
6554 }
6555
6556 case BC_INST_HALT:
6557 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006558 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006559 break;
6560 }
6561
6562 case BC_INST_RET:
6563 case BC_INST_RET0:
6564 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006565 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006566 break;
6567 }
6568
6569 case BC_INST_BOOL_OR:
6570 case BC_INST_BOOL_AND:
6571#endif // ENABLE_BC
6572 case BC_INST_REL_EQ:
6573 case BC_INST_REL_LE:
6574 case BC_INST_REL_GE:
6575 case BC_INST_REL_NE:
6576 case BC_INST_REL_LT:
6577 case BC_INST_REL_GT:
6578 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006579 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 break;
6581 }
6582
6583 case BC_INST_READ:
6584 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006585 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006586 break;
6587 }
6588
6589 case BC_INST_VAR:
6590 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006591 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006592 break;
6593 }
6594
6595 case BC_INST_ARRAY_ELEM:
6596 case BC_INST_ARRAY:
6597 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006598 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006599 break;
6600 }
6601
6602 case BC_INST_LAST:
6603 {
6604 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006605 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006606 break;
6607 }
6608
6609 case BC_INST_IBASE:
6610 case BC_INST_SCALE:
6611 case BC_INST_OBASE:
6612 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006613 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006614 break;
6615 }
6616
6617 case BC_INST_SCALE_FUNC:
6618 case BC_INST_LENGTH:
6619 case BC_INST_SQRT:
6620 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006621 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006622 break;
6623 }
6624
6625 case BC_INST_NUM:
6626 {
6627 r.t = BC_RESULT_CONSTANT;
6628 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006629 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006630 break;
6631 }
6632
6633 case BC_INST_POP:
6634 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006635 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006636 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006637 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006638 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
6642 case BC_INST_POP_EXEC:
6643 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006644 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006645 break;
6646 }
6647
6648 case BC_INST_PRINT:
6649 case BC_INST_PRINT_POP:
6650 case BC_INST_PRINT_STR:
6651 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006652 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006653 break;
6654 }
6655
6656 case BC_INST_STR:
6657 {
6658 r.t = BC_RESULT_STR;
6659 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006660 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006661 break;
6662 }
6663
6664 case BC_INST_POWER:
6665 case BC_INST_MULTIPLY:
6666 case BC_INST_DIVIDE:
6667 case BC_INST_MODULUS:
6668 case BC_INST_PLUS:
6669 case BC_INST_MINUS:
6670 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006671 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006672 break;
6673 }
6674
6675 case BC_INST_BOOL_NOT:
6676 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006677 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006678 if (s) return s;
6679
6680 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006681 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6682 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006683
6684 break;
6685 }
6686
6687 case BC_INST_NEG:
6688 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006689 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006690 break;
6691 }
6692
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006693#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006694 case BC_INST_ASSIGN_POWER:
6695 case BC_INST_ASSIGN_MULTIPLY:
6696 case BC_INST_ASSIGN_DIVIDE:
6697 case BC_INST_ASSIGN_MODULUS:
6698 case BC_INST_ASSIGN_PLUS:
6699 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006700#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006701 case BC_INST_ASSIGN:
6702 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006703 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006704 break;
6705 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006706#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006707 case BC_INST_MODEXP:
6708 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006709 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006710 break;
6711 }
6712
6713 case BC_INST_DIVMOD:
6714 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006715 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006716 break;
6717 }
6718
6719 case BC_INST_EXECUTE:
6720 case BC_INST_EXEC_COND:
6721 {
6722 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006723 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006724 break;
6725 }
6726
6727 case BC_INST_PRINT_STACK:
6728 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006729 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6730 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006731 break;
6732 }
6733
6734 case BC_INST_CLEAR_STACK:
6735 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006736 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006737 break;
6738 }
6739
6740 case BC_INST_STACK_LEN:
6741 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006742 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006743 break;
6744 }
6745
6746 case BC_INST_DUPLICATE:
6747 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006748 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006749 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006750 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006751 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006752 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006753 break;
6754 }
6755
6756 case BC_INST_SWAP:
6757 {
6758 BcResult *ptr2;
6759
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006760 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006761 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006762
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006763 ptr = bc_vec_item_rev(&G.prog.results, 0);
6764 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006765 memcpy(&r, ptr, sizeof(BcResult));
6766 memcpy(ptr, ptr2, sizeof(BcResult));
6767 memcpy(ptr2, &r, sizeof(BcResult));
6768
6769 break;
6770 }
6771
6772 case BC_INST_ASCIIFY:
6773 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006774 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006775 break;
6776 }
6777
6778 case BC_INST_PRINT_STREAM:
6779 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006780 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006781 break;
6782 }
6783
6784 case BC_INST_LOAD:
6785 case BC_INST_PUSH_VAR:
6786 {
6787 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006788 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006789 break;
6790 }
6791
6792 case BC_INST_PUSH_TO_VAR:
6793 {
6794 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006795 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006796 free(name);
6797 break;
6798 }
6799
6800 case BC_INST_QUIT:
6801 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006802 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006803 quit();
6804 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006805 break;
6806 }
6807
6808 case BC_INST_NQUIT:
6809 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006810 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006811 break;
6812 }
6813#endif // ENABLE_DC
6814 }
6815
Denys Vlasenkod38af482018-12-04 19:11:02 +01006816 if (s || G_interrupt) {
6817 bc_program_reset();
6818 break;
6819 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006820
6821 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006822 ip = bc_vec_top(&G.prog.stack);
6823 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006824 code = func->code.v;
6825 }
6826
6827 return s;
6828}
6829
Denys Vlasenko00d77792018-11-30 23:13:42 +01006830static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006831{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006832 printf("%s "BB_VER"\n"
6833 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006834 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006835 "This is free software with ABSOLUTELY NO WARRANTY\n"
6836 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006837}
6838
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006839#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006840static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006841{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006842 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6843
Gavin Howard01055ba2018-11-03 11:00:21 -06006844 BcVec v;
6845 char *env_args = getenv(bc_args_env_name), *buf;
6846
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006847 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006848
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006849 G.env_args = xstrdup(env_args);
6850 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006851
6852 bc_vec_init(&v, sizeof(char *), NULL);
6853 bc_vec_push(&v, &bc_args_env_name);
6854
6855 while (*buf != 0) {
6856 if (!isspace(*buf)) {
6857 bc_vec_push(&v, &buf);
6858 while (*buf != 0 && !isspace(*buf)) ++buf;
6859 if (*buf != 0) (*(buf++)) = '\0';
6860 }
6861 else
6862 ++buf;
6863 }
6864
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006865 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006866
6867 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006868}
6869#endif // ENABLE_BC
6870
6871static size_t bc_vm_envLen(const char *var)
6872{
6873 char *lenv = getenv(var);
6874 size_t i, len = BC_NUM_PRINT_WIDTH;
6875 int num;
6876
6877 if (!lenv) return len;
6878
6879 len = strlen(lenv);
6880
6881 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6882 if (num) {
6883 len = (size_t) atoi(lenv) - 1;
6884 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6885 }
6886 else
6887 len = BC_NUM_PRINT_WIDTH;
6888
6889 return len;
6890}
6891
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006892static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006893{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006894 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006895
Gavin Howard01055ba2018-11-03 11:00:21 -06006896 if (s) return s;
6897
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006898 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006899 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006900 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006901 }
6902
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006903 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006904 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006905 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006906 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006907 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006908 }
6909
6910 return s;
6911}
6912
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006913static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006914{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006915 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06006916 char *data;
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006917 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006918 BcFunc *main_func;
6919 BcInstPtr *ip;
6920
Denys Vlasenkodf515392018-12-02 19:27:48 +01006921 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006922 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006923
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006924 sv_file = G.prog.file;
6925 G.prog.file = file;
6926 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006927 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006928 if (s) goto err;
6929
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006930 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6931 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006932
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006933 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006934 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006935
6936err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006937 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06006938 free(data);
6939 return s;
6940}
6941
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006942static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006943{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006944 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006945 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006946 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006947 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006948
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006949 G.prog.file = NULL;
6950 bc_lex_file(&G.prs.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06006951
Denys Vlasenko7d628012018-12-04 21:46:47 +01006952 bc_char_vec_init(&buffer);
6953 bc_char_vec_init(&buf);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01006954 bc_vec_pushZeroByte(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06006955
6956 // This loop is complex because the vm tries not to send any lines that end
6957 // with a backslash to the parser. The reason for that is because the parser
6958 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6959 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006960 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006961
6962 char *string = buf.v;
6963
6964 len = buf.len - 1;
6965
6966 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006967 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006968 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006969 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006970 str += 1;
6971 }
6972 else if (len > 1 || comment) {
6973
6974 for (i = 0; i < len; ++i) {
6975
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006976 bool notend = len > i + 1;
6977 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006978
6979 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006980 if (G.sbgn == G.send)
6981 str ^= c == G.sbgn;
6982 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006983 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006984 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006985 str += 1;
6986 }
6987
6988 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6989 comment = true;
6990 break;
6991 }
6992 else if (c == '*' && notend && comment && string[i + 1] == '/')
6993 comment = false;
6994 }
6995
6996 if (str || comment || string[len - 2] == '\\') {
6997 bc_vec_concat(&buffer, buf.v);
6998 continue;
6999 }
7000 }
7001
7002 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007003 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007004 if (s) {
7005 fflush_and_check();
7006 fputs("ready for more input\n", stderr);
7007 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007008
Denys Vlasenko7d628012018-12-04 21:46:47 +01007009 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06007010 }
7011
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007012 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007013 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007014 }
7015 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007016 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01007017 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007018
Gavin Howard01055ba2018-11-03 11:00:21 -06007019 bc_vec_free(&buf);
7020 bc_vec_free(&buffer);
7021 return s;
7022}
7023
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007024#if ENABLE_BC
7025static const char bc_lib[] = {
7026 "scale=20"
7027"\n" "define e(x){"
7028"\n" "auto b,s,n,r,d,i,p,f,v"
7029"\n" "b=ibase"
7030"\n" "ibase=A"
7031"\n" "if(x<0){"
7032"\n" "n=1"
7033"\n" "x=-x"
7034"\n" "}"
7035"\n" "s=scale"
7036"\n" "r=6+s+0.44*x"
7037"\n" "scale=scale(x)+1"
7038"\n" "while(x>1){"
7039"\n" "d+=1"
7040"\n" "x/=2"
7041"\n" "scale+=1"
7042"\n" "}"
7043"\n" "scale=r"
7044"\n" "r=x+1"
7045"\n" "p=x"
7046"\n" "f=v=1"
7047"\n" "for(i=2;v!=0;++i){"
7048"\n" "p*=x"
7049"\n" "f*=i"
7050"\n" "v=p/f"
7051"\n" "r+=v"
7052"\n" "}"
7053"\n" "while((d--)!=0)r*=r"
7054"\n" "scale=s"
7055"\n" "ibase=b"
7056"\n" "if(n!=0)return(1/r)"
7057"\n" "return(r/1)"
7058"\n" "}"
7059"\n" "define l(x){"
7060"\n" "auto b,s,r,p,a,q,i,v"
7061"\n" "b=ibase"
7062"\n" "ibase=A"
7063"\n" "if(x<=0){"
7064"\n" "r=(1-10^scale)/1"
7065"\n" "ibase=b"
7066"\n" "return(r)"
7067"\n" "}"
7068"\n" "s=scale"
7069"\n" "scale+=6"
7070"\n" "p=2"
7071"\n" "while(x>=2){"
7072"\n" "p*=2"
7073"\n" "x=sqrt(x)"
7074"\n" "}"
7075"\n" "while(x<=0.5){"
7076"\n" "p*=2"
7077"\n" "x=sqrt(x)"
7078"\n" "}"
7079"\n" "r=a=(x-1)/(x+1)"
7080"\n" "q=a*a"
7081"\n" "v=1"
7082"\n" "for(i=3;v!=0;i+=2){"
7083"\n" "a*=q"
7084"\n" "v=a/i"
7085"\n" "r+=v"
7086"\n" "}"
7087"\n" "r*=p"
7088"\n" "scale=s"
7089"\n" "ibase=b"
7090"\n" "return(r/1)"
7091"\n" "}"
7092"\n" "define s(x){"
7093"\n" "auto b,s,r,n,a,q,i"
7094"\n" "b=ibase"
7095"\n" "ibase=A"
7096"\n" "s=scale"
7097"\n" "scale=1.1*s+2"
7098"\n" "a=a(1)"
7099"\n" "if(x<0){"
7100"\n" "n=1"
7101"\n" "x=-x"
7102"\n" "}"
7103"\n" "scale=0"
7104"\n" "q=(x/a+2)/4"
7105"\n" "x=x-4*q*a"
7106"\n" "if(q%2!=0)x=-x"
7107"\n" "scale=s+2"
7108"\n" "r=a=x"
7109"\n" "q=-x*x"
7110"\n" "for(i=3;a!=0;i+=2){"
7111"\n" "a*=q/(i*(i-1))"
7112"\n" "r+=a"
7113"\n" "}"
7114"\n" "scale=s"
7115"\n" "ibase=b"
7116"\n" "if(n!=0)return(-r/1)"
7117"\n" "return(r/1)"
7118"\n" "}"
7119"\n" "define c(x){"
7120"\n" "auto b,s"
7121"\n" "b=ibase"
7122"\n" "ibase=A"
7123"\n" "s=scale"
7124"\n" "scale*=1.2"
7125"\n" "x=s(2*a(1)+x)"
7126"\n" "scale=s"
7127"\n" "ibase=b"
7128"\n" "return(x/1)"
7129"\n" "}"
7130"\n" "define a(x){"
7131"\n" "auto b,s,r,n,a,m,t,f,i,u"
7132"\n" "b=ibase"
7133"\n" "ibase=A"
7134"\n" "n=1"
7135"\n" "if(x<0){"
7136"\n" "n=-1"
7137"\n" "x=-x"
7138"\n" "}"
7139"\n" "if(x==1){"
7140"\n" "if(scale<65){"
7141"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7142"\n" "}"
7143"\n" "}"
7144"\n" "if(x==.2){"
7145"\n" "if(scale<65){"
7146"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7147"\n" "}"
7148"\n" "}"
7149"\n" "s=scale"
7150"\n" "if(x>.2){"
7151"\n" "scale+=5"
7152"\n" "a=a(.2)"
7153"\n" "}"
7154"\n" "scale=s+3"
7155"\n" "while(x>.2){"
7156"\n" "m+=1"
7157"\n" "x=(x-.2)/(1+.2*x)"
7158"\n" "}"
7159"\n" "r=u=x"
7160"\n" "f=-x*x"
7161"\n" "t=1"
7162"\n" "for(i=3;t!=0;i+=2){"
7163"\n" "u*=f"
7164"\n" "t=u/i"
7165"\n" "r+=t"
7166"\n" "}"
7167"\n" "scale=s"
7168"\n" "ibase=b"
7169"\n" "return((m*a+r)/n)"
7170"\n" "}"
7171"\n" "define j(n,x){"
7172"\n" "auto b,s,o,a,i,v,f"
7173"\n" "b=ibase"
7174"\n" "ibase=A"
7175"\n" "s=scale"
7176"\n" "scale=0"
7177"\n" "n/=1"
7178"\n" "if(n<0){"
7179"\n" "n=-n"
7180"\n" "if(n%2==1)o=1"
7181"\n" "}"
7182"\n" "a=1"
7183"\n" "for(i=2;i<=n;++i)a*=i"
7184"\n" "scale=1.5*s"
7185"\n" "a=(x^n)/2^n/a"
7186"\n" "r=v=1"
7187"\n" "f=-x*x/4"
7188"\n" "scale=scale+length(a)-scale(a)"
7189"\n" "for(i=1;v!=0;++i){"
7190"\n" "v=v*f/i/(n+i)"
7191"\n" "r+=v"
7192"\n" "}"
7193"\n" "scale=s"
7194"\n" "ibase=b"
7195"\n" "if(o!=0)a=-a"
7196"\n" "return(a*r/1)"
7197"\n" "}"
7198};
7199#endif // ENABLE_BC
7200
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007201static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007202{
7203 BcStatus s = BC_STATUS_SUCCESS;
7204 size_t i;
7205
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007206#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007207 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007208
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007209 // We know that internal library is not buggy,
7210 // thus error checking is normally disabled.
7211# define DEBUG_LIB 0
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007212 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007213 s = bc_parse_text(&G.prs, bc_lib);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007214 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007215
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007216 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007217 s = G.prs.parse(&G.prs);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007218 if (DEBUG_LIB && s) return s;
7219 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007220 s = bc_program_exec();
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007221 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007222 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007223#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007224
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007225 for (i = 0; !s && i < G.files.len; ++i)
7226 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007227 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007228 fflush_and_check();
7229 fputs("ready for more input\n", stderr);
7230 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007231
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007232 if (IS_BC || !G.files.len)
7233 s = bc_vm_stdin();
7234 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7235 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007236
Denys Vlasenko00d77792018-11-30 23:13:42 +01007237 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007238}
7239
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007240#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007241static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007242{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007243 bc_num_free(&G.prog.ib);
7244 bc_num_free(&G.prog.ob);
7245 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007246# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007247 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007248# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007249 bc_vec_free(&G.prog.fns);
7250 bc_vec_free(&G.prog.fn_map);
7251 bc_vec_free(&G.prog.vars);
7252 bc_vec_free(&G.prog.var_map);
7253 bc_vec_free(&G.prog.arrs);
7254 bc_vec_free(&G.prog.arr_map);
7255 bc_vec_free(&G.prog.strs);
7256 bc_vec_free(&G.prog.consts);
7257 bc_vec_free(&G.prog.results);
7258 bc_vec_free(&G.prog.stack);
7259 bc_num_free(&G.prog.last);
7260 bc_num_free(&G.prog.zero);
7261 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007262}
7263
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007264static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007265{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007266 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007267 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007268 bc_parse_free(&G.prs);
7269 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007270}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007271#endif
7272
7273static void bc_program_init(size_t line_len)
7274{
7275 size_t idx;
7276 BcInstPtr ip;
7277
7278 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7279 memset(&ip, 0, sizeof(BcInstPtr));
7280
7281 /* G.prog.nchars = G.prog.scale = 0; - already is */
7282 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007283
7284 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7285 bc_num_ten(&G.prog.ib);
7286 G.prog.ib_t = 10;
7287
7288 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7289 bc_num_ten(&G.prog.ob);
7290 G.prog.ob_t = 10;
7291
7292 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7293 bc_num_ten(&G.prog.hexb);
7294 G.prog.hexb.num[0] = 6;
7295
7296#if ENABLE_DC
7297 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7298 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7299#endif
7300
7301 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7302 bc_num_zero(&G.prog.last);
7303
7304 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7305 bc_num_zero(&G.prog.zero);
7306
7307 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7308 bc_num_one(&G.prog.one);
7309
7310 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007311 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007312
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007313 bc_program_addFunc(xstrdup("(main)"), &idx);
7314 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007315
7316 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007317 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007318
7319 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007320 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007321
7322 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7323 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7324 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7325 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7326 bc_vec_push(&G.prog.stack, &ip);
7327}
Gavin Howard01055ba2018-11-03 11:00:21 -06007328
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007329static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007330{
Gavin Howard01055ba2018-11-03 11:00:21 -06007331 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007332
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007333 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007334
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007335 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007336 bc_vm_envArgs();
7337 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007338
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007339 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007340 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007341 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007342 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007343 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007344 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007345}
7346
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007347static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007348 const char *env_len)
7349{
7350 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007351
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007352 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007353 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007354
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007355 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007356
Denys Vlasenkod38af482018-12-04 19:11:02 +01007357 if (G.ttyin) {
7358#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007359 // With SA_RESTART, most system calls will restart
7360 // (IOW: they won't fail with EINTR).
7361 // In particular, this means ^C won't cause
7362 // stdout to get into "error state" if SIGINT hits
7363 // within write() syscall.
7364 // The downside is that ^C while line input is taken
7365 // will only be handled after [Enter] since read()
7366 // from stdin is not interrupted by ^C either,
7367 // it restarts, thus fgetc() does not return on ^C.
7368 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7369
7370 // Without SA_RESTART, this exhibits a bug:
7371 // "while (1) print 1" and try ^C-ing it.
7372 // Intermittently, instead of returning to input line,
7373 // you'll get "output error: Interrupted system call"
7374 // and exit.
7375 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007376#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007377 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007378 bc_vm_info();
7379 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007380 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007381
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007382#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007383 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007384#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007385 return st;
7386}
7387
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007388#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007389int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7390int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007391{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007392 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007393 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007394
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007395 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007396}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007397#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007398
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007399#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007400int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7401int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007402{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007403 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007404 G.sbgn = '[';
7405 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007406
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007407 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007408}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007409#endif