blob: e13b2283cf8901d7a0ea8a452a1e215eb5bccee8 [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
117//usage:#define bc_trivial_usage
118//usage: "EXPRESSION...\n"
119//usage: "function_definition\n"
120//usage:
121//usage:#define bc_full_usage "\n\n"
122//usage: "See www.gnu.org/software/bc/manual/bc.html\n"
123//usage:
124//usage:#define bc_example_usage
125//usage: "3 + 4.129\n"
126//usage: "1903 - 2893\n"
127//usage: "-129 * 213.28935\n"
128//usage: "12 / -1932\n"
129//usage: "12 % 12\n"
130//usage: "34 ^ 189\n"
131//usage: "scale = 13\n"
132//usage: "ibase = 2\n"
133//usage: "obase = A\n"
134//usage:
135//usage:#define dc_trivial_usage
136//usage: "EXPRESSION..."
137//usage:
138//usage:#define dc_full_usage "\n\n"
139//usage: "Tiny RPN calculator. Operations:\n"
140//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
141//usage: "modular exponentiation,\n"
142//usage: "p - print top of the stack (without popping),\n"
143//usage: "f - print entire stack,\n"
144//usage: "k - pop the value and set the precision.\n"
145//usage: "i - pop the value and set input radix.\n"
146//usage: "o - pop the value and set output radix.\n"
147//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
148//usage:
149//usage:#define dc_example_usage
150//usage: "$ dc 2 2 + p\n"
151//usage: "4\n"
152//usage: "$ dc 8 8 \\* 2 2 + / p\n"
153//usage: "16\n"
154//usage: "$ dc 0 1 and p\n"
155//usage: "0\n"
156//usage: "$ dc 0 1 or p\n"
157//usage: "1\n"
158//usage: "$ echo 72 9 div 8 mul p | dc\n"
159//usage: "64\n"
160
161#include "libbb.h"
162
163typedef enum BcStatus {
164
165 BC_STATUS_SUCCESS,
166
167 BC_STATUS_ALLOC_ERR,
Denys Vlasenko00d77792018-11-30 23:13:42 +0100168 BC_STATUS_INPUT_EOF,
Gavin Howard01055ba2018-11-03 11:00:21 -0600169 BC_STATUS_BIN_FILE,
170 BC_STATUS_PATH_IS_DIR,
171
172 BC_STATUS_LEX_BAD_CHAR,
173 BC_STATUS_LEX_NO_STRING_END,
174 BC_STATUS_LEX_NO_COMMENT_END,
175 BC_STATUS_LEX_EOF,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100176#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600177 BC_STATUS_LEX_EXTENDED_REG,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100178#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600179
180 BC_STATUS_PARSE_BAD_TOKEN,
181 BC_STATUS_PARSE_BAD_EXP,
182 BC_STATUS_PARSE_EMPTY_EXP,
183 BC_STATUS_PARSE_BAD_PRINT,
184 BC_STATUS_PARSE_BAD_FUNC,
185 BC_STATUS_PARSE_BAD_ASSIGN,
186 BC_STATUS_PARSE_NO_AUTO,
187 BC_STATUS_PARSE_DUPLICATE_LOCAL,
188 BC_STATUS_PARSE_NO_BLOCK_END,
189
190 BC_STATUS_MATH_NEGATIVE,
191 BC_STATUS_MATH_NON_INTEGER,
192 BC_STATUS_MATH_OVERFLOW,
193 BC_STATUS_MATH_DIVIDE_BY_ZERO,
194 BC_STATUS_MATH_BAD_STRING,
195
196 BC_STATUS_EXEC_FILE_ERR,
197 BC_STATUS_EXEC_MISMATCHED_PARAMS,
198 BC_STATUS_EXEC_UNDEFINED_FUNC,
199 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
200 BC_STATUS_EXEC_NUM_LEN,
201 BC_STATUS_EXEC_NAME_LEN,
202 BC_STATUS_EXEC_STRING_LEN,
203 BC_STATUS_EXEC_ARRAY_LEN,
204 BC_STATUS_EXEC_BAD_IBASE,
205 BC_STATUS_EXEC_BAD_SCALE,
206 BC_STATUS_EXEC_BAD_READ_EXPR,
207 BC_STATUS_EXEC_REC_READ,
208 BC_STATUS_EXEC_BAD_TYPE,
209 BC_STATUS_EXEC_BAD_OBASE,
210 BC_STATUS_EXEC_SIGNAL,
211 BC_STATUS_EXEC_STACK,
212
213 BC_STATUS_VEC_OUT_OF_BOUNDS,
214 BC_STATUS_VEC_ITEM_EXISTS,
215
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100216#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600217 BC_STATUS_POSIX_NAME_LEN,
218 BC_STATUS_POSIX_COMMENT,
219 BC_STATUS_POSIX_BAD_KW,
220 BC_STATUS_POSIX_DOT,
221 BC_STATUS_POSIX_RET,
222 BC_STATUS_POSIX_BOOL,
223 BC_STATUS_POSIX_REL_POS,
224 BC_STATUS_POSIX_MULTIREL,
225 BC_STATUS_POSIX_FOR1,
226 BC_STATUS_POSIX_FOR2,
227 BC_STATUS_POSIX_FOR3,
228 BC_STATUS_POSIX_BRACE,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100229#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600230
231 BC_STATUS_QUIT,
232 BC_STATUS_LIMITS,
233
234 BC_STATUS_INVALID_OPTION,
235
236} BcStatus;
237
238#define BC_ERR_IDX_VM (0)
239#define BC_ERR_IDX_LEX (1)
240#define BC_ERR_IDX_PARSE (2)
241#define BC_ERR_IDX_MATH (3)
242#define BC_ERR_IDX_EXEC (4)
243#define BC_ERR_IDX_VEC (5)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100244#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600245#define BC_ERR_IDX_POSIX (6)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100246#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600247
248#define BC_VEC_INVALID_IDX ((size_t) -1)
249#define BC_VEC_START_CAP (1 << 5)
250
251typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600252
253typedef struct BcVec {
254 char *v;
255 size_t len;
256 size_t cap;
257 size_t size;
258 BcVecFree dtor;
259} BcVec;
260
261#define bc_vec_pop(v) (bc_vec_npop((v), 1))
262#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
263
264#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
265
266#define BC_READ_BIN_CHAR(c) ((((c) < ' ' && !isspace((c))) || (c) > '~'))
267
268typedef signed char BcDig;
269
270typedef struct BcNum {
271 BcDig *restrict num;
272 size_t rdx;
273 size_t len;
274 size_t cap;
275 bool neg;
276} BcNum;
277
278#define BC_NUM_MIN_BASE ((unsigned long) 2)
279#define BC_NUM_MAX_IBASE ((unsigned long) 16)
280#define BC_NUM_DEF_SIZE (16)
281#define BC_NUM_PRINT_WIDTH (69)
282
283#define BC_NUM_KARATSUBA_LEN (32)
284
285#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
286#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
287#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
288#define BC_NUM_AREQ(a, b) \
289 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
290#define BC_NUM_MREQ(a, b, scale) \
291 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
292
293typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
294typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
295
296static void bc_num_init(BcNum *n, size_t req);
297static void bc_num_expand(BcNum *n, size_t req);
298static void bc_num_copy(BcNum *d, BcNum *s);
299static void bc_num_free(void *num);
300
301static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
302static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val);
303
304static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
305static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
306static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
307static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
308static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
309static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
310static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
311static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
312 size_t scale);
313
314typedef enum BcInst {
315
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100316#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600317 BC_INST_INC_PRE,
318 BC_INST_DEC_PRE,
319 BC_INST_INC_POST,
320 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100321#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600322
323 BC_INST_NEG,
324
325 BC_INST_POWER,
326 BC_INST_MULTIPLY,
327 BC_INST_DIVIDE,
328 BC_INST_MODULUS,
329 BC_INST_PLUS,
330 BC_INST_MINUS,
331
332 BC_INST_REL_EQ,
333 BC_INST_REL_LE,
334 BC_INST_REL_GE,
335 BC_INST_REL_NE,
336 BC_INST_REL_LT,
337 BC_INST_REL_GT,
338
339 BC_INST_BOOL_NOT,
340 BC_INST_BOOL_OR,
341 BC_INST_BOOL_AND,
342
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100343#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600344 BC_INST_ASSIGN_POWER,
345 BC_INST_ASSIGN_MULTIPLY,
346 BC_INST_ASSIGN_DIVIDE,
347 BC_INST_ASSIGN_MODULUS,
348 BC_INST_ASSIGN_PLUS,
349 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100350#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600351 BC_INST_ASSIGN,
352
353 BC_INST_NUM,
354 BC_INST_VAR,
355 BC_INST_ARRAY_ELEM,
356 BC_INST_ARRAY,
357
358 BC_INST_SCALE_FUNC,
359 BC_INST_IBASE,
360 BC_INST_SCALE,
361 BC_INST_LAST,
362 BC_INST_LENGTH,
363 BC_INST_READ,
364 BC_INST_OBASE,
365 BC_INST_SQRT,
366
367 BC_INST_PRINT,
368 BC_INST_PRINT_POP,
369 BC_INST_STR,
370 BC_INST_PRINT_STR,
371
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100372#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600373 BC_INST_JUMP,
374 BC_INST_JUMP_ZERO,
375
376 BC_INST_CALL,
377
378 BC_INST_RET,
379 BC_INST_RET0,
380
381 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100382#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600383
384 BC_INST_POP,
385 BC_INST_POP_EXEC,
386
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100387#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600388 BC_INST_MODEXP,
389 BC_INST_DIVMOD,
390
391 BC_INST_EXECUTE,
392 BC_INST_EXEC_COND,
393
394 BC_INST_ASCIIFY,
395 BC_INST_PRINT_STREAM,
396
397 BC_INST_PRINT_STACK,
398 BC_INST_CLEAR_STACK,
399 BC_INST_STACK_LEN,
400 BC_INST_DUPLICATE,
401 BC_INST_SWAP,
402
403 BC_INST_LOAD,
404 BC_INST_PUSH_VAR,
405 BC_INST_PUSH_TO_VAR,
406
407 BC_INST_QUIT,
408 BC_INST_NQUIT,
409
410 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100411#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600412
413} BcInst;
414
415typedef struct BcId {
416 char *name;
417 size_t idx;
418} BcId;
419
420typedef struct BcFunc {
421 BcVec code;
422 BcVec labels;
423 size_t nparams;
424 BcVec autos;
425} BcFunc;
426
427typedef enum BcResultType {
428
429 BC_RESULT_TEMP,
430
431 BC_RESULT_VAR,
432 BC_RESULT_ARRAY_ELEM,
433 BC_RESULT_ARRAY,
434
435 BC_RESULT_STR,
436
437 BC_RESULT_IBASE,
438 BC_RESULT_SCALE,
439 BC_RESULT_LAST,
440
441 // These are between to calculate ibase, obase, and last from instructions.
442 BC_RESULT_CONSTANT,
443 BC_RESULT_ONE,
444
445 BC_RESULT_OBASE,
446
447} BcResultType;
448
449typedef union BcResultData {
450 BcNum n;
451 BcVec v;
452 BcId id;
453} BcResultData;
454
455typedef struct BcResult {
456 BcResultType t;
457 BcResultData d;
458} BcResult;
459
460typedef struct BcInstPtr {
461 size_t func;
462 size_t idx;
463 size_t len;
464} BcInstPtr;
465
466static void bc_array_expand(BcVec *a, size_t len);
467static int bc_id_cmp(const void *e1, const void *e2);
468
469// BC_LEX_NEG is not used in lexing; it is only for parsing.
470typedef enum BcLexType {
471
472 BC_LEX_EOF,
473 BC_LEX_INVALID,
474
475 BC_LEX_OP_INC,
476 BC_LEX_OP_DEC,
477
478 BC_LEX_NEG,
479
480 BC_LEX_OP_POWER,
481 BC_LEX_OP_MULTIPLY,
482 BC_LEX_OP_DIVIDE,
483 BC_LEX_OP_MODULUS,
484 BC_LEX_OP_PLUS,
485 BC_LEX_OP_MINUS,
486
487 BC_LEX_OP_REL_EQ,
488 BC_LEX_OP_REL_LE,
489 BC_LEX_OP_REL_GE,
490 BC_LEX_OP_REL_NE,
491 BC_LEX_OP_REL_LT,
492 BC_LEX_OP_REL_GT,
493
494 BC_LEX_OP_BOOL_NOT,
495 BC_LEX_OP_BOOL_OR,
496 BC_LEX_OP_BOOL_AND,
497
498 BC_LEX_OP_ASSIGN_POWER,
499 BC_LEX_OP_ASSIGN_MULTIPLY,
500 BC_LEX_OP_ASSIGN_DIVIDE,
501 BC_LEX_OP_ASSIGN_MODULUS,
502 BC_LEX_OP_ASSIGN_PLUS,
503 BC_LEX_OP_ASSIGN_MINUS,
504 BC_LEX_OP_ASSIGN,
505
506 BC_LEX_NLINE,
507 BC_LEX_WHITESPACE,
508
509 BC_LEX_LPAREN,
510 BC_LEX_RPAREN,
511
512 BC_LEX_LBRACKET,
513 BC_LEX_COMMA,
514 BC_LEX_RBRACKET,
515
516 BC_LEX_LBRACE,
517 BC_LEX_SCOLON,
518 BC_LEX_RBRACE,
519
520 BC_LEX_STR,
521 BC_LEX_NAME,
522 BC_LEX_NUMBER,
523
524 BC_LEX_KEY_AUTO,
525 BC_LEX_KEY_BREAK,
526 BC_LEX_KEY_CONTINUE,
527 BC_LEX_KEY_DEFINE,
528 BC_LEX_KEY_ELSE,
529 BC_LEX_KEY_FOR,
530 BC_LEX_KEY_HALT,
531 BC_LEX_KEY_IBASE,
532 BC_LEX_KEY_IF,
533 BC_LEX_KEY_LAST,
534 BC_LEX_KEY_LENGTH,
535 BC_LEX_KEY_LIMITS,
536 BC_LEX_KEY_OBASE,
537 BC_LEX_KEY_PRINT,
538 BC_LEX_KEY_QUIT,
539 BC_LEX_KEY_READ,
540 BC_LEX_KEY_RETURN,
541 BC_LEX_KEY_SCALE,
542 BC_LEX_KEY_SQRT,
543 BC_LEX_KEY_WHILE,
544
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100545#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600546 BC_LEX_EQ_NO_REG,
547 BC_LEX_OP_MODEXP,
548 BC_LEX_OP_DIVMOD,
549
550 BC_LEX_COLON,
551 BC_LEX_ELSE,
552 BC_LEX_EXECUTE,
553 BC_LEX_PRINT_STACK,
554 BC_LEX_CLEAR_STACK,
555 BC_LEX_STACK_LEVEL,
556 BC_LEX_DUPLICATE,
557 BC_LEX_SWAP,
558 BC_LEX_POP,
559
560 BC_LEX_ASCIIFY,
561 BC_LEX_PRINT_STREAM,
562
563 BC_LEX_STORE_IBASE,
564 BC_LEX_STORE_SCALE,
565 BC_LEX_LOAD,
566 BC_LEX_LOAD_POP,
567 BC_LEX_STORE_PUSH,
568 BC_LEX_STORE_OBASE,
569 BC_LEX_PRINT_POP,
570 BC_LEX_NQUIT,
571 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100572#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600573
574} BcLexType;
575
576struct BcLex;
577typedef BcStatus (*BcLexNext)(struct BcLex *);
578
579typedef struct BcLex {
580
581 const char *buf;
582 size_t i;
583 size_t line;
584 const char *f;
585 size_t len;
586 bool newline;
587
588 struct {
589 BcLexType t;
590 BcLexType last;
591 BcVec v;
592 } t;
593
594 BcLexNext next;
595
596} BcLex;
597
598#define BC_PARSE_STREND ((char) UCHAR_MAX)
599
600#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
601#define bc_parse_updateFunc(p, f) \
602 ((p)->func = bc_vec_item(&(p)->prog->fns, ((p)->fidx = (f))))
603
604#define BC_PARSE_REL (1 << 0)
605#define BC_PARSE_PRINT (1 << 1)
606#define BC_PARSE_NOCALL (1 << 2)
607#define BC_PARSE_NOREAD (1 << 3)
608#define BC_PARSE_ARRAY (1 << 4)
609
610#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
611#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
612
613#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
614#define BC_PARSE_FUNC_INNER(parse) \
615 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
616
617#define BC_PARSE_FLAG_FUNC (1 << 1)
618#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
619
620#define BC_PARSE_FLAG_BODY (1 << 2)
621#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
622
623#define BC_PARSE_FLAG_LOOP (1 << 3)
624#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
625
626#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
627#define BC_PARSE_LOOP_INNER(parse) \
628 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
629
630#define BC_PARSE_FLAG_IF (1 << 5)
631#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
632
633#define BC_PARSE_FLAG_ELSE (1 << 6)
634#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
635
636#define BC_PARSE_FLAG_IF_END (1 << 7)
637#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
638
639#define BC_PARSE_CAN_EXEC(parse) \
640 (!(BC_PARSE_TOP_FLAG(parse) & \
641 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
642 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
643 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
644
645typedef struct BcOp {
646 char prec;
647 bool left;
648} BcOp;
649
650typedef struct BcParseNext {
651 uint32_t len;
652 BcLexType tokens[4];
653} BcParseNext;
654
655#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
656#define BC_PARSE_NEXT(a, ...) \
657 { \
658 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
659 }
660
661struct BcParse;
662
663struct BcProgram;
664
665typedef void (*BcParseInit)(struct BcParse *, struct BcProgram *, size_t);
666typedef BcStatus (*BcParseParse)(struct BcParse *);
667typedef BcStatus (*BcParseExpr)(struct BcParse *, uint8_t);
668
669typedef struct BcParse {
670
671 BcParseParse parse;
672
673 BcLex l;
674
675 BcVec flags;
676
677 BcVec exits;
678 BcVec conds;
679
680 BcVec ops;
681
682 struct BcProgram *prog;
683 BcFunc *func;
684 size_t fidx;
685
686 size_t nbraces;
687 bool auto_part;
688
689} BcParse;
690
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100691#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600692
Gavin Howard01055ba2018-11-03 11:00:21 -0600693typedef struct BcLexKeyword {
694 const char name[9];
695 const char len;
696 const bool posix;
697} BcLexKeyword;
698
699#define BC_LEX_KW_ENTRY(a, b, c) \
700 { \
701 .name = a, .len = (b), .posix = (c) \
702 }
703
704static BcStatus bc_lex_token(BcLex *l);
705
706#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
707#define BC_PARSE_LEAF(p, rparen) \
708 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
709 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
710
711// We can calculate the conversion between tokens and exprs by subtracting the
712// position of the first operator in the lex enum and adding the position of the
713// first in the expr enum. Note: This only works for binary operators.
714#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
715
716static BcStatus bc_parse_parse(BcParse *p);
717static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
718
Denys Vlasenko00d77792018-11-30 23:13:42 +0100719#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600720
Denys Vlasenko00d77792018-11-30 23:13:42 +0100721#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600722
723#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
724
Gavin Howard01055ba2018-11-03 11:00:21 -0600725static BcStatus dc_lex_token(BcLex *l);
726
727static void dc_parse_init(BcParse *p, struct BcProgram *prog, size_t func);
728static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
729
730#endif // ENABLE_DC
731
732typedef struct BcProgram {
733
734 size_t len;
735 size_t scale;
736
737 BcNum ib;
738 size_t ib_t;
739 BcNum ob;
740 size_t ob_t;
741
742 BcNum hexb;
743
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100744#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600745 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100746#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600747
748 BcVec results;
749 BcVec stack;
750
751 BcVec fns;
752 BcVec fn_map;
753
754 BcVec vars;
755 BcVec var_map;
756
757 BcVec arrs;
758 BcVec arr_map;
759
760 BcVec strs;
761 BcVec consts;
762
763 const char *file;
764
765 BcNum last;
766 BcNum zero;
767 BcNum one;
768
769 size_t nchars;
770
771 BcParseInit parse_init;
772 BcParseExpr parse_expr;
773
774} BcProgram;
775
776#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
777
778#define BC_PROG_MAIN (0)
779#define BC_PROG_READ (1)
780
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100781#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600782#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100783#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600784
785#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
786#define BC_PROG_NUM(r, n) \
787 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
788
789typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
790
791static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx);
792static BcStatus bc_program_reset(BcProgram *p, BcStatus s);
793static BcStatus bc_program_exec(BcProgram *p);
794
795#define BC_FLAG_X (1 << 0)
796#define BC_FLAG_W (1 << 1)
797#define BC_FLAG_V (1 << 2)
798#define BC_FLAG_S (1 << 3)
799#define BC_FLAG_Q (1 << 4)
800#define BC_FLAG_L (1 << 5)
801#define BC_FLAG_I (1 << 6)
802
803#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
804#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
805
806#define BC_MAX_OBASE ((unsigned long) 999)
807#define BC_MAX_DIM ((unsigned long) INT_MAX)
808#define BC_MAX_SCALE ((unsigned long) UINT_MAX)
809#define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
810#define BC_MAX_NAME BC_MAX_STRING
811#define BC_MAX_NUM BC_MAX_STRING
812#define BC_MAX_EXP ((unsigned long) LONG_MAX)
813#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
814
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100815struct globals {
Gavin Howard01055ba2018-11-03 11:00:21 -0600816 BcParseInit init;
817 BcParseExpr exp;
818 char sbgn;
819 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600820
821 BcParse prs;
822 BcProgram prog;
823
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100824 unsigned flags;
Gavin Howard01055ba2018-11-03 11:00:21 -0600825 BcVec files;
826
827 char *env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -0600828
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100829 unsigned sig; //counter?
830 unsigned sigc; //counter?
831 smallint signe; //flag
Gavin Howard01055ba2018-11-03 11:00:21 -0600832
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100833 smallint tty;
834 smallint ttyin;
Gavin Howard01055ba2018-11-03 11:00:21 -0600835
Gavin Howard01055ba2018-11-03 11:00:21 -0600836#if ENABLE_FEATURE_BC_SIGNALS
837 const char *sig_msg;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100838#endif
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100839} FIX_ALIASING;
840#define G (*ptr_to_globals)
841#define INIT_G() do { \
842 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
843} while (0)
844#define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
845#define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
846#define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
Gavin Howard01055ba2018-11-03 11:00:21 -0600847
Gavin Howard01055ba2018-11-03 11:00:21 -0600848
Denys Vlasenko00d77792018-11-30 23:13:42 +0100849#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
850
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100851#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600852static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
853 const char *msg);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100854#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600855
Denys Vlasenko00d77792018-11-30 23:13:42 +0100856static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600857
Gavin Howard01055ba2018-11-03 11:00:21 -0600858static const char* const bc_args_env_name = "BC_ENV_ARGS";
859
860static const char bc_err_fmt[] = "\n%s error: %s\n";
861static const char bc_warn_fmt[] = "\n%s warning: %s\n";
862static const char bc_err_line[] = ":%zu\n\n";
863
864static const char *bc_errs[] = {
865 "VM",
866 "Lex",
867 "Parse",
868 "Math",
869 "Runtime",
870 "Vector",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100871#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600872 "POSIX",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100873#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600874};
875
876static const uint8_t bc_err_ids[] = {
877 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
878 BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX, BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100879#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600880 BC_ERR_IDX_LEX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100881#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600882 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
883 BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
884 BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
885 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100886#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600887 BC_ERR_IDX_MATH,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100888#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600889 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
890 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
891 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
892 BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
893 BC_ERR_IDX_EXEC,
894 BC_ERR_IDX_VEC, BC_ERR_IDX_VEC,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100895#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600896 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
897 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
898 BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100899#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600900 BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
901};
902
903static const char *bc_err_msgs[] = {
904
905 NULL,
906 "memory allocation error",
907 "I/O error",
908 "file is not text:",
909 "path is a directory:",
910
911 "bad character",
912 "string end could not be found",
913 "comment end could not be found",
914 "end of file",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100915#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600916 "extended register",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100917#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600918
919 "bad token",
920 "bad expression",
921 "empty expression",
922 "bad print statement",
923 "bad function definition",
924 "bad assignment: left side must be scale, ibase, "
925 "obase, last, var, or array element",
926 "no auto variable found",
927 "function parameter or auto var has the same name as another",
928 "block end could not be found",
929
930 "negative number",
931 "non integer number",
932 "overflow",
933 "divide by zero",
934 "bad number string",
935
936 "could not open file:",
937 "mismatched parameters",
938 "undefined function",
939 "file is not executable:",
940 "number too long: must be [1, BC_NUM_MAX]",
941 "name too long: must be [1, BC_NAME_MAX]",
942 "string too long: must be [1, BC_STRING_MAX]",
943 "array too long; must be [1, BC_DIM_MAX]",
944 "bad ibase; must be [2, 16]",
945 "bad scale; must be [0, BC_SCALE_MAX]",
946 "bad read() expression",
947 "read() call inside of a read() call",
948 "variable is wrong type",
949 "bad obase; must be [2, BC_BASE_MAX]",
950 "signal caught and not handled",
951 "stack has too few elements",
952
953 "index is out of bounds",
954 "item already exists",
955
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100956#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600957 "POSIX only allows one character names; the following is bad:",
958 "POSIX does not allow '#' script comments",
959 "POSIX does not allow the following keyword:",
960 "POSIX does not allow a period ('.') as a shortcut for the last result",
961 "POSIX requires parentheses around return expressions",
962 "POSIX does not allow boolean operators; the following is bad:",
963 "POSIX does not allow comparison operators outside if or loops",
964 "POSIX requires exactly one comparison operator per condition",
965 "POSIX does not allow an empty init expression in a for loop",
966 "POSIX does not allow an empty condition expression in a for loop",
967 "POSIX does not allow an empty update expression in a for loop",
968 "POSIX requires the left brace be on the same line as the function header",
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100969#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600970
971};
972
973static const char bc_func_main[] = "(main)";
974static const char bc_func_read[] = "(read)";
975
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100976#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600977static const BcLexKeyword bc_lex_kws[20] = {
978 BC_LEX_KW_ENTRY("auto", 4, true),
979 BC_LEX_KW_ENTRY("break", 5, true),
980 BC_LEX_KW_ENTRY("continue", 8, false),
981 BC_LEX_KW_ENTRY("define", 6, true),
982 BC_LEX_KW_ENTRY("else", 4, false),
983 BC_LEX_KW_ENTRY("for", 3, true),
984 BC_LEX_KW_ENTRY("halt", 4, false),
985 BC_LEX_KW_ENTRY("ibase", 5, true),
986 BC_LEX_KW_ENTRY("if", 2, true),
987 BC_LEX_KW_ENTRY("last", 4, false),
988 BC_LEX_KW_ENTRY("length", 6, true),
989 BC_LEX_KW_ENTRY("limits", 6, false),
990 BC_LEX_KW_ENTRY("obase", 5, true),
991 BC_LEX_KW_ENTRY("print", 5, false),
992 BC_LEX_KW_ENTRY("quit", 4, true),
993 BC_LEX_KW_ENTRY("read", 4, false),
994 BC_LEX_KW_ENTRY("return", 6, true),
995 BC_LEX_KW_ENTRY("scale", 5, true),
996 BC_LEX_KW_ENTRY("sqrt", 4, true),
997 BC_LEX_KW_ENTRY("while", 5, true),
998};
999
1000// This is an array that corresponds to token types. An entry is
1001// true if the token is valid in an expression, false otherwise.
1002static const bool bc_parse_exprs[] = {
1003 false, false, true, true, true, true, true, true, true, true, true, true,
1004 true, true, true, true, true, true, true, true, true, true, true, true,
1005 true, true, true, false, false, true, true, false, false, false, false,
1006 false, false, false, true, true, false, false, false, false, false, false,
1007 false, true, false, true, true, true, true, false, false, true, false, true,
1008 true, false,
1009};
1010
1011// This is an array of data for operators that correspond to token types.
1012static const BcOp bc_parse_ops[] = {
1013 { 0, false }, { 0, false },
1014 { 1, false },
1015 { 2, false },
1016 { 3, true }, { 3, true }, { 3, true },
1017 { 4, true }, { 4, true },
1018 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
1019 { 1, false },
1020 { 7, true }, { 7, true },
1021 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
1022 { 5, false }, { 5, false },
1023};
1024
1025// These identify what tokens can come after expressions in certain cases.
1026static const BcParseNext bc_parse_next_expr =
1027 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
1028static const BcParseNext bc_parse_next_param =
1029 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
1030static const BcParseNext bc_parse_next_print =
1031 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
1032static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
1033static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
1034static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
1035static const BcParseNext bc_parse_next_read =
1036 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
1037#endif // ENABLE_BC
1038
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001039#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06001040static const BcLexType dc_lex_regs[] = {
1041 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
1042 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
1043 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
1044 BC_LEX_STORE_PUSH,
1045};
1046
1047static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
1048
1049static const BcLexType dc_lex_tokens[] = {
1050 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
1051 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
1052 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
1053 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1054 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1055 BC_LEX_INVALID, BC_LEX_INVALID,
1056 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
1057 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
1058 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1059 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
1060 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
1061 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
1062 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
1063 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
1064 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
1065 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
1066 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
1067 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
1068 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
1069 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
1070 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
1071 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1072 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1073 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1074 BC_LEX_INVALID
1075};
1076
1077static const BcInst dc_parse_insts[] = {
1078 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1079 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1080 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1081 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1082 BC_INST_INVALID, BC_INST_INVALID,
1083 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1084 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1085 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1086 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1087 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1088 BC_INST_INVALID, BC_INST_INVALID,
1089 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1090 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1091 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1092 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1093 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1094 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1095 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1096 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1097 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1098 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1099 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1100 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1101};
1102#endif // ENABLE_DC
1103
Gavin Howard01055ba2018-11-03 11:00:21 -06001104static const BcNumBinaryOp bc_program_ops[] = {
1105 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1106};
1107
1108static const char bc_program_stdin_name[] = "<stdin>";
1109static const char bc_program_ready_msg[] = "ready for more input\n";
1110
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001111#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001112static const char *bc_lib_name = "gen/lib.bc";
1113
1114static const char bc_lib[] = {
1115 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1116 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1117 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1118 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,
1119 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1120 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1121 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,
1122 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1123 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1124 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,
1125 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1126 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1127 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1128 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1129 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1130 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1131 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1132 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1133 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1134 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1135 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1136 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1137 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1138 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,
1139 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1140 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,
1141 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1142 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1143 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1144 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1145 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1146 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,
1147 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1148 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1149 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1150 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1151 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,
1152 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1153 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1154 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1155 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1156 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1157 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1158 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1159 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1160 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1161 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1162 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,
1163 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,
1164 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1165 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,
1166 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,
1167 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,
1168 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1169 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1170 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,
1171 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,
1172 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,
1173 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1174 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,
1175 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1176 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1177 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1178 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,
1179 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1180 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1181 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1182 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1183 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1184 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1185 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1186 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1187 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1188 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1189 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1190 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1191 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1192 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1193 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1194 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1195};
1196#endif // ENABLE_BC
1197
1198static void bc_vec_grow(BcVec *v, size_t n)
1199{
1200 size_t cap = v->cap * 2;
1201 while (cap < v->len + n) cap *= 2;
1202 v->v = xrealloc(v->v, v->size * cap);
1203 v->cap = cap;
1204}
1205
1206static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1207{
1208 v->size = esize;
1209 v->cap = BC_VEC_START_CAP;
1210 v->len = 0;
1211 v->dtor = dtor;
1212 v->v = xmalloc(esize * BC_VEC_START_CAP);
1213}
1214
1215static void bc_vec_expand(BcVec *v, size_t req)
1216{
1217 if (v->cap < req) {
1218 v->v = xrealloc(v->v, v->size * req);
1219 v->cap = req;
1220 }
1221}
1222
1223static void bc_vec_npop(BcVec *v, size_t n)
1224{
1225 if (!v->dtor)
1226 v->len -= n;
1227 else {
1228 size_t len = v->len - n;
1229 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1230 }
1231}
1232
1233static void bc_vec_push(BcVec *v, const void *data)
1234{
1235 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1236 memmove(v->v + (v->size * v->len), data, v->size);
1237 v->len += 1;
1238}
1239
1240static void bc_vec_pushByte(BcVec *v, char data)
1241{
1242 bc_vec_push(v, &data);
1243}
1244
1245static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1246{
1247 if (idx == v->len)
1248 bc_vec_push(v, data);
1249 else {
1250
1251 char *ptr;
1252
1253 if (v->len == v->cap) bc_vec_grow(v, 1);
1254
1255 ptr = v->v + v->size * idx;
1256
1257 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1258 memmove(ptr, data, v->size);
1259 }
1260}
1261
1262static void bc_vec_string(BcVec *v, size_t len, const char *str)
1263{
1264 bc_vec_npop(v, v->len);
1265 bc_vec_expand(v, len + 1);
1266 memcpy(v->v, str, len);
1267 v->len = len;
1268
1269 bc_vec_pushByte(v, '\0');
1270}
1271
1272static void bc_vec_concat(BcVec *v, const char *str)
1273{
1274 size_t len;
1275
1276 if (v->len == 0) bc_vec_pushByte(v, '\0');
1277
1278 len = v->len + strlen(str);
1279
1280 if (v->cap < len) bc_vec_grow(v, len - v->len);
1281 strcat(v->v, str);
1282
1283 v->len = len;
1284}
1285
1286static void *bc_vec_item(const BcVec *v, size_t idx)
1287{
1288 return v->v + v->size * idx;
1289}
1290
1291static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1292{
1293 return v->v + v->size * (v->len - idx - 1);
1294}
1295
1296static void bc_vec_free(void *vec)
1297{
1298 BcVec *v = (BcVec *) vec;
1299 bc_vec_npop(v, v->len);
1300 free(v->v);
1301}
1302
1303static size_t bc_map_find(const BcVec *v, const void *ptr)
1304{
1305 size_t low = 0, high = v->len;
1306
1307 while (low < high) {
1308
1309 size_t mid = (low + high) / 2;
1310 BcId *id = bc_vec_item(v, mid);
1311 int result = bc_id_cmp(ptr, id);
1312
1313 if (result == 0)
1314 return mid;
1315 else if (result < 0)
1316 high = mid;
1317 else
1318 low = mid + 1;
1319 }
1320
1321 return low;
1322}
1323
1324static BcStatus bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1325{
1326 BcStatus s = BC_STATUS_SUCCESS;
1327
1328 *i = bc_map_find(v, ptr);
1329
1330 if (*i == v->len)
1331 bc_vec_push(v, ptr);
1332 else if (!bc_id_cmp(ptr, bc_vec_item(v, *i)))
1333 s = BC_STATUS_VEC_ITEM_EXISTS;
1334 else
1335 bc_vec_pushAt(v, ptr, *i);
1336
1337 return s;
1338}
1339
1340static size_t bc_map_index(const BcVec *v, const void *ptr)
1341{
1342 size_t i = bc_map_find(v, ptr);
1343 if (i >= v->len) return BC_VEC_INVALID_IDX;
1344 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1345}
1346
1347static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1348{
1349 int i;
Denys Vlasenko00d77792018-11-30 23:13:42 +01001350 signed char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001351
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001352 if (G.ttyin && !G_posix) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01001353 fputs(prompt, stderr);
1354 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001355 }
1356
1357 bc_vec_npop(vec, vec->len);
1358
Denys Vlasenko00d77792018-11-30 23:13:42 +01001359 do {
1360 if (ferror(stdout) || ferror(stderr))
1361 bb_perror_msg_and_die("output error");
Gavin Howard01055ba2018-11-03 11:00:21 -06001362
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001363 errno = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06001364 i = fgetc(stdin);
1365
1366 if (i == EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001367#if ENABLE_FEATURE_BC_SIGNALS
1368 if (errno == EINTR) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001369 G.sigc = G.sig;
1370 G.signe = 0;
1371 if (G.ttyin) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01001372 fputs(bc_program_ready_msg, stderr);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001373 if (!G_posix) fputs(prompt, stderr);
Denys Vlasenko00d77792018-11-30 23:13:42 +01001374 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001375 }
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001376 clearerr(stdin);
Gavin Howard01055ba2018-11-03 11:00:21 -06001377 continue;
1378 }
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001379 if (ferror(stdin))
1380 bb_perror_msg_and_die("input error");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001381#endif
Denys Vlasenko00d77792018-11-30 23:13:42 +01001382 return BC_STATUS_INPUT_EOF;
Gavin Howard01055ba2018-11-03 11:00:21 -06001383 }
1384
1385 c = (signed char) i;
1386 if (i > UCHAR_MAX || BC_READ_BIN_CHAR(c)) return BC_STATUS_BIN_FILE;
1387 bc_vec_push(vec, &c);
Denys Vlasenko00d77792018-11-30 23:13:42 +01001388 } while (c != '\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06001389
1390 bc_vec_pushByte(vec, '\0');
1391
1392 return BC_STATUS_SUCCESS;
1393}
1394
1395static BcStatus bc_read_file(const char *path, char **buf)
1396{
1397 BcStatus s = BC_STATUS_BIN_FILE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001398 size_t size = ((size_t) -1);
1399 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001400
1401 *buf = xmalloc_open_read_close(path, &size);
1402
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001403 for (i = 0; i < size; ++i) {
1404 if (BC_READ_BIN_CHAR((*buf)[i]))
1405 goto read_err;
Gavin Howard01055ba2018-11-03 11:00:21 -06001406 }
1407
1408 return BC_STATUS_SUCCESS;
1409
1410read_err:
1411 free(*buf);
1412 return s;
1413}
1414
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001415static void bc_args(int argc, char *argv[], uint32_t *flags, BcVec *files)
Gavin Howard01055ba2018-11-03 11:00:21 -06001416{
Gavin Howard01055ba2018-11-03 11:00:21 -06001417 int i;
1418 bool do_exit = false;
1419
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001420 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001421#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001422 *flags = getopt32long(argv, "xwvsqli",
1423 "extended-register\0" No_argument "x"
1424 "warn\0" No_argument "w"
1425 "version\0" No_argument "v"
1426 "standard\0" No_argument "s"
1427 "quiet\0" No_argument "q"
1428 "mathlib\0" No_argument "l"
1429 "interactive\0" No_argument "i"
1430 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001431#else
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001432 *flags = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001433#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001434
Denys Vlasenko00d77792018-11-30 23:13:42 +01001435 if ((*flags) & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001436 if (do_exit) exit(0);
1437 // should not be necessary, getopt32() handles this??
1438 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001439
1440 for (i = optind; i < argc; ++i) bc_vec_push(files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001441}
1442
1443static void bc_num_setToZero(BcNum *n, size_t scale)
1444{
1445 n->len = 0;
1446 n->neg = false;
1447 n->rdx = scale;
1448}
1449
1450static void bc_num_zero(BcNum *n)
1451{
1452 bc_num_setToZero(n, 0);
1453}
1454
1455static void bc_num_one(BcNum *n)
1456{
1457 bc_num_setToZero(n, 0);
1458 n->len = 1;
1459 n->num[0] = 1;
1460}
1461
1462static void bc_num_ten(BcNum *n)
1463{
1464 bc_num_setToZero(n, 0);
1465 n->len = 2;
1466 n->num[0] = 0;
1467 n->num[1] = 1;
1468}
1469
1470static BcStatus bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1471 size_t len)
1472{
1473 size_t i, j;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001474 for (i = 0; !G.signe && i < len; ++i) {
1475 for (a[i] -= b[i], j = 0; !G.signe && a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001476 a[i + j++] += 10;
1477 a[i + j] -= 1;
1478 }
1479 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001480 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001481}
1482
1483static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1484{
1485 size_t i;
1486 int c = 0;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001487 for (i = len - 1; !G.signe && i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001488 return BC_NUM_NEG(i + 1, c < 0);
1489}
1490
1491static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1492{
1493 size_t i, min, a_int, b_int, diff;
1494 BcDig *max_num, *min_num;
1495 bool a_max, neg = false;
1496 ssize_t cmp;
1497
1498 if (a == b) return 0;
1499 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1500 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1501 if (a->neg) {
1502 if (b->neg)
1503 neg = true;
1504 else
1505 return -1;
1506 }
1507 else if (b->neg)
1508 return 1;
1509
1510 a_int = BC_NUM_INT(a);
1511 b_int = BC_NUM_INT(b);
1512 a_int -= b_int;
1513 a_max = (a->rdx > b->rdx);
1514
1515 if (a_int != 0) return (ssize_t) a_int;
1516
1517 if (a_max) {
1518 min = b->rdx;
1519 diff = a->rdx - b->rdx;
1520 max_num = a->num + diff;
1521 min_num = b->num;
1522 }
1523 else {
1524 min = a->rdx;
1525 diff = b->rdx - a->rdx;
1526 max_num = b->num + diff;
1527 min_num = a->num;
1528 }
1529
1530 cmp = bc_num_compare(max_num, min_num, b_int + min);
1531 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1532
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001533 for (max_num -= diff, i = diff - 1; !G.signe && i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001534 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1535 }
1536
1537 return 0;
1538}
1539
1540static void bc_num_truncate(BcNum *n, size_t places)
1541{
1542 if (places == 0) return;
1543
1544 n->rdx -= places;
1545
1546 if (n->len != 0) {
1547 n->len -= places;
1548 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1549 }
1550}
1551
1552static void bc_num_extend(BcNum *n, size_t places)
1553{
1554 size_t len = n->len + places;
1555
1556 if (places != 0) {
1557
1558 if (n->cap < len) bc_num_expand(n, len);
1559
1560 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1561 memset(n->num, 0, sizeof(BcDig) * places);
1562
1563 n->len += places;
1564 n->rdx += places;
1565 }
1566}
1567
1568static void bc_num_clean(BcNum *n)
1569{
1570 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1571 if (n->len == 0)
1572 n->neg = false;
1573 else if (n->len < n->rdx)
1574 n->len = n->rdx;
1575}
1576
1577static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1578{
1579 if (n->rdx < scale)
1580 bc_num_extend(n, scale - n->rdx);
1581 else
1582 bc_num_truncate(n, n->rdx - scale);
1583
1584 bc_num_clean(n);
1585 if (n->len != 0) n->neg = !neg1 != !neg2;
1586}
1587
1588static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1589 BcNum *restrict b)
1590{
1591 if (idx < n->len) {
1592
1593 b->len = n->len - idx;
1594 a->len = idx;
1595 a->rdx = b->rdx = 0;
1596
1597 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1598 memcpy(a->num, n->num, idx * sizeof(BcDig));
1599 }
1600 else {
1601 bc_num_zero(b);
1602 bc_num_copy(a, n);
1603 }
1604
1605 bc_num_clean(a);
1606 bc_num_clean(b);
1607}
1608
1609static BcStatus bc_num_shift(BcNum *n, size_t places)
1610{
1611 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1612 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1613
1614 if (n->rdx >= places)
1615 n->rdx -= places;
1616 else {
1617 bc_num_extend(n, places - n->rdx);
1618 n->rdx = 0;
1619 }
1620
1621 bc_num_clean(n);
1622
1623 return BC_STATUS_SUCCESS;
1624}
1625
1626static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1627{
1628 BcNum one;
1629 BcDig num[2];
1630
1631 one.cap = 2;
1632 one.num = num;
1633 bc_num_one(&one);
1634
1635 return bc_num_div(&one, a, b, scale);
1636}
1637
1638static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1639{
1640 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1641 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1642 int carry, in;
1643
1644 // Because this function doesn't need to use scale (per the bc spec),
1645 // I am hijacking it to say whether it's doing an add or a subtract.
1646
1647 if (a->len == 0) {
1648 bc_num_copy(c, b);
1649 if (sub && c->len) c->neg = !c->neg;
1650 return BC_STATUS_SUCCESS;
1651 }
1652 else if (b->len == 0) {
1653 bc_num_copy(c, a);
1654 return BC_STATUS_SUCCESS;
1655 }
1656
1657 c->neg = a->neg;
1658 c->rdx = BC_MAX(a->rdx, b->rdx);
1659 min_rdx = BC_MIN(a->rdx, b->rdx);
1660 c->len = 0;
1661
1662 if (a->rdx > b->rdx) {
1663 diff = a->rdx - b->rdx;
1664 ptr = a->num;
1665 ptr_a = a->num + diff;
1666 ptr_b = b->num;
1667 }
1668 else {
1669 diff = b->rdx - a->rdx;
1670 ptr = b->num;
1671 ptr_a = a->num;
1672 ptr_b = b->num + diff;
1673 }
1674
1675 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1676
1677 ptr_c += diff;
1678 a_int = BC_NUM_INT(a);
1679 b_int = BC_NUM_INT(b);
1680
1681 if (a_int > b_int) {
1682 min_int = b_int;
1683 max = a_int;
1684 ptr = ptr_a;
1685 }
1686 else {
1687 min_int = a_int;
1688 max = b_int;
1689 ptr = ptr_b;
1690 }
1691
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001692 for (carry = 0, i = 0; !G.signe && i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001693 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1694 carry = in / 10;
1695 ptr_c[i] = (BcDig)(in % 10);
1696 }
1697
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001698 for (; !G.signe && i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001699 in = ((int) ptr[i]) + carry;
1700 carry = in / 10;
1701 ptr_c[i] = (BcDig)(in % 10);
1702 }
1703
1704 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1705
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001706 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001707}
1708
1709static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1710{
1711 BcStatus s;
1712 ssize_t cmp;
1713 BcNum *minuend, *subtrahend;
1714 size_t start;
1715 bool aneg, bneg, neg;
1716
1717 // Because this function doesn't need to use scale (per the bc spec),
1718 // I am hijacking it to say whether it's doing an add or a subtract.
1719
1720 if (a->len == 0) {
1721 bc_num_copy(c, b);
1722 if (sub && c->len) c->neg = !c->neg;
1723 return BC_STATUS_SUCCESS;
1724 }
1725 else if (b->len == 0) {
1726 bc_num_copy(c, a);
1727 return BC_STATUS_SUCCESS;
1728 }
1729
1730 aneg = a->neg;
1731 bneg = b->neg;
1732 a->neg = b->neg = false;
1733
1734 cmp = bc_num_cmp(a, b);
1735
1736 a->neg = aneg;
1737 b->neg = bneg;
1738
1739 if (cmp == 0) {
1740 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1741 return BC_STATUS_SUCCESS;
1742 }
1743 else if (cmp > 0) {
1744 neg = a->neg;
1745 minuend = a;
1746 subtrahend = b;
1747 }
1748 else {
1749 neg = b->neg;
1750 if (sub) neg = !neg;
1751 minuend = b;
1752 subtrahend = a;
1753 }
1754
1755 bc_num_copy(c, minuend);
1756 c->neg = neg;
1757
1758 if (c->rdx < subtrahend->rdx) {
1759 bc_num_extend(c, subtrahend->rdx - c->rdx);
1760 start = 0;
1761 }
1762 else
1763 start = c->rdx - subtrahend->rdx;
1764
1765 s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1766
1767 bc_num_clean(c);
1768
1769 return s;
1770}
1771
1772static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1773 BcNum *restrict c)
1774{
1775 BcStatus s;
1776 int carry;
1777 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1778 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1779 bool aone = BC_NUM_ONE(a);
1780
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001781 if (G.signe) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06001782 if (a->len == 0 || b->len == 0) {
1783 bc_num_zero(c);
1784 return BC_STATUS_SUCCESS;
1785 }
1786 else if (aone || BC_NUM_ONE(b)) {
1787 bc_num_copy(c, aone ? b : a);
1788 return BC_STATUS_SUCCESS;
1789 }
1790
1791 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1792 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1793 {
1794 bc_num_expand(c, a->len + b->len + 1);
1795
1796 memset(c->num, 0, sizeof(BcDig) * c->cap);
1797 c->len = carry = len = 0;
1798
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001799 for (i = 0; !G.signe && i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001800
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001801 for (j = 0; !G.signe && j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001802 int in = (int) c->num[i + j];
1803 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1804 carry = in / 10;
1805 c->num[i + j] = (BcDig)(in % 10);
1806 }
1807
1808 c->num[i + j] += (BcDig) carry;
1809 len = BC_MAX(len, i + j + !!carry);
1810 carry = 0;
1811 }
1812
1813 c->len = len;
1814
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001815 return G.signe ? BC_STATUS_EXEC_SIGNAL : BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001816 }
1817
1818 bc_num_init(&l1, max);
1819 bc_num_init(&h1, max);
1820 bc_num_init(&l2, max);
1821 bc_num_init(&h2, max);
1822 bc_num_init(&m1, max);
1823 bc_num_init(&m2, max);
1824 bc_num_init(&z0, max);
1825 bc_num_init(&z1, max);
1826 bc_num_init(&z2, max);
1827 bc_num_init(&temp, max + max);
1828
1829 bc_num_split(a, max2, &l1, &h1);
1830 bc_num_split(b, max2, &l2, &h2);
1831
1832 s = bc_num_add(&h1, &l1, &m1, 0);
1833 if (s) goto err;
1834 s = bc_num_add(&h2, &l2, &m2, 0);
1835 if (s) goto err;
1836
1837 s = bc_num_k(&h1, &h2, &z0);
1838 if (s) goto err;
1839 s = bc_num_k(&m1, &m2, &z1);
1840 if (s) goto err;
1841 s = bc_num_k(&l1, &l2, &z2);
1842 if (s) goto err;
1843
1844 s = bc_num_sub(&z1, &z0, &temp, 0);
1845 if (s) goto err;
1846 s = bc_num_sub(&temp, &z2, &z1, 0);
1847 if (s) goto err;
1848
1849 s = bc_num_shift(&z0, max2 * 2);
1850 if (s) goto err;
1851 s = bc_num_shift(&z1, max2);
1852 if (s) goto err;
1853 s = bc_num_add(&z0, &z1, &temp, 0);
1854 if (s) goto err;
1855 s = bc_num_add(&temp, &z2, c, 0);
1856
1857err:
1858 bc_num_free(&temp);
1859 bc_num_free(&z2);
1860 bc_num_free(&z1);
1861 bc_num_free(&z0);
1862 bc_num_free(&m2);
1863 bc_num_free(&m1);
1864 bc_num_free(&h2);
1865 bc_num_free(&l2);
1866 bc_num_free(&h1);
1867 bc_num_free(&l1);
1868 return s;
1869}
1870
1871static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1872{
1873 BcStatus s;
1874 BcNum cpa, cpb;
1875 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1876
1877 scale = BC_MAX(scale, a->rdx);
1878 scale = BC_MAX(scale, b->rdx);
1879 scale = BC_MIN(a->rdx + b->rdx, scale);
1880 maxrdx = BC_MAX(maxrdx, scale);
1881
1882 bc_num_init(&cpa, a->len);
1883 bc_num_init(&cpb, b->len);
1884
1885 bc_num_copy(&cpa, a);
1886 bc_num_copy(&cpb, b);
1887 cpa.neg = cpb.neg = false;
1888
1889 s = bc_num_shift(&cpa, maxrdx);
1890 if (s) goto err;
1891 s = bc_num_shift(&cpb, maxrdx);
1892 if (s) goto err;
1893 s = bc_num_k(&cpa, &cpb, c);
1894 if (s) goto err;
1895
1896 maxrdx += scale;
1897 bc_num_expand(c, c->len + maxrdx);
1898
1899 if (c->len < maxrdx) {
1900 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1901 c->len += maxrdx;
1902 }
1903
1904 c->rdx = maxrdx;
1905 bc_num_retireMul(c, scale, a->neg, b->neg);
1906
1907err:
1908 bc_num_free(&cpb);
1909 bc_num_free(&cpa);
1910 return s;
1911}
1912
1913static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1914{
1915 BcStatus s = BC_STATUS_SUCCESS;
1916 BcDig *n, *p, q;
1917 size_t len, end, i;
1918 BcNum cp;
1919 bool zero = true;
1920
1921 if (b->len == 0)
1922 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1923 else if (a->len == 0) {
1924 bc_num_setToZero(c, scale);
1925 return BC_STATUS_SUCCESS;
1926 }
1927 else if (BC_NUM_ONE(b)) {
1928 bc_num_copy(c, a);
1929 bc_num_retireMul(c, scale, a->neg, b->neg);
1930 return BC_STATUS_SUCCESS;
1931 }
1932
1933 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1934 bc_num_copy(&cp, a);
1935 len = b->len;
1936
1937 if (len > cp.len) {
1938 bc_num_expand(&cp, len + 2);
1939 bc_num_extend(&cp, len - cp.len);
1940 }
1941
1942 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1943 cp.rdx -= b->rdx;
1944 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1945
1946 if (b->rdx == b->len) {
1947 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1948 len -= i - 1;
1949 }
1950
1951 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1952
1953 // We want an extra zero in front to make things simpler.
1954 cp.num[cp.len++] = 0;
1955 end = cp.len - len;
1956
1957 bc_num_expand(c, cp.len);
1958
1959 bc_num_zero(c);
1960 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1961 c->rdx = cp.rdx;
1962 c->len = cp.len;
1963 p = b->num;
1964
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01001965 for (i = end - 1; !G.signe && !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001966 n = cp.num + i;
1967 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1968 s = bc_num_subArrays(n, p, len);
1969 c->num[i] = q;
1970 }
1971
1972 if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1973 bc_num_free(&cp);
1974
1975 return s;
1976}
1977
1978static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1979 BcNum *restrict d, size_t scale, size_t ts)
1980{
1981 BcStatus s;
1982 BcNum temp;
1983 bool neg;
1984
1985 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1986
1987 if (a->len == 0) {
1988 bc_num_setToZero(d, ts);
1989 return BC_STATUS_SUCCESS;
1990 }
1991
1992 bc_num_init(&temp, d->cap);
1993 bc_num_d(a, b, c, scale);
1994
1995 if (scale != 0) scale = ts;
1996
1997 s = bc_num_m(c, b, &temp, scale);
1998 if (s) goto err;
1999 s = bc_num_sub(a, &temp, d, scale);
2000 if (s) goto err;
2001
2002 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2003
2004 neg = d->neg;
2005 bc_num_retireMul(d, ts, a->neg, b->neg);
2006 d->neg = neg;
2007
2008err:
2009 bc_num_free(&temp);
2010 return s;
2011}
2012
2013static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2014{
2015 BcStatus s;
2016 BcNum c1;
2017 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2018
2019 bc_num_init(&c1, len);
2020 s = bc_num_r(a, b, &c1, c, scale, ts);
2021 bc_num_free(&c1);
2022
2023 return s;
2024}
2025
2026static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
2027{
2028 BcStatus s = BC_STATUS_SUCCESS;
2029 BcNum copy;
2030 unsigned long pow;
2031 size_t i, powrdx, resrdx;
2032 bool neg, zero;
2033
2034 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2035
2036 if (b->len == 0) {
2037 bc_num_one(c);
2038 return BC_STATUS_SUCCESS;
2039 }
2040 else if (a->len == 0) {
2041 bc_num_setToZero(c, scale);
2042 return BC_STATUS_SUCCESS;
2043 }
2044 else if (BC_NUM_ONE(b)) {
2045 if (!b->neg)
2046 bc_num_copy(c, a);
2047 else
2048 s = bc_num_inv(a, c, scale);
2049 return s;
2050 }
2051
2052 neg = b->neg;
2053 b->neg = false;
2054
2055 s = bc_num_ulong(b, &pow);
2056 if (s) return s;
2057
2058 bc_num_init(&copy, a->len);
2059 bc_num_copy(&copy, a);
2060
2061 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2062
2063 b->neg = neg;
2064
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002065 for (powrdx = a->rdx; !G.signe && !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002066 powrdx <<= 1;
2067 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2068 if (s) goto err;
2069 }
2070
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002071 if (G.signe) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002072 s = BC_STATUS_EXEC_SIGNAL;
2073 goto err;
2074 }
2075
2076 bc_num_copy(c, &copy);
2077
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002078 for (resrdx = powrdx, pow >>= 1; !G.signe && pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002079
2080 powrdx <<= 1;
2081 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2082 if (s) goto err;
2083
2084 if (pow & 1) {
2085 resrdx += powrdx;
2086 s = bc_num_mul(c, &copy, c, resrdx);
2087 if (s) goto err;
2088 }
2089 }
2090
2091 if (neg) {
2092 s = bc_num_inv(c, c, scale);
2093 if (s) goto err;
2094 }
2095
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002096 if (G.signe) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002097 s = BC_STATUS_EXEC_SIGNAL;
2098 goto err;
2099 }
2100
2101 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2102
2103 // We can't use bc_num_clean() here.
2104 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2105 if (zero) bc_num_setToZero(c, scale);
2106
2107err:
2108 bc_num_free(&copy);
2109 return s;
2110}
2111
2112static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2113 BcNumBinaryOp op, size_t req)
2114{
2115 BcStatus s;
2116 BcNum num2, *ptr_a, *ptr_b;
2117 bool init = false;
2118
2119 if (c == a) {
2120 ptr_a = &num2;
2121 memcpy(ptr_a, c, sizeof(BcNum));
2122 init = true;
2123 }
2124 else
2125 ptr_a = a;
2126
2127 if (c == b) {
2128 ptr_b = &num2;
2129 if (c != a) {
2130 memcpy(ptr_b, c, sizeof(BcNum));
2131 init = true;
2132 }
2133 }
2134 else
2135 ptr_b = b;
2136
2137 if (init)
2138 bc_num_init(c, req);
2139 else
2140 bc_num_expand(c, req);
2141
2142 s = op(ptr_a, ptr_b, c, scale);
2143
2144 if (init) bc_num_free(&num2);
2145
2146 return s;
2147}
2148
2149static bool bc_num_strValid(const char *val, size_t base)
2150{
2151 BcDig b;
2152 bool small, radix = false;
2153 size_t i, len = strlen(val);
2154
2155 if (!len) return true;
2156
2157 small = base <= 10;
2158 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2159
2160 for (i = 0; i < len; ++i) {
2161
2162 BcDig c = val[i];
2163
2164 if (c == '.') {
2165
2166 if (radix) return false;
2167
2168 radix = true;
2169 continue;
2170 }
2171
2172 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2173 return false;
2174 }
2175
2176 return true;
2177}
2178
2179static void bc_num_parseDecimal(BcNum *n, const char *val)
2180{
2181 size_t len, i;
2182 const char *ptr;
2183 bool zero = true;
2184
2185 for (i = 0; val[i] == '0'; ++i);
2186
2187 val += i;
2188 len = strlen(val);
2189 bc_num_zero(n);
2190
2191 if (len != 0) {
2192 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2193 bc_num_expand(n, len);
2194 }
2195
2196 ptr = strchr(val, '.');
2197
2198 // Explicitly test for NULL here to produce either a 0 or 1.
2199 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2200
2201 if (!zero) {
2202 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2203 n->num[n->len] = val[i] - '0';
2204 }
2205}
2206
2207static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2208{
2209 BcStatus s;
2210 BcNum temp, mult, result;
2211 BcDig c = '\0';
2212 bool zero = true;
2213 unsigned long v;
2214 size_t i, digits, len = strlen(val);
2215
2216 bc_num_zero(n);
2217
2218 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2219 if (zero) return;
2220
2221 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2222 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2223
2224 for (i = 0; i < len; ++i) {
2225
2226 c = val[i];
2227 if (c == '.') break;
2228
2229 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2230
2231 s = bc_num_mul(n, base, &mult, 0);
2232 if (s) goto int_err;
2233 s = bc_num_ulong2num(&temp, v);
2234 if (s) goto int_err;
2235 s = bc_num_add(&mult, &temp, n, 0);
2236 if (s) goto int_err;
2237 }
2238
2239 if (i == len) {
2240 c = val[i];
2241 if (c == 0) goto int_err;
2242 }
2243
2244 bc_num_init(&result, base->len);
2245 bc_num_zero(&result);
2246 bc_num_one(&mult);
2247
2248 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2249
2250 c = val[i];
2251 if (c == 0) break;
2252
2253 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2254
2255 s = bc_num_mul(&result, base, &result, 0);
2256 if (s) goto err;
2257 s = bc_num_ulong2num(&temp, v);
2258 if (s) goto err;
2259 s = bc_num_add(&result, &temp, &result, 0);
2260 if (s) goto err;
2261 s = bc_num_mul(&mult, base, &mult, 0);
2262 if (s) goto err;
2263 }
2264
2265 s = bc_num_div(&result, &mult, &result, digits);
2266 if (s) goto err;
2267 s = bc_num_add(n, &result, n, digits);
2268 if (s) goto err;
2269
2270 if (n->len != 0) {
2271 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2272 }
2273 else
2274 bc_num_zero(n);
2275
2276err:
2277 bc_num_free(&result);
2278int_err:
2279 bc_num_free(&mult);
2280 bc_num_free(&temp);
2281}
2282
2283static void bc_num_printNewline(size_t *nchars, size_t line_len)
2284{
2285 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002286 bb_putchar('\\');
2287 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002288 *nchars = 0;
2289 }
2290}
2291
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002292#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002293static void bc_num_printChar(size_t num, size_t width, bool radix,
2294 size_t *nchars, size_t line_len)
2295{
2296 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002297 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002298 *nchars = *nchars + width;
2299}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002300#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002301
2302static void bc_num_printDigits(size_t num, size_t width, bool radix,
2303 size_t *nchars, size_t line_len)
2304{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002305 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002306
2307 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002308 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002309 ++(*nchars);
2310
2311 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002312 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2313 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002314
2315 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002316 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002317 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002318 dig = num / pow;
2319 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002320 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002321 }
2322}
2323
2324static void bc_num_printHex(size_t num, size_t width, bool radix,
2325 size_t *nchars, size_t line_len)
2326{
2327 if (radix) {
2328 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002329 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002330 *nchars += 1;
2331 }
2332
2333 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002334 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002335 *nchars = *nchars + width;
2336}
2337
2338static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2339{
2340 size_t i, rdx = n->rdx - 1;
2341
Denys Vlasenko00d77792018-11-30 23:13:42 +01002342 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002343 (*nchars) += n->neg;
2344
2345 for (i = n->len - 1; i < n->len; --i)
2346 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2347}
2348
2349static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2350 size_t *nchars, size_t len, BcNumDigitOp print)
2351{
2352 BcStatus s;
2353 BcVec stack;
2354 BcNum intp, fracp, digit, frac_len;
2355 unsigned long dig, *ptr;
2356 size_t i;
2357 bool radix;
2358
2359 if (n->len == 0) {
2360 print(0, width, false, nchars, len);
2361 return BC_STATUS_SUCCESS;
2362 }
2363
2364 bc_vec_init(&stack, sizeof(long), NULL);
2365 bc_num_init(&intp, n->len);
2366 bc_num_init(&fracp, n->rdx);
2367 bc_num_init(&digit, width);
2368 bc_num_init(&frac_len, BC_NUM_INT(n));
2369 bc_num_copy(&intp, n);
2370 bc_num_one(&frac_len);
2371
2372 bc_num_truncate(&intp, intp.rdx);
2373 s = bc_num_sub(n, &intp, &fracp, 0);
2374 if (s) goto err;
2375
2376 while (intp.len != 0) {
2377 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2378 if (s) goto err;
2379 s = bc_num_ulong(&digit, &dig);
2380 if (s) goto err;
2381 bc_vec_push(&stack, &dig);
2382 }
2383
2384 for (i = 0; i < stack.len; ++i) {
2385 ptr = bc_vec_item_rev(&stack, i);
2386 print(*ptr, width, false, nchars, len);
2387 }
2388
2389 if (!n->rdx) goto err;
2390
2391 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2392 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2393 if (s) goto err;
2394 s = bc_num_ulong(&fracp, &dig);
2395 if (s) goto err;
2396 s = bc_num_ulong2num(&intp, dig);
2397 if (s) goto err;
2398 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2399 if (s) goto err;
2400 print(dig, width, radix, nchars, len);
2401 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2402 if (s) goto err;
2403 }
2404
2405err:
2406 bc_num_free(&frac_len);
2407 bc_num_free(&digit);
2408 bc_num_free(&fracp);
2409 bc_num_free(&intp);
2410 bc_vec_free(&stack);
2411 return s;
2412}
2413
2414static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2415 size_t *nchars, size_t line_len)
2416{
2417 BcStatus s;
2418 size_t width, i;
2419 BcNumDigitOp print;
2420 bool neg = n->neg;
2421
Denys Vlasenko00d77792018-11-30 23:13:42 +01002422 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002423 (*nchars) += neg;
2424
2425 n->neg = false;
2426
2427 if (base_t <= BC_NUM_MAX_IBASE) {
2428 width = 1;
2429 print = bc_num_printHex;
2430 }
2431 else {
2432 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2433 print = bc_num_printDigits;
2434 }
2435
2436 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2437 n->neg = neg;
2438
2439 return s;
2440}
2441
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002442#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002443static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2444{
2445 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2446}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002447#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002448
2449static void bc_num_init(BcNum *n, size_t req)
2450{
2451 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2452 memset(n, 0, sizeof(BcNum));
2453 n->num = xmalloc(req);
2454 n->cap = req;
2455}
2456
2457static void bc_num_expand(BcNum *n, size_t req)
2458{
2459 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2460 if (req > n->cap) {
2461 n->num = xrealloc(n->num, req);
2462 n->cap = req;
2463 }
2464}
2465
2466static void bc_num_free(void *num)
2467{
2468 free(((BcNum *) num)->num);
2469}
2470
2471static void bc_num_copy(BcNum *d, BcNum *s)
2472{
2473 if (d != s) {
2474 bc_num_expand(d, s->cap);
2475 d->len = s->len;
2476 d->neg = s->neg;
2477 d->rdx = s->rdx;
2478 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2479 }
2480}
2481
2482static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2483 size_t base_t)
2484{
2485 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2486
2487 if (base_t == 10)
2488 bc_num_parseDecimal(n, val);
2489 else
2490 bc_num_parseBase(n, val, base);
2491
2492 return BC_STATUS_SUCCESS;
2493}
2494
2495static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2496 size_t *nchars, size_t line_len)
2497{
2498 BcStatus s = BC_STATUS_SUCCESS;
2499
2500 bc_num_printNewline(nchars, line_len);
2501
2502 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002503 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002504 ++(*nchars);
2505 }
2506 else if (base_t == 10)
2507 bc_num_printDecimal(n, nchars, line_len);
2508 else
2509 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2510
2511 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002512 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002513 *nchars = 0;
2514 }
2515
2516 return s;
2517}
2518
2519static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2520{
2521 size_t i;
2522 unsigned long pow;
2523
2524 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2525
2526 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2527
2528 unsigned long prev = *result, powprev = pow;
2529
2530 *result += ((unsigned long) n->num[i]) * pow;
2531 pow *= 10;
2532
2533 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2534 }
2535
2536 return BC_STATUS_SUCCESS;
2537}
2538
2539static BcStatus bc_num_ulong2num(BcNum *n, unsigned long val)
2540{
2541 size_t len;
2542 BcDig *ptr;
2543 unsigned long i;
2544
2545 bc_num_zero(n);
2546
2547 if (val == 0) return BC_STATUS_SUCCESS;
2548
2549 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2550 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2551
2552 return BC_STATUS_SUCCESS;
2553}
2554
2555static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2556{
2557 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2558 (void) scale;
2559 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2560}
2561
2562static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2563{
2564 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2565 (void) scale;
2566 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2567}
2568
2569static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2570{
2571 size_t req = BC_NUM_MREQ(a, b, scale);
2572 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2573}
2574
2575static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2576{
2577 size_t req = BC_NUM_MREQ(a, b, scale);
2578 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2579}
2580
2581static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2582{
2583 size_t req = BC_NUM_MREQ(a, b, scale);
2584 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2585}
2586
2587static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2588{
2589 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2590}
2591
2592static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2593{
2594 BcStatus s;
2595 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2596 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2597 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2598
2599 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2600 bc_num_expand(b, req);
2601
2602 if (a->len == 0) {
2603 bc_num_setToZero(b, scale);
2604 return BC_STATUS_SUCCESS;
2605 }
2606 else if (a->neg)
2607 return BC_STATUS_MATH_NEGATIVE;
2608 else if (BC_NUM_ONE(a)) {
2609 bc_num_one(b);
2610 bc_num_extend(b, scale);
2611 return BC_STATUS_SUCCESS;
2612 }
2613
2614 scale = BC_MAX(scale, a->rdx) + 1;
2615 len = a->len + scale;
2616
2617 bc_num_init(&num1, len);
2618 bc_num_init(&num2, len);
2619 bc_num_init(&half, BC_NUM_DEF_SIZE);
2620
2621 bc_num_one(&half);
2622 half.num[0] = 5;
2623 half.rdx = 1;
2624
2625 bc_num_init(&f, len);
2626 bc_num_init(&fprime, len);
2627
2628 x0 = &num1;
2629 x1 = &num2;
2630
2631 bc_num_one(x0);
2632 pow = BC_NUM_INT(a);
2633
2634 if (pow) {
2635
2636 if (pow & 1)
2637 x0->num[0] = 2;
2638 else
2639 x0->num[0] = 6;
2640
2641 pow -= 2 - (pow & 1);
2642
2643 bc_num_extend(x0, pow);
2644
2645 // Make sure to move the radix back.
2646 x0->rdx -= pow;
2647 }
2648
2649 x0->rdx = digs = digs1 = 0;
2650 resrdx = scale + 2;
2651 len = BC_NUM_INT(x0) + resrdx - 1;
2652
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002653 while (!G.signe && (cmp != 0 || digs < len)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002654
2655 s = bc_num_div(a, x0, &f, resrdx);
2656 if (s) goto err;
2657 s = bc_num_add(x0, &f, &fprime, resrdx);
2658 if (s) goto err;
2659 s = bc_num_mul(&fprime, &half, x1, resrdx);
2660 if (s) goto err;
2661
2662 cmp = bc_num_cmp(x1, x0);
2663 digs = x1->len - (unsigned long long) llabs(cmp);
2664
2665 if (cmp == cmp2 && digs == digs1)
2666 times += 1;
2667 else
2668 times = 0;
2669
2670 resrdx += times > 4;
2671
2672 cmp2 = cmp1;
2673 cmp1 = cmp;
2674 digs1 = digs;
2675
2676 temp = x0;
2677 x0 = x1;
2678 x1 = temp;
2679 }
2680
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01002681 if (G.signe) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002682 s = BC_STATUS_EXEC_SIGNAL;
2683 goto err;
2684 }
2685
2686 bc_num_copy(b, x0);
2687 scale -= 1;
2688 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2689
2690err:
2691 bc_num_free(&fprime);
2692 bc_num_free(&f);
2693 bc_num_free(&half);
2694 bc_num_free(&num2);
2695 bc_num_free(&num1);
2696 return s;
2697}
2698
2699static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2700 size_t scale)
2701{
2702 BcStatus s;
2703 BcNum num2, *ptr_a;
2704 bool init = false;
2705 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2706
2707 if (c == a) {
2708 memcpy(&num2, c, sizeof(BcNum));
2709 ptr_a = &num2;
2710 bc_num_init(c, len);
2711 init = true;
2712 }
2713 else {
2714 ptr_a = a;
2715 bc_num_expand(c, len);
2716 }
2717
2718 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2719
2720 if (init) bc_num_free(&num2);
2721
2722 return s;
2723}
2724
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002725#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002726static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2727{
2728 BcStatus s;
2729 BcNum base, exp, two, temp;
2730
2731 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2732 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2733 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2734
2735 bc_num_expand(d, c->len);
2736 bc_num_init(&base, c->len);
2737 bc_num_init(&exp, b->len);
2738 bc_num_init(&two, BC_NUM_DEF_SIZE);
2739 bc_num_init(&temp, b->len);
2740
2741 bc_num_one(&two);
2742 two.num[0] = 2;
2743 bc_num_one(d);
2744
2745 s = bc_num_rem(a, c, &base, 0);
2746 if (s) goto err;
2747 bc_num_copy(&exp, b);
2748
2749 while (exp.len != 0) {
2750
2751 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2752 if (s) goto err;
2753
2754 if (BC_NUM_ONE(&temp)) {
2755 s = bc_num_mul(d, &base, &temp, 0);
2756 if (s) goto err;
2757 s = bc_num_rem(&temp, c, d, 0);
2758 if (s) goto err;
2759 }
2760
2761 s = bc_num_mul(&base, &base, &temp, 0);
2762 if (s) goto err;
2763 s = bc_num_rem(&temp, c, &base, 0);
2764 if (s) goto err;
2765 }
2766
2767err:
2768 bc_num_free(&temp);
2769 bc_num_free(&two);
2770 bc_num_free(&exp);
2771 bc_num_free(&base);
2772 return s;
2773}
2774#endif // ENABLE_DC
2775
2776static int bc_id_cmp(const void *e1, const void *e2)
2777{
2778 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2779}
2780
2781static void bc_id_free(void *id)
2782{
2783 free(((BcId *) id)->name);
2784}
2785
2786static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2787{
2788 BcId a;
2789 size_t i;
2790
2791 for (i = 0; i < f->autos.len; ++i) {
2792 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2793 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2794 }
2795
2796 a.idx = var;
2797 a.name = name;
2798
2799 bc_vec_push(&f->autos, &a);
2800
2801 return BC_STATUS_SUCCESS;
2802}
2803
2804static void bc_func_init(BcFunc *f)
2805{
2806 bc_vec_init(&f->code, sizeof(char), NULL);
2807 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2808 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2809 f->nparams = 0;
2810}
2811
2812static void bc_func_free(void *func)
2813{
2814 BcFunc *f = (BcFunc *) func;
2815 bc_vec_free(&f->code);
2816 bc_vec_free(&f->autos);
2817 bc_vec_free(&f->labels);
2818}
2819
2820static void bc_array_init(BcVec *a, bool nums)
2821{
2822 if (nums)
2823 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2824 else
2825 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2826 bc_array_expand(a, 1);
2827}
2828
2829static void bc_array_copy(BcVec *d, const BcVec *s)
2830{
2831 size_t i;
2832
2833 bc_vec_npop(d, d->len);
2834 bc_vec_expand(d, s->cap);
2835 d->len = s->len;
2836
2837 for (i = 0; i < s->len; ++i) {
2838 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2839 bc_num_init(dnum, snum->len);
2840 bc_num_copy(dnum, snum);
2841 }
2842}
2843
2844static void bc_array_expand(BcVec *a, size_t len)
2845{
2846 BcResultData data;
2847
2848 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2849 while (len > a->len) {
2850 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2851 bc_vec_push(a, &data.n);
2852 }
2853 }
2854 else {
2855 while (len > a->len) {
2856 bc_array_init(&data.v, true);
2857 bc_vec_push(a, &data.v);
2858 }
2859 }
2860}
2861
2862static void bc_string_free(void *string)
2863{
2864 free(*((char **) string));
2865}
2866
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002867#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002868static void bc_result_copy(BcResult *d, BcResult *src)
2869{
2870 d->t = src->t;
2871
2872 switch (d->t) {
2873
2874 case BC_RESULT_TEMP:
2875 case BC_RESULT_IBASE:
2876 case BC_RESULT_SCALE:
2877 case BC_RESULT_OBASE:
2878 {
2879 bc_num_init(&d->d.n, src->d.n.len);
2880 bc_num_copy(&d->d.n, &src->d.n);
2881 break;
2882 }
2883
2884 case BC_RESULT_VAR:
2885 case BC_RESULT_ARRAY:
2886 case BC_RESULT_ARRAY_ELEM:
2887 {
2888 d->d.id.name = xstrdup(src->d.id.name);
2889 break;
2890 }
2891
2892 case BC_RESULT_CONSTANT:
2893 case BC_RESULT_LAST:
2894 case BC_RESULT_ONE:
2895 case BC_RESULT_STR:
2896 {
2897 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2898 break;
2899 }
2900 }
2901}
2902#endif // ENABLE_DC
2903
2904static void bc_result_free(void *result)
2905{
2906 BcResult *r = (BcResult *) result;
2907
2908 switch (r->t) {
2909
2910 case BC_RESULT_TEMP:
2911 case BC_RESULT_IBASE:
2912 case BC_RESULT_SCALE:
2913 case BC_RESULT_OBASE:
2914 {
2915 bc_num_free(&r->d.n);
2916 break;
2917 }
2918
2919 case BC_RESULT_VAR:
2920 case BC_RESULT_ARRAY:
2921 case BC_RESULT_ARRAY_ELEM:
2922 {
2923 free(r->d.id.name);
2924 break;
2925 }
2926
2927 default:
2928 {
2929 // Do nothing.
2930 break;
2931 }
2932 }
2933}
2934
2935static void bc_lex_lineComment(BcLex *l)
2936{
2937 l->t.t = BC_LEX_WHITESPACE;
2938 while (l->i < l->len && l->buf[l->i++] != '\n');
2939 --l->i;
2940}
2941
2942static void bc_lex_whitespace(BcLex *l)
2943{
2944 char c;
2945 l->t.t = BC_LEX_WHITESPACE;
2946 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2947}
2948
2949static BcStatus bc_lex_number(BcLex *l, char start)
2950{
2951 const char *buf = l->buf + l->i;
2952 size_t len, hits = 0, bslashes = 0, i = 0, j;
2953 char c = buf[i];
2954 bool last_pt, pt = start == '.';
2955
2956 last_pt = pt;
2957 l->t.t = BC_LEX_NUMBER;
2958
2959 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2960 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2961 {
2962 if (c != '\\') {
2963 last_pt = c == '.';
2964 pt = pt || last_pt;
2965 }
2966 else {
2967 ++i;
2968 bslashes += 1;
2969 }
2970
2971 c = buf[++i];
2972 }
2973
2974 len = i + 1 * !last_pt - bslashes * 2;
2975 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2976
2977 bc_vec_npop(&l->t.v, l->t.v.len);
2978 bc_vec_expand(&l->t.v, len + 1);
2979 bc_vec_push(&l->t.v, &start);
2980
2981 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2982
2983 c = buf[j];
2984
2985 // If we have hit a backslash, skip it. We don't have
2986 // to check for a newline because it's guaranteed.
2987 if (hits < bslashes && c == '\\') {
2988 ++hits;
2989 ++j;
2990 continue;
2991 }
2992
2993 bc_vec_push(&l->t.v, &c);
2994 }
2995
2996 bc_vec_pushByte(&l->t.v, '\0');
2997 l->i += i;
2998
2999 return BC_STATUS_SUCCESS;
3000}
3001
3002static BcStatus bc_lex_name(BcLex *l)
3003{
3004 size_t i = 0;
3005 const char *buf = l->buf + l->i - 1;
3006 char c = buf[i];
3007
3008 l->t.t = BC_LEX_NAME;
3009
3010 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
3011
3012 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
3013 bc_vec_string(&l->t.v, i, buf);
3014
3015 // Increment the index. We minus 1 because it has already been incremented.
3016 l->i += i - 1;
3017
3018 return BC_STATUS_SUCCESS;
3019}
3020
3021static void bc_lex_init(BcLex *l, BcLexNext next)
3022{
3023 l->next = next;
3024 bc_vec_init(&l->t.v, sizeof(char), NULL);
3025}
3026
3027static void bc_lex_free(BcLex *l)
3028{
3029 bc_vec_free(&l->t.v);
3030}
3031
3032static void bc_lex_file(BcLex *l, const char *file)
3033{
3034 l->line = 1;
3035 l->newline = false;
3036 l->f = file;
3037}
3038
3039static BcStatus bc_lex_next(BcLex *l)
3040{
3041 BcStatus s;
3042
3043 l->t.last = l->t.t;
3044 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
3045
3046 l->line += l->newline;
3047 l->t.t = BC_LEX_EOF;
3048
3049 l->newline = (l->i == l->len);
3050 if (l->newline) return BC_STATUS_SUCCESS;
3051
3052 // Loop until failure or we don't have whitespace. This
3053 // is so the parser doesn't get inundated with whitespace.
3054 do {
3055 s = l->next(l);
3056 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3057
3058 return s;
3059}
3060
3061static BcStatus bc_lex_text(BcLex *l, const char *text)
3062{
3063 l->buf = text;
3064 l->i = 0;
3065 l->len = strlen(text);
3066 l->t.t = l->t.last = BC_LEX_INVALID;
3067 return bc_lex_next(l);
3068}
3069
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003070#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003071static BcStatus bc_lex_identifier(BcLex *l)
3072{
3073 BcStatus s;
3074 size_t i;
3075 const char *buf = l->buf + l->i - 1;
3076
3077 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3078
3079 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3080
3081 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3082
3083 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3084
3085 if (!bc_lex_kws[i].posix) {
3086 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3087 bc_lex_kws[i].name);
3088 if (s) return s;
3089 }
3090
3091 // We minus 1 because the index has already been incremented.
3092 l->i += len - 1;
3093 return BC_STATUS_SUCCESS;
3094 }
3095 }
3096
3097 s = bc_lex_name(l);
3098 if (s) return s;
3099
3100 if (l->t.v.len - 1 > 1)
3101 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3102
3103 return s;
3104}
3105
3106static BcStatus bc_lex_string(BcLex *l)
3107{
3108 size_t len, nls = 0, i = l->i;
3109 char c;
3110
3111 l->t.t = BC_LEX_STR;
3112
3113 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3114
3115 if (c == '\0') {
3116 l->i = i;
3117 return BC_STATUS_LEX_NO_STRING_END;
3118 }
3119
3120 len = i - l->i;
3121 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3122 bc_vec_string(&l->t.v, len, l->buf + l->i);
3123
3124 l->i = i + 1;
3125 l->line += nls;
3126
3127 return BC_STATUS_SUCCESS;
3128}
3129
3130static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3131{
3132 if (l->buf[l->i] == '=') {
3133 ++l->i;
3134 l->t.t = with;
3135 }
3136 else
3137 l->t.t = without;
3138}
3139
3140static BcStatus bc_lex_comment(BcLex *l)
3141{
3142 size_t i, nls = 0;
3143 const char *buf = l->buf;
3144 bool end = false;
3145 char c;
3146
3147 l->t.t = BC_LEX_WHITESPACE;
3148
3149 for (i = ++l->i; !end; i += !end) {
3150
3151 for (c = buf[i]; c != '*' && c != 0; c = buf[++i]) nls += (c == '\n');
3152
3153 if (c == 0 || buf[i + 1] == '\0') {
3154 l->i = i;
3155 return BC_STATUS_LEX_NO_COMMENT_END;
3156 }
3157
3158 end = buf[i + 1] == '/';
3159 }
3160
3161 l->i = i + 2;
3162 l->line += nls;
3163
3164 return BC_STATUS_SUCCESS;
3165}
3166
3167static BcStatus bc_lex_token(BcLex *l)
3168{
3169 BcStatus s = BC_STATUS_SUCCESS;
3170 char c = l->buf[l->i++], c2;
3171
3172 // This is the workhorse of the lexer.
3173 switch (c) {
3174
3175 case '\0':
3176 case '\n':
3177 {
3178 l->newline = true;
3179 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3180 break;
3181 }
3182
3183 case '\t':
3184 case '\v':
3185 case '\f':
3186 case '\r':
3187 case ' ':
3188 {
3189 bc_lex_whitespace(l);
3190 break;
3191 }
3192
3193 case '!':
3194 {
3195 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3196
3197 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3198 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3199 if (s) return s;
3200 }
3201
3202 break;
3203 }
3204
3205 case '"':
3206 {
3207 s = bc_lex_string(l);
3208 break;
3209 }
3210
3211 case '#':
3212 {
3213 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3214 if (s) return s;
3215
3216 bc_lex_lineComment(l);
3217
3218 break;
3219 }
3220
3221 case '%':
3222 {
3223 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3224 break;
3225 }
3226
3227 case '&':
3228 {
3229 c2 = l->buf[l->i];
3230 if (c2 == '&') {
3231
3232 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3233 if (s) return s;
3234
3235 ++l->i;
3236 l->t.t = BC_LEX_OP_BOOL_AND;
3237 }
3238 else {
3239 l->t.t = BC_LEX_INVALID;
3240 s = BC_STATUS_LEX_BAD_CHAR;
3241 }
3242
3243 break;
3244 }
3245
3246 case '(':
3247 case ')':
3248 {
3249 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3250 break;
3251 }
3252
3253 case '*':
3254 {
3255 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3256 break;
3257 }
3258
3259 case '+':
3260 {
3261 c2 = l->buf[l->i];
3262 if (c2 == '+') {
3263 ++l->i;
3264 l->t.t = BC_LEX_OP_INC;
3265 }
3266 else
3267 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3268 break;
3269 }
3270
3271 case ',':
3272 {
3273 l->t.t = BC_LEX_COMMA;
3274 break;
3275 }
3276
3277 case '-':
3278 {
3279 c2 = l->buf[l->i];
3280 if (c2 == '-') {
3281 ++l->i;
3282 l->t.t = BC_LEX_OP_DEC;
3283 }
3284 else
3285 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3286 break;
3287 }
3288
3289 case '.':
3290 {
3291 if (isdigit(l->buf[l->i]))
3292 s = bc_lex_number(l, c);
3293 else {
3294 l->t.t = BC_LEX_KEY_LAST;
3295 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3296 }
3297 break;
3298 }
3299
3300 case '/':
3301 {
3302 c2 = l->buf[l->i];
3303 if (c2 == '*')
3304 s = bc_lex_comment(l);
3305 else
3306 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3307 break;
3308 }
3309
3310 case '0':
3311 case '1':
3312 case '2':
3313 case '3':
3314 case '4':
3315 case '5':
3316 case '6':
3317 case '7':
3318 case '8':
3319 case '9':
3320 case 'A':
3321 case 'B':
3322 case 'C':
3323 case 'D':
3324 case 'E':
3325 case 'F':
3326 {
3327 s = bc_lex_number(l, c);
3328 break;
3329 }
3330
3331 case ';':
3332 {
3333 l->t.t = BC_LEX_SCOLON;
3334 break;
3335 }
3336
3337 case '<':
3338 {
3339 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3340 break;
3341 }
3342
3343 case '=':
3344 {
3345 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3346 break;
3347 }
3348
3349 case '>':
3350 {
3351 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3352 break;
3353 }
3354
3355 case '[':
3356 case ']':
3357 {
3358 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3359 break;
3360 }
3361
3362 case '\\':
3363 {
3364 if (l->buf[l->i] == '\n') {
3365 l->t.t = BC_LEX_WHITESPACE;
3366 ++l->i;
3367 }
3368 else
3369 s = BC_STATUS_LEX_BAD_CHAR;
3370 break;
3371 }
3372
3373 case '^':
3374 {
3375 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3376 break;
3377 }
3378
3379 case 'a':
3380 case 'b':
3381 case 'c':
3382 case 'd':
3383 case 'e':
3384 case 'f':
3385 case 'g':
3386 case 'h':
3387 case 'i':
3388 case 'j':
3389 case 'k':
3390 case 'l':
3391 case 'm':
3392 case 'n':
3393 case 'o':
3394 case 'p':
3395 case 'q':
3396 case 'r':
3397 case 's':
3398 case 't':
3399 case 'u':
3400 case 'v':
3401 case 'w':
3402 case 'x':
3403 case 'y':
3404 case 'z':
3405 {
3406 s = bc_lex_identifier(l);
3407 break;
3408 }
3409
3410 case '{':
3411 case '}':
3412 {
3413 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3414 break;
3415 }
3416
3417 case '|':
3418 {
3419 c2 = l->buf[l->i];
3420
3421 if (c2 == '|') {
3422
3423 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3424 if (s) return s;
3425
3426 ++l->i;
3427 l->t.t = BC_LEX_OP_BOOL_OR;
3428 }
3429 else {
3430 l->t.t = BC_LEX_INVALID;
3431 s = BC_STATUS_LEX_BAD_CHAR;
3432 }
3433
3434 break;
3435 }
3436
3437 default:
3438 {
3439 l->t.t = BC_LEX_INVALID;
3440 s = BC_STATUS_LEX_BAD_CHAR;
3441 break;
3442 }
3443 }
3444
3445 return s;
3446}
3447#endif // ENABLE_BC
3448
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003449#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003450static BcStatus dc_lex_register(BcLex *l)
3451{
3452 BcStatus s = BC_STATUS_SUCCESS;
3453
3454 if (isspace(l->buf[l->i - 1])) {
3455 bc_lex_whitespace(l);
3456 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003457 if (!G_exreg)
Gavin Howard01055ba2018-11-03 11:00:21 -06003458 s = BC_STATUS_LEX_EXTENDED_REG;
3459 else
3460 s = bc_lex_name(l);
3461 }
3462 else {
3463 bc_vec_npop(&l->t.v, l->t.v.len);
3464 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3465 bc_vec_pushByte(&l->t.v, '\0');
3466 l->t.t = BC_LEX_NAME;
3467 }
3468
3469 return s;
3470}
3471
3472static BcStatus dc_lex_string(BcLex *l)
3473{
3474 size_t depth = 1, nls = 0, i = l->i;
3475 char c;
3476
3477 l->t.t = BC_LEX_STR;
3478 bc_vec_npop(&l->t.v, l->t.v.len);
3479
3480 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3481
3482 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3483 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3484 nls += (c == '\n');
3485
3486 if (depth) bc_vec_push(&l->t.v, &c);
3487 }
3488
3489 if (c == '\0') {
3490 l->i = i;
3491 return BC_STATUS_LEX_NO_STRING_END;
3492 }
3493
3494 bc_vec_pushByte(&l->t.v, '\0');
3495 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3496
3497 l->i = i;
3498 l->line += nls;
3499
3500 return BC_STATUS_SUCCESS;
3501}
3502
3503static BcStatus dc_lex_token(BcLex *l)
3504{
3505 BcStatus s = BC_STATUS_SUCCESS;
3506 char c = l->buf[l->i++], c2;
3507 size_t i;
3508
3509 for (i = 0; i < dc_lex_regs_len; ++i) {
3510 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3511 }
3512
3513 if (c >= '%' && c <= '~' &&
3514 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3515 {
3516 return s;
3517 }
3518
3519 // This is the workhorse of the lexer.
3520 switch (c) {
3521
3522 case '\0':
3523 {
3524 l->t.t = BC_LEX_EOF;
3525 break;
3526 }
3527
3528 case '\n':
3529 case '\t':
3530 case '\v':
3531 case '\f':
3532 case '\r':
3533 case ' ':
3534 {
3535 l->newline = (c == '\n');
3536 bc_lex_whitespace(l);
3537 break;
3538 }
3539
3540 case '!':
3541 {
3542 c2 = l->buf[l->i];
3543
3544 if (c2 == '=')
3545 l->t.t = BC_LEX_OP_REL_NE;
3546 else if (c2 == '<')
3547 l->t.t = BC_LEX_OP_REL_LE;
3548 else if (c2 == '>')
3549 l->t.t = BC_LEX_OP_REL_GE;
3550 else
3551 return BC_STATUS_LEX_BAD_CHAR;
3552
3553 ++l->i;
3554 break;
3555 }
3556
3557 case '#':
3558 {
3559 bc_lex_lineComment(l);
3560 break;
3561 }
3562
3563 case '.':
3564 {
3565 if (isdigit(l->buf[l->i]))
3566 s = bc_lex_number(l, c);
3567 else
3568 s = BC_STATUS_LEX_BAD_CHAR;
3569 break;
3570 }
3571
3572 case '0':
3573 case '1':
3574 case '2':
3575 case '3':
3576 case '4':
3577 case '5':
3578 case '6':
3579 case '7':
3580 case '8':
3581 case '9':
3582 case 'A':
3583 case 'B':
3584 case 'C':
3585 case 'D':
3586 case 'E':
3587 case 'F':
3588 {
3589 s = bc_lex_number(l, c);
3590 break;
3591 }
3592
3593 case '[':
3594 {
3595 s = dc_lex_string(l);
3596 break;
3597 }
3598
3599 default:
3600 {
3601 l->t.t = BC_LEX_INVALID;
3602 s = BC_STATUS_LEX_BAD_CHAR;
3603 break;
3604 }
3605 }
3606
3607 return s;
3608}
3609#endif // ENABLE_DC
3610
3611static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3612{
3613 bc_program_addFunc(p->prog, name, idx);
3614 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3615}
3616
3617static void bc_parse_pushName(BcParse *p, char *name)
3618{
3619 size_t i = 0, len = strlen(name);
3620
3621 for (; i < len; ++i) bc_parse_push(p, name[i]);
3622 bc_parse_push(p, BC_PARSE_STREND);
3623
3624 free(name);
3625}
3626
3627static void bc_parse_pushIndex(BcParse *p, size_t idx)
3628{
3629 unsigned char amt, i, nums[sizeof(size_t)];
3630
3631 for (amt = 0; idx; ++amt) {
3632 nums[amt] = (char) idx;
3633 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3634 }
3635
3636 bc_parse_push(p, amt);
3637 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3638}
3639
3640static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3641{
3642 char *num = xstrdup(p->l.t.v.v);
3643 size_t idx = p->prog->consts.len;
3644
3645 bc_vec_push(&p->prog->consts, &num);
3646
3647 bc_parse_push(p, BC_INST_NUM);
3648 bc_parse_pushIndex(p, idx);
3649
3650 ++(*nexs);
3651 (*prev) = BC_INST_NUM;
3652}
3653
3654static BcStatus bc_parse_text(BcParse *p, const char *text)
3655{
3656 BcStatus s;
3657
3658 p->func = bc_vec_item(&p->prog->fns, p->fidx);
3659
3660 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3661 p->l.t.t = BC_LEX_INVALID;
3662 s = p->parse(p);
3663 if (s) return s;
3664 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3665 }
3666
3667 return bc_lex_text(&p->l, text);
3668}
3669
3670static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3671{
3672 if (p->fidx != BC_PROG_MAIN) {
3673
3674 p->func->nparams = 0;
3675 bc_vec_npop(&p->func->code, p->func->code.len);
3676 bc_vec_npop(&p->func->autos, p->func->autos.len);
3677 bc_vec_npop(&p->func->labels, p->func->labels.len);
3678
3679 bc_parse_updateFunc(p, BC_PROG_MAIN);
3680 }
3681
3682 p->l.i = p->l.len;
3683 p->l.t.t = BC_LEX_EOF;
3684 p->auto_part = (p->nbraces = 0);
3685
3686 bc_vec_npop(&p->flags, p->flags.len - 1);
3687 bc_vec_npop(&p->exits, p->exits.len);
3688 bc_vec_npop(&p->conds, p->conds.len);
3689 bc_vec_npop(&p->ops, p->ops.len);
3690
3691 return bc_program_reset(p->prog, s);
3692}
3693
3694static void bc_parse_free(BcParse *p)
3695{
3696 bc_vec_free(&p->flags);
3697 bc_vec_free(&p->exits);
3698 bc_vec_free(&p->conds);
3699 bc_vec_free(&p->ops);
3700 bc_lex_free(&p->l);
3701}
3702
3703static void bc_parse_create(BcParse *p, BcProgram *prog, size_t func,
3704 BcParseParse parse, BcLexNext next)
3705{
3706 memset(p, 0, sizeof(BcParse));
3707
3708 bc_lex_init(&p->l, next);
3709 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3710 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3711 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3712 bc_vec_pushByte(&p->flags, 0);
3713 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3714
3715 p->parse = parse;
3716 p->prog = prog;
3717 p->auto_part = (p->nbraces = 0);
3718 bc_parse_updateFunc(p, func);
3719}
3720
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003721#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003722static BcStatus bc_parse_else(BcParse *p);
3723static BcStatus bc_parse_stmt(BcParse *p);
3724
3725static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3726 size_t *nexprs, bool next)
3727{
3728 BcStatus s = BC_STATUS_SUCCESS;
3729 BcLexType t;
3730 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3731 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3732
3733 while (p->ops.len > start) {
3734
3735 t = BC_PARSE_TOP_OP(p);
3736 if (t == BC_LEX_LPAREN) break;
3737
3738 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3739 if (l >= r && (l != r || !left)) break;
3740
3741 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3742 bc_vec_pop(&p->ops);
3743 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3744 }
3745
3746 bc_vec_push(&p->ops, &type);
3747 if (next) s = bc_lex_next(&p->l);
3748
3749 return s;
3750}
3751
3752static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3753{
3754 BcLexType top;
3755
3756 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3757 top = BC_PARSE_TOP_OP(p);
3758
3759 while (top != BC_LEX_LPAREN) {
3760
3761 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3762
3763 bc_vec_pop(&p->ops);
3764 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3765
3766 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3767 top = BC_PARSE_TOP_OP(p);
3768 }
3769
3770 bc_vec_pop(&p->ops);
3771
3772 return bc_lex_next(&p->l);
3773}
3774
3775static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3776{
3777 BcStatus s;
3778 bool comma = false;
3779 size_t nparams;
3780
3781 s = bc_lex_next(&p->l);
3782 if (s) return s;
3783
3784 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3785
3786 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3787 s = bc_parse_expr(p, flags, bc_parse_next_param);
3788 if (s) return s;
3789
3790 comma = p->l.t.t == BC_LEX_COMMA;
3791 if (comma) {
3792 s = bc_lex_next(&p->l);
3793 if (s) return s;
3794 }
3795 }
3796
3797 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3798 bc_parse_push(p, BC_INST_CALL);
3799 bc_parse_pushIndex(p, nparams);
3800
3801 return BC_STATUS_SUCCESS;
3802}
3803
3804static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3805{
3806 BcStatus s;
3807 BcId entry, *entry_ptr;
3808 size_t idx;
3809
3810 entry.name = name;
3811
3812 s = bc_parse_params(p, flags);
3813 if (s) goto err;
3814
3815 if (p->l.t.t != BC_LEX_RPAREN) {
3816 s = BC_STATUS_PARSE_BAD_TOKEN;
3817 goto err;
3818 }
3819
3820 idx = bc_map_index(&p->prog->fn_map, &entry);
3821
3822 if (idx == BC_VEC_INVALID_IDX) {
3823 name = xstrdup(entry.name);
3824 bc_parse_addFunc(p, name, &idx);
3825 idx = bc_map_index(&p->prog->fn_map, &entry);
3826 free(entry.name);
3827 }
3828 else
3829 free(name);
3830
3831 entry_ptr = bc_vec_item(&p->prog->fn_map, idx);
3832 bc_parse_pushIndex(p, entry_ptr->idx);
3833
3834 return bc_lex_next(&p->l);
3835
3836err:
3837 free(name);
3838 return s;
3839}
3840
3841static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3842{
3843 BcStatus s;
3844 char *name;
3845
3846 name = xstrdup(p->l.t.v.v);
3847 s = bc_lex_next(&p->l);
3848 if (s) goto err;
3849
3850 if (p->l.t.t == BC_LEX_LBRACKET) {
3851
3852 s = bc_lex_next(&p->l);
3853 if (s) goto err;
3854
3855 if (p->l.t.t == BC_LEX_RBRACKET) {
3856
3857 if (!(flags & BC_PARSE_ARRAY)) {
3858 s = BC_STATUS_PARSE_BAD_EXP;
3859 goto err;
3860 }
3861
3862 *type = BC_INST_ARRAY;
3863 }
3864 else {
3865
3866 *type = BC_INST_ARRAY_ELEM;
3867
3868 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3869 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3870 if (s) goto err;
3871 }
3872
3873 s = bc_lex_next(&p->l);
3874 if (s) goto err;
3875 bc_parse_push(p, *type);
3876 bc_parse_pushName(p, name);
3877 }
3878 else if (p->l.t.t == BC_LEX_LPAREN) {
3879
3880 if (flags & BC_PARSE_NOCALL) {
3881 s = BC_STATUS_PARSE_BAD_TOKEN;
3882 goto err;
3883 }
3884
3885 *type = BC_INST_CALL;
3886 s = bc_parse_call(p, name, flags);
3887 }
3888 else {
3889 *type = BC_INST_VAR;
3890 bc_parse_push(p, BC_INST_VAR);
3891 bc_parse_pushName(p, name);
3892 }
3893
3894 return s;
3895
3896err:
3897 free(name);
3898 return s;
3899}
3900
3901static BcStatus bc_parse_read(BcParse *p)
3902{
3903 BcStatus s;
3904
3905 s = bc_lex_next(&p->l);
3906 if (s) return s;
3907 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3908
3909 s = bc_lex_next(&p->l);
3910 if (s) return s;
3911 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3912
3913 bc_parse_push(p, BC_INST_READ);
3914
3915 return bc_lex_next(&p->l);
3916}
3917
3918static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3919 BcInst *prev)
3920{
3921 BcStatus s;
3922
3923 s = bc_lex_next(&p->l);
3924 if (s) return s;
3925 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3926
3927 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3928
3929 s = bc_lex_next(&p->l);
3930 if (s) return s;
3931
3932 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3933 if (s) return s;
3934
3935 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3936
3937 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3938 bc_parse_push(p, *prev);
3939
3940 return bc_lex_next(&p->l);
3941}
3942
3943static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3944{
3945 BcStatus s;
3946
3947 s = bc_lex_next(&p->l);
3948 if (s) return s;
3949
3950 if (p->l.t.t != BC_LEX_LPAREN) {
3951 *type = BC_INST_SCALE;
3952 bc_parse_push(p, BC_INST_SCALE);
3953 return BC_STATUS_SUCCESS;
3954 }
3955
3956 *type = BC_INST_SCALE_FUNC;
3957 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3958
3959 s = bc_lex_next(&p->l);
3960 if (s) return s;
3961
3962 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3963 if (s) return s;
3964 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3965 bc_parse_push(p, BC_INST_SCALE_FUNC);
3966
3967 return bc_lex_next(&p->l);
3968}
3969
3970static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3971 size_t *nexprs, uint8_t flags)
3972{
3973 BcStatus s;
3974 BcLexType type;
3975 char inst;
3976 BcInst etype = *prev;
3977
3978 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3979 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3980 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3981 {
3982 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3983 bc_parse_push(p, inst);
3984 s = bc_lex_next(&p->l);
3985 }
3986 else {
3987
3988 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3989 *paren_expr = true;
3990
3991 s = bc_lex_next(&p->l);
3992 if (s) return s;
3993 type = p->l.t.t;
3994
3995 // Because we parse the next part of the expression
3996 // right here, we need to increment this.
3997 *nexprs = *nexprs + 1;
3998
3999 switch (type) {
4000
4001 case BC_LEX_NAME:
4002 {
4003 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
4004 break;
4005 }
4006
4007 case BC_LEX_KEY_IBASE:
4008 case BC_LEX_KEY_LAST:
4009 case BC_LEX_KEY_OBASE:
4010 {
4011 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4012 s = bc_lex_next(&p->l);
4013 break;
4014 }
4015
4016 case BC_LEX_KEY_SCALE:
4017 {
4018 s = bc_lex_next(&p->l);
4019 if (s) return s;
4020 if (p->l.t.t == BC_LEX_LPAREN)
4021 s = BC_STATUS_PARSE_BAD_TOKEN;
4022 else
4023 bc_parse_push(p, BC_INST_SCALE);
4024 break;
4025 }
4026
4027 default:
4028 {
4029 s = BC_STATUS_PARSE_BAD_TOKEN;
4030 break;
4031 }
4032 }
4033
4034 if (!s) bc_parse_push(p, inst);
4035 }
4036
4037 return s;
4038}
4039
4040static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
4041 bool rparen, size_t *nexprs)
4042{
4043 BcStatus s;
4044 BcLexType type;
4045 BcInst etype = *prev;
4046
4047 s = bc_lex_next(&p->l);
4048 if (s) return s;
4049
4050 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4051 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4052 BC_LEX_OP_MINUS :
4053 BC_LEX_NEG;
4054 *prev = BC_PARSE_TOKEN_INST(type);
4055
4056 // We can just push onto the op stack because this is the largest
4057 // precedence operator that gets pushed. Inc/dec does not.
4058 if (type != BC_LEX_OP_MINUS)
4059 bc_vec_push(&p->ops, &type);
4060 else
4061 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4062
4063 return s;
4064}
4065
4066static BcStatus bc_parse_string(BcParse *p, char inst)
4067{
4068 char *str = xstrdup(p->l.t.v.v);
4069
4070 bc_parse_push(p, BC_INST_STR);
4071 bc_parse_pushIndex(p, p->prog->strs.len);
4072 bc_vec_push(&p->prog->strs, &str);
4073 bc_parse_push(p, inst);
4074
4075 return bc_lex_next(&p->l);
4076}
4077
4078static BcStatus bc_parse_print(BcParse *p)
4079{
4080 BcStatus s;
4081 BcLexType type;
4082 bool comma = false;
4083
4084 s = bc_lex_next(&p->l);
4085 if (s) return s;
4086
4087 type = p->l.t.t;
4088
4089 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4090 return BC_STATUS_PARSE_BAD_PRINT;
4091
4092 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4093
4094 if (type == BC_LEX_STR)
4095 s = bc_parse_string(p, BC_INST_PRINT_POP);
4096 else {
4097 s = bc_parse_expr(p, 0, bc_parse_next_print);
4098 if (s) return s;
4099 bc_parse_push(p, BC_INST_PRINT_POP);
4100 }
4101
4102 if (s) return s;
4103
4104 comma = p->l.t.t == BC_LEX_COMMA;
4105 if (comma) s = bc_lex_next(&p->l);
4106 type = p->l.t.t;
4107 }
4108
4109 if (s) return s;
4110 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4111
4112 return bc_lex_next(&p->l);
4113}
4114
4115static BcStatus bc_parse_return(BcParse *p)
4116{
4117 BcStatus s;
4118 BcLexType t;
4119 bool paren;
4120
4121 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4122
4123 s = bc_lex_next(&p->l);
4124 if (s) return s;
4125
4126 t = p->l.t.t;
4127 paren = t == BC_LEX_LPAREN;
4128
4129 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4130 bc_parse_push(p, BC_INST_RET0);
4131 else {
4132
4133 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4134 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4135 return s;
4136 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4137 bc_parse_push(p, BC_INST_RET0);
4138 s = bc_lex_next(&p->l);
4139 if (s) return s;
4140 }
4141
4142 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4143 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4144 if (s) return s;
4145 }
4146
4147 bc_parse_push(p, BC_INST_RET);
4148 }
4149
4150 return s;
4151}
4152
4153static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4154{
4155 BcStatus s = BC_STATUS_SUCCESS;
4156
4157 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4158 return BC_STATUS_PARSE_BAD_TOKEN;
4159
4160 if (brace) {
4161
4162 if (p->l.t.t == BC_LEX_RBRACE) {
4163 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4164 --p->nbraces;
4165 s = bc_lex_next(&p->l);
4166 if (s) return s;
4167 }
4168 else
4169 return BC_STATUS_PARSE_BAD_TOKEN;
4170 }
4171
4172 if (BC_PARSE_IF(p)) {
4173
4174 uint8_t *flag_ptr;
4175
4176 while (p->l.t.t == BC_LEX_NLINE) {
4177 s = bc_lex_next(&p->l);
4178 if (s) return s;
4179 }
4180
4181 bc_vec_pop(&p->flags);
4182
4183 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4184 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4185
4186 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4187 }
4188 else if (BC_PARSE_ELSE(p)) {
4189
4190 BcInstPtr *ip;
4191 size_t *label;
4192
4193 bc_vec_pop(&p->flags);
4194
4195 ip = bc_vec_top(&p->exits);
4196 label = bc_vec_item(&p->func->labels, ip->idx);
4197 *label = p->func->code.len;
4198
4199 bc_vec_pop(&p->exits);
4200 }
4201 else if (BC_PARSE_FUNC_INNER(p)) {
4202 bc_parse_push(p, BC_INST_RET0);
4203 bc_parse_updateFunc(p, BC_PROG_MAIN);
4204 bc_vec_pop(&p->flags);
4205 }
4206 else {
4207
4208 BcInstPtr *ip = bc_vec_top(&p->exits);
4209 size_t *label = bc_vec_top(&p->conds);
4210
4211 bc_parse_push(p, BC_INST_JUMP);
4212 bc_parse_pushIndex(p, *label);
4213
4214 label = bc_vec_item(&p->func->labels, ip->idx);
4215 *label = p->func->code.len;
4216
4217 bc_vec_pop(&p->flags);
4218 bc_vec_pop(&p->exits);
4219 bc_vec_pop(&p->conds);
4220 }
4221
4222 return s;
4223}
4224
4225static void bc_parse_startBody(BcParse *p, uint8_t flags)
4226{
4227 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4228 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4229 flags |= BC_PARSE_FLAG_BODY;
4230 bc_vec_push(&p->flags, &flags);
4231}
4232
4233static void bc_parse_noElse(BcParse *p)
4234{
4235 BcInstPtr *ip;
4236 size_t *label;
4237 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4238
4239 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4240
4241 ip = bc_vec_top(&p->exits);
4242 label = bc_vec_item(&p->func->labels, ip->idx);
4243 *label = p->func->code.len;
4244
4245 bc_vec_pop(&p->exits);
4246}
4247
4248static BcStatus bc_parse_if(BcParse *p)
4249{
4250 BcStatus s;
4251 BcInstPtr ip;
4252
4253 s = bc_lex_next(&p->l);
4254 if (s) return s;
4255 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4256
4257 s = bc_lex_next(&p->l);
4258 if (s) return s;
4259 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4260 if (s) return s;
4261 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4262
4263 s = bc_lex_next(&p->l);
4264 if (s) return s;
4265 bc_parse_push(p, BC_INST_JUMP_ZERO);
4266
4267 ip.idx = p->func->labels.len;
4268 ip.func = ip.len = 0;
4269
4270 bc_parse_pushIndex(p, ip.idx);
4271 bc_vec_push(&p->exits, &ip);
4272 bc_vec_push(&p->func->labels, &ip.idx);
4273 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4274
4275 return BC_STATUS_SUCCESS;
4276}
4277
4278static BcStatus bc_parse_else(BcParse *p)
4279{
4280 BcInstPtr ip;
4281
4282 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4283
4284 ip.idx = p->func->labels.len;
4285 ip.func = ip.len = 0;
4286
4287 bc_parse_push(p, BC_INST_JUMP);
4288 bc_parse_pushIndex(p, ip.idx);
4289
4290 bc_parse_noElse(p);
4291
4292 bc_vec_push(&p->exits, &ip);
4293 bc_vec_push(&p->func->labels, &ip.idx);
4294 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4295
4296 return bc_lex_next(&p->l);
4297}
4298
4299static BcStatus bc_parse_while(BcParse *p)
4300{
4301 BcStatus s;
4302 BcInstPtr ip;
4303
4304 s = bc_lex_next(&p->l);
4305 if (s) return s;
4306 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4307 s = bc_lex_next(&p->l);
4308 if (s) return s;
4309
4310 ip.idx = p->func->labels.len;
4311
4312 bc_vec_push(&p->func->labels, &p->func->code.len);
4313 bc_vec_push(&p->conds, &ip.idx);
4314
4315 ip.idx = p->func->labels.len;
4316 ip.func = 1;
4317 ip.len = 0;
4318
4319 bc_vec_push(&p->exits, &ip);
4320 bc_vec_push(&p->func->labels, &ip.idx);
4321
4322 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4323 if (s) return s;
4324 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4325 s = bc_lex_next(&p->l);
4326 if (s) return s;
4327
4328 bc_parse_push(p, BC_INST_JUMP_ZERO);
4329 bc_parse_pushIndex(p, ip.idx);
4330 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4331
4332 return BC_STATUS_SUCCESS;
4333}
4334
4335static BcStatus bc_parse_for(BcParse *p)
4336{
4337 BcStatus s;
4338 BcInstPtr ip;
4339 size_t cond_idx, exit_idx, body_idx, update_idx;
4340
4341 s = bc_lex_next(&p->l);
4342 if (s) return s;
4343 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4344 s = bc_lex_next(&p->l);
4345 if (s) return s;
4346
4347 if (p->l.t.t != BC_LEX_SCOLON)
4348 s = bc_parse_expr(p, 0, bc_parse_next_for);
4349 else
4350 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4351
4352 if (s) return s;
4353 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4354 s = bc_lex_next(&p->l);
4355 if (s) return s;
4356
4357 cond_idx = p->func->labels.len;
4358 update_idx = cond_idx + 1;
4359 body_idx = update_idx + 1;
4360 exit_idx = body_idx + 1;
4361
4362 bc_vec_push(&p->func->labels, &p->func->code.len);
4363
4364 if (p->l.t.t != BC_LEX_SCOLON)
4365 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4366 else
4367 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4368
4369 if (s) return s;
4370 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4371
4372 s = bc_lex_next(&p->l);
4373 if (s) return s;
4374
4375 bc_parse_push(p, BC_INST_JUMP_ZERO);
4376 bc_parse_pushIndex(p, exit_idx);
4377 bc_parse_push(p, BC_INST_JUMP);
4378 bc_parse_pushIndex(p, body_idx);
4379
4380 ip.idx = p->func->labels.len;
4381
4382 bc_vec_push(&p->conds, &update_idx);
4383 bc_vec_push(&p->func->labels, &p->func->code.len);
4384
4385 if (p->l.t.t != BC_LEX_RPAREN)
4386 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4387 else
4388 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4389
4390 if (s) return s;
4391
4392 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4393 bc_parse_push(p, BC_INST_JUMP);
4394 bc_parse_pushIndex(p, cond_idx);
4395 bc_vec_push(&p->func->labels, &p->func->code.len);
4396
4397 ip.idx = exit_idx;
4398 ip.func = 1;
4399 ip.len = 0;
4400
4401 bc_vec_push(&p->exits, &ip);
4402 bc_vec_push(&p->func->labels, &ip.idx);
4403 bc_lex_next(&p->l);
4404 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4405
4406 return BC_STATUS_SUCCESS;
4407}
4408
4409static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4410{
4411 BcStatus s;
4412 size_t i;
4413 BcInstPtr *ip;
4414
4415 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4416
4417 if (type == BC_LEX_KEY_BREAK) {
4418
4419 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4420
4421 i = p->exits.len - 1;
4422 ip = bc_vec_item(&p->exits, i);
4423
4424 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4425 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4426
4427 i = ip->idx;
4428 }
4429 else
4430 i = *((size_t *) bc_vec_top(&p->conds));
4431
4432 bc_parse_push(p, BC_INST_JUMP);
4433 bc_parse_pushIndex(p, i);
4434
4435 s = bc_lex_next(&p->l);
4436 if (s) return s;
4437
4438 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4439 return BC_STATUS_PARSE_BAD_TOKEN;
4440
4441 return bc_lex_next(&p->l);
4442}
4443
4444static BcStatus bc_parse_func(BcParse *p)
4445{
4446 BcStatus s;
4447 bool var, comma = false;
4448 uint8_t flags;
4449 char *name;
4450
4451 s = bc_lex_next(&p->l);
4452 if (s) return s;
4453 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4454
4455 name = xstrdup(p->l.t.v.v);
4456 bc_parse_addFunc(p, name, &p->fidx);
4457
4458 s = bc_lex_next(&p->l);
4459 if (s) return s;
4460 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4461 s = bc_lex_next(&p->l);
4462 if (s) return s;
4463
4464 while (p->l.t.t != BC_LEX_RPAREN) {
4465
4466 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4467
4468 ++p->func->nparams;
4469
4470 name = xstrdup(p->l.t.v.v);
4471 s = bc_lex_next(&p->l);
4472 if (s) goto err;
4473
4474 var = p->l.t.t != BC_LEX_LBRACKET;
4475
4476 if (!var) {
4477
4478 s = bc_lex_next(&p->l);
4479 if (s) goto err;
4480
4481 if (p->l.t.t != BC_LEX_RBRACKET) {
4482 s = BC_STATUS_PARSE_BAD_FUNC;
4483 goto err;
4484 }
4485
4486 s = bc_lex_next(&p->l);
4487 if (s) goto err;
4488 }
4489
4490 comma = p->l.t.t == BC_LEX_COMMA;
4491 if (comma) {
4492 s = bc_lex_next(&p->l);
4493 if (s) goto err;
4494 }
4495
4496 s = bc_func_insert(p->func, name, var);
4497 if (s) goto err;
4498 }
4499
4500 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4501
4502 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4503 bc_parse_startBody(p, flags);
4504
4505 s = bc_lex_next(&p->l);
4506 if (s) return s;
4507
4508 if (p->l.t.t != BC_LEX_LBRACE)
4509 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4510
4511 return s;
4512
4513err:
4514 free(name);
4515 return s;
4516}
4517
4518static BcStatus bc_parse_auto(BcParse *p)
4519{
4520 BcStatus s;
4521 bool comma, var, one;
4522 char *name;
4523
4524 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4525 s = bc_lex_next(&p->l);
4526 if (s) return s;
4527
4528 p->auto_part = comma = false;
4529 one = p->l.t.t == BC_LEX_NAME;
4530
4531 while (p->l.t.t == BC_LEX_NAME) {
4532
4533 name = xstrdup(p->l.t.v.v);
4534 s = bc_lex_next(&p->l);
4535 if (s) goto err;
4536
4537 var = p->l.t.t != BC_LEX_LBRACKET;
4538 if (!var) {
4539
4540 s = bc_lex_next(&p->l);
4541 if (s) goto err;
4542
4543 if (p->l.t.t != BC_LEX_RBRACKET) {
4544 s = BC_STATUS_PARSE_BAD_FUNC;
4545 goto err;
4546 }
4547
4548 s = bc_lex_next(&p->l);
4549 if (s) goto err;
4550 }
4551
4552 comma = p->l.t.t == BC_LEX_COMMA;
4553 if (comma) {
4554 s = bc_lex_next(&p->l);
4555 if (s) goto err;
4556 }
4557
4558 s = bc_func_insert(p->func, name, var);
4559 if (s) goto err;
4560 }
4561
4562 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4563 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4564
4565 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4566 return BC_STATUS_PARSE_BAD_TOKEN;
4567
4568 return bc_lex_next(&p->l);
4569
4570err:
4571 free(name);
4572 return s;
4573}
4574
4575static BcStatus bc_parse_body(BcParse *p, bool brace)
4576{
4577 BcStatus s = BC_STATUS_SUCCESS;
4578 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4579
4580 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4581
4582 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4583
4584 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4585 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4586
4587 if (!p->auto_part) {
4588 s = bc_parse_auto(p);
4589 if (s) return s;
4590 }
4591
4592 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4593 }
4594 else {
4595 s = bc_parse_stmt(p);
4596 if (!s && !brace) s = bc_parse_endBody(p, false);
4597 }
4598
4599 return s;
4600}
4601
4602static BcStatus bc_parse_stmt(BcParse *p)
4603{
4604 BcStatus s = BC_STATUS_SUCCESS;
4605
4606 switch (p->l.t.t) {
4607
4608 case BC_LEX_NLINE:
4609 {
4610 return bc_lex_next(&p->l);
4611 }
4612
4613 case BC_LEX_KEY_ELSE:
4614 {
4615 p->auto_part = false;
4616 break;
4617 }
4618
4619 case BC_LEX_LBRACE:
4620 {
4621 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4622
4623 ++p->nbraces;
4624 s = bc_lex_next(&p->l);
4625 if (s) return s;
4626
4627 return bc_parse_body(p, true);
4628 }
4629
4630 case BC_LEX_KEY_AUTO:
4631 {
4632 return bc_parse_auto(p);
4633 }
4634
4635 default:
4636 {
4637 p->auto_part = false;
4638
4639 if (BC_PARSE_IF_END(p)) {
4640 bc_parse_noElse(p);
4641 return BC_STATUS_SUCCESS;
4642 }
4643 else if (BC_PARSE_BODY(p))
4644 return bc_parse_body(p, false);
4645
4646 break;
4647 }
4648 }
4649
4650 switch (p->l.t.t) {
4651
4652 case BC_LEX_OP_INC:
4653 case BC_LEX_OP_DEC:
4654 case BC_LEX_OP_MINUS:
4655 case BC_LEX_OP_BOOL_NOT:
4656 case BC_LEX_LPAREN:
4657 case BC_LEX_NAME:
4658 case BC_LEX_NUMBER:
4659 case BC_LEX_KEY_IBASE:
4660 case BC_LEX_KEY_LAST:
4661 case BC_LEX_KEY_LENGTH:
4662 case BC_LEX_KEY_OBASE:
4663 case BC_LEX_KEY_READ:
4664 case BC_LEX_KEY_SCALE:
4665 case BC_LEX_KEY_SQRT:
4666 {
4667 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4668 break;
4669 }
4670
4671 case BC_LEX_KEY_ELSE:
4672 {
4673 s = bc_parse_else(p);
4674 break;
4675 }
4676
4677 case BC_LEX_SCOLON:
4678 {
4679 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4680 break;
4681 }
4682
4683 case BC_LEX_RBRACE:
4684 {
4685 s = bc_parse_endBody(p, true);
4686 break;
4687 }
4688
4689 case BC_LEX_STR:
4690 {
4691 s = bc_parse_string(p, BC_INST_PRINT_STR);
4692 break;
4693 }
4694
4695 case BC_LEX_KEY_BREAK:
4696 case BC_LEX_KEY_CONTINUE:
4697 {
4698 s = bc_parse_loopExit(p, p->l.t.t);
4699 break;
4700 }
4701
4702 case BC_LEX_KEY_FOR:
4703 {
4704 s = bc_parse_for(p);
4705 break;
4706 }
4707
4708 case BC_LEX_KEY_HALT:
4709 {
4710 bc_parse_push(p, BC_INST_HALT);
4711 s = bc_lex_next(&p->l);
4712 break;
4713 }
4714
4715 case BC_LEX_KEY_IF:
4716 {
4717 s = bc_parse_if(p);
4718 break;
4719 }
4720
4721 case BC_LEX_KEY_LIMITS:
4722 {
4723 s = bc_lex_next(&p->l);
4724 if (s) return s;
4725 s = BC_STATUS_LIMITS;
4726 break;
4727 }
4728
4729 case BC_LEX_KEY_PRINT:
4730 {
4731 s = bc_parse_print(p);
4732 break;
4733 }
4734
4735 case BC_LEX_KEY_QUIT:
4736 {
4737 // Quit is a compile-time command. We don't exit directly,
4738 // so the vm can clean up. Limits do the same thing.
4739 s = BC_STATUS_QUIT;
4740 break;
4741 }
4742
4743 case BC_LEX_KEY_RETURN:
4744 {
4745 s = bc_parse_return(p);
4746 break;
4747 }
4748
4749 case BC_LEX_KEY_WHILE:
4750 {
4751 s = bc_parse_while(p);
4752 break;
4753 }
4754
4755 default:
4756 {
4757 s = BC_STATUS_PARSE_BAD_TOKEN;
4758 break;
4759 }
4760 }
4761
4762 return s;
4763}
4764
4765static BcStatus bc_parse_parse(BcParse *p)
4766{
4767 BcStatus s;
4768
4769 if (p->l.t.t == BC_LEX_EOF)
4770 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4771 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4772 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4773 s = bc_parse_func(p);
4774 }
4775 else
4776 s = bc_parse_stmt(p);
4777
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01004778 if ((s && s != BC_STATUS_QUIT && s != BC_STATUS_LIMITS) || G.signe)
Gavin Howard01055ba2018-11-03 11:00:21 -06004779 s = bc_parse_reset(p, s);
4780
4781 return s;
4782}
4783
4784static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4785{
4786 BcStatus s = BC_STATUS_SUCCESS;
4787 BcInst prev = BC_INST_PRINT;
4788 BcLexType top, t = p->l.t.t;
4789 size_t nexprs = 0, ops_bgn = p->ops.len;
4790 uint32_t i, nparens, nrelops;
4791 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4792
4793 paren_first = p->l.t.t == BC_LEX_LPAREN;
4794 nparens = nrelops = 0;
4795 paren_expr = rprn = done = get_token = assign = false;
4796 bin_last = true;
4797
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01004798 for (; !G.signe && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004799 switch (t) {
4800
4801 case BC_LEX_OP_INC:
4802 case BC_LEX_OP_DEC:
4803 {
4804 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4805 rprn = get_token = bin_last = false;
4806 break;
4807 }
4808
4809 case BC_LEX_OP_MINUS:
4810 {
4811 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4812 rprn = get_token = false;
4813 bin_last = prev == BC_INST_MINUS;
4814 break;
4815 }
4816
4817 case BC_LEX_OP_ASSIGN_POWER:
4818 case BC_LEX_OP_ASSIGN_MULTIPLY:
4819 case BC_LEX_OP_ASSIGN_DIVIDE:
4820 case BC_LEX_OP_ASSIGN_MODULUS:
4821 case BC_LEX_OP_ASSIGN_PLUS:
4822 case BC_LEX_OP_ASSIGN_MINUS:
4823 case BC_LEX_OP_ASSIGN:
4824 {
4825 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4826 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4827 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4828 {
4829 s = BC_STATUS_PARSE_BAD_ASSIGN;
4830 break;
4831 }
4832 }
4833 // Fallthrough.
4834 case BC_LEX_OP_POWER:
4835 case BC_LEX_OP_MULTIPLY:
4836 case BC_LEX_OP_DIVIDE:
4837 case BC_LEX_OP_MODULUS:
4838 case BC_LEX_OP_PLUS:
4839 case BC_LEX_OP_REL_EQ:
4840 case BC_LEX_OP_REL_LE:
4841 case BC_LEX_OP_REL_GE:
4842 case BC_LEX_OP_REL_NE:
4843 case BC_LEX_OP_REL_LT:
4844 case BC_LEX_OP_REL_GT:
4845 case BC_LEX_OP_BOOL_NOT:
4846 case BC_LEX_OP_BOOL_OR:
4847 case BC_LEX_OP_BOOL_AND:
4848 {
4849 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4850 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4851 {
4852 return BC_STATUS_PARSE_BAD_EXP;
4853 }
4854
4855 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4856 prev = BC_PARSE_TOKEN_INST(t);
4857 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4858 rprn = get_token = false;
4859 bin_last = t != BC_LEX_OP_BOOL_NOT;
4860
4861 break;
4862 }
4863
4864 case BC_LEX_LPAREN:
4865 {
4866 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4867
4868 ++nparens;
4869 paren_expr = rprn = bin_last = false;
4870 get_token = true;
4871 bc_vec_push(&p->ops, &t);
4872
4873 break;
4874 }
4875
4876 case BC_LEX_RPAREN:
4877 {
4878 if (bin_last || prev == BC_INST_BOOL_NOT)
4879 return BC_STATUS_PARSE_BAD_EXP;
4880
4881 if (nparens == 0) {
4882 s = BC_STATUS_SUCCESS;
4883 done = true;
4884 get_token = false;
4885 break;
4886 }
4887 else if (!paren_expr)
4888 return BC_STATUS_PARSE_EMPTY_EXP;
4889
4890 --nparens;
4891 paren_expr = rprn = true;
4892 get_token = bin_last = false;
4893
4894 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4895
4896 break;
4897 }
4898
4899 case BC_LEX_NAME:
4900 {
4901 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4902
4903 paren_expr = true;
4904 rprn = get_token = bin_last = false;
4905 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4906 ++nexprs;
4907
4908 break;
4909 }
4910
4911 case BC_LEX_NUMBER:
4912 {
4913 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4914
4915 bc_parse_number(p, &prev, &nexprs);
4916 paren_expr = get_token = true;
4917 rprn = bin_last = false;
4918
4919 break;
4920 }
4921
4922 case BC_LEX_KEY_IBASE:
4923 case BC_LEX_KEY_LAST:
4924 case BC_LEX_KEY_OBASE:
4925 {
4926 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4927
4928 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4929 bc_parse_push(p, (char) prev);
4930
4931 paren_expr = get_token = true;
4932 rprn = bin_last = false;
4933 ++nexprs;
4934
4935 break;
4936 }
4937
4938 case BC_LEX_KEY_LENGTH:
4939 case BC_LEX_KEY_SQRT:
4940 {
4941 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4942
4943 s = bc_parse_builtin(p, t, flags, &prev);
4944 paren_expr = true;
4945 rprn = get_token = bin_last = false;
4946 ++nexprs;
4947
4948 break;
4949 }
4950
4951 case BC_LEX_KEY_READ:
4952 {
4953 if (BC_PARSE_LEAF(prev, rprn))
4954 return BC_STATUS_PARSE_BAD_EXP;
4955 else if (flags & BC_PARSE_NOREAD)
4956 s = BC_STATUS_EXEC_REC_READ;
4957 else
4958 s = bc_parse_read(p);
4959
4960 paren_expr = true;
4961 rprn = get_token = bin_last = false;
4962 ++nexprs;
4963 prev = BC_INST_READ;
4964
4965 break;
4966 }
4967
4968 case BC_LEX_KEY_SCALE:
4969 {
4970 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4971
4972 s = bc_parse_scale(p, &prev, flags);
4973 paren_expr = true;
4974 rprn = get_token = bin_last = false;
4975 ++nexprs;
4976 prev = BC_INST_SCALE;
4977
4978 break;
4979 }
4980
4981 default:
4982 {
4983 s = BC_STATUS_PARSE_BAD_TOKEN;
4984 break;
4985 }
4986 }
4987
4988 if (!s && get_token) s = bc_lex_next(&p->l);
4989 }
4990
4991 if (s) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01004992 if (G.signe) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06004993
4994 while (p->ops.len > ops_bgn) {
4995
4996 top = BC_PARSE_TOP_OP(p);
4997 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4998
4999 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
5000 return BC_STATUS_PARSE_BAD_EXP;
5001
5002 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
5003
5004 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
5005 bc_vec_pop(&p->ops);
5006 }
5007
5008 s = BC_STATUS_PARSE_BAD_EXP;
5009 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
5010
5011 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
5012 if (s) return s;
5013
5014 if (!(flags & BC_PARSE_REL) && nrelops) {
5015 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
5016 if (s) return s;
5017 }
5018 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
5019 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
5020 if (s) return s;
5021 }
5022
5023 if (flags & BC_PARSE_PRINT) {
5024 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
5025 bc_parse_push(p, BC_INST_POP);
5026 }
5027
5028 return s;
5029}
5030
5031static void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5032{
5033 bc_parse_create(p, prog, func, bc_parse_parse, bc_lex_token);
5034}
5035
5036static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
5037{
5038 return bc_parse_expr(p, flags, bc_parse_next_read);
5039}
5040#endif // ENABLE_BC
5041
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005042#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005043static BcStatus dc_parse_register(BcParse *p)
5044{
5045 BcStatus s;
5046 char *name;
5047
5048 s = bc_lex_next(&p->l);
5049 if (s) return s;
5050 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5051
5052 name = xstrdup(p->l.t.v.v);
5053 bc_parse_pushName(p, name);
5054
5055 return s;
5056}
5057
5058static BcStatus dc_parse_string(BcParse *p)
5059{
5060 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5061 size_t idx, len = p->prog->strs.len;
5062
5063 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5064 name = xstrdup(b);
5065
5066 str = xstrdup(p->l.t.v.v);
5067 bc_parse_push(p, BC_INST_STR);
5068 bc_parse_pushIndex(p, len);
5069 bc_vec_push(&p->prog->strs, &str);
5070 bc_parse_addFunc(p, name, &idx);
5071
5072 return bc_lex_next(&p->l);
5073}
5074
5075static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5076{
5077 BcStatus s;
5078
5079 bc_parse_push(p, inst);
5080 if (name) {
5081 s = dc_parse_register(p);
5082 if (s) return s;
5083 }
5084
5085 if (store) {
5086 bc_parse_push(p, BC_INST_SWAP);
5087 bc_parse_push(p, BC_INST_ASSIGN);
5088 bc_parse_push(p, BC_INST_POP);
5089 }
5090
5091 return bc_lex_next(&p->l);
5092}
5093
5094static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5095{
5096 BcStatus s;
5097
5098 bc_parse_push(p, inst);
5099 bc_parse_push(p, BC_INST_EXEC_COND);
5100
5101 s = dc_parse_register(p);
5102 if (s) return s;
5103
5104 s = bc_lex_next(&p->l);
5105 if (s) return s;
5106
5107 if (p->l.t.t == BC_LEX_ELSE) {
5108 s = dc_parse_register(p);
5109 if (s) return s;
5110 s = bc_lex_next(&p->l);
5111 }
5112 else
5113 bc_parse_push(p, BC_PARSE_STREND);
5114
5115 return s;
5116}
5117
5118static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5119{
5120 BcStatus s = BC_STATUS_SUCCESS;
5121 BcInst prev;
5122 uint8_t inst;
5123 bool assign, get_token = false;
5124
5125 switch (t) {
5126
5127 case BC_LEX_OP_REL_EQ:
5128 case BC_LEX_OP_REL_LE:
5129 case BC_LEX_OP_REL_GE:
5130 case BC_LEX_OP_REL_NE:
5131 case BC_LEX_OP_REL_LT:
5132 case BC_LEX_OP_REL_GT:
5133 {
5134 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5135 break;
5136 }
5137
5138 case BC_LEX_SCOLON:
5139 case BC_LEX_COLON:
5140 {
5141 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5142 break;
5143 }
5144
5145 case BC_LEX_STR:
5146 {
5147 s = dc_parse_string(p);
5148 break;
5149 }
5150
5151 case BC_LEX_NEG:
5152 case BC_LEX_NUMBER:
5153 {
5154 if (t == BC_LEX_NEG) {
5155 s = bc_lex_next(&p->l);
5156 if (s) return s;
5157 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5158 }
5159
5160 bc_parse_number(p, &prev, &p->nbraces);
5161
5162 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5163 get_token = true;
5164
5165 break;
5166 }
5167
5168 case BC_LEX_KEY_READ:
5169 {
5170 if (flags & BC_PARSE_NOREAD)
5171 s = BC_STATUS_EXEC_REC_READ;
5172 else
5173 bc_parse_push(p, BC_INST_READ);
5174 get_token = true;
5175 break;
5176 }
5177
5178 case BC_LEX_OP_ASSIGN:
5179 case BC_LEX_STORE_PUSH:
5180 {
5181 assign = t == BC_LEX_OP_ASSIGN;
5182 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5183 s = dc_parse_mem(p, inst, true, assign);
5184 break;
5185 }
5186
5187 case BC_LEX_LOAD:
5188 case BC_LEX_LOAD_POP:
5189 {
5190 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5191 s = dc_parse_mem(p, inst, true, false);
5192 break;
5193 }
5194
5195 case BC_LEX_STORE_IBASE:
5196 case BC_LEX_STORE_SCALE:
5197 case BC_LEX_STORE_OBASE:
5198 {
5199 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5200 s = dc_parse_mem(p, inst, false, true);
5201 break;
5202 }
5203
5204 default:
5205 {
5206 s = BC_STATUS_PARSE_BAD_TOKEN;
5207 get_token = true;
5208 break;
5209 }
5210 }
5211
5212 if (!s && get_token) s = bc_lex_next(&p->l);
5213
5214 return s;
5215}
5216
5217static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5218{
5219 BcStatus s = BC_STATUS_SUCCESS;
5220 BcInst inst;
5221 BcLexType t;
5222
5223 if (flags & BC_PARSE_NOCALL) p->nbraces = p->prog->results.len;
5224
5225 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5226
5227 inst = dc_parse_insts[t];
5228
5229 if (inst != BC_INST_INVALID) {
5230 bc_parse_push(p, inst);
5231 s = bc_lex_next(&p->l);
5232 }
5233 else
5234 s = dc_parse_token(p, t, flags);
5235 }
5236
5237 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5238 bc_parse_push(p, BC_INST_POP_EXEC);
5239
5240 return s;
5241}
5242
5243static BcStatus dc_parse_parse(BcParse *p)
5244{
5245 BcStatus s;
5246
5247 if (p->l.t.t == BC_LEX_EOF)
5248 s = BC_STATUS_LEX_EOF;
5249 else
5250 s = dc_parse_expr(p, 0);
5251
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01005252 if (s || G.signe) s = bc_parse_reset(p, s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005253
5254 return s;
5255}
5256
5257static void dc_parse_init(BcParse *p, BcProgram *prog, size_t func)
5258{
5259 bc_parse_create(p, prog, func, dc_parse_parse, dc_lex_token);
5260}
5261#endif // ENABLE_DC
5262
5263static void bc_program_search(BcProgram *p, char *id, BcVec **ret, bool var)
5264{
5265 BcStatus s;
5266 BcId e, *ptr;
5267 BcVec *v, *map;
5268 size_t i;
5269 BcResultData data;
5270 bool new;
5271
5272 v = var ? &p->vars : &p->arrs;
5273 map = var ? &p->var_map : &p->arr_map;
5274
5275 e.name = id;
5276 e.idx = v->len;
5277 s = bc_map_insert(map, &e, &i);
5278 new = s != BC_STATUS_VEC_ITEM_EXISTS;
5279
5280 if (new) {
5281 bc_array_init(&data.v, var);
5282 bc_vec_push(v, &data.v);
5283 }
5284
5285 ptr = bc_vec_item(map, i);
5286 if (new) ptr->name = xstrdup(e.name);
5287 *ret = bc_vec_item(v, ptr->idx);
5288}
5289
5290static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num, bool hex)
5291{
5292 BcStatus s = BC_STATUS_SUCCESS;
5293
5294 switch (r->t) {
5295
5296 case BC_RESULT_STR:
5297 case BC_RESULT_TEMP:
5298 case BC_RESULT_IBASE:
5299 case BC_RESULT_SCALE:
5300 case BC_RESULT_OBASE:
5301 {
5302 *num = &r->d.n;
5303 break;
5304 }
5305
5306 case BC_RESULT_CONSTANT:
5307 {
5308 char **str = bc_vec_item(&p->consts, r->d.id.idx);
5309 size_t base_t, len = strlen(*str);
5310 BcNum *base;
5311
5312 bc_num_init(&r->d.n, len);
5313
5314 hex = hex && len == 1;
5315 base = hex ? &p->hexb : &p->ib;
5316 base_t = hex ? BC_NUM_MAX_IBASE : p->ib_t;
5317 s = bc_num_parse(&r->d.n, *str, base, base_t);
5318
5319 if (s) {
5320 bc_num_free(&r->d.n);
5321 return s;
5322 }
5323
5324 *num = &r->d.n;
5325 r->t = BC_RESULT_TEMP;
5326
5327 break;
5328 }
5329
5330 case BC_RESULT_VAR:
5331 case BC_RESULT_ARRAY:
5332 case BC_RESULT_ARRAY_ELEM:
5333 {
5334 BcVec *v;
5335
5336 bc_program_search(p, r->d.id.name, &v, r->t == BC_RESULT_VAR);
5337
5338 if (r->t == BC_RESULT_ARRAY_ELEM) {
5339 v = bc_vec_top(v);
5340 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5341 *num = bc_vec_item(v, r->d.id.idx);
5342 }
5343 else
5344 *num = bc_vec_top(v);
5345
5346 break;
5347 }
5348
5349 case BC_RESULT_LAST:
5350 {
5351 *num = &p->last;
5352 break;
5353 }
5354
5355 case BC_RESULT_ONE:
5356 {
5357 *num = &p->one;
5358 break;
5359 }
5360 }
5361
5362 return s;
5363}
5364
5365static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
5366 BcResult **r, BcNum **rn, bool assign)
5367{
5368 BcStatus s;
5369 bool hex;
5370 BcResultType lt, rt;
5371
5372 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5373
5374 *r = bc_vec_item_rev(&p->results, 0);
5375 *l = bc_vec_item_rev(&p->results, 1);
5376
5377 lt = (*l)->t;
5378 rt = (*r)->t;
5379 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5380
5381 s = bc_program_num(p, *l, ln, false);
5382 if (s) return s;
5383 s = bc_program_num(p, *r, rn, hex);
5384 if (s) return s;
5385
5386 // We run this again under these conditions in case any vector has been
5387 // reallocated out from under the BcNums or arrays we had.
5388 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5389 s = bc_program_num(p, *l, ln, false);
5390 if (s) return s;
5391 }
5392
5393 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5394 return BC_STATUS_EXEC_BAD_TYPE;
5395 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5396
Gavin Howard01055ba2018-11-03 11:00:21 -06005397 return s;
5398}
5399
5400static void bc_program_binOpRetire(BcProgram *p, BcResult *r)
5401{
5402 r->t = BC_RESULT_TEMP;
5403 bc_vec_pop(&p->results);
5404 bc_vec_pop(&p->results);
5405 bc_vec_push(&p->results, r);
5406}
5407
5408static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n)
5409{
5410 BcStatus s;
5411
5412 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5413 *r = bc_vec_top(&p->results);
5414
5415 s = bc_program_num(p, *r, n, false);
5416 if (s) return s;
5417
Gavin Howard01055ba2018-11-03 11:00:21 -06005418 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5419
5420 return s;
5421}
5422
5423static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t)
5424{
5425 r->t = t;
5426 bc_vec_pop(&p->results);
5427 bc_vec_push(&p->results, r);
5428}
5429
5430static BcStatus bc_program_op(BcProgram *p, char inst)
5431{
5432 BcStatus s;
5433 BcResult *opd1, *opd2, res;
5434 BcNum *n1, *n2 = NULL;
5435
5436 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5437 if (s) return s;
5438 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5439
5440 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, p->scale);
5441 if (s) goto err;
5442 bc_program_binOpRetire(p, &res);
5443
5444 return s;
5445
5446err:
5447 bc_num_free(&res.d.n);
5448 return s;
5449}
5450
5451static BcStatus bc_program_read(BcProgram *p)
5452{
5453 BcStatus s;
5454 BcParse parse;
5455 BcVec buf;
5456 BcInstPtr ip;
5457 size_t i;
5458 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
5459
5460 for (i = 0; i < p->stack.len; ++i) {
5461 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
5462 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5463 }
5464
5465 bc_vec_npop(&f->code, f->code.len);
5466 bc_vec_init(&buf, sizeof(char), NULL);
5467
5468 s = bc_read_line(&buf, "read> ");
5469 if (s) goto io_err;
5470
5471 p->parse_init(&parse, p, BC_PROG_READ);
5472 bc_lex_file(&parse.l, bc_program_stdin_name);
5473
5474 s = bc_parse_text(&parse, buf.v);
5475 if (s) goto exec_err;
5476 s = p->parse_expr(&parse, BC_PARSE_NOREAD);
5477 if (s) goto exec_err;
5478
5479 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5480 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5481 goto exec_err;
5482 }
5483
5484 ip.func = BC_PROG_READ;
5485 ip.idx = 0;
5486 ip.len = p->results.len;
5487
5488 // Update this pointer, just in case.
5489 f = bc_vec_item(&p->fns, BC_PROG_READ);
5490
5491 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5492 bc_vec_push(&p->stack, &ip);
5493
5494exec_err:
5495 bc_parse_free(&parse);
5496io_err:
5497 bc_vec_free(&buf);
5498 return s;
5499}
5500
5501static size_t bc_program_index(char *code, size_t *bgn)
5502{
5503 char amt = code[(*bgn)++], i = 0;
5504 size_t res = 0;
5505
5506 for (; i < amt; ++i, ++(*bgn))
5507 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5508
5509 return res;
5510}
5511
5512static char *bc_program_name(char *code, size_t *bgn)
5513{
5514 size_t i;
5515 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5516
5517 s = xmalloc(ptr - str + 1);
5518 c = code[(*bgn)++];
5519
5520 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5521 s[i] = c;
5522
5523 s[i] = '\0';
5524
5525 return s;
5526}
5527
5528static void bc_program_printString(const char *str, size_t *nchars)
5529{
5530 size_t i, len = strlen(str);
5531
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005532#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005533 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005534 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005535 return;
5536 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005537#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005538
5539 for (i = 0; i < len; ++i, ++(*nchars)) {
5540
5541 int c = str[i];
5542
5543 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005544 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005545 else {
5546
5547 c = str[++i];
5548
5549 switch (c) {
5550
5551 case 'a':
5552 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005553 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005554 break;
5555 }
5556
5557 case 'b':
5558 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005559 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005560 break;
5561 }
5562
5563 case '\\':
5564 case 'e':
5565 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005566 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005567 break;
5568 }
5569
5570 case 'f':
5571 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005572 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005573 break;
5574 }
5575
5576 case 'n':
5577 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005578 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005579 *nchars = SIZE_MAX;
5580 break;
5581 }
5582
5583 case 'r':
5584 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005585 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005586 break;
5587 }
5588
5589 case 'q':
5590 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005591 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005592 break;
5593 }
5594
5595 case 't':
5596 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005597 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005598 break;
5599 }
5600
5601 default:
5602 {
5603 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005604 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005605 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005606 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005607 break;
5608 }
5609 }
5610 }
5611 }
5612}
5613
5614static BcStatus bc_program_print(BcProgram *p, char inst, size_t idx)
5615{
5616 BcStatus s = BC_STATUS_SUCCESS;
5617 BcResult *r;
5618 size_t len, i;
5619 char *str;
5620 BcNum *num = NULL;
5621 bool pop = inst != BC_INST_PRINT;
5622
5623 if (!BC_PROG_STACK(&p->results, idx + 1)) return BC_STATUS_EXEC_STACK;
5624
5625 r = bc_vec_item_rev(&p->results, idx);
5626 s = bc_program_num(p, r, &num, false);
5627 if (s) return s;
5628
5629 if (BC_PROG_NUM(r, num)) {
5630 s = bc_num_print(num, &p->ob, p->ob_t, !pop, &p->nchars, p->len);
5631 if (!s) bc_num_copy(&p->last, num);
5632 }
5633 else {
5634
5635 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5636 str = *((char **) bc_vec_item(&p->strs, idx));
5637
5638 if (inst == BC_INST_PRINT_STR) {
5639 for (i = 0, len = strlen(str); i < len; ++i) {
5640 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005641 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005642 if (c == '\n') p->nchars = SIZE_MAX;
5643 ++p->nchars;
5644 }
5645 }
5646 else {
5647 bc_program_printString(str, &p->nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005648 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005649 }
5650 }
5651
5652 if (!s && pop) bc_vec_pop(&p->results);
5653
5654 return s;
5655}
5656
5657static BcStatus bc_program_negate(BcProgram *p)
5658{
5659 BcStatus s;
5660 BcResult res, *ptr;
5661 BcNum *num = NULL;
5662
5663 s = bc_program_prep(p, &ptr, &num);
5664 if (s) return s;
5665
5666 bc_num_init(&res.d.n, num->len);
5667 bc_num_copy(&res.d.n, num);
5668 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5669
5670 bc_program_retire(p, &res, BC_RESULT_TEMP);
5671
5672 return s;
5673}
5674
5675static BcStatus bc_program_logical(BcProgram *p, char inst)
5676{
5677 BcStatus s;
5678 BcResult *opd1, *opd2, res;
5679 BcNum *n1, *n2;
5680 bool cond = 0;
5681 ssize_t cmp;
5682
5683 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
5684 if (s) return s;
5685 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5686
5687 if (inst == BC_INST_BOOL_AND)
5688 cond = bc_num_cmp(n1, &p->zero) && bc_num_cmp(n2, &p->zero);
5689 else if (inst == BC_INST_BOOL_OR)
5690 cond = bc_num_cmp(n1, &p->zero) || bc_num_cmp(n2, &p->zero);
5691 else {
5692
5693 cmp = bc_num_cmp(n1, n2);
5694
5695 switch (inst) {
5696
5697 case BC_INST_REL_EQ:
5698 {
5699 cond = cmp == 0;
5700 break;
5701 }
5702
5703 case BC_INST_REL_LE:
5704 {
5705 cond = cmp <= 0;
5706 break;
5707 }
5708
5709 case BC_INST_REL_GE:
5710 {
5711 cond = cmp >= 0;
5712 break;
5713 }
5714
5715 case BC_INST_REL_NE:
5716 {
5717 cond = cmp != 0;
5718 break;
5719 }
5720
5721 case BC_INST_REL_LT:
5722 {
5723 cond = cmp < 0;
5724 break;
5725 }
5726
5727 case BC_INST_REL_GT:
5728 {
5729 cond = cmp > 0;
5730 break;
5731 }
5732 }
5733 }
5734
5735 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5736
5737 bc_program_binOpRetire(p, &res);
5738
5739 return s;
5740}
5741
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005742#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005743static BcStatus bc_program_assignStr(BcProgram *p, BcResult *r, BcVec *v,
5744 bool push)
5745{
5746 BcNum n2;
5747 BcResult res;
5748
5749 memset(&n2, 0, sizeof(BcNum));
5750 n2.rdx = res.d.id.idx = r->d.id.idx;
5751 res.t = BC_RESULT_STR;
5752
5753 if (!push) {
5754 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
5755 bc_vec_pop(v);
5756 bc_vec_pop(&p->results);
5757 }
5758
5759 bc_vec_pop(&p->results);
5760
5761 bc_vec_push(&p->results, &res);
5762 bc_vec_push(v, &n2);
5763
5764 return BC_STATUS_SUCCESS;
5765}
5766#endif // ENABLE_DC
5767
5768static BcStatus bc_program_copyToVar(BcProgram *p, char *name, bool var)
5769{
5770 BcStatus s;
5771 BcResult *ptr, r;
5772 BcVec *v;
5773 BcNum *n;
5774
5775 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
5776
5777 ptr = bc_vec_top(&p->results);
5778 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5779 bc_program_search(p, name, &v, var);
5780
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005781#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005782 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5783 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(p, ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005784#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005785
5786 s = bc_program_num(p, ptr, &n, false);
5787 if (s) return s;
5788
5789 // Do this once more to make sure that pointers were not invalidated.
5790 bc_program_search(p, name, &v, var);
5791
5792 if (var) {
5793 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5794 bc_num_copy(&r.d.n, n);
5795 }
5796 else {
5797 bc_array_init(&r.d.v, true);
5798 bc_array_copy(&r.d.v, (BcVec *) n);
5799 }
5800
5801 bc_vec_push(v, &r.d);
5802 bc_vec_pop(&p->results);
5803
5804 return s;
5805}
5806
5807static BcStatus bc_program_assign(BcProgram *p, char inst)
5808{
5809 BcStatus s;
5810 BcResult *left, *right, res;
5811 BcNum *l = NULL, *r = NULL;
5812 unsigned long val, max;
5813 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5814
5815 s = bc_program_binOpPrep(p, &left, &l, &right, &r, assign);
5816 if (s) return s;
5817
5818 ib = left->t == BC_RESULT_IBASE;
5819 sc = left->t == BC_RESULT_SCALE;
5820
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005821#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005822
5823 if (right->t == BC_RESULT_STR) {
5824
5825 BcVec *v;
5826
5827 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5828 bc_program_search(p, left->d.id.name, &v, true);
5829
5830 return bc_program_assignStr(p, right, v, false);
5831 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005832#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005833
5834 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5835 return BC_STATUS_PARSE_BAD_ASSIGN;
5836
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005837#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06005838 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &p->zero))
5839 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5840
5841 if (assign)
5842 bc_num_copy(l, r);
5843 else
5844 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5845
5846 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005847#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005848 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005849#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005850
5851 if (ib || sc || left->t == BC_RESULT_OBASE) {
5852
5853 size_t *ptr;
5854
5855 s = bc_num_ulong(l, &val);
5856 if (s) return s;
5857 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5858
5859 if (sc) {
5860 max = BC_MAX_SCALE;
5861 ptr = &p->scale;
5862 }
5863 else {
5864 if (val < BC_NUM_MIN_BASE) return s;
5865 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5866 ptr = ib ? &p->ib_t : &p->ob_t;
5867 }
5868
5869 if (val > max) return s;
5870 if (!sc) bc_num_copy(ib ? &p->ib : &p->ob, l);
5871
5872 *ptr = (size_t) val;
5873 s = BC_STATUS_SUCCESS;
5874 }
5875
5876 bc_num_init(&res.d.n, l->len);
5877 bc_num_copy(&res.d.n, l);
5878 bc_program_binOpRetire(p, &res);
5879
5880 return s;
5881}
5882
5883static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn,
5884 bool pop, bool copy)
5885{
5886 BcStatus s = BC_STATUS_SUCCESS;
5887 BcResult r;
5888 char *name = bc_program_name(code, bgn);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005889#if ENABLE_DC // Exclude
Gavin Howard01055ba2018-11-03 11:00:21 -06005890 BcNum *num;
5891 BcVec *v;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005892#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005893 (void) pop, (void) copy;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005894#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005895
5896 r.t = BC_RESULT_VAR;
5897 r.d.id.name = name;
5898
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005899#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005900 bc_program_search(p, name, &v, true);
5901 num = bc_vec_top(v);
5902
5903 if (pop || copy) {
5904
5905 if (!BC_PROG_STACK(v, 2 - copy)) {
5906 free(name);
5907 return BC_STATUS_EXEC_STACK;
5908 }
5909
5910 free(name);
5911 name = NULL;
5912
5913 if (!BC_PROG_STR(num)) {
5914
5915 r.t = BC_RESULT_TEMP;
5916
5917 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5918 bc_num_copy(&r.d.n, num);
5919 }
5920 else {
5921 r.t = BC_RESULT_STR;
5922 r.d.id.idx = num->rdx;
5923 }
5924
5925 if (!copy) bc_vec_pop(v);
5926 }
5927#endif // ENABLE_DC
5928
5929 bc_vec_push(&p->results, &r);
5930
5931 return s;
5932}
5933
5934static BcStatus bc_program_pushArray(BcProgram *p, char *code, size_t *bgn,
5935 char inst)
5936{
5937 BcStatus s = BC_STATUS_SUCCESS;
5938 BcResult r;
5939 BcNum *num;
5940
5941 r.d.id.name = bc_program_name(code, bgn);
5942
5943 if (inst == BC_INST_ARRAY) {
5944 r.t = BC_RESULT_ARRAY;
5945 bc_vec_push(&p->results, &r);
5946 }
5947 else {
5948
5949 BcResult *operand;
5950 unsigned long temp;
5951
5952 s = bc_program_prep(p, &operand, &num);
5953 if (s) goto err;
5954 s = bc_num_ulong(num, &temp);
5955 if (s) goto err;
5956
5957 if (temp > BC_MAX_DIM) {
5958 s = BC_STATUS_EXEC_ARRAY_LEN;
5959 goto err;
5960 }
5961
5962 r.d.id.idx = (size_t) temp;
5963 bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5964 }
5965
5966err:
5967 if (s) free(r.d.id.name);
5968 return s;
5969}
5970
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005971#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06005972static BcStatus bc_program_incdec(BcProgram *p, char inst)
5973{
5974 BcStatus s;
5975 BcResult *ptr, res, copy;
5976 BcNum *num = NULL;
5977 char inst2 = inst;
5978
5979 s = bc_program_prep(p, &ptr, &num);
5980 if (s) return s;
5981
5982 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5983 copy.t = BC_RESULT_TEMP;
5984 bc_num_init(&copy.d.n, num->len);
5985 bc_num_copy(&copy.d.n, num);
5986 }
5987
5988 res.t = BC_RESULT_ONE;
5989 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5990 BC_INST_ASSIGN_PLUS :
5991 BC_INST_ASSIGN_MINUS;
5992
5993 bc_vec_push(&p->results, &res);
5994 bc_program_assign(p, inst);
5995
5996 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5997 bc_vec_pop(&p->results);
5998 bc_vec_push(&p->results, &copy);
5999 }
6000
6001 return s;
6002}
6003
6004static BcStatus bc_program_call(BcProgram *p, char *code, size_t *idx)
6005{
6006 BcStatus s = BC_STATUS_SUCCESS;
6007 BcInstPtr ip;
6008 size_t i, nparams = bc_program_index(code, idx);
6009 BcFunc *func;
6010 BcVec *v;
6011 BcId *a;
6012 BcResultData param;
6013 BcResult *arg;
6014
6015 ip.idx = 0;
6016 ip.func = bc_program_index(code, idx);
6017 func = bc_vec_item(&p->fns, ip.func);
6018
6019 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
6020 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
6021 ip.len = p->results.len - nparams;
6022
6023 for (i = 0; i < nparams; ++i) {
6024
6025 a = bc_vec_item(&func->autos, nparams - 1 - i);
6026 arg = bc_vec_top(&p->results);
6027
6028 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6029 return BC_STATUS_EXEC_BAD_TYPE;
6030
6031 s = bc_program_copyToVar(p, a->name, a->idx);
6032 if (s) return s;
6033 }
6034
6035 for (; i < func->autos.len; ++i) {
6036
6037 a = bc_vec_item(&func->autos, i);
6038 bc_program_search(p, a->name, &v, a->idx);
6039
6040 if (a->idx) {
6041 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6042 bc_vec_push(v, &param.n);
6043 }
6044 else {
6045 bc_array_init(&param.v, true);
6046 bc_vec_push(v, &param.v);
6047 }
6048 }
6049
6050 bc_vec_push(&p->stack, &ip);
6051
6052 return BC_STATUS_SUCCESS;
6053}
6054
6055static BcStatus bc_program_return(BcProgram *p, char inst)
6056{
6057 BcStatus s;
6058 BcResult res;
6059 BcFunc *f;
6060 size_t i;
6061 BcInstPtr *ip = bc_vec_top(&p->stack);
6062
6063 if (!BC_PROG_STACK(&p->results, ip->len + inst == BC_INST_RET))
6064 return BC_STATUS_EXEC_STACK;
6065
6066 f = bc_vec_item(&p->fns, ip->func);
6067 res.t = BC_RESULT_TEMP;
6068
6069 if (inst == BC_INST_RET) {
6070
6071 BcNum *num;
6072 BcResult *operand = bc_vec_top(&p->results);
6073
6074 s = bc_program_num(p, operand, &num, false);
6075 if (s) return s;
6076 bc_num_init(&res.d.n, num->len);
6077 bc_num_copy(&res.d.n, num);
6078 }
6079 else {
6080 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6081 bc_num_zero(&res.d.n);
6082 }
6083
6084 // We need to pop arguments as well, so this takes that into account.
6085 for (i = 0; i < f->autos.len; ++i) {
6086
6087 BcVec *v;
6088 BcId *a = bc_vec_item(&f->autos, i);
6089
6090 bc_program_search(p, a->name, &v, a->idx);
6091 bc_vec_pop(v);
6092 }
6093
6094 bc_vec_npop(&p->results, p->results.len - ip->len);
6095 bc_vec_push(&p->results, &res);
6096 bc_vec_pop(&p->stack);
6097
6098 return BC_STATUS_SUCCESS;
6099}
6100#endif // ENABLE_BC
6101
6102static unsigned long bc_program_scale(BcNum *n)
6103{
6104 return (unsigned long) n->rdx;
6105}
6106
6107static unsigned long bc_program_len(BcNum *n)
6108{
6109 unsigned long len = n->len;
6110 size_t i;
6111
6112 if (n->rdx != n->len) return len;
6113 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6114
6115 return len;
6116}
6117
6118static BcStatus bc_program_builtin(BcProgram *p, char inst)
6119{
6120 BcStatus s;
6121 BcResult *opnd;
6122 BcNum *num = NULL;
6123 BcResult res;
6124 bool len = inst == BC_INST_LENGTH;
6125
6126 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6127 opnd = bc_vec_top(&p->results);
6128
6129 s = bc_program_num(p, opnd, &num, false);
6130 if (s) return s;
6131
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006132#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006133 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006134#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006135
6136 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6137
6138 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, p->scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006139#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006140 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6141 s = bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6142 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006143#endif
6144#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006145 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6146
6147 char **str;
6148 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6149
6150 str = bc_vec_item(&p->strs, idx);
6151 s = bc_num_ulong2num(&res.d.n, strlen(*str));
6152 if (s) goto err;
6153 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006154#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006155 else {
6156 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6157 s = bc_num_ulong2num(&res.d.n, f(num));
6158 if (s) goto err;
6159 }
6160
6161 bc_program_retire(p, &res, BC_RESULT_TEMP);
6162
6163 return s;
6164
6165err:
6166 bc_num_free(&res.d.n);
6167 return s;
6168}
6169
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006170#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006171static BcStatus bc_program_divmod(BcProgram *p)
6172{
6173 BcStatus s;
6174 BcResult *opd1, *opd2, res, res2;
6175 BcNum *n1, *n2 = NULL;
6176
6177 s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, false);
6178 if (s) return s;
6179
6180 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6181 bc_num_init(&res2.d.n, n2->len);
6182
6183 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, p->scale);
6184 if (s) goto err;
6185
6186 bc_program_binOpRetire(p, &res2);
6187 res.t = BC_RESULT_TEMP;
6188 bc_vec_push(&p->results, &res);
6189
6190 return s;
6191
6192err:
6193 bc_num_free(&res2.d.n);
6194 bc_num_free(&res.d.n);
6195 return s;
6196}
6197
6198static BcStatus bc_program_modexp(BcProgram *p)
6199{
6200 BcStatus s;
6201 BcResult *r1, *r2, *r3, res;
6202 BcNum *n1, *n2, *n3;
6203
6204 if (!BC_PROG_STACK(&p->results, 3)) return BC_STATUS_EXEC_STACK;
6205 s = bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, false);
6206 if (s) return s;
6207
6208 r1 = bc_vec_item_rev(&p->results, 2);
6209 s = bc_program_num(p, r1, &n1, false);
6210 if (s) return s;
6211 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6212
6213 // Make sure that the values have their pointers updated, if necessary.
6214 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6215
6216 if (r1->t == r2->t) {
6217 s = bc_program_num(p, r2, &n2, false);
6218 if (s) return s;
6219 }
6220
6221 if (r1->t == r3->t) {
6222 s = bc_program_num(p, r3, &n3, false);
6223 if (s) return s;
6224 }
6225 }
6226
6227 bc_num_init(&res.d.n, n3->len);
6228 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6229 if (s) goto err;
6230
6231 bc_vec_pop(&p->results);
6232 bc_program_binOpRetire(p, &res);
6233
6234 return s;
6235
6236err:
6237 bc_num_free(&res.d.n);
6238 return s;
6239}
6240
6241static BcStatus bc_program_stackLen(BcProgram *p)
6242{
6243 BcStatus s;
6244 BcResult res;
6245 size_t len = p->results.len;
6246
6247 res.t = BC_RESULT_TEMP;
6248
6249 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6250 s = bc_num_ulong2num(&res.d.n, len);
6251 if (s) goto err;
6252 bc_vec_push(&p->results, &res);
6253
6254 return s;
6255
6256err:
6257 bc_num_free(&res.d.n);
6258 return s;
6259}
6260
6261static BcStatus bc_program_asciify(BcProgram *p)
6262{
6263 BcStatus s;
6264 BcResult *r, res;
6265 BcNum *num = NULL, n;
6266 char *str, *str2, c;
6267 size_t len = p->strs.len, idx;
6268 unsigned long val;
6269
6270 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6271 r = bc_vec_top(&p->results);
6272
6273 s = bc_program_num(p, r, &num, false);
6274 if (s) return s;
6275
6276 if (BC_PROG_NUM(r, num)) {
6277
6278 bc_num_init(&n, BC_NUM_DEF_SIZE);
6279 bc_num_copy(&n, num);
6280 bc_num_truncate(&n, n.rdx);
6281
6282 s = bc_num_mod(&n, &p->strmb, &n, 0);
6283 if (s) goto num_err;
6284 s = bc_num_ulong(&n, &val);
6285 if (s) goto num_err;
6286
6287 c = (char) val;
6288
6289 bc_num_free(&n);
6290 }
6291 else {
6292 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6293 str2 = *((char **) bc_vec_item(&p->strs, idx));
6294 c = str2[0];
6295 }
6296
6297 str = xmalloc(2);
6298 str[0] = c;
6299 str[1] = '\0';
6300
6301 str2 = xstrdup(str);
6302 bc_program_addFunc(p, str2, &idx);
6303
6304 if (idx != len + BC_PROG_REQ_FUNCS) {
6305
6306 for (idx = 0; idx < p->strs.len; ++idx) {
6307 if (!strcmp(*((char **) bc_vec_item(&p->strs, idx)), str)) {
6308 len = idx;
6309 break;
6310 }
6311 }
6312
6313 free(str);
6314 }
6315 else
6316 bc_vec_push(&p->strs, &str);
6317
6318 res.t = BC_RESULT_STR;
6319 res.d.id.idx = len;
6320 bc_vec_pop(&p->results);
6321 bc_vec_push(&p->results, &res);
6322
6323 return BC_STATUS_SUCCESS;
6324
6325num_err:
6326 bc_num_free(&n);
6327 return s;
6328}
6329
6330static BcStatus bc_program_printStream(BcProgram *p)
6331{
6332 BcStatus s;
6333 BcResult *r;
6334 BcNum *n = NULL;
6335 size_t idx;
6336 char *str;
6337
6338 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6339 r = bc_vec_top(&p->results);
6340
6341 s = bc_program_num(p, r, &n, false);
6342 if (s) return s;
6343
6344 if (BC_PROG_NUM(r, n))
6345 s = bc_num_stream(n, &p->strmb, &p->nchars, p->len);
6346 else {
6347 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6348 str = *((char **) bc_vec_item(&p->strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006349 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006350 }
6351
6352 return s;
6353}
6354
6355static BcStatus bc_program_nquit(BcProgram *p)
6356{
6357 BcStatus s;
6358 BcResult *opnd;
6359 BcNum *num = NULL;
6360 unsigned long val;
6361
6362 s = bc_program_prep(p, &opnd, &num);
6363 if (s) return s;
6364 s = bc_num_ulong(num, &val);
6365 if (s) return s;
6366
6367 bc_vec_pop(&p->results);
6368
6369 if (p->stack.len < val)
6370 return BC_STATUS_EXEC_STACK;
6371 else if (p->stack.len == val)
6372 return BC_STATUS_QUIT;
6373
6374 bc_vec_npop(&p->stack, val);
6375
6376 return s;
6377}
6378
6379static BcStatus bc_program_execStr(BcProgram *p, char *code, size_t *bgn,
6380 bool cond)
6381{
6382 BcStatus s = BC_STATUS_SUCCESS;
6383 BcResult *r;
6384 char **str;
6385 BcFunc *f;
6386 BcParse prs;
6387 BcInstPtr ip;
6388 size_t fidx, sidx;
6389 BcNum *n;
6390 bool exec;
6391
6392 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6393
6394 r = bc_vec_top(&p->results);
6395
6396 if (cond) {
6397
6398 BcVec *v;
6399 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6400
6401 if (code[*bgn] == BC_PARSE_STREND)
6402 (*bgn) += 1;
6403 else
6404 else_name = bc_program_name(code, bgn);
6405
6406 exec = r->d.n.len != 0;
6407
6408 if (exec)
6409 name = then_name;
6410 else if (else_name != NULL) {
6411 exec = true;
6412 name = else_name;
6413 }
6414
6415 if (exec) {
6416 bc_program_search(p, name, &v, true);
6417 n = bc_vec_top(v);
6418 }
6419
6420 free(then_name);
6421 free(else_name);
6422
6423 if (!exec) goto exit;
6424 if (!BC_PROG_STR(n)) {
6425 s = BC_STATUS_EXEC_BAD_TYPE;
6426 goto exit;
6427 }
6428
6429 sidx = n->rdx;
6430 }
6431 else {
6432
6433 if (r->t == BC_RESULT_STR)
6434 sidx = r->d.id.idx;
6435 else if (r->t == BC_RESULT_VAR) {
6436 s = bc_program_num(p, r, &n, false);
6437 if (s || !BC_PROG_STR(n)) goto exit;
6438 sidx = n->rdx;
6439 }
6440 else
6441 goto exit;
6442 }
6443
6444 fidx = sidx + BC_PROG_REQ_FUNCS;
6445
6446 str = bc_vec_item(&p->strs, sidx);
6447 f = bc_vec_item(&p->fns, fidx);
6448
6449 if (f->code.len == 0) {
6450
6451 p->parse_init(&prs, p, fidx);
6452 s = bc_parse_text(&prs, *str);
6453 if (s) goto err;
6454 s = p->parse_expr(&prs, BC_PARSE_NOCALL);
6455 if (s) goto err;
6456
6457 if (prs.l.t.t != BC_LEX_EOF) {
6458 s = BC_STATUS_PARSE_BAD_EXP;
6459 goto err;
6460 }
6461
6462 bc_parse_free(&prs);
6463 }
6464
6465 ip.idx = 0;
6466 ip.len = p->results.len;
6467 ip.func = fidx;
6468
6469 bc_vec_pop(&p->results);
6470 bc_vec_push(&p->stack, &ip);
6471
6472 return BC_STATUS_SUCCESS;
6473
6474err:
6475 bc_parse_free(&prs);
6476 f = bc_vec_item(&p->fns, fidx);
6477 bc_vec_npop(&f->code, f->code.len);
6478exit:
6479 bc_vec_pop(&p->results);
6480 return s;
6481}
6482#endif // ENABLE_DC
6483
6484static BcStatus bc_program_pushGlobal(BcProgram *p, char inst)
6485{
6486 BcStatus s;
6487 BcResult res;
6488 unsigned long val;
6489
6490 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6491 if (inst == BC_INST_IBASE)
6492 val = (unsigned long) p->ib_t;
6493 else if (inst == BC_INST_SCALE)
6494 val = (unsigned long) p->scale;
6495 else
6496 val = (unsigned long) p->ob_t;
6497
6498 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6499 s = bc_num_ulong2num(&res.d.n, val);
6500 if (s) goto err;
6501 bc_vec_push(&p->results, &res);
6502
6503 return s;
6504
6505err:
6506 bc_num_free(&res.d.n);
6507 return s;
6508}
6509
6510static void bc_program_free(BcProgram *p)
6511{
6512 bc_num_free(&p->ib);
6513 bc_num_free(&p->ob);
6514 bc_num_free(&p->hexb);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006515#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006516 bc_num_free(&p->strmb);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006517#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006518 bc_vec_free(&p->fns);
6519 bc_vec_free(&p->fn_map);
6520 bc_vec_free(&p->vars);
6521 bc_vec_free(&p->var_map);
6522 bc_vec_free(&p->arrs);
6523 bc_vec_free(&p->arr_map);
6524 bc_vec_free(&p->strs);
6525 bc_vec_free(&p->consts);
6526 bc_vec_free(&p->results);
6527 bc_vec_free(&p->stack);
6528 bc_num_free(&p->last);
6529 bc_num_free(&p->zero);
6530 bc_num_free(&p->one);
6531}
6532
6533static void bc_program_init(BcProgram *p, size_t line_len, BcParseInit init,
6534 BcParseExpr expr)
6535{
6536 size_t idx;
6537 BcInstPtr ip;
6538
6539 memset(p, 0, sizeof(BcProgram));
6540 memset(&ip, 0, sizeof(BcInstPtr));
6541
6542 p->nchars = p->scale = 0;
6543 p->len = line_len;
6544 p->parse_init = init;
6545 p->parse_expr = expr;
6546
6547 bc_num_init(&p->ib, BC_NUM_DEF_SIZE);
6548 bc_num_ten(&p->ib);
6549 p->ib_t = 10;
6550
6551 bc_num_init(&p->ob, BC_NUM_DEF_SIZE);
6552 bc_num_ten(&p->ob);
6553 p->ob_t = 10;
6554
6555 bc_num_init(&p->hexb, BC_NUM_DEF_SIZE);
6556 bc_num_ten(&p->hexb);
6557 p->hexb.num[0] = 6;
6558
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006559#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006560 bc_num_init(&p->strmb, BC_NUM_DEF_SIZE);
6561 bc_num_ulong2num(&p->strmb, UCHAR_MAX + 1);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006562#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006563
6564 bc_num_init(&p->last, BC_NUM_DEF_SIZE);
6565 bc_num_zero(&p->last);
6566
6567 bc_num_init(&p->zero, BC_NUM_DEF_SIZE);
6568 bc_num_zero(&p->zero);
6569
6570 bc_num_init(&p->one, BC_NUM_DEF_SIZE);
6571 bc_num_one(&p->one);
6572
6573 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
6574 bc_map_init(&p->fn_map);
6575
6576 bc_program_addFunc(p, xstrdup(bc_func_main), &idx);
6577 bc_program_addFunc(p, xstrdup(bc_func_read), &idx);
6578
6579 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
6580 bc_map_init(&p->var_map);
6581
6582 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
6583 bc_map_init(&p->arr_map);
6584
6585 bc_vec_init(&p->strs, sizeof(char *), bc_string_free);
6586 bc_vec_init(&p->consts, sizeof(char *), bc_string_free);
6587 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
6588 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
6589 bc_vec_push(&p->stack, &ip);
6590}
6591
6592static void bc_program_addFunc(BcProgram *p, char *name, size_t *idx)
6593{
6594 BcStatus s;
6595 BcId entry, *entry_ptr;
6596 BcFunc f;
6597
6598 entry.name = name;
6599 entry.idx = p->fns.len;
6600
6601 s = bc_map_insert(&p->fn_map, &entry, idx);
6602 if (s) free(name);
6603
6604 entry_ptr = bc_vec_item(&p->fn_map, *idx);
6605 *idx = entry_ptr->idx;
6606
6607 if (s == BC_STATUS_VEC_ITEM_EXISTS) {
6608
6609 BcFunc *func = bc_vec_item(&p->fns, entry_ptr->idx);
6610
6611 // We need to reset these, so the function can be repopulated.
6612 func->nparams = 0;
6613 bc_vec_npop(&func->autos, func->autos.len);
6614 bc_vec_npop(&func->code, func->code.len);
6615 bc_vec_npop(&func->labels, func->labels.len);
6616 }
6617 else {
6618 bc_func_init(&f);
6619 bc_vec_push(&p->fns, &f);
6620 }
6621}
6622
6623static BcStatus bc_program_reset(BcProgram *p, BcStatus s)
6624{
6625 BcFunc *f;
6626 BcInstPtr *ip;
6627
6628 bc_vec_npop(&p->stack, p->stack.len - 1);
6629 bc_vec_npop(&p->results, p->results.len);
6630
6631 f = bc_vec_item(&p->fns, 0);
6632 ip = bc_vec_top(&p->stack);
6633 ip->idx = f->code.len;
6634
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006635 if (!s && G.signe && !G.tty) return BC_STATUS_QUIT;
Gavin Howard01055ba2018-11-03 11:00:21 -06006636
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006637 G.sigc += G.signe;
6638 G.signe = G.sig != G.sigc;
Gavin Howard01055ba2018-11-03 11:00:21 -06006639
6640 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006641 if (G.ttyin) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01006642 fputs(bc_program_ready_msg, stderr);
6643 fflush(stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06006644 s = BC_STATUS_SUCCESS;
6645 }
6646 else
6647 s = BC_STATUS_QUIT;
6648 }
6649
6650 return s;
6651}
6652
6653static BcStatus bc_program_exec(BcProgram *p)
6654{
6655 BcStatus s = BC_STATUS_SUCCESS;
6656 size_t idx;
6657 BcResult r, *ptr;
6658 BcNum *num;
6659 BcInstPtr *ip = bc_vec_top(&p->stack);
6660 BcFunc *func = bc_vec_item(&p->fns, ip->func);
6661 char *code = func->code.v;
6662 bool cond = false;
6663
6664 while (!s && ip->idx < func->code.len) {
6665
6666 char inst = code[(ip->idx)++];
6667
6668 switch (inst) {
6669
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006670#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006671 case BC_INST_JUMP_ZERO:
6672 {
6673 s = bc_program_prep(p, &ptr, &num);
6674 if (s) return s;
6675 cond = !bc_num_cmp(num, &p->zero);
6676 bc_vec_pop(&p->results);
6677 }
6678 // Fallthrough.
6679 case BC_INST_JUMP:
6680 {
6681 size_t *addr;
6682 idx = bc_program_index(code, &ip->idx);
6683 addr = bc_vec_item(&func->labels, idx);
6684 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6685 break;
6686 }
6687
6688 case BC_INST_CALL:
6689 {
6690 s = bc_program_call(p, code, &ip->idx);
6691 break;
6692 }
6693
6694 case BC_INST_INC_PRE:
6695 case BC_INST_DEC_PRE:
6696 case BC_INST_INC_POST:
6697 case BC_INST_DEC_POST:
6698 {
6699 s = bc_program_incdec(p, inst);
6700 break;
6701 }
6702
6703 case BC_INST_HALT:
6704 {
6705 s = BC_STATUS_QUIT;
6706 break;
6707 }
6708
6709 case BC_INST_RET:
6710 case BC_INST_RET0:
6711 {
6712 s = bc_program_return(p, inst);
6713 break;
6714 }
6715
6716 case BC_INST_BOOL_OR:
6717 case BC_INST_BOOL_AND:
6718#endif // ENABLE_BC
6719 case BC_INST_REL_EQ:
6720 case BC_INST_REL_LE:
6721 case BC_INST_REL_GE:
6722 case BC_INST_REL_NE:
6723 case BC_INST_REL_LT:
6724 case BC_INST_REL_GT:
6725 {
6726 s = bc_program_logical(p, inst);
6727 break;
6728 }
6729
6730 case BC_INST_READ:
6731 {
6732 s = bc_program_read(p);
6733 break;
6734 }
6735
6736 case BC_INST_VAR:
6737 {
6738 s = bc_program_pushVar(p, code, &ip->idx, false, false);
6739 break;
6740 }
6741
6742 case BC_INST_ARRAY_ELEM:
6743 case BC_INST_ARRAY:
6744 {
6745 s = bc_program_pushArray(p, code, &ip->idx, inst);
6746 break;
6747 }
6748
6749 case BC_INST_LAST:
6750 {
6751 r.t = BC_RESULT_LAST;
6752 bc_vec_push(&p->results, &r);
6753 break;
6754 }
6755
6756 case BC_INST_IBASE:
6757 case BC_INST_SCALE:
6758 case BC_INST_OBASE:
6759 {
6760 s = bc_program_pushGlobal(p, inst);
6761 break;
6762 }
6763
6764 case BC_INST_SCALE_FUNC:
6765 case BC_INST_LENGTH:
6766 case BC_INST_SQRT:
6767 {
6768 s = bc_program_builtin(p, inst);
6769 break;
6770 }
6771
6772 case BC_INST_NUM:
6773 {
6774 r.t = BC_RESULT_CONSTANT;
6775 r.d.id.idx = bc_program_index(code, &ip->idx);
6776 bc_vec_push(&p->results, &r);
6777 break;
6778 }
6779
6780 case BC_INST_POP:
6781 {
6782 if (!BC_PROG_STACK(&p->results, 1))
6783 s = BC_STATUS_EXEC_STACK;
6784 else
6785 bc_vec_pop(&p->results);
6786 break;
6787 }
6788
6789 case BC_INST_POP_EXEC:
6790 {
6791 bc_vec_pop(&p->stack);
6792 break;
6793 }
6794
6795 case BC_INST_PRINT:
6796 case BC_INST_PRINT_POP:
6797 case BC_INST_PRINT_STR:
6798 {
6799 s = bc_program_print(p, inst, 0);
6800 break;
6801 }
6802
6803 case BC_INST_STR:
6804 {
6805 r.t = BC_RESULT_STR;
6806 r.d.id.idx = bc_program_index(code, &ip->idx);
6807 bc_vec_push(&p->results, &r);
6808 break;
6809 }
6810
6811 case BC_INST_POWER:
6812 case BC_INST_MULTIPLY:
6813 case BC_INST_DIVIDE:
6814 case BC_INST_MODULUS:
6815 case BC_INST_PLUS:
6816 case BC_INST_MINUS:
6817 {
6818 s = bc_program_op(p, inst);
6819 break;
6820 }
6821
6822 case BC_INST_BOOL_NOT:
6823 {
6824 s = bc_program_prep(p, &ptr, &num);
6825 if (s) return s;
6826
6827 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6828 (!bc_num_cmp(num, &p->zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6829 bc_program_retire(p, &r, BC_RESULT_TEMP);
6830
6831 break;
6832 }
6833
6834 case BC_INST_NEG:
6835 {
6836 s = bc_program_negate(p);
6837 break;
6838 }
6839
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006840#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006841 case BC_INST_ASSIGN_POWER:
6842 case BC_INST_ASSIGN_MULTIPLY:
6843 case BC_INST_ASSIGN_DIVIDE:
6844 case BC_INST_ASSIGN_MODULUS:
6845 case BC_INST_ASSIGN_PLUS:
6846 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006847#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006848 case BC_INST_ASSIGN:
6849 {
6850 s = bc_program_assign(p, inst);
6851 break;
6852 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006853#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006854 case BC_INST_MODEXP:
6855 {
6856 s = bc_program_modexp(p);
6857 break;
6858 }
6859
6860 case BC_INST_DIVMOD:
6861 {
6862 s = bc_program_divmod(p);
6863 break;
6864 }
6865
6866 case BC_INST_EXECUTE:
6867 case BC_INST_EXEC_COND:
6868 {
6869 cond = inst == BC_INST_EXEC_COND;
6870 s = bc_program_execStr(p, code, &ip->idx, cond);
6871 break;
6872 }
6873
6874 case BC_INST_PRINT_STACK:
6875 {
6876 for (idx = 0; !s && idx < p->results.len; ++idx)
6877 s = bc_program_print(p, BC_INST_PRINT, idx);
6878 break;
6879 }
6880
6881 case BC_INST_CLEAR_STACK:
6882 {
6883 bc_vec_npop(&p->results, p->results.len);
6884 break;
6885 }
6886
6887 case BC_INST_STACK_LEN:
6888 {
6889 s = bc_program_stackLen(p);
6890 break;
6891 }
6892
6893 case BC_INST_DUPLICATE:
6894 {
6895 if (!BC_PROG_STACK(&p->results, 1)) return BC_STATUS_EXEC_STACK;
6896 ptr = bc_vec_top(&p->results);
6897 bc_result_copy(&r, ptr);
6898 bc_vec_push(&p->results, &r);
6899 break;
6900 }
6901
6902 case BC_INST_SWAP:
6903 {
6904 BcResult *ptr2;
6905
6906 if (!BC_PROG_STACK(&p->results, 2)) return BC_STATUS_EXEC_STACK;
6907
6908 ptr = bc_vec_item_rev(&p->results, 0);
6909 ptr2 = bc_vec_item_rev(&p->results, 1);
6910 memcpy(&r, ptr, sizeof(BcResult));
6911 memcpy(ptr, ptr2, sizeof(BcResult));
6912 memcpy(ptr2, &r, sizeof(BcResult));
6913
6914 break;
6915 }
6916
6917 case BC_INST_ASCIIFY:
6918 {
6919 s = bc_program_asciify(p);
6920 break;
6921 }
6922
6923 case BC_INST_PRINT_STREAM:
6924 {
6925 s = bc_program_printStream(p);
6926 break;
6927 }
6928
6929 case BC_INST_LOAD:
6930 case BC_INST_PUSH_VAR:
6931 {
6932 bool copy = inst == BC_INST_LOAD;
6933 s = bc_program_pushVar(p, code, &ip->idx, true, copy);
6934 break;
6935 }
6936
6937 case BC_INST_PUSH_TO_VAR:
6938 {
6939 char *name = bc_program_name(code, &ip->idx);
6940 s = bc_program_copyToVar(p, name, true);
6941 free(name);
6942 break;
6943 }
6944
6945 case BC_INST_QUIT:
6946 {
6947 if (p->stack.len <= 2)
6948 s = BC_STATUS_QUIT;
6949 else
6950 bc_vec_npop(&p->stack, 2);
6951 break;
6952 }
6953
6954 case BC_INST_NQUIT:
6955 {
6956 s = bc_program_nquit(p);
6957 break;
6958 }
6959#endif // ENABLE_DC
6960 }
6961
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006962 if ((s && s != BC_STATUS_QUIT) || G.signe) s = bc_program_reset(p, s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006963
6964 // If the stack has changed, pointers may be invalid.
6965 ip = bc_vec_top(&p->stack);
6966 func = bc_vec_item(&p->fns, ip->func);
6967 code = func->code.v;
6968 }
6969
6970 return s;
6971}
6972
6973#if ENABLE_FEATURE_BC_SIGNALS
6974static void bc_vm_sig(int sig)
6975{
6976 int err = errno;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006977 size_t len = strlen(G.sig_msg);
6978 if (sig == SIGINT && write(2, G.sig_msg, len) == (ssize_t) len) {
6979 G.signe = G.sig == G.sigc;
6980 G.sig += G.signe;
Gavin Howard01055ba2018-11-03 11:00:21 -06006981 }
6982 errno = err;
6983}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006984#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006985
Denys Vlasenko00d77792018-11-30 23:13:42 +01006986static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006987{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006988 printf("%s "BB_VER"\n"
6989 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006990 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006991 "This is free software with ABSOLUTELY NO WARRANTY\n"
6992 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006993}
6994
6995static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6996{
6997 if (!s || s > BC_STATUS_VEC_ITEM_EXISTS) return s;
6998
Denys Vlasenko00d77792018-11-30 23:13:42 +01006999 fprintf(stderr, bc_err_fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7000 fprintf(stderr, " %s", file);
7001 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007002
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007003 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
Gavin Howard01055ba2018-11-03 11:00:21 -06007004}
7005
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007006#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06007007static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
7008 const char *msg)
7009{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007010 int p = (int) G_posix, w = (int) G_warn;
Gavin Howard01055ba2018-11-03 11:00:21 -06007011 const char *const fmt = p ? bc_err_fmt : bc_warn_fmt;
7012
7013 if (!(p || w) || s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
7014
Denys Vlasenko00d77792018-11-30 23:13:42 +01007015 fprintf(stderr, fmt, bc_errs[bc_err_ids[s]], bc_err_msgs[s]);
7016 if (msg) fprintf(stderr, " %s\n", msg);
7017 fprintf(stderr, " %s", file);
7018 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007019
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007020 return s * (!G.ttyin && !!p);
Gavin Howard01055ba2018-11-03 11:00:21 -06007021}
7022
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007023static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007024{
Gavin Howard01055ba2018-11-03 11:00:21 -06007025 BcVec v;
7026 char *env_args = getenv(bc_args_env_name), *buf;
7027
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007028 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06007029
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007030 G.env_args = xstrdup(env_args);
7031 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06007032
7033 bc_vec_init(&v, sizeof(char *), NULL);
7034 bc_vec_push(&v, &bc_args_env_name);
7035
7036 while (*buf != 0) {
7037 if (!isspace(*buf)) {
7038 bc_vec_push(&v, &buf);
7039 while (*buf != 0 && !isspace(*buf)) ++buf;
7040 if (*buf != 0) (*(buf++)) = '\0';
7041 }
7042 else
7043 ++buf;
7044 }
7045
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007046 bc_args((int) v.len, (char **) v.v, &G.flags, &G.files);
Gavin Howard01055ba2018-11-03 11:00:21 -06007047
7048 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007049}
7050#endif // ENABLE_BC
7051
7052static size_t bc_vm_envLen(const char *var)
7053{
7054 char *lenv = getenv(var);
7055 size_t i, len = BC_NUM_PRINT_WIDTH;
7056 int num;
7057
7058 if (!lenv) return len;
7059
7060 len = strlen(lenv);
7061
7062 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
7063 if (num) {
7064 len = (size_t) atoi(lenv) - 1;
7065 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
7066 }
7067 else
7068 len = BC_NUM_PRINT_WIDTH;
7069
7070 return len;
7071}
7072
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007073static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06007074{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007075 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06007076
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007077 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007078 if (s) return s;
7079
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007080 while (G.prs.l.t.t != BC_LEX_EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007081
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007082 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007083
7084 if (s == BC_STATUS_LIMITS) {
7085
Denys Vlasenko00d77792018-11-30 23:13:42 +01007086 bb_putchar('\n');
7087 printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
7088 printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
7089 printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
7090 printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
7091 printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
7092 printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
7093 printf("Max Exponent = %lu\n", BC_MAX_EXP);
7094 printf("Number of Vars = %lu\n", BC_MAX_VARS);
7095 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06007096
7097 s = BC_STATUS_SUCCESS;
7098 }
7099 else {
7100 if (s == BC_STATUS_QUIT) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007101 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007102 if (s) return s;
7103 }
7104 }
7105
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007106 if (BC_PARSE_CAN_EXEC(&G.prs)) {
7107 s = bc_program_exec(&G.prog);
7108 if (!s && G.tty) fflush(stdout);
Gavin Howard01055ba2018-11-03 11:00:21 -06007109 if (s && s != BC_STATUS_QUIT)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007110 s = bc_vm_error(bc_program_reset(&G.prog, s), G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007111 }
7112
7113 return s;
7114}
7115
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007116static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06007117{
7118 BcStatus s;
7119 char *data;
7120 BcFunc *main_func;
7121 BcInstPtr *ip;
7122
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007123 G.prog.file = file;
Gavin Howard01055ba2018-11-03 11:00:21 -06007124 s = bc_read_file(file, &data);
7125 if (s) return bc_vm_error(s, file, 0);
7126
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007127 bc_lex_file(&G.prs.l, file);
7128 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06007129 if (s) goto err;
7130
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007131 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
7132 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007133
7134 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
7135
7136err:
7137 free(data);
7138 return s;
7139}
7140
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007141static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007142{
7143 BcStatus s = BC_STATUS_SUCCESS;
7144 BcVec buf, buffer;
7145 char c;
7146 size_t len, i, str = 0;
7147 bool comment = false, notend;
7148
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007149 G.prog.file = bc_program_stdin_name;
7150 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06007151
7152 bc_vec_init(&buffer, sizeof(char), NULL);
7153 bc_vec_init(&buf, sizeof(char), NULL);
7154 bc_vec_pushByte(&buffer, '\0');
7155
7156 // This loop is complex because the vm tries not to send any lines that end
7157 // with a backslash to the parser. The reason for that is because the parser
7158 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7159 // case, and for strings and comments, the parser will expect more stuff.
7160 for (s = bc_read_line(&buf, ">>> "); !s; s = bc_read_line(&buf, ">>> ")) {
7161
7162 char *string = buf.v;
7163
7164 len = buf.len - 1;
7165
7166 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007167 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007168 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007169 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007170 str += 1;
7171 }
7172 else if (len > 1 || comment) {
7173
7174 for (i = 0; i < len; ++i) {
7175
7176 notend = len > i + 1;
7177 c = string[i];
7178
7179 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007180 if (G.sbgn == G.send)
7181 str ^= c == G.sbgn;
7182 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007183 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007184 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007185 str += 1;
7186 }
7187
7188 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7189 comment = true;
7190 break;
7191 }
7192 else if (c == '*' && notend && comment && string[i + 1] == '/')
7193 comment = false;
7194 }
7195
7196 if (str || comment || string[len - 2] == '\\') {
7197 bc_vec_concat(&buffer, buf.v);
7198 continue;
7199 }
7200 }
7201
7202 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007203 s = bc_vm_process(buffer.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007204 if (s) goto err;
7205
7206 bc_vec_npop(&buffer, buffer.len);
7207 }
7208
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007209 if (s == BC_STATUS_BIN_FILE) s = bc_vm_error(s, G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007210
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007211 // INPUT_EOF will always happen when stdin is
Gavin Howard01055ba2018-11-03 11:00:21 -06007212 // closed. It's not a problem in that case.
Denys Vlasenko00d77792018-11-30 23:13:42 +01007213 if (s == BC_STATUS_INPUT_EOF || s == BC_STATUS_QUIT)
7214 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06007215
7216 if (str)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007217 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7218 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007219 else if (comment)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007220 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7221 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007222
7223err:
7224 bc_vec_free(&buf);
7225 bc_vec_free(&buffer);
7226 return s;
7227}
7228
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007229static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007230{
7231 BcStatus s = BC_STATUS_SUCCESS;
7232 size_t i;
7233
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007234#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007235 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007236
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007237 bc_lex_file(&G.prs.l, bc_lib_name);
7238 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007239
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007240 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007241
7242 if (s) return s;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007243 s = bc_program_exec(&G.prog);
Gavin Howard01055ba2018-11-03 11:00:21 -06007244 if (s) return s;
7245 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007246#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007247
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007248 for (i = 0; !s && i < G.files.len; ++i)
7249 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Gavin Howard01055ba2018-11-03 11:00:21 -06007250 if (s && s != BC_STATUS_QUIT) return s;
7251
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007252 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7253 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007254
Denys Vlasenko00d77792018-11-30 23:13:42 +01007255 if (s == BC_STATUS_QUIT)
7256 s = BC_STATUS_SUCCESS;
7257 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007258}
7259
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007260static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007261{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007262 bc_vec_free(&G.files);
7263 bc_program_free(&G.prog);
7264 bc_parse_free(&G.prs);
7265 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007266}
7267
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007268static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007269{
Gavin Howard01055ba2018-11-03 11:00:21 -06007270 size_t len = bc_vm_envLen(env_len);
7271#if ENABLE_FEATURE_BC_SIGNALS
7272 struct sigaction sa;
7273
7274 sigemptyset(&sa.sa_mask);
7275 sa.sa_handler = bc_vm_sig;
7276 sa.sa_flags = 0;
7277 sigaction(SIGINT, &sa, NULL);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007278#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007279
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007280 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007281
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007282#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007283 G.flags |= BC_FLAG_S * IS_BC * (getenv("POSIXLY_CORRECT") != NULL);
7284 if (IS_BC) bc_vm_envArgs();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007285#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007286
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007287 bc_program_init(&G.prog, len, G.init, G.exp);
7288 G.init(&G.prs, &G.prog, BC_PROG_MAIN);
Gavin Howard01055ba2018-11-03 11:00:21 -06007289}
7290
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007291static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007292 const char *env_len)
7293{
7294 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007295
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007296 bc_vm_init(env_len);
7297 bc_args(argc, argv, &G.flags, &G.files);
Gavin Howard01055ba2018-11-03 11:00:21 -06007298
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007299 G.ttyin = isatty(0);
7300 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007301
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007302 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7303 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007304
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007305 bc_vm_free();
Gavin Howard01055ba2018-11-03 11:00:21 -06007306 return st;
7307}
7308
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007309#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007310int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7311int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007312{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007313 INIT_G();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007314# if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007315 G.sig_msg = "\ninterrupt (type \"quit\" to exit)\n";
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007316# endif
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007317 G.init = bc_parse_init;
7318 G.exp = bc_parse_expression;
7319 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007320
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007321 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007322}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007323#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007324
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007325#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007326int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7327int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007328{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007329 INIT_G();
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007330# if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007331 G.sig_msg = "\ninterrupt (type \"q\" to exit)\n";
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007332# endif
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007333 G.init = dc_parse_init;
7334 G.exp = dc_parse_expr;
7335 G.sbgn = '[';
7336 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007337
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007338 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007339}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007340#endif