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