blob: 1c1672c0012d03a6fcd8ab6bc8b8c6fa1cbf389b [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}
995static int bc_error_bad_character(char c)
996{
997 return bc_error_fmt("bad character '%c'", c);
998}
999static int bc_error_bad_expression(void)
1000{
1001 return bc_error("bad expression");
1002}
1003static int bc_error_bad_token(void)
1004{
1005 return bc_error("bad token");
1006}
1007static int bc_error_stack_has_too_few_elements(void)
1008{
1009 return bc_error("stack has too few elements");
1010}
1011static int bc_error_variable_is_wrong_type(void)
1012{
1013 return bc_error("variable is wrong type");
1014}
1015static int bc_error_nested_read_call(void)
1016{
1017 return bc_error("read() call inside of a read() call");
1018}
1019
Gavin Howard01055ba2018-11-03 11:00:21 -06001020static void bc_vec_grow(BcVec *v, size_t n)
1021{
1022 size_t cap = v->cap * 2;
1023 while (cap < v->len + n) cap *= 2;
1024 v->v = xrealloc(v->v, v->size * cap);
1025 v->cap = cap;
1026}
1027
1028static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1029{
1030 v->size = esize;
1031 v->cap = BC_VEC_START_CAP;
1032 v->len = 0;
1033 v->dtor = dtor;
1034 v->v = xmalloc(esize * BC_VEC_START_CAP);
1035}
1036
Denys Vlasenko7d628012018-12-04 21:46:47 +01001037static void bc_char_vec_init(BcVec *v)
1038{
1039 bc_vec_init(v, sizeof(char), NULL);
1040}
1041
Gavin Howard01055ba2018-11-03 11:00:21 -06001042static void bc_vec_expand(BcVec *v, size_t req)
1043{
1044 if (v->cap < req) {
1045 v->v = xrealloc(v->v, v->size * req);
1046 v->cap = req;
1047 }
1048}
1049
1050static void bc_vec_npop(BcVec *v, size_t n)
1051{
1052 if (!v->dtor)
1053 v->len -= n;
1054 else {
1055 size_t len = v->len - n;
1056 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1057 }
1058}
1059
Denys Vlasenko7d628012018-12-04 21:46:47 +01001060static void bc_vec_pop_all(BcVec *v)
1061{
1062 bc_vec_npop(v, v->len);
1063}
1064
Gavin Howard01055ba2018-11-03 11:00:21 -06001065static void bc_vec_push(BcVec *v, const void *data)
1066{
1067 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1068 memmove(v->v + (v->size * v->len), data, v->size);
1069 v->len += 1;
1070}
1071
1072static void bc_vec_pushByte(BcVec *v, char data)
1073{
1074 bc_vec_push(v, &data);
1075}
1076
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001077static void bc_vec_pushZeroByte(BcVec *v)
1078{
1079 //bc_vec_pushByte(v, '\0');
1080 // better:
1081 bc_vec_push(v, &const_int_0);
1082}
1083
Gavin Howard01055ba2018-11-03 11:00:21 -06001084static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1085{
1086 if (idx == v->len)
1087 bc_vec_push(v, data);
1088 else {
1089
1090 char *ptr;
1091
1092 if (v->len == v->cap) bc_vec_grow(v, 1);
1093
1094 ptr = v->v + v->size * idx;
1095
1096 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1097 memmove(ptr, data, v->size);
1098 }
1099}
1100
1101static void bc_vec_string(BcVec *v, size_t len, const char *str)
1102{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001103 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001104 bc_vec_expand(v, len + 1);
1105 memcpy(v->v, str, len);
1106 v->len = len;
1107
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001108 bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001109}
1110
1111static void bc_vec_concat(BcVec *v, const char *str)
1112{
1113 size_t len;
1114
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001115 if (v->len == 0) bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001116
1117 len = v->len + strlen(str);
1118
1119 if (v->cap < len) bc_vec_grow(v, len - v->len);
1120 strcat(v->v, str);
1121
1122 v->len = len;
1123}
1124
1125static void *bc_vec_item(const BcVec *v, size_t idx)
1126{
1127 return v->v + v->size * idx;
1128}
1129
1130static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1131{
1132 return v->v + v->size * (v->len - idx - 1);
1133}
1134
1135static void bc_vec_free(void *vec)
1136{
1137 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001138 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001139 free(v->v);
1140}
1141
1142static size_t bc_map_find(const BcVec *v, const void *ptr)
1143{
1144 size_t low = 0, high = v->len;
1145
1146 while (low < high) {
1147
1148 size_t mid = (low + high) / 2;
1149 BcId *id = bc_vec_item(v, mid);
1150 int result = bc_id_cmp(ptr, id);
1151
1152 if (result == 0)
1153 return mid;
1154 else if (result < 0)
1155 high = mid;
1156 else
1157 low = mid + 1;
1158 }
1159
1160 return low;
1161}
1162
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001163static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001164{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001165 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001166
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001167 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001168 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001169 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1170 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001171 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001172 bc_vec_pushAt(v, ptr, n);
1173 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001174}
1175
1176static size_t bc_map_index(const BcVec *v, const void *ptr)
1177{
1178 size_t i = bc_map_find(v, ptr);
1179 if (i >= v->len) return BC_VEC_INVALID_IDX;
1180 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1181}
1182
1183static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1184{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001185 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001186
Denys Vlasenko00d77792018-11-30 23:13:42 +01001187 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001188 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001189
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001190 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001191 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001192
1193 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001194#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001195 if (bb_got_signal) { // ^C was pressed
1196 intr:
1197 bb_got_signal = 0; // resets G_interrupt to zero
1198 fputs(IS_BC
1199 ? "\ninterrupt (type \"quit\" to exit)\n"
1200 : "\ninterrupt (type \"q\" to exit)\n"
1201 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001202 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001203#endif
1204 if (G.ttyin && !G_posix)
1205 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001206
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001207#if ENABLE_FEATURE_BC_SIGNALS
1208 errno = 0;
1209#endif
1210 do {
1211 i = fgetc(stdin);
1212 if (i == EOF) {
1213#if ENABLE_FEATURE_BC_SIGNALS
1214 // Both conditions appear simultaneously, check both just in case
1215 if (errno == EINTR || bb_got_signal) {
1216 // ^C was pressed
1217 clearerr(stdin);
1218 goto intr;
1219 }
1220#endif
1221 if (ferror(stdin))
1222 quit(); // this emits error message
1223 G.eof = 1;
1224 // Note: EOF does not append '\n', therefore:
1225 // printf 'print 123\n' | bc - works
1226 // printf 'print 123' | bc - fails (syntax error)
1227 break;
1228 }
1229
1230 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1231 || i > 0x7e
1232 ) {
1233 // Bad chars on this line, ignore entire line
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001234 bc_error_fmt("illegal character 0x%02x", i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001235 bad_chars = 1;
1236 }
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001237 bc_vec_pushByte(vec, (char)i);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001238 } while (i != '\n');
1239 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001240
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001241 bc_vec_pushZeroByte(vec);
Gavin Howard01055ba2018-11-03 11:00:21 -06001242
1243 return BC_STATUS_SUCCESS;
1244}
1245
Denys Vlasenkodf515392018-12-02 19:27:48 +01001246static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001247{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001248 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001249 size_t size = ((size_t) -1);
1250 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001251
Denys Vlasenkodf515392018-12-02 19:27:48 +01001252 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001253
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001254 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001255 char c = buf[i];
1256 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1257 || c > 0x7e
1258 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001259 free(buf);
1260 buf = NULL;
1261 break;
1262 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001263 }
1264
Denys Vlasenkodf515392018-12-02 19:27:48 +01001265 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001266}
1267
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001268static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001269{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001270 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001271 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001272
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001273 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001274#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001275 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001276 "extended-register\0" No_argument "x"
1277 "warn\0" No_argument "w"
1278 "version\0" No_argument "v"
1279 "standard\0" No_argument "s"
1280 "quiet\0" No_argument "q"
1281 "mathlib\0" No_argument "l"
1282 "interactive\0" No_argument "i"
1283 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001284#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001285 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001286#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001287 if (getenv("POSIXLY_CORRECT"))
1288 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001289
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001290 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001291 // should not be necessary, getopt32() handles this??
1292 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001293
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001294 for (i = optind; i < argc; ++i)
1295 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001296}
1297
1298static void bc_num_setToZero(BcNum *n, size_t scale)
1299{
1300 n->len = 0;
1301 n->neg = false;
1302 n->rdx = scale;
1303}
1304
1305static void bc_num_zero(BcNum *n)
1306{
1307 bc_num_setToZero(n, 0);
1308}
1309
1310static void bc_num_one(BcNum *n)
1311{
1312 bc_num_setToZero(n, 0);
1313 n->len = 1;
1314 n->num[0] = 1;
1315}
1316
1317static void bc_num_ten(BcNum *n)
1318{
1319 bc_num_setToZero(n, 0);
1320 n->len = 2;
1321 n->num[0] = 0;
1322 n->num[1] = 1;
1323}
1324
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001325static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001326 size_t len)
1327{
1328 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001329 for (i = 0; i < len; ++i) {
1330 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001331 a[i + j++] += 10;
1332 a[i + j] -= 1;
1333 }
1334 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001335}
1336
1337static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1338{
1339 size_t i;
1340 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001341 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001342 return BC_NUM_NEG(i + 1, c < 0);
1343}
1344
1345static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1346{
1347 size_t i, min, a_int, b_int, diff;
1348 BcDig *max_num, *min_num;
1349 bool a_max, neg = false;
1350 ssize_t cmp;
1351
1352 if (a == b) return 0;
1353 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1354 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1355 if (a->neg) {
1356 if (b->neg)
1357 neg = true;
1358 else
1359 return -1;
1360 }
1361 else if (b->neg)
1362 return 1;
1363
1364 a_int = BC_NUM_INT(a);
1365 b_int = BC_NUM_INT(b);
1366 a_int -= b_int;
1367 a_max = (a->rdx > b->rdx);
1368
1369 if (a_int != 0) return (ssize_t) a_int;
1370
1371 if (a_max) {
1372 min = b->rdx;
1373 diff = a->rdx - b->rdx;
1374 max_num = a->num + diff;
1375 min_num = b->num;
1376 }
1377 else {
1378 min = a->rdx;
1379 diff = b->rdx - a->rdx;
1380 max_num = b->num + diff;
1381 min_num = a->num;
1382 }
1383
1384 cmp = bc_num_compare(max_num, min_num, b_int + min);
1385 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1386
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001387 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001388 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1389 }
1390
1391 return 0;
1392}
1393
1394static void bc_num_truncate(BcNum *n, size_t places)
1395{
1396 if (places == 0) return;
1397
1398 n->rdx -= places;
1399
1400 if (n->len != 0) {
1401 n->len -= places;
1402 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1403 }
1404}
1405
1406static void bc_num_extend(BcNum *n, size_t places)
1407{
1408 size_t len = n->len + places;
1409
1410 if (places != 0) {
1411
1412 if (n->cap < len) bc_num_expand(n, len);
1413
1414 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1415 memset(n->num, 0, sizeof(BcDig) * places);
1416
1417 n->len += places;
1418 n->rdx += places;
1419 }
1420}
1421
1422static void bc_num_clean(BcNum *n)
1423{
1424 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1425 if (n->len == 0)
1426 n->neg = false;
1427 else if (n->len < n->rdx)
1428 n->len = n->rdx;
1429}
1430
1431static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1432{
1433 if (n->rdx < scale)
1434 bc_num_extend(n, scale - n->rdx);
1435 else
1436 bc_num_truncate(n, n->rdx - scale);
1437
1438 bc_num_clean(n);
1439 if (n->len != 0) n->neg = !neg1 != !neg2;
1440}
1441
1442static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1443 BcNum *restrict b)
1444{
1445 if (idx < n->len) {
1446
1447 b->len = n->len - idx;
1448 a->len = idx;
1449 a->rdx = b->rdx = 0;
1450
1451 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1452 memcpy(a->num, n->num, idx * sizeof(BcDig));
1453 }
1454 else {
1455 bc_num_zero(b);
1456 bc_num_copy(a, n);
1457 }
1458
1459 bc_num_clean(a);
1460 bc_num_clean(b);
1461}
1462
1463static BcStatus bc_num_shift(BcNum *n, size_t places)
1464{
1465 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001466 if (places + n->len > BC_MAX_NUM)
1467 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001468
1469 if (n->rdx >= places)
1470 n->rdx -= places;
1471 else {
1472 bc_num_extend(n, places - n->rdx);
1473 n->rdx = 0;
1474 }
1475
1476 bc_num_clean(n);
1477
1478 return BC_STATUS_SUCCESS;
1479}
1480
1481static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1482{
1483 BcNum one;
1484 BcDig num[2];
1485
1486 one.cap = 2;
1487 one.num = num;
1488 bc_num_one(&one);
1489
1490 return bc_num_div(&one, a, b, scale);
1491}
1492
1493static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1494{
1495 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1496 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1497 int carry, in;
1498
1499 // Because this function doesn't need to use scale (per the bc spec),
1500 // I am hijacking it to say whether it's doing an add or a subtract.
1501
1502 if (a->len == 0) {
1503 bc_num_copy(c, b);
1504 if (sub && c->len) c->neg = !c->neg;
1505 return BC_STATUS_SUCCESS;
1506 }
1507 else if (b->len == 0) {
1508 bc_num_copy(c, a);
1509 return BC_STATUS_SUCCESS;
1510 }
1511
1512 c->neg = a->neg;
1513 c->rdx = BC_MAX(a->rdx, b->rdx);
1514 min_rdx = BC_MIN(a->rdx, b->rdx);
1515 c->len = 0;
1516
1517 if (a->rdx > b->rdx) {
1518 diff = a->rdx - b->rdx;
1519 ptr = a->num;
1520 ptr_a = a->num + diff;
1521 ptr_b = b->num;
1522 }
1523 else {
1524 diff = b->rdx - a->rdx;
1525 ptr = b->num;
1526 ptr_a = a->num;
1527 ptr_b = b->num + diff;
1528 }
1529
1530 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1531
1532 ptr_c += diff;
1533 a_int = BC_NUM_INT(a);
1534 b_int = BC_NUM_INT(b);
1535
1536 if (a_int > b_int) {
1537 min_int = b_int;
1538 max = a_int;
1539 ptr = ptr_a;
1540 }
1541 else {
1542 min_int = a_int;
1543 max = b_int;
1544 ptr = ptr_b;
1545 }
1546
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001547 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001548 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1549 carry = in / 10;
1550 ptr_c[i] = (BcDig)(in % 10);
1551 }
1552
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001553 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001554 in = ((int) ptr[i]) + carry;
1555 carry = in / 10;
1556 ptr_c[i] = (BcDig)(in % 10);
1557 }
1558
1559 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1560
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001561 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001562}
1563
1564static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1565{
Gavin Howard01055ba2018-11-03 11:00:21 -06001566 ssize_t cmp;
1567 BcNum *minuend, *subtrahend;
1568 size_t start;
1569 bool aneg, bneg, neg;
1570
1571 // Because this function doesn't need to use scale (per the bc spec),
1572 // I am hijacking it to say whether it's doing an add or a subtract.
1573
1574 if (a->len == 0) {
1575 bc_num_copy(c, b);
1576 if (sub && c->len) c->neg = !c->neg;
1577 return BC_STATUS_SUCCESS;
1578 }
1579 else if (b->len == 0) {
1580 bc_num_copy(c, a);
1581 return BC_STATUS_SUCCESS;
1582 }
1583
1584 aneg = a->neg;
1585 bneg = b->neg;
1586 a->neg = b->neg = false;
1587
1588 cmp = bc_num_cmp(a, b);
1589
1590 a->neg = aneg;
1591 b->neg = bneg;
1592
1593 if (cmp == 0) {
1594 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1595 return BC_STATUS_SUCCESS;
1596 }
1597 else if (cmp > 0) {
1598 neg = a->neg;
1599 minuend = a;
1600 subtrahend = b;
1601 }
1602 else {
1603 neg = b->neg;
1604 if (sub) neg = !neg;
1605 minuend = b;
1606 subtrahend = a;
1607 }
1608
1609 bc_num_copy(c, minuend);
1610 c->neg = neg;
1611
1612 if (c->rdx < subtrahend->rdx) {
1613 bc_num_extend(c, subtrahend->rdx - c->rdx);
1614 start = 0;
1615 }
1616 else
1617 start = c->rdx - subtrahend->rdx;
1618
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001619 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001620
1621 bc_num_clean(c);
1622
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001623 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001624}
1625
1626static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1627 BcNum *restrict c)
1628{
1629 BcStatus s;
1630 int carry;
1631 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1632 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1633 bool aone = BC_NUM_ONE(a);
1634
Gavin Howard01055ba2018-11-03 11:00:21 -06001635 if (a->len == 0 || b->len == 0) {
1636 bc_num_zero(c);
1637 return BC_STATUS_SUCCESS;
1638 }
1639 else if (aone || BC_NUM_ONE(b)) {
1640 bc_num_copy(c, aone ? b : a);
1641 return BC_STATUS_SUCCESS;
1642 }
1643
1644 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1645 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1646 {
1647 bc_num_expand(c, a->len + b->len + 1);
1648
1649 memset(c->num, 0, sizeof(BcDig) * c->cap);
1650 c->len = carry = len = 0;
1651
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001652 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001653
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001654 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001655 int in = (int) c->num[i + j];
1656 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1657 carry = in / 10;
1658 c->num[i + j] = (BcDig)(in % 10);
1659 }
1660
1661 c->num[i + j] += (BcDig) carry;
1662 len = BC_MAX(len, i + j + !!carry);
1663 carry = 0;
1664 }
1665
1666 c->len = len;
1667
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001668 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001669 }
1670
1671 bc_num_init(&l1, max);
1672 bc_num_init(&h1, max);
1673 bc_num_init(&l2, max);
1674 bc_num_init(&h2, max);
1675 bc_num_init(&m1, max);
1676 bc_num_init(&m2, max);
1677 bc_num_init(&z0, max);
1678 bc_num_init(&z1, max);
1679 bc_num_init(&z2, max);
1680 bc_num_init(&temp, max + max);
1681
1682 bc_num_split(a, max2, &l1, &h1);
1683 bc_num_split(b, max2, &l2, &h2);
1684
1685 s = bc_num_add(&h1, &l1, &m1, 0);
1686 if (s) goto err;
1687 s = bc_num_add(&h2, &l2, &m2, 0);
1688 if (s) goto err;
1689
1690 s = bc_num_k(&h1, &h2, &z0);
1691 if (s) goto err;
1692 s = bc_num_k(&m1, &m2, &z1);
1693 if (s) goto err;
1694 s = bc_num_k(&l1, &l2, &z2);
1695 if (s) goto err;
1696
1697 s = bc_num_sub(&z1, &z0, &temp, 0);
1698 if (s) goto err;
1699 s = bc_num_sub(&temp, &z2, &z1, 0);
1700 if (s) goto err;
1701
1702 s = bc_num_shift(&z0, max2 * 2);
1703 if (s) goto err;
1704 s = bc_num_shift(&z1, max2);
1705 if (s) goto err;
1706 s = bc_num_add(&z0, &z1, &temp, 0);
1707 if (s) goto err;
1708 s = bc_num_add(&temp, &z2, c, 0);
1709
1710err:
1711 bc_num_free(&temp);
1712 bc_num_free(&z2);
1713 bc_num_free(&z1);
1714 bc_num_free(&z0);
1715 bc_num_free(&m2);
1716 bc_num_free(&m1);
1717 bc_num_free(&h2);
1718 bc_num_free(&l2);
1719 bc_num_free(&h1);
1720 bc_num_free(&l1);
1721 return s;
1722}
1723
1724static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1725{
1726 BcStatus s;
1727 BcNum cpa, cpb;
1728 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1729
1730 scale = BC_MAX(scale, a->rdx);
1731 scale = BC_MAX(scale, b->rdx);
1732 scale = BC_MIN(a->rdx + b->rdx, scale);
1733 maxrdx = BC_MAX(maxrdx, scale);
1734
1735 bc_num_init(&cpa, a->len);
1736 bc_num_init(&cpb, b->len);
1737
1738 bc_num_copy(&cpa, a);
1739 bc_num_copy(&cpb, b);
1740 cpa.neg = cpb.neg = false;
1741
1742 s = bc_num_shift(&cpa, maxrdx);
1743 if (s) goto err;
1744 s = bc_num_shift(&cpb, maxrdx);
1745 if (s) goto err;
1746 s = bc_num_k(&cpa, &cpb, c);
1747 if (s) goto err;
1748
1749 maxrdx += scale;
1750 bc_num_expand(c, c->len + maxrdx);
1751
1752 if (c->len < maxrdx) {
1753 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1754 c->len += maxrdx;
1755 }
1756
1757 c->rdx = maxrdx;
1758 bc_num_retireMul(c, scale, a->neg, b->neg);
1759
1760err:
1761 bc_num_free(&cpb);
1762 bc_num_free(&cpa);
1763 return s;
1764}
1765
1766static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1767{
1768 BcStatus s = BC_STATUS_SUCCESS;
1769 BcDig *n, *p, q;
1770 size_t len, end, i;
1771 BcNum cp;
1772 bool zero = true;
1773
1774 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001775 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001776 else if (a->len == 0) {
1777 bc_num_setToZero(c, scale);
1778 return BC_STATUS_SUCCESS;
1779 }
1780 else if (BC_NUM_ONE(b)) {
1781 bc_num_copy(c, a);
1782 bc_num_retireMul(c, scale, a->neg, b->neg);
1783 return BC_STATUS_SUCCESS;
1784 }
1785
1786 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1787 bc_num_copy(&cp, a);
1788 len = b->len;
1789
1790 if (len > cp.len) {
1791 bc_num_expand(&cp, len + 2);
1792 bc_num_extend(&cp, len - cp.len);
1793 }
1794
1795 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1796 cp.rdx -= b->rdx;
1797 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1798
1799 if (b->rdx == b->len) {
1800 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1801 len -= i - 1;
1802 }
1803
1804 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1805
1806 // We want an extra zero in front to make things simpler.
1807 cp.num[cp.len++] = 0;
1808 end = cp.len - len;
1809
1810 bc_num_expand(c, cp.len);
1811
1812 bc_num_zero(c);
1813 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1814 c->rdx = cp.rdx;
1815 c->len = cp.len;
1816 p = b->num;
1817
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001818 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001819 n = cp.num + i;
1820 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001821 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001822 c->num[i] = q;
1823 }
1824
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001825 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001826 bc_num_free(&cp);
1827
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001828 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001829}
1830
1831static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1832 BcNum *restrict d, size_t scale, size_t ts)
1833{
1834 BcStatus s;
1835 BcNum temp;
1836 bool neg;
1837
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001838 if (b->len == 0)
1839 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001840
1841 if (a->len == 0) {
1842 bc_num_setToZero(d, ts);
1843 return BC_STATUS_SUCCESS;
1844 }
1845
1846 bc_num_init(&temp, d->cap);
1847 bc_num_d(a, b, c, scale);
1848
1849 if (scale != 0) scale = ts;
1850
1851 s = bc_num_m(c, b, &temp, scale);
1852 if (s) goto err;
1853 s = bc_num_sub(a, &temp, d, scale);
1854 if (s) goto err;
1855
1856 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1857
1858 neg = d->neg;
1859 bc_num_retireMul(d, ts, a->neg, b->neg);
1860 d->neg = neg;
1861
1862err:
1863 bc_num_free(&temp);
1864 return s;
1865}
1866
1867static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1868{
1869 BcStatus s;
1870 BcNum c1;
1871 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1872
1873 bc_num_init(&c1, len);
1874 s = bc_num_r(a, b, &c1, c, scale, ts);
1875 bc_num_free(&c1);
1876
1877 return s;
1878}
1879
1880static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1881{
1882 BcStatus s = BC_STATUS_SUCCESS;
1883 BcNum copy;
1884 unsigned long pow;
1885 size_t i, powrdx, resrdx;
1886 bool neg, zero;
1887
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001888 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001889
1890 if (b->len == 0) {
1891 bc_num_one(c);
1892 return BC_STATUS_SUCCESS;
1893 }
1894 else if (a->len == 0) {
1895 bc_num_setToZero(c, scale);
1896 return BC_STATUS_SUCCESS;
1897 }
1898 else if (BC_NUM_ONE(b)) {
1899 if (!b->neg)
1900 bc_num_copy(c, a);
1901 else
1902 s = bc_num_inv(a, c, scale);
1903 return s;
1904 }
1905
1906 neg = b->neg;
1907 b->neg = false;
1908
1909 s = bc_num_ulong(b, &pow);
1910 if (s) return s;
1911
1912 bc_num_init(&copy, a->len);
1913 bc_num_copy(&copy, a);
1914
1915 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1916
1917 b->neg = neg;
1918
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001919 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001920 powrdx <<= 1;
1921 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1922 if (s) goto err;
Denys Vlasenkof359e002018-12-05 01:21:59 +01001923 // It is too slow to handle ^C only after entire "2^1000000" completes
1924 if (G_interrupt) {
1925 s = BC_STATUS_FAILURE;
1926 goto err;
1927 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001928 }
1929
Gavin Howard01055ba2018-11-03 11:00:21 -06001930 bc_num_copy(c, &copy);
1931
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001932 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001933
1934 powrdx <<= 1;
1935 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1936 if (s) goto err;
1937
1938 if (pow & 1) {
1939 resrdx += powrdx;
1940 s = bc_num_mul(c, &copy, c, resrdx);
1941 if (s) goto err;
1942 }
Denys Vlasenkof359e002018-12-05 01:21:59 +01001943 // It is too slow to handle ^C only after entire "2^1000000" completes
1944 if (G_interrupt) {
1945 s = BC_STATUS_FAILURE;
1946 goto err;
1947 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001948 }
1949
1950 if (neg) {
1951 s = bc_num_inv(c, c, scale);
1952 if (s) goto err;
1953 }
1954
Gavin Howard01055ba2018-11-03 11:00:21 -06001955 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1956
1957 // We can't use bc_num_clean() here.
1958 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1959 if (zero) bc_num_setToZero(c, scale);
1960
1961err:
1962 bc_num_free(&copy);
1963 return s;
1964}
1965
1966static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1967 BcNumBinaryOp op, size_t req)
1968{
1969 BcStatus s;
1970 BcNum num2, *ptr_a, *ptr_b;
1971 bool init = false;
1972
1973 if (c == a) {
1974 ptr_a = &num2;
1975 memcpy(ptr_a, c, sizeof(BcNum));
1976 init = true;
1977 }
1978 else
1979 ptr_a = a;
1980
1981 if (c == b) {
1982 ptr_b = &num2;
1983 if (c != a) {
1984 memcpy(ptr_b, c, sizeof(BcNum));
1985 init = true;
1986 }
1987 }
1988 else
1989 ptr_b = b;
1990
1991 if (init)
1992 bc_num_init(c, req);
1993 else
1994 bc_num_expand(c, req);
1995
1996 s = op(ptr_a, ptr_b, c, scale);
1997
1998 if (init) bc_num_free(&num2);
1999
2000 return s;
2001}
2002
2003static bool bc_num_strValid(const char *val, size_t base)
2004{
2005 BcDig b;
2006 bool small, radix = false;
2007 size_t i, len = strlen(val);
2008
2009 if (!len) return true;
2010
2011 small = base <= 10;
2012 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2013
2014 for (i = 0; i < len; ++i) {
2015
2016 BcDig c = val[i];
2017
2018 if (c == '.') {
2019
2020 if (radix) return false;
2021
2022 radix = true;
2023 continue;
2024 }
2025
2026 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2027 return false;
2028 }
2029
2030 return true;
2031}
2032
2033static void bc_num_parseDecimal(BcNum *n, const char *val)
2034{
2035 size_t len, i;
2036 const char *ptr;
2037 bool zero = true;
2038
2039 for (i = 0; val[i] == '0'; ++i);
2040
2041 val += i;
2042 len = strlen(val);
2043 bc_num_zero(n);
2044
2045 if (len != 0) {
2046 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2047 bc_num_expand(n, len);
2048 }
2049
2050 ptr = strchr(val, '.');
2051
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002052 n->rdx = 0;
2053 if (ptr != NULL)
2054 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002055
2056 if (!zero) {
2057 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2058 n->num[n->len] = val[i] - '0';
2059 }
2060}
2061
2062static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2063{
2064 BcStatus s;
2065 BcNum temp, mult, result;
2066 BcDig c = '\0';
2067 bool zero = true;
2068 unsigned long v;
2069 size_t i, digits, len = strlen(val);
2070
2071 bc_num_zero(n);
2072
2073 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2074 if (zero) return;
2075
2076 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2077 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2078
2079 for (i = 0; i < len; ++i) {
2080
2081 c = val[i];
2082 if (c == '.') break;
2083
2084 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2085
2086 s = bc_num_mul(n, base, &mult, 0);
2087 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002088 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002089 s = bc_num_add(&mult, &temp, n, 0);
2090 if (s) goto int_err;
2091 }
2092
2093 if (i == len) {
2094 c = val[i];
2095 if (c == 0) goto int_err;
2096 }
2097
2098 bc_num_init(&result, base->len);
2099 bc_num_zero(&result);
2100 bc_num_one(&mult);
2101
2102 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2103
2104 c = val[i];
2105 if (c == 0) break;
2106
2107 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2108
2109 s = bc_num_mul(&result, base, &result, 0);
2110 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002111 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002112 s = bc_num_add(&result, &temp, &result, 0);
2113 if (s) goto err;
2114 s = bc_num_mul(&mult, base, &mult, 0);
2115 if (s) goto err;
2116 }
2117
2118 s = bc_num_div(&result, &mult, &result, digits);
2119 if (s) goto err;
2120 s = bc_num_add(n, &result, n, digits);
2121 if (s) goto err;
2122
2123 if (n->len != 0) {
2124 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2125 }
2126 else
2127 bc_num_zero(n);
2128
2129err:
2130 bc_num_free(&result);
2131int_err:
2132 bc_num_free(&mult);
2133 bc_num_free(&temp);
2134}
2135
2136static void bc_num_printNewline(size_t *nchars, size_t line_len)
2137{
2138 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002139 bb_putchar('\\');
2140 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002141 *nchars = 0;
2142 }
2143}
2144
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002145#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002146static void bc_num_printChar(size_t num, size_t width, bool radix,
2147 size_t *nchars, size_t line_len)
2148{
2149 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002150 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002151 *nchars = *nchars + width;
2152}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002153#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002154
2155static void bc_num_printDigits(size_t num, size_t width, bool radix,
2156 size_t *nchars, size_t line_len)
2157{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002158 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002159
2160 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002161 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002162 ++(*nchars);
2163
2164 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002165 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2166 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002167
2168 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002169 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002170 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002171 dig = num / pow;
2172 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002173 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002174 }
2175}
2176
2177static void bc_num_printHex(size_t num, size_t width, bool radix,
2178 size_t *nchars, size_t line_len)
2179{
2180 if (radix) {
2181 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002182 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002183 *nchars += 1;
2184 }
2185
2186 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002187 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002188 *nchars = *nchars + width;
2189}
2190
2191static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2192{
2193 size_t i, rdx = n->rdx - 1;
2194
Denys Vlasenko00d77792018-11-30 23:13:42 +01002195 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002196 (*nchars) += n->neg;
2197
2198 for (i = n->len - 1; i < n->len; --i)
2199 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2200}
2201
2202static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2203 size_t *nchars, size_t len, BcNumDigitOp print)
2204{
2205 BcStatus s;
2206 BcVec stack;
2207 BcNum intp, fracp, digit, frac_len;
2208 unsigned long dig, *ptr;
2209 size_t i;
2210 bool radix;
2211
2212 if (n->len == 0) {
2213 print(0, width, false, nchars, len);
2214 return BC_STATUS_SUCCESS;
2215 }
2216
2217 bc_vec_init(&stack, sizeof(long), NULL);
2218 bc_num_init(&intp, n->len);
2219 bc_num_init(&fracp, n->rdx);
2220 bc_num_init(&digit, width);
2221 bc_num_init(&frac_len, BC_NUM_INT(n));
2222 bc_num_copy(&intp, n);
2223 bc_num_one(&frac_len);
2224
2225 bc_num_truncate(&intp, intp.rdx);
2226 s = bc_num_sub(n, &intp, &fracp, 0);
2227 if (s) goto err;
2228
2229 while (intp.len != 0) {
2230 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2231 if (s) goto err;
2232 s = bc_num_ulong(&digit, &dig);
2233 if (s) goto err;
2234 bc_vec_push(&stack, &dig);
2235 }
2236
2237 for (i = 0; i < stack.len; ++i) {
2238 ptr = bc_vec_item_rev(&stack, i);
2239 print(*ptr, width, false, nchars, len);
2240 }
2241
2242 if (!n->rdx) goto err;
2243
2244 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2245 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2246 if (s) goto err;
2247 s = bc_num_ulong(&fracp, &dig);
2248 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002249 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002250 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2251 if (s) goto err;
2252 print(dig, width, radix, nchars, len);
2253 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2254 if (s) goto err;
2255 }
2256
2257err:
2258 bc_num_free(&frac_len);
2259 bc_num_free(&digit);
2260 bc_num_free(&fracp);
2261 bc_num_free(&intp);
2262 bc_vec_free(&stack);
2263 return s;
2264}
2265
2266static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2267 size_t *nchars, size_t line_len)
2268{
2269 BcStatus s;
2270 size_t width, i;
2271 BcNumDigitOp print;
2272 bool neg = n->neg;
2273
Denys Vlasenko00d77792018-11-30 23:13:42 +01002274 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002275 (*nchars) += neg;
2276
2277 n->neg = false;
2278
2279 if (base_t <= BC_NUM_MAX_IBASE) {
2280 width = 1;
2281 print = bc_num_printHex;
2282 }
2283 else {
2284 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2285 print = bc_num_printDigits;
2286 }
2287
2288 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2289 n->neg = neg;
2290
2291 return s;
2292}
2293
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002294#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002295static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2296{
2297 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2298}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002299#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002300
2301static void bc_num_init(BcNum *n, size_t req)
2302{
2303 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2304 memset(n, 0, sizeof(BcNum));
2305 n->num = xmalloc(req);
2306 n->cap = req;
2307}
2308
2309static void bc_num_expand(BcNum *n, size_t req)
2310{
2311 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2312 if (req > n->cap) {
2313 n->num = xrealloc(n->num, req);
2314 n->cap = req;
2315 }
2316}
2317
2318static void bc_num_free(void *num)
2319{
2320 free(((BcNum *) num)->num);
2321}
2322
2323static void bc_num_copy(BcNum *d, BcNum *s)
2324{
2325 if (d != s) {
2326 bc_num_expand(d, s->cap);
2327 d->len = s->len;
2328 d->neg = s->neg;
2329 d->rdx = s->rdx;
2330 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2331 }
2332}
2333
2334static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2335 size_t base_t)
2336{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002337 if (!bc_num_strValid(val, base_t))
2338 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002339
2340 if (base_t == 10)
2341 bc_num_parseDecimal(n, val);
2342 else
2343 bc_num_parseBase(n, val, base);
2344
2345 return BC_STATUS_SUCCESS;
2346}
2347
2348static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2349 size_t *nchars, size_t line_len)
2350{
2351 BcStatus s = BC_STATUS_SUCCESS;
2352
2353 bc_num_printNewline(nchars, line_len);
2354
2355 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002356 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002357 ++(*nchars);
2358 }
2359 else if (base_t == 10)
2360 bc_num_printDecimal(n, nchars, line_len);
2361 else
2362 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2363
2364 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002365 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002366 *nchars = 0;
2367 }
2368
2369 return s;
2370}
2371
2372static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2373{
2374 size_t i;
2375 unsigned long pow;
2376
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002377 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002378
2379 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2380
2381 unsigned long prev = *result, powprev = pow;
2382
2383 *result += ((unsigned long) n->num[i]) * pow;
2384 pow *= 10;
2385
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002386 if (*result < prev || pow < powprev)
2387 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002388 }
2389
2390 return BC_STATUS_SUCCESS;
2391}
2392
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002393static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002394{
2395 size_t len;
2396 BcDig *ptr;
2397 unsigned long i;
2398
2399 bc_num_zero(n);
2400
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002401 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002402
2403 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2404 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002405}
2406
2407static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2408{
2409 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2410 (void) scale;
2411 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2412}
2413
2414static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2415{
2416 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2417 (void) scale;
2418 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2419}
2420
2421static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2422{
2423 size_t req = BC_NUM_MREQ(a, b, scale);
2424 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2425}
2426
2427static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2428{
2429 size_t req = BC_NUM_MREQ(a, b, scale);
2430 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2431}
2432
2433static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2434{
2435 size_t req = BC_NUM_MREQ(a, b, scale);
2436 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2437}
2438
2439static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2440{
2441 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2442}
2443
2444static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2445{
2446 BcStatus s;
2447 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2448 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2449 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2450
2451 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2452 bc_num_expand(b, req);
2453
2454 if (a->len == 0) {
2455 bc_num_setToZero(b, scale);
2456 return BC_STATUS_SUCCESS;
2457 }
2458 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002459 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002460 else if (BC_NUM_ONE(a)) {
2461 bc_num_one(b);
2462 bc_num_extend(b, scale);
2463 return BC_STATUS_SUCCESS;
2464 }
2465
2466 scale = BC_MAX(scale, a->rdx) + 1;
2467 len = a->len + scale;
2468
2469 bc_num_init(&num1, len);
2470 bc_num_init(&num2, len);
2471 bc_num_init(&half, BC_NUM_DEF_SIZE);
2472
2473 bc_num_one(&half);
2474 half.num[0] = 5;
2475 half.rdx = 1;
2476
2477 bc_num_init(&f, len);
2478 bc_num_init(&fprime, len);
2479
2480 x0 = &num1;
2481 x1 = &num2;
2482
2483 bc_num_one(x0);
2484 pow = BC_NUM_INT(a);
2485
2486 if (pow) {
2487
2488 if (pow & 1)
2489 x0->num[0] = 2;
2490 else
2491 x0->num[0] = 6;
2492
2493 pow -= 2 - (pow & 1);
2494
2495 bc_num_extend(x0, pow);
2496
2497 // Make sure to move the radix back.
2498 x0->rdx -= pow;
2499 }
2500
2501 x0->rdx = digs = digs1 = 0;
2502 resrdx = scale + 2;
2503 len = BC_NUM_INT(x0) + resrdx - 1;
2504
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002505 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002506
2507 s = bc_num_div(a, x0, &f, resrdx);
2508 if (s) goto err;
2509 s = bc_num_add(x0, &f, &fprime, resrdx);
2510 if (s) goto err;
2511 s = bc_num_mul(&fprime, &half, x1, resrdx);
2512 if (s) goto err;
2513
2514 cmp = bc_num_cmp(x1, x0);
2515 digs = x1->len - (unsigned long long) llabs(cmp);
2516
2517 if (cmp == cmp2 && digs == digs1)
2518 times += 1;
2519 else
2520 times = 0;
2521
2522 resrdx += times > 4;
2523
2524 cmp2 = cmp1;
2525 cmp1 = cmp;
2526 digs1 = digs;
2527
2528 temp = x0;
2529 x0 = x1;
2530 x1 = temp;
2531 }
2532
Gavin Howard01055ba2018-11-03 11:00:21 -06002533 bc_num_copy(b, x0);
2534 scale -= 1;
2535 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2536
2537err:
2538 bc_num_free(&fprime);
2539 bc_num_free(&f);
2540 bc_num_free(&half);
2541 bc_num_free(&num2);
2542 bc_num_free(&num1);
2543 return s;
2544}
2545
2546static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2547 size_t scale)
2548{
2549 BcStatus s;
2550 BcNum num2, *ptr_a;
2551 bool init = false;
2552 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2553
2554 if (c == a) {
2555 memcpy(&num2, c, sizeof(BcNum));
2556 ptr_a = &num2;
2557 bc_num_init(c, len);
2558 init = true;
2559 }
2560 else {
2561 ptr_a = a;
2562 bc_num_expand(c, len);
2563 }
2564
2565 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2566
2567 if (init) bc_num_free(&num2);
2568
2569 return s;
2570}
2571
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002572#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002573static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2574{
2575 BcStatus s;
2576 BcNum base, exp, two, temp;
2577
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002578 if (c->len == 0)
2579 return bc_error("divide by zero");
2580 if (a->rdx || b->rdx || c->rdx)
2581 return bc_error("non integer number");
2582 if (b->neg)
2583 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002584
2585 bc_num_expand(d, c->len);
2586 bc_num_init(&base, c->len);
2587 bc_num_init(&exp, b->len);
2588 bc_num_init(&two, BC_NUM_DEF_SIZE);
2589 bc_num_init(&temp, b->len);
2590
2591 bc_num_one(&two);
2592 two.num[0] = 2;
2593 bc_num_one(d);
2594
2595 s = bc_num_rem(a, c, &base, 0);
2596 if (s) goto err;
2597 bc_num_copy(&exp, b);
2598
2599 while (exp.len != 0) {
2600
2601 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2602 if (s) goto err;
2603
2604 if (BC_NUM_ONE(&temp)) {
2605 s = bc_num_mul(d, &base, &temp, 0);
2606 if (s) goto err;
2607 s = bc_num_rem(&temp, c, d, 0);
2608 if (s) goto err;
2609 }
2610
2611 s = bc_num_mul(&base, &base, &temp, 0);
2612 if (s) goto err;
2613 s = bc_num_rem(&temp, c, &base, 0);
2614 if (s) goto err;
2615 }
2616
2617err:
2618 bc_num_free(&temp);
2619 bc_num_free(&two);
2620 bc_num_free(&exp);
2621 bc_num_free(&base);
2622 return s;
2623}
2624#endif // ENABLE_DC
2625
2626static int bc_id_cmp(const void *e1, const void *e2)
2627{
2628 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2629}
2630
2631static void bc_id_free(void *id)
2632{
2633 free(((BcId *) id)->name);
2634}
2635
2636static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2637{
2638 BcId a;
2639 size_t i;
2640
2641 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002642 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2643 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002644 }
2645
2646 a.idx = var;
2647 a.name = name;
2648
2649 bc_vec_push(&f->autos, &a);
2650
2651 return BC_STATUS_SUCCESS;
2652}
2653
2654static void bc_func_init(BcFunc *f)
2655{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002656 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002657 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2658 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2659 f->nparams = 0;
2660}
2661
2662static void bc_func_free(void *func)
2663{
2664 BcFunc *f = (BcFunc *) func;
2665 bc_vec_free(&f->code);
2666 bc_vec_free(&f->autos);
2667 bc_vec_free(&f->labels);
2668}
2669
2670static void bc_array_init(BcVec *a, bool nums)
2671{
2672 if (nums)
2673 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2674 else
2675 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2676 bc_array_expand(a, 1);
2677}
2678
2679static void bc_array_copy(BcVec *d, const BcVec *s)
2680{
2681 size_t i;
2682
Denys Vlasenko7d628012018-12-04 21:46:47 +01002683 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002684 bc_vec_expand(d, s->cap);
2685 d->len = s->len;
2686
2687 for (i = 0; i < s->len; ++i) {
2688 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2689 bc_num_init(dnum, snum->len);
2690 bc_num_copy(dnum, snum);
2691 }
2692}
2693
2694static void bc_array_expand(BcVec *a, size_t len)
2695{
2696 BcResultData data;
2697
2698 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2699 while (len > a->len) {
2700 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2701 bc_vec_push(a, &data.n);
2702 }
2703 }
2704 else {
2705 while (len > a->len) {
2706 bc_array_init(&data.v, true);
2707 bc_vec_push(a, &data.v);
2708 }
2709 }
2710}
2711
2712static void bc_string_free(void *string)
2713{
2714 free(*((char **) string));
2715}
2716
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002717#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002718static void bc_result_copy(BcResult *d, BcResult *src)
2719{
2720 d->t = src->t;
2721
2722 switch (d->t) {
2723
2724 case BC_RESULT_TEMP:
2725 case BC_RESULT_IBASE:
2726 case BC_RESULT_SCALE:
2727 case BC_RESULT_OBASE:
2728 {
2729 bc_num_init(&d->d.n, src->d.n.len);
2730 bc_num_copy(&d->d.n, &src->d.n);
2731 break;
2732 }
2733
2734 case BC_RESULT_VAR:
2735 case BC_RESULT_ARRAY:
2736 case BC_RESULT_ARRAY_ELEM:
2737 {
2738 d->d.id.name = xstrdup(src->d.id.name);
2739 break;
2740 }
2741
2742 case BC_RESULT_CONSTANT:
2743 case BC_RESULT_LAST:
2744 case BC_RESULT_ONE:
2745 case BC_RESULT_STR:
2746 {
2747 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2748 break;
2749 }
2750 }
2751}
2752#endif // ENABLE_DC
2753
2754static void bc_result_free(void *result)
2755{
2756 BcResult *r = (BcResult *) result;
2757
2758 switch (r->t) {
2759
2760 case BC_RESULT_TEMP:
2761 case BC_RESULT_IBASE:
2762 case BC_RESULT_SCALE:
2763 case BC_RESULT_OBASE:
2764 {
2765 bc_num_free(&r->d.n);
2766 break;
2767 }
2768
2769 case BC_RESULT_VAR:
2770 case BC_RESULT_ARRAY:
2771 case BC_RESULT_ARRAY_ELEM:
2772 {
2773 free(r->d.id.name);
2774 break;
2775 }
2776
2777 default:
2778 {
2779 // Do nothing.
2780 break;
2781 }
2782 }
2783}
2784
2785static void bc_lex_lineComment(BcLex *l)
2786{
2787 l->t.t = BC_LEX_WHITESPACE;
2788 while (l->i < l->len && l->buf[l->i++] != '\n');
2789 --l->i;
2790}
2791
2792static void bc_lex_whitespace(BcLex *l)
2793{
2794 char c;
2795 l->t.t = BC_LEX_WHITESPACE;
2796 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2797}
2798
2799static BcStatus bc_lex_number(BcLex *l, char start)
2800{
2801 const char *buf = l->buf + l->i;
2802 size_t len, hits = 0, bslashes = 0, i = 0, j;
2803 char c = buf[i];
2804 bool last_pt, pt = start == '.';
2805
2806 last_pt = pt;
2807 l->t.t = BC_LEX_NUMBER;
2808
2809 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2810 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2811 {
2812 if (c != '\\') {
2813 last_pt = c == '.';
2814 pt = pt || last_pt;
2815 }
2816 else {
2817 ++i;
2818 bslashes += 1;
2819 }
2820
2821 c = buf[++i];
2822 }
2823
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002824 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002825 if (len > BC_MAX_NUM)
2826 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002827
Denys Vlasenko7d628012018-12-04 21:46:47 +01002828 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002829 bc_vec_expand(&l->t.v, len + 1);
2830 bc_vec_push(&l->t.v, &start);
2831
2832 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2833
2834 c = buf[j];
2835
2836 // If we have hit a backslash, skip it. We don't have
2837 // to check for a newline because it's guaranteed.
2838 if (hits < bslashes && c == '\\') {
2839 ++hits;
2840 ++j;
2841 continue;
2842 }
2843
2844 bc_vec_push(&l->t.v, &c);
2845 }
2846
Denys Vlasenko08c033c2018-12-05 16:55:08 +01002847 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002848 l->i += i;
2849
2850 return BC_STATUS_SUCCESS;
2851}
2852
2853static BcStatus bc_lex_name(BcLex *l)
2854{
2855 size_t i = 0;
2856 const char *buf = l->buf + l->i - 1;
2857 char c = buf[i];
2858
2859 l->t.t = BC_LEX_NAME;
2860
2861 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2862
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002863 if (i > BC_MAX_STRING)
2864 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002865 bc_vec_string(&l->t.v, i, buf);
2866
2867 // Increment the index. We minus 1 because it has already been incremented.
2868 l->i += i - 1;
2869
2870 return BC_STATUS_SUCCESS;
2871}
2872
2873static void bc_lex_init(BcLex *l, BcLexNext next)
2874{
2875 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002876 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002877}
2878
2879static void bc_lex_free(BcLex *l)
2880{
2881 bc_vec_free(&l->t.v);
2882}
2883
Denys Vlasenko0409ad32018-12-05 16:39:22 +01002884static void bc_lex_file(BcLex *l)
Gavin Howard01055ba2018-11-03 11:00:21 -06002885{
Denys Vlasenko5318f812018-12-05 17:48:01 +01002886 G.err_line = l->line = 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002887 l->newline = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06002888}
2889
2890static BcStatus bc_lex_next(BcLex *l)
2891{
2892 BcStatus s;
2893
2894 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002895 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002896
2897 l->line += l->newline;
Denys Vlasenko5318f812018-12-05 17:48:01 +01002898 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06002899 l->t.t = BC_LEX_EOF;
2900
2901 l->newline = (l->i == l->len);
2902 if (l->newline) return BC_STATUS_SUCCESS;
2903
2904 // Loop until failure or we don't have whitespace. This
2905 // is so the parser doesn't get inundated with whitespace.
2906 do {
2907 s = l->next(l);
2908 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2909
2910 return s;
2911}
2912
2913static BcStatus bc_lex_text(BcLex *l, const char *text)
2914{
2915 l->buf = text;
2916 l->i = 0;
2917 l->len = strlen(text);
2918 l->t.t = l->t.last = BC_LEX_INVALID;
2919 return bc_lex_next(l);
2920}
2921
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002922#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002923static BcStatus bc_lex_identifier(BcLex *l)
2924{
2925 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002926 unsigned i;
Gavin Howard01055ba2018-11-03 11:00:21 -06002927 const char *buf = l->buf + l->i - 1;
2928
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002929 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
2930 const char *keyword8 = bc_lex_kws[i].name8;
2931 unsigned j = 0;
2932 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
2933 j++;
2934 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06002935 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002936 if (keyword8[j] != '\0')
2937 continue;
2938 match:
2939 // buf starts with keyword bc_lex_kws[i]
2940 l->t.t = BC_LEX_KEY_1st_keyword + i;
2941 if ((1 << i) & POSIX_KWORD_MASK) {
2942 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name8
2943 if (s) return s;
2944 }
2945
2946 // We minus 1 because the index has already been incremented.
2947 l->i += j - 1;
2948 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06002949 }
2950
2951 s = bc_lex_name(l);
2952 if (s) return s;
2953
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01002954 if (l->t.v.len > 2)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002955 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002956
2957 return s;
2958}
2959
2960static BcStatus bc_lex_string(BcLex *l)
2961{
2962 size_t len, nls = 0, i = l->i;
2963 char c;
2964
2965 l->t.t = BC_LEX_STR;
2966
2967 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2968
2969 if (c == '\0') {
2970 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002971 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002972 }
2973
2974 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002975 if (len > BC_MAX_STRING)
2976 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002977 bc_vec_string(&l->t.v, len, l->buf + l->i);
2978
2979 l->i = i + 1;
2980 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01002981 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06002982
2983 return BC_STATUS_SUCCESS;
2984}
2985
2986static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2987{
2988 if (l->buf[l->i] == '=') {
2989 ++l->i;
2990 l->t.t = with;
2991 }
2992 else
2993 l->t.t = without;
2994}
2995
2996static BcStatus bc_lex_comment(BcLex *l)
2997{
2998 size_t i, nls = 0;
2999 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003000
3001 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003002 i = ++l->i;
3003 for (;;) {
3004 char c = buf[i];
3005 check_star:
3006 if (c == '*') {
3007 c = buf[++i];
3008 if (c == '/')
3009 break;
3010 goto check_star;
3011 }
3012 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003013 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003014 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003015 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003016 nls += (c == '\n');
3017 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003018 }
3019
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003020 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003021 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003022 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003023
3024 return BC_STATUS_SUCCESS;
3025}
3026
3027static BcStatus bc_lex_token(BcLex *l)
3028{
3029 BcStatus s = BC_STATUS_SUCCESS;
3030 char c = l->buf[l->i++], c2;
3031
3032 // This is the workhorse of the lexer.
3033 switch (c) {
3034
3035 case '\0':
3036 case '\n':
3037 {
3038 l->newline = true;
3039 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3040 break;
3041 }
3042
3043 case '\t':
3044 case '\v':
3045 case '\f':
3046 case '\r':
3047 case ' ':
3048 {
3049 bc_lex_whitespace(l);
3050 break;
3051 }
3052
3053 case '!':
3054 {
3055 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3056
3057 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003058 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003059 if (s) return s;
3060 }
3061
3062 break;
3063 }
3064
3065 case '"':
3066 {
3067 s = bc_lex_string(l);
3068 break;
3069 }
3070
3071 case '#':
3072 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003073 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003074 if (s) return s;
3075
3076 bc_lex_lineComment(l);
3077
3078 break;
3079 }
3080
3081 case '%':
3082 {
3083 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3084 break;
3085 }
3086
3087 case '&':
3088 {
3089 c2 = l->buf[l->i];
3090 if (c2 == '&') {
3091
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003092 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003093 if (s) return s;
3094
3095 ++l->i;
3096 l->t.t = BC_LEX_OP_BOOL_AND;
3097 }
3098 else {
3099 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003100 s = bc_error_bad_character('&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003101 }
3102
3103 break;
3104 }
3105
3106 case '(':
3107 case ')':
3108 {
3109 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3110 break;
3111 }
3112
3113 case '*':
3114 {
3115 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3116 break;
3117 }
3118
3119 case '+':
3120 {
3121 c2 = l->buf[l->i];
3122 if (c2 == '+') {
3123 ++l->i;
3124 l->t.t = BC_LEX_OP_INC;
3125 }
3126 else
3127 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3128 break;
3129 }
3130
3131 case ',':
3132 {
3133 l->t.t = BC_LEX_COMMA;
3134 break;
3135 }
3136
3137 case '-':
3138 {
3139 c2 = l->buf[l->i];
3140 if (c2 == '-') {
3141 ++l->i;
3142 l->t.t = BC_LEX_OP_DEC;
3143 }
3144 else
3145 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3146 break;
3147 }
3148
3149 case '.':
3150 {
3151 if (isdigit(l->buf[l->i]))
3152 s = bc_lex_number(l, c);
3153 else {
3154 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003155 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003156 }
3157 break;
3158 }
3159
3160 case '/':
3161 {
3162 c2 = l->buf[l->i];
3163 if (c2 == '*')
3164 s = bc_lex_comment(l);
3165 else
3166 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3167 break;
3168 }
3169
3170 case '0':
3171 case '1':
3172 case '2':
3173 case '3':
3174 case '4':
3175 case '5':
3176 case '6':
3177 case '7':
3178 case '8':
3179 case '9':
3180 case 'A':
3181 case 'B':
3182 case 'C':
3183 case 'D':
3184 case 'E':
3185 case 'F':
3186 {
3187 s = bc_lex_number(l, c);
3188 break;
3189 }
3190
3191 case ';':
3192 {
3193 l->t.t = BC_LEX_SCOLON;
3194 break;
3195 }
3196
3197 case '<':
3198 {
3199 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3200 break;
3201 }
3202
3203 case '=':
3204 {
3205 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3206 break;
3207 }
3208
3209 case '>':
3210 {
3211 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3212 break;
3213 }
3214
3215 case '[':
3216 case ']':
3217 {
3218 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3219 break;
3220 }
3221
3222 case '\\':
3223 {
3224 if (l->buf[l->i] == '\n') {
3225 l->t.t = BC_LEX_WHITESPACE;
3226 ++l->i;
3227 }
3228 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003229 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003230 break;
3231 }
3232
3233 case '^':
3234 {
3235 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3236 break;
3237 }
3238
3239 case 'a':
3240 case 'b':
3241 case 'c':
3242 case 'd':
3243 case 'e':
3244 case 'f':
3245 case 'g':
3246 case 'h':
3247 case 'i':
3248 case 'j':
3249 case 'k':
3250 case 'l':
3251 case 'm':
3252 case 'n':
3253 case 'o':
3254 case 'p':
3255 case 'q':
3256 case 'r':
3257 case 's':
3258 case 't':
3259 case 'u':
3260 case 'v':
3261 case 'w':
3262 case 'x':
3263 case 'y':
3264 case 'z':
3265 {
3266 s = bc_lex_identifier(l);
3267 break;
3268 }
3269
3270 case '{':
3271 case '}':
3272 {
3273 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3274 break;
3275 }
3276
3277 case '|':
3278 {
3279 c2 = l->buf[l->i];
3280
3281 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003282 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003283 if (s) return s;
3284
3285 ++l->i;
3286 l->t.t = BC_LEX_OP_BOOL_OR;
3287 }
3288 else {
3289 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003290 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003291 }
3292
3293 break;
3294 }
3295
3296 default:
3297 {
3298 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003299 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003300 break;
3301 }
3302 }
3303
3304 return s;
3305}
3306#endif // ENABLE_BC
3307
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003308#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003309static BcStatus dc_lex_register(BcLex *l)
3310{
3311 BcStatus s = BC_STATUS_SUCCESS;
3312
3313 if (isspace(l->buf[l->i - 1])) {
3314 bc_lex_whitespace(l);
3315 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003316 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003317 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003318 else
3319 s = bc_lex_name(l);
3320 }
3321 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003322 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003323 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003324 bc_vec_pushZeroByte(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003325 l->t.t = BC_LEX_NAME;
3326 }
3327
3328 return s;
3329}
3330
3331static BcStatus dc_lex_string(BcLex *l)
3332{
3333 size_t depth = 1, nls = 0, i = l->i;
3334 char c;
3335
3336 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003337 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003338
3339 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3340
3341 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3342 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3343 nls += (c == '\n');
3344
3345 if (depth) bc_vec_push(&l->t.v, &c);
3346 }
3347
3348 if (c == '\0') {
3349 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003350 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003351 }
3352
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003353 bc_vec_pushZeroByte(&l->t.v);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003354 if (i - l->i > BC_MAX_STRING)
3355 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003356
3357 l->i = i;
3358 l->line += nls;
Denys Vlasenko5318f812018-12-05 17:48:01 +01003359 G.err_line = l->line;
Gavin Howard01055ba2018-11-03 11:00:21 -06003360
3361 return BC_STATUS_SUCCESS;
3362}
3363
3364static BcStatus dc_lex_token(BcLex *l)
3365{
3366 BcStatus s = BC_STATUS_SUCCESS;
3367 char c = l->buf[l->i++], c2;
3368 size_t i;
3369
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003370 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
3371 if (l->t.last == dc_lex_regs[i])
3372 return dc_lex_register(l);
Gavin Howard01055ba2018-11-03 11:00:21 -06003373 }
3374
3375 if (c >= '%' && c <= '~' &&
3376 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3377 {
3378 return s;
3379 }
3380
3381 // This is the workhorse of the lexer.
3382 switch (c) {
3383
3384 case '\0':
3385 {
3386 l->t.t = BC_LEX_EOF;
3387 break;
3388 }
3389
3390 case '\n':
3391 case '\t':
3392 case '\v':
3393 case '\f':
3394 case '\r':
3395 case ' ':
3396 {
3397 l->newline = (c == '\n');
3398 bc_lex_whitespace(l);
3399 break;
3400 }
3401
3402 case '!':
3403 {
3404 c2 = l->buf[l->i];
3405
3406 if (c2 == '=')
3407 l->t.t = BC_LEX_OP_REL_NE;
3408 else if (c2 == '<')
3409 l->t.t = BC_LEX_OP_REL_LE;
3410 else if (c2 == '>')
3411 l->t.t = BC_LEX_OP_REL_GE;
3412 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003413 return bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003414
3415 ++l->i;
3416 break;
3417 }
3418
3419 case '#':
3420 {
3421 bc_lex_lineComment(l);
3422 break;
3423 }
3424
3425 case '.':
3426 {
3427 if (isdigit(l->buf[l->i]))
3428 s = bc_lex_number(l, c);
3429 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003430 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003431 break;
3432 }
3433
3434 case '0':
3435 case '1':
3436 case '2':
3437 case '3':
3438 case '4':
3439 case '5':
3440 case '6':
3441 case '7':
3442 case '8':
3443 case '9':
3444 case 'A':
3445 case 'B':
3446 case 'C':
3447 case 'D':
3448 case 'E':
3449 case 'F':
3450 {
3451 s = bc_lex_number(l, c);
3452 break;
3453 }
3454
3455 case '[':
3456 {
3457 s = dc_lex_string(l);
3458 break;
3459 }
3460
3461 default:
3462 {
3463 l->t.t = BC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003464 s = bc_error_bad_character(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003465 break;
3466 }
3467 }
3468
3469 return s;
3470}
3471#endif // ENABLE_DC
3472
3473static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3474{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003475 bc_program_addFunc(name, idx);
3476 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003477}
3478
3479static void bc_parse_pushName(BcParse *p, char *name)
3480{
3481 size_t i = 0, len = strlen(name);
3482
3483 for (; i < len; ++i) bc_parse_push(p, name[i]);
3484 bc_parse_push(p, BC_PARSE_STREND);
3485
3486 free(name);
3487}
3488
3489static void bc_parse_pushIndex(BcParse *p, size_t idx)
3490{
3491 unsigned char amt, i, nums[sizeof(size_t)];
3492
3493 for (amt = 0; idx; ++amt) {
3494 nums[amt] = (char) idx;
3495 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3496 }
3497
3498 bc_parse_push(p, amt);
3499 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3500}
3501
3502static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3503{
3504 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003505 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003506
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003507 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003508
3509 bc_parse_push(p, BC_INST_NUM);
3510 bc_parse_pushIndex(p, idx);
3511
3512 ++(*nexs);
3513 (*prev) = BC_INST_NUM;
3514}
3515
3516static BcStatus bc_parse_text(BcParse *p, const char *text)
3517{
3518 BcStatus s;
3519
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003520 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003521
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003522 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003523 p->l.t.t = BC_LEX_INVALID;
3524 s = p->parse(p);
3525 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003526 if (!BC_PARSE_CAN_EXEC(p))
3527 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003528 }
3529
3530 return bc_lex_text(&p->l, text);
3531}
3532
Denys Vlasenkod38af482018-12-04 19:11:02 +01003533// Called when bc/dc_parse_parse() detects a failure,
3534// resets parsing structures.
3535static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003536{
3537 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003538 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003539 bc_vec_pop_all(&p->func->code);
3540 bc_vec_pop_all(&p->func->autos);
3541 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003542
3543 bc_parse_updateFunc(p, BC_PROG_MAIN);
3544 }
3545
3546 p->l.i = p->l.len;
3547 p->l.t.t = BC_LEX_EOF;
3548 p->auto_part = (p->nbraces = 0);
3549
3550 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003551 bc_vec_pop_all(&p->exits);
3552 bc_vec_pop_all(&p->conds);
3553 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003554
Denys Vlasenkod38af482018-12-04 19:11:02 +01003555 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003556}
3557
3558static void bc_parse_free(BcParse *p)
3559{
3560 bc_vec_free(&p->flags);
3561 bc_vec_free(&p->exits);
3562 bc_vec_free(&p->conds);
3563 bc_vec_free(&p->ops);
3564 bc_lex_free(&p->l);
3565}
3566
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003567static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003568 BcParseParse parse, BcLexNext next)
3569{
3570 memset(p, 0, sizeof(BcParse));
3571
3572 bc_lex_init(&p->l, next);
3573 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3574 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3575 bc_vec_init(&p->conds, sizeof(size_t), NULL);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01003576 bc_vec_pushZeroByte(&p->flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003577 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3578
3579 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003580 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003581 bc_parse_updateFunc(p, func);
3582}
3583
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003584#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003585static BcStatus bc_parse_else(BcParse *p);
3586static BcStatus bc_parse_stmt(BcParse *p);
3587
3588static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3589 size_t *nexprs, bool next)
3590{
3591 BcStatus s = BC_STATUS_SUCCESS;
3592 BcLexType t;
3593 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3594 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3595
3596 while (p->ops.len > start) {
3597
3598 t = BC_PARSE_TOP_OP(p);
3599 if (t == BC_LEX_LPAREN) break;
3600
3601 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3602 if (l >= r && (l != r || !left)) break;
3603
3604 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3605 bc_vec_pop(&p->ops);
3606 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3607 }
3608
3609 bc_vec_push(&p->ops, &type);
3610 if (next) s = bc_lex_next(&p->l);
3611
3612 return s;
3613}
3614
3615static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3616{
3617 BcLexType top;
3618
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003619 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003620 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003621 top = BC_PARSE_TOP_OP(p);
3622
3623 while (top != BC_LEX_LPAREN) {
3624
3625 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3626
3627 bc_vec_pop(&p->ops);
3628 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3629
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003630 if (p->ops.len <= ops_bgn)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003631 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003632 top = BC_PARSE_TOP_OP(p);
3633 }
3634
3635 bc_vec_pop(&p->ops);
3636
3637 return bc_lex_next(&p->l);
3638}
3639
3640static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3641{
3642 BcStatus s;
3643 bool comma = false;
3644 size_t nparams;
3645
3646 s = bc_lex_next(&p->l);
3647 if (s) return s;
3648
3649 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3650
3651 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3652 s = bc_parse_expr(p, flags, bc_parse_next_param);
3653 if (s) return s;
3654
3655 comma = p->l.t.t == BC_LEX_COMMA;
3656 if (comma) {
3657 s = bc_lex_next(&p->l);
3658 if (s) return s;
3659 }
3660 }
3661
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003662 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003663 bc_parse_push(p, BC_INST_CALL);
3664 bc_parse_pushIndex(p, nparams);
3665
3666 return BC_STATUS_SUCCESS;
3667}
3668
3669static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3670{
3671 BcStatus s;
3672 BcId entry, *entry_ptr;
3673 size_t idx;
3674
3675 entry.name = name;
3676
3677 s = bc_parse_params(p, flags);
3678 if (s) goto err;
3679
3680 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003681 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003682 goto err;
3683 }
3684
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003685 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003686
3687 if (idx == BC_VEC_INVALID_IDX) {
3688 name = xstrdup(entry.name);
3689 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003690 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003691 free(entry.name);
3692 }
3693 else
3694 free(name);
3695
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003696 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003697 bc_parse_pushIndex(p, entry_ptr->idx);
3698
3699 return bc_lex_next(&p->l);
3700
3701err:
3702 free(name);
3703 return s;
3704}
3705
3706static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3707{
3708 BcStatus s;
3709 char *name;
3710
3711 name = xstrdup(p->l.t.v.v);
3712 s = bc_lex_next(&p->l);
3713 if (s) goto err;
3714
3715 if (p->l.t.t == BC_LEX_LBRACKET) {
3716
3717 s = bc_lex_next(&p->l);
3718 if (s) goto err;
3719
3720 if (p->l.t.t == BC_LEX_RBRACKET) {
3721
3722 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003723 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003724 goto err;
3725 }
3726
3727 *type = BC_INST_ARRAY;
3728 }
3729 else {
3730
3731 *type = BC_INST_ARRAY_ELEM;
3732
3733 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3734 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3735 if (s) goto err;
3736 }
3737
3738 s = bc_lex_next(&p->l);
3739 if (s) goto err;
3740 bc_parse_push(p, *type);
3741 bc_parse_pushName(p, name);
3742 }
3743 else if (p->l.t.t == BC_LEX_LPAREN) {
3744
3745 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003746 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003747 goto err;
3748 }
3749
3750 *type = BC_INST_CALL;
3751 s = bc_parse_call(p, name, flags);
3752 }
3753 else {
3754 *type = BC_INST_VAR;
3755 bc_parse_push(p, BC_INST_VAR);
3756 bc_parse_pushName(p, name);
3757 }
3758
3759 return s;
3760
3761err:
3762 free(name);
3763 return s;
3764}
3765
3766static BcStatus bc_parse_read(BcParse *p)
3767{
3768 BcStatus s;
3769
3770 s = bc_lex_next(&p->l);
3771 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003772 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003773
3774 s = bc_lex_next(&p->l);
3775 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003776 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003777
3778 bc_parse_push(p, BC_INST_READ);
3779
3780 return bc_lex_next(&p->l);
3781}
3782
3783static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3784 BcInst *prev)
3785{
3786 BcStatus s;
3787
3788 s = bc_lex_next(&p->l);
3789 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003790 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003791
3792 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3793
3794 s = bc_lex_next(&p->l);
3795 if (s) return s;
3796
3797 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3798 if (s) return s;
3799
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003800 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003801
3802 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3803 bc_parse_push(p, *prev);
3804
3805 return bc_lex_next(&p->l);
3806}
3807
3808static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3809{
3810 BcStatus s;
3811
3812 s = bc_lex_next(&p->l);
3813 if (s) return s;
3814
3815 if (p->l.t.t != BC_LEX_LPAREN) {
3816 *type = BC_INST_SCALE;
3817 bc_parse_push(p, BC_INST_SCALE);
3818 return BC_STATUS_SUCCESS;
3819 }
3820
3821 *type = BC_INST_SCALE_FUNC;
3822 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3823
3824 s = bc_lex_next(&p->l);
3825 if (s) return s;
3826
3827 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3828 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003829 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003830 bc_parse_push(p, BC_INST_SCALE_FUNC);
3831
3832 return bc_lex_next(&p->l);
3833}
3834
3835static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3836 size_t *nexprs, uint8_t flags)
3837{
3838 BcStatus s;
3839 BcLexType type;
3840 char inst;
3841 BcInst etype = *prev;
3842
3843 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3844 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3845 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3846 {
3847 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3848 bc_parse_push(p, inst);
3849 s = bc_lex_next(&p->l);
3850 }
3851 else {
3852
3853 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3854 *paren_expr = true;
3855
3856 s = bc_lex_next(&p->l);
3857 if (s) return s;
3858 type = p->l.t.t;
3859
3860 // Because we parse the next part of the expression
3861 // right here, we need to increment this.
3862 *nexprs = *nexprs + 1;
3863
3864 switch (type) {
3865
3866 case BC_LEX_NAME:
3867 {
3868 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3869 break;
3870 }
3871
3872 case BC_LEX_KEY_IBASE:
3873 case BC_LEX_KEY_LAST:
3874 case BC_LEX_KEY_OBASE:
3875 {
3876 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3877 s = bc_lex_next(&p->l);
3878 break;
3879 }
3880
3881 case BC_LEX_KEY_SCALE:
3882 {
3883 s = bc_lex_next(&p->l);
3884 if (s) return s;
3885 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003886 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003887 else
3888 bc_parse_push(p, BC_INST_SCALE);
3889 break;
3890 }
3891
3892 default:
3893 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003894 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003895 break;
3896 }
3897 }
3898
3899 if (!s) bc_parse_push(p, inst);
3900 }
3901
3902 return s;
3903}
3904
3905static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3906 bool rparen, size_t *nexprs)
3907{
3908 BcStatus s;
3909 BcLexType type;
3910 BcInst etype = *prev;
3911
3912 s = bc_lex_next(&p->l);
3913 if (s) return s;
3914
3915 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3916 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3917 BC_LEX_OP_MINUS :
3918 BC_LEX_NEG;
3919 *prev = BC_PARSE_TOKEN_INST(type);
3920
3921 // We can just push onto the op stack because this is the largest
3922 // precedence operator that gets pushed. Inc/dec does not.
3923 if (type != BC_LEX_OP_MINUS)
3924 bc_vec_push(&p->ops, &type);
3925 else
3926 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3927
3928 return s;
3929}
3930
3931static BcStatus bc_parse_string(BcParse *p, char inst)
3932{
3933 char *str = xstrdup(p->l.t.v.v);
3934
3935 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003936 bc_parse_pushIndex(p, G.prog.strs.len);
3937 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003938 bc_parse_push(p, inst);
3939
3940 return bc_lex_next(&p->l);
3941}
3942
3943static BcStatus bc_parse_print(BcParse *p)
3944{
3945 BcStatus s;
3946 BcLexType type;
3947 bool comma = false;
3948
3949 s = bc_lex_next(&p->l);
3950 if (s) return s;
3951
3952 type = p->l.t.t;
3953
3954 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003955 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003956
3957 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3958
3959 if (type == BC_LEX_STR)
3960 s = bc_parse_string(p, BC_INST_PRINT_POP);
3961 else {
3962 s = bc_parse_expr(p, 0, bc_parse_next_print);
3963 if (s) return s;
3964 bc_parse_push(p, BC_INST_PRINT_POP);
3965 }
3966
3967 if (s) return s;
3968
3969 comma = p->l.t.t == BC_LEX_COMMA;
3970 if (comma) s = bc_lex_next(&p->l);
3971 type = p->l.t.t;
3972 }
3973
3974 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003975 if (comma) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003976
3977 return bc_lex_next(&p->l);
3978}
3979
3980static BcStatus bc_parse_return(BcParse *p)
3981{
3982 BcStatus s;
3983 BcLexType t;
3984 bool paren;
3985
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003986 if (!BC_PARSE_FUNC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003987
3988 s = bc_lex_next(&p->l);
3989 if (s) return s;
3990
3991 t = p->l.t.t;
3992 paren = t == BC_LEX_LPAREN;
3993
3994 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3995 bc_parse_push(p, BC_INST_RET0);
3996 else {
3997
3998 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3999 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4000 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004001
4002 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004003 bc_parse_push(p, BC_INST_RET0);
4004 s = bc_lex_next(&p->l);
4005 if (s) return s;
4006 }
4007
4008 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004009 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06004010 if (s) return s;
4011 }
4012
4013 bc_parse_push(p, BC_INST_RET);
4014 }
4015
4016 return s;
4017}
4018
4019static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4020{
4021 BcStatus s = BC_STATUS_SUCCESS;
4022
4023 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004024 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004025
4026 if (brace) {
4027
4028 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004029 if (!p->nbraces) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004030 --p->nbraces;
4031 s = bc_lex_next(&p->l);
4032 if (s) return s;
4033 }
4034 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004035 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004036 }
4037
4038 if (BC_PARSE_IF(p)) {
4039
4040 uint8_t *flag_ptr;
4041
4042 while (p->l.t.t == BC_LEX_NLINE) {
4043 s = bc_lex_next(&p->l);
4044 if (s) return s;
4045 }
4046
4047 bc_vec_pop(&p->flags);
4048
4049 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4050 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4051
4052 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4053 }
4054 else if (BC_PARSE_ELSE(p)) {
4055
4056 BcInstPtr *ip;
4057 size_t *label;
4058
4059 bc_vec_pop(&p->flags);
4060
4061 ip = bc_vec_top(&p->exits);
4062 label = bc_vec_item(&p->func->labels, ip->idx);
4063 *label = p->func->code.len;
4064
4065 bc_vec_pop(&p->exits);
4066 }
4067 else if (BC_PARSE_FUNC_INNER(p)) {
4068 bc_parse_push(p, BC_INST_RET0);
4069 bc_parse_updateFunc(p, BC_PROG_MAIN);
4070 bc_vec_pop(&p->flags);
4071 }
4072 else {
4073
4074 BcInstPtr *ip = bc_vec_top(&p->exits);
4075 size_t *label = bc_vec_top(&p->conds);
4076
4077 bc_parse_push(p, BC_INST_JUMP);
4078 bc_parse_pushIndex(p, *label);
4079
4080 label = bc_vec_item(&p->func->labels, ip->idx);
4081 *label = p->func->code.len;
4082
4083 bc_vec_pop(&p->flags);
4084 bc_vec_pop(&p->exits);
4085 bc_vec_pop(&p->conds);
4086 }
4087
4088 return s;
4089}
4090
4091static void bc_parse_startBody(BcParse *p, uint8_t flags)
4092{
4093 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4094 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4095 flags |= BC_PARSE_FLAG_BODY;
4096 bc_vec_push(&p->flags, &flags);
4097}
4098
4099static void bc_parse_noElse(BcParse *p)
4100{
4101 BcInstPtr *ip;
4102 size_t *label;
4103 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4104
4105 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4106
4107 ip = bc_vec_top(&p->exits);
4108 label = bc_vec_item(&p->func->labels, ip->idx);
4109 *label = p->func->code.len;
4110
4111 bc_vec_pop(&p->exits);
4112}
4113
4114static BcStatus bc_parse_if(BcParse *p)
4115{
4116 BcStatus s;
4117 BcInstPtr ip;
4118
4119 s = bc_lex_next(&p->l);
4120 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004121 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004122
4123 s = bc_lex_next(&p->l);
4124 if (s) return s;
4125 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4126 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004127 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004128
4129 s = bc_lex_next(&p->l);
4130 if (s) return s;
4131 bc_parse_push(p, BC_INST_JUMP_ZERO);
4132
4133 ip.idx = p->func->labels.len;
4134 ip.func = ip.len = 0;
4135
4136 bc_parse_pushIndex(p, ip.idx);
4137 bc_vec_push(&p->exits, &ip);
4138 bc_vec_push(&p->func->labels, &ip.idx);
4139 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4140
4141 return BC_STATUS_SUCCESS;
4142}
4143
4144static BcStatus bc_parse_else(BcParse *p)
4145{
4146 BcInstPtr ip;
4147
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004148 if (!BC_PARSE_IF_END(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004149
4150 ip.idx = p->func->labels.len;
4151 ip.func = ip.len = 0;
4152
4153 bc_parse_push(p, BC_INST_JUMP);
4154 bc_parse_pushIndex(p, ip.idx);
4155
4156 bc_parse_noElse(p);
4157
4158 bc_vec_push(&p->exits, &ip);
4159 bc_vec_push(&p->func->labels, &ip.idx);
4160 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4161
4162 return bc_lex_next(&p->l);
4163}
4164
4165static BcStatus bc_parse_while(BcParse *p)
4166{
4167 BcStatus s;
4168 BcInstPtr ip;
4169
4170 s = bc_lex_next(&p->l);
4171 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004172 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004173 s = bc_lex_next(&p->l);
4174 if (s) return s;
4175
4176 ip.idx = p->func->labels.len;
4177
4178 bc_vec_push(&p->func->labels, &p->func->code.len);
4179 bc_vec_push(&p->conds, &ip.idx);
4180
4181 ip.idx = p->func->labels.len;
4182 ip.func = 1;
4183 ip.len = 0;
4184
4185 bc_vec_push(&p->exits, &ip);
4186 bc_vec_push(&p->func->labels, &ip.idx);
4187
4188 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4189 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004190 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004191 s = bc_lex_next(&p->l);
4192 if (s) return s;
4193
4194 bc_parse_push(p, BC_INST_JUMP_ZERO);
4195 bc_parse_pushIndex(p, ip.idx);
4196 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4197
4198 return BC_STATUS_SUCCESS;
4199}
4200
4201static BcStatus bc_parse_for(BcParse *p)
4202{
4203 BcStatus s;
4204 BcInstPtr ip;
4205 size_t cond_idx, exit_idx, body_idx, update_idx;
4206
4207 s = bc_lex_next(&p->l);
4208 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004209 if (p->l.t.t != BC_LEX_LPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004210 s = bc_lex_next(&p->l);
4211 if (s) return s;
4212
4213 if (p->l.t.t != BC_LEX_SCOLON)
4214 s = bc_parse_expr(p, 0, bc_parse_next_for);
4215 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004216 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004217
4218 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004219 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004220 s = bc_lex_next(&p->l);
4221 if (s) return s;
4222
4223 cond_idx = p->func->labels.len;
4224 update_idx = cond_idx + 1;
4225 body_idx = update_idx + 1;
4226 exit_idx = body_idx + 1;
4227
4228 bc_vec_push(&p->func->labels, &p->func->code.len);
4229
4230 if (p->l.t.t != BC_LEX_SCOLON)
4231 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4232 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004233 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004234
4235 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004236 if (p->l.t.t != BC_LEX_SCOLON) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004237
4238 s = bc_lex_next(&p->l);
4239 if (s) return s;
4240
4241 bc_parse_push(p, BC_INST_JUMP_ZERO);
4242 bc_parse_pushIndex(p, exit_idx);
4243 bc_parse_push(p, BC_INST_JUMP);
4244 bc_parse_pushIndex(p, body_idx);
4245
4246 ip.idx = p->func->labels.len;
4247
4248 bc_vec_push(&p->conds, &update_idx);
4249 bc_vec_push(&p->func->labels, &p->func->code.len);
4250
4251 if (p->l.t.t != BC_LEX_RPAREN)
4252 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4253 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004254 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004255
4256 if (s) return s;
4257
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004258 if (p->l.t.t != BC_LEX_RPAREN) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004259 bc_parse_push(p, BC_INST_JUMP);
4260 bc_parse_pushIndex(p, cond_idx);
4261 bc_vec_push(&p->func->labels, &p->func->code.len);
4262
4263 ip.idx = exit_idx;
4264 ip.func = 1;
4265 ip.len = 0;
4266
4267 bc_vec_push(&p->exits, &ip);
4268 bc_vec_push(&p->func->labels, &ip.idx);
4269 bc_lex_next(&p->l);
4270 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4271
4272 return BC_STATUS_SUCCESS;
4273}
4274
4275static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4276{
4277 BcStatus s;
4278 size_t i;
4279 BcInstPtr *ip;
4280
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004281 if (!BC_PARSE_LOOP(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004282
4283 if (type == BC_LEX_KEY_BREAK) {
4284
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004285 if (p->exits.len == 0) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004286
4287 i = p->exits.len - 1;
4288 ip = bc_vec_item(&p->exits, i);
4289
4290 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004291 if (i >= p->exits.len && !ip->func) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004292
4293 i = ip->idx;
4294 }
4295 else
4296 i = *((size_t *) bc_vec_top(&p->conds));
4297
4298 bc_parse_push(p, BC_INST_JUMP);
4299 bc_parse_pushIndex(p, i);
4300
4301 s = bc_lex_next(&p->l);
4302 if (s) return s;
4303
4304 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004305 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004306
4307 return bc_lex_next(&p->l);
4308}
4309
4310static BcStatus bc_parse_func(BcParse *p)
4311{
4312 BcStatus s;
4313 bool var, comma = false;
4314 uint8_t flags;
4315 char *name;
4316
4317 s = bc_lex_next(&p->l);
4318 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004319 if (p->l.t.t != BC_LEX_NAME)
4320 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004321
4322 name = xstrdup(p->l.t.v.v);
4323 bc_parse_addFunc(p, name, &p->fidx);
4324
4325 s = bc_lex_next(&p->l);
4326 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004327 if (p->l.t.t != BC_LEX_LPAREN)
4328 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004329 s = bc_lex_next(&p->l);
4330 if (s) return s;
4331
4332 while (p->l.t.t != BC_LEX_RPAREN) {
4333
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004334 if (p->l.t.t != BC_LEX_NAME)
4335 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004336
4337 ++p->func->nparams;
4338
4339 name = xstrdup(p->l.t.v.v);
4340 s = bc_lex_next(&p->l);
4341 if (s) goto err;
4342
4343 var = p->l.t.t != BC_LEX_LBRACKET;
4344
4345 if (!var) {
4346
4347 s = bc_lex_next(&p->l);
4348 if (s) goto err;
4349
4350 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004351 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004352 goto err;
4353 }
4354
4355 s = bc_lex_next(&p->l);
4356 if (s) goto err;
4357 }
4358
4359 comma = p->l.t.t == BC_LEX_COMMA;
4360 if (comma) {
4361 s = bc_lex_next(&p->l);
4362 if (s) goto err;
4363 }
4364
4365 s = bc_func_insert(p->func, name, var);
4366 if (s) goto err;
4367 }
4368
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004369 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004370
4371 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4372 bc_parse_startBody(p, flags);
4373
4374 s = bc_lex_next(&p->l);
4375 if (s) return s;
4376
4377 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004378 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 -06004379
4380 return s;
4381
4382err:
4383 free(name);
4384 return s;
4385}
4386
4387static BcStatus bc_parse_auto(BcParse *p)
4388{
4389 BcStatus s;
4390 bool comma, var, one;
4391 char *name;
4392
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004393 if (!p->auto_part) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004394 s = bc_lex_next(&p->l);
4395 if (s) return s;
4396
4397 p->auto_part = comma = false;
4398 one = p->l.t.t == BC_LEX_NAME;
4399
4400 while (p->l.t.t == BC_LEX_NAME) {
4401
4402 name = xstrdup(p->l.t.v.v);
4403 s = bc_lex_next(&p->l);
4404 if (s) goto err;
4405
4406 var = p->l.t.t != BC_LEX_LBRACKET;
4407 if (!var) {
4408
4409 s = bc_lex_next(&p->l);
4410 if (s) goto err;
4411
4412 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004413 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004414 goto err;
4415 }
4416
4417 s = bc_lex_next(&p->l);
4418 if (s) goto err;
4419 }
4420
4421 comma = p->l.t.t == BC_LEX_COMMA;
4422 if (comma) {
4423 s = bc_lex_next(&p->l);
4424 if (s) goto err;
4425 }
4426
4427 s = bc_func_insert(p->func, name, var);
4428 if (s) goto err;
4429 }
4430
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004431 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004432 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004433
4434 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004435 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004436
4437 return bc_lex_next(&p->l);
4438
4439err:
4440 free(name);
4441 return s;
4442}
4443
4444static BcStatus bc_parse_body(BcParse *p, bool brace)
4445{
4446 BcStatus s = BC_STATUS_SUCCESS;
4447 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4448
4449 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4450
4451 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4452
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004453 if (!brace) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004454 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4455
4456 if (!p->auto_part) {
4457 s = bc_parse_auto(p);
4458 if (s) return s;
4459 }
4460
4461 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4462 }
4463 else {
4464 s = bc_parse_stmt(p);
4465 if (!s && !brace) s = bc_parse_endBody(p, false);
4466 }
4467
4468 return s;
4469}
4470
4471static BcStatus bc_parse_stmt(BcParse *p)
4472{
4473 BcStatus s = BC_STATUS_SUCCESS;
4474
4475 switch (p->l.t.t) {
4476
4477 case BC_LEX_NLINE:
4478 {
4479 return bc_lex_next(&p->l);
4480 }
4481
4482 case BC_LEX_KEY_ELSE:
4483 {
4484 p->auto_part = false;
4485 break;
4486 }
4487
4488 case BC_LEX_LBRACE:
4489 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004490 if (!BC_PARSE_BODY(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004491
4492 ++p->nbraces;
4493 s = bc_lex_next(&p->l);
4494 if (s) return s;
4495
4496 return bc_parse_body(p, true);
4497 }
4498
4499 case BC_LEX_KEY_AUTO:
4500 {
4501 return bc_parse_auto(p);
4502 }
4503
4504 default:
4505 {
4506 p->auto_part = false;
4507
4508 if (BC_PARSE_IF_END(p)) {
4509 bc_parse_noElse(p);
4510 return BC_STATUS_SUCCESS;
4511 }
4512 else if (BC_PARSE_BODY(p))
4513 return bc_parse_body(p, false);
4514
4515 break;
4516 }
4517 }
4518
4519 switch (p->l.t.t) {
4520
4521 case BC_LEX_OP_INC:
4522 case BC_LEX_OP_DEC:
4523 case BC_LEX_OP_MINUS:
4524 case BC_LEX_OP_BOOL_NOT:
4525 case BC_LEX_LPAREN:
4526 case BC_LEX_NAME:
4527 case BC_LEX_NUMBER:
4528 case BC_LEX_KEY_IBASE:
4529 case BC_LEX_KEY_LAST:
4530 case BC_LEX_KEY_LENGTH:
4531 case BC_LEX_KEY_OBASE:
4532 case BC_LEX_KEY_READ:
4533 case BC_LEX_KEY_SCALE:
4534 case BC_LEX_KEY_SQRT:
4535 {
4536 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4537 break;
4538 }
4539
4540 case BC_LEX_KEY_ELSE:
4541 {
4542 s = bc_parse_else(p);
4543 break;
4544 }
4545
4546 case BC_LEX_SCOLON:
4547 {
4548 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4549 break;
4550 }
4551
4552 case BC_LEX_RBRACE:
4553 {
4554 s = bc_parse_endBody(p, true);
4555 break;
4556 }
4557
4558 case BC_LEX_STR:
4559 {
4560 s = bc_parse_string(p, BC_INST_PRINT_STR);
4561 break;
4562 }
4563
4564 case BC_LEX_KEY_BREAK:
4565 case BC_LEX_KEY_CONTINUE:
4566 {
4567 s = bc_parse_loopExit(p, p->l.t.t);
4568 break;
4569 }
4570
4571 case BC_LEX_KEY_FOR:
4572 {
4573 s = bc_parse_for(p);
4574 break;
4575 }
4576
4577 case BC_LEX_KEY_HALT:
4578 {
4579 bc_parse_push(p, BC_INST_HALT);
4580 s = bc_lex_next(&p->l);
4581 break;
4582 }
4583
4584 case BC_LEX_KEY_IF:
4585 {
4586 s = bc_parse_if(p);
4587 break;
4588 }
4589
4590 case BC_LEX_KEY_LIMITS:
4591 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004592 // "limits" is a compile-time command,
4593 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004594 s = bc_lex_next(&p->l);
4595 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004596 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4597 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4598 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4599 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4600 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4601 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4602 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4603 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004604 break;
4605 }
4606
4607 case BC_LEX_KEY_PRINT:
4608 {
4609 s = bc_parse_print(p);
4610 break;
4611 }
4612
4613 case BC_LEX_KEY_QUIT:
4614 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004615 // "quit" is a compile-time command. For example,
4616 // "if (0 == 1) quit" terminates when parsing the statement,
4617 // not when it is executed
4618 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004619 }
4620
4621 case BC_LEX_KEY_RETURN:
4622 {
4623 s = bc_parse_return(p);
4624 break;
4625 }
4626
4627 case BC_LEX_KEY_WHILE:
4628 {
4629 s = bc_parse_while(p);
4630 break;
4631 }
4632
4633 default:
4634 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004635 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004636 break;
4637 }
4638 }
4639
4640 return s;
4641}
4642
4643static BcStatus bc_parse_parse(BcParse *p)
4644{
4645 BcStatus s;
4646
4647 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004648 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 -06004649 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004650 if (!BC_PARSE_CAN_EXEC(p)) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004651 s = bc_parse_func(p);
4652 }
4653 else
4654 s = bc_parse_stmt(p);
4655
Denys Vlasenkod38af482018-12-04 19:11:02 +01004656 if (s || G_interrupt) {
4657 bc_parse_reset(p);
4658 s = BC_STATUS_FAILURE;
4659 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004660
4661 return s;
4662}
4663
4664static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4665{
4666 BcStatus s = BC_STATUS_SUCCESS;
4667 BcInst prev = BC_INST_PRINT;
4668 BcLexType top, t = p->l.t.t;
4669 size_t nexprs = 0, ops_bgn = p->ops.len;
4670 uint32_t i, nparens, nrelops;
4671 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4672
4673 paren_first = p->l.t.t == BC_LEX_LPAREN;
4674 nparens = nrelops = 0;
4675 paren_expr = rprn = done = get_token = assign = false;
4676 bin_last = true;
4677
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004678 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004679 switch (t) {
4680
4681 case BC_LEX_OP_INC:
4682 case BC_LEX_OP_DEC:
4683 {
4684 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4685 rprn = get_token = bin_last = false;
4686 break;
4687 }
4688
4689 case BC_LEX_OP_MINUS:
4690 {
4691 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4692 rprn = get_token = false;
4693 bin_last = prev == BC_INST_MINUS;
4694 break;
4695 }
4696
4697 case BC_LEX_OP_ASSIGN_POWER:
4698 case BC_LEX_OP_ASSIGN_MULTIPLY:
4699 case BC_LEX_OP_ASSIGN_DIVIDE:
4700 case BC_LEX_OP_ASSIGN_MODULUS:
4701 case BC_LEX_OP_ASSIGN_PLUS:
4702 case BC_LEX_OP_ASSIGN_MINUS:
4703 case BC_LEX_OP_ASSIGN:
4704 {
4705 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4706 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4707 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4708 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004709 s = bc_error("bad assignment:"
4710 " left side must be scale,"
4711 " ibase, obase, last, var,"
4712 " or array element"
4713 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004714 break;
4715 }
4716 }
4717 // Fallthrough.
4718 case BC_LEX_OP_POWER:
4719 case BC_LEX_OP_MULTIPLY:
4720 case BC_LEX_OP_DIVIDE:
4721 case BC_LEX_OP_MODULUS:
4722 case BC_LEX_OP_PLUS:
4723 case BC_LEX_OP_REL_EQ:
4724 case BC_LEX_OP_REL_LE:
4725 case BC_LEX_OP_REL_GE:
4726 case BC_LEX_OP_REL_NE:
4727 case BC_LEX_OP_REL_LT:
4728 case BC_LEX_OP_REL_GT:
4729 case BC_LEX_OP_BOOL_NOT:
4730 case BC_LEX_OP_BOOL_OR:
4731 case BC_LEX_OP_BOOL_AND:
4732 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004733 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4734 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4735 ) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004736 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004737 }
4738
4739 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4740 prev = BC_PARSE_TOKEN_INST(t);
4741 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4742 rprn = get_token = false;
4743 bin_last = t != BC_LEX_OP_BOOL_NOT;
4744
4745 break;
4746 }
4747
4748 case BC_LEX_LPAREN:
4749 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004750 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004751 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004752 ++nparens;
4753 paren_expr = rprn = bin_last = false;
4754 get_token = true;
4755 bc_vec_push(&p->ops, &t);
4756
4757 break;
4758 }
4759
4760 case BC_LEX_RPAREN:
4761 {
4762 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004763 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004764
4765 if (nparens == 0) {
4766 s = BC_STATUS_SUCCESS;
4767 done = true;
4768 get_token = false;
4769 break;
4770 }
4771 else if (!paren_expr)
4772 return BC_STATUS_PARSE_EMPTY_EXP;
4773
4774 --nparens;
4775 paren_expr = rprn = true;
4776 get_token = bin_last = false;
4777
4778 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4779
4780 break;
4781 }
4782
4783 case BC_LEX_NAME:
4784 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004785 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004786 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004787 paren_expr = true;
4788 rprn = get_token = bin_last = false;
4789 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4790 ++nexprs;
4791
4792 break;
4793 }
4794
4795 case BC_LEX_NUMBER:
4796 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004797 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004798 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004799 bc_parse_number(p, &prev, &nexprs);
4800 paren_expr = get_token = true;
4801 rprn = bin_last = false;
4802
4803 break;
4804 }
4805
4806 case BC_LEX_KEY_IBASE:
4807 case BC_LEX_KEY_LAST:
4808 case BC_LEX_KEY_OBASE:
4809 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004810 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004811 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004812 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4813 bc_parse_push(p, (char) prev);
4814
4815 paren_expr = get_token = true;
4816 rprn = bin_last = false;
4817 ++nexprs;
4818
4819 break;
4820 }
4821
4822 case BC_LEX_KEY_LENGTH:
4823 case BC_LEX_KEY_SQRT:
4824 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004825 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004826 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004827 s = bc_parse_builtin(p, t, flags, &prev);
4828 paren_expr = true;
4829 rprn = get_token = bin_last = false;
4830 ++nexprs;
4831
4832 break;
4833 }
4834
4835 case BC_LEX_KEY_READ:
4836 {
4837 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004838 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004839 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004840 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06004841 else
4842 s = bc_parse_read(p);
4843
4844 paren_expr = true;
4845 rprn = get_token = bin_last = false;
4846 ++nexprs;
4847 prev = BC_INST_READ;
4848
4849 break;
4850 }
4851
4852 case BC_LEX_KEY_SCALE:
4853 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004854 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004855 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004856 s = bc_parse_scale(p, &prev, flags);
4857 paren_expr = true;
4858 rprn = get_token = bin_last = false;
4859 ++nexprs;
4860 prev = BC_INST_SCALE;
4861
4862 break;
4863 }
4864
4865 default:
4866 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004867 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004868 break;
4869 }
4870 }
4871
4872 if (!s && get_token) s = bc_lex_next(&p->l);
4873 }
4874
4875 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004876 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004877
4878 while (p->ops.len > ops_bgn) {
4879
4880 top = BC_PARSE_TOP_OP(p);
4881 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4882
4883 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004884 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004885
4886 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4887
4888 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4889 bc_vec_pop(&p->ops);
4890 }
4891
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004892 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004893 return bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06004894
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004895 for (i = 0; i < next.len; ++i)
4896 if (t == next.tokens[i])
4897 goto ok;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004898 return bc_error_bad_expression();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004899 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004900
4901 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004902 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004903 if (s) return s;
4904 }
4905 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004906 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004907 if (s) return s;
4908 }
4909
4910 if (flags & BC_PARSE_PRINT) {
4911 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4912 bc_parse_push(p, BC_INST_POP);
4913 }
4914
4915 return s;
4916}
4917
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004918static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004919{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004920 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004921}
4922
4923static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4924{
4925 return bc_parse_expr(p, flags, bc_parse_next_read);
4926}
4927#endif // ENABLE_BC
4928
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004929#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004930static BcStatus dc_parse_register(BcParse *p)
4931{
4932 BcStatus s;
4933 char *name;
4934
4935 s = bc_lex_next(&p->l);
4936 if (s) return s;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004937 if (p->l.t.t != BC_LEX_NAME) return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06004938
4939 name = xstrdup(p->l.t.v.v);
4940 bc_parse_pushName(p, name);
4941
4942 return s;
4943}
4944
4945static BcStatus dc_parse_string(BcParse *p)
4946{
4947 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004948 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004949
4950 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4951 name = xstrdup(b);
4952
4953 str = xstrdup(p->l.t.v.v);
4954 bc_parse_push(p, BC_INST_STR);
4955 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004956 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004957 bc_parse_addFunc(p, name, &idx);
4958
4959 return bc_lex_next(&p->l);
4960}
4961
4962static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4963{
4964 BcStatus s;
4965
4966 bc_parse_push(p, inst);
4967 if (name) {
4968 s = dc_parse_register(p);
4969 if (s) return s;
4970 }
4971
4972 if (store) {
4973 bc_parse_push(p, BC_INST_SWAP);
4974 bc_parse_push(p, BC_INST_ASSIGN);
4975 bc_parse_push(p, BC_INST_POP);
4976 }
4977
4978 return bc_lex_next(&p->l);
4979}
4980
4981static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4982{
4983 BcStatus s;
4984
4985 bc_parse_push(p, inst);
4986 bc_parse_push(p, BC_INST_EXEC_COND);
4987
4988 s = dc_parse_register(p);
4989 if (s) return s;
4990
4991 s = bc_lex_next(&p->l);
4992 if (s) return s;
4993
4994 if (p->l.t.t == BC_LEX_ELSE) {
4995 s = dc_parse_register(p);
4996 if (s) return s;
4997 s = bc_lex_next(&p->l);
4998 }
4999 else
5000 bc_parse_push(p, BC_PARSE_STREND);
5001
5002 return s;
5003}
5004
5005static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5006{
5007 BcStatus s = BC_STATUS_SUCCESS;
5008 BcInst prev;
5009 uint8_t inst;
5010 bool assign, get_token = false;
5011
5012 switch (t) {
5013
5014 case BC_LEX_OP_REL_EQ:
5015 case BC_LEX_OP_REL_LE:
5016 case BC_LEX_OP_REL_GE:
5017 case BC_LEX_OP_REL_NE:
5018 case BC_LEX_OP_REL_LT:
5019 case BC_LEX_OP_REL_GT:
5020 {
5021 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5022 break;
5023 }
5024
5025 case BC_LEX_SCOLON:
5026 case BC_LEX_COLON:
5027 {
5028 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5029 break;
5030 }
5031
5032 case BC_LEX_STR:
5033 {
5034 s = dc_parse_string(p);
5035 break;
5036 }
5037
5038 case BC_LEX_NEG:
5039 case BC_LEX_NUMBER:
5040 {
5041 if (t == BC_LEX_NEG) {
5042 s = bc_lex_next(&p->l);
5043 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005044 if (p->l.t.t != BC_LEX_NUMBER)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005045 return bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005046 }
5047
5048 bc_parse_number(p, &prev, &p->nbraces);
5049
5050 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5051 get_token = true;
5052
5053 break;
5054 }
5055
5056 case BC_LEX_KEY_READ:
5057 {
5058 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005059 s = bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005060 else
5061 bc_parse_push(p, BC_INST_READ);
5062 get_token = true;
5063 break;
5064 }
5065
5066 case BC_LEX_OP_ASSIGN:
5067 case BC_LEX_STORE_PUSH:
5068 {
5069 assign = t == BC_LEX_OP_ASSIGN;
5070 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5071 s = dc_parse_mem(p, inst, true, assign);
5072 break;
5073 }
5074
5075 case BC_LEX_LOAD:
5076 case BC_LEX_LOAD_POP:
5077 {
5078 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5079 s = dc_parse_mem(p, inst, true, false);
5080 break;
5081 }
5082
5083 case BC_LEX_STORE_IBASE:
5084 case BC_LEX_STORE_SCALE:
5085 case BC_LEX_STORE_OBASE:
5086 {
5087 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5088 s = dc_parse_mem(p, inst, false, true);
5089 break;
5090 }
5091
5092 default:
5093 {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005094 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06005095 get_token = true;
5096 break;
5097 }
5098 }
5099
5100 if (!s && get_token) s = bc_lex_next(&p->l);
5101
5102 return s;
5103}
5104
5105static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5106{
5107 BcStatus s = BC_STATUS_SUCCESS;
5108 BcInst inst;
5109 BcLexType t;
5110
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005111 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005112
5113 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5114
5115 inst = dc_parse_insts[t];
5116
5117 if (inst != BC_INST_INVALID) {
5118 bc_parse_push(p, inst);
5119 s = bc_lex_next(&p->l);
5120 }
5121 else
5122 s = dc_parse_token(p, t, flags);
5123 }
5124
5125 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5126 bc_parse_push(p, BC_INST_POP_EXEC);
5127
5128 return s;
5129}
5130
5131static BcStatus dc_parse_parse(BcParse *p)
5132{
5133 BcStatus s;
5134
5135 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005136 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005137 else
5138 s = dc_parse_expr(p, 0);
5139
Denys Vlasenkod38af482018-12-04 19:11:02 +01005140 if (s || G_interrupt) {
5141 bc_parse_reset(p);
5142 s = BC_STATUS_FAILURE;
5143 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005144
5145 return s;
5146}
5147
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005148static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005149{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005150 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005151}
5152#endif // ENABLE_DC
5153
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005154static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005155{
5156 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005157 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005158 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005159 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005160 }
5161}
5162
5163static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5164{
5165 if (IS_BC) {
5166 return bc_parse_expression(p, flags);
5167 } else {
5168 return dc_parse_expr(p, flags);
5169 }
5170}
5171
Denys Vlasenkodf515392018-12-02 19:27:48 +01005172static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005173{
Gavin Howard01055ba2018-11-03 11:00:21 -06005174 BcId e, *ptr;
5175 BcVec *v, *map;
5176 size_t i;
5177 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005178 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005179
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005180 v = var ? &G.prog.vars : &G.prog.arrs;
5181 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005182
5183 e.name = id;
5184 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005185 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005186
5187 if (new) {
5188 bc_array_init(&data.v, var);
5189 bc_vec_push(v, &data.v);
5190 }
5191
5192 ptr = bc_vec_item(map, i);
5193 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005194 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005195}
5196
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005197static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005198{
5199 BcStatus s = BC_STATUS_SUCCESS;
5200
5201 switch (r->t) {
5202
5203 case BC_RESULT_STR:
5204 case BC_RESULT_TEMP:
5205 case BC_RESULT_IBASE:
5206 case BC_RESULT_SCALE:
5207 case BC_RESULT_OBASE:
5208 {
5209 *num = &r->d.n;
5210 break;
5211 }
5212
5213 case BC_RESULT_CONSTANT:
5214 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005215 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005216 size_t base_t, len = strlen(*str);
5217 BcNum *base;
5218
5219 bc_num_init(&r->d.n, len);
5220
5221 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005222 base = hex ? &G.prog.hexb : &G.prog.ib;
5223 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005224 s = bc_num_parse(&r->d.n, *str, base, base_t);
5225
5226 if (s) {
5227 bc_num_free(&r->d.n);
5228 return s;
5229 }
5230
5231 *num = &r->d.n;
5232 r->t = BC_RESULT_TEMP;
5233
5234 break;
5235 }
5236
5237 case BC_RESULT_VAR:
5238 case BC_RESULT_ARRAY:
5239 case BC_RESULT_ARRAY_ELEM:
5240 {
5241 BcVec *v;
5242
Denys Vlasenkodf515392018-12-02 19:27:48 +01005243 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005244
5245 if (r->t == BC_RESULT_ARRAY_ELEM) {
5246 v = bc_vec_top(v);
5247 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5248 *num = bc_vec_item(v, r->d.id.idx);
5249 }
5250 else
5251 *num = bc_vec_top(v);
5252
5253 break;
5254 }
5255
5256 case BC_RESULT_LAST:
5257 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005258 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005259 break;
5260 }
5261
5262 case BC_RESULT_ONE:
5263 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005264 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005265 break;
5266 }
5267 }
5268
5269 return s;
5270}
5271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005272static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005273 BcResult **r, BcNum **rn, bool assign)
5274{
5275 BcStatus s;
5276 bool hex;
5277 BcResultType lt, rt;
5278
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005279 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005280 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005281
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005282 *r = bc_vec_item_rev(&G.prog.results, 0);
5283 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005284
5285 lt = (*l)->t;
5286 rt = (*r)->t;
5287 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5288
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005289 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005290 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005291 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005292 if (s) return s;
5293
5294 // We run this again under these conditions in case any vector has been
5295 // reallocated out from under the BcNums or arrays we had.
5296 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005297 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005298 if (s) return s;
5299 }
5300
5301 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005302 return bc_error_variable_is_wrong_type();
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005303 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005304 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005305
Gavin Howard01055ba2018-11-03 11:00:21 -06005306 return s;
5307}
5308
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005309static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005310{
5311 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005312 bc_vec_pop(&G.prog.results);
5313 bc_vec_pop(&G.prog.results);
5314 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005315}
5316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005317static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005318{
5319 BcStatus s;
5320
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005321 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005322 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005323 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005324
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005325 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005326 if (s) return s;
5327
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005328 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005329 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005330
5331 return s;
5332}
5333
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005334static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005335{
5336 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005337 bc_vec_pop(&G.prog.results);
5338 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005339}
5340
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005341static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005342{
5343 BcStatus s;
5344 BcResult *opd1, *opd2, res;
5345 BcNum *n1, *n2 = NULL;
5346
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005347 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005348 if (s) return s;
5349 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5350
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005351 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005352 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005353 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005354
5355 return s;
5356
5357err:
5358 bc_num_free(&res.d.n);
5359 return s;
5360}
5361
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005362static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005363{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005364 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005365 BcStatus s;
5366 BcParse parse;
5367 BcVec buf;
5368 BcInstPtr ip;
5369 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005370 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005371
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005372 for (i = 0; i < G.prog.stack.len; ++i) {
5373 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005374 if (ip_ptr->func == BC_PROG_READ)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005375 return bc_error_nested_read_call();
Gavin Howard01055ba2018-11-03 11:00:21 -06005376 }
5377
Denys Vlasenko7d628012018-12-04 21:46:47 +01005378 bc_vec_pop_all(&f->code);
5379 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005380
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005381 sv_file = G.prog.file;
5382 G.prog.file = NULL;
5383
Gavin Howard01055ba2018-11-03 11:00:21 -06005384 s = bc_read_line(&buf, "read> ");
5385 if (s) goto io_err;
5386
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005387 common_parse_init(&parse, BC_PROG_READ);
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005388 bc_lex_file(&parse.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005389
5390 s = bc_parse_text(&parse, buf.v);
5391 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005392 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005393 if (s) goto exec_err;
5394
5395 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005396 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005397 goto exec_err;
5398 }
5399
5400 ip.func = BC_PROG_READ;
5401 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005402 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005403
5404 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005405 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005406
5407 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005408 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005409
5410exec_err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01005411 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06005412 bc_parse_free(&parse);
5413io_err:
5414 bc_vec_free(&buf);
5415 return s;
5416}
5417
5418static size_t bc_program_index(char *code, size_t *bgn)
5419{
5420 char amt = code[(*bgn)++], i = 0;
5421 size_t res = 0;
5422
5423 for (; i < amt; ++i, ++(*bgn))
5424 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5425
5426 return res;
5427}
5428
5429static char *bc_program_name(char *code, size_t *bgn)
5430{
5431 size_t i;
5432 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5433
5434 s = xmalloc(ptr - str + 1);
5435 c = code[(*bgn)++];
5436
5437 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5438 s[i] = c;
5439
5440 s[i] = '\0';
5441
5442 return s;
5443}
5444
5445static void bc_program_printString(const char *str, size_t *nchars)
5446{
5447 size_t i, len = strlen(str);
5448
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005449#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005450 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005451 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005452 return;
5453 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005454#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005455
5456 for (i = 0; i < len; ++i, ++(*nchars)) {
5457
5458 int c = str[i];
5459
5460 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005461 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005462 else {
5463
5464 c = str[++i];
5465
5466 switch (c) {
5467
5468 case 'a':
5469 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005470 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005471 break;
5472 }
5473
5474 case 'b':
5475 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005476 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005477 break;
5478 }
5479
5480 case '\\':
5481 case 'e':
5482 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005483 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005484 break;
5485 }
5486
5487 case 'f':
5488 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005489 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005490 break;
5491 }
5492
5493 case 'n':
5494 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005495 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005496 *nchars = SIZE_MAX;
5497 break;
5498 }
5499
5500 case 'r':
5501 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005502 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005503 break;
5504 }
5505
5506 case 'q':
5507 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005508 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005509 break;
5510 }
5511
5512 case 't':
5513 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005514 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005515 break;
5516 }
5517
5518 default:
5519 {
5520 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005521 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005522 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005523 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005524 break;
5525 }
5526 }
5527 }
5528 }
5529}
5530
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005531static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005532{
5533 BcStatus s = BC_STATUS_SUCCESS;
5534 BcResult *r;
5535 size_t len, i;
5536 char *str;
5537 BcNum *num = NULL;
5538 bool pop = inst != BC_INST_PRINT;
5539
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005540 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005541 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005542
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005543 r = bc_vec_item_rev(&G.prog.results, idx);
5544 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005545 if (s) return s;
5546
5547 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005548 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5549 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005550 }
5551 else {
5552
5553 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005554 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005555
5556 if (inst == BC_INST_PRINT_STR) {
5557 for (i = 0, len = strlen(str); i < len; ++i) {
5558 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005559 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005560 if (c == '\n') G.prog.nchars = SIZE_MAX;
5561 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005562 }
5563 }
5564 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005565 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005566 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005567 }
5568 }
5569
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005570 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005571
5572 return s;
5573}
5574
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005575static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005576{
5577 BcStatus s;
5578 BcResult res, *ptr;
5579 BcNum *num = NULL;
5580
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005581 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005582 if (s) return s;
5583
5584 bc_num_init(&res.d.n, num->len);
5585 bc_num_copy(&res.d.n, num);
5586 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5587
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005588 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005589
5590 return s;
5591}
5592
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005593static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005594{
5595 BcStatus s;
5596 BcResult *opd1, *opd2, res;
5597 BcNum *n1, *n2;
5598 bool cond = 0;
5599 ssize_t cmp;
5600
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005601 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005602 if (s) return s;
5603 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5604
5605 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005606 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005607 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005608 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005609 else {
5610
5611 cmp = bc_num_cmp(n1, n2);
5612
5613 switch (inst) {
5614
5615 case BC_INST_REL_EQ:
5616 {
5617 cond = cmp == 0;
5618 break;
5619 }
5620
5621 case BC_INST_REL_LE:
5622 {
5623 cond = cmp <= 0;
5624 break;
5625 }
5626
5627 case BC_INST_REL_GE:
5628 {
5629 cond = cmp >= 0;
5630 break;
5631 }
5632
5633 case BC_INST_REL_NE:
5634 {
5635 cond = cmp != 0;
5636 break;
5637 }
5638
5639 case BC_INST_REL_LT:
5640 {
5641 cond = cmp < 0;
5642 break;
5643 }
5644
5645 case BC_INST_REL_GT:
5646 {
5647 cond = cmp > 0;
5648 break;
5649 }
5650 }
5651 }
5652
5653 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5654
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005655 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005656
5657 return s;
5658}
5659
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005660#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005661static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005662 bool push)
5663{
5664 BcNum n2;
5665 BcResult res;
5666
5667 memset(&n2, 0, sizeof(BcNum));
5668 n2.rdx = res.d.id.idx = r->d.id.idx;
5669 res.t = BC_RESULT_STR;
5670
5671 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005672 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005673 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005674 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005675 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005676 }
5677
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005678 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005679
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005680 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005681 bc_vec_push(v, &n2);
5682
5683 return BC_STATUS_SUCCESS;
5684}
5685#endif // ENABLE_DC
5686
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005687static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005688{
5689 BcStatus s;
5690 BcResult *ptr, r;
5691 BcVec *v;
5692 BcNum *n;
5693
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005694 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005695 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06005696
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005697 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005698 if ((ptr->t == BC_RESULT_ARRAY) != !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005699 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005700 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005701
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005702#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005703 if (ptr->t == BC_RESULT_STR && !var)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005704 return bc_error_variable_is_wrong_type();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005705 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005706#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005707
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005708 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005709 if (s) return s;
5710
5711 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005712 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005713
5714 if (var) {
5715 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5716 bc_num_copy(&r.d.n, n);
5717 }
5718 else {
5719 bc_array_init(&r.d.v, true);
5720 bc_array_copy(&r.d.v, (BcVec *) n);
5721 }
5722
5723 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005724 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005725
5726 return s;
5727}
5728
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005729static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005730{
5731 BcStatus s;
5732 BcResult *left, *right, res;
5733 BcNum *l = NULL, *r = NULL;
5734 unsigned long val, max;
5735 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5736
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005737 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005738 if (s) return s;
5739
5740 ib = left->t == BC_RESULT_IBASE;
5741 sc = left->t == BC_RESULT_SCALE;
5742
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005743#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005744
5745 if (right->t == BC_RESULT_STR) {
5746
5747 BcVec *v;
5748
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005749 if (left->t != BC_RESULT_VAR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005750 return bc_error_variable_is_wrong_type();
Denys Vlasenkodf515392018-12-02 19:27:48 +01005751 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005752
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005753 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005754 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005755#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005756
5757 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005758 return bc_error("bad assignment:"
5759 " left side must be scale,"
5760 " ibase, obase, last, var,"
5761 " or array element"
5762 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005763
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005764#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005765 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005766 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005767
5768 if (assign)
5769 bc_num_copy(l, r);
5770 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005771 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005772
5773 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005774#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005775 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005776#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005777
5778 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005779 static const char *const msg[] = {
5780 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5781 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5782 "?1", //BC_RESULT_LAST
5783 "?2", //BC_RESULT_CONSTANT
5784 "?3", //BC_RESULT_ONE
5785 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5786 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005787 size_t *ptr;
5788
5789 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005790 if (s)
5791 return s;
5792 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005793 if (sc) {
5794 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005795 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005796 }
5797 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005798 if (val < BC_NUM_MIN_BASE)
5799 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005800 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005801 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005802 }
5803
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005804 if (val > max)
5805 return bc_error(msg[s]);
5806 if (!sc)
5807 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005808
5809 *ptr = (size_t) val;
5810 s = BC_STATUS_SUCCESS;
5811 }
5812
5813 bc_num_init(&res.d.n, l->len);
5814 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005815 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005816
5817 return s;
5818}
5819
Denys Vlasenko416ce762018-12-02 20:57:17 +01005820#if !ENABLE_DC
5821#define bc_program_pushVar(code, bgn, pop, copy) \
5822 bc_program_pushVar(code, bgn)
5823// for bc, 'pop' and 'copy' are always false
5824#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005825static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005826 bool pop, bool copy)
5827{
5828 BcStatus s = BC_STATUS_SUCCESS;
5829 BcResult r;
5830 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005831
5832 r.t = BC_RESULT_VAR;
5833 r.d.id.name = name;
5834
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005835#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005836 {
5837 BcVec *v = bc_program_search(name, true);
5838 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005839
Denys Vlasenko416ce762018-12-02 20:57:17 +01005840 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005841
Denys Vlasenko416ce762018-12-02 20:57:17 +01005842 if (!BC_PROG_STACK(v, 2 - copy)) {
5843 free(name);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005844 return bc_error_stack_has_too_few_elements();
Denys Vlasenko416ce762018-12-02 20:57:17 +01005845 }
5846
Gavin Howard01055ba2018-11-03 11:00:21 -06005847 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005848 name = NULL;
5849
5850 if (!BC_PROG_STR(num)) {
5851
5852 r.t = BC_RESULT_TEMP;
5853
5854 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5855 bc_num_copy(&r.d.n, num);
5856 }
5857 else {
5858 r.t = BC_RESULT_STR;
5859 r.d.id.idx = num->rdx;
5860 }
5861
5862 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005863 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005864 }
5865#endif // ENABLE_DC
5866
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005867 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005868
5869 return s;
5870}
5871
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005872static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005873 char inst)
5874{
5875 BcStatus s = BC_STATUS_SUCCESS;
5876 BcResult r;
5877 BcNum *num;
5878
5879 r.d.id.name = bc_program_name(code, bgn);
5880
5881 if (inst == BC_INST_ARRAY) {
5882 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005883 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005884 }
5885 else {
5886
5887 BcResult *operand;
5888 unsigned long temp;
5889
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005890 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005891 if (s) goto err;
5892 s = bc_num_ulong(num, &temp);
5893 if (s) goto err;
5894
5895 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005896 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005897 goto err;
5898 }
5899
5900 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005901 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005902 }
5903
5904err:
5905 if (s) free(r.d.id.name);
5906 return s;
5907}
5908
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005909#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005910static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005911{
5912 BcStatus s;
5913 BcResult *ptr, res, copy;
5914 BcNum *num = NULL;
5915 char inst2 = inst;
5916
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005917 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005918 if (s) return s;
5919
5920 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5921 copy.t = BC_RESULT_TEMP;
5922 bc_num_init(&copy.d.n, num->len);
5923 bc_num_copy(&copy.d.n, num);
5924 }
5925
5926 res.t = BC_RESULT_ONE;
5927 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5928 BC_INST_ASSIGN_PLUS :
5929 BC_INST_ASSIGN_MINUS;
5930
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005931 bc_vec_push(&G.prog.results, &res);
5932 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005933
5934 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005935 bc_vec_pop(&G.prog.results);
5936 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005937 }
5938
5939 return s;
5940}
5941
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005942static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005943{
5944 BcStatus s = BC_STATUS_SUCCESS;
5945 BcInstPtr ip;
5946 size_t i, nparams = bc_program_index(code, idx);
5947 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005948 BcId *a;
5949 BcResultData param;
5950 BcResult *arg;
5951
5952 ip.idx = 0;
5953 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005954 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005955
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005956 if (func->code.len == 0) {
5957 return bc_error("undefined function");
5958 }
5959 if (nparams != func->nparams) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005960 return bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams);
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005961 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005962 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005963
5964 for (i = 0; i < nparams; ++i) {
5965
5966 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005967 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005968
5969 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01005970 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06005971
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005972 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005973 if (s) return s;
5974 }
5975
5976 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005977 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005978
5979 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005980 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005981
5982 if (a->idx) {
5983 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5984 bc_vec_push(v, &param.n);
5985 }
5986 else {
5987 bc_array_init(&param.v, true);
5988 bc_vec_push(v, &param.v);
5989 }
5990 }
5991
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005992 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005993
5994 return BC_STATUS_SUCCESS;
5995}
5996
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005997static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005998{
5999 BcStatus s;
6000 BcResult res;
6001 BcFunc *f;
6002 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006003 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006004
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006005 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006006 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006007
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006008 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006009 res.t = BC_RESULT_TEMP;
6010
6011 if (inst == BC_INST_RET) {
6012
6013 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006014 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006015
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006016 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006017 if (s) return s;
6018 bc_num_init(&res.d.n, num->len);
6019 bc_num_copy(&res.d.n, num);
6020 }
6021 else {
6022 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6023 bc_num_zero(&res.d.n);
6024 }
6025
6026 // We need to pop arguments as well, so this takes that into account.
6027 for (i = 0; i < f->autos.len; ++i) {
6028
6029 BcVec *v;
6030 BcId *a = bc_vec_item(&f->autos, i);
6031
Denys Vlasenkodf515392018-12-02 19:27:48 +01006032 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006033 bc_vec_pop(v);
6034 }
6035
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006036 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6037 bc_vec_push(&G.prog.results, &res);
6038 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006039
6040 return BC_STATUS_SUCCESS;
6041}
6042#endif // ENABLE_BC
6043
6044static unsigned long bc_program_scale(BcNum *n)
6045{
6046 return (unsigned long) n->rdx;
6047}
6048
6049static unsigned long bc_program_len(BcNum *n)
6050{
6051 unsigned long len = n->len;
6052 size_t i;
6053
6054 if (n->rdx != n->len) return len;
6055 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6056
6057 return len;
6058}
6059
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006060static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006061{
6062 BcStatus s;
6063 BcResult *opnd;
6064 BcNum *num = NULL;
6065 BcResult res;
6066 bool len = inst == BC_INST_LENGTH;
6067
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006068 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006069 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006070 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006071
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006072 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006073 if (s) return s;
6074
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006075#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006076 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006077 return bc_error_variable_is_wrong_type();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006078#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006079
6080 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6081
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006082 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006083#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006084 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006085 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006086 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006087#endif
6088#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006089 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6090
6091 char **str;
6092 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6093
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006094 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006095 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006096 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006097#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006098 else {
6099 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006100 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006101 }
6102
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006103 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006104
6105 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006106}
6107
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006108#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006109static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006110{
6111 BcStatus s;
6112 BcResult *opd1, *opd2, res, res2;
6113 BcNum *n1, *n2 = NULL;
6114
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006115 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006116 if (s) return s;
6117
6118 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6119 bc_num_init(&res2.d.n, n2->len);
6120
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006121 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006122 if (s) goto err;
6123
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006124 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006125 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006126 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006127
6128 return s;
6129
6130err:
6131 bc_num_free(&res2.d.n);
6132 bc_num_free(&res.d.n);
6133 return s;
6134}
6135
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006136static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006137{
6138 BcStatus s;
6139 BcResult *r1, *r2, *r3, res;
6140 BcNum *n1, *n2, *n3;
6141
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006142 if (!BC_PROG_STACK(&G.prog.results, 3))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006143 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006144 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006145 if (s) return s;
6146
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006147 r1 = bc_vec_item_rev(&G.prog.results, 2);
6148 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006149 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006150 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006151 return bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006152
6153 // Make sure that the values have their pointers updated, if necessary.
6154 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6155
6156 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006157 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006158 if (s) return s;
6159 }
6160
6161 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006162 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006163 if (s) return s;
6164 }
6165 }
6166
6167 bc_num_init(&res.d.n, n3->len);
6168 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6169 if (s) goto err;
6170
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006171 bc_vec_pop(&G.prog.results);
6172 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006173
6174 return s;
6175
6176err:
6177 bc_num_free(&res.d.n);
6178 return s;
6179}
6180
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006181static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006182{
Gavin Howard01055ba2018-11-03 11:00:21 -06006183 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006185
6186 res.t = BC_RESULT_TEMP;
6187
6188 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006189 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006190 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006191}
6192
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006193static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006194{
6195 BcStatus s;
6196 BcResult *r, res;
6197 BcNum *num = NULL, n;
6198 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006199 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006200 unsigned long val;
6201
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006202 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006203 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006204 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006205
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006206 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006207 if (s) return s;
6208
6209 if (BC_PROG_NUM(r, num)) {
6210
6211 bc_num_init(&n, BC_NUM_DEF_SIZE);
6212 bc_num_copy(&n, num);
6213 bc_num_truncate(&n, n.rdx);
6214
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006215 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006216 if (s) goto num_err;
6217 s = bc_num_ulong(&n, &val);
6218 if (s) goto num_err;
6219
6220 c = (char) val;
6221
6222 bc_num_free(&n);
6223 }
6224 else {
6225 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006226 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006227 c = str2[0];
6228 }
6229
6230 str = xmalloc(2);
6231 str[0] = c;
6232 str[1] = '\0';
6233
6234 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006235 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006236
6237 if (idx != len + BC_PROG_REQ_FUNCS) {
6238
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006239 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6240 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006241 len = idx;
6242 break;
6243 }
6244 }
6245
6246 free(str);
6247 }
6248 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006249 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006250
6251 res.t = BC_RESULT_STR;
6252 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006253 bc_vec_pop(&G.prog.results);
6254 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006255
6256 return BC_STATUS_SUCCESS;
6257
6258num_err:
6259 bc_num_free(&n);
6260 return s;
6261}
6262
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006263static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006264{
6265 BcStatus s;
6266 BcResult *r;
6267 BcNum *n = NULL;
6268 size_t idx;
6269 char *str;
6270
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006271 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006272 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006273 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006274
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006275 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006276 if (s) return s;
6277
6278 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006279 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006280 else {
6281 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006282 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006283 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006284 }
6285
6286 return s;
6287}
6288
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006289static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006290{
6291 BcStatus s;
6292 BcResult *opnd;
6293 BcNum *num = NULL;
6294 unsigned long val;
6295
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006296 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006297 if (s) return s;
6298 s = bc_num_ulong(num, &val);
6299 if (s) return s;
6300
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006301 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006302
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006303 if (G.prog.stack.len < val)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006304 return bc_error_stack_has_too_few_elements();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006305 if (G.prog.stack.len == val)
6306 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006307
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006308 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006309
6310 return s;
6311}
6312
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006313static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006314 bool cond)
6315{
6316 BcStatus s = BC_STATUS_SUCCESS;
6317 BcResult *r;
6318 char **str;
6319 BcFunc *f;
6320 BcParse prs;
6321 BcInstPtr ip;
6322 size_t fidx, sidx;
6323 BcNum *n;
6324 bool exec;
6325
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006326 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006327 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006328
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006329 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006330
6331 if (cond) {
6332
Gavin Howard01055ba2018-11-03 11:00:21 -06006333 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6334
6335 if (code[*bgn] == BC_PARSE_STREND)
6336 (*bgn) += 1;
6337 else
6338 else_name = bc_program_name(code, bgn);
6339
6340 exec = r->d.n.len != 0;
6341
6342 if (exec)
6343 name = then_name;
6344 else if (else_name != NULL) {
6345 exec = true;
6346 name = else_name;
6347 }
6348
6349 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006350 BcVec *v;
6351 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006352 n = bc_vec_top(v);
6353 }
6354
6355 free(then_name);
6356 free(else_name);
6357
6358 if (!exec) goto exit;
6359 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006360 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006361 goto exit;
6362 }
6363
6364 sidx = n->rdx;
6365 }
6366 else {
6367
6368 if (r->t == BC_RESULT_STR)
6369 sidx = r->d.id.idx;
6370 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006371 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006372 if (s || !BC_PROG_STR(n)) goto exit;
6373 sidx = n->rdx;
6374 }
6375 else
6376 goto exit;
6377 }
6378
6379 fidx = sidx + BC_PROG_REQ_FUNCS;
6380
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006381 str = bc_vec_item(&G.prog.strs, sidx);
6382 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006383
6384 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006385 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006386 s = bc_parse_text(&prs, *str);
6387 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006388 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006389 if (s) goto err;
6390
6391 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006392 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06006393 goto err;
6394 }
6395
6396 bc_parse_free(&prs);
6397 }
6398
6399 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006400 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006401 ip.func = fidx;
6402
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006403 bc_vec_pop(&G.prog.results);
6404 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006405
6406 return BC_STATUS_SUCCESS;
6407
6408err:
6409 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006410 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006411 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006412exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006413 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006414 return s;
6415}
6416#endif // ENABLE_DC
6417
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006418static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006419{
Gavin Howard01055ba2018-11-03 11:00:21 -06006420 BcResult res;
6421 unsigned long val;
6422
6423 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6424 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006425 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006426 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006427 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006428 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006429 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006430
6431 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006432 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006433 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006434}
6435
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006436static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006437{
Gavin Howard01055ba2018-11-03 11:00:21 -06006438 BcId entry, *entry_ptr;
6439 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006440 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006441
6442 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006443 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006444
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006445 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6446 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006447
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006448 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006449 *idx = entry_ptr->idx;
6450
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006451 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006452
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006453 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006454
6455 // We need to reset these, so the function can be repopulated.
6456 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006457 bc_vec_pop_all(&func->autos);
6458 bc_vec_pop_all(&func->code);
6459 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006460 }
6461 else {
6462 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006463 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 }
6465}
6466
Denys Vlasenkod38af482018-12-04 19:11:02 +01006467// Called when parsing or execution detects a failure,
6468// resets execution structures.
6469static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006470{
6471 BcFunc *f;
6472 BcInstPtr *ip;
6473
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006474 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006475 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006476
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006477 f = bc_vec_item(&G.prog.fns, 0);
6478 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006479 ip->idx = f->code.len;
6480
Denys Vlasenkod38af482018-12-04 19:11:02 +01006481 // If !tty, no need to check for ^C: we don't have ^C handler,
6482 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006483}
6484
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006485static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006486{
6487 BcStatus s = BC_STATUS_SUCCESS;
6488 size_t idx;
6489 BcResult r, *ptr;
6490 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006491 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6492 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006493 char *code = func->code.v;
6494 bool cond = false;
6495
6496 while (!s && ip->idx < func->code.len) {
6497
6498 char inst = code[(ip->idx)++];
6499
6500 switch (inst) {
6501
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006502#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006503 case BC_INST_JUMP_ZERO:
6504 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006505 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006506 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006507 cond = !bc_num_cmp(num, &G.prog.zero);
6508 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006509 }
6510 // Fallthrough.
6511 case BC_INST_JUMP:
6512 {
6513 size_t *addr;
6514 idx = bc_program_index(code, &ip->idx);
6515 addr = bc_vec_item(&func->labels, idx);
6516 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6517 break;
6518 }
6519
6520 case BC_INST_CALL:
6521 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006522 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006523 break;
6524 }
6525
6526 case BC_INST_INC_PRE:
6527 case BC_INST_DEC_PRE:
6528 case BC_INST_INC_POST:
6529 case BC_INST_DEC_POST:
6530 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006531 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006532 break;
6533 }
6534
6535 case BC_INST_HALT:
6536 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006537 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006538 break;
6539 }
6540
6541 case BC_INST_RET:
6542 case BC_INST_RET0:
6543 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006544 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006545 break;
6546 }
6547
6548 case BC_INST_BOOL_OR:
6549 case BC_INST_BOOL_AND:
6550#endif // ENABLE_BC
6551 case BC_INST_REL_EQ:
6552 case BC_INST_REL_LE:
6553 case BC_INST_REL_GE:
6554 case BC_INST_REL_NE:
6555 case BC_INST_REL_LT:
6556 case BC_INST_REL_GT:
6557 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006558 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006559 break;
6560 }
6561
6562 case BC_INST_READ:
6563 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006564 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006565 break;
6566 }
6567
6568 case BC_INST_VAR:
6569 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006570 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006571 break;
6572 }
6573
6574 case BC_INST_ARRAY_ELEM:
6575 case BC_INST_ARRAY:
6576 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006577 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006578 break;
6579 }
6580
6581 case BC_INST_LAST:
6582 {
6583 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006584 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006585 break;
6586 }
6587
6588 case BC_INST_IBASE:
6589 case BC_INST_SCALE:
6590 case BC_INST_OBASE:
6591 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006592 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006593 break;
6594 }
6595
6596 case BC_INST_SCALE_FUNC:
6597 case BC_INST_LENGTH:
6598 case BC_INST_SQRT:
6599 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006600 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006601 break;
6602 }
6603
6604 case BC_INST_NUM:
6605 {
6606 r.t = BC_RESULT_CONSTANT;
6607 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006608 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006609 break;
6610 }
6611
6612 case BC_INST_POP:
6613 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006614 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006615 s = bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006616 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006617 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006618 break;
6619 }
6620
6621 case BC_INST_POP_EXEC:
6622 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006623 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006624 break;
6625 }
6626
6627 case BC_INST_PRINT:
6628 case BC_INST_PRINT_POP:
6629 case BC_INST_PRINT_STR:
6630 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006631 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006632 break;
6633 }
6634
6635 case BC_INST_STR:
6636 {
6637 r.t = BC_RESULT_STR;
6638 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006639 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006640 break;
6641 }
6642
6643 case BC_INST_POWER:
6644 case BC_INST_MULTIPLY:
6645 case BC_INST_DIVIDE:
6646 case BC_INST_MODULUS:
6647 case BC_INST_PLUS:
6648 case BC_INST_MINUS:
6649 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006650 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006651 break;
6652 }
6653
6654 case BC_INST_BOOL_NOT:
6655 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006656 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006657 if (s) return s;
6658
6659 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006660 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6661 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006662
6663 break;
6664 }
6665
6666 case BC_INST_NEG:
6667 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006668 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006669 break;
6670 }
6671
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006672#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006673 case BC_INST_ASSIGN_POWER:
6674 case BC_INST_ASSIGN_MULTIPLY:
6675 case BC_INST_ASSIGN_DIVIDE:
6676 case BC_INST_ASSIGN_MODULUS:
6677 case BC_INST_ASSIGN_PLUS:
6678 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006679#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006680 case BC_INST_ASSIGN:
6681 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006682 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006683 break;
6684 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006685#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006686 case BC_INST_MODEXP:
6687 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006688 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006689 break;
6690 }
6691
6692 case BC_INST_DIVMOD:
6693 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006694 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006695 break;
6696 }
6697
6698 case BC_INST_EXECUTE:
6699 case BC_INST_EXEC_COND:
6700 {
6701 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006702 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006703 break;
6704 }
6705
6706 case BC_INST_PRINT_STACK:
6707 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006708 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6709 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006710 break;
6711 }
6712
6713 case BC_INST_CLEAR_STACK:
6714 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006715 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006716 break;
6717 }
6718
6719 case BC_INST_STACK_LEN:
6720 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006721 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006722 break;
6723 }
6724
6725 case BC_INST_DUPLICATE:
6726 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006727 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006728 return bc_error_stack_has_too_few_elements();
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006729 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006730 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006731 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006732 break;
6733 }
6734
6735 case BC_INST_SWAP:
6736 {
6737 BcResult *ptr2;
6738
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006739 if (!BC_PROG_STACK(&G.prog.results, 2))
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006740 return bc_error_stack_has_too_few_elements();
Gavin Howard01055ba2018-11-03 11:00:21 -06006741
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006742 ptr = bc_vec_item_rev(&G.prog.results, 0);
6743 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006744 memcpy(&r, ptr, sizeof(BcResult));
6745 memcpy(ptr, ptr2, sizeof(BcResult));
6746 memcpy(ptr2, &r, sizeof(BcResult));
6747
6748 break;
6749 }
6750
6751 case BC_INST_ASCIIFY:
6752 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006753 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006754 break;
6755 }
6756
6757 case BC_INST_PRINT_STREAM:
6758 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006759 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006760 break;
6761 }
6762
6763 case BC_INST_LOAD:
6764 case BC_INST_PUSH_VAR:
6765 {
6766 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006767 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006768 break;
6769 }
6770
6771 case BC_INST_PUSH_TO_VAR:
6772 {
6773 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006774 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006775 free(name);
6776 break;
6777 }
6778
6779 case BC_INST_QUIT:
6780 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006781 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006782 quit();
6783 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006784 break;
6785 }
6786
6787 case BC_INST_NQUIT:
6788 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006789 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006790 break;
6791 }
6792#endif // ENABLE_DC
6793 }
6794
Denys Vlasenkod38af482018-12-04 19:11:02 +01006795 if (s || G_interrupt) {
6796 bc_program_reset();
6797 break;
6798 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006799
6800 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006801 ip = bc_vec_top(&G.prog.stack);
6802 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006803 code = func->code.v;
6804 }
6805
6806 return s;
6807}
6808
Denys Vlasenko00d77792018-11-30 23:13:42 +01006809static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006810{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006811 printf("%s "BB_VER"\n"
6812 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006813 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006814 "This is free software with ABSOLUTELY NO WARRANTY\n"
6815 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816}
6817
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006818#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006819static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006820{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006821 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6822
Gavin Howard01055ba2018-11-03 11:00:21 -06006823 BcVec v;
6824 char *env_args = getenv(bc_args_env_name), *buf;
6825
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006826 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006827
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006828 G.env_args = xstrdup(env_args);
6829 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006830
6831 bc_vec_init(&v, sizeof(char *), NULL);
6832 bc_vec_push(&v, &bc_args_env_name);
6833
6834 while (*buf != 0) {
6835 if (!isspace(*buf)) {
6836 bc_vec_push(&v, &buf);
6837 while (*buf != 0 && !isspace(*buf)) ++buf;
6838 if (*buf != 0) (*(buf++)) = '\0';
6839 }
6840 else
6841 ++buf;
6842 }
6843
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006844 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006845
6846 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006847}
6848#endif // ENABLE_BC
6849
6850static size_t bc_vm_envLen(const char *var)
6851{
6852 char *lenv = getenv(var);
6853 size_t i, len = BC_NUM_PRINT_WIDTH;
6854 int num;
6855
6856 if (!lenv) return len;
6857
6858 len = strlen(lenv);
6859
6860 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6861 if (num) {
6862 len = (size_t) atoi(lenv) - 1;
6863 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6864 }
6865 else
6866 len = BC_NUM_PRINT_WIDTH;
6867
6868 return len;
6869}
6870
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006871static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006872{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006873 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006874
Gavin Howard01055ba2018-11-03 11:00:21 -06006875 if (s) return s;
6876
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006877 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006878 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006879 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006880 }
6881
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006882 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006883 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006884 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006885 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006886 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006887 }
6888
6889 return s;
6890}
6891
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006892static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006893{
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006894 const char *sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06006895 char *data;
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006896 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006897 BcFunc *main_func;
6898 BcInstPtr *ip;
6899
Denys Vlasenkodf515392018-12-02 19:27:48 +01006900 data = bc_read_file(file);
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006901 if (!data) return bc_error_fmt("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006902
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006903 sv_file = G.prog.file;
6904 G.prog.file = file;
6905 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006906 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006907 if (s) goto err;
6908
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006909 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6910 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006911
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006912 if (main_func->code.len < ip->idx)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006913 s = bc_error_fmt("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006914
6915err:
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006916 G.prog.file = sv_file;
Gavin Howard01055ba2018-11-03 11:00:21 -06006917 free(data);
6918 return s;
6919}
6920
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006921static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006922{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006923 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006924 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006925 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006926 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006927
Denys Vlasenko0409ad32018-12-05 16:39:22 +01006928 G.prog.file = NULL;
6929 bc_lex_file(&G.prs.l);
Gavin Howard01055ba2018-11-03 11:00:21 -06006930
Denys Vlasenko7d628012018-12-04 21:46:47 +01006931 bc_char_vec_init(&buffer);
6932 bc_char_vec_init(&buf);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01006933 bc_vec_pushZeroByte(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06006934
6935 // This loop is complex because the vm tries not to send any lines that end
6936 // with a backslash to the parser. The reason for that is because the parser
6937 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6938 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006939 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006940
6941 char *string = buf.v;
6942
6943 len = buf.len - 1;
6944
6945 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006946 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006947 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006948 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006949 str += 1;
6950 }
6951 else if (len > 1 || comment) {
6952
6953 for (i = 0; i < len; ++i) {
6954
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006955 bool notend = len > i + 1;
6956 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006957
6958 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006959 if (G.sbgn == G.send)
6960 str ^= c == G.sbgn;
6961 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006962 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006963 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006964 str += 1;
6965 }
6966
6967 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6968 comment = true;
6969 break;
6970 }
6971 else if (c == '*' && notend && comment && string[i + 1] == '/')
6972 comment = false;
6973 }
6974
6975 if (str || comment || string[len - 2] == '\\') {
6976 bc_vec_concat(&buffer, buf.v);
6977 continue;
6978 }
6979 }
6980
6981 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006982 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006983 if (s) {
6984 fflush_and_check();
6985 fputs("ready for more input\n", stderr);
6986 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006987
Denys Vlasenko7d628012018-12-04 21:46:47 +01006988 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06006989 }
6990
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006991 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006992 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006993 }
6994 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006995 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006996 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006997
Gavin Howard01055ba2018-11-03 11:00:21 -06006998 bc_vec_free(&buf);
6999 bc_vec_free(&buffer);
7000 return s;
7001}
7002
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007003#if ENABLE_BC
7004static const char bc_lib[] = {
7005 "scale=20"
7006"\n" "define e(x){"
7007"\n" "auto b,s,n,r,d,i,p,f,v"
7008"\n" "b=ibase"
7009"\n" "ibase=A"
7010"\n" "if(x<0){"
7011"\n" "n=1"
7012"\n" "x=-x"
7013"\n" "}"
7014"\n" "s=scale"
7015"\n" "r=6+s+0.44*x"
7016"\n" "scale=scale(x)+1"
7017"\n" "while(x>1){"
7018"\n" "d+=1"
7019"\n" "x/=2"
7020"\n" "scale+=1"
7021"\n" "}"
7022"\n" "scale=r"
7023"\n" "r=x+1"
7024"\n" "p=x"
7025"\n" "f=v=1"
7026"\n" "for(i=2;v!=0;++i){"
7027"\n" "p*=x"
7028"\n" "f*=i"
7029"\n" "v=p/f"
7030"\n" "r+=v"
7031"\n" "}"
7032"\n" "while((d--)!=0)r*=r"
7033"\n" "scale=s"
7034"\n" "ibase=b"
7035"\n" "if(n!=0)return(1/r)"
7036"\n" "return(r/1)"
7037"\n" "}"
7038"\n" "define l(x){"
7039"\n" "auto b,s,r,p,a,q,i,v"
7040"\n" "b=ibase"
7041"\n" "ibase=A"
7042"\n" "if(x<=0){"
7043"\n" "r=(1-10^scale)/1"
7044"\n" "ibase=b"
7045"\n" "return(r)"
7046"\n" "}"
7047"\n" "s=scale"
7048"\n" "scale+=6"
7049"\n" "p=2"
7050"\n" "while(x>=2){"
7051"\n" "p*=2"
7052"\n" "x=sqrt(x)"
7053"\n" "}"
7054"\n" "while(x<=0.5){"
7055"\n" "p*=2"
7056"\n" "x=sqrt(x)"
7057"\n" "}"
7058"\n" "r=a=(x-1)/(x+1)"
7059"\n" "q=a*a"
7060"\n" "v=1"
7061"\n" "for(i=3;v!=0;i+=2){"
7062"\n" "a*=q"
7063"\n" "v=a/i"
7064"\n" "r+=v"
7065"\n" "}"
7066"\n" "r*=p"
7067"\n" "scale=s"
7068"\n" "ibase=b"
7069"\n" "return(r/1)"
7070"\n" "}"
7071"\n" "define s(x){"
7072"\n" "auto b,s,r,n,a,q,i"
7073"\n" "b=ibase"
7074"\n" "ibase=A"
7075"\n" "s=scale"
7076"\n" "scale=1.1*s+2"
7077"\n" "a=a(1)"
7078"\n" "if(x<0){"
7079"\n" "n=1"
7080"\n" "x=-x"
7081"\n" "}"
7082"\n" "scale=0"
7083"\n" "q=(x/a+2)/4"
7084"\n" "x=x-4*q*a"
7085"\n" "if(q%2!=0)x=-x"
7086"\n" "scale=s+2"
7087"\n" "r=a=x"
7088"\n" "q=-x*x"
7089"\n" "for(i=3;a!=0;i+=2){"
7090"\n" "a*=q/(i*(i-1))"
7091"\n" "r+=a"
7092"\n" "}"
7093"\n" "scale=s"
7094"\n" "ibase=b"
7095"\n" "if(n!=0)return(-r/1)"
7096"\n" "return(r/1)"
7097"\n" "}"
7098"\n" "define c(x){"
7099"\n" "auto b,s"
7100"\n" "b=ibase"
7101"\n" "ibase=A"
7102"\n" "s=scale"
7103"\n" "scale*=1.2"
7104"\n" "x=s(2*a(1)+x)"
7105"\n" "scale=s"
7106"\n" "ibase=b"
7107"\n" "return(x/1)"
7108"\n" "}"
7109"\n" "define a(x){"
7110"\n" "auto b,s,r,n,a,m,t,f,i,u"
7111"\n" "b=ibase"
7112"\n" "ibase=A"
7113"\n" "n=1"
7114"\n" "if(x<0){"
7115"\n" "n=-1"
7116"\n" "x=-x"
7117"\n" "}"
7118"\n" "if(x==1){"
7119"\n" "if(scale<65){"
7120"\n" "return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7121"\n" "}"
7122"\n" "}"
7123"\n" "if(x==.2){"
7124"\n" "if(scale<65){"
7125"\n" "return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
7126"\n" "}"
7127"\n" "}"
7128"\n" "s=scale"
7129"\n" "if(x>.2){"
7130"\n" "scale+=5"
7131"\n" "a=a(.2)"
7132"\n" "}"
7133"\n" "scale=s+3"
7134"\n" "while(x>.2){"
7135"\n" "m+=1"
7136"\n" "x=(x-.2)/(1+.2*x)"
7137"\n" "}"
7138"\n" "r=u=x"
7139"\n" "f=-x*x"
7140"\n" "t=1"
7141"\n" "for(i=3;t!=0;i+=2){"
7142"\n" "u*=f"
7143"\n" "t=u/i"
7144"\n" "r+=t"
7145"\n" "}"
7146"\n" "scale=s"
7147"\n" "ibase=b"
7148"\n" "return((m*a+r)/n)"
7149"\n" "}"
7150"\n" "define j(n,x){"
7151"\n" "auto b,s,o,a,i,v,f"
7152"\n" "b=ibase"
7153"\n" "ibase=A"
7154"\n" "s=scale"
7155"\n" "scale=0"
7156"\n" "n/=1"
7157"\n" "if(n<0){"
7158"\n" "n=-n"
7159"\n" "if(n%2==1)o=1"
7160"\n" "}"
7161"\n" "a=1"
7162"\n" "for(i=2;i<=n;++i)a*=i"
7163"\n" "scale=1.5*s"
7164"\n" "a=(x^n)/2^n/a"
7165"\n" "r=v=1"
7166"\n" "f=-x*x/4"
7167"\n" "scale=scale+length(a)-scale(a)"
7168"\n" "for(i=1;v!=0;++i){"
7169"\n" "v=v*f/i/(n+i)"
7170"\n" "r+=v"
7171"\n" "}"
7172"\n" "scale=s"
7173"\n" "ibase=b"
7174"\n" "if(o!=0)a=-a"
7175"\n" "return(a*r/1)"
7176"\n" "}"
7177};
7178#endif // ENABLE_BC
7179
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007180static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007181{
7182 BcStatus s = BC_STATUS_SUCCESS;
7183 size_t i;
7184
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007185#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007186 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007187
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007188 // We know that internal library is not buggy,
7189 // thus error checking is normally disabled.
7190# define DEBUG_LIB 0
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007191 bc_lex_file(&G.prs.l);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007192 s = bc_parse_text(&G.prs, bc_lib);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007193 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007194
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007195 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007196 s = G.prs.parse(&G.prs);
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007197 if (DEBUG_LIB && s) return s;
7198 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007199 s = bc_program_exec();
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007200 if (DEBUG_LIB && s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007201 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007202#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007203
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007204 for (i = 0; !s && i < G.files.len; ++i)
7205 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007206 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007207 fflush_and_check();
7208 fputs("ready for more input\n", stderr);
7209 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007210
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007211 if (IS_BC || !G.files.len)
7212 s = bc_vm_stdin();
7213 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7214 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007215
Denys Vlasenko00d77792018-11-30 23:13:42 +01007216 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007217}
7218
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007219#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007220static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007221{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007222 bc_num_free(&G.prog.ib);
7223 bc_num_free(&G.prog.ob);
7224 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007225# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007226 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007227# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007228 bc_vec_free(&G.prog.fns);
7229 bc_vec_free(&G.prog.fn_map);
7230 bc_vec_free(&G.prog.vars);
7231 bc_vec_free(&G.prog.var_map);
7232 bc_vec_free(&G.prog.arrs);
7233 bc_vec_free(&G.prog.arr_map);
7234 bc_vec_free(&G.prog.strs);
7235 bc_vec_free(&G.prog.consts);
7236 bc_vec_free(&G.prog.results);
7237 bc_vec_free(&G.prog.stack);
7238 bc_num_free(&G.prog.last);
7239 bc_num_free(&G.prog.zero);
7240 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007241}
7242
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007243static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007244{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007245 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007246 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007247 bc_parse_free(&G.prs);
7248 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007249}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007250#endif
7251
7252static void bc_program_init(size_t line_len)
7253{
7254 size_t idx;
7255 BcInstPtr ip;
7256
7257 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7258 memset(&ip, 0, sizeof(BcInstPtr));
7259
7260 /* G.prog.nchars = G.prog.scale = 0; - already is */
7261 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007262
7263 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7264 bc_num_ten(&G.prog.ib);
7265 G.prog.ib_t = 10;
7266
7267 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7268 bc_num_ten(&G.prog.ob);
7269 G.prog.ob_t = 10;
7270
7271 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7272 bc_num_ten(&G.prog.hexb);
7273 G.prog.hexb.num[0] = 6;
7274
7275#if ENABLE_DC
7276 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7277 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7278#endif
7279
7280 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7281 bc_num_zero(&G.prog.last);
7282
7283 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7284 bc_num_zero(&G.prog.zero);
7285
7286 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7287 bc_num_one(&G.prog.one);
7288
7289 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007290 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007291
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007292 bc_program_addFunc(xstrdup("(main)"), &idx);
7293 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007294
7295 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007296 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007297
7298 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007299 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007300
7301 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7302 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7303 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7304 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7305 bc_vec_push(&G.prog.stack, &ip);
7306}
Gavin Howard01055ba2018-11-03 11:00:21 -06007307
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007308static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007309{
Gavin Howard01055ba2018-11-03 11:00:21 -06007310 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007311
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007312 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007313
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007314 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007315 bc_vm_envArgs();
7316 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007317
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007318 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007319 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007320 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007321 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007322 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007323 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007324}
7325
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007326static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007327 const char *env_len)
7328{
7329 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007330
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007331 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007332 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007333
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007334 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007335
Denys Vlasenkod38af482018-12-04 19:11:02 +01007336 if (G.ttyin) {
7337#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007338 // With SA_RESTART, most system calls will restart
7339 // (IOW: they won't fail with EINTR).
7340 // In particular, this means ^C won't cause
7341 // stdout to get into "error state" if SIGINT hits
7342 // within write() syscall.
7343 // The downside is that ^C while line input is taken
7344 // will only be handled after [Enter] since read()
7345 // from stdin is not interrupted by ^C either,
7346 // it restarts, thus fgetc() does not return on ^C.
7347 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7348
7349 // Without SA_RESTART, this exhibits a bug:
7350 // "while (1) print 1" and try ^C-ing it.
7351 // Intermittently, instead of returning to input line,
7352 // you'll get "output error: Interrupted system call"
7353 // and exit.
7354 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007355#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007356 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007357 bc_vm_info();
7358 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007359 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007360
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007361#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007362 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007363#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007364 return st;
7365}
7366
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007367#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007368int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7369int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007370{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007371 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007372 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007373
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007374 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007375}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007376#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007377
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007378#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007379int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7380int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007381{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007382 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007383 G.sbgn = '[';
7384 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007385
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007386 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007387}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007388#endif