blob: bc5501d91d4dae8f3917717c3ddefa9c63a6a9db [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
192#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
193
Gavin Howard01055ba2018-11-03 11:00:21 -0600194typedef signed char BcDig;
195
196typedef struct BcNum {
197 BcDig *restrict num;
198 size_t rdx;
199 size_t len;
200 size_t cap;
201 bool neg;
202} BcNum;
203
204#define BC_NUM_MIN_BASE ((unsigned long) 2)
205#define BC_NUM_MAX_IBASE ((unsigned long) 16)
206#define BC_NUM_DEF_SIZE (16)
207#define BC_NUM_PRINT_WIDTH (69)
208
209#define BC_NUM_KARATSUBA_LEN (32)
210
211#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
212#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
213#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
214#define BC_NUM_AREQ(a, b) \
215 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
216#define BC_NUM_MREQ(a, b, scale) \
217 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
218
219typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
220typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
221
222static void bc_num_init(BcNum *n, size_t req);
223static void bc_num_expand(BcNum *n, size_t req);
224static void bc_num_copy(BcNum *d, BcNum *s);
225static void bc_num_free(void *num);
226
227static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100228static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600229
230static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
235static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
236static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
237static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 size_t scale);
239
240typedef enum BcInst {
241
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100242#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600243 BC_INST_INC_PRE,
244 BC_INST_DEC_PRE,
245 BC_INST_INC_POST,
246 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100247#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600248
249 BC_INST_NEG,
250
251 BC_INST_POWER,
252 BC_INST_MULTIPLY,
253 BC_INST_DIVIDE,
254 BC_INST_MODULUS,
255 BC_INST_PLUS,
256 BC_INST_MINUS,
257
258 BC_INST_REL_EQ,
259 BC_INST_REL_LE,
260 BC_INST_REL_GE,
261 BC_INST_REL_NE,
262 BC_INST_REL_LT,
263 BC_INST_REL_GT,
264
265 BC_INST_BOOL_NOT,
266 BC_INST_BOOL_OR,
267 BC_INST_BOOL_AND,
268
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100269#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600270 BC_INST_ASSIGN_POWER,
271 BC_INST_ASSIGN_MULTIPLY,
272 BC_INST_ASSIGN_DIVIDE,
273 BC_INST_ASSIGN_MODULUS,
274 BC_INST_ASSIGN_PLUS,
275 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100276#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600277 BC_INST_ASSIGN,
278
279 BC_INST_NUM,
280 BC_INST_VAR,
281 BC_INST_ARRAY_ELEM,
282 BC_INST_ARRAY,
283
284 BC_INST_SCALE_FUNC,
285 BC_INST_IBASE,
286 BC_INST_SCALE,
287 BC_INST_LAST,
288 BC_INST_LENGTH,
289 BC_INST_READ,
290 BC_INST_OBASE,
291 BC_INST_SQRT,
292
293 BC_INST_PRINT,
294 BC_INST_PRINT_POP,
295 BC_INST_STR,
296 BC_INST_PRINT_STR,
297
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100298#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600299 BC_INST_JUMP,
300 BC_INST_JUMP_ZERO,
301
302 BC_INST_CALL,
303
304 BC_INST_RET,
305 BC_INST_RET0,
306
307 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100308#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600309
310 BC_INST_POP,
311 BC_INST_POP_EXEC,
312
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100313#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600314 BC_INST_MODEXP,
315 BC_INST_DIVMOD,
316
317 BC_INST_EXECUTE,
318 BC_INST_EXEC_COND,
319
320 BC_INST_ASCIIFY,
321 BC_INST_PRINT_STREAM,
322
323 BC_INST_PRINT_STACK,
324 BC_INST_CLEAR_STACK,
325 BC_INST_STACK_LEN,
326 BC_INST_DUPLICATE,
327 BC_INST_SWAP,
328
329 BC_INST_LOAD,
330 BC_INST_PUSH_VAR,
331 BC_INST_PUSH_TO_VAR,
332
333 BC_INST_QUIT,
334 BC_INST_NQUIT,
335
336 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100337#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600338
339} BcInst;
340
341typedef struct BcId {
342 char *name;
343 size_t idx;
344} BcId;
345
346typedef struct BcFunc {
347 BcVec code;
348 BcVec labels;
349 size_t nparams;
350 BcVec autos;
351} BcFunc;
352
353typedef enum BcResultType {
354
355 BC_RESULT_TEMP,
356
357 BC_RESULT_VAR,
358 BC_RESULT_ARRAY_ELEM,
359 BC_RESULT_ARRAY,
360
361 BC_RESULT_STR,
362
363 BC_RESULT_IBASE,
364 BC_RESULT_SCALE,
365 BC_RESULT_LAST,
366
367 // These are between to calculate ibase, obase, and last from instructions.
368 BC_RESULT_CONSTANT,
369 BC_RESULT_ONE,
370
371 BC_RESULT_OBASE,
372
373} BcResultType;
374
375typedef union BcResultData {
376 BcNum n;
377 BcVec v;
378 BcId id;
379} BcResultData;
380
381typedef struct BcResult {
382 BcResultType t;
383 BcResultData d;
384} BcResult;
385
386typedef struct BcInstPtr {
387 size_t func;
388 size_t idx;
389 size_t len;
390} BcInstPtr;
391
392static void bc_array_expand(BcVec *a, size_t len);
393static int bc_id_cmp(const void *e1, const void *e2);
394
395// BC_LEX_NEG is not used in lexing; it is only for parsing.
396typedef enum BcLexType {
397
398 BC_LEX_EOF,
399 BC_LEX_INVALID,
400
401 BC_LEX_OP_INC,
402 BC_LEX_OP_DEC,
403
404 BC_LEX_NEG,
405
406 BC_LEX_OP_POWER,
407 BC_LEX_OP_MULTIPLY,
408 BC_LEX_OP_DIVIDE,
409 BC_LEX_OP_MODULUS,
410 BC_LEX_OP_PLUS,
411 BC_LEX_OP_MINUS,
412
413 BC_LEX_OP_REL_EQ,
414 BC_LEX_OP_REL_LE,
415 BC_LEX_OP_REL_GE,
416 BC_LEX_OP_REL_NE,
417 BC_LEX_OP_REL_LT,
418 BC_LEX_OP_REL_GT,
419
420 BC_LEX_OP_BOOL_NOT,
421 BC_LEX_OP_BOOL_OR,
422 BC_LEX_OP_BOOL_AND,
423
424 BC_LEX_OP_ASSIGN_POWER,
425 BC_LEX_OP_ASSIGN_MULTIPLY,
426 BC_LEX_OP_ASSIGN_DIVIDE,
427 BC_LEX_OP_ASSIGN_MODULUS,
428 BC_LEX_OP_ASSIGN_PLUS,
429 BC_LEX_OP_ASSIGN_MINUS,
430 BC_LEX_OP_ASSIGN,
431
432 BC_LEX_NLINE,
433 BC_LEX_WHITESPACE,
434
435 BC_LEX_LPAREN,
436 BC_LEX_RPAREN,
437
438 BC_LEX_LBRACKET,
439 BC_LEX_COMMA,
440 BC_LEX_RBRACKET,
441
442 BC_LEX_LBRACE,
443 BC_LEX_SCOLON,
444 BC_LEX_RBRACE,
445
446 BC_LEX_STR,
447 BC_LEX_NAME,
448 BC_LEX_NUMBER,
449
450 BC_LEX_KEY_AUTO,
451 BC_LEX_KEY_BREAK,
452 BC_LEX_KEY_CONTINUE,
453 BC_LEX_KEY_DEFINE,
454 BC_LEX_KEY_ELSE,
455 BC_LEX_KEY_FOR,
456 BC_LEX_KEY_HALT,
457 BC_LEX_KEY_IBASE,
458 BC_LEX_KEY_IF,
459 BC_LEX_KEY_LAST,
460 BC_LEX_KEY_LENGTH,
461 BC_LEX_KEY_LIMITS,
462 BC_LEX_KEY_OBASE,
463 BC_LEX_KEY_PRINT,
464 BC_LEX_KEY_QUIT,
465 BC_LEX_KEY_READ,
466 BC_LEX_KEY_RETURN,
467 BC_LEX_KEY_SCALE,
468 BC_LEX_KEY_SQRT,
469 BC_LEX_KEY_WHILE,
470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100471#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_EQ_NO_REG,
473 BC_LEX_OP_MODEXP,
474 BC_LEX_OP_DIVMOD,
475
476 BC_LEX_COLON,
477 BC_LEX_ELSE,
478 BC_LEX_EXECUTE,
479 BC_LEX_PRINT_STACK,
480 BC_LEX_CLEAR_STACK,
481 BC_LEX_STACK_LEVEL,
482 BC_LEX_DUPLICATE,
483 BC_LEX_SWAP,
484 BC_LEX_POP,
485
486 BC_LEX_ASCIIFY,
487 BC_LEX_PRINT_STREAM,
488
489 BC_LEX_STORE_IBASE,
490 BC_LEX_STORE_SCALE,
491 BC_LEX_LOAD,
492 BC_LEX_LOAD_POP,
493 BC_LEX_STORE_PUSH,
494 BC_LEX_STORE_OBASE,
495 BC_LEX_PRINT_POP,
496 BC_LEX_NQUIT,
497 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100498#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600499
500} BcLexType;
501
502struct BcLex;
503typedef BcStatus (*BcLexNext)(struct BcLex *);
504
505typedef struct BcLex {
506
507 const char *buf;
508 size_t i;
509 size_t line;
510 const char *f;
511 size_t len;
512 bool newline;
513
514 struct {
515 BcLexType t;
516 BcLexType last;
517 BcVec v;
518 } t;
519
520 BcLexNext next;
521
522} BcLex;
523
524#define BC_PARSE_STREND ((char) UCHAR_MAX)
525
526#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
527#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100528 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600529
530#define BC_PARSE_REL (1 << 0)
531#define BC_PARSE_PRINT (1 << 1)
532#define BC_PARSE_NOCALL (1 << 2)
533#define BC_PARSE_NOREAD (1 << 3)
534#define BC_PARSE_ARRAY (1 << 4)
535
536#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
537#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
538
539#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
540#define BC_PARSE_FUNC_INNER(parse) \
541 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
542
543#define BC_PARSE_FLAG_FUNC (1 << 1)
544#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
545
546#define BC_PARSE_FLAG_BODY (1 << 2)
547#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
548
549#define BC_PARSE_FLAG_LOOP (1 << 3)
550#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
551
552#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
553#define BC_PARSE_LOOP_INNER(parse) \
554 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
555
556#define BC_PARSE_FLAG_IF (1 << 5)
557#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
558
559#define BC_PARSE_FLAG_ELSE (1 << 6)
560#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
561
562#define BC_PARSE_FLAG_IF_END (1 << 7)
563#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
564
565#define BC_PARSE_CAN_EXEC(parse) \
566 (!(BC_PARSE_TOP_FLAG(parse) & \
567 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
568 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
569 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
570
571typedef struct BcOp {
572 char prec;
573 bool left;
574} BcOp;
575
576typedef struct BcParseNext {
577 uint32_t len;
578 BcLexType tokens[4];
579} BcParseNext;
580
581#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
582#define BC_PARSE_NEXT(a, ...) \
583 { \
584 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
585 }
586
587struct BcParse;
588
589struct BcProgram;
590
Gavin Howard01055ba2018-11-03 11:00:21 -0600591typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600592
593typedef struct BcParse {
594
595 BcParseParse parse;
596
597 BcLex l;
598
599 BcVec flags;
600
601 BcVec exits;
602 BcVec conds;
603
604 BcVec ops;
605
Gavin Howard01055ba2018-11-03 11:00:21 -0600606 BcFunc *func;
607 size_t fidx;
608
609 size_t nbraces;
610 bool auto_part;
611
612} BcParse;
613
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100614#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600615
Gavin Howard01055ba2018-11-03 11:00:21 -0600616typedef struct BcLexKeyword {
617 const char name[9];
618 const char len;
619 const bool posix;
620} BcLexKeyword;
621
622#define BC_LEX_KW_ENTRY(a, b, c) \
623 { \
624 .name = a, .len = (b), .posix = (c) \
625 }
626
627static BcStatus bc_lex_token(BcLex *l);
628
629#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
630#define BC_PARSE_LEAF(p, rparen) \
631 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
632 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
633
634// We can calculate the conversion between tokens and exprs by subtracting the
635// position of the first operator in the lex enum and adding the position of the
636// first in the expr enum. Note: This only works for binary operators.
637#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
638
Gavin Howard01055ba2018-11-03 11:00:21 -0600639static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
640
Denys Vlasenko00d77792018-11-30 23:13:42 +0100641#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600642
Denys Vlasenko00d77792018-11-30 23:13:42 +0100643#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600644
645#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
646
Gavin Howard01055ba2018-11-03 11:00:21 -0600647static BcStatus dc_lex_token(BcLex *l);
648
Gavin Howard01055ba2018-11-03 11:00:21 -0600649static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
650
651#endif // ENABLE_DC
652
653typedef struct BcProgram {
654
655 size_t len;
656 size_t scale;
657
658 BcNum ib;
659 size_t ib_t;
660 BcNum ob;
661 size_t ob_t;
662
663 BcNum hexb;
664
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100665#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600666 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100667#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600668
669 BcVec results;
670 BcVec stack;
671
672 BcVec fns;
673 BcVec fn_map;
674
675 BcVec vars;
676 BcVec var_map;
677
678 BcVec arrs;
679 BcVec arr_map;
680
681 BcVec strs;
682 BcVec consts;
683
684 const char *file;
685
686 BcNum last;
687 BcNum zero;
688 BcNum one;
689
690 size_t nchars;
691
Gavin Howard01055ba2018-11-03 11:00:21 -0600692} BcProgram;
693
694#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
695
696#define BC_PROG_MAIN (0)
697#define BC_PROG_READ (1)
698
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100699#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600700#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100701#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600702
703#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
704#define BC_PROG_NUM(r, n) \
705 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
706
707typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
708
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100709static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100710static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600711
712#define BC_FLAG_X (1 << 0)
713#define BC_FLAG_W (1 << 1)
714#define BC_FLAG_V (1 << 2)
715#define BC_FLAG_S (1 << 3)
716#define BC_FLAG_Q (1 << 4)
717#define BC_FLAG_L (1 << 5)
718#define BC_FLAG_I (1 << 6)
719
720#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
721#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
722
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100723#define BC_MAX_OBASE ((unsigned) 999)
724#define BC_MAX_DIM ((unsigned) INT_MAX)
725#define BC_MAX_SCALE ((unsigned) UINT_MAX)
726#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
727#define BC_MAX_NAME BC_MAX_STRING
728#define BC_MAX_NUM BC_MAX_STRING
729#define BC_MAX_EXP ((unsigned long) LONG_MAX)
730#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600731
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100732struct globals {
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
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100739 unsigned flags;
Gavin Howard01055ba2018-11-03 11:00:21 -0600740 BcVec files;
741
742 char *env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -0600743
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100744 smallint tty;
745 smallint ttyin;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100746 smallint eof;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100747} FIX_ALIASING;
748#define G (*ptr_to_globals)
749#define INIT_G() do { \
750 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
751} while (0)
752#define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
753#define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
754#define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100755#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600756
Gavin Howard01055ba2018-11-03 11:00:21 -0600757
Denys Vlasenko00d77792018-11-30 23:13:42 +0100758#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
759
Denys Vlasenko00d77792018-11-30 23:13:42 +0100760static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600761
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100762#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600763static const BcLexKeyword bc_lex_kws[20] = {
764 BC_LEX_KW_ENTRY("auto", 4, true),
765 BC_LEX_KW_ENTRY("break", 5, true),
766 BC_LEX_KW_ENTRY("continue", 8, false),
767 BC_LEX_KW_ENTRY("define", 6, true),
768 BC_LEX_KW_ENTRY("else", 4, false),
769 BC_LEX_KW_ENTRY("for", 3, true),
770 BC_LEX_KW_ENTRY("halt", 4, false),
771 BC_LEX_KW_ENTRY("ibase", 5, true),
772 BC_LEX_KW_ENTRY("if", 2, true),
773 BC_LEX_KW_ENTRY("last", 4, false),
774 BC_LEX_KW_ENTRY("length", 6, true),
775 BC_LEX_KW_ENTRY("limits", 6, false),
776 BC_LEX_KW_ENTRY("obase", 5, true),
777 BC_LEX_KW_ENTRY("print", 5, false),
778 BC_LEX_KW_ENTRY("quit", 4, true),
779 BC_LEX_KW_ENTRY("read", 4, false),
780 BC_LEX_KW_ENTRY("return", 6, true),
781 BC_LEX_KW_ENTRY("scale", 5, true),
782 BC_LEX_KW_ENTRY("sqrt", 4, true),
783 BC_LEX_KW_ENTRY("while", 5, true),
784};
785
786// This is an array that corresponds to token types. An entry is
787// true if the token is valid in an expression, false otherwise.
788static const bool bc_parse_exprs[] = {
789 false, false, true, true, true, true, true, true, true, true, true, true,
790 true, true, true, true, true, true, true, true, true, true, true, true,
791 true, true, true, false, false, true, true, false, false, false, false,
792 false, false, false, true, true, false, false, false, false, false, false,
793 false, true, false, true, true, true, true, false, false, true, false, true,
794 true, false,
795};
796
797// This is an array of data for operators that correspond to token types.
798static const BcOp bc_parse_ops[] = {
799 { 0, false }, { 0, false },
800 { 1, false },
801 { 2, false },
802 { 3, true }, { 3, true }, { 3, true },
803 { 4, true }, { 4, true },
804 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
805 { 1, false },
806 { 7, true }, { 7, true },
807 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
808 { 5, false }, { 5, false },
809};
810
811// These identify what tokens can come after expressions in certain cases.
812static const BcParseNext bc_parse_next_expr =
813 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
814static const BcParseNext bc_parse_next_param =
815 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
816static const BcParseNext bc_parse_next_print =
817 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
818static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
819static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
820static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
821static const BcParseNext bc_parse_next_read =
822 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
823#endif // ENABLE_BC
824
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100825#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600826static const BcLexType dc_lex_regs[] = {
827 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
828 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
829 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
830 BC_LEX_STORE_PUSH,
831};
832
833static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
834
835static const BcLexType dc_lex_tokens[] = {
836 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
837 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
838 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
839 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
840 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
843 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
844 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
845 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
846 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
847 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
848 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
849 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
850 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
852 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
853 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
854 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
855 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
856 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
857 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
858 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
859 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
860 BC_LEX_INVALID
861};
862
863static const BcInst dc_parse_insts[] = {
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
865 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
866 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
871 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
874 BC_INST_INVALID, BC_INST_INVALID,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
876 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
878 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
879 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
880 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
881 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
883 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
884 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
885 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
886 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
887};
888#endif // ENABLE_DC
889
Gavin Howard01055ba2018-11-03 11:00:21 -0600890static const BcNumBinaryOp bc_program_ops[] = {
891 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
892};
893
894static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600895
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100896#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600897static const char *bc_lib_name = "gen/lib.bc";
898
899static const char bc_lib[] = {
900 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
901 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
902 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
903 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,
904 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
905 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
906 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,
907 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
908 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
909 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,
910 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
911 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
912 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
913 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
914 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
915 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
916 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
917 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
918 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
919 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
920 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
921 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
922 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
923 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,
924 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
925 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,
926 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
927 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
928 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
929 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
930 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
931 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,
932 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
933 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
934 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
935 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
936 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,
937 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
938 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
939 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
940 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
941 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
942 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
943 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
944 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
945 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
946 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
947 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,
948 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,
949 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
950 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,
951 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,
952 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,
953 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
954 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
955 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,
956 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,
957 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,
958 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
959 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,
960 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
961 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
962 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
963 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,
964 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
965 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
966 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
967 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
968 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
969 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
970 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
971 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
972 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
973 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
974 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
975 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
976 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
977 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
978 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
979 117,114,110,40,97,42,114,47,49,41,10,125,10,0
980};
981#endif // ENABLE_BC
982
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100983static void fflush_and_check(void)
984{
985 fflush_all();
986 if (ferror(stdout) || ferror(stderr))
987 bb_perror_msg_and_die("output error");
988}
989
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100990static void quit(void) NORETURN;
991static void quit(void)
992{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100993 if (ferror(stdin))
994 bb_perror_msg_and_die("input error");
995 fflush_and_check();
996 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100997}
998
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100999static int bc_error(const char *fmt, ...)
1000{
1001 va_list p;
1002
1003 va_start(p, fmt);
1004 bb_verror_msg(fmt, p, NULL);
1005 va_end(p);
1006 if (!G.ttyin)
1007 exit(1);
1008 return BC_STATUS_FAILURE;
1009}
1010
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001011static int bc_posix_error(const char *fmt, ...)
1012{
1013 va_list p;
1014
1015 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W)))
1016 return BC_STATUS_SUCCESS;
1017
1018 va_start(p, fmt);
1019 bb_verror_msg(fmt, p, NULL);
1020 va_end(p);
1021
1022 // Do we treat non-POSIX constructs as errors?
1023 if (!(G.flags & BC_FLAG_S))
1024 return BC_STATUS_SUCCESS; // no, it's a warning
1025 if (!G.ttyin)
1026 exit(1);
1027 return BC_STATUS_FAILURE;
1028}
1029
Gavin Howard01055ba2018-11-03 11:00:21 -06001030static void bc_vec_grow(BcVec *v, size_t n)
1031{
1032 size_t cap = v->cap * 2;
1033 while (cap < v->len + n) cap *= 2;
1034 v->v = xrealloc(v->v, v->size * cap);
1035 v->cap = cap;
1036}
1037
1038static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1039{
1040 v->size = esize;
1041 v->cap = BC_VEC_START_CAP;
1042 v->len = 0;
1043 v->dtor = dtor;
1044 v->v = xmalloc(esize * BC_VEC_START_CAP);
1045}
1046
1047static 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
1065static void bc_vec_push(BcVec *v, const void *data)
1066{
1067 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1068 memmove(v->v + (v->size * v->len), data, v->size);
1069 v->len += 1;
1070}
1071
1072static void bc_vec_pushByte(BcVec *v, char data)
1073{
1074 bc_vec_push(v, &data);
1075}
1076
1077static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1078{
1079 if (idx == v->len)
1080 bc_vec_push(v, data);
1081 else {
1082
1083 char *ptr;
1084
1085 if (v->len == v->cap) bc_vec_grow(v, 1);
1086
1087 ptr = v->v + v->size * idx;
1088
1089 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1090 memmove(ptr, data, v->size);
1091 }
1092}
1093
1094static void bc_vec_string(BcVec *v, size_t len, const char *str)
1095{
1096 bc_vec_npop(v, v->len);
1097 bc_vec_expand(v, len + 1);
1098 memcpy(v->v, str, len);
1099 v->len = len;
1100
1101 bc_vec_pushByte(v, '\0');
1102}
1103
1104static void bc_vec_concat(BcVec *v, const char *str)
1105{
1106 size_t len;
1107
1108 if (v->len == 0) bc_vec_pushByte(v, '\0');
1109
1110 len = v->len + strlen(str);
1111
1112 if (v->cap < len) bc_vec_grow(v, len - v->len);
1113 strcat(v->v, str);
1114
1115 v->len = len;
1116}
1117
1118static void *bc_vec_item(const BcVec *v, size_t idx)
1119{
1120 return v->v + v->size * idx;
1121}
1122
1123static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1124{
1125 return v->v + v->size * (v->len - idx - 1);
1126}
1127
1128static void bc_vec_free(void *vec)
1129{
1130 BcVec *v = (BcVec *) vec;
1131 bc_vec_npop(v, v->len);
1132 free(v->v);
1133}
1134
1135static size_t bc_map_find(const BcVec *v, const void *ptr)
1136{
1137 size_t low = 0, high = v->len;
1138
1139 while (low < high) {
1140
1141 size_t mid = (low + high) / 2;
1142 BcId *id = bc_vec_item(v, mid);
1143 int result = bc_id_cmp(ptr, id);
1144
1145 if (result == 0)
1146 return mid;
1147 else if (result < 0)
1148 high = mid;
1149 else
1150 low = mid + 1;
1151 }
1152
1153 return low;
1154}
1155
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001156static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001157{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001158 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001159
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001160 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001161 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001162 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1163 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001164 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001165 bc_vec_pushAt(v, ptr, n);
1166 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001167}
1168
1169static size_t bc_map_index(const BcVec *v, const void *ptr)
1170{
1171 size_t i = bc_map_find(v, ptr);
1172 if (i >= v->len) return BC_VEC_INVALID_IDX;
1173 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1174}
1175
1176static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1177{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001178 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001179
Denys Vlasenko00d77792018-11-30 23:13:42 +01001180 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001181 int i;
1182 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001183
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001184 bad_chars = 0;
1185 bc_vec_npop(vec, vec->len);
1186
1187 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001188#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001189 if (bb_got_signal) { // ^C was pressed
1190 intr:
1191 bb_got_signal = 0; // resets G_interrupt to zero
1192 fputs(IS_BC
1193 ? "\ninterrupt (type \"quit\" to exit)\n"
1194 : "\ninterrupt (type \"q\" to exit)\n"
1195 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001196 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001197#endif
1198 if (G.ttyin && !G_posix)
1199 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001200
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001201#if ENABLE_FEATURE_BC_SIGNALS
1202 errno = 0;
1203#endif
1204 do {
1205 i = fgetc(stdin);
1206 if (i == EOF) {
1207#if ENABLE_FEATURE_BC_SIGNALS
1208 // Both conditions appear simultaneously, check both just in case
1209 if (errno == EINTR || bb_got_signal) {
1210 // ^C was pressed
1211 clearerr(stdin);
1212 goto intr;
1213 }
1214#endif
1215 if (ferror(stdin))
1216 quit(); // this emits error message
1217 G.eof = 1;
1218 // Note: EOF does not append '\n', therefore:
1219 // printf 'print 123\n' | bc - works
1220 // printf 'print 123' | bc - fails (syntax error)
1221 break;
1222 }
1223
1224 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1225 || i > 0x7e
1226 ) {
1227 // Bad chars on this line, ignore entire line
1228 bc_error("illegal character 0x%02x", i);
1229 bad_chars = 1;
1230 }
1231 c = (char) i;
1232 bc_vec_push(vec, &c);
1233 } while (i != '\n');
1234 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001235
1236 bc_vec_pushByte(vec, '\0');
1237
1238 return BC_STATUS_SUCCESS;
1239}
1240
Denys Vlasenkodf515392018-12-02 19:27:48 +01001241static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001242{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001243 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001244 size_t size = ((size_t) -1);
1245 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001246
Denys Vlasenkodf515392018-12-02 19:27:48 +01001247 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001248
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001249 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001250 char c = buf[i];
1251 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1252 || c > 0x7e
1253 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001254 free(buf);
1255 buf = NULL;
1256 break;
1257 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001258 }
1259
Denys Vlasenkodf515392018-12-02 19:27:48 +01001260 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001261}
1262
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001263static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001264{
Gavin Howard01055ba2018-11-03 11:00:21 -06001265 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001266
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001267 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001268#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001269 G.flags = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001270 "extended-register\0" No_argument "x"
1271 "warn\0" No_argument "w"
1272 "version\0" No_argument "v"
1273 "standard\0" No_argument "s"
1274 "quiet\0" No_argument "q"
1275 "mathlib\0" No_argument "l"
1276 "interactive\0" No_argument "i"
1277 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001278#else
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001279 G.flags = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001280#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001281
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001282 if (G.flags & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001283 // should not be necessary, getopt32() handles this??
1284 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001285
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001286 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001287}
1288
1289static void bc_num_setToZero(BcNum *n, size_t scale)
1290{
1291 n->len = 0;
1292 n->neg = false;
1293 n->rdx = scale;
1294}
1295
1296static void bc_num_zero(BcNum *n)
1297{
1298 bc_num_setToZero(n, 0);
1299}
1300
1301static void bc_num_one(BcNum *n)
1302{
1303 bc_num_setToZero(n, 0);
1304 n->len = 1;
1305 n->num[0] = 1;
1306}
1307
1308static void bc_num_ten(BcNum *n)
1309{
1310 bc_num_setToZero(n, 0);
1311 n->len = 2;
1312 n->num[0] = 0;
1313 n->num[1] = 1;
1314}
1315
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001316static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001317 size_t len)
1318{
1319 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001320 for (i = 0; i < len; ++i) {
1321 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001322 a[i + j++] += 10;
1323 a[i + j] -= 1;
1324 }
1325 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001326}
1327
1328static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1329{
1330 size_t i;
1331 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001332 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001333 return BC_NUM_NEG(i + 1, c < 0);
1334}
1335
1336static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1337{
1338 size_t i, min, a_int, b_int, diff;
1339 BcDig *max_num, *min_num;
1340 bool a_max, neg = false;
1341 ssize_t cmp;
1342
1343 if (a == b) return 0;
1344 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1345 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1346 if (a->neg) {
1347 if (b->neg)
1348 neg = true;
1349 else
1350 return -1;
1351 }
1352 else if (b->neg)
1353 return 1;
1354
1355 a_int = BC_NUM_INT(a);
1356 b_int = BC_NUM_INT(b);
1357 a_int -= b_int;
1358 a_max = (a->rdx > b->rdx);
1359
1360 if (a_int != 0) return (ssize_t) a_int;
1361
1362 if (a_max) {
1363 min = b->rdx;
1364 diff = a->rdx - b->rdx;
1365 max_num = a->num + diff;
1366 min_num = b->num;
1367 }
1368 else {
1369 min = a->rdx;
1370 diff = b->rdx - a->rdx;
1371 max_num = b->num + diff;
1372 min_num = a->num;
1373 }
1374
1375 cmp = bc_num_compare(max_num, min_num, b_int + min);
1376 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1377
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001378 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001379 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1380 }
1381
1382 return 0;
1383}
1384
1385static void bc_num_truncate(BcNum *n, size_t places)
1386{
1387 if (places == 0) return;
1388
1389 n->rdx -= places;
1390
1391 if (n->len != 0) {
1392 n->len -= places;
1393 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1394 }
1395}
1396
1397static void bc_num_extend(BcNum *n, size_t places)
1398{
1399 size_t len = n->len + places;
1400
1401 if (places != 0) {
1402
1403 if (n->cap < len) bc_num_expand(n, len);
1404
1405 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1406 memset(n->num, 0, sizeof(BcDig) * places);
1407
1408 n->len += places;
1409 n->rdx += places;
1410 }
1411}
1412
1413static void bc_num_clean(BcNum *n)
1414{
1415 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1416 if (n->len == 0)
1417 n->neg = false;
1418 else if (n->len < n->rdx)
1419 n->len = n->rdx;
1420}
1421
1422static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1423{
1424 if (n->rdx < scale)
1425 bc_num_extend(n, scale - n->rdx);
1426 else
1427 bc_num_truncate(n, n->rdx - scale);
1428
1429 bc_num_clean(n);
1430 if (n->len != 0) n->neg = !neg1 != !neg2;
1431}
1432
1433static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1434 BcNum *restrict b)
1435{
1436 if (idx < n->len) {
1437
1438 b->len = n->len - idx;
1439 a->len = idx;
1440 a->rdx = b->rdx = 0;
1441
1442 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1443 memcpy(a->num, n->num, idx * sizeof(BcDig));
1444 }
1445 else {
1446 bc_num_zero(b);
1447 bc_num_copy(a, n);
1448 }
1449
1450 bc_num_clean(a);
1451 bc_num_clean(b);
1452}
1453
1454static BcStatus bc_num_shift(BcNum *n, size_t places)
1455{
1456 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001457 if (places + n->len > BC_MAX_NUM)
1458 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001459
1460 if (n->rdx >= places)
1461 n->rdx -= places;
1462 else {
1463 bc_num_extend(n, places - n->rdx);
1464 n->rdx = 0;
1465 }
1466
1467 bc_num_clean(n);
1468
1469 return BC_STATUS_SUCCESS;
1470}
1471
1472static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1473{
1474 BcNum one;
1475 BcDig num[2];
1476
1477 one.cap = 2;
1478 one.num = num;
1479 bc_num_one(&one);
1480
1481 return bc_num_div(&one, a, b, scale);
1482}
1483
1484static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1485{
1486 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1487 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1488 int carry, in;
1489
1490 // Because this function doesn't need to use scale (per the bc spec),
1491 // I am hijacking it to say whether it's doing an add or a subtract.
1492
1493 if (a->len == 0) {
1494 bc_num_copy(c, b);
1495 if (sub && c->len) c->neg = !c->neg;
1496 return BC_STATUS_SUCCESS;
1497 }
1498 else if (b->len == 0) {
1499 bc_num_copy(c, a);
1500 return BC_STATUS_SUCCESS;
1501 }
1502
1503 c->neg = a->neg;
1504 c->rdx = BC_MAX(a->rdx, b->rdx);
1505 min_rdx = BC_MIN(a->rdx, b->rdx);
1506 c->len = 0;
1507
1508 if (a->rdx > b->rdx) {
1509 diff = a->rdx - b->rdx;
1510 ptr = a->num;
1511 ptr_a = a->num + diff;
1512 ptr_b = b->num;
1513 }
1514 else {
1515 diff = b->rdx - a->rdx;
1516 ptr = b->num;
1517 ptr_a = a->num;
1518 ptr_b = b->num + diff;
1519 }
1520
1521 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1522
1523 ptr_c += diff;
1524 a_int = BC_NUM_INT(a);
1525 b_int = BC_NUM_INT(b);
1526
1527 if (a_int > b_int) {
1528 min_int = b_int;
1529 max = a_int;
1530 ptr = ptr_a;
1531 }
1532 else {
1533 min_int = a_int;
1534 max = b_int;
1535 ptr = ptr_b;
1536 }
1537
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001538 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001539 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1540 carry = in / 10;
1541 ptr_c[i] = (BcDig)(in % 10);
1542 }
1543
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001544 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001545 in = ((int) ptr[i]) + carry;
1546 carry = in / 10;
1547 ptr_c[i] = (BcDig)(in % 10);
1548 }
1549
1550 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1551
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001552 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001553}
1554
1555static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1556{
Gavin Howard01055ba2018-11-03 11:00:21 -06001557 ssize_t cmp;
1558 BcNum *minuend, *subtrahend;
1559 size_t start;
1560 bool aneg, bneg, neg;
1561
1562 // Because this function doesn't need to use scale (per the bc spec),
1563 // I am hijacking it to say whether it's doing an add or a subtract.
1564
1565 if (a->len == 0) {
1566 bc_num_copy(c, b);
1567 if (sub && c->len) c->neg = !c->neg;
1568 return BC_STATUS_SUCCESS;
1569 }
1570 else if (b->len == 0) {
1571 bc_num_copy(c, a);
1572 return BC_STATUS_SUCCESS;
1573 }
1574
1575 aneg = a->neg;
1576 bneg = b->neg;
1577 a->neg = b->neg = false;
1578
1579 cmp = bc_num_cmp(a, b);
1580
1581 a->neg = aneg;
1582 b->neg = bneg;
1583
1584 if (cmp == 0) {
1585 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1586 return BC_STATUS_SUCCESS;
1587 }
1588 else if (cmp > 0) {
1589 neg = a->neg;
1590 minuend = a;
1591 subtrahend = b;
1592 }
1593 else {
1594 neg = b->neg;
1595 if (sub) neg = !neg;
1596 minuend = b;
1597 subtrahend = a;
1598 }
1599
1600 bc_num_copy(c, minuend);
1601 c->neg = neg;
1602
1603 if (c->rdx < subtrahend->rdx) {
1604 bc_num_extend(c, subtrahend->rdx - c->rdx);
1605 start = 0;
1606 }
1607 else
1608 start = c->rdx - subtrahend->rdx;
1609
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001610 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001611
1612 bc_num_clean(c);
1613
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001614 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001615}
1616
1617static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1618 BcNum *restrict c)
1619{
1620 BcStatus s;
1621 int carry;
1622 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1623 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1624 bool aone = BC_NUM_ONE(a);
1625
Gavin Howard01055ba2018-11-03 11:00:21 -06001626 if (a->len == 0 || b->len == 0) {
1627 bc_num_zero(c);
1628 return BC_STATUS_SUCCESS;
1629 }
1630 else if (aone || BC_NUM_ONE(b)) {
1631 bc_num_copy(c, aone ? b : a);
1632 return BC_STATUS_SUCCESS;
1633 }
1634
1635 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1636 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1637 {
1638 bc_num_expand(c, a->len + b->len + 1);
1639
1640 memset(c->num, 0, sizeof(BcDig) * c->cap);
1641 c->len = carry = len = 0;
1642
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001643 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001644
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001645 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001646 int in = (int) c->num[i + j];
1647 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1648 carry = in / 10;
1649 c->num[i + j] = (BcDig)(in % 10);
1650 }
1651
1652 c->num[i + j] += (BcDig) carry;
1653 len = BC_MAX(len, i + j + !!carry);
1654 carry = 0;
1655 }
1656
1657 c->len = len;
1658
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001659 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001660 }
1661
1662 bc_num_init(&l1, max);
1663 bc_num_init(&h1, max);
1664 bc_num_init(&l2, max);
1665 bc_num_init(&h2, max);
1666 bc_num_init(&m1, max);
1667 bc_num_init(&m2, max);
1668 bc_num_init(&z0, max);
1669 bc_num_init(&z1, max);
1670 bc_num_init(&z2, max);
1671 bc_num_init(&temp, max + max);
1672
1673 bc_num_split(a, max2, &l1, &h1);
1674 bc_num_split(b, max2, &l2, &h2);
1675
1676 s = bc_num_add(&h1, &l1, &m1, 0);
1677 if (s) goto err;
1678 s = bc_num_add(&h2, &l2, &m2, 0);
1679 if (s) goto err;
1680
1681 s = bc_num_k(&h1, &h2, &z0);
1682 if (s) goto err;
1683 s = bc_num_k(&m1, &m2, &z1);
1684 if (s) goto err;
1685 s = bc_num_k(&l1, &l2, &z2);
1686 if (s) goto err;
1687
1688 s = bc_num_sub(&z1, &z0, &temp, 0);
1689 if (s) goto err;
1690 s = bc_num_sub(&temp, &z2, &z1, 0);
1691 if (s) goto err;
1692
1693 s = bc_num_shift(&z0, max2 * 2);
1694 if (s) goto err;
1695 s = bc_num_shift(&z1, max2);
1696 if (s) goto err;
1697 s = bc_num_add(&z0, &z1, &temp, 0);
1698 if (s) goto err;
1699 s = bc_num_add(&temp, &z2, c, 0);
1700
1701err:
1702 bc_num_free(&temp);
1703 bc_num_free(&z2);
1704 bc_num_free(&z1);
1705 bc_num_free(&z0);
1706 bc_num_free(&m2);
1707 bc_num_free(&m1);
1708 bc_num_free(&h2);
1709 bc_num_free(&l2);
1710 bc_num_free(&h1);
1711 bc_num_free(&l1);
1712 return s;
1713}
1714
1715static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1716{
1717 BcStatus s;
1718 BcNum cpa, cpb;
1719 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1720
1721 scale = BC_MAX(scale, a->rdx);
1722 scale = BC_MAX(scale, b->rdx);
1723 scale = BC_MIN(a->rdx + b->rdx, scale);
1724 maxrdx = BC_MAX(maxrdx, scale);
1725
1726 bc_num_init(&cpa, a->len);
1727 bc_num_init(&cpb, b->len);
1728
1729 bc_num_copy(&cpa, a);
1730 bc_num_copy(&cpb, b);
1731 cpa.neg = cpb.neg = false;
1732
1733 s = bc_num_shift(&cpa, maxrdx);
1734 if (s) goto err;
1735 s = bc_num_shift(&cpb, maxrdx);
1736 if (s) goto err;
1737 s = bc_num_k(&cpa, &cpb, c);
1738 if (s) goto err;
1739
1740 maxrdx += scale;
1741 bc_num_expand(c, c->len + maxrdx);
1742
1743 if (c->len < maxrdx) {
1744 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1745 c->len += maxrdx;
1746 }
1747
1748 c->rdx = maxrdx;
1749 bc_num_retireMul(c, scale, a->neg, b->neg);
1750
1751err:
1752 bc_num_free(&cpb);
1753 bc_num_free(&cpa);
1754 return s;
1755}
1756
1757static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1758{
1759 BcStatus s = BC_STATUS_SUCCESS;
1760 BcDig *n, *p, q;
1761 size_t len, end, i;
1762 BcNum cp;
1763 bool zero = true;
1764
1765 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001766 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001767 else if (a->len == 0) {
1768 bc_num_setToZero(c, scale);
1769 return BC_STATUS_SUCCESS;
1770 }
1771 else if (BC_NUM_ONE(b)) {
1772 bc_num_copy(c, a);
1773 bc_num_retireMul(c, scale, a->neg, b->neg);
1774 return BC_STATUS_SUCCESS;
1775 }
1776
1777 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1778 bc_num_copy(&cp, a);
1779 len = b->len;
1780
1781 if (len > cp.len) {
1782 bc_num_expand(&cp, len + 2);
1783 bc_num_extend(&cp, len - cp.len);
1784 }
1785
1786 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1787 cp.rdx -= b->rdx;
1788 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1789
1790 if (b->rdx == b->len) {
1791 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1792 len -= i - 1;
1793 }
1794
1795 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1796
1797 // We want an extra zero in front to make things simpler.
1798 cp.num[cp.len++] = 0;
1799 end = cp.len - len;
1800
1801 bc_num_expand(c, cp.len);
1802
1803 bc_num_zero(c);
1804 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1805 c->rdx = cp.rdx;
1806 c->len = cp.len;
1807 p = b->num;
1808
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001809 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001810 n = cp.num + i;
1811 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001812 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001813 c->num[i] = q;
1814 }
1815
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001816 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001817 bc_num_free(&cp);
1818
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001819 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001820}
1821
1822static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1823 BcNum *restrict d, size_t scale, size_t ts)
1824{
1825 BcStatus s;
1826 BcNum temp;
1827 bool neg;
1828
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001829 if (b->len == 0)
1830 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001831
1832 if (a->len == 0) {
1833 bc_num_setToZero(d, ts);
1834 return BC_STATUS_SUCCESS;
1835 }
1836
1837 bc_num_init(&temp, d->cap);
1838 bc_num_d(a, b, c, scale);
1839
1840 if (scale != 0) scale = ts;
1841
1842 s = bc_num_m(c, b, &temp, scale);
1843 if (s) goto err;
1844 s = bc_num_sub(a, &temp, d, scale);
1845 if (s) goto err;
1846
1847 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1848
1849 neg = d->neg;
1850 bc_num_retireMul(d, ts, a->neg, b->neg);
1851 d->neg = neg;
1852
1853err:
1854 bc_num_free(&temp);
1855 return s;
1856}
1857
1858static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1859{
1860 BcStatus s;
1861 BcNum c1;
1862 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1863
1864 bc_num_init(&c1, len);
1865 s = bc_num_r(a, b, &c1, c, scale, ts);
1866 bc_num_free(&c1);
1867
1868 return s;
1869}
1870
1871static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1872{
1873 BcStatus s = BC_STATUS_SUCCESS;
1874 BcNum copy;
1875 unsigned long pow;
1876 size_t i, powrdx, resrdx;
1877 bool neg, zero;
1878
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001879 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001880
1881 if (b->len == 0) {
1882 bc_num_one(c);
1883 return BC_STATUS_SUCCESS;
1884 }
1885 else if (a->len == 0) {
1886 bc_num_setToZero(c, scale);
1887 return BC_STATUS_SUCCESS;
1888 }
1889 else if (BC_NUM_ONE(b)) {
1890 if (!b->neg)
1891 bc_num_copy(c, a);
1892 else
1893 s = bc_num_inv(a, c, scale);
1894 return s;
1895 }
1896
1897 neg = b->neg;
1898 b->neg = false;
1899
1900 s = bc_num_ulong(b, &pow);
1901 if (s) return s;
1902
1903 bc_num_init(&copy, a->len);
1904 bc_num_copy(&copy, a);
1905
1906 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1907
1908 b->neg = neg;
1909
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001910 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001911 powrdx <<= 1;
1912 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1913 if (s) goto err;
1914 }
1915
Gavin Howard01055ba2018-11-03 11:00:21 -06001916 bc_num_copy(c, &copy);
1917
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001918 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001919
1920 powrdx <<= 1;
1921 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1922 if (s) goto err;
1923
1924 if (pow & 1) {
1925 resrdx += powrdx;
1926 s = bc_num_mul(c, &copy, c, resrdx);
1927 if (s) goto err;
1928 }
1929 }
1930
1931 if (neg) {
1932 s = bc_num_inv(c, c, scale);
1933 if (s) goto err;
1934 }
1935
Gavin Howard01055ba2018-11-03 11:00:21 -06001936 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1937
1938 // We can't use bc_num_clean() here.
1939 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1940 if (zero) bc_num_setToZero(c, scale);
1941
1942err:
1943 bc_num_free(&copy);
1944 return s;
1945}
1946
1947static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1948 BcNumBinaryOp op, size_t req)
1949{
1950 BcStatus s;
1951 BcNum num2, *ptr_a, *ptr_b;
1952 bool init = false;
1953
1954 if (c == a) {
1955 ptr_a = &num2;
1956 memcpy(ptr_a, c, sizeof(BcNum));
1957 init = true;
1958 }
1959 else
1960 ptr_a = a;
1961
1962 if (c == b) {
1963 ptr_b = &num2;
1964 if (c != a) {
1965 memcpy(ptr_b, c, sizeof(BcNum));
1966 init = true;
1967 }
1968 }
1969 else
1970 ptr_b = b;
1971
1972 if (init)
1973 bc_num_init(c, req);
1974 else
1975 bc_num_expand(c, req);
1976
1977 s = op(ptr_a, ptr_b, c, scale);
1978
1979 if (init) bc_num_free(&num2);
1980
1981 return s;
1982}
1983
1984static bool bc_num_strValid(const char *val, size_t base)
1985{
1986 BcDig b;
1987 bool small, radix = false;
1988 size_t i, len = strlen(val);
1989
1990 if (!len) return true;
1991
1992 small = base <= 10;
1993 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1994
1995 for (i = 0; i < len; ++i) {
1996
1997 BcDig c = val[i];
1998
1999 if (c == '.') {
2000
2001 if (radix) return false;
2002
2003 radix = true;
2004 continue;
2005 }
2006
2007 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2008 return false;
2009 }
2010
2011 return true;
2012}
2013
2014static void bc_num_parseDecimal(BcNum *n, const char *val)
2015{
2016 size_t len, i;
2017 const char *ptr;
2018 bool zero = true;
2019
2020 for (i = 0; val[i] == '0'; ++i);
2021
2022 val += i;
2023 len = strlen(val);
2024 bc_num_zero(n);
2025
2026 if (len != 0) {
2027 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2028 bc_num_expand(n, len);
2029 }
2030
2031 ptr = strchr(val, '.');
2032
2033 // Explicitly test for NULL here to produce either a 0 or 1.
2034 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2035
2036 if (!zero) {
2037 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2038 n->num[n->len] = val[i] - '0';
2039 }
2040}
2041
2042static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2043{
2044 BcStatus s;
2045 BcNum temp, mult, result;
2046 BcDig c = '\0';
2047 bool zero = true;
2048 unsigned long v;
2049 size_t i, digits, len = strlen(val);
2050
2051 bc_num_zero(n);
2052
2053 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2054 if (zero) return;
2055
2056 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2057 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2058
2059 for (i = 0; i < len; ++i) {
2060
2061 c = val[i];
2062 if (c == '.') break;
2063
2064 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2065
2066 s = bc_num_mul(n, base, &mult, 0);
2067 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002068 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002069 s = bc_num_add(&mult, &temp, n, 0);
2070 if (s) goto int_err;
2071 }
2072
2073 if (i == len) {
2074 c = val[i];
2075 if (c == 0) goto int_err;
2076 }
2077
2078 bc_num_init(&result, base->len);
2079 bc_num_zero(&result);
2080 bc_num_one(&mult);
2081
2082 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2083
2084 c = val[i];
2085 if (c == 0) break;
2086
2087 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2088
2089 s = bc_num_mul(&result, base, &result, 0);
2090 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002091 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002092 s = bc_num_add(&result, &temp, &result, 0);
2093 if (s) goto err;
2094 s = bc_num_mul(&mult, base, &mult, 0);
2095 if (s) goto err;
2096 }
2097
2098 s = bc_num_div(&result, &mult, &result, digits);
2099 if (s) goto err;
2100 s = bc_num_add(n, &result, n, digits);
2101 if (s) goto err;
2102
2103 if (n->len != 0) {
2104 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2105 }
2106 else
2107 bc_num_zero(n);
2108
2109err:
2110 bc_num_free(&result);
2111int_err:
2112 bc_num_free(&mult);
2113 bc_num_free(&temp);
2114}
2115
2116static void bc_num_printNewline(size_t *nchars, size_t line_len)
2117{
2118 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002119 bb_putchar('\\');
2120 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002121 *nchars = 0;
2122 }
2123}
2124
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002125#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002126static void bc_num_printChar(size_t num, size_t width, bool radix,
2127 size_t *nchars, size_t line_len)
2128{
2129 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002130 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002131 *nchars = *nchars + width;
2132}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002133#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002134
2135static void bc_num_printDigits(size_t num, size_t width, bool radix,
2136 size_t *nchars, size_t line_len)
2137{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002138 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002139
2140 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002141 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002142 ++(*nchars);
2143
2144 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002145 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2146 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002147
2148 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002149 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002150 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002151 dig = num / pow;
2152 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002153 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002154 }
2155}
2156
2157static void bc_num_printHex(size_t num, size_t width, bool radix,
2158 size_t *nchars, size_t line_len)
2159{
2160 if (radix) {
2161 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002162 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002163 *nchars += 1;
2164 }
2165
2166 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002167 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002168 *nchars = *nchars + width;
2169}
2170
2171static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2172{
2173 size_t i, rdx = n->rdx - 1;
2174
Denys Vlasenko00d77792018-11-30 23:13:42 +01002175 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002176 (*nchars) += n->neg;
2177
2178 for (i = n->len - 1; i < n->len; --i)
2179 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2180}
2181
2182static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2183 size_t *nchars, size_t len, BcNumDigitOp print)
2184{
2185 BcStatus s;
2186 BcVec stack;
2187 BcNum intp, fracp, digit, frac_len;
2188 unsigned long dig, *ptr;
2189 size_t i;
2190 bool radix;
2191
2192 if (n->len == 0) {
2193 print(0, width, false, nchars, len);
2194 return BC_STATUS_SUCCESS;
2195 }
2196
2197 bc_vec_init(&stack, sizeof(long), NULL);
2198 bc_num_init(&intp, n->len);
2199 bc_num_init(&fracp, n->rdx);
2200 bc_num_init(&digit, width);
2201 bc_num_init(&frac_len, BC_NUM_INT(n));
2202 bc_num_copy(&intp, n);
2203 bc_num_one(&frac_len);
2204
2205 bc_num_truncate(&intp, intp.rdx);
2206 s = bc_num_sub(n, &intp, &fracp, 0);
2207 if (s) goto err;
2208
2209 while (intp.len != 0) {
2210 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2211 if (s) goto err;
2212 s = bc_num_ulong(&digit, &dig);
2213 if (s) goto err;
2214 bc_vec_push(&stack, &dig);
2215 }
2216
2217 for (i = 0; i < stack.len; ++i) {
2218 ptr = bc_vec_item_rev(&stack, i);
2219 print(*ptr, width, false, nchars, len);
2220 }
2221
2222 if (!n->rdx) goto err;
2223
2224 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2225 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2226 if (s) goto err;
2227 s = bc_num_ulong(&fracp, &dig);
2228 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002229 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002230 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2231 if (s) goto err;
2232 print(dig, width, radix, nchars, len);
2233 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2234 if (s) goto err;
2235 }
2236
2237err:
2238 bc_num_free(&frac_len);
2239 bc_num_free(&digit);
2240 bc_num_free(&fracp);
2241 bc_num_free(&intp);
2242 bc_vec_free(&stack);
2243 return s;
2244}
2245
2246static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2247 size_t *nchars, size_t line_len)
2248{
2249 BcStatus s;
2250 size_t width, i;
2251 BcNumDigitOp print;
2252 bool neg = n->neg;
2253
Denys Vlasenko00d77792018-11-30 23:13:42 +01002254 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002255 (*nchars) += neg;
2256
2257 n->neg = false;
2258
2259 if (base_t <= BC_NUM_MAX_IBASE) {
2260 width = 1;
2261 print = bc_num_printHex;
2262 }
2263 else {
2264 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2265 print = bc_num_printDigits;
2266 }
2267
2268 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2269 n->neg = neg;
2270
2271 return s;
2272}
2273
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002274#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002275static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2276{
2277 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2278}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002279#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002280
2281static void bc_num_init(BcNum *n, size_t req)
2282{
2283 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2284 memset(n, 0, sizeof(BcNum));
2285 n->num = xmalloc(req);
2286 n->cap = req;
2287}
2288
2289static void bc_num_expand(BcNum *n, size_t req)
2290{
2291 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2292 if (req > n->cap) {
2293 n->num = xrealloc(n->num, req);
2294 n->cap = req;
2295 }
2296}
2297
2298static void bc_num_free(void *num)
2299{
2300 free(((BcNum *) num)->num);
2301}
2302
2303static void bc_num_copy(BcNum *d, BcNum *s)
2304{
2305 if (d != s) {
2306 bc_num_expand(d, s->cap);
2307 d->len = s->len;
2308 d->neg = s->neg;
2309 d->rdx = s->rdx;
2310 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2311 }
2312}
2313
2314static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2315 size_t base_t)
2316{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002317 if (!bc_num_strValid(val, base_t))
2318 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002319
2320 if (base_t == 10)
2321 bc_num_parseDecimal(n, val);
2322 else
2323 bc_num_parseBase(n, val, base);
2324
2325 return BC_STATUS_SUCCESS;
2326}
2327
2328static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2329 size_t *nchars, size_t line_len)
2330{
2331 BcStatus s = BC_STATUS_SUCCESS;
2332
2333 bc_num_printNewline(nchars, line_len);
2334
2335 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002336 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002337 ++(*nchars);
2338 }
2339 else if (base_t == 10)
2340 bc_num_printDecimal(n, nchars, line_len);
2341 else
2342 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2343
2344 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002345 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002346 *nchars = 0;
2347 }
2348
2349 return s;
2350}
2351
2352static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2353{
2354 size_t i;
2355 unsigned long pow;
2356
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002357 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002358
2359 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2360
2361 unsigned long prev = *result, powprev = pow;
2362
2363 *result += ((unsigned long) n->num[i]) * pow;
2364 pow *= 10;
2365
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002366 if (*result < prev || pow < powprev)
2367 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002368 }
2369
2370 return BC_STATUS_SUCCESS;
2371}
2372
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002373static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002374{
2375 size_t len;
2376 BcDig *ptr;
2377 unsigned long i;
2378
2379 bc_num_zero(n);
2380
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002381 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002382
2383 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2384 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002385}
2386
2387static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2388{
2389 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2390 (void) scale;
2391 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2392}
2393
2394static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2395{
2396 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2397 (void) scale;
2398 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2399}
2400
2401static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2402{
2403 size_t req = BC_NUM_MREQ(a, b, scale);
2404 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2405}
2406
2407static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2408{
2409 size_t req = BC_NUM_MREQ(a, b, scale);
2410 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2411}
2412
2413static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2414{
2415 size_t req = BC_NUM_MREQ(a, b, scale);
2416 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2417}
2418
2419static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2420{
2421 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2422}
2423
2424static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2425{
2426 BcStatus s;
2427 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2428 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2429 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2430
2431 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2432 bc_num_expand(b, req);
2433
2434 if (a->len == 0) {
2435 bc_num_setToZero(b, scale);
2436 return BC_STATUS_SUCCESS;
2437 }
2438 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002439 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002440 else if (BC_NUM_ONE(a)) {
2441 bc_num_one(b);
2442 bc_num_extend(b, scale);
2443 return BC_STATUS_SUCCESS;
2444 }
2445
2446 scale = BC_MAX(scale, a->rdx) + 1;
2447 len = a->len + scale;
2448
2449 bc_num_init(&num1, len);
2450 bc_num_init(&num2, len);
2451 bc_num_init(&half, BC_NUM_DEF_SIZE);
2452
2453 bc_num_one(&half);
2454 half.num[0] = 5;
2455 half.rdx = 1;
2456
2457 bc_num_init(&f, len);
2458 bc_num_init(&fprime, len);
2459
2460 x0 = &num1;
2461 x1 = &num2;
2462
2463 bc_num_one(x0);
2464 pow = BC_NUM_INT(a);
2465
2466 if (pow) {
2467
2468 if (pow & 1)
2469 x0->num[0] = 2;
2470 else
2471 x0->num[0] = 6;
2472
2473 pow -= 2 - (pow & 1);
2474
2475 bc_num_extend(x0, pow);
2476
2477 // Make sure to move the radix back.
2478 x0->rdx -= pow;
2479 }
2480
2481 x0->rdx = digs = digs1 = 0;
2482 resrdx = scale + 2;
2483 len = BC_NUM_INT(x0) + resrdx - 1;
2484
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002485 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002486
2487 s = bc_num_div(a, x0, &f, resrdx);
2488 if (s) goto err;
2489 s = bc_num_add(x0, &f, &fprime, resrdx);
2490 if (s) goto err;
2491 s = bc_num_mul(&fprime, &half, x1, resrdx);
2492 if (s) goto err;
2493
2494 cmp = bc_num_cmp(x1, x0);
2495 digs = x1->len - (unsigned long long) llabs(cmp);
2496
2497 if (cmp == cmp2 && digs == digs1)
2498 times += 1;
2499 else
2500 times = 0;
2501
2502 resrdx += times > 4;
2503
2504 cmp2 = cmp1;
2505 cmp1 = cmp;
2506 digs1 = digs;
2507
2508 temp = x0;
2509 x0 = x1;
2510 x1 = temp;
2511 }
2512
Gavin Howard01055ba2018-11-03 11:00:21 -06002513 bc_num_copy(b, x0);
2514 scale -= 1;
2515 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2516
2517err:
2518 bc_num_free(&fprime);
2519 bc_num_free(&f);
2520 bc_num_free(&half);
2521 bc_num_free(&num2);
2522 bc_num_free(&num1);
2523 return s;
2524}
2525
2526static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2527 size_t scale)
2528{
2529 BcStatus s;
2530 BcNum num2, *ptr_a;
2531 bool init = false;
2532 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2533
2534 if (c == a) {
2535 memcpy(&num2, c, sizeof(BcNum));
2536 ptr_a = &num2;
2537 bc_num_init(c, len);
2538 init = true;
2539 }
2540 else {
2541 ptr_a = a;
2542 bc_num_expand(c, len);
2543 }
2544
2545 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2546
2547 if (init) bc_num_free(&num2);
2548
2549 return s;
2550}
2551
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002552#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002553static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2554{
2555 BcStatus s;
2556 BcNum base, exp, two, temp;
2557
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002558 if (c->len == 0)
2559 return bc_error("divide by zero");
2560 if (a->rdx || b->rdx || c->rdx)
2561 return bc_error("non integer number");
2562 if (b->neg)
2563 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002564
2565 bc_num_expand(d, c->len);
2566 bc_num_init(&base, c->len);
2567 bc_num_init(&exp, b->len);
2568 bc_num_init(&two, BC_NUM_DEF_SIZE);
2569 bc_num_init(&temp, b->len);
2570
2571 bc_num_one(&two);
2572 two.num[0] = 2;
2573 bc_num_one(d);
2574
2575 s = bc_num_rem(a, c, &base, 0);
2576 if (s) goto err;
2577 bc_num_copy(&exp, b);
2578
2579 while (exp.len != 0) {
2580
2581 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2582 if (s) goto err;
2583
2584 if (BC_NUM_ONE(&temp)) {
2585 s = bc_num_mul(d, &base, &temp, 0);
2586 if (s) goto err;
2587 s = bc_num_rem(&temp, c, d, 0);
2588 if (s) goto err;
2589 }
2590
2591 s = bc_num_mul(&base, &base, &temp, 0);
2592 if (s) goto err;
2593 s = bc_num_rem(&temp, c, &base, 0);
2594 if (s) goto err;
2595 }
2596
2597err:
2598 bc_num_free(&temp);
2599 bc_num_free(&two);
2600 bc_num_free(&exp);
2601 bc_num_free(&base);
2602 return s;
2603}
2604#endif // ENABLE_DC
2605
2606static int bc_id_cmp(const void *e1, const void *e2)
2607{
2608 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2609}
2610
2611static void bc_id_free(void *id)
2612{
2613 free(((BcId *) id)->name);
2614}
2615
2616static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2617{
2618 BcId a;
2619 size_t i;
2620
2621 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002622 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2623 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002624 }
2625
2626 a.idx = var;
2627 a.name = name;
2628
2629 bc_vec_push(&f->autos, &a);
2630
2631 return BC_STATUS_SUCCESS;
2632}
2633
2634static void bc_func_init(BcFunc *f)
2635{
2636 bc_vec_init(&f->code, sizeof(char), NULL);
2637 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2638 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2639 f->nparams = 0;
2640}
2641
2642static void bc_func_free(void *func)
2643{
2644 BcFunc *f = (BcFunc *) func;
2645 bc_vec_free(&f->code);
2646 bc_vec_free(&f->autos);
2647 bc_vec_free(&f->labels);
2648}
2649
2650static void bc_array_init(BcVec *a, bool nums)
2651{
2652 if (nums)
2653 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2654 else
2655 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2656 bc_array_expand(a, 1);
2657}
2658
2659static void bc_array_copy(BcVec *d, const BcVec *s)
2660{
2661 size_t i;
2662
2663 bc_vec_npop(d, d->len);
2664 bc_vec_expand(d, s->cap);
2665 d->len = s->len;
2666
2667 for (i = 0; i < s->len; ++i) {
2668 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2669 bc_num_init(dnum, snum->len);
2670 bc_num_copy(dnum, snum);
2671 }
2672}
2673
2674static void bc_array_expand(BcVec *a, size_t len)
2675{
2676 BcResultData data;
2677
2678 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2679 while (len > a->len) {
2680 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2681 bc_vec_push(a, &data.n);
2682 }
2683 }
2684 else {
2685 while (len > a->len) {
2686 bc_array_init(&data.v, true);
2687 bc_vec_push(a, &data.v);
2688 }
2689 }
2690}
2691
2692static void bc_string_free(void *string)
2693{
2694 free(*((char **) string));
2695}
2696
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002697#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002698static void bc_result_copy(BcResult *d, BcResult *src)
2699{
2700 d->t = src->t;
2701
2702 switch (d->t) {
2703
2704 case BC_RESULT_TEMP:
2705 case BC_RESULT_IBASE:
2706 case BC_RESULT_SCALE:
2707 case BC_RESULT_OBASE:
2708 {
2709 bc_num_init(&d->d.n, src->d.n.len);
2710 bc_num_copy(&d->d.n, &src->d.n);
2711 break;
2712 }
2713
2714 case BC_RESULT_VAR:
2715 case BC_RESULT_ARRAY:
2716 case BC_RESULT_ARRAY_ELEM:
2717 {
2718 d->d.id.name = xstrdup(src->d.id.name);
2719 break;
2720 }
2721
2722 case BC_RESULT_CONSTANT:
2723 case BC_RESULT_LAST:
2724 case BC_RESULT_ONE:
2725 case BC_RESULT_STR:
2726 {
2727 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2728 break;
2729 }
2730 }
2731}
2732#endif // ENABLE_DC
2733
2734static void bc_result_free(void *result)
2735{
2736 BcResult *r = (BcResult *) result;
2737
2738 switch (r->t) {
2739
2740 case BC_RESULT_TEMP:
2741 case BC_RESULT_IBASE:
2742 case BC_RESULT_SCALE:
2743 case BC_RESULT_OBASE:
2744 {
2745 bc_num_free(&r->d.n);
2746 break;
2747 }
2748
2749 case BC_RESULT_VAR:
2750 case BC_RESULT_ARRAY:
2751 case BC_RESULT_ARRAY_ELEM:
2752 {
2753 free(r->d.id.name);
2754 break;
2755 }
2756
2757 default:
2758 {
2759 // Do nothing.
2760 break;
2761 }
2762 }
2763}
2764
2765static void bc_lex_lineComment(BcLex *l)
2766{
2767 l->t.t = BC_LEX_WHITESPACE;
2768 while (l->i < l->len && l->buf[l->i++] != '\n');
2769 --l->i;
2770}
2771
2772static void bc_lex_whitespace(BcLex *l)
2773{
2774 char c;
2775 l->t.t = BC_LEX_WHITESPACE;
2776 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2777}
2778
2779static BcStatus bc_lex_number(BcLex *l, char start)
2780{
2781 const char *buf = l->buf + l->i;
2782 size_t len, hits = 0, bslashes = 0, i = 0, j;
2783 char c = buf[i];
2784 bool last_pt, pt = start == '.';
2785
2786 last_pt = pt;
2787 l->t.t = BC_LEX_NUMBER;
2788
2789 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2790 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2791 {
2792 if (c != '\\') {
2793 last_pt = c == '.';
2794 pt = pt || last_pt;
2795 }
2796 else {
2797 ++i;
2798 bslashes += 1;
2799 }
2800
2801 c = buf[++i];
2802 }
2803
2804 len = i + 1 * !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002805 if (len > BC_MAX_NUM)
2806 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002807
2808 bc_vec_npop(&l->t.v, l->t.v.len);
2809 bc_vec_expand(&l->t.v, len + 1);
2810 bc_vec_push(&l->t.v, &start);
2811
2812 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2813
2814 c = buf[j];
2815
2816 // If we have hit a backslash, skip it. We don't have
2817 // to check for a newline because it's guaranteed.
2818 if (hits < bslashes && c == '\\') {
2819 ++hits;
2820 ++j;
2821 continue;
2822 }
2823
2824 bc_vec_push(&l->t.v, &c);
2825 }
2826
2827 bc_vec_pushByte(&l->t.v, '\0');
2828 l->i += i;
2829
2830 return BC_STATUS_SUCCESS;
2831}
2832
2833static BcStatus bc_lex_name(BcLex *l)
2834{
2835 size_t i = 0;
2836 const char *buf = l->buf + l->i - 1;
2837 char c = buf[i];
2838
2839 l->t.t = BC_LEX_NAME;
2840
2841 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2842
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002843 if (i > BC_MAX_STRING)
2844 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002845 bc_vec_string(&l->t.v, i, buf);
2846
2847 // Increment the index. We minus 1 because it has already been incremented.
2848 l->i += i - 1;
2849
2850 return BC_STATUS_SUCCESS;
2851}
2852
2853static void bc_lex_init(BcLex *l, BcLexNext next)
2854{
2855 l->next = next;
2856 bc_vec_init(&l->t.v, sizeof(char), NULL);
2857}
2858
2859static void bc_lex_free(BcLex *l)
2860{
2861 bc_vec_free(&l->t.v);
2862}
2863
2864static void bc_lex_file(BcLex *l, const char *file)
2865{
2866 l->line = 1;
2867 l->newline = false;
2868 l->f = file;
2869}
2870
2871static BcStatus bc_lex_next(BcLex *l)
2872{
2873 BcStatus s;
2874
2875 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002876 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002877
2878 l->line += l->newline;
2879 l->t.t = BC_LEX_EOF;
2880
2881 l->newline = (l->i == l->len);
2882 if (l->newline) return BC_STATUS_SUCCESS;
2883
2884 // Loop until failure or we don't have whitespace. This
2885 // is so the parser doesn't get inundated with whitespace.
2886 do {
2887 s = l->next(l);
2888 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2889
2890 return s;
2891}
2892
2893static BcStatus bc_lex_text(BcLex *l, const char *text)
2894{
2895 l->buf = text;
2896 l->i = 0;
2897 l->len = strlen(text);
2898 l->t.t = l->t.last = BC_LEX_INVALID;
2899 return bc_lex_next(l);
2900}
2901
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002902#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002903static BcStatus bc_lex_identifier(BcLex *l)
2904{
2905 BcStatus s;
2906 size_t i;
2907 const char *buf = l->buf + l->i - 1;
2908
2909 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2910
2911 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2912
2913 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2914
2915 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2916
2917 if (!bc_lex_kws[i].posix) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002918 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
Gavin Howard01055ba2018-11-03 11:00:21 -06002919 if (s) return s;
2920 }
2921
2922 // We minus 1 because the index has already been incremented.
2923 l->i += len - 1;
2924 return BC_STATUS_SUCCESS;
2925 }
2926 }
2927
2928 s = bc_lex_name(l);
2929 if (s) return s;
2930
2931 if (l->t.v.len - 1 > 1)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002932 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002933
2934 return s;
2935}
2936
2937static BcStatus bc_lex_string(BcLex *l)
2938{
2939 size_t len, nls = 0, i = l->i;
2940 char c;
2941
2942 l->t.t = BC_LEX_STR;
2943
2944 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2945
2946 if (c == '\0') {
2947 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002948 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002949 }
2950
2951 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002952 if (len > BC_MAX_STRING)
2953 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002954 bc_vec_string(&l->t.v, len, l->buf + l->i);
2955
2956 l->i = i + 1;
2957 l->line += nls;
2958
2959 return BC_STATUS_SUCCESS;
2960}
2961
2962static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2963{
2964 if (l->buf[l->i] == '=') {
2965 ++l->i;
2966 l->t.t = with;
2967 }
2968 else
2969 l->t.t = without;
2970}
2971
2972static BcStatus bc_lex_comment(BcLex *l)
2973{
2974 size_t i, nls = 0;
2975 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06002976
2977 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002978 i = ++l->i;
2979 for (;;) {
2980 char c = buf[i];
2981 check_star:
2982 if (c == '*') {
2983 c = buf[++i];
2984 if (c == '/')
2985 break;
2986 goto check_star;
2987 }
2988 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06002989 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002990 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002991 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002992 nls += (c == '\n');
2993 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06002994 }
2995
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002996 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002997 l->line += nls;
2998
2999 return BC_STATUS_SUCCESS;
3000}
3001
3002static BcStatus bc_lex_token(BcLex *l)
3003{
3004 BcStatus s = BC_STATUS_SUCCESS;
3005 char c = l->buf[l->i++], c2;
3006
3007 // This is the workhorse of the lexer.
3008 switch (c) {
3009
3010 case '\0':
3011 case '\n':
3012 {
3013 l->newline = true;
3014 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3015 break;
3016 }
3017
3018 case '\t':
3019 case '\v':
3020 case '\f':
3021 case '\r':
3022 case ' ':
3023 {
3024 bc_lex_whitespace(l);
3025 break;
3026 }
3027
3028 case '!':
3029 {
3030 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3031
3032 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003033 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003034 if (s) return s;
3035 }
3036
3037 break;
3038 }
3039
3040 case '"':
3041 {
3042 s = bc_lex_string(l);
3043 break;
3044 }
3045
3046 case '#':
3047 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003048 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003049 if (s) return s;
3050
3051 bc_lex_lineComment(l);
3052
3053 break;
3054 }
3055
3056 case '%':
3057 {
3058 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3059 break;
3060 }
3061
3062 case '&':
3063 {
3064 c2 = l->buf[l->i];
3065 if (c2 == '&') {
3066
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003067 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003068 if (s) return s;
3069
3070 ++l->i;
3071 l->t.t = BC_LEX_OP_BOOL_AND;
3072 }
3073 else {
3074 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003075 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003076 }
3077
3078 break;
3079 }
3080
3081 case '(':
3082 case ')':
3083 {
3084 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3085 break;
3086 }
3087
3088 case '*':
3089 {
3090 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3091 break;
3092 }
3093
3094 case '+':
3095 {
3096 c2 = l->buf[l->i];
3097 if (c2 == '+') {
3098 ++l->i;
3099 l->t.t = BC_LEX_OP_INC;
3100 }
3101 else
3102 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3103 break;
3104 }
3105
3106 case ',':
3107 {
3108 l->t.t = BC_LEX_COMMA;
3109 break;
3110 }
3111
3112 case '-':
3113 {
3114 c2 = l->buf[l->i];
3115 if (c2 == '-') {
3116 ++l->i;
3117 l->t.t = BC_LEX_OP_DEC;
3118 }
3119 else
3120 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3121 break;
3122 }
3123
3124 case '.':
3125 {
3126 if (isdigit(l->buf[l->i]))
3127 s = bc_lex_number(l, c);
3128 else {
3129 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003130 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003131 }
3132 break;
3133 }
3134
3135 case '/':
3136 {
3137 c2 = l->buf[l->i];
3138 if (c2 == '*')
3139 s = bc_lex_comment(l);
3140 else
3141 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3142 break;
3143 }
3144
3145 case '0':
3146 case '1':
3147 case '2':
3148 case '3':
3149 case '4':
3150 case '5':
3151 case '6':
3152 case '7':
3153 case '8':
3154 case '9':
3155 case 'A':
3156 case 'B':
3157 case 'C':
3158 case 'D':
3159 case 'E':
3160 case 'F':
3161 {
3162 s = bc_lex_number(l, c);
3163 break;
3164 }
3165
3166 case ';':
3167 {
3168 l->t.t = BC_LEX_SCOLON;
3169 break;
3170 }
3171
3172 case '<':
3173 {
3174 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3175 break;
3176 }
3177
3178 case '=':
3179 {
3180 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3181 break;
3182 }
3183
3184 case '>':
3185 {
3186 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3187 break;
3188 }
3189
3190 case '[':
3191 case ']':
3192 {
3193 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3194 break;
3195 }
3196
3197 case '\\':
3198 {
3199 if (l->buf[l->i] == '\n') {
3200 l->t.t = BC_LEX_WHITESPACE;
3201 ++l->i;
3202 }
3203 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003204 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003205 break;
3206 }
3207
3208 case '^':
3209 {
3210 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3211 break;
3212 }
3213
3214 case 'a':
3215 case 'b':
3216 case 'c':
3217 case 'd':
3218 case 'e':
3219 case 'f':
3220 case 'g':
3221 case 'h':
3222 case 'i':
3223 case 'j':
3224 case 'k':
3225 case 'l':
3226 case 'm':
3227 case 'n':
3228 case 'o':
3229 case 'p':
3230 case 'q':
3231 case 'r':
3232 case 's':
3233 case 't':
3234 case 'u':
3235 case 'v':
3236 case 'w':
3237 case 'x':
3238 case 'y':
3239 case 'z':
3240 {
3241 s = bc_lex_identifier(l);
3242 break;
3243 }
3244
3245 case '{':
3246 case '}':
3247 {
3248 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3249 break;
3250 }
3251
3252 case '|':
3253 {
3254 c2 = l->buf[l->i];
3255
3256 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003257 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003258 if (s) return s;
3259
3260 ++l->i;
3261 l->t.t = BC_LEX_OP_BOOL_OR;
3262 }
3263 else {
3264 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003265 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003266 }
3267
3268 break;
3269 }
3270
3271 default:
3272 {
3273 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003274 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003275 break;
3276 }
3277 }
3278
3279 return s;
3280}
3281#endif // ENABLE_BC
3282
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003283#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003284static BcStatus dc_lex_register(BcLex *l)
3285{
3286 BcStatus s = BC_STATUS_SUCCESS;
3287
3288 if (isspace(l->buf[l->i - 1])) {
3289 bc_lex_whitespace(l);
3290 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003291 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003292 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003293 else
3294 s = bc_lex_name(l);
3295 }
3296 else {
3297 bc_vec_npop(&l->t.v, l->t.v.len);
3298 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3299 bc_vec_pushByte(&l->t.v, '\0');
3300 l->t.t = BC_LEX_NAME;
3301 }
3302
3303 return s;
3304}
3305
3306static BcStatus dc_lex_string(BcLex *l)
3307{
3308 size_t depth = 1, nls = 0, i = l->i;
3309 char c;
3310
3311 l->t.t = BC_LEX_STR;
3312 bc_vec_npop(&l->t.v, l->t.v.len);
3313
3314 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3315
3316 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3317 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3318 nls += (c == '\n');
3319
3320 if (depth) bc_vec_push(&l->t.v, &c);
3321 }
3322
3323 if (c == '\0') {
3324 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003325 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003326 }
3327
3328 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003329 if (i - l->i > BC_MAX_STRING)
3330 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003331
3332 l->i = i;
3333 l->line += nls;
3334
3335 return BC_STATUS_SUCCESS;
3336}
3337
3338static BcStatus dc_lex_token(BcLex *l)
3339{
3340 BcStatus s = BC_STATUS_SUCCESS;
3341 char c = l->buf[l->i++], c2;
3342 size_t i;
3343
3344 for (i = 0; i < dc_lex_regs_len; ++i) {
3345 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3346 }
3347
3348 if (c >= '%' && c <= '~' &&
3349 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3350 {
3351 return s;
3352 }
3353
3354 // This is the workhorse of the lexer.
3355 switch (c) {
3356
3357 case '\0':
3358 {
3359 l->t.t = BC_LEX_EOF;
3360 break;
3361 }
3362
3363 case '\n':
3364 case '\t':
3365 case '\v':
3366 case '\f':
3367 case '\r':
3368 case ' ':
3369 {
3370 l->newline = (c == '\n');
3371 bc_lex_whitespace(l);
3372 break;
3373 }
3374
3375 case '!':
3376 {
3377 c2 = l->buf[l->i];
3378
3379 if (c2 == '=')
3380 l->t.t = BC_LEX_OP_REL_NE;
3381 else if (c2 == '<')
3382 l->t.t = BC_LEX_OP_REL_LE;
3383 else if (c2 == '>')
3384 l->t.t = BC_LEX_OP_REL_GE;
3385 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003386 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003387
3388 ++l->i;
3389 break;
3390 }
3391
3392 case '#':
3393 {
3394 bc_lex_lineComment(l);
3395 break;
3396 }
3397
3398 case '.':
3399 {
3400 if (isdigit(l->buf[l->i]))
3401 s = bc_lex_number(l, c);
3402 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003403 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003404 break;
3405 }
3406
3407 case '0':
3408 case '1':
3409 case '2':
3410 case '3':
3411 case '4':
3412 case '5':
3413 case '6':
3414 case '7':
3415 case '8':
3416 case '9':
3417 case 'A':
3418 case 'B':
3419 case 'C':
3420 case 'D':
3421 case 'E':
3422 case 'F':
3423 {
3424 s = bc_lex_number(l, c);
3425 break;
3426 }
3427
3428 case '[':
3429 {
3430 s = dc_lex_string(l);
3431 break;
3432 }
3433
3434 default:
3435 {
3436 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003437 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003438 break;
3439 }
3440 }
3441
3442 return s;
3443}
3444#endif // ENABLE_DC
3445
3446static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3447{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003448 bc_program_addFunc(name, idx);
3449 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003450}
3451
3452static void bc_parse_pushName(BcParse *p, char *name)
3453{
3454 size_t i = 0, len = strlen(name);
3455
3456 for (; i < len; ++i) bc_parse_push(p, name[i]);
3457 bc_parse_push(p, BC_PARSE_STREND);
3458
3459 free(name);
3460}
3461
3462static void bc_parse_pushIndex(BcParse *p, size_t idx)
3463{
3464 unsigned char amt, i, nums[sizeof(size_t)];
3465
3466 for (amt = 0; idx; ++amt) {
3467 nums[amt] = (char) idx;
3468 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3469 }
3470
3471 bc_parse_push(p, amt);
3472 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3473}
3474
3475static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3476{
3477 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003478 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003479
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003480 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003481
3482 bc_parse_push(p, BC_INST_NUM);
3483 bc_parse_pushIndex(p, idx);
3484
3485 ++(*nexs);
3486 (*prev) = BC_INST_NUM;
3487}
3488
3489static BcStatus bc_parse_text(BcParse *p, const char *text)
3490{
3491 BcStatus s;
3492
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003493 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003494
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003495 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003496 p->l.t.t = BC_LEX_INVALID;
3497 s = p->parse(p);
3498 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003499 if (!BC_PARSE_CAN_EXEC(p))
3500 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003501 }
3502
3503 return bc_lex_text(&p->l, text);
3504}
3505
Denys Vlasenkod38af482018-12-04 19:11:02 +01003506// Called when bc/dc_parse_parse() detects a failure,
3507// resets parsing structures.
3508static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003509{
3510 if (p->fidx != BC_PROG_MAIN) {
3511
3512 p->func->nparams = 0;
3513 bc_vec_npop(&p->func->code, p->func->code.len);
3514 bc_vec_npop(&p->func->autos, p->func->autos.len);
3515 bc_vec_npop(&p->func->labels, p->func->labels.len);
3516
3517 bc_parse_updateFunc(p, BC_PROG_MAIN);
3518 }
3519
3520 p->l.i = p->l.len;
3521 p->l.t.t = BC_LEX_EOF;
3522 p->auto_part = (p->nbraces = 0);
3523
3524 bc_vec_npop(&p->flags, p->flags.len - 1);
3525 bc_vec_npop(&p->exits, p->exits.len);
3526 bc_vec_npop(&p->conds, p->conds.len);
3527 bc_vec_npop(&p->ops, p->ops.len);
3528
Denys Vlasenkod38af482018-12-04 19:11:02 +01003529 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003530}
3531
3532static void bc_parse_free(BcParse *p)
3533{
3534 bc_vec_free(&p->flags);
3535 bc_vec_free(&p->exits);
3536 bc_vec_free(&p->conds);
3537 bc_vec_free(&p->ops);
3538 bc_lex_free(&p->l);
3539}
3540
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003541static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003542 BcParseParse parse, BcLexNext next)
3543{
3544 memset(p, 0, sizeof(BcParse));
3545
3546 bc_lex_init(&p->l, next);
3547 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3548 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3549 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3550 bc_vec_pushByte(&p->flags, 0);
3551 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3552
3553 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003554 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003555 bc_parse_updateFunc(p, func);
3556}
3557
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003558#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003559static BcStatus bc_parse_else(BcParse *p);
3560static BcStatus bc_parse_stmt(BcParse *p);
3561
3562static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3563 size_t *nexprs, bool next)
3564{
3565 BcStatus s = BC_STATUS_SUCCESS;
3566 BcLexType t;
3567 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3568 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3569
3570 while (p->ops.len > start) {
3571
3572 t = BC_PARSE_TOP_OP(p);
3573 if (t == BC_LEX_LPAREN) break;
3574
3575 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3576 if (l >= r && (l != r || !left)) break;
3577
3578 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3579 bc_vec_pop(&p->ops);
3580 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3581 }
3582
3583 bc_vec_push(&p->ops, &type);
3584 if (next) s = bc_lex_next(&p->l);
3585
3586 return s;
3587}
3588
3589static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3590{
3591 BcLexType top;
3592
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003593 if (p->ops.len <= ops_bgn)
3594 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003595 top = BC_PARSE_TOP_OP(p);
3596
3597 while (top != BC_LEX_LPAREN) {
3598
3599 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3600
3601 bc_vec_pop(&p->ops);
3602 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3603
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003604 if (p->ops.len <= ops_bgn)
3605 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003606 top = BC_PARSE_TOP_OP(p);
3607 }
3608
3609 bc_vec_pop(&p->ops);
3610
3611 return bc_lex_next(&p->l);
3612}
3613
3614static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3615{
3616 BcStatus s;
3617 bool comma = false;
3618 size_t nparams;
3619
3620 s = bc_lex_next(&p->l);
3621 if (s) return s;
3622
3623 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3624
3625 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3626 s = bc_parse_expr(p, flags, bc_parse_next_param);
3627 if (s) return s;
3628
3629 comma = p->l.t.t == BC_LEX_COMMA;
3630 if (comma) {
3631 s = bc_lex_next(&p->l);
3632 if (s) return s;
3633 }
3634 }
3635
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003636 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003637 bc_parse_push(p, BC_INST_CALL);
3638 bc_parse_pushIndex(p, nparams);
3639
3640 return BC_STATUS_SUCCESS;
3641}
3642
3643static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3644{
3645 BcStatus s;
3646 BcId entry, *entry_ptr;
3647 size_t idx;
3648
3649 entry.name = name;
3650
3651 s = bc_parse_params(p, flags);
3652 if (s) goto err;
3653
3654 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003655 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003656 goto err;
3657 }
3658
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003659 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003660
3661 if (idx == BC_VEC_INVALID_IDX) {
3662 name = xstrdup(entry.name);
3663 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003664 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003665 free(entry.name);
3666 }
3667 else
3668 free(name);
3669
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003670 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003671 bc_parse_pushIndex(p, entry_ptr->idx);
3672
3673 return bc_lex_next(&p->l);
3674
3675err:
3676 free(name);
3677 return s;
3678}
3679
3680static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3681{
3682 BcStatus s;
3683 char *name;
3684
3685 name = xstrdup(p->l.t.v.v);
3686 s = bc_lex_next(&p->l);
3687 if (s) goto err;
3688
3689 if (p->l.t.t == BC_LEX_LBRACKET) {
3690
3691 s = bc_lex_next(&p->l);
3692 if (s) goto err;
3693
3694 if (p->l.t.t == BC_LEX_RBRACKET) {
3695
3696 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003697 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003698 goto err;
3699 }
3700
3701 *type = BC_INST_ARRAY;
3702 }
3703 else {
3704
3705 *type = BC_INST_ARRAY_ELEM;
3706
3707 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3708 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3709 if (s) goto err;
3710 }
3711
3712 s = bc_lex_next(&p->l);
3713 if (s) goto err;
3714 bc_parse_push(p, *type);
3715 bc_parse_pushName(p, name);
3716 }
3717 else if (p->l.t.t == BC_LEX_LPAREN) {
3718
3719 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003720 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003721 goto err;
3722 }
3723
3724 *type = BC_INST_CALL;
3725 s = bc_parse_call(p, name, flags);
3726 }
3727 else {
3728 *type = BC_INST_VAR;
3729 bc_parse_push(p, BC_INST_VAR);
3730 bc_parse_pushName(p, name);
3731 }
3732
3733 return s;
3734
3735err:
3736 free(name);
3737 return s;
3738}
3739
3740static BcStatus bc_parse_read(BcParse *p)
3741{
3742 BcStatus s;
3743
3744 s = bc_lex_next(&p->l);
3745 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003746 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003747
3748 s = bc_lex_next(&p->l);
3749 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003750 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003751
3752 bc_parse_push(p, BC_INST_READ);
3753
3754 return bc_lex_next(&p->l);
3755}
3756
3757static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3758 BcInst *prev)
3759{
3760 BcStatus s;
3761
3762 s = bc_lex_next(&p->l);
3763 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003764 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003765
3766 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3767
3768 s = bc_lex_next(&p->l);
3769 if (s) return s;
3770
3771 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3772 if (s) return s;
3773
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003774 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003775
3776 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3777 bc_parse_push(p, *prev);
3778
3779 return bc_lex_next(&p->l);
3780}
3781
3782static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3783{
3784 BcStatus s;
3785
3786 s = bc_lex_next(&p->l);
3787 if (s) return s;
3788
3789 if (p->l.t.t != BC_LEX_LPAREN) {
3790 *type = BC_INST_SCALE;
3791 bc_parse_push(p, BC_INST_SCALE);
3792 return BC_STATUS_SUCCESS;
3793 }
3794
3795 *type = BC_INST_SCALE_FUNC;
3796 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3797
3798 s = bc_lex_next(&p->l);
3799 if (s) return s;
3800
3801 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3802 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003803 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003804 bc_parse_push(p, BC_INST_SCALE_FUNC);
3805
3806 return bc_lex_next(&p->l);
3807}
3808
3809static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3810 size_t *nexprs, uint8_t flags)
3811{
3812 BcStatus s;
3813 BcLexType type;
3814 char inst;
3815 BcInst etype = *prev;
3816
3817 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3818 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3819 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3820 {
3821 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3822 bc_parse_push(p, inst);
3823 s = bc_lex_next(&p->l);
3824 }
3825 else {
3826
3827 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3828 *paren_expr = true;
3829
3830 s = bc_lex_next(&p->l);
3831 if (s) return s;
3832 type = p->l.t.t;
3833
3834 // Because we parse the next part of the expression
3835 // right here, we need to increment this.
3836 *nexprs = *nexprs + 1;
3837
3838 switch (type) {
3839
3840 case BC_LEX_NAME:
3841 {
3842 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3843 break;
3844 }
3845
3846 case BC_LEX_KEY_IBASE:
3847 case BC_LEX_KEY_LAST:
3848 case BC_LEX_KEY_OBASE:
3849 {
3850 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3851 s = bc_lex_next(&p->l);
3852 break;
3853 }
3854
3855 case BC_LEX_KEY_SCALE:
3856 {
3857 s = bc_lex_next(&p->l);
3858 if (s) return s;
3859 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003860 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003861 else
3862 bc_parse_push(p, BC_INST_SCALE);
3863 break;
3864 }
3865
3866 default:
3867 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003868 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003869 break;
3870 }
3871 }
3872
3873 if (!s) bc_parse_push(p, inst);
3874 }
3875
3876 return s;
3877}
3878
3879static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3880 bool rparen, size_t *nexprs)
3881{
3882 BcStatus s;
3883 BcLexType type;
3884 BcInst etype = *prev;
3885
3886 s = bc_lex_next(&p->l);
3887 if (s) return s;
3888
3889 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3890 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3891 BC_LEX_OP_MINUS :
3892 BC_LEX_NEG;
3893 *prev = BC_PARSE_TOKEN_INST(type);
3894
3895 // We can just push onto the op stack because this is the largest
3896 // precedence operator that gets pushed. Inc/dec does not.
3897 if (type != BC_LEX_OP_MINUS)
3898 bc_vec_push(&p->ops, &type);
3899 else
3900 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3901
3902 return s;
3903}
3904
3905static BcStatus bc_parse_string(BcParse *p, char inst)
3906{
3907 char *str = xstrdup(p->l.t.v.v);
3908
3909 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003910 bc_parse_pushIndex(p, G.prog.strs.len);
3911 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003912 bc_parse_push(p, inst);
3913
3914 return bc_lex_next(&p->l);
3915}
3916
3917static BcStatus bc_parse_print(BcParse *p)
3918{
3919 BcStatus s;
3920 BcLexType type;
3921 bool comma = false;
3922
3923 s = bc_lex_next(&p->l);
3924 if (s) return s;
3925
3926 type = p->l.t.t;
3927
3928 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003929 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003930
3931 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3932
3933 if (type == BC_LEX_STR)
3934 s = bc_parse_string(p, BC_INST_PRINT_POP);
3935 else {
3936 s = bc_parse_expr(p, 0, bc_parse_next_print);
3937 if (s) return s;
3938 bc_parse_push(p, BC_INST_PRINT_POP);
3939 }
3940
3941 if (s) return s;
3942
3943 comma = p->l.t.t == BC_LEX_COMMA;
3944 if (comma) s = bc_lex_next(&p->l);
3945 type = p->l.t.t;
3946 }
3947
3948 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003949 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003950
3951 return bc_lex_next(&p->l);
3952}
3953
3954static BcStatus bc_parse_return(BcParse *p)
3955{
3956 BcStatus s;
3957 BcLexType t;
3958 bool paren;
3959
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003960 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003961
3962 s = bc_lex_next(&p->l);
3963 if (s) return s;
3964
3965 t = p->l.t.t;
3966 paren = t == BC_LEX_LPAREN;
3967
3968 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3969 bc_parse_push(p, BC_INST_RET0);
3970 else {
3971
3972 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3973 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3974 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003975
3976 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003977 bc_parse_push(p, BC_INST_RET0);
3978 s = bc_lex_next(&p->l);
3979 if (s) return s;
3980 }
3981
3982 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003983 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06003984 if (s) return s;
3985 }
3986
3987 bc_parse_push(p, BC_INST_RET);
3988 }
3989
3990 return s;
3991}
3992
3993static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3994{
3995 BcStatus s = BC_STATUS_SUCCESS;
3996
3997 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003998 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003999
4000 if (brace) {
4001
4002 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004003 if (!p->nbraces) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004004 --p->nbraces;
4005 s = bc_lex_next(&p->l);
4006 if (s) return s;
4007 }
4008 else
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004009 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004010 }
4011
4012 if (BC_PARSE_IF(p)) {
4013
4014 uint8_t *flag_ptr;
4015
4016 while (p->l.t.t == BC_LEX_NLINE) {
4017 s = bc_lex_next(&p->l);
4018 if (s) return s;
4019 }
4020
4021 bc_vec_pop(&p->flags);
4022
4023 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4024 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4025
4026 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4027 }
4028 else if (BC_PARSE_ELSE(p)) {
4029
4030 BcInstPtr *ip;
4031 size_t *label;
4032
4033 bc_vec_pop(&p->flags);
4034
4035 ip = bc_vec_top(&p->exits);
4036 label = bc_vec_item(&p->func->labels, ip->idx);
4037 *label = p->func->code.len;
4038
4039 bc_vec_pop(&p->exits);
4040 }
4041 else if (BC_PARSE_FUNC_INNER(p)) {
4042 bc_parse_push(p, BC_INST_RET0);
4043 bc_parse_updateFunc(p, BC_PROG_MAIN);
4044 bc_vec_pop(&p->flags);
4045 }
4046 else {
4047
4048 BcInstPtr *ip = bc_vec_top(&p->exits);
4049 size_t *label = bc_vec_top(&p->conds);
4050
4051 bc_parse_push(p, BC_INST_JUMP);
4052 bc_parse_pushIndex(p, *label);
4053
4054 label = bc_vec_item(&p->func->labels, ip->idx);
4055 *label = p->func->code.len;
4056
4057 bc_vec_pop(&p->flags);
4058 bc_vec_pop(&p->exits);
4059 bc_vec_pop(&p->conds);
4060 }
4061
4062 return s;
4063}
4064
4065static void bc_parse_startBody(BcParse *p, uint8_t flags)
4066{
4067 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4068 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4069 flags |= BC_PARSE_FLAG_BODY;
4070 bc_vec_push(&p->flags, &flags);
4071}
4072
4073static void bc_parse_noElse(BcParse *p)
4074{
4075 BcInstPtr *ip;
4076 size_t *label;
4077 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4078
4079 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4080
4081 ip = bc_vec_top(&p->exits);
4082 label = bc_vec_item(&p->func->labels, ip->idx);
4083 *label = p->func->code.len;
4084
4085 bc_vec_pop(&p->exits);
4086}
4087
4088static BcStatus bc_parse_if(BcParse *p)
4089{
4090 BcStatus s;
4091 BcInstPtr ip;
4092
4093 s = bc_lex_next(&p->l);
4094 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004095 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004096
4097 s = bc_lex_next(&p->l);
4098 if (s) return s;
4099 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4100 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004101 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004102
4103 s = bc_lex_next(&p->l);
4104 if (s) return s;
4105 bc_parse_push(p, BC_INST_JUMP_ZERO);
4106
4107 ip.idx = p->func->labels.len;
4108 ip.func = ip.len = 0;
4109
4110 bc_parse_pushIndex(p, ip.idx);
4111 bc_vec_push(&p->exits, &ip);
4112 bc_vec_push(&p->func->labels, &ip.idx);
4113 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4114
4115 return BC_STATUS_SUCCESS;
4116}
4117
4118static BcStatus bc_parse_else(BcParse *p)
4119{
4120 BcInstPtr ip;
4121
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004122 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004123
4124 ip.idx = p->func->labels.len;
4125 ip.func = ip.len = 0;
4126
4127 bc_parse_push(p, BC_INST_JUMP);
4128 bc_parse_pushIndex(p, ip.idx);
4129
4130 bc_parse_noElse(p);
4131
4132 bc_vec_push(&p->exits, &ip);
4133 bc_vec_push(&p->func->labels, &ip.idx);
4134 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4135
4136 return bc_lex_next(&p->l);
4137}
4138
4139static BcStatus bc_parse_while(BcParse *p)
4140{
4141 BcStatus s;
4142 BcInstPtr ip;
4143
4144 s = bc_lex_next(&p->l);
4145 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004146 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004147 s = bc_lex_next(&p->l);
4148 if (s) return s;
4149
4150 ip.idx = p->func->labels.len;
4151
4152 bc_vec_push(&p->func->labels, &p->func->code.len);
4153 bc_vec_push(&p->conds, &ip.idx);
4154
4155 ip.idx = p->func->labels.len;
4156 ip.func = 1;
4157 ip.len = 0;
4158
4159 bc_vec_push(&p->exits, &ip);
4160 bc_vec_push(&p->func->labels, &ip.idx);
4161
4162 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4163 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004164 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004165 s = bc_lex_next(&p->l);
4166 if (s) return s;
4167
4168 bc_parse_push(p, BC_INST_JUMP_ZERO);
4169 bc_parse_pushIndex(p, ip.idx);
4170 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4171
4172 return BC_STATUS_SUCCESS;
4173}
4174
4175static BcStatus bc_parse_for(BcParse *p)
4176{
4177 BcStatus s;
4178 BcInstPtr ip;
4179 size_t cond_idx, exit_idx, body_idx, update_idx;
4180
4181 s = bc_lex_next(&p->l);
4182 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004183 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004184 s = bc_lex_next(&p->l);
4185 if (s) return s;
4186
4187 if (p->l.t.t != BC_LEX_SCOLON)
4188 s = bc_parse_expr(p, 0, bc_parse_next_for);
4189 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004190 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004191
4192 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004193 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004194 s = bc_lex_next(&p->l);
4195 if (s) return s;
4196
4197 cond_idx = p->func->labels.len;
4198 update_idx = cond_idx + 1;
4199 body_idx = update_idx + 1;
4200 exit_idx = body_idx + 1;
4201
4202 bc_vec_push(&p->func->labels, &p->func->code.len);
4203
4204 if (p->l.t.t != BC_LEX_SCOLON)
4205 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4206 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004207 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004208
4209 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004210 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004211
4212 s = bc_lex_next(&p->l);
4213 if (s) return s;
4214
4215 bc_parse_push(p, BC_INST_JUMP_ZERO);
4216 bc_parse_pushIndex(p, exit_idx);
4217 bc_parse_push(p, BC_INST_JUMP);
4218 bc_parse_pushIndex(p, body_idx);
4219
4220 ip.idx = p->func->labels.len;
4221
4222 bc_vec_push(&p->conds, &update_idx);
4223 bc_vec_push(&p->func->labels, &p->func->code.len);
4224
4225 if (p->l.t.t != BC_LEX_RPAREN)
4226 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4227 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004228 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004229
4230 if (s) return s;
4231
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004232 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004233 bc_parse_push(p, BC_INST_JUMP);
4234 bc_parse_pushIndex(p, cond_idx);
4235 bc_vec_push(&p->func->labels, &p->func->code.len);
4236
4237 ip.idx = exit_idx;
4238 ip.func = 1;
4239 ip.len = 0;
4240
4241 bc_vec_push(&p->exits, &ip);
4242 bc_vec_push(&p->func->labels, &ip.idx);
4243 bc_lex_next(&p->l);
4244 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4245
4246 return BC_STATUS_SUCCESS;
4247}
4248
4249static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4250{
4251 BcStatus s;
4252 size_t i;
4253 BcInstPtr *ip;
4254
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004255 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004256
4257 if (type == BC_LEX_KEY_BREAK) {
4258
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004259 if (p->exits.len == 0) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004260
4261 i = p->exits.len - 1;
4262 ip = bc_vec_item(&p->exits, i);
4263
4264 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004265 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004266
4267 i = ip->idx;
4268 }
4269 else
4270 i = *((size_t *) bc_vec_top(&p->conds));
4271
4272 bc_parse_push(p, BC_INST_JUMP);
4273 bc_parse_pushIndex(p, i);
4274
4275 s = bc_lex_next(&p->l);
4276 if (s) return s;
4277
4278 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004279 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004280
4281 return bc_lex_next(&p->l);
4282}
4283
4284static BcStatus bc_parse_func(BcParse *p)
4285{
4286 BcStatus s;
4287 bool var, comma = false;
4288 uint8_t flags;
4289 char *name;
4290
4291 s = bc_lex_next(&p->l);
4292 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004293 if (p->l.t.t != BC_LEX_NAME)
4294 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004295
4296 name = xstrdup(p->l.t.v.v);
4297 bc_parse_addFunc(p, name, &p->fidx);
4298
4299 s = bc_lex_next(&p->l);
4300 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004301 if (p->l.t.t != BC_LEX_LPAREN)
4302 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004303 s = bc_lex_next(&p->l);
4304 if (s) return s;
4305
4306 while (p->l.t.t != BC_LEX_RPAREN) {
4307
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004308 if (p->l.t.t != BC_LEX_NAME)
4309 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004310
4311 ++p->func->nparams;
4312
4313 name = xstrdup(p->l.t.v.v);
4314 s = bc_lex_next(&p->l);
4315 if (s) goto err;
4316
4317 var = p->l.t.t != BC_LEX_LBRACKET;
4318
4319 if (!var) {
4320
4321 s = bc_lex_next(&p->l);
4322 if (s) goto err;
4323
4324 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004325 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004326 goto err;
4327 }
4328
4329 s = bc_lex_next(&p->l);
4330 if (s) goto err;
4331 }
4332
4333 comma = p->l.t.t == BC_LEX_COMMA;
4334 if (comma) {
4335 s = bc_lex_next(&p->l);
4336 if (s) goto err;
4337 }
4338
4339 s = bc_func_insert(p->func, name, var);
4340 if (s) goto err;
4341 }
4342
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004343 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004344
4345 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4346 bc_parse_startBody(p, flags);
4347
4348 s = bc_lex_next(&p->l);
4349 if (s) return s;
4350
4351 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004352 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 -06004353
4354 return s;
4355
4356err:
4357 free(name);
4358 return s;
4359}
4360
4361static BcStatus bc_parse_auto(BcParse *p)
4362{
4363 BcStatus s;
4364 bool comma, var, one;
4365 char *name;
4366
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004367 if (!p->auto_part) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004368 s = bc_lex_next(&p->l);
4369 if (s) return s;
4370
4371 p->auto_part = comma = false;
4372 one = p->l.t.t == BC_LEX_NAME;
4373
4374 while (p->l.t.t == BC_LEX_NAME) {
4375
4376 name = xstrdup(p->l.t.v.v);
4377 s = bc_lex_next(&p->l);
4378 if (s) goto err;
4379
4380 var = p->l.t.t != BC_LEX_LBRACKET;
4381 if (!var) {
4382
4383 s = bc_lex_next(&p->l);
4384 if (s) goto err;
4385
4386 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004387 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004388 goto err;
4389 }
4390
4391 s = bc_lex_next(&p->l);
4392 if (s) goto err;
4393 }
4394
4395 comma = p->l.t.t == BC_LEX_COMMA;
4396 if (comma) {
4397 s = bc_lex_next(&p->l);
4398 if (s) goto err;
4399 }
4400
4401 s = bc_func_insert(p->func, name, var);
4402 if (s) goto err;
4403 }
4404
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004405 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004406 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004407
4408 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004409 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004410
4411 return bc_lex_next(&p->l);
4412
4413err:
4414 free(name);
4415 return s;
4416}
4417
4418static BcStatus bc_parse_body(BcParse *p, bool brace)
4419{
4420 BcStatus s = BC_STATUS_SUCCESS;
4421 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4422
4423 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4424
4425 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4426
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004427 if (!brace) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004428 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4429
4430 if (!p->auto_part) {
4431 s = bc_parse_auto(p);
4432 if (s) return s;
4433 }
4434
4435 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4436 }
4437 else {
4438 s = bc_parse_stmt(p);
4439 if (!s && !brace) s = bc_parse_endBody(p, false);
4440 }
4441
4442 return s;
4443}
4444
4445static BcStatus bc_parse_stmt(BcParse *p)
4446{
4447 BcStatus s = BC_STATUS_SUCCESS;
4448
4449 switch (p->l.t.t) {
4450
4451 case BC_LEX_NLINE:
4452 {
4453 return bc_lex_next(&p->l);
4454 }
4455
4456 case BC_LEX_KEY_ELSE:
4457 {
4458 p->auto_part = false;
4459 break;
4460 }
4461
4462 case BC_LEX_LBRACE:
4463 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004464 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004465
4466 ++p->nbraces;
4467 s = bc_lex_next(&p->l);
4468 if (s) return s;
4469
4470 return bc_parse_body(p, true);
4471 }
4472
4473 case BC_LEX_KEY_AUTO:
4474 {
4475 return bc_parse_auto(p);
4476 }
4477
4478 default:
4479 {
4480 p->auto_part = false;
4481
4482 if (BC_PARSE_IF_END(p)) {
4483 bc_parse_noElse(p);
4484 return BC_STATUS_SUCCESS;
4485 }
4486 else if (BC_PARSE_BODY(p))
4487 return bc_parse_body(p, false);
4488
4489 break;
4490 }
4491 }
4492
4493 switch (p->l.t.t) {
4494
4495 case BC_LEX_OP_INC:
4496 case BC_LEX_OP_DEC:
4497 case BC_LEX_OP_MINUS:
4498 case BC_LEX_OP_BOOL_NOT:
4499 case BC_LEX_LPAREN:
4500 case BC_LEX_NAME:
4501 case BC_LEX_NUMBER:
4502 case BC_LEX_KEY_IBASE:
4503 case BC_LEX_KEY_LAST:
4504 case BC_LEX_KEY_LENGTH:
4505 case BC_LEX_KEY_OBASE:
4506 case BC_LEX_KEY_READ:
4507 case BC_LEX_KEY_SCALE:
4508 case BC_LEX_KEY_SQRT:
4509 {
4510 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4511 break;
4512 }
4513
4514 case BC_LEX_KEY_ELSE:
4515 {
4516 s = bc_parse_else(p);
4517 break;
4518 }
4519
4520 case BC_LEX_SCOLON:
4521 {
4522 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4523 break;
4524 }
4525
4526 case BC_LEX_RBRACE:
4527 {
4528 s = bc_parse_endBody(p, true);
4529 break;
4530 }
4531
4532 case BC_LEX_STR:
4533 {
4534 s = bc_parse_string(p, BC_INST_PRINT_STR);
4535 break;
4536 }
4537
4538 case BC_LEX_KEY_BREAK:
4539 case BC_LEX_KEY_CONTINUE:
4540 {
4541 s = bc_parse_loopExit(p, p->l.t.t);
4542 break;
4543 }
4544
4545 case BC_LEX_KEY_FOR:
4546 {
4547 s = bc_parse_for(p);
4548 break;
4549 }
4550
4551 case BC_LEX_KEY_HALT:
4552 {
4553 bc_parse_push(p, BC_INST_HALT);
4554 s = bc_lex_next(&p->l);
4555 break;
4556 }
4557
4558 case BC_LEX_KEY_IF:
4559 {
4560 s = bc_parse_if(p);
4561 break;
4562 }
4563
4564 case BC_LEX_KEY_LIMITS:
4565 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004566 // "limits" is a compile-time command,
4567 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004568 s = bc_lex_next(&p->l);
4569 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004570 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4571 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4572 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4573 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4574 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4575 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4576 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4577 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004578 break;
4579 }
4580
4581 case BC_LEX_KEY_PRINT:
4582 {
4583 s = bc_parse_print(p);
4584 break;
4585 }
4586
4587 case BC_LEX_KEY_QUIT:
4588 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004589 // "quit" is a compile-time command. For example,
4590 // "if (0 == 1) quit" terminates when parsing the statement,
4591 // not when it is executed
4592 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004593 }
4594
4595 case BC_LEX_KEY_RETURN:
4596 {
4597 s = bc_parse_return(p);
4598 break;
4599 }
4600
4601 case BC_LEX_KEY_WHILE:
4602 {
4603 s = bc_parse_while(p);
4604 break;
4605 }
4606
4607 default:
4608 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004609 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004610 break;
4611 }
4612 }
4613
4614 return s;
4615}
4616
4617static BcStatus bc_parse_parse(BcParse *p)
4618{
4619 BcStatus s;
4620
4621 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004622 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 -06004623 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004624 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004625 s = bc_parse_func(p);
4626 }
4627 else
4628 s = bc_parse_stmt(p);
4629
Denys Vlasenkod38af482018-12-04 19:11:02 +01004630 if (s || G_interrupt) {
4631 bc_parse_reset(p);
4632 s = BC_STATUS_FAILURE;
4633 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004634
4635 return s;
4636}
4637
4638static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4639{
4640 BcStatus s = BC_STATUS_SUCCESS;
4641 BcInst prev = BC_INST_PRINT;
4642 BcLexType top, t = p->l.t.t;
4643 size_t nexprs = 0, ops_bgn = p->ops.len;
4644 uint32_t i, nparens, nrelops;
4645 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4646
4647 paren_first = p->l.t.t == BC_LEX_LPAREN;
4648 nparens = nrelops = 0;
4649 paren_expr = rprn = done = get_token = assign = false;
4650 bin_last = true;
4651
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004652 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004653 switch (t) {
4654
4655 case BC_LEX_OP_INC:
4656 case BC_LEX_OP_DEC:
4657 {
4658 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4659 rprn = get_token = bin_last = false;
4660 break;
4661 }
4662
4663 case BC_LEX_OP_MINUS:
4664 {
4665 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4666 rprn = get_token = false;
4667 bin_last = prev == BC_INST_MINUS;
4668 break;
4669 }
4670
4671 case BC_LEX_OP_ASSIGN_POWER:
4672 case BC_LEX_OP_ASSIGN_MULTIPLY:
4673 case BC_LEX_OP_ASSIGN_DIVIDE:
4674 case BC_LEX_OP_ASSIGN_MODULUS:
4675 case BC_LEX_OP_ASSIGN_PLUS:
4676 case BC_LEX_OP_ASSIGN_MINUS:
4677 case BC_LEX_OP_ASSIGN:
4678 {
4679 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4680 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4681 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4682 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004683 s = bc_error("bad assignment:"
4684 " left side must be scale,"
4685 " ibase, obase, last, var,"
4686 " or array element"
4687 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004688 break;
4689 }
4690 }
4691 // Fallthrough.
4692 case BC_LEX_OP_POWER:
4693 case BC_LEX_OP_MULTIPLY:
4694 case BC_LEX_OP_DIVIDE:
4695 case BC_LEX_OP_MODULUS:
4696 case BC_LEX_OP_PLUS:
4697 case BC_LEX_OP_REL_EQ:
4698 case BC_LEX_OP_REL_LE:
4699 case BC_LEX_OP_REL_GE:
4700 case BC_LEX_OP_REL_NE:
4701 case BC_LEX_OP_REL_LT:
4702 case BC_LEX_OP_REL_GT:
4703 case BC_LEX_OP_BOOL_NOT:
4704 case BC_LEX_OP_BOOL_OR:
4705 case BC_LEX_OP_BOOL_AND:
4706 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004707 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4708 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4709 ) {
4710 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004711 }
4712
4713 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4714 prev = BC_PARSE_TOKEN_INST(t);
4715 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4716 rprn = get_token = false;
4717 bin_last = t != BC_LEX_OP_BOOL_NOT;
4718
4719 break;
4720 }
4721
4722 case BC_LEX_LPAREN:
4723 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004724 if (BC_PARSE_LEAF(prev, rprn))
4725 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004726 ++nparens;
4727 paren_expr = rprn = bin_last = false;
4728 get_token = true;
4729 bc_vec_push(&p->ops, &t);
4730
4731 break;
4732 }
4733
4734 case BC_LEX_RPAREN:
4735 {
4736 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004737 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004738
4739 if (nparens == 0) {
4740 s = BC_STATUS_SUCCESS;
4741 done = true;
4742 get_token = false;
4743 break;
4744 }
4745 else if (!paren_expr)
4746 return BC_STATUS_PARSE_EMPTY_EXP;
4747
4748 --nparens;
4749 paren_expr = rprn = true;
4750 get_token = bin_last = false;
4751
4752 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4753
4754 break;
4755 }
4756
4757 case BC_LEX_NAME:
4758 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004759 if (BC_PARSE_LEAF(prev, rprn))
4760 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004761 paren_expr = true;
4762 rprn = get_token = bin_last = false;
4763 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4764 ++nexprs;
4765
4766 break;
4767 }
4768
4769 case BC_LEX_NUMBER:
4770 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004771 if (BC_PARSE_LEAF(prev, rprn))
4772 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004773 bc_parse_number(p, &prev, &nexprs);
4774 paren_expr = get_token = true;
4775 rprn = bin_last = false;
4776
4777 break;
4778 }
4779
4780 case BC_LEX_KEY_IBASE:
4781 case BC_LEX_KEY_LAST:
4782 case BC_LEX_KEY_OBASE:
4783 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004784 if (BC_PARSE_LEAF(prev, rprn))
4785 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004786 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4787 bc_parse_push(p, (char) prev);
4788
4789 paren_expr = get_token = true;
4790 rprn = bin_last = false;
4791 ++nexprs;
4792
4793 break;
4794 }
4795
4796 case BC_LEX_KEY_LENGTH:
4797 case BC_LEX_KEY_SQRT:
4798 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004799 if (BC_PARSE_LEAF(prev, rprn))
4800 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004801 s = bc_parse_builtin(p, t, flags, &prev);
4802 paren_expr = true;
4803 rprn = get_token = bin_last = false;
4804 ++nexprs;
4805
4806 break;
4807 }
4808
4809 case BC_LEX_KEY_READ:
4810 {
4811 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004812 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004813 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004814 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06004815 else
4816 s = bc_parse_read(p);
4817
4818 paren_expr = true;
4819 rprn = get_token = bin_last = false;
4820 ++nexprs;
4821 prev = BC_INST_READ;
4822
4823 break;
4824 }
4825
4826 case BC_LEX_KEY_SCALE:
4827 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004828 if (BC_PARSE_LEAF(prev, rprn))
4829 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004830 s = bc_parse_scale(p, &prev, flags);
4831 paren_expr = true;
4832 rprn = get_token = bin_last = false;
4833 ++nexprs;
4834 prev = BC_INST_SCALE;
4835
4836 break;
4837 }
4838
4839 default:
4840 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004841 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004842 break;
4843 }
4844 }
4845
4846 if (!s && get_token) s = bc_lex_next(&p->l);
4847 }
4848
4849 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004850 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004851
4852 while (p->ops.len > ops_bgn) {
4853
4854 top = BC_PARSE_TOP_OP(p);
4855 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4856
4857 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004858 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004859
4860 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4861
4862 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4863 bc_vec_pop(&p->ops);
4864 }
4865
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004866 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4867 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004868
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004869 for (i = 0; i < next.len; ++i)
4870 if (t == next.tokens[i])
4871 goto ok;
4872 return bc_error("bad expression");
4873 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004874
4875 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004876 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004877 if (s) return s;
4878 }
4879 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004880 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004881 if (s) return s;
4882 }
4883
4884 if (flags & BC_PARSE_PRINT) {
4885 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4886 bc_parse_push(p, BC_INST_POP);
4887 }
4888
4889 return s;
4890}
4891
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004892static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004893{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004894 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004895}
4896
4897static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4898{
4899 return bc_parse_expr(p, flags, bc_parse_next_read);
4900}
4901#endif // ENABLE_BC
4902
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004903#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004904static BcStatus dc_parse_register(BcParse *p)
4905{
4906 BcStatus s;
4907 char *name;
4908
4909 s = bc_lex_next(&p->l);
4910 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004911 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004912
4913 name = xstrdup(p->l.t.v.v);
4914 bc_parse_pushName(p, name);
4915
4916 return s;
4917}
4918
4919static BcStatus dc_parse_string(BcParse *p)
4920{
4921 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004922 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004923
4924 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4925 name = xstrdup(b);
4926
4927 str = xstrdup(p->l.t.v.v);
4928 bc_parse_push(p, BC_INST_STR);
4929 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004930 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004931 bc_parse_addFunc(p, name, &idx);
4932
4933 return bc_lex_next(&p->l);
4934}
4935
4936static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4937{
4938 BcStatus s;
4939
4940 bc_parse_push(p, inst);
4941 if (name) {
4942 s = dc_parse_register(p);
4943 if (s) return s;
4944 }
4945
4946 if (store) {
4947 bc_parse_push(p, BC_INST_SWAP);
4948 bc_parse_push(p, BC_INST_ASSIGN);
4949 bc_parse_push(p, BC_INST_POP);
4950 }
4951
4952 return bc_lex_next(&p->l);
4953}
4954
4955static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4956{
4957 BcStatus s;
4958
4959 bc_parse_push(p, inst);
4960 bc_parse_push(p, BC_INST_EXEC_COND);
4961
4962 s = dc_parse_register(p);
4963 if (s) return s;
4964
4965 s = bc_lex_next(&p->l);
4966 if (s) return s;
4967
4968 if (p->l.t.t == BC_LEX_ELSE) {
4969 s = dc_parse_register(p);
4970 if (s) return s;
4971 s = bc_lex_next(&p->l);
4972 }
4973 else
4974 bc_parse_push(p, BC_PARSE_STREND);
4975
4976 return s;
4977}
4978
4979static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4980{
4981 BcStatus s = BC_STATUS_SUCCESS;
4982 BcInst prev;
4983 uint8_t inst;
4984 bool assign, get_token = false;
4985
4986 switch (t) {
4987
4988 case BC_LEX_OP_REL_EQ:
4989 case BC_LEX_OP_REL_LE:
4990 case BC_LEX_OP_REL_GE:
4991 case BC_LEX_OP_REL_NE:
4992 case BC_LEX_OP_REL_LT:
4993 case BC_LEX_OP_REL_GT:
4994 {
4995 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
4996 break;
4997 }
4998
4999 case BC_LEX_SCOLON:
5000 case BC_LEX_COLON:
5001 {
5002 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5003 break;
5004 }
5005
5006 case BC_LEX_STR:
5007 {
5008 s = dc_parse_string(p);
5009 break;
5010 }
5011
5012 case BC_LEX_NEG:
5013 case BC_LEX_NUMBER:
5014 {
5015 if (t == BC_LEX_NEG) {
5016 s = bc_lex_next(&p->l);
5017 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005018 if (p->l.t.t != BC_LEX_NUMBER)
5019 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005020 }
5021
5022 bc_parse_number(p, &prev, &p->nbraces);
5023
5024 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5025 get_token = true;
5026
5027 break;
5028 }
5029
5030 case BC_LEX_KEY_READ:
5031 {
5032 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005033 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005034 else
5035 bc_parse_push(p, BC_INST_READ);
5036 get_token = true;
5037 break;
5038 }
5039
5040 case BC_LEX_OP_ASSIGN:
5041 case BC_LEX_STORE_PUSH:
5042 {
5043 assign = t == BC_LEX_OP_ASSIGN;
5044 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5045 s = dc_parse_mem(p, inst, true, assign);
5046 break;
5047 }
5048
5049 case BC_LEX_LOAD:
5050 case BC_LEX_LOAD_POP:
5051 {
5052 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5053 s = dc_parse_mem(p, inst, true, false);
5054 break;
5055 }
5056
5057 case BC_LEX_STORE_IBASE:
5058 case BC_LEX_STORE_SCALE:
5059 case BC_LEX_STORE_OBASE:
5060 {
5061 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5062 s = dc_parse_mem(p, inst, false, true);
5063 break;
5064 }
5065
5066 default:
5067 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005068 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005069 get_token = true;
5070 break;
5071 }
5072 }
5073
5074 if (!s && get_token) s = bc_lex_next(&p->l);
5075
5076 return s;
5077}
5078
5079static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5080{
5081 BcStatus s = BC_STATUS_SUCCESS;
5082 BcInst inst;
5083 BcLexType t;
5084
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005085 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005086
5087 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5088
5089 inst = dc_parse_insts[t];
5090
5091 if (inst != BC_INST_INVALID) {
5092 bc_parse_push(p, inst);
5093 s = bc_lex_next(&p->l);
5094 }
5095 else
5096 s = dc_parse_token(p, t, flags);
5097 }
5098
5099 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5100 bc_parse_push(p, BC_INST_POP_EXEC);
5101
5102 return s;
5103}
5104
5105static BcStatus dc_parse_parse(BcParse *p)
5106{
5107 BcStatus s;
5108
5109 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005110 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005111 else
5112 s = dc_parse_expr(p, 0);
5113
Denys Vlasenkod38af482018-12-04 19:11:02 +01005114 if (s || G_interrupt) {
5115 bc_parse_reset(p);
5116 s = BC_STATUS_FAILURE;
5117 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005118
5119 return s;
5120}
5121
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005122static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005123{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005124 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005125}
5126#endif // ENABLE_DC
5127
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005128static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005129{
5130 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005131 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005132 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005133 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005134 }
5135}
5136
5137static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5138{
5139 if (IS_BC) {
5140 return bc_parse_expression(p, flags);
5141 } else {
5142 return dc_parse_expr(p, flags);
5143 }
5144}
5145
Denys Vlasenkodf515392018-12-02 19:27:48 +01005146static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005147{
Gavin Howard01055ba2018-11-03 11:00:21 -06005148 BcId e, *ptr;
5149 BcVec *v, *map;
5150 size_t i;
5151 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005152 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005153
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005154 v = var ? &G.prog.vars : &G.prog.arrs;
5155 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005156
5157 e.name = id;
5158 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005159 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005160
5161 if (new) {
5162 bc_array_init(&data.v, var);
5163 bc_vec_push(v, &data.v);
5164 }
5165
5166 ptr = bc_vec_item(map, i);
5167 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005168 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005169}
5170
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005171static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005172{
5173 BcStatus s = BC_STATUS_SUCCESS;
5174
5175 switch (r->t) {
5176
5177 case BC_RESULT_STR:
5178 case BC_RESULT_TEMP:
5179 case BC_RESULT_IBASE:
5180 case BC_RESULT_SCALE:
5181 case BC_RESULT_OBASE:
5182 {
5183 *num = &r->d.n;
5184 break;
5185 }
5186
5187 case BC_RESULT_CONSTANT:
5188 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005189 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005190 size_t base_t, len = strlen(*str);
5191 BcNum *base;
5192
5193 bc_num_init(&r->d.n, len);
5194
5195 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005196 base = hex ? &G.prog.hexb : &G.prog.ib;
5197 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005198 s = bc_num_parse(&r->d.n, *str, base, base_t);
5199
5200 if (s) {
5201 bc_num_free(&r->d.n);
5202 return s;
5203 }
5204
5205 *num = &r->d.n;
5206 r->t = BC_RESULT_TEMP;
5207
5208 break;
5209 }
5210
5211 case BC_RESULT_VAR:
5212 case BC_RESULT_ARRAY:
5213 case BC_RESULT_ARRAY_ELEM:
5214 {
5215 BcVec *v;
5216
Denys Vlasenkodf515392018-12-02 19:27:48 +01005217 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005218
5219 if (r->t == BC_RESULT_ARRAY_ELEM) {
5220 v = bc_vec_top(v);
5221 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5222 *num = bc_vec_item(v, r->d.id.idx);
5223 }
5224 else
5225 *num = bc_vec_top(v);
5226
5227 break;
5228 }
5229
5230 case BC_RESULT_LAST:
5231 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005232 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005233 break;
5234 }
5235
5236 case BC_RESULT_ONE:
5237 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005238 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005239 break;
5240 }
5241 }
5242
5243 return s;
5244}
5245
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005246static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005247 BcResult **r, BcNum **rn, bool assign)
5248{
5249 BcStatus s;
5250 bool hex;
5251 BcResultType lt, rt;
5252
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005253 if (!BC_PROG_STACK(&G.prog.results, 2))
5254 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005255
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005256 *r = bc_vec_item_rev(&G.prog.results, 0);
5257 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005258
5259 lt = (*l)->t;
5260 rt = (*r)->t;
5261 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5262
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005263 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005264 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005265 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005266 if (s) return s;
5267
5268 // We run this again under these conditions in case any vector has been
5269 // reallocated out from under the BcNums or arrays we had.
5270 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005271 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005272 if (s) return s;
5273 }
5274
5275 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005276 return bc_error("variable is wrong type");
5277 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5278 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005279
Gavin Howard01055ba2018-11-03 11:00:21 -06005280 return s;
5281}
5282
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005283static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005284{
5285 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005286 bc_vec_pop(&G.prog.results);
5287 bc_vec_pop(&G.prog.results);
5288 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005289}
5290
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005291static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005292{
5293 BcStatus s;
5294
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005295 if (!BC_PROG_STACK(&G.prog.results, 1))
5296 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005297 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005298
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005299 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005300 if (s) return s;
5301
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005302 if (!BC_PROG_NUM((*r), (*n)))
5303 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005304
5305 return s;
5306}
5307
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005308static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005309{
5310 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005311 bc_vec_pop(&G.prog.results);
5312 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005313}
5314
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005315static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005316{
5317 BcStatus s;
5318 BcResult *opd1, *opd2, res;
5319 BcNum *n1, *n2 = NULL;
5320
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005321 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005322 if (s) return s;
5323 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5324
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005325 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005326 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005327 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005328
5329 return s;
5330
5331err:
5332 bc_num_free(&res.d.n);
5333 return s;
5334}
5335
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005336static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005337{
5338 BcStatus s;
5339 BcParse parse;
5340 BcVec buf;
5341 BcInstPtr ip;
5342 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005343 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005344
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005345 for (i = 0; i < G.prog.stack.len; ++i) {
5346 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005347 if (ip_ptr->func == BC_PROG_READ)
5348 return bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005349 }
5350
5351 bc_vec_npop(&f->code, f->code.len);
5352 bc_vec_init(&buf, sizeof(char), NULL);
5353
5354 s = bc_read_line(&buf, "read> ");
5355 if (s) goto io_err;
5356
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005357 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005358 bc_lex_file(&parse.l, bc_program_stdin_name);
5359
5360 s = bc_parse_text(&parse, buf.v);
5361 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005362 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005363 if (s) goto exec_err;
5364
5365 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005366 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005367 goto exec_err;
5368 }
5369
5370 ip.func = BC_PROG_READ;
5371 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005372 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005373
5374 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005375 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005376
5377 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005378 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005379
5380exec_err:
5381 bc_parse_free(&parse);
5382io_err:
5383 bc_vec_free(&buf);
5384 return s;
5385}
5386
5387static size_t bc_program_index(char *code, size_t *bgn)
5388{
5389 char amt = code[(*bgn)++], i = 0;
5390 size_t res = 0;
5391
5392 for (; i < amt; ++i, ++(*bgn))
5393 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5394
5395 return res;
5396}
5397
5398static char *bc_program_name(char *code, size_t *bgn)
5399{
5400 size_t i;
5401 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5402
5403 s = xmalloc(ptr - str + 1);
5404 c = code[(*bgn)++];
5405
5406 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5407 s[i] = c;
5408
5409 s[i] = '\0';
5410
5411 return s;
5412}
5413
5414static void bc_program_printString(const char *str, size_t *nchars)
5415{
5416 size_t i, len = strlen(str);
5417
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005418#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005419 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005420 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005421 return;
5422 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005423#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005424
5425 for (i = 0; i < len; ++i, ++(*nchars)) {
5426
5427 int c = str[i];
5428
5429 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005430 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005431 else {
5432
5433 c = str[++i];
5434
5435 switch (c) {
5436
5437 case 'a':
5438 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005439 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005440 break;
5441 }
5442
5443 case 'b':
5444 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005445 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005446 break;
5447 }
5448
5449 case '\\':
5450 case 'e':
5451 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005452 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005453 break;
5454 }
5455
5456 case 'f':
5457 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005458 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005459 break;
5460 }
5461
5462 case 'n':
5463 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005464 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005465 *nchars = SIZE_MAX;
5466 break;
5467 }
5468
5469 case 'r':
5470 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005471 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005472 break;
5473 }
5474
5475 case 'q':
5476 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005477 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005478 break;
5479 }
5480
5481 case 't':
5482 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005483 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005484 break;
5485 }
5486
5487 default:
5488 {
5489 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005490 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005491 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005492 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005493 break;
5494 }
5495 }
5496 }
5497 }
5498}
5499
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005500static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005501{
5502 BcStatus s = BC_STATUS_SUCCESS;
5503 BcResult *r;
5504 size_t len, i;
5505 char *str;
5506 BcNum *num = NULL;
5507 bool pop = inst != BC_INST_PRINT;
5508
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005509 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5510 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005511
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005512 r = bc_vec_item_rev(&G.prog.results, idx);
5513 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005514 if (s) return s;
5515
5516 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005517 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5518 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005519 }
5520 else {
5521
5522 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005523 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005524
5525 if (inst == BC_INST_PRINT_STR) {
5526 for (i = 0, len = strlen(str); i < len; ++i) {
5527 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005528 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005529 if (c == '\n') G.prog.nchars = SIZE_MAX;
5530 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005531 }
5532 }
5533 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005534 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005535 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005536 }
5537 }
5538
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005539 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005540
5541 return s;
5542}
5543
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005544static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005545{
5546 BcStatus s;
5547 BcResult res, *ptr;
5548 BcNum *num = NULL;
5549
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005550 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005551 if (s) return s;
5552
5553 bc_num_init(&res.d.n, num->len);
5554 bc_num_copy(&res.d.n, num);
5555 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5556
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005557 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005558
5559 return s;
5560}
5561
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005562static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005563{
5564 BcStatus s;
5565 BcResult *opd1, *opd2, res;
5566 BcNum *n1, *n2;
5567 bool cond = 0;
5568 ssize_t cmp;
5569
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005570 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005571 if (s) return s;
5572 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5573
5574 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005575 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005576 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005577 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005578 else {
5579
5580 cmp = bc_num_cmp(n1, n2);
5581
5582 switch (inst) {
5583
5584 case BC_INST_REL_EQ:
5585 {
5586 cond = cmp == 0;
5587 break;
5588 }
5589
5590 case BC_INST_REL_LE:
5591 {
5592 cond = cmp <= 0;
5593 break;
5594 }
5595
5596 case BC_INST_REL_GE:
5597 {
5598 cond = cmp >= 0;
5599 break;
5600 }
5601
5602 case BC_INST_REL_NE:
5603 {
5604 cond = cmp != 0;
5605 break;
5606 }
5607
5608 case BC_INST_REL_LT:
5609 {
5610 cond = cmp < 0;
5611 break;
5612 }
5613
5614 case BC_INST_REL_GT:
5615 {
5616 cond = cmp > 0;
5617 break;
5618 }
5619 }
5620 }
5621
5622 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5623
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005624 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005625
5626 return s;
5627}
5628
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005629#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005630static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005631 bool push)
5632{
5633 BcNum n2;
5634 BcResult res;
5635
5636 memset(&n2, 0, sizeof(BcNum));
5637 n2.rdx = res.d.id.idx = r->d.id.idx;
5638 res.t = BC_RESULT_STR;
5639
5640 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005641 if (!BC_PROG_STACK(&G.prog.results, 2))
5642 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005643 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005644 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005645 }
5646
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005647 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005648
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005650 bc_vec_push(v, &n2);
5651
5652 return BC_STATUS_SUCCESS;
5653}
5654#endif // ENABLE_DC
5655
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005656static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005657{
5658 BcStatus s;
5659 BcResult *ptr, r;
5660 BcVec *v;
5661 BcNum *n;
5662
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005663 if (!BC_PROG_STACK(&G.prog.results, 1))
5664 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005665
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005666 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005667 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5668 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005669 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005670
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005671#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005672 if (ptr->t == BC_RESULT_STR && !var)
5673 return bc_error("variable is wrong type");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005674 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005675#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005676
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005677 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005678 if (s) return s;
5679
5680 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005681 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005682
5683 if (var) {
5684 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5685 bc_num_copy(&r.d.n, n);
5686 }
5687 else {
5688 bc_array_init(&r.d.v, true);
5689 bc_array_copy(&r.d.v, (BcVec *) n);
5690 }
5691
5692 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005693 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005694
5695 return s;
5696}
5697
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005698static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005699{
5700 BcStatus s;
5701 BcResult *left, *right, res;
5702 BcNum *l = NULL, *r = NULL;
5703 unsigned long val, max;
5704 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5705
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005706 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005707 if (s) return s;
5708
5709 ib = left->t == BC_RESULT_IBASE;
5710 sc = left->t == BC_RESULT_SCALE;
5711
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005712#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005713
5714 if (right->t == BC_RESULT_STR) {
5715
5716 BcVec *v;
5717
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005718 if (left->t != BC_RESULT_VAR)
5719 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005720 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005721
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005722 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005723 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005724#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005725
5726 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005727 return bc_error("bad assignment:"
5728 " left side must be scale,"
5729 " ibase, obase, last, var,"
5730 " or array element"
5731 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005732
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005733#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005734 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005735 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005736
5737 if (assign)
5738 bc_num_copy(l, r);
5739 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005740 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005741
5742 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005743#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005744 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005745#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005746
5747 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005748 static const char *const msg[] = {
5749 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5750 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5751 "?1", //BC_RESULT_LAST
5752 "?2", //BC_RESULT_CONSTANT
5753 "?3", //BC_RESULT_ONE
5754 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5755 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005756 size_t *ptr;
5757
5758 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005759 if (s)
5760 return s;
5761 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005762 if (sc) {
5763 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005764 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005765 }
5766 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005767 if (val < BC_NUM_MIN_BASE)
5768 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005769 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005770 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005771 }
5772
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005773 if (val > max)
5774 return bc_error(msg[s]);
5775 if (!sc)
5776 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005777
5778 *ptr = (size_t) val;
5779 s = BC_STATUS_SUCCESS;
5780 }
5781
5782 bc_num_init(&res.d.n, l->len);
5783 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005784 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005785
5786 return s;
5787}
5788
Denys Vlasenko416ce762018-12-02 20:57:17 +01005789#if !ENABLE_DC
5790#define bc_program_pushVar(code, bgn, pop, copy) \
5791 bc_program_pushVar(code, bgn)
5792// for bc, 'pop' and 'copy' are always false
5793#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005794static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005795 bool pop, bool copy)
5796{
5797 BcStatus s = BC_STATUS_SUCCESS;
5798 BcResult r;
5799 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005800
5801 r.t = BC_RESULT_VAR;
5802 r.d.id.name = name;
5803
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005804#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005805 {
5806 BcVec *v = bc_program_search(name, true);
5807 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005808
Denys Vlasenko416ce762018-12-02 20:57:17 +01005809 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005810
Denys Vlasenko416ce762018-12-02 20:57:17 +01005811 if (!BC_PROG_STACK(v, 2 - copy)) {
5812 free(name);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005813 return bc_error("stack has too few elements");
Denys Vlasenko416ce762018-12-02 20:57:17 +01005814 }
5815
Gavin Howard01055ba2018-11-03 11:00:21 -06005816 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005817 name = NULL;
5818
5819 if (!BC_PROG_STR(num)) {
5820
5821 r.t = BC_RESULT_TEMP;
5822
5823 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5824 bc_num_copy(&r.d.n, num);
5825 }
5826 else {
5827 r.t = BC_RESULT_STR;
5828 r.d.id.idx = num->rdx;
5829 }
5830
5831 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005832 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005833 }
5834#endif // ENABLE_DC
5835
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005836 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005837
5838 return s;
5839}
5840
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005841static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005842 char inst)
5843{
5844 BcStatus s = BC_STATUS_SUCCESS;
5845 BcResult r;
5846 BcNum *num;
5847
5848 r.d.id.name = bc_program_name(code, bgn);
5849
5850 if (inst == BC_INST_ARRAY) {
5851 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005852 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005853 }
5854 else {
5855
5856 BcResult *operand;
5857 unsigned long temp;
5858
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005859 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005860 if (s) goto err;
5861 s = bc_num_ulong(num, &temp);
5862 if (s) goto err;
5863
5864 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005865 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005866 goto err;
5867 }
5868
5869 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005870 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005871 }
5872
5873err:
5874 if (s) free(r.d.id.name);
5875 return s;
5876}
5877
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005878#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005879static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005880{
5881 BcStatus s;
5882 BcResult *ptr, res, copy;
5883 BcNum *num = NULL;
5884 char inst2 = inst;
5885
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005886 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005887 if (s) return s;
5888
5889 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5890 copy.t = BC_RESULT_TEMP;
5891 bc_num_init(&copy.d.n, num->len);
5892 bc_num_copy(&copy.d.n, num);
5893 }
5894
5895 res.t = BC_RESULT_ONE;
5896 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5897 BC_INST_ASSIGN_PLUS :
5898 BC_INST_ASSIGN_MINUS;
5899
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005900 bc_vec_push(&G.prog.results, &res);
5901 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005902
5903 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005904 bc_vec_pop(&G.prog.results);
5905 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005906 }
5907
5908 return s;
5909}
5910
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005911static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005912{
5913 BcStatus s = BC_STATUS_SUCCESS;
5914 BcInstPtr ip;
5915 size_t i, nparams = bc_program_index(code, idx);
5916 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005917 BcId *a;
5918 BcResultData param;
5919 BcResult *arg;
5920
5921 ip.idx = 0;
5922 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005923 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005924
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005925 if (func->code.len == 0) {
5926 return bc_error("undefined function");
5927 }
5928 if (nparams != func->nparams) {
5929 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5930 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005931 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005932
5933 for (i = 0; i < nparams; ++i) {
5934
5935 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005936 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005937
5938 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005939 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005940
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005941 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005942 if (s) return s;
5943 }
5944
5945 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005946 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005947
5948 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005949 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005950
5951 if (a->idx) {
5952 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5953 bc_vec_push(v, &param.n);
5954 }
5955 else {
5956 bc_array_init(&param.v, true);
5957 bc_vec_push(v, &param.v);
5958 }
5959 }
5960
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005961 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005962
5963 return BC_STATUS_SUCCESS;
5964}
5965
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005966static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005967{
5968 BcStatus s;
5969 BcResult res;
5970 BcFunc *f;
5971 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005972 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06005973
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005974 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005975 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005976
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005977 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005978 res.t = BC_RESULT_TEMP;
5979
5980 if (inst == BC_INST_RET) {
5981
5982 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005983 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005984
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005985 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005986 if (s) return s;
5987 bc_num_init(&res.d.n, num->len);
5988 bc_num_copy(&res.d.n, num);
5989 }
5990 else {
5991 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5992 bc_num_zero(&res.d.n);
5993 }
5994
5995 // We need to pop arguments as well, so this takes that into account.
5996 for (i = 0; i < f->autos.len; ++i) {
5997
5998 BcVec *v;
5999 BcId *a = bc_vec_item(&f->autos, i);
6000
Denys Vlasenkodf515392018-12-02 19:27:48 +01006001 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006002 bc_vec_pop(v);
6003 }
6004
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006005 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6006 bc_vec_push(&G.prog.results, &res);
6007 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006008
6009 return BC_STATUS_SUCCESS;
6010}
6011#endif // ENABLE_BC
6012
6013static unsigned long bc_program_scale(BcNum *n)
6014{
6015 return (unsigned long) n->rdx;
6016}
6017
6018static unsigned long bc_program_len(BcNum *n)
6019{
6020 unsigned long len = n->len;
6021 size_t i;
6022
6023 if (n->rdx != n->len) return len;
6024 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6025
6026 return len;
6027}
6028
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006029static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006030{
6031 BcStatus s;
6032 BcResult *opnd;
6033 BcNum *num = NULL;
6034 BcResult res;
6035 bool len = inst == BC_INST_LENGTH;
6036
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006037 if (!BC_PROG_STACK(&G.prog.results, 1))
6038 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006039 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006040
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006041 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006042 if (s) return s;
6043
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006044#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006045 if (!BC_PROG_NUM(opnd, num) && !len)
6046 return bc_error("variable is wrong type");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006047#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006048
6049 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6050
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006051 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006052#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006053 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006054 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006055 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006056#endif
6057#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006058 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6059
6060 char **str;
6061 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6062
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006063 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006064 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006065 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006066#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006067 else {
6068 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006069 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006070 }
6071
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006072 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006073
6074 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006075}
6076
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006077#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006078static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006079{
6080 BcStatus s;
6081 BcResult *opd1, *opd2, res, res2;
6082 BcNum *n1, *n2 = NULL;
6083
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006084 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006085 if (s) return s;
6086
6087 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6088 bc_num_init(&res2.d.n, n2->len);
6089
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006090 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006091 if (s) goto err;
6092
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006093 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006094 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006095 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006096
6097 return s;
6098
6099err:
6100 bc_num_free(&res2.d.n);
6101 bc_num_free(&res.d.n);
6102 return s;
6103}
6104
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006105static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006106{
6107 BcStatus s;
6108 BcResult *r1, *r2, *r3, res;
6109 BcNum *n1, *n2, *n3;
6110
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006111 if (!BC_PROG_STACK(&G.prog.results, 3))
6112 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006113 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006114 if (s) return s;
6115
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006116 r1 = bc_vec_item_rev(&G.prog.results, 2);
6117 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006118 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006119 if (!BC_PROG_NUM(r1, n1))
6120 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006121
6122 // Make sure that the values have their pointers updated, if necessary.
6123 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6124
6125 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006126 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006127 if (s) return s;
6128 }
6129
6130 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006131 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006132 if (s) return s;
6133 }
6134 }
6135
6136 bc_num_init(&res.d.n, n3->len);
6137 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6138 if (s) goto err;
6139
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006140 bc_vec_pop(&G.prog.results);
6141 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006142
6143 return s;
6144
6145err:
6146 bc_num_free(&res.d.n);
6147 return s;
6148}
6149
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006150static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006151{
Gavin Howard01055ba2018-11-03 11:00:21 -06006152 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006153 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006154
6155 res.t = BC_RESULT_TEMP;
6156
6157 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006158 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006159 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006160}
6161
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006162static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006163{
6164 BcStatus s;
6165 BcResult *r, res;
6166 BcNum *num = NULL, n;
6167 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006168 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006169 unsigned long val;
6170
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006171 if (!BC_PROG_STACK(&G.prog.results, 1))
6172 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006173 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006174
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006175 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006176 if (s) return s;
6177
6178 if (BC_PROG_NUM(r, num)) {
6179
6180 bc_num_init(&n, BC_NUM_DEF_SIZE);
6181 bc_num_copy(&n, num);
6182 bc_num_truncate(&n, n.rdx);
6183
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006184 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006185 if (s) goto num_err;
6186 s = bc_num_ulong(&n, &val);
6187 if (s) goto num_err;
6188
6189 c = (char) val;
6190
6191 bc_num_free(&n);
6192 }
6193 else {
6194 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006195 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006196 c = str2[0];
6197 }
6198
6199 str = xmalloc(2);
6200 str[0] = c;
6201 str[1] = '\0';
6202
6203 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006204 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006205
6206 if (idx != len + BC_PROG_REQ_FUNCS) {
6207
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006208 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6209 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006210 len = idx;
6211 break;
6212 }
6213 }
6214
6215 free(str);
6216 }
6217 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006218 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006219
6220 res.t = BC_RESULT_STR;
6221 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006222 bc_vec_pop(&G.prog.results);
6223 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006224
6225 return BC_STATUS_SUCCESS;
6226
6227num_err:
6228 bc_num_free(&n);
6229 return s;
6230}
6231
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006232static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006233{
6234 BcStatus s;
6235 BcResult *r;
6236 BcNum *n = NULL;
6237 size_t idx;
6238 char *str;
6239
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006240 if (!BC_PROG_STACK(&G.prog.results, 1))
6241 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006242 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006243
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006244 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006245 if (s) return s;
6246
6247 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006248 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006249 else {
6250 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006251 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006252 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006253 }
6254
6255 return s;
6256}
6257
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006258static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006259{
6260 BcStatus s;
6261 BcResult *opnd;
6262 BcNum *num = NULL;
6263 unsigned long val;
6264
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006265 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006266 if (s) return s;
6267 s = bc_num_ulong(num, &val);
6268 if (s) return s;
6269
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006270 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 if (G.prog.stack.len < val)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006273 return bc_error("stack has too few elements");
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006274 if (G.prog.stack.len == val)
6275 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006276
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006277 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006278
6279 return s;
6280}
6281
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006282static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006283 bool cond)
6284{
6285 BcStatus s = BC_STATUS_SUCCESS;
6286 BcResult *r;
6287 char **str;
6288 BcFunc *f;
6289 BcParse prs;
6290 BcInstPtr ip;
6291 size_t fidx, sidx;
6292 BcNum *n;
6293 bool exec;
6294
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006295 if (!BC_PROG_STACK(&G.prog.results, 1))
6296 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006297
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006298 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006299
6300 if (cond) {
6301
Gavin Howard01055ba2018-11-03 11:00:21 -06006302 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6303
6304 if (code[*bgn] == BC_PARSE_STREND)
6305 (*bgn) += 1;
6306 else
6307 else_name = bc_program_name(code, bgn);
6308
6309 exec = r->d.n.len != 0;
6310
6311 if (exec)
6312 name = then_name;
6313 else if (else_name != NULL) {
6314 exec = true;
6315 name = else_name;
6316 }
6317
6318 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006319 BcVec *v;
6320 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006321 n = bc_vec_top(v);
6322 }
6323
6324 free(then_name);
6325 free(else_name);
6326
6327 if (!exec) goto exit;
6328 if (!BC_PROG_STR(n)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006329 s = bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006330 goto exit;
6331 }
6332
6333 sidx = n->rdx;
6334 }
6335 else {
6336
6337 if (r->t == BC_RESULT_STR)
6338 sidx = r->d.id.idx;
6339 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006340 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006341 if (s || !BC_PROG_STR(n)) goto exit;
6342 sidx = n->rdx;
6343 }
6344 else
6345 goto exit;
6346 }
6347
6348 fidx = sidx + BC_PROG_REQ_FUNCS;
6349
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006350 str = bc_vec_item(&G.prog.strs, sidx);
6351 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006352
6353 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006354 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006355 s = bc_parse_text(&prs, *str);
6356 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006357 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006358 if (s) goto err;
6359
6360 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006361 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06006362 goto err;
6363 }
6364
6365 bc_parse_free(&prs);
6366 }
6367
6368 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006369 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006370 ip.func = fidx;
6371
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006372 bc_vec_pop(&G.prog.results);
6373 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006374
6375 return BC_STATUS_SUCCESS;
6376
6377err:
6378 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006379 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006380 bc_vec_npop(&f->code, f->code.len);
6381exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006382 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006383 return s;
6384}
6385#endif // ENABLE_DC
6386
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006387static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006388{
Gavin Howard01055ba2018-11-03 11:00:21 -06006389 BcResult res;
6390 unsigned long val;
6391
6392 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6393 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006394 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006395 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006396 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006397 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006398 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006399
6400 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006401 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006402 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006403}
6404
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006405static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006406{
Gavin Howard01055ba2018-11-03 11:00:21 -06006407 BcId entry, *entry_ptr;
6408 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006409 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006410
6411 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006412 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006413
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006414 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6415 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006416
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006417 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006418 *idx = entry_ptr->idx;
6419
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006420 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006421
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006422 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006423
6424 // We need to reset these, so the function can be repopulated.
6425 func->nparams = 0;
6426 bc_vec_npop(&func->autos, func->autos.len);
6427 bc_vec_npop(&func->code, func->code.len);
6428 bc_vec_npop(&func->labels, func->labels.len);
6429 }
6430 else {
6431 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006432 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006433 }
6434}
6435
Denys Vlasenkod38af482018-12-04 19:11:02 +01006436// Called when parsing or execution detects a failure,
6437// resets execution structures.
6438static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006439{
6440 BcFunc *f;
6441 BcInstPtr *ip;
6442
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006443 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6444 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006445
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006446 f = bc_vec_item(&G.prog.fns, 0);
6447 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006448 ip->idx = f->code.len;
6449
Denys Vlasenkod38af482018-12-04 19:11:02 +01006450 // If !tty, no need to check for ^C: we don't have ^C handler,
6451 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006452}
6453
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006454static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006455{
6456 BcStatus s = BC_STATUS_SUCCESS;
6457 size_t idx;
6458 BcResult r, *ptr;
6459 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006460 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6461 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006462 char *code = func->code.v;
6463 bool cond = false;
6464
6465 while (!s && ip->idx < func->code.len) {
6466
6467 char inst = code[(ip->idx)++];
6468
6469 switch (inst) {
6470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006471#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006472 case BC_INST_JUMP_ZERO:
6473 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006474 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006475 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006476 cond = !bc_num_cmp(num, &G.prog.zero);
6477 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006478 }
6479 // Fallthrough.
6480 case BC_INST_JUMP:
6481 {
6482 size_t *addr;
6483 idx = bc_program_index(code, &ip->idx);
6484 addr = bc_vec_item(&func->labels, idx);
6485 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6486 break;
6487 }
6488
6489 case BC_INST_CALL:
6490 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006491 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006492 break;
6493 }
6494
6495 case BC_INST_INC_PRE:
6496 case BC_INST_DEC_PRE:
6497 case BC_INST_INC_POST:
6498 case BC_INST_DEC_POST:
6499 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006500 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006501 break;
6502 }
6503
6504 case BC_INST_HALT:
6505 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006506 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006507 break;
6508 }
6509
6510 case BC_INST_RET:
6511 case BC_INST_RET0:
6512 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006513 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006514 break;
6515 }
6516
6517 case BC_INST_BOOL_OR:
6518 case BC_INST_BOOL_AND:
6519#endif // ENABLE_BC
6520 case BC_INST_REL_EQ:
6521 case BC_INST_REL_LE:
6522 case BC_INST_REL_GE:
6523 case BC_INST_REL_NE:
6524 case BC_INST_REL_LT:
6525 case BC_INST_REL_GT:
6526 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006527 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006528 break;
6529 }
6530
6531 case BC_INST_READ:
6532 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006533 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006534 break;
6535 }
6536
6537 case BC_INST_VAR:
6538 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006539 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006540 break;
6541 }
6542
6543 case BC_INST_ARRAY_ELEM:
6544 case BC_INST_ARRAY:
6545 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006546 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006547 break;
6548 }
6549
6550 case BC_INST_LAST:
6551 {
6552 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006553 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006554 break;
6555 }
6556
6557 case BC_INST_IBASE:
6558 case BC_INST_SCALE:
6559 case BC_INST_OBASE:
6560 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006561 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006562 break;
6563 }
6564
6565 case BC_INST_SCALE_FUNC:
6566 case BC_INST_LENGTH:
6567 case BC_INST_SQRT:
6568 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006569 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006570 break;
6571 }
6572
6573 case BC_INST_NUM:
6574 {
6575 r.t = BC_RESULT_CONSTANT;
6576 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006577 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006578 break;
6579 }
6580
6581 case BC_INST_POP:
6582 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006583 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006584 s = bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006585 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006586 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006587 break;
6588 }
6589
6590 case BC_INST_POP_EXEC:
6591 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006592 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006593 break;
6594 }
6595
6596 case BC_INST_PRINT:
6597 case BC_INST_PRINT_POP:
6598 case BC_INST_PRINT_STR:
6599 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006600 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006601 break;
6602 }
6603
6604 case BC_INST_STR:
6605 {
6606 r.t = BC_RESULT_STR;
6607 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006608 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006609 break;
6610 }
6611
6612 case BC_INST_POWER:
6613 case BC_INST_MULTIPLY:
6614 case BC_INST_DIVIDE:
6615 case BC_INST_MODULUS:
6616 case BC_INST_PLUS:
6617 case BC_INST_MINUS:
6618 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006619 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006620 break;
6621 }
6622
6623 case BC_INST_BOOL_NOT:
6624 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006625 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006626 if (s) return s;
6627
6628 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006629 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6630 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006631
6632 break;
6633 }
6634
6635 case BC_INST_NEG:
6636 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006637 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006638 break;
6639 }
6640
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006641#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006642 case BC_INST_ASSIGN_POWER:
6643 case BC_INST_ASSIGN_MULTIPLY:
6644 case BC_INST_ASSIGN_DIVIDE:
6645 case BC_INST_ASSIGN_MODULUS:
6646 case BC_INST_ASSIGN_PLUS:
6647 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006648#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006649 case BC_INST_ASSIGN:
6650 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006651 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006652 break;
6653 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006654#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006655 case BC_INST_MODEXP:
6656 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006657 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006658 break;
6659 }
6660
6661 case BC_INST_DIVMOD:
6662 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006663 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006664 break;
6665 }
6666
6667 case BC_INST_EXECUTE:
6668 case BC_INST_EXEC_COND:
6669 {
6670 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006671 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006672 break;
6673 }
6674
6675 case BC_INST_PRINT_STACK:
6676 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006677 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6678 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006679 break;
6680 }
6681
6682 case BC_INST_CLEAR_STACK:
6683 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006684 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006685 break;
6686 }
6687
6688 case BC_INST_STACK_LEN:
6689 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006690 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006691 break;
6692 }
6693
6694 case BC_INST_DUPLICATE:
6695 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006696 if (!BC_PROG_STACK(&G.prog.results, 1))
6697 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006698 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006699 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006700 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006701 break;
6702 }
6703
6704 case BC_INST_SWAP:
6705 {
6706 BcResult *ptr2;
6707
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006708 if (!BC_PROG_STACK(&G.prog.results, 2))
6709 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006710
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006711 ptr = bc_vec_item_rev(&G.prog.results, 0);
6712 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006713 memcpy(&r, ptr, sizeof(BcResult));
6714 memcpy(ptr, ptr2, sizeof(BcResult));
6715 memcpy(ptr2, &r, sizeof(BcResult));
6716
6717 break;
6718 }
6719
6720 case BC_INST_ASCIIFY:
6721 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006722 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006723 break;
6724 }
6725
6726 case BC_INST_PRINT_STREAM:
6727 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006728 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006729 break;
6730 }
6731
6732 case BC_INST_LOAD:
6733 case BC_INST_PUSH_VAR:
6734 {
6735 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006736 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006737 break;
6738 }
6739
6740 case BC_INST_PUSH_TO_VAR:
6741 {
6742 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006743 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006744 free(name);
6745 break;
6746 }
6747
6748 case BC_INST_QUIT:
6749 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006750 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006751 quit();
6752 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006753 break;
6754 }
6755
6756 case BC_INST_NQUIT:
6757 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006758 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006759 break;
6760 }
6761#endif // ENABLE_DC
6762 }
6763
Denys Vlasenkod38af482018-12-04 19:11:02 +01006764 if (s || G_interrupt) {
6765 bc_program_reset();
6766 break;
6767 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006768
6769 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006770 ip = bc_vec_top(&G.prog.stack);
6771 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006772 code = func->code.v;
6773 }
6774
6775 return s;
6776}
6777
Denys Vlasenko00d77792018-11-30 23:13:42 +01006778static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006779{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006780 printf("%s "BB_VER"\n"
6781 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006782 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006783 "This is free software with ABSOLUTELY NO WARRANTY\n"
6784 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006785}
6786
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006787#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006788static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006789{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006790 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6791
Gavin Howard01055ba2018-11-03 11:00:21 -06006792 BcVec v;
6793 char *env_args = getenv(bc_args_env_name), *buf;
6794
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006795 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006796
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006797 G.env_args = xstrdup(env_args);
6798 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006799
6800 bc_vec_init(&v, sizeof(char *), NULL);
6801 bc_vec_push(&v, &bc_args_env_name);
6802
6803 while (*buf != 0) {
6804 if (!isspace(*buf)) {
6805 bc_vec_push(&v, &buf);
6806 while (*buf != 0 && !isspace(*buf)) ++buf;
6807 if (*buf != 0) (*(buf++)) = '\0';
6808 }
6809 else
6810 ++buf;
6811 }
6812
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006813 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006814
6815 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816}
6817#endif // ENABLE_BC
6818
6819static size_t bc_vm_envLen(const char *var)
6820{
6821 char *lenv = getenv(var);
6822 size_t i, len = BC_NUM_PRINT_WIDTH;
6823 int num;
6824
6825 if (!lenv) return len;
6826
6827 len = strlen(lenv);
6828
6829 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6830 if (num) {
6831 len = (size_t) atoi(lenv) - 1;
6832 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6833 }
6834 else
6835 len = BC_NUM_PRINT_WIDTH;
6836
6837 return len;
6838}
6839
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006840static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006841{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006842 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006843
Gavin Howard01055ba2018-11-03 11:00:21 -06006844 if (s) return s;
6845
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006846 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006847 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006848 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006849 }
6850
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006851 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006852 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006853 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006854 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006855 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006856 }
6857
6858 return s;
6859}
6860
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006861static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006862{
6863 BcStatus s;
6864 char *data;
6865 BcFunc *main_func;
6866 BcInstPtr *ip;
6867
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006868 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006869 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01006870 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006871
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006872 bc_lex_file(&G.prs.l, file);
6873 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006874 if (s) goto err;
6875
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006876 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6877 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006878
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006879 if (main_func->code.len < ip->idx)
6880 s = bc_error("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006881
6882err:
6883 free(data);
6884 return s;
6885}
6886
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006887static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006888{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006889 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006890 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006891 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006892 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006893
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006894 G.prog.file = bc_program_stdin_name;
6895 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006896
6897 bc_vec_init(&buffer, sizeof(char), NULL);
6898 bc_vec_init(&buf, sizeof(char), NULL);
6899 bc_vec_pushByte(&buffer, '\0');
6900
6901 // This loop is complex because the vm tries not to send any lines that end
6902 // with a backslash to the parser. The reason for that is because the parser
6903 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6904 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006905 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006906
6907 char *string = buf.v;
6908
6909 len = buf.len - 1;
6910
6911 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006912 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006913 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006914 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006915 str += 1;
6916 }
6917 else if (len > 1 || comment) {
6918
6919 for (i = 0; i < len; ++i) {
6920
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006921 bool notend = len > i + 1;
6922 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006923
6924 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006925 if (G.sbgn == G.send)
6926 str ^= c == G.sbgn;
6927 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006928 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006929 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006930 str += 1;
6931 }
6932
6933 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6934 comment = true;
6935 break;
6936 }
6937 else if (c == '*' && notend && comment && string[i + 1] == '/')
6938 comment = false;
6939 }
6940
6941 if (str || comment || string[len - 2] == '\\') {
6942 bc_vec_concat(&buffer, buf.v);
6943 continue;
6944 }
6945 }
6946
6947 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006948 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006949 if (s) {
6950 fflush_and_check();
6951 fputs("ready for more input\n", stderr);
6952 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006953
6954 bc_vec_npop(&buffer, buffer.len);
6955 }
6956
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006957 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006958 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006959 }
6960 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006961 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006962 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006963
Gavin Howard01055ba2018-11-03 11:00:21 -06006964 bc_vec_free(&buf);
6965 bc_vec_free(&buffer);
6966 return s;
6967}
6968
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006969static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006970{
6971 BcStatus s = BC_STATUS_SUCCESS;
6972 size_t i;
6973
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006974#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006975 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006976
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006977 bc_lex_file(&G.prs.l, bc_lib_name);
6978 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06006979
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006980 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6981 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006982
6983 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006984 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06006985 if (s) return s;
6986 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006987#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006988
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006989 for (i = 0; !s && i < G.files.len; ++i)
6990 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006991 if (s) {
6992 if (!G.tty)
6993 return s;
6994 fflush_and_check();
6995 fputs("ready for more input\n", stderr);
6996 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006997
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006998 if (IS_BC || !G.files.len)
6999 s = bc_vm_stdin();
7000 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7001 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007002
Denys Vlasenko00d77792018-11-30 23:13:42 +01007003 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007004}
7005
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007006#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007007static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007008{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007009 bc_num_free(&G.prog.ib);
7010 bc_num_free(&G.prog.ob);
7011 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007012# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007013 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007014# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007015 bc_vec_free(&G.prog.fns);
7016 bc_vec_free(&G.prog.fn_map);
7017 bc_vec_free(&G.prog.vars);
7018 bc_vec_free(&G.prog.var_map);
7019 bc_vec_free(&G.prog.arrs);
7020 bc_vec_free(&G.prog.arr_map);
7021 bc_vec_free(&G.prog.strs);
7022 bc_vec_free(&G.prog.consts);
7023 bc_vec_free(&G.prog.results);
7024 bc_vec_free(&G.prog.stack);
7025 bc_num_free(&G.prog.last);
7026 bc_num_free(&G.prog.zero);
7027 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007028}
7029
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007030static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007031{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007032 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007033 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007034 bc_parse_free(&G.prs);
7035 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007036}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007037#endif
7038
7039static void bc_program_init(size_t line_len)
7040{
7041 size_t idx;
7042 BcInstPtr ip;
7043
7044 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7045 memset(&ip, 0, sizeof(BcInstPtr));
7046
7047 /* G.prog.nchars = G.prog.scale = 0; - already is */
7048 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007049
7050 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7051 bc_num_ten(&G.prog.ib);
7052 G.prog.ib_t = 10;
7053
7054 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7055 bc_num_ten(&G.prog.ob);
7056 G.prog.ob_t = 10;
7057
7058 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7059 bc_num_ten(&G.prog.hexb);
7060 G.prog.hexb.num[0] = 6;
7061
7062#if ENABLE_DC
7063 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7064 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7065#endif
7066
7067 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7068 bc_num_zero(&G.prog.last);
7069
7070 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7071 bc_num_zero(&G.prog.zero);
7072
7073 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7074 bc_num_one(&G.prog.one);
7075
7076 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7077 bc_map_init(&G.prog.fn_map);
7078
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007079 bc_program_addFunc(xstrdup("(main)"), &idx);
7080 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007081
7082 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7083 bc_map_init(&G.prog.var_map);
7084
7085 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7086 bc_map_init(&G.prog.arr_map);
7087
7088 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7089 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7090 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7091 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7092 bc_vec_push(&G.prog.stack, &ip);
7093}
Gavin Howard01055ba2018-11-03 11:00:21 -06007094
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007095static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007096{
Gavin Howard01055ba2018-11-03 11:00:21 -06007097 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007098
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007099 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007100
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007101 if (IS_BC) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007102 if (getenv("POSIXLY_CORRECT"))
7103 G.flags |= BC_FLAG_S;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007104 bc_vm_envArgs();
7105 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007106
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007107 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007108 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007109 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007110 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007111 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007112 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007113}
7114
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007115static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007116 const char *env_len)
7117{
7118 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007119
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007120 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007121 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007122
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007123 G.ttyin = isatty(0);
7124 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007125
Denys Vlasenkod38af482018-12-04 19:11:02 +01007126 if (G.ttyin) {
7127#if ENABLE_FEATURE_BC_SIGNALS
7128 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7129#endif
7130 if (!(G.flags & BC_FLAG_Q))
7131 bc_vm_info();
7132 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007133 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007134
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007135#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007136 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007137#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007138 return st;
7139}
7140
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007141#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007142int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7143int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007144{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007145 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007146 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007147
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007148 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007149}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007150#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007151
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007152#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007153int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7154int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007155{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007156 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007157 G.sbgn = '[';
7158 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007159
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007160 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007161}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007162#endif