blob: 148e340a5c3013fe85f3febca6405652c4678368 [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 {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100733 smallint ttyin;
734 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600735 char sbgn;
736 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600737
738 BcParse prs;
739 BcProgram prog;
740
Gavin Howard01055ba2018-11-03 11:00:21 -0600741 BcVec files;
742
743 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100744} FIX_ALIASING;
745#define G (*ptr_to_globals)
746#define INIT_G() do { \
747 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
748} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100749#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
750#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
751#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100752#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600753
Gavin Howard01055ba2018-11-03 11:00:21 -0600754
Denys Vlasenko00d77792018-11-30 23:13:42 +0100755#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
756
Denys Vlasenko00d77792018-11-30 23:13:42 +0100757static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600758
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100759#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600760static const BcLexKeyword bc_lex_kws[20] = {
761 BC_LEX_KW_ENTRY("auto", 4, true),
762 BC_LEX_KW_ENTRY("break", 5, true),
763 BC_LEX_KW_ENTRY("continue", 8, false),
764 BC_LEX_KW_ENTRY("define", 6, true),
765 BC_LEX_KW_ENTRY("else", 4, false),
766 BC_LEX_KW_ENTRY("for", 3, true),
767 BC_LEX_KW_ENTRY("halt", 4, false),
768 BC_LEX_KW_ENTRY("ibase", 5, true),
769 BC_LEX_KW_ENTRY("if", 2, true),
770 BC_LEX_KW_ENTRY("last", 4, false),
771 BC_LEX_KW_ENTRY("length", 6, true),
772 BC_LEX_KW_ENTRY("limits", 6, false),
773 BC_LEX_KW_ENTRY("obase", 5, true),
774 BC_LEX_KW_ENTRY("print", 5, false),
775 BC_LEX_KW_ENTRY("quit", 4, true),
776 BC_LEX_KW_ENTRY("read", 4, false),
777 BC_LEX_KW_ENTRY("return", 6, true),
778 BC_LEX_KW_ENTRY("scale", 5, true),
779 BC_LEX_KW_ENTRY("sqrt", 4, true),
780 BC_LEX_KW_ENTRY("while", 5, true),
781};
782
783// This is an array that corresponds to token types. An entry is
784// true if the token is valid in an expression, false otherwise.
785static const bool bc_parse_exprs[] = {
786 false, false, true, true, true, true, true, true, true, true, true, true,
787 true, true, true, true, true, true, true, true, true, true, true, true,
788 true, true, true, false, false, true, true, false, false, false, false,
789 false, false, false, true, true, false, false, false, false, false, false,
790 false, true, false, true, true, true, true, false, false, true, false, true,
791 true, false,
792};
793
794// This is an array of data for operators that correspond to token types.
795static const BcOp bc_parse_ops[] = {
796 { 0, false }, { 0, false },
797 { 1, false },
798 { 2, false },
799 { 3, true }, { 3, true }, { 3, true },
800 { 4, true }, { 4, true },
801 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
802 { 1, false },
803 { 7, true }, { 7, true },
804 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
805 { 5, false }, { 5, false },
806};
807
808// These identify what tokens can come after expressions in certain cases.
809static const BcParseNext bc_parse_next_expr =
810 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
811static const BcParseNext bc_parse_next_param =
812 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
813static const BcParseNext bc_parse_next_print =
814 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
815static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
816static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
817static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
818static const BcParseNext bc_parse_next_read =
819 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
820#endif // ENABLE_BC
821
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100822#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600823static const BcLexType dc_lex_regs[] = {
824 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
825 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
826 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
827 BC_LEX_STORE_PUSH,
828};
829
830static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
831
832static const BcLexType dc_lex_tokens[] = {
833 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
834 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
835 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
836 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
838 BC_LEX_INVALID, BC_LEX_INVALID,
839 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
840 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
843 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
844 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
845 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
847 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
848 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
849 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
850 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
852 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
853 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
854 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
855 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
856 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
857 BC_LEX_INVALID
858};
859
860static const BcInst dc_parse_insts[] = {
861 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
862 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
863 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
871 BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
874 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
876 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
878 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
879 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
880 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
881 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
883 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
884};
885#endif // ENABLE_DC
886
Gavin Howard01055ba2018-11-03 11:00:21 -0600887static const BcNumBinaryOp bc_program_ops[] = {
888 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
889};
890
891static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600892
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100893#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600894static const char *bc_lib_name = "gen/lib.bc";
895
896static const char bc_lib[] = {
897 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
898 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
899 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
900 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,
901 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
902 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
903 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,
904 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
905 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
906 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,
907 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
908 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
909 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
910 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
911 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
912 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
913 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
914 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
915 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
916 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
917 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
918 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
919 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
920 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,
921 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
922 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,
923 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
924 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
925 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
926 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
927 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
928 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,
929 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
930 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
931 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
932 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
933 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,
934 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
935 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
936 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
937 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
938 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
939 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
940 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
941 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
942 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
943 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
944 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,
945 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,
946 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
947 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,
948 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,
949 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,
950 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
951 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
952 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,
953 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,
954 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,
955 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
956 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,
957 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
958 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
959 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
960 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,
961 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
962 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
963 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
964 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
965 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
966 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
967 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
968 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
969 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
970 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
971 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
972 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
973 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
974 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
975 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
976 117,114,110,40,97,42,114,47,49,41,10,125,10,0
977};
978#endif // ENABLE_BC
979
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100980static void fflush_and_check(void)
981{
982 fflush_all();
983 if (ferror(stdout) || ferror(stderr))
984 bb_perror_msg_and_die("output error");
985}
986
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100987static void quit(void) NORETURN;
988static void quit(void)
989{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100990 if (ferror(stdin))
991 bb_perror_msg_and_die("input error");
992 fflush_and_check();
993 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100994}
995
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100996static int bc_error(const char *fmt, ...)
997{
998 va_list p;
999
1000 va_start(p, fmt);
1001 bb_verror_msg(fmt, p, NULL);
1002 va_end(p);
1003 if (!G.ttyin)
1004 exit(1);
1005 return BC_STATUS_FAILURE;
1006}
1007
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001008static int bc_posix_error(const char *fmt, ...)
1009{
1010 va_list p;
1011
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001012 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001013 return BC_STATUS_SUCCESS;
1014
1015 va_start(p, fmt);
1016 bb_verror_msg(fmt, p, NULL);
1017 va_end(p);
1018
1019 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001020 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001021 return BC_STATUS_SUCCESS; // no, it's a warning
1022 if (!G.ttyin)
1023 exit(1);
1024 return BC_STATUS_FAILURE;
1025}
1026
Gavin Howard01055ba2018-11-03 11:00:21 -06001027static void bc_vec_grow(BcVec *v, size_t n)
1028{
1029 size_t cap = v->cap * 2;
1030 while (cap < v->len + n) cap *= 2;
1031 v->v = xrealloc(v->v, v->size * cap);
1032 v->cap = cap;
1033}
1034
1035static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1036{
1037 v->size = esize;
1038 v->cap = BC_VEC_START_CAP;
1039 v->len = 0;
1040 v->dtor = dtor;
1041 v->v = xmalloc(esize * BC_VEC_START_CAP);
1042}
1043
1044static void bc_vec_expand(BcVec *v, size_t req)
1045{
1046 if (v->cap < req) {
1047 v->v = xrealloc(v->v, v->size * req);
1048 v->cap = req;
1049 }
1050}
1051
1052static void bc_vec_npop(BcVec *v, size_t n)
1053{
1054 if (!v->dtor)
1055 v->len -= n;
1056 else {
1057 size_t len = v->len - n;
1058 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1059 }
1060}
1061
1062static void bc_vec_push(BcVec *v, const void *data)
1063{
1064 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1065 memmove(v->v + (v->size * v->len), data, v->size);
1066 v->len += 1;
1067}
1068
1069static void bc_vec_pushByte(BcVec *v, char data)
1070{
1071 bc_vec_push(v, &data);
1072}
1073
1074static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1075{
1076 if (idx == v->len)
1077 bc_vec_push(v, data);
1078 else {
1079
1080 char *ptr;
1081
1082 if (v->len == v->cap) bc_vec_grow(v, 1);
1083
1084 ptr = v->v + v->size * idx;
1085
1086 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1087 memmove(ptr, data, v->size);
1088 }
1089}
1090
1091static void bc_vec_string(BcVec *v, size_t len, const char *str)
1092{
1093 bc_vec_npop(v, v->len);
1094 bc_vec_expand(v, len + 1);
1095 memcpy(v->v, str, len);
1096 v->len = len;
1097
1098 bc_vec_pushByte(v, '\0');
1099}
1100
1101static void bc_vec_concat(BcVec *v, const char *str)
1102{
1103 size_t len;
1104
1105 if (v->len == 0) bc_vec_pushByte(v, '\0');
1106
1107 len = v->len + strlen(str);
1108
1109 if (v->cap < len) bc_vec_grow(v, len - v->len);
1110 strcat(v->v, str);
1111
1112 v->len = len;
1113}
1114
1115static void *bc_vec_item(const BcVec *v, size_t idx)
1116{
1117 return v->v + v->size * idx;
1118}
1119
1120static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1121{
1122 return v->v + v->size * (v->len - idx - 1);
1123}
1124
1125static void bc_vec_free(void *vec)
1126{
1127 BcVec *v = (BcVec *) vec;
1128 bc_vec_npop(v, v->len);
1129 free(v->v);
1130}
1131
1132static size_t bc_map_find(const BcVec *v, const void *ptr)
1133{
1134 size_t low = 0, high = v->len;
1135
1136 while (low < high) {
1137
1138 size_t mid = (low + high) / 2;
1139 BcId *id = bc_vec_item(v, mid);
1140 int result = bc_id_cmp(ptr, id);
1141
1142 if (result == 0)
1143 return mid;
1144 else if (result < 0)
1145 high = mid;
1146 else
1147 low = mid + 1;
1148 }
1149
1150 return low;
1151}
1152
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001153static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001154{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001155 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001156
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001157 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001158 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001159 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1160 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001161 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001162 bc_vec_pushAt(v, ptr, n);
1163 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001164}
1165
1166static size_t bc_map_index(const BcVec *v, const void *ptr)
1167{
1168 size_t i = bc_map_find(v, ptr);
1169 if (i >= v->len) return BC_VEC_INVALID_IDX;
1170 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1171}
1172
1173static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1174{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001175 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001176
Denys Vlasenko00d77792018-11-30 23:13:42 +01001177 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001178 int i;
1179 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001180
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001181 bad_chars = 0;
1182 bc_vec_npop(vec, vec->len);
1183
1184 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001185#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001186 if (bb_got_signal) { // ^C was pressed
1187 intr:
1188 bb_got_signal = 0; // resets G_interrupt to zero
1189 fputs(IS_BC
1190 ? "\ninterrupt (type \"quit\" to exit)\n"
1191 : "\ninterrupt (type \"q\" to exit)\n"
1192 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001193 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001194#endif
1195 if (G.ttyin && !G_posix)
1196 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001197
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001198#if ENABLE_FEATURE_BC_SIGNALS
1199 errno = 0;
1200#endif
1201 do {
1202 i = fgetc(stdin);
1203 if (i == EOF) {
1204#if ENABLE_FEATURE_BC_SIGNALS
1205 // Both conditions appear simultaneously, check both just in case
1206 if (errno == EINTR || bb_got_signal) {
1207 // ^C was pressed
1208 clearerr(stdin);
1209 goto intr;
1210 }
1211#endif
1212 if (ferror(stdin))
1213 quit(); // this emits error message
1214 G.eof = 1;
1215 // Note: EOF does not append '\n', therefore:
1216 // printf 'print 123\n' | bc - works
1217 // printf 'print 123' | bc - fails (syntax error)
1218 break;
1219 }
1220
1221 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1222 || i > 0x7e
1223 ) {
1224 // Bad chars on this line, ignore entire line
1225 bc_error("illegal character 0x%02x", i);
1226 bad_chars = 1;
1227 }
1228 c = (char) i;
1229 bc_vec_push(vec, &c);
1230 } while (i != '\n');
1231 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001232
1233 bc_vec_pushByte(vec, '\0');
1234
1235 return BC_STATUS_SUCCESS;
1236}
1237
Denys Vlasenkodf515392018-12-02 19:27:48 +01001238static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001239{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001240 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001241 size_t size = ((size_t) -1);
1242 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001243
Denys Vlasenkodf515392018-12-02 19:27:48 +01001244 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001245
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001246 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001247 char c = buf[i];
1248 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1249 || c > 0x7e
1250 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001251 free(buf);
1252 buf = NULL;
1253 break;
1254 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001255 }
1256
Denys Vlasenkodf515392018-12-02 19:27:48 +01001257 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001258}
1259
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001260static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001261{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001262 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001263 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001264
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001265 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001266#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001267 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001268 "extended-register\0" No_argument "x"
1269 "warn\0" No_argument "w"
1270 "version\0" No_argument "v"
1271 "standard\0" No_argument "s"
1272 "quiet\0" No_argument "q"
1273 "mathlib\0" No_argument "l"
1274 "interactive\0" No_argument "i"
1275 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001276#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001277 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001278#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001279 if (getenv("POSIXLY_CORRECT"))
1280 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001281
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001282 if (opts & 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 Vlasenkod70d4a02018-12-04 20:58:40 +01001286 for (i = optind; i < argc; ++i)
1287 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001288}
1289
1290static void bc_num_setToZero(BcNum *n, size_t scale)
1291{
1292 n->len = 0;
1293 n->neg = false;
1294 n->rdx = scale;
1295}
1296
1297static void bc_num_zero(BcNum *n)
1298{
1299 bc_num_setToZero(n, 0);
1300}
1301
1302static void bc_num_one(BcNum *n)
1303{
1304 bc_num_setToZero(n, 0);
1305 n->len = 1;
1306 n->num[0] = 1;
1307}
1308
1309static void bc_num_ten(BcNum *n)
1310{
1311 bc_num_setToZero(n, 0);
1312 n->len = 2;
1313 n->num[0] = 0;
1314 n->num[1] = 1;
1315}
1316
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001317static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001318 size_t len)
1319{
1320 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001321 for (i = 0; i < len; ++i) {
1322 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001323 a[i + j++] += 10;
1324 a[i + j] -= 1;
1325 }
1326 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001327}
1328
1329static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1330{
1331 size_t i;
1332 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001333 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001334 return BC_NUM_NEG(i + 1, c < 0);
1335}
1336
1337static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1338{
1339 size_t i, min, a_int, b_int, diff;
1340 BcDig *max_num, *min_num;
1341 bool a_max, neg = false;
1342 ssize_t cmp;
1343
1344 if (a == b) return 0;
1345 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1346 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1347 if (a->neg) {
1348 if (b->neg)
1349 neg = true;
1350 else
1351 return -1;
1352 }
1353 else if (b->neg)
1354 return 1;
1355
1356 a_int = BC_NUM_INT(a);
1357 b_int = BC_NUM_INT(b);
1358 a_int -= b_int;
1359 a_max = (a->rdx > b->rdx);
1360
1361 if (a_int != 0) return (ssize_t) a_int;
1362
1363 if (a_max) {
1364 min = b->rdx;
1365 diff = a->rdx - b->rdx;
1366 max_num = a->num + diff;
1367 min_num = b->num;
1368 }
1369 else {
1370 min = a->rdx;
1371 diff = b->rdx - a->rdx;
1372 max_num = b->num + diff;
1373 min_num = a->num;
1374 }
1375
1376 cmp = bc_num_compare(max_num, min_num, b_int + min);
1377 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1378
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001379 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001380 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1381 }
1382
1383 return 0;
1384}
1385
1386static void bc_num_truncate(BcNum *n, size_t places)
1387{
1388 if (places == 0) return;
1389
1390 n->rdx -= places;
1391
1392 if (n->len != 0) {
1393 n->len -= places;
1394 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1395 }
1396}
1397
1398static void bc_num_extend(BcNum *n, size_t places)
1399{
1400 size_t len = n->len + places;
1401
1402 if (places != 0) {
1403
1404 if (n->cap < len) bc_num_expand(n, len);
1405
1406 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1407 memset(n->num, 0, sizeof(BcDig) * places);
1408
1409 n->len += places;
1410 n->rdx += places;
1411 }
1412}
1413
1414static void bc_num_clean(BcNum *n)
1415{
1416 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1417 if (n->len == 0)
1418 n->neg = false;
1419 else if (n->len < n->rdx)
1420 n->len = n->rdx;
1421}
1422
1423static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1424{
1425 if (n->rdx < scale)
1426 bc_num_extend(n, scale - n->rdx);
1427 else
1428 bc_num_truncate(n, n->rdx - scale);
1429
1430 bc_num_clean(n);
1431 if (n->len != 0) n->neg = !neg1 != !neg2;
1432}
1433
1434static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1435 BcNum *restrict b)
1436{
1437 if (idx < n->len) {
1438
1439 b->len = n->len - idx;
1440 a->len = idx;
1441 a->rdx = b->rdx = 0;
1442
1443 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1444 memcpy(a->num, n->num, idx * sizeof(BcDig));
1445 }
1446 else {
1447 bc_num_zero(b);
1448 bc_num_copy(a, n);
1449 }
1450
1451 bc_num_clean(a);
1452 bc_num_clean(b);
1453}
1454
1455static BcStatus bc_num_shift(BcNum *n, size_t places)
1456{
1457 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001458 if (places + n->len > BC_MAX_NUM)
1459 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001460
1461 if (n->rdx >= places)
1462 n->rdx -= places;
1463 else {
1464 bc_num_extend(n, places - n->rdx);
1465 n->rdx = 0;
1466 }
1467
1468 bc_num_clean(n);
1469
1470 return BC_STATUS_SUCCESS;
1471}
1472
1473static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1474{
1475 BcNum one;
1476 BcDig num[2];
1477
1478 one.cap = 2;
1479 one.num = num;
1480 bc_num_one(&one);
1481
1482 return bc_num_div(&one, a, b, scale);
1483}
1484
1485static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1486{
1487 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1488 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1489 int carry, in;
1490
1491 // Because this function doesn't need to use scale (per the bc spec),
1492 // I am hijacking it to say whether it's doing an add or a subtract.
1493
1494 if (a->len == 0) {
1495 bc_num_copy(c, b);
1496 if (sub && c->len) c->neg = !c->neg;
1497 return BC_STATUS_SUCCESS;
1498 }
1499 else if (b->len == 0) {
1500 bc_num_copy(c, a);
1501 return BC_STATUS_SUCCESS;
1502 }
1503
1504 c->neg = a->neg;
1505 c->rdx = BC_MAX(a->rdx, b->rdx);
1506 min_rdx = BC_MIN(a->rdx, b->rdx);
1507 c->len = 0;
1508
1509 if (a->rdx > b->rdx) {
1510 diff = a->rdx - b->rdx;
1511 ptr = a->num;
1512 ptr_a = a->num + diff;
1513 ptr_b = b->num;
1514 }
1515 else {
1516 diff = b->rdx - a->rdx;
1517 ptr = b->num;
1518 ptr_a = a->num;
1519 ptr_b = b->num + diff;
1520 }
1521
1522 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1523
1524 ptr_c += diff;
1525 a_int = BC_NUM_INT(a);
1526 b_int = BC_NUM_INT(b);
1527
1528 if (a_int > b_int) {
1529 min_int = b_int;
1530 max = a_int;
1531 ptr = ptr_a;
1532 }
1533 else {
1534 min_int = a_int;
1535 max = b_int;
1536 ptr = ptr_b;
1537 }
1538
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001539 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001540 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1541 carry = in / 10;
1542 ptr_c[i] = (BcDig)(in % 10);
1543 }
1544
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001545 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001546 in = ((int) ptr[i]) + carry;
1547 carry = in / 10;
1548 ptr_c[i] = (BcDig)(in % 10);
1549 }
1550
1551 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1552
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001553 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001554}
1555
1556static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1557{
Gavin Howard01055ba2018-11-03 11:00:21 -06001558 ssize_t cmp;
1559 BcNum *minuend, *subtrahend;
1560 size_t start;
1561 bool aneg, bneg, neg;
1562
1563 // Because this function doesn't need to use scale (per the bc spec),
1564 // I am hijacking it to say whether it's doing an add or a subtract.
1565
1566 if (a->len == 0) {
1567 bc_num_copy(c, b);
1568 if (sub && c->len) c->neg = !c->neg;
1569 return BC_STATUS_SUCCESS;
1570 }
1571 else if (b->len == 0) {
1572 bc_num_copy(c, a);
1573 return BC_STATUS_SUCCESS;
1574 }
1575
1576 aneg = a->neg;
1577 bneg = b->neg;
1578 a->neg = b->neg = false;
1579
1580 cmp = bc_num_cmp(a, b);
1581
1582 a->neg = aneg;
1583 b->neg = bneg;
1584
1585 if (cmp == 0) {
1586 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1587 return BC_STATUS_SUCCESS;
1588 }
1589 else if (cmp > 0) {
1590 neg = a->neg;
1591 minuend = a;
1592 subtrahend = b;
1593 }
1594 else {
1595 neg = b->neg;
1596 if (sub) neg = !neg;
1597 minuend = b;
1598 subtrahend = a;
1599 }
1600
1601 bc_num_copy(c, minuend);
1602 c->neg = neg;
1603
1604 if (c->rdx < subtrahend->rdx) {
1605 bc_num_extend(c, subtrahend->rdx - c->rdx);
1606 start = 0;
1607 }
1608 else
1609 start = c->rdx - subtrahend->rdx;
1610
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001611 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001612
1613 bc_num_clean(c);
1614
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001615 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001616}
1617
1618static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1619 BcNum *restrict c)
1620{
1621 BcStatus s;
1622 int carry;
1623 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1624 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1625 bool aone = BC_NUM_ONE(a);
1626
Gavin Howard01055ba2018-11-03 11:00:21 -06001627 if (a->len == 0 || b->len == 0) {
1628 bc_num_zero(c);
1629 return BC_STATUS_SUCCESS;
1630 }
1631 else if (aone || BC_NUM_ONE(b)) {
1632 bc_num_copy(c, aone ? b : a);
1633 return BC_STATUS_SUCCESS;
1634 }
1635
1636 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1637 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1638 {
1639 bc_num_expand(c, a->len + b->len + 1);
1640
1641 memset(c->num, 0, sizeof(BcDig) * c->cap);
1642 c->len = carry = len = 0;
1643
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001644 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001645
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001646 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001647 int in = (int) c->num[i + j];
1648 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1649 carry = in / 10;
1650 c->num[i + j] = (BcDig)(in % 10);
1651 }
1652
1653 c->num[i + j] += (BcDig) carry;
1654 len = BC_MAX(len, i + j + !!carry);
1655 carry = 0;
1656 }
1657
1658 c->len = len;
1659
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001660 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001661 }
1662
1663 bc_num_init(&l1, max);
1664 bc_num_init(&h1, max);
1665 bc_num_init(&l2, max);
1666 bc_num_init(&h2, max);
1667 bc_num_init(&m1, max);
1668 bc_num_init(&m2, max);
1669 bc_num_init(&z0, max);
1670 bc_num_init(&z1, max);
1671 bc_num_init(&z2, max);
1672 bc_num_init(&temp, max + max);
1673
1674 bc_num_split(a, max2, &l1, &h1);
1675 bc_num_split(b, max2, &l2, &h2);
1676
1677 s = bc_num_add(&h1, &l1, &m1, 0);
1678 if (s) goto err;
1679 s = bc_num_add(&h2, &l2, &m2, 0);
1680 if (s) goto err;
1681
1682 s = bc_num_k(&h1, &h2, &z0);
1683 if (s) goto err;
1684 s = bc_num_k(&m1, &m2, &z1);
1685 if (s) goto err;
1686 s = bc_num_k(&l1, &l2, &z2);
1687 if (s) goto err;
1688
1689 s = bc_num_sub(&z1, &z0, &temp, 0);
1690 if (s) goto err;
1691 s = bc_num_sub(&temp, &z2, &z1, 0);
1692 if (s) goto err;
1693
1694 s = bc_num_shift(&z0, max2 * 2);
1695 if (s) goto err;
1696 s = bc_num_shift(&z1, max2);
1697 if (s) goto err;
1698 s = bc_num_add(&z0, &z1, &temp, 0);
1699 if (s) goto err;
1700 s = bc_num_add(&temp, &z2, c, 0);
1701
1702err:
1703 bc_num_free(&temp);
1704 bc_num_free(&z2);
1705 bc_num_free(&z1);
1706 bc_num_free(&z0);
1707 bc_num_free(&m2);
1708 bc_num_free(&m1);
1709 bc_num_free(&h2);
1710 bc_num_free(&l2);
1711 bc_num_free(&h1);
1712 bc_num_free(&l1);
1713 return s;
1714}
1715
1716static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1717{
1718 BcStatus s;
1719 BcNum cpa, cpb;
1720 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1721
1722 scale = BC_MAX(scale, a->rdx);
1723 scale = BC_MAX(scale, b->rdx);
1724 scale = BC_MIN(a->rdx + b->rdx, scale);
1725 maxrdx = BC_MAX(maxrdx, scale);
1726
1727 bc_num_init(&cpa, a->len);
1728 bc_num_init(&cpb, b->len);
1729
1730 bc_num_copy(&cpa, a);
1731 bc_num_copy(&cpb, b);
1732 cpa.neg = cpb.neg = false;
1733
1734 s = bc_num_shift(&cpa, maxrdx);
1735 if (s) goto err;
1736 s = bc_num_shift(&cpb, maxrdx);
1737 if (s) goto err;
1738 s = bc_num_k(&cpa, &cpb, c);
1739 if (s) goto err;
1740
1741 maxrdx += scale;
1742 bc_num_expand(c, c->len + maxrdx);
1743
1744 if (c->len < maxrdx) {
1745 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1746 c->len += maxrdx;
1747 }
1748
1749 c->rdx = maxrdx;
1750 bc_num_retireMul(c, scale, a->neg, b->neg);
1751
1752err:
1753 bc_num_free(&cpb);
1754 bc_num_free(&cpa);
1755 return s;
1756}
1757
1758static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1759{
1760 BcStatus s = BC_STATUS_SUCCESS;
1761 BcDig *n, *p, q;
1762 size_t len, end, i;
1763 BcNum cp;
1764 bool zero = true;
1765
1766 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001767 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001768 else if (a->len == 0) {
1769 bc_num_setToZero(c, scale);
1770 return BC_STATUS_SUCCESS;
1771 }
1772 else if (BC_NUM_ONE(b)) {
1773 bc_num_copy(c, a);
1774 bc_num_retireMul(c, scale, a->neg, b->neg);
1775 return BC_STATUS_SUCCESS;
1776 }
1777
1778 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1779 bc_num_copy(&cp, a);
1780 len = b->len;
1781
1782 if (len > cp.len) {
1783 bc_num_expand(&cp, len + 2);
1784 bc_num_extend(&cp, len - cp.len);
1785 }
1786
1787 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1788 cp.rdx -= b->rdx;
1789 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1790
1791 if (b->rdx == b->len) {
1792 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1793 len -= i - 1;
1794 }
1795
1796 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1797
1798 // We want an extra zero in front to make things simpler.
1799 cp.num[cp.len++] = 0;
1800 end = cp.len - len;
1801
1802 bc_num_expand(c, cp.len);
1803
1804 bc_num_zero(c);
1805 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1806 c->rdx = cp.rdx;
1807 c->len = cp.len;
1808 p = b->num;
1809
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001810 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001811 n = cp.num + i;
1812 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001813 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001814 c->num[i] = q;
1815 }
1816
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001817 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001818 bc_num_free(&cp);
1819
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001820 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001821}
1822
1823static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1824 BcNum *restrict d, size_t scale, size_t ts)
1825{
1826 BcStatus s;
1827 BcNum temp;
1828 bool neg;
1829
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001830 if (b->len == 0)
1831 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001832
1833 if (a->len == 0) {
1834 bc_num_setToZero(d, ts);
1835 return BC_STATUS_SUCCESS;
1836 }
1837
1838 bc_num_init(&temp, d->cap);
1839 bc_num_d(a, b, c, scale);
1840
1841 if (scale != 0) scale = ts;
1842
1843 s = bc_num_m(c, b, &temp, scale);
1844 if (s) goto err;
1845 s = bc_num_sub(a, &temp, d, scale);
1846 if (s) goto err;
1847
1848 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1849
1850 neg = d->neg;
1851 bc_num_retireMul(d, ts, a->neg, b->neg);
1852 d->neg = neg;
1853
1854err:
1855 bc_num_free(&temp);
1856 return s;
1857}
1858
1859static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1860{
1861 BcStatus s;
1862 BcNum c1;
1863 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1864
1865 bc_num_init(&c1, len);
1866 s = bc_num_r(a, b, &c1, c, scale, ts);
1867 bc_num_free(&c1);
1868
1869 return s;
1870}
1871
1872static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1873{
1874 BcStatus s = BC_STATUS_SUCCESS;
1875 BcNum copy;
1876 unsigned long pow;
1877 size_t i, powrdx, resrdx;
1878 bool neg, zero;
1879
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001880 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001881
1882 if (b->len == 0) {
1883 bc_num_one(c);
1884 return BC_STATUS_SUCCESS;
1885 }
1886 else if (a->len == 0) {
1887 bc_num_setToZero(c, scale);
1888 return BC_STATUS_SUCCESS;
1889 }
1890 else if (BC_NUM_ONE(b)) {
1891 if (!b->neg)
1892 bc_num_copy(c, a);
1893 else
1894 s = bc_num_inv(a, c, scale);
1895 return s;
1896 }
1897
1898 neg = b->neg;
1899 b->neg = false;
1900
1901 s = bc_num_ulong(b, &pow);
1902 if (s) return s;
1903
1904 bc_num_init(&copy, a->len);
1905 bc_num_copy(&copy, a);
1906
1907 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1908
1909 b->neg = neg;
1910
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001911 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001912 powrdx <<= 1;
1913 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1914 if (s) goto err;
1915 }
1916
Gavin Howard01055ba2018-11-03 11:00:21 -06001917 bc_num_copy(c, &copy);
1918
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001919 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001920
1921 powrdx <<= 1;
1922 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1923 if (s) goto err;
1924
1925 if (pow & 1) {
1926 resrdx += powrdx;
1927 s = bc_num_mul(c, &copy, c, resrdx);
1928 if (s) goto err;
1929 }
1930 }
1931
1932 if (neg) {
1933 s = bc_num_inv(c, c, scale);
1934 if (s) goto err;
1935 }
1936
Gavin Howard01055ba2018-11-03 11:00:21 -06001937 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1938
1939 // We can't use bc_num_clean() here.
1940 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1941 if (zero) bc_num_setToZero(c, scale);
1942
1943err:
1944 bc_num_free(&copy);
1945 return s;
1946}
1947
1948static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1949 BcNumBinaryOp op, size_t req)
1950{
1951 BcStatus s;
1952 BcNum num2, *ptr_a, *ptr_b;
1953 bool init = false;
1954
1955 if (c == a) {
1956 ptr_a = &num2;
1957 memcpy(ptr_a, c, sizeof(BcNum));
1958 init = true;
1959 }
1960 else
1961 ptr_a = a;
1962
1963 if (c == b) {
1964 ptr_b = &num2;
1965 if (c != a) {
1966 memcpy(ptr_b, c, sizeof(BcNum));
1967 init = true;
1968 }
1969 }
1970 else
1971 ptr_b = b;
1972
1973 if (init)
1974 bc_num_init(c, req);
1975 else
1976 bc_num_expand(c, req);
1977
1978 s = op(ptr_a, ptr_b, c, scale);
1979
1980 if (init) bc_num_free(&num2);
1981
1982 return s;
1983}
1984
1985static bool bc_num_strValid(const char *val, size_t base)
1986{
1987 BcDig b;
1988 bool small, radix = false;
1989 size_t i, len = strlen(val);
1990
1991 if (!len) return true;
1992
1993 small = base <= 10;
1994 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1995
1996 for (i = 0; i < len; ++i) {
1997
1998 BcDig c = val[i];
1999
2000 if (c == '.') {
2001
2002 if (radix) return false;
2003
2004 radix = true;
2005 continue;
2006 }
2007
2008 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2009 return false;
2010 }
2011
2012 return true;
2013}
2014
2015static void bc_num_parseDecimal(BcNum *n, const char *val)
2016{
2017 size_t len, i;
2018 const char *ptr;
2019 bool zero = true;
2020
2021 for (i = 0; val[i] == '0'; ++i);
2022
2023 val += i;
2024 len = strlen(val);
2025 bc_num_zero(n);
2026
2027 if (len != 0) {
2028 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2029 bc_num_expand(n, len);
2030 }
2031
2032 ptr = strchr(val, '.');
2033
2034 // Explicitly test for NULL here to produce either a 0 or 1.
2035 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2036
2037 if (!zero) {
2038 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2039 n->num[n->len] = val[i] - '0';
2040 }
2041}
2042
2043static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2044{
2045 BcStatus s;
2046 BcNum temp, mult, result;
2047 BcDig c = '\0';
2048 bool zero = true;
2049 unsigned long v;
2050 size_t i, digits, len = strlen(val);
2051
2052 bc_num_zero(n);
2053
2054 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2055 if (zero) return;
2056
2057 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2058 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2059
2060 for (i = 0; i < len; ++i) {
2061
2062 c = val[i];
2063 if (c == '.') break;
2064
2065 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2066
2067 s = bc_num_mul(n, base, &mult, 0);
2068 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002069 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002070 s = bc_num_add(&mult, &temp, n, 0);
2071 if (s) goto int_err;
2072 }
2073
2074 if (i == len) {
2075 c = val[i];
2076 if (c == 0) goto int_err;
2077 }
2078
2079 bc_num_init(&result, base->len);
2080 bc_num_zero(&result);
2081 bc_num_one(&mult);
2082
2083 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2084
2085 c = val[i];
2086 if (c == 0) break;
2087
2088 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2089
2090 s = bc_num_mul(&result, base, &result, 0);
2091 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002092 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002093 s = bc_num_add(&result, &temp, &result, 0);
2094 if (s) goto err;
2095 s = bc_num_mul(&mult, base, &mult, 0);
2096 if (s) goto err;
2097 }
2098
2099 s = bc_num_div(&result, &mult, &result, digits);
2100 if (s) goto err;
2101 s = bc_num_add(n, &result, n, digits);
2102 if (s) goto err;
2103
2104 if (n->len != 0) {
2105 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2106 }
2107 else
2108 bc_num_zero(n);
2109
2110err:
2111 bc_num_free(&result);
2112int_err:
2113 bc_num_free(&mult);
2114 bc_num_free(&temp);
2115}
2116
2117static void bc_num_printNewline(size_t *nchars, size_t line_len)
2118{
2119 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002120 bb_putchar('\\');
2121 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002122 *nchars = 0;
2123 }
2124}
2125
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002126#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002127static void bc_num_printChar(size_t num, size_t width, bool radix,
2128 size_t *nchars, size_t line_len)
2129{
2130 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002131 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002132 *nchars = *nchars + width;
2133}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002134#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002135
2136static void bc_num_printDigits(size_t num, size_t width, bool radix,
2137 size_t *nchars, size_t line_len)
2138{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002139 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002140
2141 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002142 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002143 ++(*nchars);
2144
2145 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002146 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2147 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002148
2149 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002150 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002151 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002152 dig = num / pow;
2153 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002154 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002155 }
2156}
2157
2158static void bc_num_printHex(size_t num, size_t width, bool radix,
2159 size_t *nchars, size_t line_len)
2160{
2161 if (radix) {
2162 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002163 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002164 *nchars += 1;
2165 }
2166
2167 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002168 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002169 *nchars = *nchars + width;
2170}
2171
2172static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2173{
2174 size_t i, rdx = n->rdx - 1;
2175
Denys Vlasenko00d77792018-11-30 23:13:42 +01002176 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002177 (*nchars) += n->neg;
2178
2179 for (i = n->len - 1; i < n->len; --i)
2180 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2181}
2182
2183static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2184 size_t *nchars, size_t len, BcNumDigitOp print)
2185{
2186 BcStatus s;
2187 BcVec stack;
2188 BcNum intp, fracp, digit, frac_len;
2189 unsigned long dig, *ptr;
2190 size_t i;
2191 bool radix;
2192
2193 if (n->len == 0) {
2194 print(0, width, false, nchars, len);
2195 return BC_STATUS_SUCCESS;
2196 }
2197
2198 bc_vec_init(&stack, sizeof(long), NULL);
2199 bc_num_init(&intp, n->len);
2200 bc_num_init(&fracp, n->rdx);
2201 bc_num_init(&digit, width);
2202 bc_num_init(&frac_len, BC_NUM_INT(n));
2203 bc_num_copy(&intp, n);
2204 bc_num_one(&frac_len);
2205
2206 bc_num_truncate(&intp, intp.rdx);
2207 s = bc_num_sub(n, &intp, &fracp, 0);
2208 if (s) goto err;
2209
2210 while (intp.len != 0) {
2211 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2212 if (s) goto err;
2213 s = bc_num_ulong(&digit, &dig);
2214 if (s) goto err;
2215 bc_vec_push(&stack, &dig);
2216 }
2217
2218 for (i = 0; i < stack.len; ++i) {
2219 ptr = bc_vec_item_rev(&stack, i);
2220 print(*ptr, width, false, nchars, len);
2221 }
2222
2223 if (!n->rdx) goto err;
2224
2225 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2226 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2227 if (s) goto err;
2228 s = bc_num_ulong(&fracp, &dig);
2229 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002230 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002231 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2232 if (s) goto err;
2233 print(dig, width, radix, nchars, len);
2234 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2235 if (s) goto err;
2236 }
2237
2238err:
2239 bc_num_free(&frac_len);
2240 bc_num_free(&digit);
2241 bc_num_free(&fracp);
2242 bc_num_free(&intp);
2243 bc_vec_free(&stack);
2244 return s;
2245}
2246
2247static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2248 size_t *nchars, size_t line_len)
2249{
2250 BcStatus s;
2251 size_t width, i;
2252 BcNumDigitOp print;
2253 bool neg = n->neg;
2254
Denys Vlasenko00d77792018-11-30 23:13:42 +01002255 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002256 (*nchars) += neg;
2257
2258 n->neg = false;
2259
2260 if (base_t <= BC_NUM_MAX_IBASE) {
2261 width = 1;
2262 print = bc_num_printHex;
2263 }
2264 else {
2265 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2266 print = bc_num_printDigits;
2267 }
2268
2269 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2270 n->neg = neg;
2271
2272 return s;
2273}
2274
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002275#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002276static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2277{
2278 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2279}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002280#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002281
2282static void bc_num_init(BcNum *n, size_t req)
2283{
2284 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2285 memset(n, 0, sizeof(BcNum));
2286 n->num = xmalloc(req);
2287 n->cap = req;
2288}
2289
2290static void bc_num_expand(BcNum *n, size_t req)
2291{
2292 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2293 if (req > n->cap) {
2294 n->num = xrealloc(n->num, req);
2295 n->cap = req;
2296 }
2297}
2298
2299static void bc_num_free(void *num)
2300{
2301 free(((BcNum *) num)->num);
2302}
2303
2304static void bc_num_copy(BcNum *d, BcNum *s)
2305{
2306 if (d != s) {
2307 bc_num_expand(d, s->cap);
2308 d->len = s->len;
2309 d->neg = s->neg;
2310 d->rdx = s->rdx;
2311 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2312 }
2313}
2314
2315static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2316 size_t base_t)
2317{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002318 if (!bc_num_strValid(val, base_t))
2319 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002320
2321 if (base_t == 10)
2322 bc_num_parseDecimal(n, val);
2323 else
2324 bc_num_parseBase(n, val, base);
2325
2326 return BC_STATUS_SUCCESS;
2327}
2328
2329static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2330 size_t *nchars, size_t line_len)
2331{
2332 BcStatus s = BC_STATUS_SUCCESS;
2333
2334 bc_num_printNewline(nchars, line_len);
2335
2336 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002337 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002338 ++(*nchars);
2339 }
2340 else if (base_t == 10)
2341 bc_num_printDecimal(n, nchars, line_len);
2342 else
2343 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2344
2345 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002346 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002347 *nchars = 0;
2348 }
2349
2350 return s;
2351}
2352
2353static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2354{
2355 size_t i;
2356 unsigned long pow;
2357
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002358 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002359
2360 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2361
2362 unsigned long prev = *result, powprev = pow;
2363
2364 *result += ((unsigned long) n->num[i]) * pow;
2365 pow *= 10;
2366
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002367 if (*result < prev || pow < powprev)
2368 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002369 }
2370
2371 return BC_STATUS_SUCCESS;
2372}
2373
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002374static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002375{
2376 size_t len;
2377 BcDig *ptr;
2378 unsigned long i;
2379
2380 bc_num_zero(n);
2381
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002382 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002383
2384 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2385 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002386}
2387
2388static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2389{
2390 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2391 (void) scale;
2392 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2393}
2394
2395static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2396{
2397 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2398 (void) scale;
2399 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2400}
2401
2402static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2403{
2404 size_t req = BC_NUM_MREQ(a, b, scale);
2405 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2406}
2407
2408static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2409{
2410 size_t req = BC_NUM_MREQ(a, b, scale);
2411 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2412}
2413
2414static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2415{
2416 size_t req = BC_NUM_MREQ(a, b, scale);
2417 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2418}
2419
2420static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2421{
2422 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2423}
2424
2425static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2426{
2427 BcStatus s;
2428 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2429 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2430 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2431
2432 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2433 bc_num_expand(b, req);
2434
2435 if (a->len == 0) {
2436 bc_num_setToZero(b, scale);
2437 return BC_STATUS_SUCCESS;
2438 }
2439 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002440 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002441 else if (BC_NUM_ONE(a)) {
2442 bc_num_one(b);
2443 bc_num_extend(b, scale);
2444 return BC_STATUS_SUCCESS;
2445 }
2446
2447 scale = BC_MAX(scale, a->rdx) + 1;
2448 len = a->len + scale;
2449
2450 bc_num_init(&num1, len);
2451 bc_num_init(&num2, len);
2452 bc_num_init(&half, BC_NUM_DEF_SIZE);
2453
2454 bc_num_one(&half);
2455 half.num[0] = 5;
2456 half.rdx = 1;
2457
2458 bc_num_init(&f, len);
2459 bc_num_init(&fprime, len);
2460
2461 x0 = &num1;
2462 x1 = &num2;
2463
2464 bc_num_one(x0);
2465 pow = BC_NUM_INT(a);
2466
2467 if (pow) {
2468
2469 if (pow & 1)
2470 x0->num[0] = 2;
2471 else
2472 x0->num[0] = 6;
2473
2474 pow -= 2 - (pow & 1);
2475
2476 bc_num_extend(x0, pow);
2477
2478 // Make sure to move the radix back.
2479 x0->rdx -= pow;
2480 }
2481
2482 x0->rdx = digs = digs1 = 0;
2483 resrdx = scale + 2;
2484 len = BC_NUM_INT(x0) + resrdx - 1;
2485
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002486 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002487
2488 s = bc_num_div(a, x0, &f, resrdx);
2489 if (s) goto err;
2490 s = bc_num_add(x0, &f, &fprime, resrdx);
2491 if (s) goto err;
2492 s = bc_num_mul(&fprime, &half, x1, resrdx);
2493 if (s) goto err;
2494
2495 cmp = bc_num_cmp(x1, x0);
2496 digs = x1->len - (unsigned long long) llabs(cmp);
2497
2498 if (cmp == cmp2 && digs == digs1)
2499 times += 1;
2500 else
2501 times = 0;
2502
2503 resrdx += times > 4;
2504
2505 cmp2 = cmp1;
2506 cmp1 = cmp;
2507 digs1 = digs;
2508
2509 temp = x0;
2510 x0 = x1;
2511 x1 = temp;
2512 }
2513
Gavin Howard01055ba2018-11-03 11:00:21 -06002514 bc_num_copy(b, x0);
2515 scale -= 1;
2516 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2517
2518err:
2519 bc_num_free(&fprime);
2520 bc_num_free(&f);
2521 bc_num_free(&half);
2522 bc_num_free(&num2);
2523 bc_num_free(&num1);
2524 return s;
2525}
2526
2527static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2528 size_t scale)
2529{
2530 BcStatus s;
2531 BcNum num2, *ptr_a;
2532 bool init = false;
2533 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2534
2535 if (c == a) {
2536 memcpy(&num2, c, sizeof(BcNum));
2537 ptr_a = &num2;
2538 bc_num_init(c, len);
2539 init = true;
2540 }
2541 else {
2542 ptr_a = a;
2543 bc_num_expand(c, len);
2544 }
2545
2546 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2547
2548 if (init) bc_num_free(&num2);
2549
2550 return s;
2551}
2552
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002553#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002554static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2555{
2556 BcStatus s;
2557 BcNum base, exp, two, temp;
2558
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002559 if (c->len == 0)
2560 return bc_error("divide by zero");
2561 if (a->rdx || b->rdx || c->rdx)
2562 return bc_error("non integer number");
2563 if (b->neg)
2564 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002565
2566 bc_num_expand(d, c->len);
2567 bc_num_init(&base, c->len);
2568 bc_num_init(&exp, b->len);
2569 bc_num_init(&two, BC_NUM_DEF_SIZE);
2570 bc_num_init(&temp, b->len);
2571
2572 bc_num_one(&two);
2573 two.num[0] = 2;
2574 bc_num_one(d);
2575
2576 s = bc_num_rem(a, c, &base, 0);
2577 if (s) goto err;
2578 bc_num_copy(&exp, b);
2579
2580 while (exp.len != 0) {
2581
2582 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2583 if (s) goto err;
2584
2585 if (BC_NUM_ONE(&temp)) {
2586 s = bc_num_mul(d, &base, &temp, 0);
2587 if (s) goto err;
2588 s = bc_num_rem(&temp, c, d, 0);
2589 if (s) goto err;
2590 }
2591
2592 s = bc_num_mul(&base, &base, &temp, 0);
2593 if (s) goto err;
2594 s = bc_num_rem(&temp, c, &base, 0);
2595 if (s) goto err;
2596 }
2597
2598err:
2599 bc_num_free(&temp);
2600 bc_num_free(&two);
2601 bc_num_free(&exp);
2602 bc_num_free(&base);
2603 return s;
2604}
2605#endif // ENABLE_DC
2606
2607static int bc_id_cmp(const void *e1, const void *e2)
2608{
2609 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2610}
2611
2612static void bc_id_free(void *id)
2613{
2614 free(((BcId *) id)->name);
2615}
2616
2617static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2618{
2619 BcId a;
2620 size_t i;
2621
2622 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002623 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2624 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002625 }
2626
2627 a.idx = var;
2628 a.name = name;
2629
2630 bc_vec_push(&f->autos, &a);
2631
2632 return BC_STATUS_SUCCESS;
2633}
2634
2635static void bc_func_init(BcFunc *f)
2636{
2637 bc_vec_init(&f->code, sizeof(char), NULL);
2638 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2639 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2640 f->nparams = 0;
2641}
2642
2643static void bc_func_free(void *func)
2644{
2645 BcFunc *f = (BcFunc *) func;
2646 bc_vec_free(&f->code);
2647 bc_vec_free(&f->autos);
2648 bc_vec_free(&f->labels);
2649}
2650
2651static void bc_array_init(BcVec *a, bool nums)
2652{
2653 if (nums)
2654 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2655 else
2656 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2657 bc_array_expand(a, 1);
2658}
2659
2660static void bc_array_copy(BcVec *d, const BcVec *s)
2661{
2662 size_t i;
2663
2664 bc_vec_npop(d, d->len);
2665 bc_vec_expand(d, s->cap);
2666 d->len = s->len;
2667
2668 for (i = 0; i < s->len; ++i) {
2669 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2670 bc_num_init(dnum, snum->len);
2671 bc_num_copy(dnum, snum);
2672 }
2673}
2674
2675static void bc_array_expand(BcVec *a, size_t len)
2676{
2677 BcResultData data;
2678
2679 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2680 while (len > a->len) {
2681 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2682 bc_vec_push(a, &data.n);
2683 }
2684 }
2685 else {
2686 while (len > a->len) {
2687 bc_array_init(&data.v, true);
2688 bc_vec_push(a, &data.v);
2689 }
2690 }
2691}
2692
2693static void bc_string_free(void *string)
2694{
2695 free(*((char **) string));
2696}
2697
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002698#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002699static void bc_result_copy(BcResult *d, BcResult *src)
2700{
2701 d->t = src->t;
2702
2703 switch (d->t) {
2704
2705 case BC_RESULT_TEMP:
2706 case BC_RESULT_IBASE:
2707 case BC_RESULT_SCALE:
2708 case BC_RESULT_OBASE:
2709 {
2710 bc_num_init(&d->d.n, src->d.n.len);
2711 bc_num_copy(&d->d.n, &src->d.n);
2712 break;
2713 }
2714
2715 case BC_RESULT_VAR:
2716 case BC_RESULT_ARRAY:
2717 case BC_RESULT_ARRAY_ELEM:
2718 {
2719 d->d.id.name = xstrdup(src->d.id.name);
2720 break;
2721 }
2722
2723 case BC_RESULT_CONSTANT:
2724 case BC_RESULT_LAST:
2725 case BC_RESULT_ONE:
2726 case BC_RESULT_STR:
2727 {
2728 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2729 break;
2730 }
2731 }
2732}
2733#endif // ENABLE_DC
2734
2735static void bc_result_free(void *result)
2736{
2737 BcResult *r = (BcResult *) result;
2738
2739 switch (r->t) {
2740
2741 case BC_RESULT_TEMP:
2742 case BC_RESULT_IBASE:
2743 case BC_RESULT_SCALE:
2744 case BC_RESULT_OBASE:
2745 {
2746 bc_num_free(&r->d.n);
2747 break;
2748 }
2749
2750 case BC_RESULT_VAR:
2751 case BC_RESULT_ARRAY:
2752 case BC_RESULT_ARRAY_ELEM:
2753 {
2754 free(r->d.id.name);
2755 break;
2756 }
2757
2758 default:
2759 {
2760 // Do nothing.
2761 break;
2762 }
2763 }
2764}
2765
2766static void bc_lex_lineComment(BcLex *l)
2767{
2768 l->t.t = BC_LEX_WHITESPACE;
2769 while (l->i < l->len && l->buf[l->i++] != '\n');
2770 --l->i;
2771}
2772
2773static void bc_lex_whitespace(BcLex *l)
2774{
2775 char c;
2776 l->t.t = BC_LEX_WHITESPACE;
2777 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2778}
2779
2780static BcStatus bc_lex_number(BcLex *l, char start)
2781{
2782 const char *buf = l->buf + l->i;
2783 size_t len, hits = 0, bslashes = 0, i = 0, j;
2784 char c = buf[i];
2785 bool last_pt, pt = start == '.';
2786
2787 last_pt = pt;
2788 l->t.t = BC_LEX_NUMBER;
2789
2790 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2791 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2792 {
2793 if (c != '\\') {
2794 last_pt = c == '.';
2795 pt = pt || last_pt;
2796 }
2797 else {
2798 ++i;
2799 bslashes += 1;
2800 }
2801
2802 c = buf[++i];
2803 }
2804
2805 len = i + 1 * !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002806 if (len > BC_MAX_NUM)
2807 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002808
2809 bc_vec_npop(&l->t.v, l->t.v.len);
2810 bc_vec_expand(&l->t.v, len + 1);
2811 bc_vec_push(&l->t.v, &start);
2812
2813 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2814
2815 c = buf[j];
2816
2817 // If we have hit a backslash, skip it. We don't have
2818 // to check for a newline because it's guaranteed.
2819 if (hits < bslashes && c == '\\') {
2820 ++hits;
2821 ++j;
2822 continue;
2823 }
2824
2825 bc_vec_push(&l->t.v, &c);
2826 }
2827
2828 bc_vec_pushByte(&l->t.v, '\0');
2829 l->i += i;
2830
2831 return BC_STATUS_SUCCESS;
2832}
2833
2834static BcStatus bc_lex_name(BcLex *l)
2835{
2836 size_t i = 0;
2837 const char *buf = l->buf + l->i - 1;
2838 char c = buf[i];
2839
2840 l->t.t = BC_LEX_NAME;
2841
2842 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2843
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002844 if (i > BC_MAX_STRING)
2845 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002846 bc_vec_string(&l->t.v, i, buf);
2847
2848 // Increment the index. We minus 1 because it has already been incremented.
2849 l->i += i - 1;
2850
2851 return BC_STATUS_SUCCESS;
2852}
2853
2854static void bc_lex_init(BcLex *l, BcLexNext next)
2855{
2856 l->next = next;
2857 bc_vec_init(&l->t.v, sizeof(char), NULL);
2858}
2859
2860static void bc_lex_free(BcLex *l)
2861{
2862 bc_vec_free(&l->t.v);
2863}
2864
2865static void bc_lex_file(BcLex *l, const char *file)
2866{
2867 l->line = 1;
2868 l->newline = false;
2869 l->f = file;
2870}
2871
2872static BcStatus bc_lex_next(BcLex *l)
2873{
2874 BcStatus s;
2875
2876 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002877 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002878
2879 l->line += l->newline;
2880 l->t.t = BC_LEX_EOF;
2881
2882 l->newline = (l->i == l->len);
2883 if (l->newline) return BC_STATUS_SUCCESS;
2884
2885 // Loop until failure or we don't have whitespace. This
2886 // is so the parser doesn't get inundated with whitespace.
2887 do {
2888 s = l->next(l);
2889 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2890
2891 return s;
2892}
2893
2894static BcStatus bc_lex_text(BcLex *l, const char *text)
2895{
2896 l->buf = text;
2897 l->i = 0;
2898 l->len = strlen(text);
2899 l->t.t = l->t.last = BC_LEX_INVALID;
2900 return bc_lex_next(l);
2901}
2902
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002903#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002904static BcStatus bc_lex_identifier(BcLex *l)
2905{
2906 BcStatus s;
2907 size_t i;
2908 const char *buf = l->buf + l->i - 1;
2909
2910 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2911
2912 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2913
2914 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2915
2916 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2917
2918 if (!bc_lex_kws[i].posix) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002919 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
Gavin Howard01055ba2018-11-03 11:00:21 -06002920 if (s) return s;
2921 }
2922
2923 // We minus 1 because the index has already been incremented.
2924 l->i += len - 1;
2925 return BC_STATUS_SUCCESS;
2926 }
2927 }
2928
2929 s = bc_lex_name(l);
2930 if (s) return s;
2931
2932 if (l->t.v.len - 1 > 1)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002933 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002934
2935 return s;
2936}
2937
2938static BcStatus bc_lex_string(BcLex *l)
2939{
2940 size_t len, nls = 0, i = l->i;
2941 char c;
2942
2943 l->t.t = BC_LEX_STR;
2944
2945 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2946
2947 if (c == '\0') {
2948 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002949 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002950 }
2951
2952 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002953 if (len > BC_MAX_STRING)
2954 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002955 bc_vec_string(&l->t.v, len, l->buf + l->i);
2956
2957 l->i = i + 1;
2958 l->line += nls;
2959
2960 return BC_STATUS_SUCCESS;
2961}
2962
2963static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2964{
2965 if (l->buf[l->i] == '=') {
2966 ++l->i;
2967 l->t.t = with;
2968 }
2969 else
2970 l->t.t = without;
2971}
2972
2973static BcStatus bc_lex_comment(BcLex *l)
2974{
2975 size_t i, nls = 0;
2976 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06002977
2978 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002979 i = ++l->i;
2980 for (;;) {
2981 char c = buf[i];
2982 check_star:
2983 if (c == '*') {
2984 c = buf[++i];
2985 if (c == '/')
2986 break;
2987 goto check_star;
2988 }
2989 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06002990 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002991 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002992 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002993 nls += (c == '\n');
2994 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06002995 }
2996
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002997 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002998 l->line += nls;
2999
3000 return BC_STATUS_SUCCESS;
3001}
3002
3003static BcStatus bc_lex_token(BcLex *l)
3004{
3005 BcStatus s = BC_STATUS_SUCCESS;
3006 char c = l->buf[l->i++], c2;
3007
3008 // This is the workhorse of the lexer.
3009 switch (c) {
3010
3011 case '\0':
3012 case '\n':
3013 {
3014 l->newline = true;
3015 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3016 break;
3017 }
3018
3019 case '\t':
3020 case '\v':
3021 case '\f':
3022 case '\r':
3023 case ' ':
3024 {
3025 bc_lex_whitespace(l);
3026 break;
3027 }
3028
3029 case '!':
3030 {
3031 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3032
3033 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003034 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003035 if (s) return s;
3036 }
3037
3038 break;
3039 }
3040
3041 case '"':
3042 {
3043 s = bc_lex_string(l);
3044 break;
3045 }
3046
3047 case '#':
3048 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003049 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003050 if (s) return s;
3051
3052 bc_lex_lineComment(l);
3053
3054 break;
3055 }
3056
3057 case '%':
3058 {
3059 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3060 break;
3061 }
3062
3063 case '&':
3064 {
3065 c2 = l->buf[l->i];
3066 if (c2 == '&') {
3067
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003068 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003069 if (s) return s;
3070
3071 ++l->i;
3072 l->t.t = BC_LEX_OP_BOOL_AND;
3073 }
3074 else {
3075 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003076 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003077 }
3078
3079 break;
3080 }
3081
3082 case '(':
3083 case ')':
3084 {
3085 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3086 break;
3087 }
3088
3089 case '*':
3090 {
3091 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3092 break;
3093 }
3094
3095 case '+':
3096 {
3097 c2 = l->buf[l->i];
3098 if (c2 == '+') {
3099 ++l->i;
3100 l->t.t = BC_LEX_OP_INC;
3101 }
3102 else
3103 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3104 break;
3105 }
3106
3107 case ',':
3108 {
3109 l->t.t = BC_LEX_COMMA;
3110 break;
3111 }
3112
3113 case '-':
3114 {
3115 c2 = l->buf[l->i];
3116 if (c2 == '-') {
3117 ++l->i;
3118 l->t.t = BC_LEX_OP_DEC;
3119 }
3120 else
3121 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3122 break;
3123 }
3124
3125 case '.':
3126 {
3127 if (isdigit(l->buf[l->i]))
3128 s = bc_lex_number(l, c);
3129 else {
3130 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003131 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003132 }
3133 break;
3134 }
3135
3136 case '/':
3137 {
3138 c2 = l->buf[l->i];
3139 if (c2 == '*')
3140 s = bc_lex_comment(l);
3141 else
3142 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3143 break;
3144 }
3145
3146 case '0':
3147 case '1':
3148 case '2':
3149 case '3':
3150 case '4':
3151 case '5':
3152 case '6':
3153 case '7':
3154 case '8':
3155 case '9':
3156 case 'A':
3157 case 'B':
3158 case 'C':
3159 case 'D':
3160 case 'E':
3161 case 'F':
3162 {
3163 s = bc_lex_number(l, c);
3164 break;
3165 }
3166
3167 case ';':
3168 {
3169 l->t.t = BC_LEX_SCOLON;
3170 break;
3171 }
3172
3173 case '<':
3174 {
3175 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3176 break;
3177 }
3178
3179 case '=':
3180 {
3181 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3182 break;
3183 }
3184
3185 case '>':
3186 {
3187 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3188 break;
3189 }
3190
3191 case '[':
3192 case ']':
3193 {
3194 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3195 break;
3196 }
3197
3198 case '\\':
3199 {
3200 if (l->buf[l->i] == '\n') {
3201 l->t.t = BC_LEX_WHITESPACE;
3202 ++l->i;
3203 }
3204 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003205 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003206 break;
3207 }
3208
3209 case '^':
3210 {
3211 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3212 break;
3213 }
3214
3215 case 'a':
3216 case 'b':
3217 case 'c':
3218 case 'd':
3219 case 'e':
3220 case 'f':
3221 case 'g':
3222 case 'h':
3223 case 'i':
3224 case 'j':
3225 case 'k':
3226 case 'l':
3227 case 'm':
3228 case 'n':
3229 case 'o':
3230 case 'p':
3231 case 'q':
3232 case 'r':
3233 case 's':
3234 case 't':
3235 case 'u':
3236 case 'v':
3237 case 'w':
3238 case 'x':
3239 case 'y':
3240 case 'z':
3241 {
3242 s = bc_lex_identifier(l);
3243 break;
3244 }
3245
3246 case '{':
3247 case '}':
3248 {
3249 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3250 break;
3251 }
3252
3253 case '|':
3254 {
3255 c2 = l->buf[l->i];
3256
3257 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003258 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003259 if (s) return s;
3260
3261 ++l->i;
3262 l->t.t = BC_LEX_OP_BOOL_OR;
3263 }
3264 else {
3265 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003266 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003267 }
3268
3269 break;
3270 }
3271
3272 default:
3273 {
3274 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003275 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003276 break;
3277 }
3278 }
3279
3280 return s;
3281}
3282#endif // ENABLE_BC
3283
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003284#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003285static BcStatus dc_lex_register(BcLex *l)
3286{
3287 BcStatus s = BC_STATUS_SUCCESS;
3288
3289 if (isspace(l->buf[l->i - 1])) {
3290 bc_lex_whitespace(l);
3291 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003292 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003293 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003294 else
3295 s = bc_lex_name(l);
3296 }
3297 else {
3298 bc_vec_npop(&l->t.v, l->t.v.len);
3299 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3300 bc_vec_pushByte(&l->t.v, '\0');
3301 l->t.t = BC_LEX_NAME;
3302 }
3303
3304 return s;
3305}
3306
3307static BcStatus dc_lex_string(BcLex *l)
3308{
3309 size_t depth = 1, nls = 0, i = l->i;
3310 char c;
3311
3312 l->t.t = BC_LEX_STR;
3313 bc_vec_npop(&l->t.v, l->t.v.len);
3314
3315 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3316
3317 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3318 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3319 nls += (c == '\n');
3320
3321 if (depth) bc_vec_push(&l->t.v, &c);
3322 }
3323
3324 if (c == '\0') {
3325 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003326 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003327 }
3328
3329 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003330 if (i - l->i > BC_MAX_STRING)
3331 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003332
3333 l->i = i;
3334 l->line += nls;
3335
3336 return BC_STATUS_SUCCESS;
3337}
3338
3339static BcStatus dc_lex_token(BcLex *l)
3340{
3341 BcStatus s = BC_STATUS_SUCCESS;
3342 char c = l->buf[l->i++], c2;
3343 size_t i;
3344
3345 for (i = 0; i < dc_lex_regs_len; ++i) {
3346 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3347 }
3348
3349 if (c >= '%' && c <= '~' &&
3350 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3351 {
3352 return s;
3353 }
3354
3355 // This is the workhorse of the lexer.
3356 switch (c) {
3357
3358 case '\0':
3359 {
3360 l->t.t = BC_LEX_EOF;
3361 break;
3362 }
3363
3364 case '\n':
3365 case '\t':
3366 case '\v':
3367 case '\f':
3368 case '\r':
3369 case ' ':
3370 {
3371 l->newline = (c == '\n');
3372 bc_lex_whitespace(l);
3373 break;
3374 }
3375
3376 case '!':
3377 {
3378 c2 = l->buf[l->i];
3379
3380 if (c2 == '=')
3381 l->t.t = BC_LEX_OP_REL_NE;
3382 else if (c2 == '<')
3383 l->t.t = BC_LEX_OP_REL_LE;
3384 else if (c2 == '>')
3385 l->t.t = BC_LEX_OP_REL_GE;
3386 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003387 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003388
3389 ++l->i;
3390 break;
3391 }
3392
3393 case '#':
3394 {
3395 bc_lex_lineComment(l);
3396 break;
3397 }
3398
3399 case '.':
3400 {
3401 if (isdigit(l->buf[l->i]))
3402 s = bc_lex_number(l, c);
3403 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003404 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003405 break;
3406 }
3407
3408 case '0':
3409 case '1':
3410 case '2':
3411 case '3':
3412 case '4':
3413 case '5':
3414 case '6':
3415 case '7':
3416 case '8':
3417 case '9':
3418 case 'A':
3419 case 'B':
3420 case 'C':
3421 case 'D':
3422 case 'E':
3423 case 'F':
3424 {
3425 s = bc_lex_number(l, c);
3426 break;
3427 }
3428
3429 case '[':
3430 {
3431 s = dc_lex_string(l);
3432 break;
3433 }
3434
3435 default:
3436 {
3437 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003438 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003439 break;
3440 }
3441 }
3442
3443 return s;
3444}
3445#endif // ENABLE_DC
3446
3447static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3448{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003449 bc_program_addFunc(name, idx);
3450 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003451}
3452
3453static void bc_parse_pushName(BcParse *p, char *name)
3454{
3455 size_t i = 0, len = strlen(name);
3456
3457 for (; i < len; ++i) bc_parse_push(p, name[i]);
3458 bc_parse_push(p, BC_PARSE_STREND);
3459
3460 free(name);
3461}
3462
3463static void bc_parse_pushIndex(BcParse *p, size_t idx)
3464{
3465 unsigned char amt, i, nums[sizeof(size_t)];
3466
3467 for (amt = 0; idx; ++amt) {
3468 nums[amt] = (char) idx;
3469 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3470 }
3471
3472 bc_parse_push(p, amt);
3473 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3474}
3475
3476static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3477{
3478 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003479 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003480
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003481 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003482
3483 bc_parse_push(p, BC_INST_NUM);
3484 bc_parse_pushIndex(p, idx);
3485
3486 ++(*nexs);
3487 (*prev) = BC_INST_NUM;
3488}
3489
3490static BcStatus bc_parse_text(BcParse *p, const char *text)
3491{
3492 BcStatus s;
3493
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003494 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003495
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003496 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003497 p->l.t.t = BC_LEX_INVALID;
3498 s = p->parse(p);
3499 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003500 if (!BC_PARSE_CAN_EXEC(p))
3501 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003502 }
3503
3504 return bc_lex_text(&p->l, text);
3505}
3506
Denys Vlasenkod38af482018-12-04 19:11:02 +01003507// Called when bc/dc_parse_parse() detects a failure,
3508// resets parsing structures.
3509static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003510{
3511 if (p->fidx != BC_PROG_MAIN) {
3512
3513 p->func->nparams = 0;
3514 bc_vec_npop(&p->func->code, p->func->code.len);
3515 bc_vec_npop(&p->func->autos, p->func->autos.len);
3516 bc_vec_npop(&p->func->labels, p->func->labels.len);
3517
3518 bc_parse_updateFunc(p, BC_PROG_MAIN);
3519 }
3520
3521 p->l.i = p->l.len;
3522 p->l.t.t = BC_LEX_EOF;
3523 p->auto_part = (p->nbraces = 0);
3524
3525 bc_vec_npop(&p->flags, p->flags.len - 1);
3526 bc_vec_npop(&p->exits, p->exits.len);
3527 bc_vec_npop(&p->conds, p->conds.len);
3528 bc_vec_npop(&p->ops, p->ops.len);
3529
Denys Vlasenkod38af482018-12-04 19:11:02 +01003530 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003531}
3532
3533static void bc_parse_free(BcParse *p)
3534{
3535 bc_vec_free(&p->flags);
3536 bc_vec_free(&p->exits);
3537 bc_vec_free(&p->conds);
3538 bc_vec_free(&p->ops);
3539 bc_lex_free(&p->l);
3540}
3541
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003542static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003543 BcParseParse parse, BcLexNext next)
3544{
3545 memset(p, 0, sizeof(BcParse));
3546
3547 bc_lex_init(&p->l, next);
3548 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3549 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3550 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3551 bc_vec_pushByte(&p->flags, 0);
3552 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3553
3554 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003555 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003556 bc_parse_updateFunc(p, func);
3557}
3558
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003559#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003560static BcStatus bc_parse_else(BcParse *p);
3561static BcStatus bc_parse_stmt(BcParse *p);
3562
3563static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3564 size_t *nexprs, bool next)
3565{
3566 BcStatus s = BC_STATUS_SUCCESS;
3567 BcLexType t;
3568 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3569 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3570
3571 while (p->ops.len > start) {
3572
3573 t = BC_PARSE_TOP_OP(p);
3574 if (t == BC_LEX_LPAREN) break;
3575
3576 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3577 if (l >= r && (l != r || !left)) break;
3578
3579 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3580 bc_vec_pop(&p->ops);
3581 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3582 }
3583
3584 bc_vec_push(&p->ops, &type);
3585 if (next) s = bc_lex_next(&p->l);
3586
3587 return s;
3588}
3589
3590static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3591{
3592 BcLexType top;
3593
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003594 if (p->ops.len <= ops_bgn)
3595 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003596 top = BC_PARSE_TOP_OP(p);
3597
3598 while (top != BC_LEX_LPAREN) {
3599
3600 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3601
3602 bc_vec_pop(&p->ops);
3603 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3604
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003605 if (p->ops.len <= ops_bgn)
3606 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003607 top = BC_PARSE_TOP_OP(p);
3608 }
3609
3610 bc_vec_pop(&p->ops);
3611
3612 return bc_lex_next(&p->l);
3613}
3614
3615static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3616{
3617 BcStatus s;
3618 bool comma = false;
3619 size_t nparams;
3620
3621 s = bc_lex_next(&p->l);
3622 if (s) return s;
3623
3624 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3625
3626 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3627 s = bc_parse_expr(p, flags, bc_parse_next_param);
3628 if (s) return s;
3629
3630 comma = p->l.t.t == BC_LEX_COMMA;
3631 if (comma) {
3632 s = bc_lex_next(&p->l);
3633 if (s) return s;
3634 }
3635 }
3636
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003637 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003638 bc_parse_push(p, BC_INST_CALL);
3639 bc_parse_pushIndex(p, nparams);
3640
3641 return BC_STATUS_SUCCESS;
3642}
3643
3644static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3645{
3646 BcStatus s;
3647 BcId entry, *entry_ptr;
3648 size_t idx;
3649
3650 entry.name = name;
3651
3652 s = bc_parse_params(p, flags);
3653 if (s) goto err;
3654
3655 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003656 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003657 goto err;
3658 }
3659
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003660 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003661
3662 if (idx == BC_VEC_INVALID_IDX) {
3663 name = xstrdup(entry.name);
3664 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003665 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003666 free(entry.name);
3667 }
3668 else
3669 free(name);
3670
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003671 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003672 bc_parse_pushIndex(p, entry_ptr->idx);
3673
3674 return bc_lex_next(&p->l);
3675
3676err:
3677 free(name);
3678 return s;
3679}
3680
3681static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3682{
3683 BcStatus s;
3684 char *name;
3685
3686 name = xstrdup(p->l.t.v.v);
3687 s = bc_lex_next(&p->l);
3688 if (s) goto err;
3689
3690 if (p->l.t.t == BC_LEX_LBRACKET) {
3691
3692 s = bc_lex_next(&p->l);
3693 if (s) goto err;
3694
3695 if (p->l.t.t == BC_LEX_RBRACKET) {
3696
3697 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003698 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003699 goto err;
3700 }
3701
3702 *type = BC_INST_ARRAY;
3703 }
3704 else {
3705
3706 *type = BC_INST_ARRAY_ELEM;
3707
3708 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3709 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3710 if (s) goto err;
3711 }
3712
3713 s = bc_lex_next(&p->l);
3714 if (s) goto err;
3715 bc_parse_push(p, *type);
3716 bc_parse_pushName(p, name);
3717 }
3718 else if (p->l.t.t == BC_LEX_LPAREN) {
3719
3720 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003721 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003722 goto err;
3723 }
3724
3725 *type = BC_INST_CALL;
3726 s = bc_parse_call(p, name, flags);
3727 }
3728 else {
3729 *type = BC_INST_VAR;
3730 bc_parse_push(p, BC_INST_VAR);
3731 bc_parse_pushName(p, name);
3732 }
3733
3734 return s;
3735
3736err:
3737 free(name);
3738 return s;
3739}
3740
3741static BcStatus bc_parse_read(BcParse *p)
3742{
3743 BcStatus s;
3744
3745 s = bc_lex_next(&p->l);
3746 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003747 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003748
3749 s = bc_lex_next(&p->l);
3750 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003751 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003752
3753 bc_parse_push(p, BC_INST_READ);
3754
3755 return bc_lex_next(&p->l);
3756}
3757
3758static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3759 BcInst *prev)
3760{
3761 BcStatus s;
3762
3763 s = bc_lex_next(&p->l);
3764 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003765 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003766
3767 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3768
3769 s = bc_lex_next(&p->l);
3770 if (s) return s;
3771
3772 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3773 if (s) return s;
3774
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003775 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003776
3777 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3778 bc_parse_push(p, *prev);
3779
3780 return bc_lex_next(&p->l);
3781}
3782
3783static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3784{
3785 BcStatus s;
3786
3787 s = bc_lex_next(&p->l);
3788 if (s) return s;
3789
3790 if (p->l.t.t != BC_LEX_LPAREN) {
3791 *type = BC_INST_SCALE;
3792 bc_parse_push(p, BC_INST_SCALE);
3793 return BC_STATUS_SUCCESS;
3794 }
3795
3796 *type = BC_INST_SCALE_FUNC;
3797 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3798
3799 s = bc_lex_next(&p->l);
3800 if (s) return s;
3801
3802 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3803 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003804 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003805 bc_parse_push(p, BC_INST_SCALE_FUNC);
3806
3807 return bc_lex_next(&p->l);
3808}
3809
3810static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3811 size_t *nexprs, uint8_t flags)
3812{
3813 BcStatus s;
3814 BcLexType type;
3815 char inst;
3816 BcInst etype = *prev;
3817
3818 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3819 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3820 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3821 {
3822 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3823 bc_parse_push(p, inst);
3824 s = bc_lex_next(&p->l);
3825 }
3826 else {
3827
3828 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3829 *paren_expr = true;
3830
3831 s = bc_lex_next(&p->l);
3832 if (s) return s;
3833 type = p->l.t.t;
3834
3835 // Because we parse the next part of the expression
3836 // right here, we need to increment this.
3837 *nexprs = *nexprs + 1;
3838
3839 switch (type) {
3840
3841 case BC_LEX_NAME:
3842 {
3843 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3844 break;
3845 }
3846
3847 case BC_LEX_KEY_IBASE:
3848 case BC_LEX_KEY_LAST:
3849 case BC_LEX_KEY_OBASE:
3850 {
3851 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3852 s = bc_lex_next(&p->l);
3853 break;
3854 }
3855
3856 case BC_LEX_KEY_SCALE:
3857 {
3858 s = bc_lex_next(&p->l);
3859 if (s) return s;
3860 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003861 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003862 else
3863 bc_parse_push(p, BC_INST_SCALE);
3864 break;
3865 }
3866
3867 default:
3868 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003869 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003870 break;
3871 }
3872 }
3873
3874 if (!s) bc_parse_push(p, inst);
3875 }
3876
3877 return s;
3878}
3879
3880static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3881 bool rparen, size_t *nexprs)
3882{
3883 BcStatus s;
3884 BcLexType type;
3885 BcInst etype = *prev;
3886
3887 s = bc_lex_next(&p->l);
3888 if (s) return s;
3889
3890 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3891 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3892 BC_LEX_OP_MINUS :
3893 BC_LEX_NEG;
3894 *prev = BC_PARSE_TOKEN_INST(type);
3895
3896 // We can just push onto the op stack because this is the largest
3897 // precedence operator that gets pushed. Inc/dec does not.
3898 if (type != BC_LEX_OP_MINUS)
3899 bc_vec_push(&p->ops, &type);
3900 else
3901 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3902
3903 return s;
3904}
3905
3906static BcStatus bc_parse_string(BcParse *p, char inst)
3907{
3908 char *str = xstrdup(p->l.t.v.v);
3909
3910 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003911 bc_parse_pushIndex(p, G.prog.strs.len);
3912 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003913 bc_parse_push(p, inst);
3914
3915 return bc_lex_next(&p->l);
3916}
3917
3918static BcStatus bc_parse_print(BcParse *p)
3919{
3920 BcStatus s;
3921 BcLexType type;
3922 bool comma = false;
3923
3924 s = bc_lex_next(&p->l);
3925 if (s) return s;
3926
3927 type = p->l.t.t;
3928
3929 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003930 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003931
3932 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3933
3934 if (type == BC_LEX_STR)
3935 s = bc_parse_string(p, BC_INST_PRINT_POP);
3936 else {
3937 s = bc_parse_expr(p, 0, bc_parse_next_print);
3938 if (s) return s;
3939 bc_parse_push(p, BC_INST_PRINT_POP);
3940 }
3941
3942 if (s) return s;
3943
3944 comma = p->l.t.t == BC_LEX_COMMA;
3945 if (comma) s = bc_lex_next(&p->l);
3946 type = p->l.t.t;
3947 }
3948
3949 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003950 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003951
3952 return bc_lex_next(&p->l);
3953}
3954
3955static BcStatus bc_parse_return(BcParse *p)
3956{
3957 BcStatus s;
3958 BcLexType t;
3959 bool paren;
3960
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003961 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003962
3963 s = bc_lex_next(&p->l);
3964 if (s) return s;
3965
3966 t = p->l.t.t;
3967 paren = t == BC_LEX_LPAREN;
3968
3969 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3970 bc_parse_push(p, BC_INST_RET0);
3971 else {
3972
3973 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3974 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3975 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003976
3977 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003978 bc_parse_push(p, BC_INST_RET0);
3979 s = bc_lex_next(&p->l);
3980 if (s) return s;
3981 }
3982
3983 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003984 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06003985 if (s) return s;
3986 }
3987
3988 bc_parse_push(p, BC_INST_RET);
3989 }
3990
3991 return s;
3992}
3993
3994static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3995{
3996 BcStatus s = BC_STATUS_SUCCESS;
3997
3998 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003999 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004000
4001 if (brace) {
4002
4003 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004004 if (!p->nbraces) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004005 --p->nbraces;
4006 s = bc_lex_next(&p->l);
4007 if (s) return s;
4008 }
4009 else
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004010 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004011 }
4012
4013 if (BC_PARSE_IF(p)) {
4014
4015 uint8_t *flag_ptr;
4016
4017 while (p->l.t.t == BC_LEX_NLINE) {
4018 s = bc_lex_next(&p->l);
4019 if (s) return s;
4020 }
4021
4022 bc_vec_pop(&p->flags);
4023
4024 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4025 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4026
4027 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4028 }
4029 else if (BC_PARSE_ELSE(p)) {
4030
4031 BcInstPtr *ip;
4032 size_t *label;
4033
4034 bc_vec_pop(&p->flags);
4035
4036 ip = bc_vec_top(&p->exits);
4037 label = bc_vec_item(&p->func->labels, ip->idx);
4038 *label = p->func->code.len;
4039
4040 bc_vec_pop(&p->exits);
4041 }
4042 else if (BC_PARSE_FUNC_INNER(p)) {
4043 bc_parse_push(p, BC_INST_RET0);
4044 bc_parse_updateFunc(p, BC_PROG_MAIN);
4045 bc_vec_pop(&p->flags);
4046 }
4047 else {
4048
4049 BcInstPtr *ip = bc_vec_top(&p->exits);
4050 size_t *label = bc_vec_top(&p->conds);
4051
4052 bc_parse_push(p, BC_INST_JUMP);
4053 bc_parse_pushIndex(p, *label);
4054
4055 label = bc_vec_item(&p->func->labels, ip->idx);
4056 *label = p->func->code.len;
4057
4058 bc_vec_pop(&p->flags);
4059 bc_vec_pop(&p->exits);
4060 bc_vec_pop(&p->conds);
4061 }
4062
4063 return s;
4064}
4065
4066static void bc_parse_startBody(BcParse *p, uint8_t flags)
4067{
4068 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4069 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4070 flags |= BC_PARSE_FLAG_BODY;
4071 bc_vec_push(&p->flags, &flags);
4072}
4073
4074static void bc_parse_noElse(BcParse *p)
4075{
4076 BcInstPtr *ip;
4077 size_t *label;
4078 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4079
4080 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4081
4082 ip = bc_vec_top(&p->exits);
4083 label = bc_vec_item(&p->func->labels, ip->idx);
4084 *label = p->func->code.len;
4085
4086 bc_vec_pop(&p->exits);
4087}
4088
4089static BcStatus bc_parse_if(BcParse *p)
4090{
4091 BcStatus s;
4092 BcInstPtr ip;
4093
4094 s = bc_lex_next(&p->l);
4095 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004096 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004097
4098 s = bc_lex_next(&p->l);
4099 if (s) return s;
4100 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4101 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004102 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004103
4104 s = bc_lex_next(&p->l);
4105 if (s) return s;
4106 bc_parse_push(p, BC_INST_JUMP_ZERO);
4107
4108 ip.idx = p->func->labels.len;
4109 ip.func = ip.len = 0;
4110
4111 bc_parse_pushIndex(p, ip.idx);
4112 bc_vec_push(&p->exits, &ip);
4113 bc_vec_push(&p->func->labels, &ip.idx);
4114 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4115
4116 return BC_STATUS_SUCCESS;
4117}
4118
4119static BcStatus bc_parse_else(BcParse *p)
4120{
4121 BcInstPtr ip;
4122
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004123 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004124
4125 ip.idx = p->func->labels.len;
4126 ip.func = ip.len = 0;
4127
4128 bc_parse_push(p, BC_INST_JUMP);
4129 bc_parse_pushIndex(p, ip.idx);
4130
4131 bc_parse_noElse(p);
4132
4133 bc_vec_push(&p->exits, &ip);
4134 bc_vec_push(&p->func->labels, &ip.idx);
4135 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4136
4137 return bc_lex_next(&p->l);
4138}
4139
4140static BcStatus bc_parse_while(BcParse *p)
4141{
4142 BcStatus s;
4143 BcInstPtr ip;
4144
4145 s = bc_lex_next(&p->l);
4146 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004147 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004148 s = bc_lex_next(&p->l);
4149 if (s) return s;
4150
4151 ip.idx = p->func->labels.len;
4152
4153 bc_vec_push(&p->func->labels, &p->func->code.len);
4154 bc_vec_push(&p->conds, &ip.idx);
4155
4156 ip.idx = p->func->labels.len;
4157 ip.func = 1;
4158 ip.len = 0;
4159
4160 bc_vec_push(&p->exits, &ip);
4161 bc_vec_push(&p->func->labels, &ip.idx);
4162
4163 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4164 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004165 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004166 s = bc_lex_next(&p->l);
4167 if (s) return s;
4168
4169 bc_parse_push(p, BC_INST_JUMP_ZERO);
4170 bc_parse_pushIndex(p, ip.idx);
4171 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4172
4173 return BC_STATUS_SUCCESS;
4174}
4175
4176static BcStatus bc_parse_for(BcParse *p)
4177{
4178 BcStatus s;
4179 BcInstPtr ip;
4180 size_t cond_idx, exit_idx, body_idx, update_idx;
4181
4182 s = bc_lex_next(&p->l);
4183 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004184 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004185 s = bc_lex_next(&p->l);
4186 if (s) return s;
4187
4188 if (p->l.t.t != BC_LEX_SCOLON)
4189 s = bc_parse_expr(p, 0, bc_parse_next_for);
4190 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004191 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004192
4193 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004194 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004195 s = bc_lex_next(&p->l);
4196 if (s) return s;
4197
4198 cond_idx = p->func->labels.len;
4199 update_idx = cond_idx + 1;
4200 body_idx = update_idx + 1;
4201 exit_idx = body_idx + 1;
4202
4203 bc_vec_push(&p->func->labels, &p->func->code.len);
4204
4205 if (p->l.t.t != BC_LEX_SCOLON)
4206 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4207 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004208 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004209
4210 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004211 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004212
4213 s = bc_lex_next(&p->l);
4214 if (s) return s;
4215
4216 bc_parse_push(p, BC_INST_JUMP_ZERO);
4217 bc_parse_pushIndex(p, exit_idx);
4218 bc_parse_push(p, BC_INST_JUMP);
4219 bc_parse_pushIndex(p, body_idx);
4220
4221 ip.idx = p->func->labels.len;
4222
4223 bc_vec_push(&p->conds, &update_idx);
4224 bc_vec_push(&p->func->labels, &p->func->code.len);
4225
4226 if (p->l.t.t != BC_LEX_RPAREN)
4227 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4228 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004229 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004230
4231 if (s) return s;
4232
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004233 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004234 bc_parse_push(p, BC_INST_JUMP);
4235 bc_parse_pushIndex(p, cond_idx);
4236 bc_vec_push(&p->func->labels, &p->func->code.len);
4237
4238 ip.idx = exit_idx;
4239 ip.func = 1;
4240 ip.len = 0;
4241
4242 bc_vec_push(&p->exits, &ip);
4243 bc_vec_push(&p->func->labels, &ip.idx);
4244 bc_lex_next(&p->l);
4245 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4246
4247 return BC_STATUS_SUCCESS;
4248}
4249
4250static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4251{
4252 BcStatus s;
4253 size_t i;
4254 BcInstPtr *ip;
4255
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004256 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004257
4258 if (type == BC_LEX_KEY_BREAK) {
4259
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004260 if (p->exits.len == 0) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004261
4262 i = p->exits.len - 1;
4263 ip = bc_vec_item(&p->exits, i);
4264
4265 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004266 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004267
4268 i = ip->idx;
4269 }
4270 else
4271 i = *((size_t *) bc_vec_top(&p->conds));
4272
4273 bc_parse_push(p, BC_INST_JUMP);
4274 bc_parse_pushIndex(p, i);
4275
4276 s = bc_lex_next(&p->l);
4277 if (s) return s;
4278
4279 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004280 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004281
4282 return bc_lex_next(&p->l);
4283}
4284
4285static BcStatus bc_parse_func(BcParse *p)
4286{
4287 BcStatus s;
4288 bool var, comma = false;
4289 uint8_t flags;
4290 char *name;
4291
4292 s = bc_lex_next(&p->l);
4293 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004294 if (p->l.t.t != BC_LEX_NAME)
4295 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004296
4297 name = xstrdup(p->l.t.v.v);
4298 bc_parse_addFunc(p, name, &p->fidx);
4299
4300 s = bc_lex_next(&p->l);
4301 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004302 if (p->l.t.t != BC_LEX_LPAREN)
4303 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004304 s = bc_lex_next(&p->l);
4305 if (s) return s;
4306
4307 while (p->l.t.t != BC_LEX_RPAREN) {
4308
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004309 if (p->l.t.t != BC_LEX_NAME)
4310 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004311
4312 ++p->func->nparams;
4313
4314 name = xstrdup(p->l.t.v.v);
4315 s = bc_lex_next(&p->l);
4316 if (s) goto err;
4317
4318 var = p->l.t.t != BC_LEX_LBRACKET;
4319
4320 if (!var) {
4321
4322 s = bc_lex_next(&p->l);
4323 if (s) goto err;
4324
4325 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004326 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004327 goto err;
4328 }
4329
4330 s = bc_lex_next(&p->l);
4331 if (s) goto err;
4332 }
4333
4334 comma = p->l.t.t == BC_LEX_COMMA;
4335 if (comma) {
4336 s = bc_lex_next(&p->l);
4337 if (s) goto err;
4338 }
4339
4340 s = bc_func_insert(p->func, name, var);
4341 if (s) goto err;
4342 }
4343
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004344 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004345
4346 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4347 bc_parse_startBody(p, flags);
4348
4349 s = bc_lex_next(&p->l);
4350 if (s) return s;
4351
4352 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004353 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 -06004354
4355 return s;
4356
4357err:
4358 free(name);
4359 return s;
4360}
4361
4362static BcStatus bc_parse_auto(BcParse *p)
4363{
4364 BcStatus s;
4365 bool comma, var, one;
4366 char *name;
4367
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004368 if (!p->auto_part) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004369 s = bc_lex_next(&p->l);
4370 if (s) return s;
4371
4372 p->auto_part = comma = false;
4373 one = p->l.t.t == BC_LEX_NAME;
4374
4375 while (p->l.t.t == BC_LEX_NAME) {
4376
4377 name = xstrdup(p->l.t.v.v);
4378 s = bc_lex_next(&p->l);
4379 if (s) goto err;
4380
4381 var = p->l.t.t != BC_LEX_LBRACKET;
4382 if (!var) {
4383
4384 s = bc_lex_next(&p->l);
4385 if (s) goto err;
4386
4387 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004388 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004389 goto err;
4390 }
4391
4392 s = bc_lex_next(&p->l);
4393 if (s) goto err;
4394 }
4395
4396 comma = p->l.t.t == BC_LEX_COMMA;
4397 if (comma) {
4398 s = bc_lex_next(&p->l);
4399 if (s) goto err;
4400 }
4401
4402 s = bc_func_insert(p->func, name, var);
4403 if (s) goto err;
4404 }
4405
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004406 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004407 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004408
4409 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004410 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004411
4412 return bc_lex_next(&p->l);
4413
4414err:
4415 free(name);
4416 return s;
4417}
4418
4419static BcStatus bc_parse_body(BcParse *p, bool brace)
4420{
4421 BcStatus s = BC_STATUS_SUCCESS;
4422 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4423
4424 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4425
4426 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4427
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004428 if (!brace) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004429 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4430
4431 if (!p->auto_part) {
4432 s = bc_parse_auto(p);
4433 if (s) return s;
4434 }
4435
4436 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4437 }
4438 else {
4439 s = bc_parse_stmt(p);
4440 if (!s && !brace) s = bc_parse_endBody(p, false);
4441 }
4442
4443 return s;
4444}
4445
4446static BcStatus bc_parse_stmt(BcParse *p)
4447{
4448 BcStatus s = BC_STATUS_SUCCESS;
4449
4450 switch (p->l.t.t) {
4451
4452 case BC_LEX_NLINE:
4453 {
4454 return bc_lex_next(&p->l);
4455 }
4456
4457 case BC_LEX_KEY_ELSE:
4458 {
4459 p->auto_part = false;
4460 break;
4461 }
4462
4463 case BC_LEX_LBRACE:
4464 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004465 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004466
4467 ++p->nbraces;
4468 s = bc_lex_next(&p->l);
4469 if (s) return s;
4470
4471 return bc_parse_body(p, true);
4472 }
4473
4474 case BC_LEX_KEY_AUTO:
4475 {
4476 return bc_parse_auto(p);
4477 }
4478
4479 default:
4480 {
4481 p->auto_part = false;
4482
4483 if (BC_PARSE_IF_END(p)) {
4484 bc_parse_noElse(p);
4485 return BC_STATUS_SUCCESS;
4486 }
4487 else if (BC_PARSE_BODY(p))
4488 return bc_parse_body(p, false);
4489
4490 break;
4491 }
4492 }
4493
4494 switch (p->l.t.t) {
4495
4496 case BC_LEX_OP_INC:
4497 case BC_LEX_OP_DEC:
4498 case BC_LEX_OP_MINUS:
4499 case BC_LEX_OP_BOOL_NOT:
4500 case BC_LEX_LPAREN:
4501 case BC_LEX_NAME:
4502 case BC_LEX_NUMBER:
4503 case BC_LEX_KEY_IBASE:
4504 case BC_LEX_KEY_LAST:
4505 case BC_LEX_KEY_LENGTH:
4506 case BC_LEX_KEY_OBASE:
4507 case BC_LEX_KEY_READ:
4508 case BC_LEX_KEY_SCALE:
4509 case BC_LEX_KEY_SQRT:
4510 {
4511 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4512 break;
4513 }
4514
4515 case BC_LEX_KEY_ELSE:
4516 {
4517 s = bc_parse_else(p);
4518 break;
4519 }
4520
4521 case BC_LEX_SCOLON:
4522 {
4523 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4524 break;
4525 }
4526
4527 case BC_LEX_RBRACE:
4528 {
4529 s = bc_parse_endBody(p, true);
4530 break;
4531 }
4532
4533 case BC_LEX_STR:
4534 {
4535 s = bc_parse_string(p, BC_INST_PRINT_STR);
4536 break;
4537 }
4538
4539 case BC_LEX_KEY_BREAK:
4540 case BC_LEX_KEY_CONTINUE:
4541 {
4542 s = bc_parse_loopExit(p, p->l.t.t);
4543 break;
4544 }
4545
4546 case BC_LEX_KEY_FOR:
4547 {
4548 s = bc_parse_for(p);
4549 break;
4550 }
4551
4552 case BC_LEX_KEY_HALT:
4553 {
4554 bc_parse_push(p, BC_INST_HALT);
4555 s = bc_lex_next(&p->l);
4556 break;
4557 }
4558
4559 case BC_LEX_KEY_IF:
4560 {
4561 s = bc_parse_if(p);
4562 break;
4563 }
4564
4565 case BC_LEX_KEY_LIMITS:
4566 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004567 // "limits" is a compile-time command,
4568 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004569 s = bc_lex_next(&p->l);
4570 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004571 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4572 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4573 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4574 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4575 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4576 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4577 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4578 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004579 break;
4580 }
4581
4582 case BC_LEX_KEY_PRINT:
4583 {
4584 s = bc_parse_print(p);
4585 break;
4586 }
4587
4588 case BC_LEX_KEY_QUIT:
4589 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004590 // "quit" is a compile-time command. For example,
4591 // "if (0 == 1) quit" terminates when parsing the statement,
4592 // not when it is executed
4593 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004594 }
4595
4596 case BC_LEX_KEY_RETURN:
4597 {
4598 s = bc_parse_return(p);
4599 break;
4600 }
4601
4602 case BC_LEX_KEY_WHILE:
4603 {
4604 s = bc_parse_while(p);
4605 break;
4606 }
4607
4608 default:
4609 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004610 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004611 break;
4612 }
4613 }
4614
4615 return s;
4616}
4617
4618static BcStatus bc_parse_parse(BcParse *p)
4619{
4620 BcStatus s;
4621
4622 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004623 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 -06004624 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004625 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004626 s = bc_parse_func(p);
4627 }
4628 else
4629 s = bc_parse_stmt(p);
4630
Denys Vlasenkod38af482018-12-04 19:11:02 +01004631 if (s || G_interrupt) {
4632 bc_parse_reset(p);
4633 s = BC_STATUS_FAILURE;
4634 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004635
4636 return s;
4637}
4638
4639static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4640{
4641 BcStatus s = BC_STATUS_SUCCESS;
4642 BcInst prev = BC_INST_PRINT;
4643 BcLexType top, t = p->l.t.t;
4644 size_t nexprs = 0, ops_bgn = p->ops.len;
4645 uint32_t i, nparens, nrelops;
4646 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4647
4648 paren_first = p->l.t.t == BC_LEX_LPAREN;
4649 nparens = nrelops = 0;
4650 paren_expr = rprn = done = get_token = assign = false;
4651 bin_last = true;
4652
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004653 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004654 switch (t) {
4655
4656 case BC_LEX_OP_INC:
4657 case BC_LEX_OP_DEC:
4658 {
4659 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4660 rprn = get_token = bin_last = false;
4661 break;
4662 }
4663
4664 case BC_LEX_OP_MINUS:
4665 {
4666 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4667 rprn = get_token = false;
4668 bin_last = prev == BC_INST_MINUS;
4669 break;
4670 }
4671
4672 case BC_LEX_OP_ASSIGN_POWER:
4673 case BC_LEX_OP_ASSIGN_MULTIPLY:
4674 case BC_LEX_OP_ASSIGN_DIVIDE:
4675 case BC_LEX_OP_ASSIGN_MODULUS:
4676 case BC_LEX_OP_ASSIGN_PLUS:
4677 case BC_LEX_OP_ASSIGN_MINUS:
4678 case BC_LEX_OP_ASSIGN:
4679 {
4680 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4681 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4682 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4683 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004684 s = bc_error("bad assignment:"
4685 " left side must be scale,"
4686 " ibase, obase, last, var,"
4687 " or array element"
4688 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004689 break;
4690 }
4691 }
4692 // Fallthrough.
4693 case BC_LEX_OP_POWER:
4694 case BC_LEX_OP_MULTIPLY:
4695 case BC_LEX_OP_DIVIDE:
4696 case BC_LEX_OP_MODULUS:
4697 case BC_LEX_OP_PLUS:
4698 case BC_LEX_OP_REL_EQ:
4699 case BC_LEX_OP_REL_LE:
4700 case BC_LEX_OP_REL_GE:
4701 case BC_LEX_OP_REL_NE:
4702 case BC_LEX_OP_REL_LT:
4703 case BC_LEX_OP_REL_GT:
4704 case BC_LEX_OP_BOOL_NOT:
4705 case BC_LEX_OP_BOOL_OR:
4706 case BC_LEX_OP_BOOL_AND:
4707 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004708 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4709 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4710 ) {
4711 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004712 }
4713
4714 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4715 prev = BC_PARSE_TOKEN_INST(t);
4716 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4717 rprn = get_token = false;
4718 bin_last = t != BC_LEX_OP_BOOL_NOT;
4719
4720 break;
4721 }
4722
4723 case BC_LEX_LPAREN:
4724 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004725 if (BC_PARSE_LEAF(prev, rprn))
4726 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004727 ++nparens;
4728 paren_expr = rprn = bin_last = false;
4729 get_token = true;
4730 bc_vec_push(&p->ops, &t);
4731
4732 break;
4733 }
4734
4735 case BC_LEX_RPAREN:
4736 {
4737 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004738 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004739
4740 if (nparens == 0) {
4741 s = BC_STATUS_SUCCESS;
4742 done = true;
4743 get_token = false;
4744 break;
4745 }
4746 else if (!paren_expr)
4747 return BC_STATUS_PARSE_EMPTY_EXP;
4748
4749 --nparens;
4750 paren_expr = rprn = true;
4751 get_token = bin_last = false;
4752
4753 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4754
4755 break;
4756 }
4757
4758 case BC_LEX_NAME:
4759 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004760 if (BC_PARSE_LEAF(prev, rprn))
4761 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004762 paren_expr = true;
4763 rprn = get_token = bin_last = false;
4764 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4765 ++nexprs;
4766
4767 break;
4768 }
4769
4770 case BC_LEX_NUMBER:
4771 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004772 if (BC_PARSE_LEAF(prev, rprn))
4773 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004774 bc_parse_number(p, &prev, &nexprs);
4775 paren_expr = get_token = true;
4776 rprn = bin_last = false;
4777
4778 break;
4779 }
4780
4781 case BC_LEX_KEY_IBASE:
4782 case BC_LEX_KEY_LAST:
4783 case BC_LEX_KEY_OBASE:
4784 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004785 if (BC_PARSE_LEAF(prev, rprn))
4786 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004787 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4788 bc_parse_push(p, (char) prev);
4789
4790 paren_expr = get_token = true;
4791 rprn = bin_last = false;
4792 ++nexprs;
4793
4794 break;
4795 }
4796
4797 case BC_LEX_KEY_LENGTH:
4798 case BC_LEX_KEY_SQRT:
4799 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004800 if (BC_PARSE_LEAF(prev, rprn))
4801 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004802 s = bc_parse_builtin(p, t, flags, &prev);
4803 paren_expr = true;
4804 rprn = get_token = bin_last = false;
4805 ++nexprs;
4806
4807 break;
4808 }
4809
4810 case BC_LEX_KEY_READ:
4811 {
4812 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004813 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004814 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004815 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06004816 else
4817 s = bc_parse_read(p);
4818
4819 paren_expr = true;
4820 rprn = get_token = bin_last = false;
4821 ++nexprs;
4822 prev = BC_INST_READ;
4823
4824 break;
4825 }
4826
4827 case BC_LEX_KEY_SCALE:
4828 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004829 if (BC_PARSE_LEAF(prev, rprn))
4830 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004831 s = bc_parse_scale(p, &prev, flags);
4832 paren_expr = true;
4833 rprn = get_token = bin_last = false;
4834 ++nexprs;
4835 prev = BC_INST_SCALE;
4836
4837 break;
4838 }
4839
4840 default:
4841 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004842 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004843 break;
4844 }
4845 }
4846
4847 if (!s && get_token) s = bc_lex_next(&p->l);
4848 }
4849
4850 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004851 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004852
4853 while (p->ops.len > ops_bgn) {
4854
4855 top = BC_PARSE_TOP_OP(p);
4856 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4857
4858 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004859 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004860
4861 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4862
4863 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4864 bc_vec_pop(&p->ops);
4865 }
4866
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004867 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4868 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004869
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004870 for (i = 0; i < next.len; ++i)
4871 if (t == next.tokens[i])
4872 goto ok;
4873 return bc_error("bad expression");
4874 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004875
4876 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004877 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004878 if (s) return s;
4879 }
4880 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004881 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004882 if (s) return s;
4883 }
4884
4885 if (flags & BC_PARSE_PRINT) {
4886 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4887 bc_parse_push(p, BC_INST_POP);
4888 }
4889
4890 return s;
4891}
4892
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004893static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004894{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004895 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004896}
4897
4898static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4899{
4900 return bc_parse_expr(p, flags, bc_parse_next_read);
4901}
4902#endif // ENABLE_BC
4903
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004904#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004905static BcStatus dc_parse_register(BcParse *p)
4906{
4907 BcStatus s;
4908 char *name;
4909
4910 s = bc_lex_next(&p->l);
4911 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004912 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004913
4914 name = xstrdup(p->l.t.v.v);
4915 bc_parse_pushName(p, name);
4916
4917 return s;
4918}
4919
4920static BcStatus dc_parse_string(BcParse *p)
4921{
4922 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004923 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004924
4925 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4926 name = xstrdup(b);
4927
4928 str = xstrdup(p->l.t.v.v);
4929 bc_parse_push(p, BC_INST_STR);
4930 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004931 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004932 bc_parse_addFunc(p, name, &idx);
4933
4934 return bc_lex_next(&p->l);
4935}
4936
4937static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4938{
4939 BcStatus s;
4940
4941 bc_parse_push(p, inst);
4942 if (name) {
4943 s = dc_parse_register(p);
4944 if (s) return s;
4945 }
4946
4947 if (store) {
4948 bc_parse_push(p, BC_INST_SWAP);
4949 bc_parse_push(p, BC_INST_ASSIGN);
4950 bc_parse_push(p, BC_INST_POP);
4951 }
4952
4953 return bc_lex_next(&p->l);
4954}
4955
4956static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4957{
4958 BcStatus s;
4959
4960 bc_parse_push(p, inst);
4961 bc_parse_push(p, BC_INST_EXEC_COND);
4962
4963 s = dc_parse_register(p);
4964 if (s) return s;
4965
4966 s = bc_lex_next(&p->l);
4967 if (s) return s;
4968
4969 if (p->l.t.t == BC_LEX_ELSE) {
4970 s = dc_parse_register(p);
4971 if (s) return s;
4972 s = bc_lex_next(&p->l);
4973 }
4974 else
4975 bc_parse_push(p, BC_PARSE_STREND);
4976
4977 return s;
4978}
4979
4980static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4981{
4982 BcStatus s = BC_STATUS_SUCCESS;
4983 BcInst prev;
4984 uint8_t inst;
4985 bool assign, get_token = false;
4986
4987 switch (t) {
4988
4989 case BC_LEX_OP_REL_EQ:
4990 case BC_LEX_OP_REL_LE:
4991 case BC_LEX_OP_REL_GE:
4992 case BC_LEX_OP_REL_NE:
4993 case BC_LEX_OP_REL_LT:
4994 case BC_LEX_OP_REL_GT:
4995 {
4996 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
4997 break;
4998 }
4999
5000 case BC_LEX_SCOLON:
5001 case BC_LEX_COLON:
5002 {
5003 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5004 break;
5005 }
5006
5007 case BC_LEX_STR:
5008 {
5009 s = dc_parse_string(p);
5010 break;
5011 }
5012
5013 case BC_LEX_NEG:
5014 case BC_LEX_NUMBER:
5015 {
5016 if (t == BC_LEX_NEG) {
5017 s = bc_lex_next(&p->l);
5018 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005019 if (p->l.t.t != BC_LEX_NUMBER)
5020 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005021 }
5022
5023 bc_parse_number(p, &prev, &p->nbraces);
5024
5025 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5026 get_token = true;
5027
5028 break;
5029 }
5030
5031 case BC_LEX_KEY_READ:
5032 {
5033 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005034 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005035 else
5036 bc_parse_push(p, BC_INST_READ);
5037 get_token = true;
5038 break;
5039 }
5040
5041 case BC_LEX_OP_ASSIGN:
5042 case BC_LEX_STORE_PUSH:
5043 {
5044 assign = t == BC_LEX_OP_ASSIGN;
5045 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5046 s = dc_parse_mem(p, inst, true, assign);
5047 break;
5048 }
5049
5050 case BC_LEX_LOAD:
5051 case BC_LEX_LOAD_POP:
5052 {
5053 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5054 s = dc_parse_mem(p, inst, true, false);
5055 break;
5056 }
5057
5058 case BC_LEX_STORE_IBASE:
5059 case BC_LEX_STORE_SCALE:
5060 case BC_LEX_STORE_OBASE:
5061 {
5062 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5063 s = dc_parse_mem(p, inst, false, true);
5064 break;
5065 }
5066
5067 default:
5068 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005069 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005070 get_token = true;
5071 break;
5072 }
5073 }
5074
5075 if (!s && get_token) s = bc_lex_next(&p->l);
5076
5077 return s;
5078}
5079
5080static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5081{
5082 BcStatus s = BC_STATUS_SUCCESS;
5083 BcInst inst;
5084 BcLexType t;
5085
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005086 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005087
5088 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5089
5090 inst = dc_parse_insts[t];
5091
5092 if (inst != BC_INST_INVALID) {
5093 bc_parse_push(p, inst);
5094 s = bc_lex_next(&p->l);
5095 }
5096 else
5097 s = dc_parse_token(p, t, flags);
5098 }
5099
5100 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5101 bc_parse_push(p, BC_INST_POP_EXEC);
5102
5103 return s;
5104}
5105
5106static BcStatus dc_parse_parse(BcParse *p)
5107{
5108 BcStatus s;
5109
5110 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005111 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005112 else
5113 s = dc_parse_expr(p, 0);
5114
Denys Vlasenkod38af482018-12-04 19:11:02 +01005115 if (s || G_interrupt) {
5116 bc_parse_reset(p);
5117 s = BC_STATUS_FAILURE;
5118 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005119
5120 return s;
5121}
5122
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005123static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005124{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005125 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005126}
5127#endif // ENABLE_DC
5128
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005129static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005130{
5131 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005132 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005133 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005134 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005135 }
5136}
5137
5138static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5139{
5140 if (IS_BC) {
5141 return bc_parse_expression(p, flags);
5142 } else {
5143 return dc_parse_expr(p, flags);
5144 }
5145}
5146
Denys Vlasenkodf515392018-12-02 19:27:48 +01005147static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005148{
Gavin Howard01055ba2018-11-03 11:00:21 -06005149 BcId e, *ptr;
5150 BcVec *v, *map;
5151 size_t i;
5152 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005153 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005154
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005155 v = var ? &G.prog.vars : &G.prog.arrs;
5156 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005157
5158 e.name = id;
5159 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005160 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005161
5162 if (new) {
5163 bc_array_init(&data.v, var);
5164 bc_vec_push(v, &data.v);
5165 }
5166
5167 ptr = bc_vec_item(map, i);
5168 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005169 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005170}
5171
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005172static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005173{
5174 BcStatus s = BC_STATUS_SUCCESS;
5175
5176 switch (r->t) {
5177
5178 case BC_RESULT_STR:
5179 case BC_RESULT_TEMP:
5180 case BC_RESULT_IBASE:
5181 case BC_RESULT_SCALE:
5182 case BC_RESULT_OBASE:
5183 {
5184 *num = &r->d.n;
5185 break;
5186 }
5187
5188 case BC_RESULT_CONSTANT:
5189 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005190 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005191 size_t base_t, len = strlen(*str);
5192 BcNum *base;
5193
5194 bc_num_init(&r->d.n, len);
5195
5196 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005197 base = hex ? &G.prog.hexb : &G.prog.ib;
5198 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005199 s = bc_num_parse(&r->d.n, *str, base, base_t);
5200
5201 if (s) {
5202 bc_num_free(&r->d.n);
5203 return s;
5204 }
5205
5206 *num = &r->d.n;
5207 r->t = BC_RESULT_TEMP;
5208
5209 break;
5210 }
5211
5212 case BC_RESULT_VAR:
5213 case BC_RESULT_ARRAY:
5214 case BC_RESULT_ARRAY_ELEM:
5215 {
5216 BcVec *v;
5217
Denys Vlasenkodf515392018-12-02 19:27:48 +01005218 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005219
5220 if (r->t == BC_RESULT_ARRAY_ELEM) {
5221 v = bc_vec_top(v);
5222 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5223 *num = bc_vec_item(v, r->d.id.idx);
5224 }
5225 else
5226 *num = bc_vec_top(v);
5227
5228 break;
5229 }
5230
5231 case BC_RESULT_LAST:
5232 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005233 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005234 break;
5235 }
5236
5237 case BC_RESULT_ONE:
5238 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005239 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005240 break;
5241 }
5242 }
5243
5244 return s;
5245}
5246
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005247static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005248 BcResult **r, BcNum **rn, bool assign)
5249{
5250 BcStatus s;
5251 bool hex;
5252 BcResultType lt, rt;
5253
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005254 if (!BC_PROG_STACK(&G.prog.results, 2))
5255 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005256
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005257 *r = bc_vec_item_rev(&G.prog.results, 0);
5258 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005259
5260 lt = (*l)->t;
5261 rt = (*r)->t;
5262 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5263
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005264 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005265 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005266 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005267 if (s) return s;
5268
5269 // We run this again under these conditions in case any vector has been
5270 // reallocated out from under the BcNums or arrays we had.
5271 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005272 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005273 if (s) return s;
5274 }
5275
5276 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005277 return bc_error("variable is wrong type");
5278 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5279 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005280
Gavin Howard01055ba2018-11-03 11:00:21 -06005281 return s;
5282}
5283
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005284static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005285{
5286 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005287 bc_vec_pop(&G.prog.results);
5288 bc_vec_pop(&G.prog.results);
5289 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005290}
5291
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005292static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005293{
5294 BcStatus s;
5295
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005296 if (!BC_PROG_STACK(&G.prog.results, 1))
5297 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005298 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005299
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005300 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005301 if (s) return s;
5302
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005303 if (!BC_PROG_NUM((*r), (*n)))
5304 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005305
5306 return s;
5307}
5308
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005309static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005310{
5311 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005312 bc_vec_pop(&G.prog.results);
5313 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005314}
5315
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005316static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005317{
5318 BcStatus s;
5319 BcResult *opd1, *opd2, res;
5320 BcNum *n1, *n2 = NULL;
5321
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005322 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005323 if (s) return s;
5324 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5325
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005326 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005327 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005328 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005329
5330 return s;
5331
5332err:
5333 bc_num_free(&res.d.n);
5334 return s;
5335}
5336
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005337static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005338{
5339 BcStatus s;
5340 BcParse parse;
5341 BcVec buf;
5342 BcInstPtr ip;
5343 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005344 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005345
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005346 for (i = 0; i < G.prog.stack.len; ++i) {
5347 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005348 if (ip_ptr->func == BC_PROG_READ)
5349 return bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005350 }
5351
5352 bc_vec_npop(&f->code, f->code.len);
5353 bc_vec_init(&buf, sizeof(char), NULL);
5354
5355 s = bc_read_line(&buf, "read> ");
5356 if (s) goto io_err;
5357
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005358 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005359 bc_lex_file(&parse.l, bc_program_stdin_name);
5360
5361 s = bc_parse_text(&parse, buf.v);
5362 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005363 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005364 if (s) goto exec_err;
5365
5366 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005367 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005368 goto exec_err;
5369 }
5370
5371 ip.func = BC_PROG_READ;
5372 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005373 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005374
5375 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005376 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005377
5378 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005379 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005380
5381exec_err:
5382 bc_parse_free(&parse);
5383io_err:
5384 bc_vec_free(&buf);
5385 return s;
5386}
5387
5388static size_t bc_program_index(char *code, size_t *bgn)
5389{
5390 char amt = code[(*bgn)++], i = 0;
5391 size_t res = 0;
5392
5393 for (; i < amt; ++i, ++(*bgn))
5394 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5395
5396 return res;
5397}
5398
5399static char *bc_program_name(char *code, size_t *bgn)
5400{
5401 size_t i;
5402 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5403
5404 s = xmalloc(ptr - str + 1);
5405 c = code[(*bgn)++];
5406
5407 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5408 s[i] = c;
5409
5410 s[i] = '\0';
5411
5412 return s;
5413}
5414
5415static void bc_program_printString(const char *str, size_t *nchars)
5416{
5417 size_t i, len = strlen(str);
5418
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005419#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005420 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005421 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005422 return;
5423 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005424#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005425
5426 for (i = 0; i < len; ++i, ++(*nchars)) {
5427
5428 int c = str[i];
5429
5430 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005431 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005432 else {
5433
5434 c = str[++i];
5435
5436 switch (c) {
5437
5438 case 'a':
5439 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005440 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005441 break;
5442 }
5443
5444 case 'b':
5445 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005446 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005447 break;
5448 }
5449
5450 case '\\':
5451 case 'e':
5452 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005453 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005454 break;
5455 }
5456
5457 case 'f':
5458 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005459 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005460 break;
5461 }
5462
5463 case 'n':
5464 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005465 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005466 *nchars = SIZE_MAX;
5467 break;
5468 }
5469
5470 case 'r':
5471 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005472 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005473 break;
5474 }
5475
5476 case 'q':
5477 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005478 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005479 break;
5480 }
5481
5482 case 't':
5483 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005484 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005485 break;
5486 }
5487
5488 default:
5489 {
5490 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005491 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005492 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005493 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005494 break;
5495 }
5496 }
5497 }
5498 }
5499}
5500
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005501static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005502{
5503 BcStatus s = BC_STATUS_SUCCESS;
5504 BcResult *r;
5505 size_t len, i;
5506 char *str;
5507 BcNum *num = NULL;
5508 bool pop = inst != BC_INST_PRINT;
5509
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005510 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5511 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005512
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005513 r = bc_vec_item_rev(&G.prog.results, idx);
5514 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005515 if (s) return s;
5516
5517 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005518 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5519 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005520 }
5521 else {
5522
5523 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005524 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005525
5526 if (inst == BC_INST_PRINT_STR) {
5527 for (i = 0, len = strlen(str); i < len; ++i) {
5528 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005529 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005530 if (c == '\n') G.prog.nchars = SIZE_MAX;
5531 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005532 }
5533 }
5534 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005535 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005536 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005537 }
5538 }
5539
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005540 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005541
5542 return s;
5543}
5544
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005545static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005546{
5547 BcStatus s;
5548 BcResult res, *ptr;
5549 BcNum *num = NULL;
5550
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005551 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005552 if (s) return s;
5553
5554 bc_num_init(&res.d.n, num->len);
5555 bc_num_copy(&res.d.n, num);
5556 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5557
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005558 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005559
5560 return s;
5561}
5562
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005563static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005564{
5565 BcStatus s;
5566 BcResult *opd1, *opd2, res;
5567 BcNum *n1, *n2;
5568 bool cond = 0;
5569 ssize_t cmp;
5570
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005571 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005572 if (s) return s;
5573 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5574
5575 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005576 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005577 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005578 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005579 else {
5580
5581 cmp = bc_num_cmp(n1, n2);
5582
5583 switch (inst) {
5584
5585 case BC_INST_REL_EQ:
5586 {
5587 cond = cmp == 0;
5588 break;
5589 }
5590
5591 case BC_INST_REL_LE:
5592 {
5593 cond = cmp <= 0;
5594 break;
5595 }
5596
5597 case BC_INST_REL_GE:
5598 {
5599 cond = cmp >= 0;
5600 break;
5601 }
5602
5603 case BC_INST_REL_NE:
5604 {
5605 cond = cmp != 0;
5606 break;
5607 }
5608
5609 case BC_INST_REL_LT:
5610 {
5611 cond = cmp < 0;
5612 break;
5613 }
5614
5615 case BC_INST_REL_GT:
5616 {
5617 cond = cmp > 0;
5618 break;
5619 }
5620 }
5621 }
5622
5623 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5624
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005625 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005626
5627 return s;
5628}
5629
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005630#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005631static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005632 bool push)
5633{
5634 BcNum n2;
5635 BcResult res;
5636
5637 memset(&n2, 0, sizeof(BcNum));
5638 n2.rdx = res.d.id.idx = r->d.id.idx;
5639 res.t = BC_RESULT_STR;
5640
5641 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005642 if (!BC_PROG_STACK(&G.prog.results, 2))
5643 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005644 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005645 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005646 }
5647
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005648 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005649
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005650 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005651 bc_vec_push(v, &n2);
5652
5653 return BC_STATUS_SUCCESS;
5654}
5655#endif // ENABLE_DC
5656
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005657static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005658{
5659 BcStatus s;
5660 BcResult *ptr, r;
5661 BcVec *v;
5662 BcNum *n;
5663
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005664 if (!BC_PROG_STACK(&G.prog.results, 1))
5665 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005666
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005667 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005668 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5669 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005670 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005671
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005672#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005673 if (ptr->t == BC_RESULT_STR && !var)
5674 return bc_error("variable is wrong type");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005675 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005676#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005677
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005678 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005679 if (s) return s;
5680
5681 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005682 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005683
5684 if (var) {
5685 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5686 bc_num_copy(&r.d.n, n);
5687 }
5688 else {
5689 bc_array_init(&r.d.v, true);
5690 bc_array_copy(&r.d.v, (BcVec *) n);
5691 }
5692
5693 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005694 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005695
5696 return s;
5697}
5698
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005699static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005700{
5701 BcStatus s;
5702 BcResult *left, *right, res;
5703 BcNum *l = NULL, *r = NULL;
5704 unsigned long val, max;
5705 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5706
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005707 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005708 if (s) return s;
5709
5710 ib = left->t == BC_RESULT_IBASE;
5711 sc = left->t == BC_RESULT_SCALE;
5712
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005713#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005714
5715 if (right->t == BC_RESULT_STR) {
5716
5717 BcVec *v;
5718
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005719 if (left->t != BC_RESULT_VAR)
5720 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005721 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005722
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005723 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005724 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005725#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005726
5727 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005728 return bc_error("bad assignment:"
5729 " left side must be scale,"
5730 " ibase, obase, last, var,"
5731 " or array element"
5732 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005733
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005734#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005735 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005736 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005737
5738 if (assign)
5739 bc_num_copy(l, r);
5740 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005741 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005742
5743 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005744#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005745 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005746#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005747
5748 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005749 static const char *const msg[] = {
5750 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5751 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5752 "?1", //BC_RESULT_LAST
5753 "?2", //BC_RESULT_CONSTANT
5754 "?3", //BC_RESULT_ONE
5755 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5756 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005757 size_t *ptr;
5758
5759 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005760 if (s)
5761 return s;
5762 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005763 if (sc) {
5764 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005765 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005766 }
5767 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005768 if (val < BC_NUM_MIN_BASE)
5769 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005770 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005771 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005772 }
5773
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005774 if (val > max)
5775 return bc_error(msg[s]);
5776 if (!sc)
5777 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005778
5779 *ptr = (size_t) val;
5780 s = BC_STATUS_SUCCESS;
5781 }
5782
5783 bc_num_init(&res.d.n, l->len);
5784 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005785 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005786
5787 return s;
5788}
5789
Denys Vlasenko416ce762018-12-02 20:57:17 +01005790#if !ENABLE_DC
5791#define bc_program_pushVar(code, bgn, pop, copy) \
5792 bc_program_pushVar(code, bgn)
5793// for bc, 'pop' and 'copy' are always false
5794#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005795static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005796 bool pop, bool copy)
5797{
5798 BcStatus s = BC_STATUS_SUCCESS;
5799 BcResult r;
5800 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005801
5802 r.t = BC_RESULT_VAR;
5803 r.d.id.name = name;
5804
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005805#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005806 {
5807 BcVec *v = bc_program_search(name, true);
5808 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005809
Denys Vlasenko416ce762018-12-02 20:57:17 +01005810 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005811
Denys Vlasenko416ce762018-12-02 20:57:17 +01005812 if (!BC_PROG_STACK(v, 2 - copy)) {
5813 free(name);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005814 return bc_error("stack has too few elements");
Denys Vlasenko416ce762018-12-02 20:57:17 +01005815 }
5816
Gavin Howard01055ba2018-11-03 11:00:21 -06005817 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005818 name = NULL;
5819
5820 if (!BC_PROG_STR(num)) {
5821
5822 r.t = BC_RESULT_TEMP;
5823
5824 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5825 bc_num_copy(&r.d.n, num);
5826 }
5827 else {
5828 r.t = BC_RESULT_STR;
5829 r.d.id.idx = num->rdx;
5830 }
5831
5832 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005833 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005834 }
5835#endif // ENABLE_DC
5836
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005837 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005838
5839 return s;
5840}
5841
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005842static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005843 char inst)
5844{
5845 BcStatus s = BC_STATUS_SUCCESS;
5846 BcResult r;
5847 BcNum *num;
5848
5849 r.d.id.name = bc_program_name(code, bgn);
5850
5851 if (inst == BC_INST_ARRAY) {
5852 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005853 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005854 }
5855 else {
5856
5857 BcResult *operand;
5858 unsigned long temp;
5859
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005860 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005861 if (s) goto err;
5862 s = bc_num_ulong(num, &temp);
5863 if (s) goto err;
5864
5865 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005866 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005867 goto err;
5868 }
5869
5870 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005871 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005872 }
5873
5874err:
5875 if (s) free(r.d.id.name);
5876 return s;
5877}
5878
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005879#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005880static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005881{
5882 BcStatus s;
5883 BcResult *ptr, res, copy;
5884 BcNum *num = NULL;
5885 char inst2 = inst;
5886
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005887 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005888 if (s) return s;
5889
5890 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5891 copy.t = BC_RESULT_TEMP;
5892 bc_num_init(&copy.d.n, num->len);
5893 bc_num_copy(&copy.d.n, num);
5894 }
5895
5896 res.t = BC_RESULT_ONE;
5897 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5898 BC_INST_ASSIGN_PLUS :
5899 BC_INST_ASSIGN_MINUS;
5900
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005901 bc_vec_push(&G.prog.results, &res);
5902 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005903
5904 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005905 bc_vec_pop(&G.prog.results);
5906 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005907 }
5908
5909 return s;
5910}
5911
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005912static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005913{
5914 BcStatus s = BC_STATUS_SUCCESS;
5915 BcInstPtr ip;
5916 size_t i, nparams = bc_program_index(code, idx);
5917 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005918 BcId *a;
5919 BcResultData param;
5920 BcResult *arg;
5921
5922 ip.idx = 0;
5923 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005924 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005925
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005926 if (func->code.len == 0) {
5927 return bc_error("undefined function");
5928 }
5929 if (nparams != func->nparams) {
5930 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5931 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005932 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005933
5934 for (i = 0; i < nparams; ++i) {
5935
5936 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005937 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005938
5939 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005940 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005941
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005942 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005943 if (s) return s;
5944 }
5945
5946 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005947 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005948
5949 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005950 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005951
5952 if (a->idx) {
5953 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5954 bc_vec_push(v, &param.n);
5955 }
5956 else {
5957 bc_array_init(&param.v, true);
5958 bc_vec_push(v, &param.v);
5959 }
5960 }
5961
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005962 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005963
5964 return BC_STATUS_SUCCESS;
5965}
5966
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005967static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005968{
5969 BcStatus s;
5970 BcResult res;
5971 BcFunc *f;
5972 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005973 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06005974
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005975 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005976 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005977
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005978 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005979 res.t = BC_RESULT_TEMP;
5980
5981 if (inst == BC_INST_RET) {
5982
5983 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005984 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005985
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005986 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005987 if (s) return s;
5988 bc_num_init(&res.d.n, num->len);
5989 bc_num_copy(&res.d.n, num);
5990 }
5991 else {
5992 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5993 bc_num_zero(&res.d.n);
5994 }
5995
5996 // We need to pop arguments as well, so this takes that into account.
5997 for (i = 0; i < f->autos.len; ++i) {
5998
5999 BcVec *v;
6000 BcId *a = bc_vec_item(&f->autos, i);
6001
Denys Vlasenkodf515392018-12-02 19:27:48 +01006002 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006003 bc_vec_pop(v);
6004 }
6005
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006006 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6007 bc_vec_push(&G.prog.results, &res);
6008 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006009
6010 return BC_STATUS_SUCCESS;
6011}
6012#endif // ENABLE_BC
6013
6014static unsigned long bc_program_scale(BcNum *n)
6015{
6016 return (unsigned long) n->rdx;
6017}
6018
6019static unsigned long bc_program_len(BcNum *n)
6020{
6021 unsigned long len = n->len;
6022 size_t i;
6023
6024 if (n->rdx != n->len) return len;
6025 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6026
6027 return len;
6028}
6029
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006030static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006031{
6032 BcStatus s;
6033 BcResult *opnd;
6034 BcNum *num = NULL;
6035 BcResult res;
6036 bool len = inst == BC_INST_LENGTH;
6037
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006038 if (!BC_PROG_STACK(&G.prog.results, 1))
6039 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006040 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006041
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006042 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006043 if (s) return s;
6044
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006045#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006046 if (!BC_PROG_NUM(opnd, num) && !len)
6047 return bc_error("variable is wrong type");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006048#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006049
6050 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6051
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006052 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006053#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006054 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006055 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006056 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006057#endif
6058#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006059 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6060
6061 char **str;
6062 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6063
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006064 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006065 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006066 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006067#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006068 else {
6069 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006070 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006071 }
6072
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006073 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006074
6075 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006076}
6077
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006078#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006079static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006080{
6081 BcStatus s;
6082 BcResult *opd1, *opd2, res, res2;
6083 BcNum *n1, *n2 = NULL;
6084
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006085 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006086 if (s) return s;
6087
6088 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6089 bc_num_init(&res2.d.n, n2->len);
6090
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006091 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006092 if (s) goto err;
6093
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006094 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006095 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006096 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006097
6098 return s;
6099
6100err:
6101 bc_num_free(&res2.d.n);
6102 bc_num_free(&res.d.n);
6103 return s;
6104}
6105
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006106static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006107{
6108 BcStatus s;
6109 BcResult *r1, *r2, *r3, res;
6110 BcNum *n1, *n2, *n3;
6111
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006112 if (!BC_PROG_STACK(&G.prog.results, 3))
6113 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006114 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006115 if (s) return s;
6116
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006117 r1 = bc_vec_item_rev(&G.prog.results, 2);
6118 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006119 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006120 if (!BC_PROG_NUM(r1, n1))
6121 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006122
6123 // Make sure that the values have their pointers updated, if necessary.
6124 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6125
6126 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006127 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006128 if (s) return s;
6129 }
6130
6131 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006132 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006133 if (s) return s;
6134 }
6135 }
6136
6137 bc_num_init(&res.d.n, n3->len);
6138 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6139 if (s) goto err;
6140
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006141 bc_vec_pop(&G.prog.results);
6142 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006143
6144 return s;
6145
6146err:
6147 bc_num_free(&res.d.n);
6148 return s;
6149}
6150
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006151static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006152{
Gavin Howard01055ba2018-11-03 11:00:21 -06006153 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006154 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006155
6156 res.t = BC_RESULT_TEMP;
6157
6158 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006159 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006160 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006161}
6162
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006163static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006164{
6165 BcStatus s;
6166 BcResult *r, res;
6167 BcNum *num = NULL, n;
6168 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006169 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006170 unsigned long val;
6171
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006172 if (!BC_PROG_STACK(&G.prog.results, 1))
6173 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006174 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006175
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006176 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006177 if (s) return s;
6178
6179 if (BC_PROG_NUM(r, num)) {
6180
6181 bc_num_init(&n, BC_NUM_DEF_SIZE);
6182 bc_num_copy(&n, num);
6183 bc_num_truncate(&n, n.rdx);
6184
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006185 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006186 if (s) goto num_err;
6187 s = bc_num_ulong(&n, &val);
6188 if (s) goto num_err;
6189
6190 c = (char) val;
6191
6192 bc_num_free(&n);
6193 }
6194 else {
6195 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006196 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006197 c = str2[0];
6198 }
6199
6200 str = xmalloc(2);
6201 str[0] = c;
6202 str[1] = '\0';
6203
6204 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006205 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006206
6207 if (idx != len + BC_PROG_REQ_FUNCS) {
6208
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006209 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6210 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006211 len = idx;
6212 break;
6213 }
6214 }
6215
6216 free(str);
6217 }
6218 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006219 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006220
6221 res.t = BC_RESULT_STR;
6222 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006223 bc_vec_pop(&G.prog.results);
6224 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006225
6226 return BC_STATUS_SUCCESS;
6227
6228num_err:
6229 bc_num_free(&n);
6230 return s;
6231}
6232
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006233static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006234{
6235 BcStatus s;
6236 BcResult *r;
6237 BcNum *n = NULL;
6238 size_t idx;
6239 char *str;
6240
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006241 if (!BC_PROG_STACK(&G.prog.results, 1))
6242 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006243 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006244
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006245 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006246 if (s) return s;
6247
6248 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006249 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006250 else {
6251 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006252 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006253 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006254 }
6255
6256 return s;
6257}
6258
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006259static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006260{
6261 BcStatus s;
6262 BcResult *opnd;
6263 BcNum *num = NULL;
6264 unsigned long val;
6265
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006266 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006267 if (s) return s;
6268 s = bc_num_ulong(num, &val);
6269 if (s) return s;
6270
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006271 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006272
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006273 if (G.prog.stack.len < val)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006274 return bc_error("stack has too few elements");
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006275 if (G.prog.stack.len == val)
6276 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006277
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006278 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006279
6280 return s;
6281}
6282
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006283static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006284 bool cond)
6285{
6286 BcStatus s = BC_STATUS_SUCCESS;
6287 BcResult *r;
6288 char **str;
6289 BcFunc *f;
6290 BcParse prs;
6291 BcInstPtr ip;
6292 size_t fidx, sidx;
6293 BcNum *n;
6294 bool exec;
6295
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006296 if (!BC_PROG_STACK(&G.prog.results, 1))
6297 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006298
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006299 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006300
6301 if (cond) {
6302
Gavin Howard01055ba2018-11-03 11:00:21 -06006303 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6304
6305 if (code[*bgn] == BC_PARSE_STREND)
6306 (*bgn) += 1;
6307 else
6308 else_name = bc_program_name(code, bgn);
6309
6310 exec = r->d.n.len != 0;
6311
6312 if (exec)
6313 name = then_name;
6314 else if (else_name != NULL) {
6315 exec = true;
6316 name = else_name;
6317 }
6318
6319 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006320 BcVec *v;
6321 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006322 n = bc_vec_top(v);
6323 }
6324
6325 free(then_name);
6326 free(else_name);
6327
6328 if (!exec) goto exit;
6329 if (!BC_PROG_STR(n)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006330 s = bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006331 goto exit;
6332 }
6333
6334 sidx = n->rdx;
6335 }
6336 else {
6337
6338 if (r->t == BC_RESULT_STR)
6339 sidx = r->d.id.idx;
6340 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006341 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006342 if (s || !BC_PROG_STR(n)) goto exit;
6343 sidx = n->rdx;
6344 }
6345 else
6346 goto exit;
6347 }
6348
6349 fidx = sidx + BC_PROG_REQ_FUNCS;
6350
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006351 str = bc_vec_item(&G.prog.strs, sidx);
6352 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006353
6354 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006355 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006356 s = bc_parse_text(&prs, *str);
6357 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006358 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006359 if (s) goto err;
6360
6361 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006362 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06006363 goto err;
6364 }
6365
6366 bc_parse_free(&prs);
6367 }
6368
6369 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006370 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006371 ip.func = fidx;
6372
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006373 bc_vec_pop(&G.prog.results);
6374 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006375
6376 return BC_STATUS_SUCCESS;
6377
6378err:
6379 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006380 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006381 bc_vec_npop(&f->code, f->code.len);
6382exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006383 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006384 return s;
6385}
6386#endif // ENABLE_DC
6387
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006388static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006389{
Gavin Howard01055ba2018-11-03 11:00:21 -06006390 BcResult res;
6391 unsigned long val;
6392
6393 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6394 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006395 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006396 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006397 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006398 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006399 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006400
6401 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006402 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006403 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006404}
6405
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006406static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006407{
Gavin Howard01055ba2018-11-03 11:00:21 -06006408 BcId entry, *entry_ptr;
6409 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006410 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006411
6412 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006413 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006414
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006415 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6416 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006417
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006418 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006419 *idx = entry_ptr->idx;
6420
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006421 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006422
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006423 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006424
6425 // We need to reset these, so the function can be repopulated.
6426 func->nparams = 0;
6427 bc_vec_npop(&func->autos, func->autos.len);
6428 bc_vec_npop(&func->code, func->code.len);
6429 bc_vec_npop(&func->labels, func->labels.len);
6430 }
6431 else {
6432 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006433 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006434 }
6435}
6436
Denys Vlasenkod38af482018-12-04 19:11:02 +01006437// Called when parsing or execution detects a failure,
6438// resets execution structures.
6439static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006440{
6441 BcFunc *f;
6442 BcInstPtr *ip;
6443
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006444 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6445 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006446
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006447 f = bc_vec_item(&G.prog.fns, 0);
6448 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006449 ip->idx = f->code.len;
6450
Denys Vlasenkod38af482018-12-04 19:11:02 +01006451 // If !tty, no need to check for ^C: we don't have ^C handler,
6452 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006453}
6454
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006455static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006456{
6457 BcStatus s = BC_STATUS_SUCCESS;
6458 size_t idx;
6459 BcResult r, *ptr;
6460 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006461 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6462 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006463 char *code = func->code.v;
6464 bool cond = false;
6465
6466 while (!s && ip->idx < func->code.len) {
6467
6468 char inst = code[(ip->idx)++];
6469
6470 switch (inst) {
6471
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006472#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006473 case BC_INST_JUMP_ZERO:
6474 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006475 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006476 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006477 cond = !bc_num_cmp(num, &G.prog.zero);
6478 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006479 }
6480 // Fallthrough.
6481 case BC_INST_JUMP:
6482 {
6483 size_t *addr;
6484 idx = bc_program_index(code, &ip->idx);
6485 addr = bc_vec_item(&func->labels, idx);
6486 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6487 break;
6488 }
6489
6490 case BC_INST_CALL:
6491 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006492 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006493 break;
6494 }
6495
6496 case BC_INST_INC_PRE:
6497 case BC_INST_DEC_PRE:
6498 case BC_INST_INC_POST:
6499 case BC_INST_DEC_POST:
6500 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006501 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006502 break;
6503 }
6504
6505 case BC_INST_HALT:
6506 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006507 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006508 break;
6509 }
6510
6511 case BC_INST_RET:
6512 case BC_INST_RET0:
6513 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006514 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006515 break;
6516 }
6517
6518 case BC_INST_BOOL_OR:
6519 case BC_INST_BOOL_AND:
6520#endif // ENABLE_BC
6521 case BC_INST_REL_EQ:
6522 case BC_INST_REL_LE:
6523 case BC_INST_REL_GE:
6524 case BC_INST_REL_NE:
6525 case BC_INST_REL_LT:
6526 case BC_INST_REL_GT:
6527 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006528 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006529 break;
6530 }
6531
6532 case BC_INST_READ:
6533 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006534 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006535 break;
6536 }
6537
6538 case BC_INST_VAR:
6539 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006540 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006541 break;
6542 }
6543
6544 case BC_INST_ARRAY_ELEM:
6545 case BC_INST_ARRAY:
6546 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006547 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006548 break;
6549 }
6550
6551 case BC_INST_LAST:
6552 {
6553 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006554 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006555 break;
6556 }
6557
6558 case BC_INST_IBASE:
6559 case BC_INST_SCALE:
6560 case BC_INST_OBASE:
6561 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006562 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 break;
6564 }
6565
6566 case BC_INST_SCALE_FUNC:
6567 case BC_INST_LENGTH:
6568 case BC_INST_SQRT:
6569 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006570 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006571 break;
6572 }
6573
6574 case BC_INST_NUM:
6575 {
6576 r.t = BC_RESULT_CONSTANT;
6577 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006578 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006579 break;
6580 }
6581
6582 case BC_INST_POP:
6583 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006584 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006585 s = bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006586 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006587 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006588 break;
6589 }
6590
6591 case BC_INST_POP_EXEC:
6592 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006593 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006594 break;
6595 }
6596
6597 case BC_INST_PRINT:
6598 case BC_INST_PRINT_POP:
6599 case BC_INST_PRINT_STR:
6600 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006601 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006602 break;
6603 }
6604
6605 case BC_INST_STR:
6606 {
6607 r.t = BC_RESULT_STR;
6608 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006609 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 break;
6611 }
6612
6613 case BC_INST_POWER:
6614 case BC_INST_MULTIPLY:
6615 case BC_INST_DIVIDE:
6616 case BC_INST_MODULUS:
6617 case BC_INST_PLUS:
6618 case BC_INST_MINUS:
6619 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006620 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006621 break;
6622 }
6623
6624 case BC_INST_BOOL_NOT:
6625 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006626 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006627 if (s) return s;
6628
6629 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006630 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6631 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006632
6633 break;
6634 }
6635
6636 case BC_INST_NEG:
6637 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006638 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006639 break;
6640 }
6641
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006642#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006643 case BC_INST_ASSIGN_POWER:
6644 case BC_INST_ASSIGN_MULTIPLY:
6645 case BC_INST_ASSIGN_DIVIDE:
6646 case BC_INST_ASSIGN_MODULUS:
6647 case BC_INST_ASSIGN_PLUS:
6648 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006649#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006650 case BC_INST_ASSIGN:
6651 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006652 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006653 break;
6654 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006655#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006656 case BC_INST_MODEXP:
6657 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006658 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006659 break;
6660 }
6661
6662 case BC_INST_DIVMOD:
6663 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006664 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006665 break;
6666 }
6667
6668 case BC_INST_EXECUTE:
6669 case BC_INST_EXEC_COND:
6670 {
6671 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006672 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006673 break;
6674 }
6675
6676 case BC_INST_PRINT_STACK:
6677 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006678 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6679 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006680 break;
6681 }
6682
6683 case BC_INST_CLEAR_STACK:
6684 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006685 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006686 break;
6687 }
6688
6689 case BC_INST_STACK_LEN:
6690 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006691 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006692 break;
6693 }
6694
6695 case BC_INST_DUPLICATE:
6696 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006697 if (!BC_PROG_STACK(&G.prog.results, 1))
6698 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006699 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006700 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006701 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006702 break;
6703 }
6704
6705 case BC_INST_SWAP:
6706 {
6707 BcResult *ptr2;
6708
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006709 if (!BC_PROG_STACK(&G.prog.results, 2))
6710 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006711
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006712 ptr = bc_vec_item_rev(&G.prog.results, 0);
6713 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006714 memcpy(&r, ptr, sizeof(BcResult));
6715 memcpy(ptr, ptr2, sizeof(BcResult));
6716 memcpy(ptr2, &r, sizeof(BcResult));
6717
6718 break;
6719 }
6720
6721 case BC_INST_ASCIIFY:
6722 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006723 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006724 break;
6725 }
6726
6727 case BC_INST_PRINT_STREAM:
6728 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006729 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006730 break;
6731 }
6732
6733 case BC_INST_LOAD:
6734 case BC_INST_PUSH_VAR:
6735 {
6736 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006737 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006738 break;
6739 }
6740
6741 case BC_INST_PUSH_TO_VAR:
6742 {
6743 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006744 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006745 free(name);
6746 break;
6747 }
6748
6749 case BC_INST_QUIT:
6750 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006751 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006752 quit();
6753 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006754 break;
6755 }
6756
6757 case BC_INST_NQUIT:
6758 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006759 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006760 break;
6761 }
6762#endif // ENABLE_DC
6763 }
6764
Denys Vlasenkod38af482018-12-04 19:11:02 +01006765 if (s || G_interrupt) {
6766 bc_program_reset();
6767 break;
6768 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006769
6770 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006771 ip = bc_vec_top(&G.prog.stack);
6772 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006773 code = func->code.v;
6774 }
6775
6776 return s;
6777}
6778
Denys Vlasenko00d77792018-11-30 23:13:42 +01006779static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006780{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006781 printf("%s "BB_VER"\n"
6782 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006783 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006784 "This is free software with ABSOLUTELY NO WARRANTY\n"
6785 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006786}
6787
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006788#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006789static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006790{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006791 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6792
Gavin Howard01055ba2018-11-03 11:00:21 -06006793 BcVec v;
6794 char *env_args = getenv(bc_args_env_name), *buf;
6795
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006796 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006797
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006798 G.env_args = xstrdup(env_args);
6799 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006800
6801 bc_vec_init(&v, sizeof(char *), NULL);
6802 bc_vec_push(&v, &bc_args_env_name);
6803
6804 while (*buf != 0) {
6805 if (!isspace(*buf)) {
6806 bc_vec_push(&v, &buf);
6807 while (*buf != 0 && !isspace(*buf)) ++buf;
6808 if (*buf != 0) (*(buf++)) = '\0';
6809 }
6810 else
6811 ++buf;
6812 }
6813
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006814 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006815
6816 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006817}
6818#endif // ENABLE_BC
6819
6820static size_t bc_vm_envLen(const char *var)
6821{
6822 char *lenv = getenv(var);
6823 size_t i, len = BC_NUM_PRINT_WIDTH;
6824 int num;
6825
6826 if (!lenv) return len;
6827
6828 len = strlen(lenv);
6829
6830 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6831 if (num) {
6832 len = (size_t) atoi(lenv) - 1;
6833 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6834 }
6835 else
6836 len = BC_NUM_PRINT_WIDTH;
6837
6838 return len;
6839}
6840
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006841static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006842{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006843 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006844
Gavin Howard01055ba2018-11-03 11:00:21 -06006845 if (s) return s;
6846
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006847 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006848 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006849 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006850 }
6851
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006852 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006853 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006854 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006855 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006856 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006857 }
6858
6859 return s;
6860}
6861
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006862static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006863{
6864 BcStatus s;
6865 char *data;
6866 BcFunc *main_func;
6867 BcInstPtr *ip;
6868
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006869 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006870 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01006871 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006872
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006873 bc_lex_file(&G.prs.l, file);
6874 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006875 if (s) goto err;
6876
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006877 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6878 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006879
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006880 if (main_func->code.len < ip->idx)
6881 s = bc_error("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006882
6883err:
6884 free(data);
6885 return s;
6886}
6887
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006888static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006889{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006890 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006891 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006892 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006893 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006894
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006895 G.prog.file = bc_program_stdin_name;
6896 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006897
6898 bc_vec_init(&buffer, sizeof(char), NULL);
6899 bc_vec_init(&buf, sizeof(char), NULL);
6900 bc_vec_pushByte(&buffer, '\0');
6901
6902 // This loop is complex because the vm tries not to send any lines that end
6903 // with a backslash to the parser. The reason for that is because the parser
6904 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6905 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006906 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006907
6908 char *string = buf.v;
6909
6910 len = buf.len - 1;
6911
6912 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006913 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006914 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006915 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006916 str += 1;
6917 }
6918 else if (len > 1 || comment) {
6919
6920 for (i = 0; i < len; ++i) {
6921
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006922 bool notend = len > i + 1;
6923 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006924
6925 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006926 if (G.sbgn == G.send)
6927 str ^= c == G.sbgn;
6928 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006929 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006930 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006931 str += 1;
6932 }
6933
6934 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6935 comment = true;
6936 break;
6937 }
6938 else if (c == '*' && notend && comment && string[i + 1] == '/')
6939 comment = false;
6940 }
6941
6942 if (str || comment || string[len - 2] == '\\') {
6943 bc_vec_concat(&buffer, buf.v);
6944 continue;
6945 }
6946 }
6947
6948 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006949 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006950 if (s) {
6951 fflush_and_check();
6952 fputs("ready for more input\n", stderr);
6953 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006954
6955 bc_vec_npop(&buffer, buffer.len);
6956 }
6957
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006958 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006959 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006960 }
6961 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006962 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006963 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006964
Gavin Howard01055ba2018-11-03 11:00:21 -06006965 bc_vec_free(&buf);
6966 bc_vec_free(&buffer);
6967 return s;
6968}
6969
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006970static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006971{
6972 BcStatus s = BC_STATUS_SUCCESS;
6973 size_t i;
6974
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006975#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01006976 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006977
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006978 bc_lex_file(&G.prs.l, bc_lib_name);
6979 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06006980
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006981 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6982 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006983
6984 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006985 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06006986 if (s) return s;
6987 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006988#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006989
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006990 for (i = 0; !s && i < G.files.len; ++i)
6991 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006992 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006993 fflush_and_check();
6994 fputs("ready for more input\n", stderr);
6995 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006996
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006997 if (IS_BC || !G.files.len)
6998 s = bc_vm_stdin();
6999 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7000 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007001
Denys Vlasenko00d77792018-11-30 23:13:42 +01007002 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007003}
7004
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007005#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007006static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007007{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007008 bc_num_free(&G.prog.ib);
7009 bc_num_free(&G.prog.ob);
7010 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007011# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007012 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007013# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007014 bc_vec_free(&G.prog.fns);
7015 bc_vec_free(&G.prog.fn_map);
7016 bc_vec_free(&G.prog.vars);
7017 bc_vec_free(&G.prog.var_map);
7018 bc_vec_free(&G.prog.arrs);
7019 bc_vec_free(&G.prog.arr_map);
7020 bc_vec_free(&G.prog.strs);
7021 bc_vec_free(&G.prog.consts);
7022 bc_vec_free(&G.prog.results);
7023 bc_vec_free(&G.prog.stack);
7024 bc_num_free(&G.prog.last);
7025 bc_num_free(&G.prog.zero);
7026 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007027}
7028
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007029static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007030{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007031 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007032 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007033 bc_parse_free(&G.prs);
7034 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007035}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007036#endif
7037
7038static void bc_program_init(size_t line_len)
7039{
7040 size_t idx;
7041 BcInstPtr ip;
7042
7043 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7044 memset(&ip, 0, sizeof(BcInstPtr));
7045
7046 /* G.prog.nchars = G.prog.scale = 0; - already is */
7047 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007048
7049 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7050 bc_num_ten(&G.prog.ib);
7051 G.prog.ib_t = 10;
7052
7053 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7054 bc_num_ten(&G.prog.ob);
7055 G.prog.ob_t = 10;
7056
7057 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7058 bc_num_ten(&G.prog.hexb);
7059 G.prog.hexb.num[0] = 6;
7060
7061#if ENABLE_DC
7062 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7063 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7064#endif
7065
7066 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7067 bc_num_zero(&G.prog.last);
7068
7069 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7070 bc_num_zero(&G.prog.zero);
7071
7072 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7073 bc_num_one(&G.prog.one);
7074
7075 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7076 bc_map_init(&G.prog.fn_map);
7077
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007078 bc_program_addFunc(xstrdup("(main)"), &idx);
7079 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007080
7081 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7082 bc_map_init(&G.prog.var_map);
7083
7084 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7085 bc_map_init(&G.prog.arr_map);
7086
7087 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7088 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7089 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7090 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7091 bc_vec_push(&G.prog.stack, &ip);
7092}
Gavin Howard01055ba2018-11-03 11:00:21 -06007093
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007094static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007095{
Gavin Howard01055ba2018-11-03 11:00:21 -06007096 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007097
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007098 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007099
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007100 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007101 bc_vm_envArgs();
7102 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007103
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007104 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007105 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007106 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007107 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007108 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007109 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007110}
7111
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007112static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007113 const char *env_len)
7114{
7115 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007116
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007117 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007118 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007119
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007120 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007121
Denys Vlasenkod38af482018-12-04 19:11:02 +01007122 if (G.ttyin) {
7123#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007124 // With SA_RESTART, most system calls will restart
7125 // (IOW: they won't fail with EINTR).
7126 // In particular, this means ^C won't cause
7127 // stdout to get into "error state" if SIGINT hits
7128 // within write() syscall.
7129 // The downside is that ^C while line input is taken
7130 // will only be handled after [Enter] since read()
7131 // from stdin is not interrupted by ^C either,
7132 // it restarts, thus fgetc() does not return on ^C.
7133 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7134
7135 // Without SA_RESTART, this exhibits a bug:
7136 // "while (1) print 1" and try ^C-ing it.
7137 // Intermittently, instead of returning to input line,
7138 // you'll get "output error: Interrupted system call"
7139 // and exit.
7140 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007141#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007142 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007143 bc_vm_info();
7144 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007145 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007146
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007147#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007148 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007149#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007150 return st;
7151}
7152
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007153#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007154int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7155int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007156{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007157 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007158 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007159
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007160 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007161}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007162#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007163
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007164#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007165int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7166int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007167{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007168 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007169 G.sbgn = '[';
7170 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007171
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007172 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007173}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007174#endif