blob: 7a11e63def6bd130e438a8366988f9e8de545c30 [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
448 BC_LEX_KEY_AUTO,
449 BC_LEX_KEY_BREAK,
450 BC_LEX_KEY_CONTINUE,
451 BC_LEX_KEY_DEFINE,
452 BC_LEX_KEY_ELSE,
453 BC_LEX_KEY_FOR,
454 BC_LEX_KEY_HALT,
455 BC_LEX_KEY_IBASE,
456 BC_LEX_KEY_IF,
457 BC_LEX_KEY_LAST,
458 BC_LEX_KEY_LENGTH,
459 BC_LEX_KEY_LIMITS,
460 BC_LEX_KEY_OBASE,
461 BC_LEX_KEY_PRINT,
462 BC_LEX_KEY_QUIT,
463 BC_LEX_KEY_READ,
464 BC_LEX_KEY_RETURN,
465 BC_LEX_KEY_SCALE,
466 BC_LEX_KEY_SQRT,
467 BC_LEX_KEY_WHILE,
468
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100469#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600470 BC_LEX_EQ_NO_REG,
471 BC_LEX_OP_MODEXP,
472 BC_LEX_OP_DIVMOD,
473
474 BC_LEX_COLON,
475 BC_LEX_ELSE,
476 BC_LEX_EXECUTE,
477 BC_LEX_PRINT_STACK,
478 BC_LEX_CLEAR_STACK,
479 BC_LEX_STACK_LEVEL,
480 BC_LEX_DUPLICATE,
481 BC_LEX_SWAP,
482 BC_LEX_POP,
483
484 BC_LEX_ASCIIFY,
485 BC_LEX_PRINT_STREAM,
486
487 BC_LEX_STORE_IBASE,
488 BC_LEX_STORE_SCALE,
489 BC_LEX_LOAD,
490 BC_LEX_LOAD_POP,
491 BC_LEX_STORE_PUSH,
492 BC_LEX_STORE_OBASE,
493 BC_LEX_PRINT_POP,
494 BC_LEX_NQUIT,
495 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100496#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600497
498} BcLexType;
499
500struct BcLex;
501typedef BcStatus (*BcLexNext)(struct BcLex *);
502
503typedef struct BcLex {
504
505 const char *buf;
506 size_t i;
507 size_t line;
508 const char *f;
509 size_t len;
510 bool newline;
511
512 struct {
513 BcLexType t;
514 BcLexType last;
515 BcVec v;
516 } t;
517
518 BcLexNext next;
519
520} BcLex;
521
522#define BC_PARSE_STREND ((char) UCHAR_MAX)
523
524#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
525#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100526 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600527
528#define BC_PARSE_REL (1 << 0)
529#define BC_PARSE_PRINT (1 << 1)
530#define BC_PARSE_NOCALL (1 << 2)
531#define BC_PARSE_NOREAD (1 << 3)
532#define BC_PARSE_ARRAY (1 << 4)
533
534#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
535#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
536
537#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
538#define BC_PARSE_FUNC_INNER(parse) \
539 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
540
541#define BC_PARSE_FLAG_FUNC (1 << 1)
542#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
543
544#define BC_PARSE_FLAG_BODY (1 << 2)
545#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
546
547#define BC_PARSE_FLAG_LOOP (1 << 3)
548#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
549
550#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
551#define BC_PARSE_LOOP_INNER(parse) \
552 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
553
554#define BC_PARSE_FLAG_IF (1 << 5)
555#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
556
557#define BC_PARSE_FLAG_ELSE (1 << 6)
558#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
559
560#define BC_PARSE_FLAG_IF_END (1 << 7)
561#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
562
563#define BC_PARSE_CAN_EXEC(parse) \
564 (!(BC_PARSE_TOP_FLAG(parse) & \
565 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
566 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
567 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
568
569typedef struct BcOp {
570 char prec;
571 bool left;
572} BcOp;
573
574typedef struct BcParseNext {
575 uint32_t len;
576 BcLexType tokens[4];
577} BcParseNext;
578
579#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
580#define BC_PARSE_NEXT(a, ...) \
581 { \
582 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
583 }
584
585struct BcParse;
586
587struct BcProgram;
588
Gavin Howard01055ba2018-11-03 11:00:21 -0600589typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600590
591typedef struct BcParse {
592
593 BcParseParse parse;
594
595 BcLex l;
596
597 BcVec flags;
598
599 BcVec exits;
600 BcVec conds;
601
602 BcVec ops;
603
Gavin Howard01055ba2018-11-03 11:00:21 -0600604 BcFunc *func;
605 size_t fidx;
606
607 size_t nbraces;
608 bool auto_part;
609
610} BcParse;
611
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100612#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600613
Gavin Howard01055ba2018-11-03 11:00:21 -0600614typedef struct BcLexKeyword {
615 const char name[9];
616 const char len;
617 const bool posix;
618} BcLexKeyword;
619
620#define BC_LEX_KW_ENTRY(a, b, c) \
621 { \
622 .name = a, .len = (b), .posix = (c) \
623 }
624
625static BcStatus bc_lex_token(BcLex *l);
626
627#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
628#define BC_PARSE_LEAF(p, rparen) \
629 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
630 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
631
632// We can calculate the conversion between tokens and exprs by subtracting the
633// position of the first operator in the lex enum and adding the position of the
634// first in the expr enum. Note: This only works for binary operators.
635#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
636
Gavin Howard01055ba2018-11-03 11:00:21 -0600637static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
638
Denys Vlasenko00d77792018-11-30 23:13:42 +0100639#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600640
Denys Vlasenko00d77792018-11-30 23:13:42 +0100641#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600642
643#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
644
Gavin Howard01055ba2018-11-03 11:00:21 -0600645static BcStatus dc_lex_token(BcLex *l);
646
Gavin Howard01055ba2018-11-03 11:00:21 -0600647static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
648
649#endif // ENABLE_DC
650
651typedef struct BcProgram {
652
653 size_t len;
654 size_t scale;
655
656 BcNum ib;
657 size_t ib_t;
658 BcNum ob;
659 size_t ob_t;
660
661 BcNum hexb;
662
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100663#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600664 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100665#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600666
667 BcVec results;
668 BcVec stack;
669
670 BcVec fns;
671 BcVec fn_map;
672
673 BcVec vars;
674 BcVec var_map;
675
676 BcVec arrs;
677 BcVec arr_map;
678
679 BcVec strs;
680 BcVec consts;
681
682 const char *file;
683
684 BcNum last;
685 BcNum zero;
686 BcNum one;
687
688 size_t nchars;
689
Gavin Howard01055ba2018-11-03 11:00:21 -0600690} BcProgram;
691
692#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
693
694#define BC_PROG_MAIN (0)
695#define BC_PROG_READ (1)
696
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100697#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600698#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100699#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600700
701#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
702#define BC_PROG_NUM(r, n) \
703 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
704
705typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
706
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100707static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100708static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600709
710#define BC_FLAG_X (1 << 0)
711#define BC_FLAG_W (1 << 1)
712#define BC_FLAG_V (1 << 2)
713#define BC_FLAG_S (1 << 3)
714#define BC_FLAG_Q (1 << 4)
715#define BC_FLAG_L (1 << 5)
716#define BC_FLAG_I (1 << 6)
717
718#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
719#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
720
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100721#define BC_MAX_OBASE ((unsigned) 999)
722#define BC_MAX_DIM ((unsigned) INT_MAX)
723#define BC_MAX_SCALE ((unsigned) UINT_MAX)
724#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
725#define BC_MAX_NAME BC_MAX_STRING
726#define BC_MAX_NUM BC_MAX_STRING
727#define BC_MAX_EXP ((unsigned long) LONG_MAX)
728#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600729
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100730struct globals {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100731 smallint ttyin;
732 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600733 char sbgn;
734 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600735
736 BcParse prs;
737 BcProgram prog;
738
Gavin Howard01055ba2018-11-03 11:00:21 -0600739 BcVec files;
740
741 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100742} FIX_ALIASING;
743#define G (*ptr_to_globals)
744#define INIT_G() do { \
745 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
746} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100747#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
748#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
749#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100750#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600751
Gavin Howard01055ba2018-11-03 11:00:21 -0600752
Denys Vlasenko00d77792018-11-30 23:13:42 +0100753#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
754
Denys Vlasenko00d77792018-11-30 23:13:42 +0100755static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600756
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100757#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600758static const BcLexKeyword bc_lex_kws[20] = {
759 BC_LEX_KW_ENTRY("auto", 4, true),
760 BC_LEX_KW_ENTRY("break", 5, true),
761 BC_LEX_KW_ENTRY("continue", 8, false),
762 BC_LEX_KW_ENTRY("define", 6, true),
763 BC_LEX_KW_ENTRY("else", 4, false),
764 BC_LEX_KW_ENTRY("for", 3, true),
765 BC_LEX_KW_ENTRY("halt", 4, false),
766 BC_LEX_KW_ENTRY("ibase", 5, true),
767 BC_LEX_KW_ENTRY("if", 2, true),
768 BC_LEX_KW_ENTRY("last", 4, false),
769 BC_LEX_KW_ENTRY("length", 6, true),
770 BC_LEX_KW_ENTRY("limits", 6, false),
771 BC_LEX_KW_ENTRY("obase", 5, true),
772 BC_LEX_KW_ENTRY("print", 5, false),
773 BC_LEX_KW_ENTRY("quit", 4, true),
774 BC_LEX_KW_ENTRY("read", 4, false),
775 BC_LEX_KW_ENTRY("return", 6, true),
776 BC_LEX_KW_ENTRY("scale", 5, true),
777 BC_LEX_KW_ENTRY("sqrt", 4, true),
778 BC_LEX_KW_ENTRY("while", 5, true),
779};
780
781// This is an array that corresponds to token types. An entry is
782// true if the token is valid in an expression, false otherwise.
783static const bool bc_parse_exprs[] = {
784 false, false, true, true, true, true, true, true, true, true, true, true,
785 true, true, true, true, true, true, true, true, true, true, true, true,
786 true, true, true, false, false, true, true, false, false, false, false,
787 false, false, false, true, true, false, false, false, false, false, false,
788 false, true, false, true, true, true, true, false, false, true, false, true,
789 true, false,
790};
791
792// This is an array of data for operators that correspond to token types.
793static const BcOp bc_parse_ops[] = {
794 { 0, false }, { 0, false },
795 { 1, false },
796 { 2, false },
797 { 3, true }, { 3, true }, { 3, true },
798 { 4, true }, { 4, true },
799 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
800 { 1, false },
801 { 7, true }, { 7, true },
802 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
803 { 5, false }, { 5, false },
804};
805
806// These identify what tokens can come after expressions in certain cases.
807static const BcParseNext bc_parse_next_expr =
808 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
809static const BcParseNext bc_parse_next_param =
810 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
811static const BcParseNext bc_parse_next_print =
812 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
813static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
814static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
815static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
816static const BcParseNext bc_parse_next_read =
817 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
818#endif // ENABLE_BC
819
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100820#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600821static const BcLexType dc_lex_regs[] = {
822 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
823 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
824 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
825 BC_LEX_STORE_PUSH,
826};
827
828static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
829
830static const BcLexType dc_lex_tokens[] = {
831 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
832 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
833 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
834 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
835 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
836 BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
838 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
839 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
840 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
841 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
842 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
843 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
844 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
845 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
847 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
848 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
849 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
850 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
851 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
852 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
853 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
854 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
855 BC_LEX_INVALID
856};
857
858static const BcInst dc_parse_insts[] = {
859 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
860 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
861 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
862 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
863 BC_INST_INVALID, BC_INST_INVALID,
864 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
869 BC_INST_INVALID, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
871 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
874 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
875 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
876 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
878 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
879 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
880 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
881 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
882};
883#endif // ENABLE_DC
884
Gavin Howard01055ba2018-11-03 11:00:21 -0600885static const BcNumBinaryOp bc_program_ops[] = {
886 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
887};
888
889static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600890
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100891#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600892static const char *bc_lib_name = "gen/lib.bc";
893
894static const char bc_lib[] = {
895 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
896 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
897 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
898 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
899 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
900 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
901 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
902 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
903 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
904 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
905 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
906 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
907 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
908 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
909 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
910 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
911 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
912 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
913 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
914 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
915 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
916 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
917 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
918 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
919 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
920 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
921 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
922 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
923 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
924 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
925 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
926 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
927 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
928 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
929 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
930 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
931 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
932 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
933 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
934 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
935 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
936 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
937 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
938 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
939 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
940 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
941 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
942 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
943 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
944 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
945 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
946 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
947 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
948 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
949 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
950 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
951 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
952 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
953 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
954 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
955 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
956 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
957 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
958 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
959 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
960 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
961 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
962 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
963 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
964 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
965 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
966 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
967 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
968 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
969 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
970 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
971 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
972 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
973 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
974 117,114,110,40,97,42,114,47,49,41,10,125,10,0
975};
976#endif // ENABLE_BC
977
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100978static void fflush_and_check(void)
979{
980 fflush_all();
981 if (ferror(stdout) || ferror(stderr))
982 bb_perror_msg_and_die("output error");
983}
984
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100985static void quit(void) NORETURN;
986static void quit(void)
987{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100988 if (ferror(stdin))
989 bb_perror_msg_and_die("input error");
990 fflush_and_check();
991 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100992}
993
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100994static int bc_error(const char *fmt, ...)
995{
996 va_list p;
997
998 va_start(p, fmt);
999 bb_verror_msg(fmt, p, NULL);
1000 va_end(p);
1001 if (!G.ttyin)
1002 exit(1);
1003 return BC_STATUS_FAILURE;
1004}
1005
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001006static int bc_posix_error(const char *fmt, ...)
1007{
1008 va_list p;
1009
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001010 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001011 return BC_STATUS_SUCCESS;
1012
1013 va_start(p, fmt);
1014 bb_verror_msg(fmt, p, NULL);
1015 va_end(p);
1016
1017 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001018 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001019 return BC_STATUS_SUCCESS; // no, it's a warning
1020 if (!G.ttyin)
1021 exit(1);
1022 return BC_STATUS_FAILURE;
1023}
1024
Gavin Howard01055ba2018-11-03 11:00:21 -06001025static void bc_vec_grow(BcVec *v, size_t n)
1026{
1027 size_t cap = v->cap * 2;
1028 while (cap < v->len + n) cap *= 2;
1029 v->v = xrealloc(v->v, v->size * cap);
1030 v->cap = cap;
1031}
1032
1033static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1034{
1035 v->size = esize;
1036 v->cap = BC_VEC_START_CAP;
1037 v->len = 0;
1038 v->dtor = dtor;
1039 v->v = xmalloc(esize * BC_VEC_START_CAP);
1040}
1041
Denys Vlasenko7d628012018-12-04 21:46:47 +01001042static void bc_char_vec_init(BcVec *v)
1043{
1044 bc_vec_init(v, sizeof(char), NULL);
1045}
1046
Gavin Howard01055ba2018-11-03 11:00:21 -06001047static void bc_vec_expand(BcVec *v, size_t req)
1048{
1049 if (v->cap < req) {
1050 v->v = xrealloc(v->v, v->size * req);
1051 v->cap = req;
1052 }
1053}
1054
1055static void bc_vec_npop(BcVec *v, size_t n)
1056{
1057 if (!v->dtor)
1058 v->len -= n;
1059 else {
1060 size_t len = v->len - n;
1061 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1062 }
1063}
1064
Denys Vlasenko7d628012018-12-04 21:46:47 +01001065static void bc_vec_pop_all(BcVec *v)
1066{
1067 bc_vec_npop(v, v->len);
1068}
1069
Gavin Howard01055ba2018-11-03 11:00:21 -06001070static void bc_vec_push(BcVec *v, const void *data)
1071{
1072 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1073 memmove(v->v + (v->size * v->len), data, v->size);
1074 v->len += 1;
1075}
1076
1077static void bc_vec_pushByte(BcVec *v, char data)
1078{
1079 bc_vec_push(v, &data);
1080}
1081
1082static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1083{
1084 if (idx == v->len)
1085 bc_vec_push(v, data);
1086 else {
1087
1088 char *ptr;
1089
1090 if (v->len == v->cap) bc_vec_grow(v, 1);
1091
1092 ptr = v->v + v->size * idx;
1093
1094 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1095 memmove(ptr, data, v->size);
1096 }
1097}
1098
1099static void bc_vec_string(BcVec *v, size_t len, const char *str)
1100{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001101 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001102 bc_vec_expand(v, len + 1);
1103 memcpy(v->v, str, len);
1104 v->len = len;
1105
1106 bc_vec_pushByte(v, '\0');
1107}
1108
1109static void bc_vec_concat(BcVec *v, const char *str)
1110{
1111 size_t len;
1112
1113 if (v->len == 0) bc_vec_pushByte(v, '\0');
1114
1115 len = v->len + strlen(str);
1116
1117 if (v->cap < len) bc_vec_grow(v, len - v->len);
1118 strcat(v->v, str);
1119
1120 v->len = len;
1121}
1122
1123static void *bc_vec_item(const BcVec *v, size_t idx)
1124{
1125 return v->v + v->size * idx;
1126}
1127
1128static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1129{
1130 return v->v + v->size * (v->len - idx - 1);
1131}
1132
1133static void bc_vec_free(void *vec)
1134{
1135 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001136 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001137 free(v->v);
1138}
1139
1140static size_t bc_map_find(const BcVec *v, const void *ptr)
1141{
1142 size_t low = 0, high = v->len;
1143
1144 while (low < high) {
1145
1146 size_t mid = (low + high) / 2;
1147 BcId *id = bc_vec_item(v, mid);
1148 int result = bc_id_cmp(ptr, id);
1149
1150 if (result == 0)
1151 return mid;
1152 else if (result < 0)
1153 high = mid;
1154 else
1155 low = mid + 1;
1156 }
1157
1158 return low;
1159}
1160
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001161static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001162{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001163 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001164
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001165 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001166 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001167 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1168 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001169 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001170 bc_vec_pushAt(v, ptr, n);
1171 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001172}
1173
1174static size_t bc_map_index(const BcVec *v, const void *ptr)
1175{
1176 size_t i = bc_map_find(v, ptr);
1177 if (i >= v->len) return BC_VEC_INVALID_IDX;
1178 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1179}
1180
1181static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1182{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001183 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001184
Denys Vlasenko00d77792018-11-30 23:13:42 +01001185 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001186 int i;
1187 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001188
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001189 bad_chars = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001190 bc_vec_pop_all(vec);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001191
1192 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001193#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001194 if (bb_got_signal) { // ^C was pressed
1195 intr:
1196 bb_got_signal = 0; // resets G_interrupt to zero
1197 fputs(IS_BC
1198 ? "\ninterrupt (type \"quit\" to exit)\n"
1199 : "\ninterrupt (type \"q\" to exit)\n"
1200 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001201 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001202#endif
1203 if (G.ttyin && !G_posix)
1204 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001205
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001206#if ENABLE_FEATURE_BC_SIGNALS
1207 errno = 0;
1208#endif
1209 do {
1210 i = fgetc(stdin);
1211 if (i == EOF) {
1212#if ENABLE_FEATURE_BC_SIGNALS
1213 // Both conditions appear simultaneously, check both just in case
1214 if (errno == EINTR || bb_got_signal) {
1215 // ^C was pressed
1216 clearerr(stdin);
1217 goto intr;
1218 }
1219#endif
1220 if (ferror(stdin))
1221 quit(); // this emits error message
1222 G.eof = 1;
1223 // Note: EOF does not append '\n', therefore:
1224 // printf 'print 123\n' | bc - works
1225 // printf 'print 123' | bc - fails (syntax error)
1226 break;
1227 }
1228
1229 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1230 || i > 0x7e
1231 ) {
1232 // Bad chars on this line, ignore entire line
1233 bc_error("illegal character 0x%02x", i);
1234 bad_chars = 1;
1235 }
1236 c = (char) i;
1237 bc_vec_push(vec, &c);
1238 } while (i != '\n');
1239 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001240
1241 bc_vec_pushByte(vec, '\0');
1242
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;
1923 }
1924
Gavin Howard01055ba2018-11-03 11:00:21 -06001925 bc_num_copy(c, &copy);
1926
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001927 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001928
1929 powrdx <<= 1;
1930 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1931 if (s) goto err;
1932
1933 if (pow & 1) {
1934 resrdx += powrdx;
1935 s = bc_num_mul(c, &copy, c, resrdx);
1936 if (s) goto err;
1937 }
1938 }
1939
1940 if (neg) {
1941 s = bc_num_inv(c, c, scale);
1942 if (s) goto err;
1943 }
1944
Gavin Howard01055ba2018-11-03 11:00:21 -06001945 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1946
1947 // We can't use bc_num_clean() here.
1948 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1949 if (zero) bc_num_setToZero(c, scale);
1950
1951err:
1952 bc_num_free(&copy);
1953 return s;
1954}
1955
1956static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1957 BcNumBinaryOp op, size_t req)
1958{
1959 BcStatus s;
1960 BcNum num2, *ptr_a, *ptr_b;
1961 bool init = false;
1962
1963 if (c == a) {
1964 ptr_a = &num2;
1965 memcpy(ptr_a, c, sizeof(BcNum));
1966 init = true;
1967 }
1968 else
1969 ptr_a = a;
1970
1971 if (c == b) {
1972 ptr_b = &num2;
1973 if (c != a) {
1974 memcpy(ptr_b, c, sizeof(BcNum));
1975 init = true;
1976 }
1977 }
1978 else
1979 ptr_b = b;
1980
1981 if (init)
1982 bc_num_init(c, req);
1983 else
1984 bc_num_expand(c, req);
1985
1986 s = op(ptr_a, ptr_b, c, scale);
1987
1988 if (init) bc_num_free(&num2);
1989
1990 return s;
1991}
1992
1993static bool bc_num_strValid(const char *val, size_t base)
1994{
1995 BcDig b;
1996 bool small, radix = false;
1997 size_t i, len = strlen(val);
1998
1999 if (!len) return true;
2000
2001 small = base <= 10;
2002 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2003
2004 for (i = 0; i < len; ++i) {
2005
2006 BcDig c = val[i];
2007
2008 if (c == '.') {
2009
2010 if (radix) return false;
2011
2012 radix = true;
2013 continue;
2014 }
2015
2016 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2017 return false;
2018 }
2019
2020 return true;
2021}
2022
2023static void bc_num_parseDecimal(BcNum *n, const char *val)
2024{
2025 size_t len, i;
2026 const char *ptr;
2027 bool zero = true;
2028
2029 for (i = 0; val[i] == '0'; ++i);
2030
2031 val += i;
2032 len = strlen(val);
2033 bc_num_zero(n);
2034
2035 if (len != 0) {
2036 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2037 bc_num_expand(n, len);
2038 }
2039
2040 ptr = strchr(val, '.');
2041
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002042 n->rdx = 0;
2043 if (ptr != NULL)
2044 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002045
2046 if (!zero) {
2047 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2048 n->num[n->len] = val[i] - '0';
2049 }
2050}
2051
2052static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2053{
2054 BcStatus s;
2055 BcNum temp, mult, result;
2056 BcDig c = '\0';
2057 bool zero = true;
2058 unsigned long v;
2059 size_t i, digits, len = strlen(val);
2060
2061 bc_num_zero(n);
2062
2063 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2064 if (zero) return;
2065
2066 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2067 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2068
2069 for (i = 0; i < len; ++i) {
2070
2071 c = val[i];
2072 if (c == '.') break;
2073
2074 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2075
2076 s = bc_num_mul(n, base, &mult, 0);
2077 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002078 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002079 s = bc_num_add(&mult, &temp, n, 0);
2080 if (s) goto int_err;
2081 }
2082
2083 if (i == len) {
2084 c = val[i];
2085 if (c == 0) goto int_err;
2086 }
2087
2088 bc_num_init(&result, base->len);
2089 bc_num_zero(&result);
2090 bc_num_one(&mult);
2091
2092 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2093
2094 c = val[i];
2095 if (c == 0) break;
2096
2097 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2098
2099 s = bc_num_mul(&result, base, &result, 0);
2100 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002101 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002102 s = bc_num_add(&result, &temp, &result, 0);
2103 if (s) goto err;
2104 s = bc_num_mul(&mult, base, &mult, 0);
2105 if (s) goto err;
2106 }
2107
2108 s = bc_num_div(&result, &mult, &result, digits);
2109 if (s) goto err;
2110 s = bc_num_add(n, &result, n, digits);
2111 if (s) goto err;
2112
2113 if (n->len != 0) {
2114 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2115 }
2116 else
2117 bc_num_zero(n);
2118
2119err:
2120 bc_num_free(&result);
2121int_err:
2122 bc_num_free(&mult);
2123 bc_num_free(&temp);
2124}
2125
2126static void bc_num_printNewline(size_t *nchars, size_t line_len)
2127{
2128 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002129 bb_putchar('\\');
2130 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002131 *nchars = 0;
2132 }
2133}
2134
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002135#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002136static void bc_num_printChar(size_t num, size_t width, bool radix,
2137 size_t *nchars, size_t line_len)
2138{
2139 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002140 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002141 *nchars = *nchars + width;
2142}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002143#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002144
2145static void bc_num_printDigits(size_t num, size_t width, bool radix,
2146 size_t *nchars, size_t line_len)
2147{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002148 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002149
2150 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002151 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002152 ++(*nchars);
2153
2154 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002155 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2156 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002157
2158 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002159 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002160 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002161 dig = num / pow;
2162 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002163 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002164 }
2165}
2166
2167static void bc_num_printHex(size_t num, size_t width, bool radix,
2168 size_t *nchars, size_t line_len)
2169{
2170 if (radix) {
2171 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002172 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002173 *nchars += 1;
2174 }
2175
2176 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002177 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002178 *nchars = *nchars + width;
2179}
2180
2181static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2182{
2183 size_t i, rdx = n->rdx - 1;
2184
Denys Vlasenko00d77792018-11-30 23:13:42 +01002185 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002186 (*nchars) += n->neg;
2187
2188 for (i = n->len - 1; i < n->len; --i)
2189 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2190}
2191
2192static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2193 size_t *nchars, size_t len, BcNumDigitOp print)
2194{
2195 BcStatus s;
2196 BcVec stack;
2197 BcNum intp, fracp, digit, frac_len;
2198 unsigned long dig, *ptr;
2199 size_t i;
2200 bool radix;
2201
2202 if (n->len == 0) {
2203 print(0, width, false, nchars, len);
2204 return BC_STATUS_SUCCESS;
2205 }
2206
2207 bc_vec_init(&stack, sizeof(long), NULL);
2208 bc_num_init(&intp, n->len);
2209 bc_num_init(&fracp, n->rdx);
2210 bc_num_init(&digit, width);
2211 bc_num_init(&frac_len, BC_NUM_INT(n));
2212 bc_num_copy(&intp, n);
2213 bc_num_one(&frac_len);
2214
2215 bc_num_truncate(&intp, intp.rdx);
2216 s = bc_num_sub(n, &intp, &fracp, 0);
2217 if (s) goto err;
2218
2219 while (intp.len != 0) {
2220 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2221 if (s) goto err;
2222 s = bc_num_ulong(&digit, &dig);
2223 if (s) goto err;
2224 bc_vec_push(&stack, &dig);
2225 }
2226
2227 for (i = 0; i < stack.len; ++i) {
2228 ptr = bc_vec_item_rev(&stack, i);
2229 print(*ptr, width, false, nchars, len);
2230 }
2231
2232 if (!n->rdx) goto err;
2233
2234 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2235 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2236 if (s) goto err;
2237 s = bc_num_ulong(&fracp, &dig);
2238 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002239 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002240 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2241 if (s) goto err;
2242 print(dig, width, radix, nchars, len);
2243 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2244 if (s) goto err;
2245 }
2246
2247err:
2248 bc_num_free(&frac_len);
2249 bc_num_free(&digit);
2250 bc_num_free(&fracp);
2251 bc_num_free(&intp);
2252 bc_vec_free(&stack);
2253 return s;
2254}
2255
2256static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2257 size_t *nchars, size_t line_len)
2258{
2259 BcStatus s;
2260 size_t width, i;
2261 BcNumDigitOp print;
2262 bool neg = n->neg;
2263
Denys Vlasenko00d77792018-11-30 23:13:42 +01002264 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002265 (*nchars) += neg;
2266
2267 n->neg = false;
2268
2269 if (base_t <= BC_NUM_MAX_IBASE) {
2270 width = 1;
2271 print = bc_num_printHex;
2272 }
2273 else {
2274 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2275 print = bc_num_printDigits;
2276 }
2277
2278 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2279 n->neg = neg;
2280
2281 return s;
2282}
2283
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002284#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002285static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2286{
2287 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2288}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002289#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002290
2291static void bc_num_init(BcNum *n, size_t req)
2292{
2293 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2294 memset(n, 0, sizeof(BcNum));
2295 n->num = xmalloc(req);
2296 n->cap = req;
2297}
2298
2299static void bc_num_expand(BcNum *n, size_t req)
2300{
2301 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2302 if (req > n->cap) {
2303 n->num = xrealloc(n->num, req);
2304 n->cap = req;
2305 }
2306}
2307
2308static void bc_num_free(void *num)
2309{
2310 free(((BcNum *) num)->num);
2311}
2312
2313static void bc_num_copy(BcNum *d, BcNum *s)
2314{
2315 if (d != s) {
2316 bc_num_expand(d, s->cap);
2317 d->len = s->len;
2318 d->neg = s->neg;
2319 d->rdx = s->rdx;
2320 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2321 }
2322}
2323
2324static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2325 size_t base_t)
2326{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002327 if (!bc_num_strValid(val, base_t))
2328 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002329
2330 if (base_t == 10)
2331 bc_num_parseDecimal(n, val);
2332 else
2333 bc_num_parseBase(n, val, base);
2334
2335 return BC_STATUS_SUCCESS;
2336}
2337
2338static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2339 size_t *nchars, size_t line_len)
2340{
2341 BcStatus s = BC_STATUS_SUCCESS;
2342
2343 bc_num_printNewline(nchars, line_len);
2344
2345 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002346 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002347 ++(*nchars);
2348 }
2349 else if (base_t == 10)
2350 bc_num_printDecimal(n, nchars, line_len);
2351 else
2352 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2353
2354 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002355 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002356 *nchars = 0;
2357 }
2358
2359 return s;
2360}
2361
2362static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2363{
2364 size_t i;
2365 unsigned long pow;
2366
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002367 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002368
2369 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2370
2371 unsigned long prev = *result, powprev = pow;
2372
2373 *result += ((unsigned long) n->num[i]) * pow;
2374 pow *= 10;
2375
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002376 if (*result < prev || pow < powprev)
2377 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002378 }
2379
2380 return BC_STATUS_SUCCESS;
2381}
2382
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002383static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002384{
2385 size_t len;
2386 BcDig *ptr;
2387 unsigned long i;
2388
2389 bc_num_zero(n);
2390
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002391 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002392
2393 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2394 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002395}
2396
2397static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2398{
2399 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2400 (void) scale;
2401 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2402}
2403
2404static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2405{
2406 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2407 (void) scale;
2408 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2409}
2410
2411static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2412{
2413 size_t req = BC_NUM_MREQ(a, b, scale);
2414 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2415}
2416
2417static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2418{
2419 size_t req = BC_NUM_MREQ(a, b, scale);
2420 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2421}
2422
2423static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2424{
2425 size_t req = BC_NUM_MREQ(a, b, scale);
2426 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2427}
2428
2429static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2430{
2431 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2432}
2433
2434static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2435{
2436 BcStatus s;
2437 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2438 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2439 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2440
2441 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2442 bc_num_expand(b, req);
2443
2444 if (a->len == 0) {
2445 bc_num_setToZero(b, scale);
2446 return BC_STATUS_SUCCESS;
2447 }
2448 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002449 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002450 else if (BC_NUM_ONE(a)) {
2451 bc_num_one(b);
2452 bc_num_extend(b, scale);
2453 return BC_STATUS_SUCCESS;
2454 }
2455
2456 scale = BC_MAX(scale, a->rdx) + 1;
2457 len = a->len + scale;
2458
2459 bc_num_init(&num1, len);
2460 bc_num_init(&num2, len);
2461 bc_num_init(&half, BC_NUM_DEF_SIZE);
2462
2463 bc_num_one(&half);
2464 half.num[0] = 5;
2465 half.rdx = 1;
2466
2467 bc_num_init(&f, len);
2468 bc_num_init(&fprime, len);
2469
2470 x0 = &num1;
2471 x1 = &num2;
2472
2473 bc_num_one(x0);
2474 pow = BC_NUM_INT(a);
2475
2476 if (pow) {
2477
2478 if (pow & 1)
2479 x0->num[0] = 2;
2480 else
2481 x0->num[0] = 6;
2482
2483 pow -= 2 - (pow & 1);
2484
2485 bc_num_extend(x0, pow);
2486
2487 // Make sure to move the radix back.
2488 x0->rdx -= pow;
2489 }
2490
2491 x0->rdx = digs = digs1 = 0;
2492 resrdx = scale + 2;
2493 len = BC_NUM_INT(x0) + resrdx - 1;
2494
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002495 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002496
2497 s = bc_num_div(a, x0, &f, resrdx);
2498 if (s) goto err;
2499 s = bc_num_add(x0, &f, &fprime, resrdx);
2500 if (s) goto err;
2501 s = bc_num_mul(&fprime, &half, x1, resrdx);
2502 if (s) goto err;
2503
2504 cmp = bc_num_cmp(x1, x0);
2505 digs = x1->len - (unsigned long long) llabs(cmp);
2506
2507 if (cmp == cmp2 && digs == digs1)
2508 times += 1;
2509 else
2510 times = 0;
2511
2512 resrdx += times > 4;
2513
2514 cmp2 = cmp1;
2515 cmp1 = cmp;
2516 digs1 = digs;
2517
2518 temp = x0;
2519 x0 = x1;
2520 x1 = temp;
2521 }
2522
Gavin Howard01055ba2018-11-03 11:00:21 -06002523 bc_num_copy(b, x0);
2524 scale -= 1;
2525 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2526
2527err:
2528 bc_num_free(&fprime);
2529 bc_num_free(&f);
2530 bc_num_free(&half);
2531 bc_num_free(&num2);
2532 bc_num_free(&num1);
2533 return s;
2534}
2535
2536static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2537 size_t scale)
2538{
2539 BcStatus s;
2540 BcNum num2, *ptr_a;
2541 bool init = false;
2542 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2543
2544 if (c == a) {
2545 memcpy(&num2, c, sizeof(BcNum));
2546 ptr_a = &num2;
2547 bc_num_init(c, len);
2548 init = true;
2549 }
2550 else {
2551 ptr_a = a;
2552 bc_num_expand(c, len);
2553 }
2554
2555 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2556
2557 if (init) bc_num_free(&num2);
2558
2559 return s;
2560}
2561
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002562#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002563static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2564{
2565 BcStatus s;
2566 BcNum base, exp, two, temp;
2567
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002568 if (c->len == 0)
2569 return bc_error("divide by zero");
2570 if (a->rdx || b->rdx || c->rdx)
2571 return bc_error("non integer number");
2572 if (b->neg)
2573 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002574
2575 bc_num_expand(d, c->len);
2576 bc_num_init(&base, c->len);
2577 bc_num_init(&exp, b->len);
2578 bc_num_init(&two, BC_NUM_DEF_SIZE);
2579 bc_num_init(&temp, b->len);
2580
2581 bc_num_one(&two);
2582 two.num[0] = 2;
2583 bc_num_one(d);
2584
2585 s = bc_num_rem(a, c, &base, 0);
2586 if (s) goto err;
2587 bc_num_copy(&exp, b);
2588
2589 while (exp.len != 0) {
2590
2591 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2592 if (s) goto err;
2593
2594 if (BC_NUM_ONE(&temp)) {
2595 s = bc_num_mul(d, &base, &temp, 0);
2596 if (s) goto err;
2597 s = bc_num_rem(&temp, c, d, 0);
2598 if (s) goto err;
2599 }
2600
2601 s = bc_num_mul(&base, &base, &temp, 0);
2602 if (s) goto err;
2603 s = bc_num_rem(&temp, c, &base, 0);
2604 if (s) goto err;
2605 }
2606
2607err:
2608 bc_num_free(&temp);
2609 bc_num_free(&two);
2610 bc_num_free(&exp);
2611 bc_num_free(&base);
2612 return s;
2613}
2614#endif // ENABLE_DC
2615
2616static int bc_id_cmp(const void *e1, const void *e2)
2617{
2618 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2619}
2620
2621static void bc_id_free(void *id)
2622{
2623 free(((BcId *) id)->name);
2624}
2625
2626static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2627{
2628 BcId a;
2629 size_t i;
2630
2631 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002632 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2633 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002634 }
2635
2636 a.idx = var;
2637 a.name = name;
2638
2639 bc_vec_push(&f->autos, &a);
2640
2641 return BC_STATUS_SUCCESS;
2642}
2643
2644static void bc_func_init(BcFunc *f)
2645{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002646 bc_char_vec_init(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06002647 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2648 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2649 f->nparams = 0;
2650}
2651
2652static void bc_func_free(void *func)
2653{
2654 BcFunc *f = (BcFunc *) func;
2655 bc_vec_free(&f->code);
2656 bc_vec_free(&f->autos);
2657 bc_vec_free(&f->labels);
2658}
2659
2660static void bc_array_init(BcVec *a, bool nums)
2661{
2662 if (nums)
2663 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2664 else
2665 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2666 bc_array_expand(a, 1);
2667}
2668
2669static void bc_array_copy(BcVec *d, const BcVec *s)
2670{
2671 size_t i;
2672
Denys Vlasenko7d628012018-12-04 21:46:47 +01002673 bc_vec_pop_all(d);
Gavin Howard01055ba2018-11-03 11:00:21 -06002674 bc_vec_expand(d, s->cap);
2675 d->len = s->len;
2676
2677 for (i = 0; i < s->len; ++i) {
2678 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2679 bc_num_init(dnum, snum->len);
2680 bc_num_copy(dnum, snum);
2681 }
2682}
2683
2684static void bc_array_expand(BcVec *a, size_t len)
2685{
2686 BcResultData data;
2687
2688 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2689 while (len > a->len) {
2690 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2691 bc_vec_push(a, &data.n);
2692 }
2693 }
2694 else {
2695 while (len > a->len) {
2696 bc_array_init(&data.v, true);
2697 bc_vec_push(a, &data.v);
2698 }
2699 }
2700}
2701
2702static void bc_string_free(void *string)
2703{
2704 free(*((char **) string));
2705}
2706
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002707#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002708static void bc_result_copy(BcResult *d, BcResult *src)
2709{
2710 d->t = src->t;
2711
2712 switch (d->t) {
2713
2714 case BC_RESULT_TEMP:
2715 case BC_RESULT_IBASE:
2716 case BC_RESULT_SCALE:
2717 case BC_RESULT_OBASE:
2718 {
2719 bc_num_init(&d->d.n, src->d.n.len);
2720 bc_num_copy(&d->d.n, &src->d.n);
2721 break;
2722 }
2723
2724 case BC_RESULT_VAR:
2725 case BC_RESULT_ARRAY:
2726 case BC_RESULT_ARRAY_ELEM:
2727 {
2728 d->d.id.name = xstrdup(src->d.id.name);
2729 break;
2730 }
2731
2732 case BC_RESULT_CONSTANT:
2733 case BC_RESULT_LAST:
2734 case BC_RESULT_ONE:
2735 case BC_RESULT_STR:
2736 {
2737 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2738 break;
2739 }
2740 }
2741}
2742#endif // ENABLE_DC
2743
2744static void bc_result_free(void *result)
2745{
2746 BcResult *r = (BcResult *) result;
2747
2748 switch (r->t) {
2749
2750 case BC_RESULT_TEMP:
2751 case BC_RESULT_IBASE:
2752 case BC_RESULT_SCALE:
2753 case BC_RESULT_OBASE:
2754 {
2755 bc_num_free(&r->d.n);
2756 break;
2757 }
2758
2759 case BC_RESULT_VAR:
2760 case BC_RESULT_ARRAY:
2761 case BC_RESULT_ARRAY_ELEM:
2762 {
2763 free(r->d.id.name);
2764 break;
2765 }
2766
2767 default:
2768 {
2769 // Do nothing.
2770 break;
2771 }
2772 }
2773}
2774
2775static void bc_lex_lineComment(BcLex *l)
2776{
2777 l->t.t = BC_LEX_WHITESPACE;
2778 while (l->i < l->len && l->buf[l->i++] != '\n');
2779 --l->i;
2780}
2781
2782static void bc_lex_whitespace(BcLex *l)
2783{
2784 char c;
2785 l->t.t = BC_LEX_WHITESPACE;
2786 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2787}
2788
2789static BcStatus bc_lex_number(BcLex *l, char start)
2790{
2791 const char *buf = l->buf + l->i;
2792 size_t len, hits = 0, bslashes = 0, i = 0, j;
2793 char c = buf[i];
2794 bool last_pt, pt = start == '.';
2795
2796 last_pt = pt;
2797 l->t.t = BC_LEX_NUMBER;
2798
2799 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2800 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2801 {
2802 if (c != '\\') {
2803 last_pt = c == '.';
2804 pt = pt || last_pt;
2805 }
2806 else {
2807 ++i;
2808 bslashes += 1;
2809 }
2810
2811 c = buf[++i];
2812 }
2813
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002814 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002815 if (len > BC_MAX_NUM)
2816 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002817
Denys Vlasenko7d628012018-12-04 21:46:47 +01002818 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002819 bc_vec_expand(&l->t.v, len + 1);
2820 bc_vec_push(&l->t.v, &start);
2821
2822 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2823
2824 c = buf[j];
2825
2826 // If we have hit a backslash, skip it. We don't have
2827 // to check for a newline because it's guaranteed.
2828 if (hits < bslashes && c == '\\') {
2829 ++hits;
2830 ++j;
2831 continue;
2832 }
2833
2834 bc_vec_push(&l->t.v, &c);
2835 }
2836
2837 bc_vec_pushByte(&l->t.v, '\0');
2838 l->i += i;
2839
2840 return BC_STATUS_SUCCESS;
2841}
2842
2843static BcStatus bc_lex_name(BcLex *l)
2844{
2845 size_t i = 0;
2846 const char *buf = l->buf + l->i - 1;
2847 char c = buf[i];
2848
2849 l->t.t = BC_LEX_NAME;
2850
2851 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2852
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002853 if (i > BC_MAX_STRING)
2854 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002855 bc_vec_string(&l->t.v, i, buf);
2856
2857 // Increment the index. We minus 1 because it has already been incremented.
2858 l->i += i - 1;
2859
2860 return BC_STATUS_SUCCESS;
2861}
2862
2863static void bc_lex_init(BcLex *l, BcLexNext next)
2864{
2865 l->next = next;
Denys Vlasenko7d628012018-12-04 21:46:47 +01002866 bc_char_vec_init(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002867}
2868
2869static void bc_lex_free(BcLex *l)
2870{
2871 bc_vec_free(&l->t.v);
2872}
2873
2874static void bc_lex_file(BcLex *l, const char *file)
2875{
2876 l->line = 1;
2877 l->newline = false;
2878 l->f = file;
2879}
2880
2881static BcStatus bc_lex_next(BcLex *l)
2882{
2883 BcStatus s;
2884
2885 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002886 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002887
2888 l->line += l->newline;
2889 l->t.t = BC_LEX_EOF;
2890
2891 l->newline = (l->i == l->len);
2892 if (l->newline) return BC_STATUS_SUCCESS;
2893
2894 // Loop until failure or we don't have whitespace. This
2895 // is so the parser doesn't get inundated with whitespace.
2896 do {
2897 s = l->next(l);
2898 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2899
2900 return s;
2901}
2902
2903static BcStatus bc_lex_text(BcLex *l, const char *text)
2904{
2905 l->buf = text;
2906 l->i = 0;
2907 l->len = strlen(text);
2908 l->t.t = l->t.last = BC_LEX_INVALID;
2909 return bc_lex_next(l);
2910}
2911
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002912#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002913static BcStatus bc_lex_identifier(BcLex *l)
2914{
2915 BcStatus s;
2916 size_t i;
2917 const char *buf = l->buf + l->i - 1;
2918
2919 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2920
2921 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2922
2923 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2924
2925 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2926
2927 if (!bc_lex_kws[i].posix) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002928 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
Gavin Howard01055ba2018-11-03 11:00:21 -06002929 if (s) return s;
2930 }
2931
2932 // We minus 1 because the index has already been incremented.
2933 l->i += len - 1;
2934 return BC_STATUS_SUCCESS;
2935 }
2936 }
2937
2938 s = bc_lex_name(l);
2939 if (s) return s;
2940
2941 if (l->t.v.len - 1 > 1)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002942 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002943
2944 return s;
2945}
2946
2947static BcStatus bc_lex_string(BcLex *l)
2948{
2949 size_t len, nls = 0, i = l->i;
2950 char c;
2951
2952 l->t.t = BC_LEX_STR;
2953
2954 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2955
2956 if (c == '\0') {
2957 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002958 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002959 }
2960
2961 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002962 if (len > BC_MAX_STRING)
2963 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002964 bc_vec_string(&l->t.v, len, l->buf + l->i);
2965
2966 l->i = i + 1;
2967 l->line += nls;
2968
2969 return BC_STATUS_SUCCESS;
2970}
2971
2972static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2973{
2974 if (l->buf[l->i] == '=') {
2975 ++l->i;
2976 l->t.t = with;
2977 }
2978 else
2979 l->t.t = without;
2980}
2981
2982static BcStatus bc_lex_comment(BcLex *l)
2983{
2984 size_t i, nls = 0;
2985 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06002986
2987 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002988 i = ++l->i;
2989 for (;;) {
2990 char c = buf[i];
2991 check_star:
2992 if (c == '*') {
2993 c = buf[++i];
2994 if (c == '/')
2995 break;
2996 goto check_star;
2997 }
2998 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06002999 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003000 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003001 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003002 nls += (c == '\n');
3003 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003004 }
3005
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003006 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003007 l->line += nls;
3008
3009 return BC_STATUS_SUCCESS;
3010}
3011
3012static BcStatus bc_lex_token(BcLex *l)
3013{
3014 BcStatus s = BC_STATUS_SUCCESS;
3015 char c = l->buf[l->i++], c2;
3016
3017 // This is the workhorse of the lexer.
3018 switch (c) {
3019
3020 case '\0':
3021 case '\n':
3022 {
3023 l->newline = true;
3024 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3025 break;
3026 }
3027
3028 case '\t':
3029 case '\v':
3030 case '\f':
3031 case '\r':
3032 case ' ':
3033 {
3034 bc_lex_whitespace(l);
3035 break;
3036 }
3037
3038 case '!':
3039 {
3040 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3041
3042 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003043 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003044 if (s) return s;
3045 }
3046
3047 break;
3048 }
3049
3050 case '"':
3051 {
3052 s = bc_lex_string(l);
3053 break;
3054 }
3055
3056 case '#':
3057 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003058 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003059 if (s) return s;
3060
3061 bc_lex_lineComment(l);
3062
3063 break;
3064 }
3065
3066 case '%':
3067 {
3068 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3069 break;
3070 }
3071
3072 case '&':
3073 {
3074 c2 = l->buf[l->i];
3075 if (c2 == '&') {
3076
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003077 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003078 if (s) return s;
3079
3080 ++l->i;
3081 l->t.t = BC_LEX_OP_BOOL_AND;
3082 }
3083 else {
3084 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003085 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003086 }
3087
3088 break;
3089 }
3090
3091 case '(':
3092 case ')':
3093 {
3094 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3095 break;
3096 }
3097
3098 case '*':
3099 {
3100 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3101 break;
3102 }
3103
3104 case '+':
3105 {
3106 c2 = l->buf[l->i];
3107 if (c2 == '+') {
3108 ++l->i;
3109 l->t.t = BC_LEX_OP_INC;
3110 }
3111 else
3112 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3113 break;
3114 }
3115
3116 case ',':
3117 {
3118 l->t.t = BC_LEX_COMMA;
3119 break;
3120 }
3121
3122 case '-':
3123 {
3124 c2 = l->buf[l->i];
3125 if (c2 == '-') {
3126 ++l->i;
3127 l->t.t = BC_LEX_OP_DEC;
3128 }
3129 else
3130 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3131 break;
3132 }
3133
3134 case '.':
3135 {
3136 if (isdigit(l->buf[l->i]))
3137 s = bc_lex_number(l, c);
3138 else {
3139 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003140 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003141 }
3142 break;
3143 }
3144
3145 case '/':
3146 {
3147 c2 = l->buf[l->i];
3148 if (c2 == '*')
3149 s = bc_lex_comment(l);
3150 else
3151 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3152 break;
3153 }
3154
3155 case '0':
3156 case '1':
3157 case '2':
3158 case '3':
3159 case '4':
3160 case '5':
3161 case '6':
3162 case '7':
3163 case '8':
3164 case '9':
3165 case 'A':
3166 case 'B':
3167 case 'C':
3168 case 'D':
3169 case 'E':
3170 case 'F':
3171 {
3172 s = bc_lex_number(l, c);
3173 break;
3174 }
3175
3176 case ';':
3177 {
3178 l->t.t = BC_LEX_SCOLON;
3179 break;
3180 }
3181
3182 case '<':
3183 {
3184 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3185 break;
3186 }
3187
3188 case '=':
3189 {
3190 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3191 break;
3192 }
3193
3194 case '>':
3195 {
3196 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3197 break;
3198 }
3199
3200 case '[':
3201 case ']':
3202 {
3203 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3204 break;
3205 }
3206
3207 case '\\':
3208 {
3209 if (l->buf[l->i] == '\n') {
3210 l->t.t = BC_LEX_WHITESPACE;
3211 ++l->i;
3212 }
3213 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003214 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003215 break;
3216 }
3217
3218 case '^':
3219 {
3220 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3221 break;
3222 }
3223
3224 case 'a':
3225 case 'b':
3226 case 'c':
3227 case 'd':
3228 case 'e':
3229 case 'f':
3230 case 'g':
3231 case 'h':
3232 case 'i':
3233 case 'j':
3234 case 'k':
3235 case 'l':
3236 case 'm':
3237 case 'n':
3238 case 'o':
3239 case 'p':
3240 case 'q':
3241 case 'r':
3242 case 's':
3243 case 't':
3244 case 'u':
3245 case 'v':
3246 case 'w':
3247 case 'x':
3248 case 'y':
3249 case 'z':
3250 {
3251 s = bc_lex_identifier(l);
3252 break;
3253 }
3254
3255 case '{':
3256 case '}':
3257 {
3258 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3259 break;
3260 }
3261
3262 case '|':
3263 {
3264 c2 = l->buf[l->i];
3265
3266 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003267 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003268 if (s) return s;
3269
3270 ++l->i;
3271 l->t.t = BC_LEX_OP_BOOL_OR;
3272 }
3273 else {
3274 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003275 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003276 }
3277
3278 break;
3279 }
3280
3281 default:
3282 {
3283 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003284 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003285 break;
3286 }
3287 }
3288
3289 return s;
3290}
3291#endif // ENABLE_BC
3292
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003293#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003294static BcStatus dc_lex_register(BcLex *l)
3295{
3296 BcStatus s = BC_STATUS_SUCCESS;
3297
3298 if (isspace(l->buf[l->i - 1])) {
3299 bc_lex_whitespace(l);
3300 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003301 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003302 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003303 else
3304 s = bc_lex_name(l);
3305 }
3306 else {
Denys Vlasenko7d628012018-12-04 21:46:47 +01003307 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003308 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3309 bc_vec_pushByte(&l->t.v, '\0');
3310 l->t.t = BC_LEX_NAME;
3311 }
3312
3313 return s;
3314}
3315
3316static BcStatus dc_lex_string(BcLex *l)
3317{
3318 size_t depth = 1, nls = 0, i = l->i;
3319 char c;
3320
3321 l->t.t = BC_LEX_STR;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003322 bc_vec_pop_all(&l->t.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06003323
3324 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3325
3326 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3327 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3328 nls += (c == '\n');
3329
3330 if (depth) bc_vec_push(&l->t.v, &c);
3331 }
3332
3333 if (c == '\0') {
3334 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003335 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003336 }
3337
3338 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003339 if (i - l->i > BC_MAX_STRING)
3340 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003341
3342 l->i = i;
3343 l->line += nls;
3344
3345 return BC_STATUS_SUCCESS;
3346}
3347
3348static BcStatus dc_lex_token(BcLex *l)
3349{
3350 BcStatus s = BC_STATUS_SUCCESS;
3351 char c = l->buf[l->i++], c2;
3352 size_t i;
3353
3354 for (i = 0; i < dc_lex_regs_len; ++i) {
3355 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3356 }
3357
3358 if (c >= '%' && c <= '~' &&
3359 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3360 {
3361 return s;
3362 }
3363
3364 // This is the workhorse of the lexer.
3365 switch (c) {
3366
3367 case '\0':
3368 {
3369 l->t.t = BC_LEX_EOF;
3370 break;
3371 }
3372
3373 case '\n':
3374 case '\t':
3375 case '\v':
3376 case '\f':
3377 case '\r':
3378 case ' ':
3379 {
3380 l->newline = (c == '\n');
3381 bc_lex_whitespace(l);
3382 break;
3383 }
3384
3385 case '!':
3386 {
3387 c2 = l->buf[l->i];
3388
3389 if (c2 == '=')
3390 l->t.t = BC_LEX_OP_REL_NE;
3391 else if (c2 == '<')
3392 l->t.t = BC_LEX_OP_REL_LE;
3393 else if (c2 == '>')
3394 l->t.t = BC_LEX_OP_REL_GE;
3395 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003396 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003397
3398 ++l->i;
3399 break;
3400 }
3401
3402 case '#':
3403 {
3404 bc_lex_lineComment(l);
3405 break;
3406 }
3407
3408 case '.':
3409 {
3410 if (isdigit(l->buf[l->i]))
3411 s = bc_lex_number(l, c);
3412 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003413 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003414 break;
3415 }
3416
3417 case '0':
3418 case '1':
3419 case '2':
3420 case '3':
3421 case '4':
3422 case '5':
3423 case '6':
3424 case '7':
3425 case '8':
3426 case '9':
3427 case 'A':
3428 case 'B':
3429 case 'C':
3430 case 'D':
3431 case 'E':
3432 case 'F':
3433 {
3434 s = bc_lex_number(l, c);
3435 break;
3436 }
3437
3438 case '[':
3439 {
3440 s = dc_lex_string(l);
3441 break;
3442 }
3443
3444 default:
3445 {
3446 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003447 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003448 break;
3449 }
3450 }
3451
3452 return s;
3453}
3454#endif // ENABLE_DC
3455
3456static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3457{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003458 bc_program_addFunc(name, idx);
3459 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003460}
3461
3462static void bc_parse_pushName(BcParse *p, char *name)
3463{
3464 size_t i = 0, len = strlen(name);
3465
3466 for (; i < len; ++i) bc_parse_push(p, name[i]);
3467 bc_parse_push(p, BC_PARSE_STREND);
3468
3469 free(name);
3470}
3471
3472static void bc_parse_pushIndex(BcParse *p, size_t idx)
3473{
3474 unsigned char amt, i, nums[sizeof(size_t)];
3475
3476 for (amt = 0; idx; ++amt) {
3477 nums[amt] = (char) idx;
3478 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3479 }
3480
3481 bc_parse_push(p, amt);
3482 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3483}
3484
3485static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3486{
3487 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003488 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003489
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003490 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003491
3492 bc_parse_push(p, BC_INST_NUM);
3493 bc_parse_pushIndex(p, idx);
3494
3495 ++(*nexs);
3496 (*prev) = BC_INST_NUM;
3497}
3498
3499static BcStatus bc_parse_text(BcParse *p, const char *text)
3500{
3501 BcStatus s;
3502
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003503 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003504
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003505 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003506 p->l.t.t = BC_LEX_INVALID;
3507 s = p->parse(p);
3508 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003509 if (!BC_PARSE_CAN_EXEC(p))
3510 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003511 }
3512
3513 return bc_lex_text(&p->l, text);
3514}
3515
Denys Vlasenkod38af482018-12-04 19:11:02 +01003516// Called when bc/dc_parse_parse() detects a failure,
3517// resets parsing structures.
3518static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003519{
3520 if (p->fidx != BC_PROG_MAIN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003521 p->func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01003522 bc_vec_pop_all(&p->func->code);
3523 bc_vec_pop_all(&p->func->autos);
3524 bc_vec_pop_all(&p->func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06003525
3526 bc_parse_updateFunc(p, BC_PROG_MAIN);
3527 }
3528
3529 p->l.i = p->l.len;
3530 p->l.t.t = BC_LEX_EOF;
3531 p->auto_part = (p->nbraces = 0);
3532
3533 bc_vec_npop(&p->flags, p->flags.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01003534 bc_vec_pop_all(&p->exits);
3535 bc_vec_pop_all(&p->conds);
3536 bc_vec_pop_all(&p->ops);
Gavin Howard01055ba2018-11-03 11:00:21 -06003537
Denys Vlasenkod38af482018-12-04 19:11:02 +01003538 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003539}
3540
3541static void bc_parse_free(BcParse *p)
3542{
3543 bc_vec_free(&p->flags);
3544 bc_vec_free(&p->exits);
3545 bc_vec_free(&p->conds);
3546 bc_vec_free(&p->ops);
3547 bc_lex_free(&p->l);
3548}
3549
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003550static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003551 BcParseParse parse, BcLexNext next)
3552{
3553 memset(p, 0, sizeof(BcParse));
3554
3555 bc_lex_init(&p->l, next);
3556 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3557 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3558 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3559 bc_vec_pushByte(&p->flags, 0);
3560 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3561
3562 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003563 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003564 bc_parse_updateFunc(p, func);
3565}
3566
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003567#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003568static BcStatus bc_parse_else(BcParse *p);
3569static BcStatus bc_parse_stmt(BcParse *p);
3570
3571static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3572 size_t *nexprs, bool next)
3573{
3574 BcStatus s = BC_STATUS_SUCCESS;
3575 BcLexType t;
3576 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3577 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3578
3579 while (p->ops.len > start) {
3580
3581 t = BC_PARSE_TOP_OP(p);
3582 if (t == BC_LEX_LPAREN) break;
3583
3584 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3585 if (l >= r && (l != r || !left)) break;
3586
3587 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3588 bc_vec_pop(&p->ops);
3589 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3590 }
3591
3592 bc_vec_push(&p->ops, &type);
3593 if (next) s = bc_lex_next(&p->l);
3594
3595 return s;
3596}
3597
3598static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3599{
3600 BcLexType top;
3601
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003602 if (p->ops.len <= ops_bgn)
3603 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003604 top = BC_PARSE_TOP_OP(p);
3605
3606 while (top != BC_LEX_LPAREN) {
3607
3608 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3609
3610 bc_vec_pop(&p->ops);
3611 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3612
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003613 if (p->ops.len <= ops_bgn)
3614 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003615 top = BC_PARSE_TOP_OP(p);
3616 }
3617
3618 bc_vec_pop(&p->ops);
3619
3620 return bc_lex_next(&p->l);
3621}
3622
3623static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3624{
3625 BcStatus s;
3626 bool comma = false;
3627 size_t nparams;
3628
3629 s = bc_lex_next(&p->l);
3630 if (s) return s;
3631
3632 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3633
3634 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3635 s = bc_parse_expr(p, flags, bc_parse_next_param);
3636 if (s) return s;
3637
3638 comma = p->l.t.t == BC_LEX_COMMA;
3639 if (comma) {
3640 s = bc_lex_next(&p->l);
3641 if (s) return s;
3642 }
3643 }
3644
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003645 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003646 bc_parse_push(p, BC_INST_CALL);
3647 bc_parse_pushIndex(p, nparams);
3648
3649 return BC_STATUS_SUCCESS;
3650}
3651
3652static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3653{
3654 BcStatus s;
3655 BcId entry, *entry_ptr;
3656 size_t idx;
3657
3658 entry.name = name;
3659
3660 s = bc_parse_params(p, flags);
3661 if (s) goto err;
3662
3663 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003664 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003665 goto err;
3666 }
3667
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003668 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003669
3670 if (idx == BC_VEC_INVALID_IDX) {
3671 name = xstrdup(entry.name);
3672 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003673 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003674 free(entry.name);
3675 }
3676 else
3677 free(name);
3678
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003679 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003680 bc_parse_pushIndex(p, entry_ptr->idx);
3681
3682 return bc_lex_next(&p->l);
3683
3684err:
3685 free(name);
3686 return s;
3687}
3688
3689static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3690{
3691 BcStatus s;
3692 char *name;
3693
3694 name = xstrdup(p->l.t.v.v);
3695 s = bc_lex_next(&p->l);
3696 if (s) goto err;
3697
3698 if (p->l.t.t == BC_LEX_LBRACKET) {
3699
3700 s = bc_lex_next(&p->l);
3701 if (s) goto err;
3702
3703 if (p->l.t.t == BC_LEX_RBRACKET) {
3704
3705 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003706 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003707 goto err;
3708 }
3709
3710 *type = BC_INST_ARRAY;
3711 }
3712 else {
3713
3714 *type = BC_INST_ARRAY_ELEM;
3715
3716 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3717 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3718 if (s) goto err;
3719 }
3720
3721 s = bc_lex_next(&p->l);
3722 if (s) goto err;
3723 bc_parse_push(p, *type);
3724 bc_parse_pushName(p, name);
3725 }
3726 else if (p->l.t.t == BC_LEX_LPAREN) {
3727
3728 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003729 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003730 goto err;
3731 }
3732
3733 *type = BC_INST_CALL;
3734 s = bc_parse_call(p, name, flags);
3735 }
3736 else {
3737 *type = BC_INST_VAR;
3738 bc_parse_push(p, BC_INST_VAR);
3739 bc_parse_pushName(p, name);
3740 }
3741
3742 return s;
3743
3744err:
3745 free(name);
3746 return s;
3747}
3748
3749static BcStatus bc_parse_read(BcParse *p)
3750{
3751 BcStatus s;
3752
3753 s = bc_lex_next(&p->l);
3754 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003755 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003756
3757 s = bc_lex_next(&p->l);
3758 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003759 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003760
3761 bc_parse_push(p, BC_INST_READ);
3762
3763 return bc_lex_next(&p->l);
3764}
3765
3766static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3767 BcInst *prev)
3768{
3769 BcStatus s;
3770
3771 s = bc_lex_next(&p->l);
3772 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003773 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003774
3775 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3776
3777 s = bc_lex_next(&p->l);
3778 if (s) return s;
3779
3780 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3781 if (s) return s;
3782
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003783 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003784
3785 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3786 bc_parse_push(p, *prev);
3787
3788 return bc_lex_next(&p->l);
3789}
3790
3791static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3792{
3793 BcStatus s;
3794
3795 s = bc_lex_next(&p->l);
3796 if (s) return s;
3797
3798 if (p->l.t.t != BC_LEX_LPAREN) {
3799 *type = BC_INST_SCALE;
3800 bc_parse_push(p, BC_INST_SCALE);
3801 return BC_STATUS_SUCCESS;
3802 }
3803
3804 *type = BC_INST_SCALE_FUNC;
3805 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3806
3807 s = bc_lex_next(&p->l);
3808 if (s) return s;
3809
3810 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3811 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003812 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003813 bc_parse_push(p, BC_INST_SCALE_FUNC);
3814
3815 return bc_lex_next(&p->l);
3816}
3817
3818static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3819 size_t *nexprs, uint8_t flags)
3820{
3821 BcStatus s;
3822 BcLexType type;
3823 char inst;
3824 BcInst etype = *prev;
3825
3826 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3827 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3828 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3829 {
3830 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3831 bc_parse_push(p, inst);
3832 s = bc_lex_next(&p->l);
3833 }
3834 else {
3835
3836 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3837 *paren_expr = true;
3838
3839 s = bc_lex_next(&p->l);
3840 if (s) return s;
3841 type = p->l.t.t;
3842
3843 // Because we parse the next part of the expression
3844 // right here, we need to increment this.
3845 *nexprs = *nexprs + 1;
3846
3847 switch (type) {
3848
3849 case BC_LEX_NAME:
3850 {
3851 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3852 break;
3853 }
3854
3855 case BC_LEX_KEY_IBASE:
3856 case BC_LEX_KEY_LAST:
3857 case BC_LEX_KEY_OBASE:
3858 {
3859 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3860 s = bc_lex_next(&p->l);
3861 break;
3862 }
3863
3864 case BC_LEX_KEY_SCALE:
3865 {
3866 s = bc_lex_next(&p->l);
3867 if (s) return s;
3868 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003869 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003870 else
3871 bc_parse_push(p, BC_INST_SCALE);
3872 break;
3873 }
3874
3875 default:
3876 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003877 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003878 break;
3879 }
3880 }
3881
3882 if (!s) bc_parse_push(p, inst);
3883 }
3884
3885 return s;
3886}
3887
3888static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3889 bool rparen, size_t *nexprs)
3890{
3891 BcStatus s;
3892 BcLexType type;
3893 BcInst etype = *prev;
3894
3895 s = bc_lex_next(&p->l);
3896 if (s) return s;
3897
3898 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3899 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3900 BC_LEX_OP_MINUS :
3901 BC_LEX_NEG;
3902 *prev = BC_PARSE_TOKEN_INST(type);
3903
3904 // We can just push onto the op stack because this is the largest
3905 // precedence operator that gets pushed. Inc/dec does not.
3906 if (type != BC_LEX_OP_MINUS)
3907 bc_vec_push(&p->ops, &type);
3908 else
3909 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3910
3911 return s;
3912}
3913
3914static BcStatus bc_parse_string(BcParse *p, char inst)
3915{
3916 char *str = xstrdup(p->l.t.v.v);
3917
3918 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003919 bc_parse_pushIndex(p, G.prog.strs.len);
3920 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003921 bc_parse_push(p, inst);
3922
3923 return bc_lex_next(&p->l);
3924}
3925
3926static BcStatus bc_parse_print(BcParse *p)
3927{
3928 BcStatus s;
3929 BcLexType type;
3930 bool comma = false;
3931
3932 s = bc_lex_next(&p->l);
3933 if (s) return s;
3934
3935 type = p->l.t.t;
3936
3937 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003938 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003939
3940 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3941
3942 if (type == BC_LEX_STR)
3943 s = bc_parse_string(p, BC_INST_PRINT_POP);
3944 else {
3945 s = bc_parse_expr(p, 0, bc_parse_next_print);
3946 if (s) return s;
3947 bc_parse_push(p, BC_INST_PRINT_POP);
3948 }
3949
3950 if (s) return s;
3951
3952 comma = p->l.t.t == BC_LEX_COMMA;
3953 if (comma) s = bc_lex_next(&p->l);
3954 type = p->l.t.t;
3955 }
3956
3957 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003958 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003959
3960 return bc_lex_next(&p->l);
3961}
3962
3963static BcStatus bc_parse_return(BcParse *p)
3964{
3965 BcStatus s;
3966 BcLexType t;
3967 bool paren;
3968
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003969 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003970
3971 s = bc_lex_next(&p->l);
3972 if (s) return s;
3973
3974 t = p->l.t.t;
3975 paren = t == BC_LEX_LPAREN;
3976
3977 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3978 bc_parse_push(p, BC_INST_RET0);
3979 else {
3980
3981 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3982 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3983 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003984
3985 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003986 bc_parse_push(p, BC_INST_RET0);
3987 s = bc_lex_next(&p->l);
3988 if (s) return s;
3989 }
3990
3991 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003992 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06003993 if (s) return s;
3994 }
3995
3996 bc_parse_push(p, BC_INST_RET);
3997 }
3998
3999 return s;
4000}
4001
4002static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4003{
4004 BcStatus s = BC_STATUS_SUCCESS;
4005
4006 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004007 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004008
4009 if (brace) {
4010
4011 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004012 if (!p->nbraces) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004013 --p->nbraces;
4014 s = bc_lex_next(&p->l);
4015 if (s) return s;
4016 }
4017 else
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004018 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004019 }
4020
4021 if (BC_PARSE_IF(p)) {
4022
4023 uint8_t *flag_ptr;
4024
4025 while (p->l.t.t == BC_LEX_NLINE) {
4026 s = bc_lex_next(&p->l);
4027 if (s) return s;
4028 }
4029
4030 bc_vec_pop(&p->flags);
4031
4032 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4033 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4034
4035 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4036 }
4037 else if (BC_PARSE_ELSE(p)) {
4038
4039 BcInstPtr *ip;
4040 size_t *label;
4041
4042 bc_vec_pop(&p->flags);
4043
4044 ip = bc_vec_top(&p->exits);
4045 label = bc_vec_item(&p->func->labels, ip->idx);
4046 *label = p->func->code.len;
4047
4048 bc_vec_pop(&p->exits);
4049 }
4050 else if (BC_PARSE_FUNC_INNER(p)) {
4051 bc_parse_push(p, BC_INST_RET0);
4052 bc_parse_updateFunc(p, BC_PROG_MAIN);
4053 bc_vec_pop(&p->flags);
4054 }
4055 else {
4056
4057 BcInstPtr *ip = bc_vec_top(&p->exits);
4058 size_t *label = bc_vec_top(&p->conds);
4059
4060 bc_parse_push(p, BC_INST_JUMP);
4061 bc_parse_pushIndex(p, *label);
4062
4063 label = bc_vec_item(&p->func->labels, ip->idx);
4064 *label = p->func->code.len;
4065
4066 bc_vec_pop(&p->flags);
4067 bc_vec_pop(&p->exits);
4068 bc_vec_pop(&p->conds);
4069 }
4070
4071 return s;
4072}
4073
4074static void bc_parse_startBody(BcParse *p, uint8_t flags)
4075{
4076 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4077 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4078 flags |= BC_PARSE_FLAG_BODY;
4079 bc_vec_push(&p->flags, &flags);
4080}
4081
4082static void bc_parse_noElse(BcParse *p)
4083{
4084 BcInstPtr *ip;
4085 size_t *label;
4086 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4087
4088 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4089
4090 ip = bc_vec_top(&p->exits);
4091 label = bc_vec_item(&p->func->labels, ip->idx);
4092 *label = p->func->code.len;
4093
4094 bc_vec_pop(&p->exits);
4095}
4096
4097static BcStatus bc_parse_if(BcParse *p)
4098{
4099 BcStatus s;
4100 BcInstPtr ip;
4101
4102 s = bc_lex_next(&p->l);
4103 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004104 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004105
4106 s = bc_lex_next(&p->l);
4107 if (s) return s;
4108 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4109 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004110 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004111
4112 s = bc_lex_next(&p->l);
4113 if (s) return s;
4114 bc_parse_push(p, BC_INST_JUMP_ZERO);
4115
4116 ip.idx = p->func->labels.len;
4117 ip.func = ip.len = 0;
4118
4119 bc_parse_pushIndex(p, ip.idx);
4120 bc_vec_push(&p->exits, &ip);
4121 bc_vec_push(&p->func->labels, &ip.idx);
4122 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4123
4124 return BC_STATUS_SUCCESS;
4125}
4126
4127static BcStatus bc_parse_else(BcParse *p)
4128{
4129 BcInstPtr ip;
4130
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004131 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004132
4133 ip.idx = p->func->labels.len;
4134 ip.func = ip.len = 0;
4135
4136 bc_parse_push(p, BC_INST_JUMP);
4137 bc_parse_pushIndex(p, ip.idx);
4138
4139 bc_parse_noElse(p);
4140
4141 bc_vec_push(&p->exits, &ip);
4142 bc_vec_push(&p->func->labels, &ip.idx);
4143 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4144
4145 return bc_lex_next(&p->l);
4146}
4147
4148static BcStatus bc_parse_while(BcParse *p)
4149{
4150 BcStatus s;
4151 BcInstPtr ip;
4152
4153 s = bc_lex_next(&p->l);
4154 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004155 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004156 s = bc_lex_next(&p->l);
4157 if (s) return s;
4158
4159 ip.idx = p->func->labels.len;
4160
4161 bc_vec_push(&p->func->labels, &p->func->code.len);
4162 bc_vec_push(&p->conds, &ip.idx);
4163
4164 ip.idx = p->func->labels.len;
4165 ip.func = 1;
4166 ip.len = 0;
4167
4168 bc_vec_push(&p->exits, &ip);
4169 bc_vec_push(&p->func->labels, &ip.idx);
4170
4171 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4172 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004173 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004174 s = bc_lex_next(&p->l);
4175 if (s) return s;
4176
4177 bc_parse_push(p, BC_INST_JUMP_ZERO);
4178 bc_parse_pushIndex(p, ip.idx);
4179 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4180
4181 return BC_STATUS_SUCCESS;
4182}
4183
4184static BcStatus bc_parse_for(BcParse *p)
4185{
4186 BcStatus s;
4187 BcInstPtr ip;
4188 size_t cond_idx, exit_idx, body_idx, update_idx;
4189
4190 s = bc_lex_next(&p->l);
4191 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004192 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004193 s = bc_lex_next(&p->l);
4194 if (s) return s;
4195
4196 if (p->l.t.t != BC_LEX_SCOLON)
4197 s = bc_parse_expr(p, 0, bc_parse_next_for);
4198 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004199 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004200
4201 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004202 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004203 s = bc_lex_next(&p->l);
4204 if (s) return s;
4205
4206 cond_idx = p->func->labels.len;
4207 update_idx = cond_idx + 1;
4208 body_idx = update_idx + 1;
4209 exit_idx = body_idx + 1;
4210
4211 bc_vec_push(&p->func->labels, &p->func->code.len);
4212
4213 if (p->l.t.t != BC_LEX_SCOLON)
4214 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4215 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004216 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004217
4218 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004219 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004220
4221 s = bc_lex_next(&p->l);
4222 if (s) return s;
4223
4224 bc_parse_push(p, BC_INST_JUMP_ZERO);
4225 bc_parse_pushIndex(p, exit_idx);
4226 bc_parse_push(p, BC_INST_JUMP);
4227 bc_parse_pushIndex(p, body_idx);
4228
4229 ip.idx = p->func->labels.len;
4230
4231 bc_vec_push(&p->conds, &update_idx);
4232 bc_vec_push(&p->func->labels, &p->func->code.len);
4233
4234 if (p->l.t.t != BC_LEX_RPAREN)
4235 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4236 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004237 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004238
4239 if (s) return s;
4240
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004241 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004242 bc_parse_push(p, BC_INST_JUMP);
4243 bc_parse_pushIndex(p, cond_idx);
4244 bc_vec_push(&p->func->labels, &p->func->code.len);
4245
4246 ip.idx = exit_idx;
4247 ip.func = 1;
4248 ip.len = 0;
4249
4250 bc_vec_push(&p->exits, &ip);
4251 bc_vec_push(&p->func->labels, &ip.idx);
4252 bc_lex_next(&p->l);
4253 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4254
4255 return BC_STATUS_SUCCESS;
4256}
4257
4258static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4259{
4260 BcStatus s;
4261 size_t i;
4262 BcInstPtr *ip;
4263
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004264 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004265
4266 if (type == BC_LEX_KEY_BREAK) {
4267
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004268 if (p->exits.len == 0) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004269
4270 i = p->exits.len - 1;
4271 ip = bc_vec_item(&p->exits, i);
4272
4273 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004274 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004275
4276 i = ip->idx;
4277 }
4278 else
4279 i = *((size_t *) bc_vec_top(&p->conds));
4280
4281 bc_parse_push(p, BC_INST_JUMP);
4282 bc_parse_pushIndex(p, i);
4283
4284 s = bc_lex_next(&p->l);
4285 if (s) return s;
4286
4287 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004288 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004289
4290 return bc_lex_next(&p->l);
4291}
4292
4293static BcStatus bc_parse_func(BcParse *p)
4294{
4295 BcStatus s;
4296 bool var, comma = false;
4297 uint8_t flags;
4298 char *name;
4299
4300 s = bc_lex_next(&p->l);
4301 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004302 if (p->l.t.t != BC_LEX_NAME)
4303 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004304
4305 name = xstrdup(p->l.t.v.v);
4306 bc_parse_addFunc(p, name, &p->fidx);
4307
4308 s = bc_lex_next(&p->l);
4309 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004310 if (p->l.t.t != BC_LEX_LPAREN)
4311 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004312 s = bc_lex_next(&p->l);
4313 if (s) return s;
4314
4315 while (p->l.t.t != BC_LEX_RPAREN) {
4316
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004317 if (p->l.t.t != BC_LEX_NAME)
4318 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004319
4320 ++p->func->nparams;
4321
4322 name = xstrdup(p->l.t.v.v);
4323 s = bc_lex_next(&p->l);
4324 if (s) goto err;
4325
4326 var = p->l.t.t != BC_LEX_LBRACKET;
4327
4328 if (!var) {
4329
4330 s = bc_lex_next(&p->l);
4331 if (s) goto err;
4332
4333 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004334 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004335 goto err;
4336 }
4337
4338 s = bc_lex_next(&p->l);
4339 if (s) goto err;
4340 }
4341
4342 comma = p->l.t.t == BC_LEX_COMMA;
4343 if (comma) {
4344 s = bc_lex_next(&p->l);
4345 if (s) goto err;
4346 }
4347
4348 s = bc_func_insert(p->func, name, var);
4349 if (s) goto err;
4350 }
4351
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004352 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004353
4354 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4355 bc_parse_startBody(p, flags);
4356
4357 s = bc_lex_next(&p->l);
4358 if (s) return s;
4359
4360 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004361 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 -06004362
4363 return s;
4364
4365err:
4366 free(name);
4367 return s;
4368}
4369
4370static BcStatus bc_parse_auto(BcParse *p)
4371{
4372 BcStatus s;
4373 bool comma, var, one;
4374 char *name;
4375
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004376 if (!p->auto_part) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004377 s = bc_lex_next(&p->l);
4378 if (s) return s;
4379
4380 p->auto_part = comma = false;
4381 one = p->l.t.t == BC_LEX_NAME;
4382
4383 while (p->l.t.t == BC_LEX_NAME) {
4384
4385 name = xstrdup(p->l.t.v.v);
4386 s = bc_lex_next(&p->l);
4387 if (s) goto err;
4388
4389 var = p->l.t.t != BC_LEX_LBRACKET;
4390 if (!var) {
4391
4392 s = bc_lex_next(&p->l);
4393 if (s) goto err;
4394
4395 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004396 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004397 goto err;
4398 }
4399
4400 s = bc_lex_next(&p->l);
4401 if (s) goto err;
4402 }
4403
4404 comma = p->l.t.t == BC_LEX_COMMA;
4405 if (comma) {
4406 s = bc_lex_next(&p->l);
4407 if (s) goto err;
4408 }
4409
4410 s = bc_func_insert(p->func, name, var);
4411 if (s) goto err;
4412 }
4413
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004414 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004415 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004416
4417 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004418 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004419
4420 return bc_lex_next(&p->l);
4421
4422err:
4423 free(name);
4424 return s;
4425}
4426
4427static BcStatus bc_parse_body(BcParse *p, bool brace)
4428{
4429 BcStatus s = BC_STATUS_SUCCESS;
4430 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4431
4432 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4433
4434 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4435
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004436 if (!brace) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004437 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4438
4439 if (!p->auto_part) {
4440 s = bc_parse_auto(p);
4441 if (s) return s;
4442 }
4443
4444 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4445 }
4446 else {
4447 s = bc_parse_stmt(p);
4448 if (!s && !brace) s = bc_parse_endBody(p, false);
4449 }
4450
4451 return s;
4452}
4453
4454static BcStatus bc_parse_stmt(BcParse *p)
4455{
4456 BcStatus s = BC_STATUS_SUCCESS;
4457
4458 switch (p->l.t.t) {
4459
4460 case BC_LEX_NLINE:
4461 {
4462 return bc_lex_next(&p->l);
4463 }
4464
4465 case BC_LEX_KEY_ELSE:
4466 {
4467 p->auto_part = false;
4468 break;
4469 }
4470
4471 case BC_LEX_LBRACE:
4472 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004473 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004474
4475 ++p->nbraces;
4476 s = bc_lex_next(&p->l);
4477 if (s) return s;
4478
4479 return bc_parse_body(p, true);
4480 }
4481
4482 case BC_LEX_KEY_AUTO:
4483 {
4484 return bc_parse_auto(p);
4485 }
4486
4487 default:
4488 {
4489 p->auto_part = false;
4490
4491 if (BC_PARSE_IF_END(p)) {
4492 bc_parse_noElse(p);
4493 return BC_STATUS_SUCCESS;
4494 }
4495 else if (BC_PARSE_BODY(p))
4496 return bc_parse_body(p, false);
4497
4498 break;
4499 }
4500 }
4501
4502 switch (p->l.t.t) {
4503
4504 case BC_LEX_OP_INC:
4505 case BC_LEX_OP_DEC:
4506 case BC_LEX_OP_MINUS:
4507 case BC_LEX_OP_BOOL_NOT:
4508 case BC_LEX_LPAREN:
4509 case BC_LEX_NAME:
4510 case BC_LEX_NUMBER:
4511 case BC_LEX_KEY_IBASE:
4512 case BC_LEX_KEY_LAST:
4513 case BC_LEX_KEY_LENGTH:
4514 case BC_LEX_KEY_OBASE:
4515 case BC_LEX_KEY_READ:
4516 case BC_LEX_KEY_SCALE:
4517 case BC_LEX_KEY_SQRT:
4518 {
4519 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4520 break;
4521 }
4522
4523 case BC_LEX_KEY_ELSE:
4524 {
4525 s = bc_parse_else(p);
4526 break;
4527 }
4528
4529 case BC_LEX_SCOLON:
4530 {
4531 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4532 break;
4533 }
4534
4535 case BC_LEX_RBRACE:
4536 {
4537 s = bc_parse_endBody(p, true);
4538 break;
4539 }
4540
4541 case BC_LEX_STR:
4542 {
4543 s = bc_parse_string(p, BC_INST_PRINT_STR);
4544 break;
4545 }
4546
4547 case BC_LEX_KEY_BREAK:
4548 case BC_LEX_KEY_CONTINUE:
4549 {
4550 s = bc_parse_loopExit(p, p->l.t.t);
4551 break;
4552 }
4553
4554 case BC_LEX_KEY_FOR:
4555 {
4556 s = bc_parse_for(p);
4557 break;
4558 }
4559
4560 case BC_LEX_KEY_HALT:
4561 {
4562 bc_parse_push(p, BC_INST_HALT);
4563 s = bc_lex_next(&p->l);
4564 break;
4565 }
4566
4567 case BC_LEX_KEY_IF:
4568 {
4569 s = bc_parse_if(p);
4570 break;
4571 }
4572
4573 case BC_LEX_KEY_LIMITS:
4574 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004575 // "limits" is a compile-time command,
4576 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004577 s = bc_lex_next(&p->l);
4578 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004579 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4580 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4581 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4582 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4583 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4584 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4585 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4586 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004587 break;
4588 }
4589
4590 case BC_LEX_KEY_PRINT:
4591 {
4592 s = bc_parse_print(p);
4593 break;
4594 }
4595
4596 case BC_LEX_KEY_QUIT:
4597 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004598 // "quit" is a compile-time command. For example,
4599 // "if (0 == 1) quit" terminates when parsing the statement,
4600 // not when it is executed
4601 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004602 }
4603
4604 case BC_LEX_KEY_RETURN:
4605 {
4606 s = bc_parse_return(p);
4607 break;
4608 }
4609
4610 case BC_LEX_KEY_WHILE:
4611 {
4612 s = bc_parse_while(p);
4613 break;
4614 }
4615
4616 default:
4617 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004618 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004619 break;
4620 }
4621 }
4622
4623 return s;
4624}
4625
4626static BcStatus bc_parse_parse(BcParse *p)
4627{
4628 BcStatus s;
4629
4630 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004631 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 -06004632 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004633 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004634 s = bc_parse_func(p);
4635 }
4636 else
4637 s = bc_parse_stmt(p);
4638
Denys Vlasenkod38af482018-12-04 19:11:02 +01004639 if (s || G_interrupt) {
4640 bc_parse_reset(p);
4641 s = BC_STATUS_FAILURE;
4642 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004643
4644 return s;
4645}
4646
4647static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4648{
4649 BcStatus s = BC_STATUS_SUCCESS;
4650 BcInst prev = BC_INST_PRINT;
4651 BcLexType top, t = p->l.t.t;
4652 size_t nexprs = 0, ops_bgn = p->ops.len;
4653 uint32_t i, nparens, nrelops;
4654 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4655
4656 paren_first = p->l.t.t == BC_LEX_LPAREN;
4657 nparens = nrelops = 0;
4658 paren_expr = rprn = done = get_token = assign = false;
4659 bin_last = true;
4660
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004661 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004662 switch (t) {
4663
4664 case BC_LEX_OP_INC:
4665 case BC_LEX_OP_DEC:
4666 {
4667 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4668 rprn = get_token = bin_last = false;
4669 break;
4670 }
4671
4672 case BC_LEX_OP_MINUS:
4673 {
4674 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4675 rprn = get_token = false;
4676 bin_last = prev == BC_INST_MINUS;
4677 break;
4678 }
4679
4680 case BC_LEX_OP_ASSIGN_POWER:
4681 case BC_LEX_OP_ASSIGN_MULTIPLY:
4682 case BC_LEX_OP_ASSIGN_DIVIDE:
4683 case BC_LEX_OP_ASSIGN_MODULUS:
4684 case BC_LEX_OP_ASSIGN_PLUS:
4685 case BC_LEX_OP_ASSIGN_MINUS:
4686 case BC_LEX_OP_ASSIGN:
4687 {
4688 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4689 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4690 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4691 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004692 s = bc_error("bad assignment:"
4693 " left side must be scale,"
4694 " ibase, obase, last, var,"
4695 " or array element"
4696 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004697 break;
4698 }
4699 }
4700 // Fallthrough.
4701 case BC_LEX_OP_POWER:
4702 case BC_LEX_OP_MULTIPLY:
4703 case BC_LEX_OP_DIVIDE:
4704 case BC_LEX_OP_MODULUS:
4705 case BC_LEX_OP_PLUS:
4706 case BC_LEX_OP_REL_EQ:
4707 case BC_LEX_OP_REL_LE:
4708 case BC_LEX_OP_REL_GE:
4709 case BC_LEX_OP_REL_NE:
4710 case BC_LEX_OP_REL_LT:
4711 case BC_LEX_OP_REL_GT:
4712 case BC_LEX_OP_BOOL_NOT:
4713 case BC_LEX_OP_BOOL_OR:
4714 case BC_LEX_OP_BOOL_AND:
4715 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004716 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4717 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4718 ) {
4719 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004720 }
4721
4722 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4723 prev = BC_PARSE_TOKEN_INST(t);
4724 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4725 rprn = get_token = false;
4726 bin_last = t != BC_LEX_OP_BOOL_NOT;
4727
4728 break;
4729 }
4730
4731 case BC_LEX_LPAREN:
4732 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004733 if (BC_PARSE_LEAF(prev, rprn))
4734 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004735 ++nparens;
4736 paren_expr = rprn = bin_last = false;
4737 get_token = true;
4738 bc_vec_push(&p->ops, &t);
4739
4740 break;
4741 }
4742
4743 case BC_LEX_RPAREN:
4744 {
4745 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004746 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004747
4748 if (nparens == 0) {
4749 s = BC_STATUS_SUCCESS;
4750 done = true;
4751 get_token = false;
4752 break;
4753 }
4754 else if (!paren_expr)
4755 return BC_STATUS_PARSE_EMPTY_EXP;
4756
4757 --nparens;
4758 paren_expr = rprn = true;
4759 get_token = bin_last = false;
4760
4761 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4762
4763 break;
4764 }
4765
4766 case BC_LEX_NAME:
4767 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004768 if (BC_PARSE_LEAF(prev, rprn))
4769 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004770 paren_expr = true;
4771 rprn = get_token = bin_last = false;
4772 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4773 ++nexprs;
4774
4775 break;
4776 }
4777
4778 case BC_LEX_NUMBER:
4779 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004780 if (BC_PARSE_LEAF(prev, rprn))
4781 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004782 bc_parse_number(p, &prev, &nexprs);
4783 paren_expr = get_token = true;
4784 rprn = bin_last = false;
4785
4786 break;
4787 }
4788
4789 case BC_LEX_KEY_IBASE:
4790 case BC_LEX_KEY_LAST:
4791 case BC_LEX_KEY_OBASE:
4792 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004793 if (BC_PARSE_LEAF(prev, rprn))
4794 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004795 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4796 bc_parse_push(p, (char) prev);
4797
4798 paren_expr = get_token = true;
4799 rprn = bin_last = false;
4800 ++nexprs;
4801
4802 break;
4803 }
4804
4805 case BC_LEX_KEY_LENGTH:
4806 case BC_LEX_KEY_SQRT:
4807 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004808 if (BC_PARSE_LEAF(prev, rprn))
4809 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004810 s = bc_parse_builtin(p, t, flags, &prev);
4811 paren_expr = true;
4812 rprn = get_token = bin_last = false;
4813 ++nexprs;
4814
4815 break;
4816 }
4817
4818 case BC_LEX_KEY_READ:
4819 {
4820 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004821 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004822 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004823 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06004824 else
4825 s = bc_parse_read(p);
4826
4827 paren_expr = true;
4828 rprn = get_token = bin_last = false;
4829 ++nexprs;
4830 prev = BC_INST_READ;
4831
4832 break;
4833 }
4834
4835 case BC_LEX_KEY_SCALE:
4836 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004837 if (BC_PARSE_LEAF(prev, rprn))
4838 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004839 s = bc_parse_scale(p, &prev, flags);
4840 paren_expr = true;
4841 rprn = get_token = bin_last = false;
4842 ++nexprs;
4843 prev = BC_INST_SCALE;
4844
4845 break;
4846 }
4847
4848 default:
4849 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004850 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004851 break;
4852 }
4853 }
4854
4855 if (!s && get_token) s = bc_lex_next(&p->l);
4856 }
4857
4858 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004859 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004860
4861 while (p->ops.len > ops_bgn) {
4862
4863 top = BC_PARSE_TOP_OP(p);
4864 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4865
4866 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004867 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004868
4869 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4870
4871 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4872 bc_vec_pop(&p->ops);
4873 }
4874
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004875 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4876 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004877
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004878 for (i = 0; i < next.len; ++i)
4879 if (t == next.tokens[i])
4880 goto ok;
4881 return bc_error("bad expression");
4882 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004883
4884 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004885 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004886 if (s) return s;
4887 }
4888 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004889 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004890 if (s) return s;
4891 }
4892
4893 if (flags & BC_PARSE_PRINT) {
4894 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4895 bc_parse_push(p, BC_INST_POP);
4896 }
4897
4898 return s;
4899}
4900
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004901static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004902{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004903 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004904}
4905
4906static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4907{
4908 return bc_parse_expr(p, flags, bc_parse_next_read);
4909}
4910#endif // ENABLE_BC
4911
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004912#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004913static BcStatus dc_parse_register(BcParse *p)
4914{
4915 BcStatus s;
4916 char *name;
4917
4918 s = bc_lex_next(&p->l);
4919 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004920 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004921
4922 name = xstrdup(p->l.t.v.v);
4923 bc_parse_pushName(p, name);
4924
4925 return s;
4926}
4927
4928static BcStatus dc_parse_string(BcParse *p)
4929{
4930 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004931 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004932
4933 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4934 name = xstrdup(b);
4935
4936 str = xstrdup(p->l.t.v.v);
4937 bc_parse_push(p, BC_INST_STR);
4938 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004939 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004940 bc_parse_addFunc(p, name, &idx);
4941
4942 return bc_lex_next(&p->l);
4943}
4944
4945static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4946{
4947 BcStatus s;
4948
4949 bc_parse_push(p, inst);
4950 if (name) {
4951 s = dc_parse_register(p);
4952 if (s) return s;
4953 }
4954
4955 if (store) {
4956 bc_parse_push(p, BC_INST_SWAP);
4957 bc_parse_push(p, BC_INST_ASSIGN);
4958 bc_parse_push(p, BC_INST_POP);
4959 }
4960
4961 return bc_lex_next(&p->l);
4962}
4963
4964static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4965{
4966 BcStatus s;
4967
4968 bc_parse_push(p, inst);
4969 bc_parse_push(p, BC_INST_EXEC_COND);
4970
4971 s = dc_parse_register(p);
4972 if (s) return s;
4973
4974 s = bc_lex_next(&p->l);
4975 if (s) return s;
4976
4977 if (p->l.t.t == BC_LEX_ELSE) {
4978 s = dc_parse_register(p);
4979 if (s) return s;
4980 s = bc_lex_next(&p->l);
4981 }
4982 else
4983 bc_parse_push(p, BC_PARSE_STREND);
4984
4985 return s;
4986}
4987
4988static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4989{
4990 BcStatus s = BC_STATUS_SUCCESS;
4991 BcInst prev;
4992 uint8_t inst;
4993 bool assign, get_token = false;
4994
4995 switch (t) {
4996
4997 case BC_LEX_OP_REL_EQ:
4998 case BC_LEX_OP_REL_LE:
4999 case BC_LEX_OP_REL_GE:
5000 case BC_LEX_OP_REL_NE:
5001 case BC_LEX_OP_REL_LT:
5002 case BC_LEX_OP_REL_GT:
5003 {
5004 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5005 break;
5006 }
5007
5008 case BC_LEX_SCOLON:
5009 case BC_LEX_COLON:
5010 {
5011 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5012 break;
5013 }
5014
5015 case BC_LEX_STR:
5016 {
5017 s = dc_parse_string(p);
5018 break;
5019 }
5020
5021 case BC_LEX_NEG:
5022 case BC_LEX_NUMBER:
5023 {
5024 if (t == BC_LEX_NEG) {
5025 s = bc_lex_next(&p->l);
5026 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005027 if (p->l.t.t != BC_LEX_NUMBER)
5028 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005029 }
5030
5031 bc_parse_number(p, &prev, &p->nbraces);
5032
5033 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5034 get_token = true;
5035
5036 break;
5037 }
5038
5039 case BC_LEX_KEY_READ:
5040 {
5041 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005042 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005043 else
5044 bc_parse_push(p, BC_INST_READ);
5045 get_token = true;
5046 break;
5047 }
5048
5049 case BC_LEX_OP_ASSIGN:
5050 case BC_LEX_STORE_PUSH:
5051 {
5052 assign = t == BC_LEX_OP_ASSIGN;
5053 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5054 s = dc_parse_mem(p, inst, true, assign);
5055 break;
5056 }
5057
5058 case BC_LEX_LOAD:
5059 case BC_LEX_LOAD_POP:
5060 {
5061 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5062 s = dc_parse_mem(p, inst, true, false);
5063 break;
5064 }
5065
5066 case BC_LEX_STORE_IBASE:
5067 case BC_LEX_STORE_SCALE:
5068 case BC_LEX_STORE_OBASE:
5069 {
5070 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5071 s = dc_parse_mem(p, inst, false, true);
5072 break;
5073 }
5074
5075 default:
5076 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005077 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005078 get_token = true;
5079 break;
5080 }
5081 }
5082
5083 if (!s && get_token) s = bc_lex_next(&p->l);
5084
5085 return s;
5086}
5087
5088static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5089{
5090 BcStatus s = BC_STATUS_SUCCESS;
5091 BcInst inst;
5092 BcLexType t;
5093
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005094 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005095
5096 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5097
5098 inst = dc_parse_insts[t];
5099
5100 if (inst != BC_INST_INVALID) {
5101 bc_parse_push(p, inst);
5102 s = bc_lex_next(&p->l);
5103 }
5104 else
5105 s = dc_parse_token(p, t, flags);
5106 }
5107
5108 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5109 bc_parse_push(p, BC_INST_POP_EXEC);
5110
5111 return s;
5112}
5113
5114static BcStatus dc_parse_parse(BcParse *p)
5115{
5116 BcStatus s;
5117
5118 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005119 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005120 else
5121 s = dc_parse_expr(p, 0);
5122
Denys Vlasenkod38af482018-12-04 19:11:02 +01005123 if (s || G_interrupt) {
5124 bc_parse_reset(p);
5125 s = BC_STATUS_FAILURE;
5126 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005127
5128 return s;
5129}
5130
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005131static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005132{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005133 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005134}
5135#endif // ENABLE_DC
5136
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005137static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005138{
5139 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005140 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005141 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005142 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005143 }
5144}
5145
5146static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5147{
5148 if (IS_BC) {
5149 return bc_parse_expression(p, flags);
5150 } else {
5151 return dc_parse_expr(p, flags);
5152 }
5153}
5154
Denys Vlasenkodf515392018-12-02 19:27:48 +01005155static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005156{
Gavin Howard01055ba2018-11-03 11:00:21 -06005157 BcId e, *ptr;
5158 BcVec *v, *map;
5159 size_t i;
5160 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005161 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005162
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005163 v = var ? &G.prog.vars : &G.prog.arrs;
5164 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005165
5166 e.name = id;
5167 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005168 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005169
5170 if (new) {
5171 bc_array_init(&data.v, var);
5172 bc_vec_push(v, &data.v);
5173 }
5174
5175 ptr = bc_vec_item(map, i);
5176 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005177 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005178}
5179
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005180static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005181{
5182 BcStatus s = BC_STATUS_SUCCESS;
5183
5184 switch (r->t) {
5185
5186 case BC_RESULT_STR:
5187 case BC_RESULT_TEMP:
5188 case BC_RESULT_IBASE:
5189 case BC_RESULT_SCALE:
5190 case BC_RESULT_OBASE:
5191 {
5192 *num = &r->d.n;
5193 break;
5194 }
5195
5196 case BC_RESULT_CONSTANT:
5197 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005198 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005199 size_t base_t, len = strlen(*str);
5200 BcNum *base;
5201
5202 bc_num_init(&r->d.n, len);
5203
5204 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005205 base = hex ? &G.prog.hexb : &G.prog.ib;
5206 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005207 s = bc_num_parse(&r->d.n, *str, base, base_t);
5208
5209 if (s) {
5210 bc_num_free(&r->d.n);
5211 return s;
5212 }
5213
5214 *num = &r->d.n;
5215 r->t = BC_RESULT_TEMP;
5216
5217 break;
5218 }
5219
5220 case BC_RESULT_VAR:
5221 case BC_RESULT_ARRAY:
5222 case BC_RESULT_ARRAY_ELEM:
5223 {
5224 BcVec *v;
5225
Denys Vlasenkodf515392018-12-02 19:27:48 +01005226 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005227
5228 if (r->t == BC_RESULT_ARRAY_ELEM) {
5229 v = bc_vec_top(v);
5230 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5231 *num = bc_vec_item(v, r->d.id.idx);
5232 }
5233 else
5234 *num = bc_vec_top(v);
5235
5236 break;
5237 }
5238
5239 case BC_RESULT_LAST:
5240 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005241 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005242 break;
5243 }
5244
5245 case BC_RESULT_ONE:
5246 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005247 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005248 break;
5249 }
5250 }
5251
5252 return s;
5253}
5254
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005255static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005256 BcResult **r, BcNum **rn, bool assign)
5257{
5258 BcStatus s;
5259 bool hex;
5260 BcResultType lt, rt;
5261
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005262 if (!BC_PROG_STACK(&G.prog.results, 2))
5263 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005264
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005265 *r = bc_vec_item_rev(&G.prog.results, 0);
5266 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005267
5268 lt = (*l)->t;
5269 rt = (*r)->t;
5270 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005272 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005273 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005274 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005275 if (s) return s;
5276
5277 // We run this again under these conditions in case any vector has been
5278 // reallocated out from under the BcNums or arrays we had.
5279 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005280 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005281 if (s) return s;
5282 }
5283
5284 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005285 return bc_error("variable is wrong type");
5286 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5287 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005288
Gavin Howard01055ba2018-11-03 11:00:21 -06005289 return s;
5290}
5291
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005292static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005293{
5294 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005295 bc_vec_pop(&G.prog.results);
5296 bc_vec_pop(&G.prog.results);
5297 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005298}
5299
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005300static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005301{
5302 BcStatus s;
5303
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005304 if (!BC_PROG_STACK(&G.prog.results, 1))
5305 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005306 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005307
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005308 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005309 if (s) return s;
5310
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005311 if (!BC_PROG_NUM((*r), (*n)))
5312 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005313
5314 return s;
5315}
5316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005317static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005318{
5319 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005320 bc_vec_pop(&G.prog.results);
5321 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005322}
5323
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005324static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005325{
5326 BcStatus s;
5327 BcResult *opd1, *opd2, res;
5328 BcNum *n1, *n2 = NULL;
5329
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005330 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005331 if (s) return s;
5332 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5333
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005334 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005335 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005336 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005337
5338 return s;
5339
5340err:
5341 bc_num_free(&res.d.n);
5342 return s;
5343}
5344
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005345static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005346{
5347 BcStatus s;
5348 BcParse parse;
5349 BcVec buf;
5350 BcInstPtr ip;
5351 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005352 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005353
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005354 for (i = 0; i < G.prog.stack.len; ++i) {
5355 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005356 if (ip_ptr->func == BC_PROG_READ)
5357 return bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005358 }
5359
Denys Vlasenko7d628012018-12-04 21:46:47 +01005360 bc_vec_pop_all(&f->code);
5361 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06005362
5363 s = bc_read_line(&buf, "read> ");
5364 if (s) goto io_err;
5365
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005366 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005367 bc_lex_file(&parse.l, bc_program_stdin_name);
5368
5369 s = bc_parse_text(&parse, buf.v);
5370 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005371 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005372 if (s) goto exec_err;
5373
5374 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005375 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005376 goto exec_err;
5377 }
5378
5379 ip.func = BC_PROG_READ;
5380 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005381 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005382
5383 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005384 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005385
5386 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005387 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005388
5389exec_err:
5390 bc_parse_free(&parse);
5391io_err:
5392 bc_vec_free(&buf);
5393 return s;
5394}
5395
5396static size_t bc_program_index(char *code, size_t *bgn)
5397{
5398 char amt = code[(*bgn)++], i = 0;
5399 size_t res = 0;
5400
5401 for (; i < amt; ++i, ++(*bgn))
5402 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5403
5404 return res;
5405}
5406
5407static char *bc_program_name(char *code, size_t *bgn)
5408{
5409 size_t i;
5410 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5411
5412 s = xmalloc(ptr - str + 1);
5413 c = code[(*bgn)++];
5414
5415 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5416 s[i] = c;
5417
5418 s[i] = '\0';
5419
5420 return s;
5421}
5422
5423static void bc_program_printString(const char *str, size_t *nchars)
5424{
5425 size_t i, len = strlen(str);
5426
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005427#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005428 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005429 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005430 return;
5431 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005432#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005433
5434 for (i = 0; i < len; ++i, ++(*nchars)) {
5435
5436 int c = str[i];
5437
5438 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005439 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005440 else {
5441
5442 c = str[++i];
5443
5444 switch (c) {
5445
5446 case 'a':
5447 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005448 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005449 break;
5450 }
5451
5452 case 'b':
5453 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005454 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005455 break;
5456 }
5457
5458 case '\\':
5459 case 'e':
5460 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005461 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005462 break;
5463 }
5464
5465 case 'f':
5466 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005467 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005468 break;
5469 }
5470
5471 case 'n':
5472 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005473 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005474 *nchars = SIZE_MAX;
5475 break;
5476 }
5477
5478 case 'r':
5479 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005480 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005481 break;
5482 }
5483
5484 case 'q':
5485 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005486 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005487 break;
5488 }
5489
5490 case 't':
5491 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005492 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005493 break;
5494 }
5495
5496 default:
5497 {
5498 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005499 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005500 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005501 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005502 break;
5503 }
5504 }
5505 }
5506 }
5507}
5508
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005509static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005510{
5511 BcStatus s = BC_STATUS_SUCCESS;
5512 BcResult *r;
5513 size_t len, i;
5514 char *str;
5515 BcNum *num = NULL;
5516 bool pop = inst != BC_INST_PRINT;
5517
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005518 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5519 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005520
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005521 r = bc_vec_item_rev(&G.prog.results, idx);
5522 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005523 if (s) return s;
5524
5525 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005526 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5527 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005528 }
5529 else {
5530
5531 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005532 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005533
5534 if (inst == BC_INST_PRINT_STR) {
5535 for (i = 0, len = strlen(str); i < len; ++i) {
5536 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005537 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005538 if (c == '\n') G.prog.nchars = SIZE_MAX;
5539 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005540 }
5541 }
5542 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005543 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005544 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005545 }
5546 }
5547
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005548 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005549
5550 return s;
5551}
5552
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005553static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005554{
5555 BcStatus s;
5556 BcResult res, *ptr;
5557 BcNum *num = NULL;
5558
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005559 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005560 if (s) return s;
5561
5562 bc_num_init(&res.d.n, num->len);
5563 bc_num_copy(&res.d.n, num);
5564 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5565
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005566 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005567
5568 return s;
5569}
5570
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005571static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005572{
5573 BcStatus s;
5574 BcResult *opd1, *opd2, res;
5575 BcNum *n1, *n2;
5576 bool cond = 0;
5577 ssize_t cmp;
5578
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005579 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005580 if (s) return s;
5581 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5582
5583 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005584 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005585 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005586 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005587 else {
5588
5589 cmp = bc_num_cmp(n1, n2);
5590
5591 switch (inst) {
5592
5593 case BC_INST_REL_EQ:
5594 {
5595 cond = cmp == 0;
5596 break;
5597 }
5598
5599 case BC_INST_REL_LE:
5600 {
5601 cond = cmp <= 0;
5602 break;
5603 }
5604
5605 case BC_INST_REL_GE:
5606 {
5607 cond = cmp >= 0;
5608 break;
5609 }
5610
5611 case BC_INST_REL_NE:
5612 {
5613 cond = cmp != 0;
5614 break;
5615 }
5616
5617 case BC_INST_REL_LT:
5618 {
5619 cond = cmp < 0;
5620 break;
5621 }
5622
5623 case BC_INST_REL_GT:
5624 {
5625 cond = cmp > 0;
5626 break;
5627 }
5628 }
5629 }
5630
5631 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5632
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005633 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005634
5635 return s;
5636}
5637
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005638#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005639static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005640 bool push)
5641{
5642 BcNum n2;
5643 BcResult res;
5644
5645 memset(&n2, 0, sizeof(BcNum));
5646 n2.rdx = res.d.id.idx = r->d.id.idx;
5647 res.t = BC_RESULT_STR;
5648
5649 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005650 if (!BC_PROG_STACK(&G.prog.results, 2))
5651 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005652 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005653 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005654 }
5655
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005656 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005657
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005658 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005659 bc_vec_push(v, &n2);
5660
5661 return BC_STATUS_SUCCESS;
5662}
5663#endif // ENABLE_DC
5664
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005665static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005666{
5667 BcStatus s;
5668 BcResult *ptr, r;
5669 BcVec *v;
5670 BcNum *n;
5671
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005672 if (!BC_PROG_STACK(&G.prog.results, 1))
5673 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005674
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005675 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005676 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5677 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005678 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005679
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005680#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005681 if (ptr->t == BC_RESULT_STR && !var)
5682 return bc_error("variable is wrong type");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005683 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005684#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005685
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005686 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005687 if (s) return s;
5688
5689 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005690 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005691
5692 if (var) {
5693 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5694 bc_num_copy(&r.d.n, n);
5695 }
5696 else {
5697 bc_array_init(&r.d.v, true);
5698 bc_array_copy(&r.d.v, (BcVec *) n);
5699 }
5700
5701 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005702 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005703
5704 return s;
5705}
5706
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005707static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005708{
5709 BcStatus s;
5710 BcResult *left, *right, res;
5711 BcNum *l = NULL, *r = NULL;
5712 unsigned long val, max;
5713 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5714
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005715 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005716 if (s) return s;
5717
5718 ib = left->t == BC_RESULT_IBASE;
5719 sc = left->t == BC_RESULT_SCALE;
5720
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005721#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005722
5723 if (right->t == BC_RESULT_STR) {
5724
5725 BcVec *v;
5726
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005727 if (left->t != BC_RESULT_VAR)
5728 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005729 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005730
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005731 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005732 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005733#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
5735 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005736 return bc_error("bad assignment:"
5737 " left side must be scale,"
5738 " ibase, obase, last, var,"
5739 " or array element"
5740 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005741
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005742#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005743 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005744 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005745
5746 if (assign)
5747 bc_num_copy(l, r);
5748 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005749 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005750
5751 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005752#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005753 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005754#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005755
5756 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005757 static const char *const msg[] = {
5758 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5759 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5760 "?1", //BC_RESULT_LAST
5761 "?2", //BC_RESULT_CONSTANT
5762 "?3", //BC_RESULT_ONE
5763 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5764 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005765 size_t *ptr;
5766
5767 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005768 if (s)
5769 return s;
5770 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005771 if (sc) {
5772 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005773 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005774 }
5775 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005776 if (val < BC_NUM_MIN_BASE)
5777 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005778 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005779 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005780 }
5781
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005782 if (val > max)
5783 return bc_error(msg[s]);
5784 if (!sc)
5785 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005786
5787 *ptr = (size_t) val;
5788 s = BC_STATUS_SUCCESS;
5789 }
5790
5791 bc_num_init(&res.d.n, l->len);
5792 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005793 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005794
5795 return s;
5796}
5797
Denys Vlasenko416ce762018-12-02 20:57:17 +01005798#if !ENABLE_DC
5799#define bc_program_pushVar(code, bgn, pop, copy) \
5800 bc_program_pushVar(code, bgn)
5801// for bc, 'pop' and 'copy' are always false
5802#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005803static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005804 bool pop, bool copy)
5805{
5806 BcStatus s = BC_STATUS_SUCCESS;
5807 BcResult r;
5808 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005809
5810 r.t = BC_RESULT_VAR;
5811 r.d.id.name = name;
5812
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005813#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005814 {
5815 BcVec *v = bc_program_search(name, true);
5816 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005817
Denys Vlasenko416ce762018-12-02 20:57:17 +01005818 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005819
Denys Vlasenko416ce762018-12-02 20:57:17 +01005820 if (!BC_PROG_STACK(v, 2 - copy)) {
5821 free(name);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005822 return bc_error("stack has too few elements");
Denys Vlasenko416ce762018-12-02 20:57:17 +01005823 }
5824
Gavin Howard01055ba2018-11-03 11:00:21 -06005825 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005826 name = NULL;
5827
5828 if (!BC_PROG_STR(num)) {
5829
5830 r.t = BC_RESULT_TEMP;
5831
5832 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5833 bc_num_copy(&r.d.n, num);
5834 }
5835 else {
5836 r.t = BC_RESULT_STR;
5837 r.d.id.idx = num->rdx;
5838 }
5839
5840 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005841 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005842 }
5843#endif // ENABLE_DC
5844
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005845 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005846
5847 return s;
5848}
5849
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005850static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005851 char inst)
5852{
5853 BcStatus s = BC_STATUS_SUCCESS;
5854 BcResult r;
5855 BcNum *num;
5856
5857 r.d.id.name = bc_program_name(code, bgn);
5858
5859 if (inst == BC_INST_ARRAY) {
5860 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005861 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005862 }
5863 else {
5864
5865 BcResult *operand;
5866 unsigned long temp;
5867
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005868 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005869 if (s) goto err;
5870 s = bc_num_ulong(num, &temp);
5871 if (s) goto err;
5872
5873 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005874 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005875 goto err;
5876 }
5877
5878 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005879 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005880 }
5881
5882err:
5883 if (s) free(r.d.id.name);
5884 return s;
5885}
5886
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005887#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005888static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005889{
5890 BcStatus s;
5891 BcResult *ptr, res, copy;
5892 BcNum *num = NULL;
5893 char inst2 = inst;
5894
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005895 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005896 if (s) return s;
5897
5898 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5899 copy.t = BC_RESULT_TEMP;
5900 bc_num_init(&copy.d.n, num->len);
5901 bc_num_copy(&copy.d.n, num);
5902 }
5903
5904 res.t = BC_RESULT_ONE;
5905 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5906 BC_INST_ASSIGN_PLUS :
5907 BC_INST_ASSIGN_MINUS;
5908
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005909 bc_vec_push(&G.prog.results, &res);
5910 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005911
5912 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005913 bc_vec_pop(&G.prog.results);
5914 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005915 }
5916
5917 return s;
5918}
5919
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005920static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005921{
5922 BcStatus s = BC_STATUS_SUCCESS;
5923 BcInstPtr ip;
5924 size_t i, nparams = bc_program_index(code, idx);
5925 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005926 BcId *a;
5927 BcResultData param;
5928 BcResult *arg;
5929
5930 ip.idx = 0;
5931 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005932 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005933
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005934 if (func->code.len == 0) {
5935 return bc_error("undefined function");
5936 }
5937 if (nparams != func->nparams) {
5938 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5939 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005940 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005941
5942 for (i = 0; i < nparams; ++i) {
5943
5944 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005945 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005946
5947 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005948 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005949
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005950 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005951 if (s) return s;
5952 }
5953
5954 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005955 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005956
5957 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005958 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005959
5960 if (a->idx) {
5961 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5962 bc_vec_push(v, &param.n);
5963 }
5964 else {
5965 bc_array_init(&param.v, true);
5966 bc_vec_push(v, &param.v);
5967 }
5968 }
5969
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005970 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005971
5972 return BC_STATUS_SUCCESS;
5973}
5974
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005975static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005976{
5977 BcStatus s;
5978 BcResult res;
5979 BcFunc *f;
5980 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005981 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06005982
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005983 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005984 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005985
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005986 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005987 res.t = BC_RESULT_TEMP;
5988
5989 if (inst == BC_INST_RET) {
5990
5991 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005992 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005993
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005994 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005995 if (s) return s;
5996 bc_num_init(&res.d.n, num->len);
5997 bc_num_copy(&res.d.n, num);
5998 }
5999 else {
6000 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6001 bc_num_zero(&res.d.n);
6002 }
6003
6004 // We need to pop arguments as well, so this takes that into account.
6005 for (i = 0; i < f->autos.len; ++i) {
6006
6007 BcVec *v;
6008 BcId *a = bc_vec_item(&f->autos, i);
6009
Denys Vlasenkodf515392018-12-02 19:27:48 +01006010 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006011 bc_vec_pop(v);
6012 }
6013
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006014 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6015 bc_vec_push(&G.prog.results, &res);
6016 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006017
6018 return BC_STATUS_SUCCESS;
6019}
6020#endif // ENABLE_BC
6021
6022static unsigned long bc_program_scale(BcNum *n)
6023{
6024 return (unsigned long) n->rdx;
6025}
6026
6027static unsigned long bc_program_len(BcNum *n)
6028{
6029 unsigned long len = n->len;
6030 size_t i;
6031
6032 if (n->rdx != n->len) return len;
6033 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6034
6035 return len;
6036}
6037
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006038static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006039{
6040 BcStatus s;
6041 BcResult *opnd;
6042 BcNum *num = NULL;
6043 BcResult res;
6044 bool len = inst == BC_INST_LENGTH;
6045
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006046 if (!BC_PROG_STACK(&G.prog.results, 1))
6047 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006048 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006049
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006050 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006051 if (s) return s;
6052
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006053#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006054 if (!BC_PROG_NUM(opnd, num) && !len)
6055 return bc_error("variable is wrong type");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006056#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006057
6058 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6059
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006060 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006061#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006062 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006063 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006064 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006065#endif
6066#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006067 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6068
6069 char **str;
6070 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6071
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006072 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006073 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006074 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006075#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006076 else {
6077 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006078 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006079 }
6080
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006081 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006082
6083 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006084}
6085
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006086#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006087static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006088{
6089 BcStatus s;
6090 BcResult *opd1, *opd2, res, res2;
6091 BcNum *n1, *n2 = NULL;
6092
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006093 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006094 if (s) return s;
6095
6096 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6097 bc_num_init(&res2.d.n, n2->len);
6098
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006099 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006100 if (s) goto err;
6101
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006102 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006103 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006104 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006105
6106 return s;
6107
6108err:
6109 bc_num_free(&res2.d.n);
6110 bc_num_free(&res.d.n);
6111 return s;
6112}
6113
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006114static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006115{
6116 BcStatus s;
6117 BcResult *r1, *r2, *r3, res;
6118 BcNum *n1, *n2, *n3;
6119
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006120 if (!BC_PROG_STACK(&G.prog.results, 3))
6121 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006122 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006123 if (s) return s;
6124
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006125 r1 = bc_vec_item_rev(&G.prog.results, 2);
6126 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006127 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006128 if (!BC_PROG_NUM(r1, n1))
6129 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006130
6131 // Make sure that the values have their pointers updated, if necessary.
6132 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6133
6134 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006135 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006136 if (s) return s;
6137 }
6138
6139 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006140 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006141 if (s) return s;
6142 }
6143 }
6144
6145 bc_num_init(&res.d.n, n3->len);
6146 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6147 if (s) goto err;
6148
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006149 bc_vec_pop(&G.prog.results);
6150 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006151
6152 return s;
6153
6154err:
6155 bc_num_free(&res.d.n);
6156 return s;
6157}
6158
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006159static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006160{
Gavin Howard01055ba2018-11-03 11:00:21 -06006161 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006162 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006163
6164 res.t = BC_RESULT_TEMP;
6165
6166 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006167 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006168 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006169}
6170
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006171static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006172{
6173 BcStatus s;
6174 BcResult *r, res;
6175 BcNum *num = NULL, n;
6176 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006177 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006178 unsigned long val;
6179
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006180 if (!BC_PROG_STACK(&G.prog.results, 1))
6181 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006182 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006183
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006185 if (s) return s;
6186
6187 if (BC_PROG_NUM(r, num)) {
6188
6189 bc_num_init(&n, BC_NUM_DEF_SIZE);
6190 bc_num_copy(&n, num);
6191 bc_num_truncate(&n, n.rdx);
6192
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006193 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006194 if (s) goto num_err;
6195 s = bc_num_ulong(&n, &val);
6196 if (s) goto num_err;
6197
6198 c = (char) val;
6199
6200 bc_num_free(&n);
6201 }
6202 else {
6203 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006204 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006205 c = str2[0];
6206 }
6207
6208 str = xmalloc(2);
6209 str[0] = c;
6210 str[1] = '\0';
6211
6212 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006213 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006214
6215 if (idx != len + BC_PROG_REQ_FUNCS) {
6216
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006217 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6218 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006219 len = idx;
6220 break;
6221 }
6222 }
6223
6224 free(str);
6225 }
6226 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006227 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006228
6229 res.t = BC_RESULT_STR;
6230 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006231 bc_vec_pop(&G.prog.results);
6232 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006233
6234 return BC_STATUS_SUCCESS;
6235
6236num_err:
6237 bc_num_free(&n);
6238 return s;
6239}
6240
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006241static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006242{
6243 BcStatus s;
6244 BcResult *r;
6245 BcNum *n = NULL;
6246 size_t idx;
6247 char *str;
6248
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006249 if (!BC_PROG_STACK(&G.prog.results, 1))
6250 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006251 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006252
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006253 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006254 if (s) return s;
6255
6256 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006257 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006258 else {
6259 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006260 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006261 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006262 }
6263
6264 return s;
6265}
6266
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006267static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006268{
6269 BcStatus s;
6270 BcResult *opnd;
6271 BcNum *num = NULL;
6272 unsigned long val;
6273
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006274 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006275 if (s) return s;
6276 s = bc_num_ulong(num, &val);
6277 if (s) return s;
6278
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006279 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006280
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006281 if (G.prog.stack.len < val)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006282 return bc_error("stack has too few elements");
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006283 if (G.prog.stack.len == val)
6284 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006285
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006286 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006287
6288 return s;
6289}
6290
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006291static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006292 bool cond)
6293{
6294 BcStatus s = BC_STATUS_SUCCESS;
6295 BcResult *r;
6296 char **str;
6297 BcFunc *f;
6298 BcParse prs;
6299 BcInstPtr ip;
6300 size_t fidx, sidx;
6301 BcNum *n;
6302 bool exec;
6303
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006304 if (!BC_PROG_STACK(&G.prog.results, 1))
6305 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006306
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006307 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006308
6309 if (cond) {
6310
Gavin Howard01055ba2018-11-03 11:00:21 -06006311 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6312
6313 if (code[*bgn] == BC_PARSE_STREND)
6314 (*bgn) += 1;
6315 else
6316 else_name = bc_program_name(code, bgn);
6317
6318 exec = r->d.n.len != 0;
6319
6320 if (exec)
6321 name = then_name;
6322 else if (else_name != NULL) {
6323 exec = true;
6324 name = else_name;
6325 }
6326
6327 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006328 BcVec *v;
6329 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006330 n = bc_vec_top(v);
6331 }
6332
6333 free(then_name);
6334 free(else_name);
6335
6336 if (!exec) goto exit;
6337 if (!BC_PROG_STR(n)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006338 s = bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006339 goto exit;
6340 }
6341
6342 sidx = n->rdx;
6343 }
6344 else {
6345
6346 if (r->t == BC_RESULT_STR)
6347 sidx = r->d.id.idx;
6348 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006349 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006350 if (s || !BC_PROG_STR(n)) goto exit;
6351 sidx = n->rdx;
6352 }
6353 else
6354 goto exit;
6355 }
6356
6357 fidx = sidx + BC_PROG_REQ_FUNCS;
6358
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006359 str = bc_vec_item(&G.prog.strs, sidx);
6360 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006361
6362 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006363 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006364 s = bc_parse_text(&prs, *str);
6365 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006366 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006367 if (s) goto err;
6368
6369 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006370 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06006371 goto err;
6372 }
6373
6374 bc_parse_free(&prs);
6375 }
6376
6377 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006378 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006379 ip.func = fidx;
6380
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006381 bc_vec_pop(&G.prog.results);
6382 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006383
6384 return BC_STATUS_SUCCESS;
6385
6386err:
6387 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006388 f = bc_vec_item(&G.prog.fns, fidx);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006389 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06006390exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006391 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006392 return s;
6393}
6394#endif // ENABLE_DC
6395
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006396static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006397{
Gavin Howard01055ba2018-11-03 11:00:21 -06006398 BcResult res;
6399 unsigned long val;
6400
6401 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6402 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006403 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006404 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006405 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006406 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006407 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006408
6409 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006410 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006411 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006412}
6413
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006414static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006415{
Gavin Howard01055ba2018-11-03 11:00:21 -06006416 BcId entry, *entry_ptr;
6417 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006418 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006419
6420 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006421 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006422
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006423 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6424 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006425
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006426 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006427 *idx = entry_ptr->idx;
6428
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006429 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006430
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006431 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006432
6433 // We need to reset these, so the function can be repopulated.
6434 func->nparams = 0;
Denys Vlasenko7d628012018-12-04 21:46:47 +01006435 bc_vec_pop_all(&func->autos);
6436 bc_vec_pop_all(&func->code);
6437 bc_vec_pop_all(&func->labels);
Gavin Howard01055ba2018-11-03 11:00:21 -06006438 }
6439 else {
6440 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006441 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006442 }
6443}
6444
Denys Vlasenkod38af482018-12-04 19:11:02 +01006445// Called when parsing or execution detects a failure,
6446// resets execution structures.
6447static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006448{
6449 BcFunc *f;
6450 BcInstPtr *ip;
6451
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006452 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
Denys Vlasenko7d628012018-12-04 21:46:47 +01006453 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006454
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006455 f = bc_vec_item(&G.prog.fns, 0);
6456 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006457 ip->idx = f->code.len;
6458
Denys Vlasenkod38af482018-12-04 19:11:02 +01006459 // If !tty, no need to check for ^C: we don't have ^C handler,
6460 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006461}
6462
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006463static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006464{
6465 BcStatus s = BC_STATUS_SUCCESS;
6466 size_t idx;
6467 BcResult r, *ptr;
6468 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006469 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6470 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006471 char *code = func->code.v;
6472 bool cond = false;
6473
6474 while (!s && ip->idx < func->code.len) {
6475
6476 char inst = code[(ip->idx)++];
6477
6478 switch (inst) {
6479
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006480#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006481 case BC_INST_JUMP_ZERO:
6482 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006483 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006484 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006485 cond = !bc_num_cmp(num, &G.prog.zero);
6486 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006487 }
6488 // Fallthrough.
6489 case BC_INST_JUMP:
6490 {
6491 size_t *addr;
6492 idx = bc_program_index(code, &ip->idx);
6493 addr = bc_vec_item(&func->labels, idx);
6494 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6495 break;
6496 }
6497
6498 case BC_INST_CALL:
6499 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006500 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006501 break;
6502 }
6503
6504 case BC_INST_INC_PRE:
6505 case BC_INST_DEC_PRE:
6506 case BC_INST_INC_POST:
6507 case BC_INST_DEC_POST:
6508 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006509 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006510 break;
6511 }
6512
6513 case BC_INST_HALT:
6514 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006515 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006516 break;
6517 }
6518
6519 case BC_INST_RET:
6520 case BC_INST_RET0:
6521 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006522 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006523 break;
6524 }
6525
6526 case BC_INST_BOOL_OR:
6527 case BC_INST_BOOL_AND:
6528#endif // ENABLE_BC
6529 case BC_INST_REL_EQ:
6530 case BC_INST_REL_LE:
6531 case BC_INST_REL_GE:
6532 case BC_INST_REL_NE:
6533 case BC_INST_REL_LT:
6534 case BC_INST_REL_GT:
6535 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006536 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006537 break;
6538 }
6539
6540 case BC_INST_READ:
6541 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006542 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006543 break;
6544 }
6545
6546 case BC_INST_VAR:
6547 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006548 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006549 break;
6550 }
6551
6552 case BC_INST_ARRAY_ELEM:
6553 case BC_INST_ARRAY:
6554 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006555 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 break;
6557 }
6558
6559 case BC_INST_LAST:
6560 {
6561 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006562 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 break;
6564 }
6565
6566 case BC_INST_IBASE:
6567 case BC_INST_SCALE:
6568 case BC_INST_OBASE:
6569 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006570 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006571 break;
6572 }
6573
6574 case BC_INST_SCALE_FUNC:
6575 case BC_INST_LENGTH:
6576 case BC_INST_SQRT:
6577 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006578 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006579 break;
6580 }
6581
6582 case BC_INST_NUM:
6583 {
6584 r.t = BC_RESULT_CONSTANT;
6585 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006586 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006587 break;
6588 }
6589
6590 case BC_INST_POP:
6591 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006592 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006593 s = bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006594 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006595 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006596 break;
6597 }
6598
6599 case BC_INST_POP_EXEC:
6600 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006601 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006602 break;
6603 }
6604
6605 case BC_INST_PRINT:
6606 case BC_INST_PRINT_POP:
6607 case BC_INST_PRINT_STR:
6608 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006609 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 break;
6611 }
6612
6613 case BC_INST_STR:
6614 {
6615 r.t = BC_RESULT_STR;
6616 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006617 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006618 break;
6619 }
6620
6621 case BC_INST_POWER:
6622 case BC_INST_MULTIPLY:
6623 case BC_INST_DIVIDE:
6624 case BC_INST_MODULUS:
6625 case BC_INST_PLUS:
6626 case BC_INST_MINUS:
6627 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006628 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006629 break;
6630 }
6631
6632 case BC_INST_BOOL_NOT:
6633 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006634 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006635 if (s) return s;
6636
6637 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006638 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6639 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006640
6641 break;
6642 }
6643
6644 case BC_INST_NEG:
6645 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006646 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006647 break;
6648 }
6649
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006650#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006651 case BC_INST_ASSIGN_POWER:
6652 case BC_INST_ASSIGN_MULTIPLY:
6653 case BC_INST_ASSIGN_DIVIDE:
6654 case BC_INST_ASSIGN_MODULUS:
6655 case BC_INST_ASSIGN_PLUS:
6656 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006657#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006658 case BC_INST_ASSIGN:
6659 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006660 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006661 break;
6662 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006663#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006664 case BC_INST_MODEXP:
6665 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006666 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006667 break;
6668 }
6669
6670 case BC_INST_DIVMOD:
6671 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006672 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006673 break;
6674 }
6675
6676 case BC_INST_EXECUTE:
6677 case BC_INST_EXEC_COND:
6678 {
6679 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006680 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006681 break;
6682 }
6683
6684 case BC_INST_PRINT_STACK:
6685 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006686 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6687 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006688 break;
6689 }
6690
6691 case BC_INST_CLEAR_STACK:
6692 {
Denys Vlasenko7d628012018-12-04 21:46:47 +01006693 bc_vec_pop_all(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006694 break;
6695 }
6696
6697 case BC_INST_STACK_LEN:
6698 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006699 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006700 break;
6701 }
6702
6703 case BC_INST_DUPLICATE:
6704 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006705 if (!BC_PROG_STACK(&G.prog.results, 1))
6706 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006707 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006708 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006709 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006710 break;
6711 }
6712
6713 case BC_INST_SWAP:
6714 {
6715 BcResult *ptr2;
6716
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006717 if (!BC_PROG_STACK(&G.prog.results, 2))
6718 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006719
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006720 ptr = bc_vec_item_rev(&G.prog.results, 0);
6721 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006722 memcpy(&r, ptr, sizeof(BcResult));
6723 memcpy(ptr, ptr2, sizeof(BcResult));
6724 memcpy(ptr2, &r, sizeof(BcResult));
6725
6726 break;
6727 }
6728
6729 case BC_INST_ASCIIFY:
6730 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006731 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006732 break;
6733 }
6734
6735 case BC_INST_PRINT_STREAM:
6736 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006737 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006738 break;
6739 }
6740
6741 case BC_INST_LOAD:
6742 case BC_INST_PUSH_VAR:
6743 {
6744 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006745 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006746 break;
6747 }
6748
6749 case BC_INST_PUSH_TO_VAR:
6750 {
6751 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006752 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006753 free(name);
6754 break;
6755 }
6756
6757 case BC_INST_QUIT:
6758 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006759 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006760 quit();
6761 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006762 break;
6763 }
6764
6765 case BC_INST_NQUIT:
6766 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006767 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006768 break;
6769 }
6770#endif // ENABLE_DC
6771 }
6772
Denys Vlasenkod38af482018-12-04 19:11:02 +01006773 if (s || G_interrupt) {
6774 bc_program_reset();
6775 break;
6776 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006777
6778 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006779 ip = bc_vec_top(&G.prog.stack);
6780 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006781 code = func->code.v;
6782 }
6783
6784 return s;
6785}
6786
Denys Vlasenko00d77792018-11-30 23:13:42 +01006787static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006788{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006789 printf("%s "BB_VER"\n"
6790 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006791 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006792 "This is free software with ABSOLUTELY NO WARRANTY\n"
6793 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006794}
6795
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006796#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006797static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006798{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006799 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6800
Gavin Howard01055ba2018-11-03 11:00:21 -06006801 BcVec v;
6802 char *env_args = getenv(bc_args_env_name), *buf;
6803
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006804 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006805
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006806 G.env_args = xstrdup(env_args);
6807 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006808
6809 bc_vec_init(&v, sizeof(char *), NULL);
6810 bc_vec_push(&v, &bc_args_env_name);
6811
6812 while (*buf != 0) {
6813 if (!isspace(*buf)) {
6814 bc_vec_push(&v, &buf);
6815 while (*buf != 0 && !isspace(*buf)) ++buf;
6816 if (*buf != 0) (*(buf++)) = '\0';
6817 }
6818 else
6819 ++buf;
6820 }
6821
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006822 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006823
6824 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006825}
6826#endif // ENABLE_BC
6827
6828static size_t bc_vm_envLen(const char *var)
6829{
6830 char *lenv = getenv(var);
6831 size_t i, len = BC_NUM_PRINT_WIDTH;
6832 int num;
6833
6834 if (!lenv) return len;
6835
6836 len = strlen(lenv);
6837
6838 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6839 if (num) {
6840 len = (size_t) atoi(lenv) - 1;
6841 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6842 }
6843 else
6844 len = BC_NUM_PRINT_WIDTH;
6845
6846 return len;
6847}
6848
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006849static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006850{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006851 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006852
Gavin Howard01055ba2018-11-03 11:00:21 -06006853 if (s) return s;
6854
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006855 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006856 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006857 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006858 }
6859
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006860 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006861 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006862 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006863 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006864 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006865 }
6866
6867 return s;
6868}
6869
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006870static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006871{
6872 BcStatus s;
6873 char *data;
6874 BcFunc *main_func;
6875 BcInstPtr *ip;
6876
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006877 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006878 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01006879 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006880
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006881 bc_lex_file(&G.prs.l, file);
6882 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006883 if (s) goto err;
6884
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006885 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6886 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006887
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006888 if (main_func->code.len < ip->idx)
6889 s = bc_error("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006890
6891err:
6892 free(data);
6893 return s;
6894}
6895
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006896static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006897{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006898 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006899 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006900 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006901 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006902
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006903 G.prog.file = bc_program_stdin_name;
6904 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006905
Denys Vlasenko7d628012018-12-04 21:46:47 +01006906 bc_char_vec_init(&buffer);
6907 bc_char_vec_init(&buf);
Gavin Howard01055ba2018-11-03 11:00:21 -06006908 bc_vec_pushByte(&buffer, '\0');
6909
6910 // This loop is complex because the vm tries not to send any lines that end
6911 // with a backslash to the parser. The reason for that is because the parser
6912 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6913 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006914 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006915
6916 char *string = buf.v;
6917
6918 len = buf.len - 1;
6919
6920 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006921 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006922 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006923 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006924 str += 1;
6925 }
6926 else if (len > 1 || comment) {
6927
6928 for (i = 0; i < len; ++i) {
6929
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006930 bool notend = len > i + 1;
6931 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006932
6933 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006934 if (G.sbgn == G.send)
6935 str ^= c == G.sbgn;
6936 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006937 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006938 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006939 str += 1;
6940 }
6941
6942 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6943 comment = true;
6944 break;
6945 }
6946 else if (c == '*' && notend && comment && string[i + 1] == '/')
6947 comment = false;
6948 }
6949
6950 if (str || comment || string[len - 2] == '\\') {
6951 bc_vec_concat(&buffer, buf.v);
6952 continue;
6953 }
6954 }
6955
6956 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006957 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006958 if (s) {
6959 fflush_and_check();
6960 fputs("ready for more input\n", stderr);
6961 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006962
Denys Vlasenko7d628012018-12-04 21:46:47 +01006963 bc_vec_pop_all(&buffer);
Gavin Howard01055ba2018-11-03 11:00:21 -06006964 }
6965
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006966 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006967 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006968 }
6969 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006970 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006971 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006972
Gavin Howard01055ba2018-11-03 11:00:21 -06006973 bc_vec_free(&buf);
6974 bc_vec_free(&buffer);
6975 return s;
6976}
6977
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006978static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006979{
6980 BcStatus s = BC_STATUS_SUCCESS;
6981 size_t i;
6982
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006983#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01006984 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006985
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006986 bc_lex_file(&G.prs.l, bc_lib_name);
6987 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06006988
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006989 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6990 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006991
6992 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006993 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06006994 if (s) return s;
6995 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006996#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006997
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006998 for (i = 0; !s && i < G.files.len; ++i)
6999 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007000 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007001 fflush_and_check();
7002 fputs("ready for more input\n", stderr);
7003 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007004
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007005 if (IS_BC || !G.files.len)
7006 s = bc_vm_stdin();
7007 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7008 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007009
Denys Vlasenko00d77792018-11-30 23:13:42 +01007010 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007011}
7012
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007013#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007014static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007015{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007016 bc_num_free(&G.prog.ib);
7017 bc_num_free(&G.prog.ob);
7018 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007019# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007020 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007021# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007022 bc_vec_free(&G.prog.fns);
7023 bc_vec_free(&G.prog.fn_map);
7024 bc_vec_free(&G.prog.vars);
7025 bc_vec_free(&G.prog.var_map);
7026 bc_vec_free(&G.prog.arrs);
7027 bc_vec_free(&G.prog.arr_map);
7028 bc_vec_free(&G.prog.strs);
7029 bc_vec_free(&G.prog.consts);
7030 bc_vec_free(&G.prog.results);
7031 bc_vec_free(&G.prog.stack);
7032 bc_num_free(&G.prog.last);
7033 bc_num_free(&G.prog.zero);
7034 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007035}
7036
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007037static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007038{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007039 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007040 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007041 bc_parse_free(&G.prs);
7042 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007043}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007044#endif
7045
7046static void bc_program_init(size_t line_len)
7047{
7048 size_t idx;
7049 BcInstPtr ip;
7050
7051 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7052 memset(&ip, 0, sizeof(BcInstPtr));
7053
7054 /* G.prog.nchars = G.prog.scale = 0; - already is */
7055 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007056
7057 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7058 bc_num_ten(&G.prog.ib);
7059 G.prog.ib_t = 10;
7060
7061 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7062 bc_num_ten(&G.prog.ob);
7063 G.prog.ob_t = 10;
7064
7065 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7066 bc_num_ten(&G.prog.hexb);
7067 G.prog.hexb.num[0] = 6;
7068
7069#if ENABLE_DC
7070 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7071 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7072#endif
7073
7074 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7075 bc_num_zero(&G.prog.last);
7076
7077 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7078 bc_num_zero(&G.prog.zero);
7079
7080 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7081 bc_num_one(&G.prog.one);
7082
7083 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007084 bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007085
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007086 bc_program_addFunc(xstrdup("(main)"), &idx);
7087 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007088
7089 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007090 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007091
7092 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007093 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007094
7095 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7096 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7097 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7098 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7099 bc_vec_push(&G.prog.stack, &ip);
7100}
Gavin Howard01055ba2018-11-03 11:00:21 -06007101
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007102static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007103{
Gavin Howard01055ba2018-11-03 11:00:21 -06007104 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007105
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007106 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007107
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007108 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007109 bc_vm_envArgs();
7110 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007111
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007112 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007113 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007114 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007115 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007116 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007117 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007118}
7119
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007120static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007121 const char *env_len)
7122{
7123 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007124
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007125 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007126 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007127
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007128 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007129
Denys Vlasenkod38af482018-12-04 19:11:02 +01007130 if (G.ttyin) {
7131#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007132 // With SA_RESTART, most system calls will restart
7133 // (IOW: they won't fail with EINTR).
7134 // In particular, this means ^C won't cause
7135 // stdout to get into "error state" if SIGINT hits
7136 // within write() syscall.
7137 // The downside is that ^C while line input is taken
7138 // will only be handled after [Enter] since read()
7139 // from stdin is not interrupted by ^C either,
7140 // it restarts, thus fgetc() does not return on ^C.
7141 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7142
7143 // Without SA_RESTART, this exhibits a bug:
7144 // "while (1) print 1" and try ^C-ing it.
7145 // Intermittently, instead of returning to input line,
7146 // you'll get "output error: Interrupted system call"
7147 // and exit.
7148 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007149#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007150 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007151 bc_vm_info();
7152 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007153 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007154
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007155#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007156 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007157#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007158 return st;
7159}
7160
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007161#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007162int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7163int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007164{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007165 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007166 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007167
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007168 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007169}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007170#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007171
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007172#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007173int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7174int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007175{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007176 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007177 G.sbgn = '[';
7178 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007179
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007180 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007181}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007182#endif