blob: d208a0cc6aee29eb7e1abe40eb86e8aebc125088 [file] [log] [blame]
Gavin Howard01055ba2018-11-03 11:00:21 -06001/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
5 *
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
8 */
9//config:config BC
10//config: bool "bc (45 kb; 49 kb when combined with dc)"
11//config: default y
12//config: help
13//config: bc is a command-line, arbitrary-precision calculator with a
14//config: Turing-complete language. See the GNU bc manual
15//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17//config: for details.
18//config:
19//config: This bc has four differences to the GNU bc:
20//config:
21//config: 1) The period (.) can also be used as a shortcut for "last", as in
22//config: the BSD bc.
23//config: 2) Arrays are copied before being passed as arguments to
24//config: functions. This behavior is required by the bc spec.
25//config: 3) Arrays can be passed to the builtin "length" function to get
26//config: the number of elements currently in the array. The following
27//config: example prints "1":
28//config:
29//config: a[0] = 0
30//config: length(a[])
31//config:
32//config: 4) The precedence of the boolean "not" operator (!) is equal to
33//config: that of the unary minus (-), or negation, operator. This still
34//config: allows POSIX-compliant scripts to work while somewhat
35//config: preserving expected behavior (versus C) and making parsing
36//config: easier.
37//config:
38//config: Options:
39//config:
40//config: -i --interactive force interactive mode
41//config: -l --mathlib use predefined math routines:
42//config:
43//config: s(expr) = sine of expr in radians
44//config: c(expr) = cosine of expr in radians
45//config: a(expr) = arctangent of expr, returning
46//config: radians
47//config: l(expr) = natural log of expr
48//config: e(expr) = raises e to the power of expr
49//config: j(n, x) = Bessel function of integer order
50//config: n of x
51//config:
52//config: -q --quiet don't print version and copyright.
53//config: -s --standard error if any non-POSIX extensions are used.
54//config: -w --warn warn if any non-POSIX extensions are used.
55//config: -v --version print version and copyright and exit.
56//config:
57//config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
58//config: enabled.
59//config:
60//config:config DC
61//config: bool "dc (38 kb; 49 kb when combined with bc)"
62//config: default y
63//config: help
64//config: dc is a reverse-polish notation command-line calculator which
65//config: supports unlimited precision arithmetic. See the FreeBSD man page
66//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68//config: for details.
69//config:
70//config: This dc has a few differences from the two above:
71//config:
72//config: 1) When printing a byte stream (command "P"), this bc follows what
73//config: the FreeBSD dc does.
74//config: 2) This dc implements the GNU extensions for divmod ("~") and
75//config: modular exponentiation ("|").
76//config: 3) This dc implements all FreeBSD extensions, except for "J" and
77//config: "M".
78//config: 4) Like the FreeBSD dc, this dc supports extended registers.
79//config: However, they are implemented differently. When it encounters
80//config: whitespace where a register should be, it skips the whitespace.
81//config: If the character following is not a lowercase letter, an error
82//config: is issued. Otherwise, the register name is parsed by the
83//config: following regex:
84//config:
85//config: [a-z][a-z0-9_]*
86//config:
87//config: This generally means that register names will be surrounded by
88//config: whitespace.
89//config:
90//config: Examples:
91//config:
92//config: l idx s temp L index S temp2 < do_thing
93//config:
94//config: Also note that, like the FreeBSD dc, extended registers are not
95//config: allowed unless the "-x" option is given.
96//config:
97//config:config FEATURE_BC_SIGNALS
98//config: bool "Enable bc/dc signal handling"
99//config: default y
100//config: depends on BC || DC
101//config: help
102//config: Enable signal handling for bc and dc.
103//config:
104//config:config FEATURE_BC_LONG_OPTIONS
105//config: bool "Enable bc/dc long options"
106//config: default y
107//config: depends on BC || DC
108//config: help
109//config: Enable long options for bc and dc.
110
111//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
113
114//kbuild:lib-$(CONFIG_BC) += bc.o
115//kbuild:lib-$(CONFIG_DC) += bc.o
116
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100117//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600118//usage:#define bc_trivial_usage
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100119//usage: "[-sqli] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600120//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100121//usage:#define bc_full_usage "\n"
122//usage: "\nArbitrary precision calculator"
123//usage: "\n"
124//usage: "\n -i Interactive"
125//usage: "\n -l Load standard math library"
126//usage: "\n -s Be POSIX compatible"
127//usage: "\n -q Quiet"
128//usage: "\n -w Warn if extensions are used"
129///////: "\n -v Version"
Gavin Howard01055ba2018-11-03 11:00:21 -0600130//usage:
131//usage:#define bc_example_usage
132//usage: "3 + 4.129\n"
133//usage: "1903 - 2893\n"
134//usage: "-129 * 213.28935\n"
135//usage: "12 / -1932\n"
136//usage: "12 % 12\n"
137//usage: "34 ^ 189\n"
138//usage: "scale = 13\n"
139//usage: "ibase = 2\n"
140//usage: "obase = A\n"
141//usage:
142//usage:#define dc_trivial_usage
143//usage: "EXPRESSION..."
144//usage:
145//usage:#define dc_full_usage "\n\n"
146//usage: "Tiny RPN calculator. Operations:\n"
147//usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148//usage: "modular exponentiation,\n"
149//usage: "p - print top of the stack (without popping),\n"
150//usage: "f - print entire stack,\n"
151//usage: "k - pop the value and set the precision.\n"
152//usage: "i - pop the value and set input radix.\n"
153//usage: "o - pop the value and set output radix.\n"
154//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
155//usage:
156//usage:#define dc_example_usage
157//usage: "$ dc 2 2 + p\n"
158//usage: "4\n"
159//usage: "$ dc 8 8 \\* 2 2 + / p\n"
160//usage: "16\n"
161//usage: "$ dc 0 1 and p\n"
162//usage: "0\n"
163//usage: "$ dc 0 1 or p\n"
164//usage: "1\n"
165//usage: "$ echo 72 9 div 8 mul p | dc\n"
166//usage: "64\n"
167
168#include "libbb.h"
169
170typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100171 BC_STATUS_SUCCESS = 0,
172 BC_STATUS_FAILURE = 1,
173 BC_STATUS_PARSE_EMPTY_EXP = 2, // bc_parse_expr() uses this
Gavin Howard01055ba2018-11-03 11:00:21 -0600174} BcStatus;
175
Gavin Howard01055ba2018-11-03 11:00:21 -0600176#define BC_VEC_INVALID_IDX ((size_t) -1)
177#define BC_VEC_START_CAP (1 << 5)
178
179typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600180
181typedef struct BcVec {
182 char *v;
183 size_t len;
184 size_t cap;
185 size_t size;
186 BcVecFree dtor;
187} BcVec;
188
189#define bc_vec_pop(v) (bc_vec_npop((v), 1))
190#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
191
192#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
193
Gavin Howard01055ba2018-11-03 11:00:21 -0600194typedef signed char BcDig;
195
196typedef struct BcNum {
197 BcDig *restrict num;
198 size_t rdx;
199 size_t len;
200 size_t cap;
201 bool neg;
202} BcNum;
203
204#define BC_NUM_MIN_BASE ((unsigned long) 2)
205#define BC_NUM_MAX_IBASE ((unsigned long) 16)
206#define BC_NUM_DEF_SIZE (16)
207#define BC_NUM_PRINT_WIDTH (69)
208
209#define BC_NUM_KARATSUBA_LEN (32)
210
211#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
212#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
213#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
214#define BC_NUM_AREQ(a, b) \
215 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
216#define BC_NUM_MREQ(a, b, scale) \
217 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
218
219typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
220typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
221
222static void bc_num_init(BcNum *n, size_t req);
223static void bc_num_expand(BcNum *n, size_t req);
224static void bc_num_copy(BcNum *d, BcNum *s);
225static void bc_num_free(void *num);
226
227static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100228static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600229
230static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
231static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
232static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
233static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
234static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
235static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
236static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
237static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
238 size_t scale);
239
240typedef enum BcInst {
241
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100242#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600243 BC_INST_INC_PRE,
244 BC_INST_DEC_PRE,
245 BC_INST_INC_POST,
246 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100247#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600248
249 BC_INST_NEG,
250
251 BC_INST_POWER,
252 BC_INST_MULTIPLY,
253 BC_INST_DIVIDE,
254 BC_INST_MODULUS,
255 BC_INST_PLUS,
256 BC_INST_MINUS,
257
258 BC_INST_REL_EQ,
259 BC_INST_REL_LE,
260 BC_INST_REL_GE,
261 BC_INST_REL_NE,
262 BC_INST_REL_LT,
263 BC_INST_REL_GT,
264
265 BC_INST_BOOL_NOT,
266 BC_INST_BOOL_OR,
267 BC_INST_BOOL_AND,
268
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100269#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600270 BC_INST_ASSIGN_POWER,
271 BC_INST_ASSIGN_MULTIPLY,
272 BC_INST_ASSIGN_DIVIDE,
273 BC_INST_ASSIGN_MODULUS,
274 BC_INST_ASSIGN_PLUS,
275 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100276#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600277 BC_INST_ASSIGN,
278
279 BC_INST_NUM,
280 BC_INST_VAR,
281 BC_INST_ARRAY_ELEM,
282 BC_INST_ARRAY,
283
284 BC_INST_SCALE_FUNC,
285 BC_INST_IBASE,
286 BC_INST_SCALE,
287 BC_INST_LAST,
288 BC_INST_LENGTH,
289 BC_INST_READ,
290 BC_INST_OBASE,
291 BC_INST_SQRT,
292
293 BC_INST_PRINT,
294 BC_INST_PRINT_POP,
295 BC_INST_STR,
296 BC_INST_PRINT_STR,
297
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100298#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600299 BC_INST_JUMP,
300 BC_INST_JUMP_ZERO,
301
302 BC_INST_CALL,
303
304 BC_INST_RET,
305 BC_INST_RET0,
306
307 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100308#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600309
310 BC_INST_POP,
311 BC_INST_POP_EXEC,
312
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100313#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600314 BC_INST_MODEXP,
315 BC_INST_DIVMOD,
316
317 BC_INST_EXECUTE,
318 BC_INST_EXEC_COND,
319
320 BC_INST_ASCIIFY,
321 BC_INST_PRINT_STREAM,
322
323 BC_INST_PRINT_STACK,
324 BC_INST_CLEAR_STACK,
325 BC_INST_STACK_LEN,
326 BC_INST_DUPLICATE,
327 BC_INST_SWAP,
328
329 BC_INST_LOAD,
330 BC_INST_PUSH_VAR,
331 BC_INST_PUSH_TO_VAR,
332
333 BC_INST_QUIT,
334 BC_INST_NQUIT,
335
336 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100337#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600338
339} BcInst;
340
341typedef struct BcId {
342 char *name;
343 size_t idx;
344} BcId;
345
346typedef struct BcFunc {
347 BcVec code;
348 BcVec labels;
349 size_t nparams;
350 BcVec autos;
351} BcFunc;
352
353typedef enum BcResultType {
354
355 BC_RESULT_TEMP,
356
357 BC_RESULT_VAR,
358 BC_RESULT_ARRAY_ELEM,
359 BC_RESULT_ARRAY,
360
361 BC_RESULT_STR,
362
363 BC_RESULT_IBASE,
364 BC_RESULT_SCALE,
365 BC_RESULT_LAST,
366
367 // These are between to calculate ibase, obase, and last from instructions.
368 BC_RESULT_CONSTANT,
369 BC_RESULT_ONE,
370
371 BC_RESULT_OBASE,
372
373} BcResultType;
374
375typedef union BcResultData {
376 BcNum n;
377 BcVec v;
378 BcId id;
379} BcResultData;
380
381typedef struct BcResult {
382 BcResultType t;
383 BcResultData d;
384} BcResult;
385
386typedef struct BcInstPtr {
387 size_t func;
388 size_t idx;
389 size_t len;
390} BcInstPtr;
391
392static void bc_array_expand(BcVec *a, size_t len);
393static int bc_id_cmp(const void *e1, const void *e2);
394
395// BC_LEX_NEG is not used in lexing; it is only for parsing.
396typedef enum BcLexType {
397
398 BC_LEX_EOF,
399 BC_LEX_INVALID,
400
401 BC_LEX_OP_INC,
402 BC_LEX_OP_DEC,
403
404 BC_LEX_NEG,
405
406 BC_LEX_OP_POWER,
407 BC_LEX_OP_MULTIPLY,
408 BC_LEX_OP_DIVIDE,
409 BC_LEX_OP_MODULUS,
410 BC_LEX_OP_PLUS,
411 BC_LEX_OP_MINUS,
412
413 BC_LEX_OP_REL_EQ,
414 BC_LEX_OP_REL_LE,
415 BC_LEX_OP_REL_GE,
416 BC_LEX_OP_REL_NE,
417 BC_LEX_OP_REL_LT,
418 BC_LEX_OP_REL_GT,
419
420 BC_LEX_OP_BOOL_NOT,
421 BC_LEX_OP_BOOL_OR,
422 BC_LEX_OP_BOOL_AND,
423
424 BC_LEX_OP_ASSIGN_POWER,
425 BC_LEX_OP_ASSIGN_MULTIPLY,
426 BC_LEX_OP_ASSIGN_DIVIDE,
427 BC_LEX_OP_ASSIGN_MODULUS,
428 BC_LEX_OP_ASSIGN_PLUS,
429 BC_LEX_OP_ASSIGN_MINUS,
430 BC_LEX_OP_ASSIGN,
431
432 BC_LEX_NLINE,
433 BC_LEX_WHITESPACE,
434
435 BC_LEX_LPAREN,
436 BC_LEX_RPAREN,
437
438 BC_LEX_LBRACKET,
439 BC_LEX_COMMA,
440 BC_LEX_RBRACKET,
441
442 BC_LEX_LBRACE,
443 BC_LEX_SCOLON,
444 BC_LEX_RBRACE,
445
446 BC_LEX_STR,
447 BC_LEX_NAME,
448 BC_LEX_NUMBER,
449
450 BC_LEX_KEY_AUTO,
451 BC_LEX_KEY_BREAK,
452 BC_LEX_KEY_CONTINUE,
453 BC_LEX_KEY_DEFINE,
454 BC_LEX_KEY_ELSE,
455 BC_LEX_KEY_FOR,
456 BC_LEX_KEY_HALT,
457 BC_LEX_KEY_IBASE,
458 BC_LEX_KEY_IF,
459 BC_LEX_KEY_LAST,
460 BC_LEX_KEY_LENGTH,
461 BC_LEX_KEY_LIMITS,
462 BC_LEX_KEY_OBASE,
463 BC_LEX_KEY_PRINT,
464 BC_LEX_KEY_QUIT,
465 BC_LEX_KEY_READ,
466 BC_LEX_KEY_RETURN,
467 BC_LEX_KEY_SCALE,
468 BC_LEX_KEY_SQRT,
469 BC_LEX_KEY_WHILE,
470
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100471#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_EQ_NO_REG,
473 BC_LEX_OP_MODEXP,
474 BC_LEX_OP_DIVMOD,
475
476 BC_LEX_COLON,
477 BC_LEX_ELSE,
478 BC_LEX_EXECUTE,
479 BC_LEX_PRINT_STACK,
480 BC_LEX_CLEAR_STACK,
481 BC_LEX_STACK_LEVEL,
482 BC_LEX_DUPLICATE,
483 BC_LEX_SWAP,
484 BC_LEX_POP,
485
486 BC_LEX_ASCIIFY,
487 BC_LEX_PRINT_STREAM,
488
489 BC_LEX_STORE_IBASE,
490 BC_LEX_STORE_SCALE,
491 BC_LEX_LOAD,
492 BC_LEX_LOAD_POP,
493 BC_LEX_STORE_PUSH,
494 BC_LEX_STORE_OBASE,
495 BC_LEX_PRINT_POP,
496 BC_LEX_NQUIT,
497 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100498#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600499
500} BcLexType;
501
502struct BcLex;
503typedef BcStatus (*BcLexNext)(struct BcLex *);
504
505typedef struct BcLex {
506
507 const char *buf;
508 size_t i;
509 size_t line;
510 const char *f;
511 size_t len;
512 bool newline;
513
514 struct {
515 BcLexType t;
516 BcLexType last;
517 BcVec v;
518 } t;
519
520 BcLexNext next;
521
522} BcLex;
523
524#define BC_PARSE_STREND ((char) UCHAR_MAX)
525
526#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
527#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100528 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600529
530#define BC_PARSE_REL (1 << 0)
531#define BC_PARSE_PRINT (1 << 1)
532#define BC_PARSE_NOCALL (1 << 2)
533#define BC_PARSE_NOREAD (1 << 3)
534#define BC_PARSE_ARRAY (1 << 4)
535
536#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
537#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
538
539#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
540#define BC_PARSE_FUNC_INNER(parse) \
541 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
542
543#define BC_PARSE_FLAG_FUNC (1 << 1)
544#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
545
546#define BC_PARSE_FLAG_BODY (1 << 2)
547#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
548
549#define BC_PARSE_FLAG_LOOP (1 << 3)
550#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
551
552#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
553#define BC_PARSE_LOOP_INNER(parse) \
554 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
555
556#define BC_PARSE_FLAG_IF (1 << 5)
557#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
558
559#define BC_PARSE_FLAG_ELSE (1 << 6)
560#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
561
562#define BC_PARSE_FLAG_IF_END (1 << 7)
563#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
564
565#define BC_PARSE_CAN_EXEC(parse) \
566 (!(BC_PARSE_TOP_FLAG(parse) & \
567 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
568 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
569 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
570
571typedef struct BcOp {
572 char prec;
573 bool left;
574} BcOp;
575
576typedef struct BcParseNext {
577 uint32_t len;
578 BcLexType tokens[4];
579} BcParseNext;
580
581#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
582#define BC_PARSE_NEXT(a, ...) \
583 { \
584 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
585 }
586
587struct BcParse;
588
589struct BcProgram;
590
Gavin Howard01055ba2018-11-03 11:00:21 -0600591typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600592
593typedef struct BcParse {
594
595 BcParseParse parse;
596
597 BcLex l;
598
599 BcVec flags;
600
601 BcVec exits;
602 BcVec conds;
603
604 BcVec ops;
605
Gavin Howard01055ba2018-11-03 11:00:21 -0600606 BcFunc *func;
607 size_t fidx;
608
609 size_t nbraces;
610 bool auto_part;
611
612} BcParse;
613
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100614#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600615
Gavin Howard01055ba2018-11-03 11:00:21 -0600616typedef struct BcLexKeyword {
617 const char name[9];
618 const char len;
619 const bool posix;
620} BcLexKeyword;
621
622#define BC_LEX_KW_ENTRY(a, b, c) \
623 { \
624 .name = a, .len = (b), .posix = (c) \
625 }
626
627static BcStatus bc_lex_token(BcLex *l);
628
629#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
630#define BC_PARSE_LEAF(p, rparen) \
631 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
632 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
633
634// We can calculate the conversion between tokens and exprs by subtracting the
635// position of the first operator in the lex enum and adding the position of the
636// first in the expr enum. Note: This only works for binary operators.
637#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
638
Gavin Howard01055ba2018-11-03 11:00:21 -0600639static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
640
Denys Vlasenko00d77792018-11-30 23:13:42 +0100641#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600642
Denys Vlasenko00d77792018-11-30 23:13:42 +0100643#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600644
645#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
646
Gavin Howard01055ba2018-11-03 11:00:21 -0600647static BcStatus dc_lex_token(BcLex *l);
648
Gavin Howard01055ba2018-11-03 11:00:21 -0600649static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
650
651#endif // ENABLE_DC
652
653typedef struct BcProgram {
654
655 size_t len;
656 size_t scale;
657
658 BcNum ib;
659 size_t ib_t;
660 BcNum ob;
661 size_t ob_t;
662
663 BcNum hexb;
664
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100665#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600666 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100667#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600668
669 BcVec results;
670 BcVec stack;
671
672 BcVec fns;
673 BcVec fn_map;
674
675 BcVec vars;
676 BcVec var_map;
677
678 BcVec arrs;
679 BcVec arr_map;
680
681 BcVec strs;
682 BcVec consts;
683
684 const char *file;
685
686 BcNum last;
687 BcNum zero;
688 BcNum one;
689
690 size_t nchars;
691
Gavin Howard01055ba2018-11-03 11:00:21 -0600692} BcProgram;
693
694#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
695
696#define BC_PROG_MAIN (0)
697#define BC_PROG_READ (1)
698
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100699#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600700#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100701#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600702
703#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
704#define BC_PROG_NUM(r, n) \
705 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
706
707typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
708
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100709static void bc_program_addFunc(char *name, size_t *idx);
Denys Vlasenkod38af482018-12-04 19:11:02 +0100710static void bc_program_reset(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600711
712#define BC_FLAG_X (1 << 0)
713#define BC_FLAG_W (1 << 1)
714#define BC_FLAG_V (1 << 2)
715#define BC_FLAG_S (1 << 3)
716#define BC_FLAG_Q (1 << 4)
717#define BC_FLAG_L (1 << 5)
718#define BC_FLAG_I (1 << 6)
719
720#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
721#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
722
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100723#define BC_MAX_OBASE ((unsigned) 999)
724#define BC_MAX_DIM ((unsigned) INT_MAX)
725#define BC_MAX_SCALE ((unsigned) UINT_MAX)
726#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
727#define BC_MAX_NAME BC_MAX_STRING
728#define BC_MAX_NUM BC_MAX_STRING
729#define BC_MAX_EXP ((unsigned long) LONG_MAX)
730#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600731
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100732struct globals {
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100733 smallint ttyin;
734 smallint eof;
Gavin Howard01055ba2018-11-03 11:00:21 -0600735 char sbgn;
736 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600737
738 BcParse prs;
739 BcProgram prog;
740
Gavin Howard01055ba2018-11-03 11:00:21 -0600741 BcVec files;
742
743 char *env_args;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100744} FIX_ALIASING;
745#define G (*ptr_to_globals)
746#define INIT_G() do { \
747 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
748} while (0)
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100749#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
750#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
751#define G_exreg (ENABLE_DC && (option_mask32 & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100752#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600753
Gavin Howard01055ba2018-11-03 11:00:21 -0600754
Denys Vlasenko00d77792018-11-30 23:13:42 +0100755#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
756
Denys Vlasenko00d77792018-11-30 23:13:42 +0100757static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600758
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100759#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600760static const BcLexKeyword bc_lex_kws[20] = {
761 BC_LEX_KW_ENTRY("auto", 4, true),
762 BC_LEX_KW_ENTRY("break", 5, true),
763 BC_LEX_KW_ENTRY("continue", 8, false),
764 BC_LEX_KW_ENTRY("define", 6, true),
765 BC_LEX_KW_ENTRY("else", 4, false),
766 BC_LEX_KW_ENTRY("for", 3, true),
767 BC_LEX_KW_ENTRY("halt", 4, false),
768 BC_LEX_KW_ENTRY("ibase", 5, true),
769 BC_LEX_KW_ENTRY("if", 2, true),
770 BC_LEX_KW_ENTRY("last", 4, false),
771 BC_LEX_KW_ENTRY("length", 6, true),
772 BC_LEX_KW_ENTRY("limits", 6, false),
773 BC_LEX_KW_ENTRY("obase", 5, true),
774 BC_LEX_KW_ENTRY("print", 5, false),
775 BC_LEX_KW_ENTRY("quit", 4, true),
776 BC_LEX_KW_ENTRY("read", 4, false),
777 BC_LEX_KW_ENTRY("return", 6, true),
778 BC_LEX_KW_ENTRY("scale", 5, true),
779 BC_LEX_KW_ENTRY("sqrt", 4, true),
780 BC_LEX_KW_ENTRY("while", 5, true),
781};
782
783// This is an array that corresponds to token types. An entry is
784// true if the token is valid in an expression, false otherwise.
785static const bool bc_parse_exprs[] = {
786 false, false, true, true, true, true, true, true, true, true, true, true,
787 true, true, true, true, true, true, true, true, true, true, true, true,
788 true, true, true, false, false, true, true, false, false, false, false,
789 false, false, false, true, true, false, false, false, false, false, false,
790 false, true, false, true, true, true, true, false, false, true, false, true,
791 true, false,
792};
793
794// This is an array of data for operators that correspond to token types.
795static const BcOp bc_parse_ops[] = {
796 { 0, false }, { 0, false },
797 { 1, false },
798 { 2, false },
799 { 3, true }, { 3, true }, { 3, true },
800 { 4, true }, { 4, true },
801 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
802 { 1, false },
803 { 7, true }, { 7, true },
804 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
805 { 5, false }, { 5, false },
806};
807
808// These identify what tokens can come after expressions in certain cases.
809static const BcParseNext bc_parse_next_expr =
810 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
811static const BcParseNext bc_parse_next_param =
812 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
813static const BcParseNext bc_parse_next_print =
814 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
815static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
816static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
817static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
818static const BcParseNext bc_parse_next_read =
819 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
820#endif // ENABLE_BC
821
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100822#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600823static const BcLexType dc_lex_regs[] = {
824 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
825 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
826 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
827 BC_LEX_STORE_PUSH,
828};
829
830static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
831
832static const BcLexType dc_lex_tokens[] = {
833 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
834 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
835 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
836 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
837 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
838 BC_LEX_INVALID, BC_LEX_INVALID,
839 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
840 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
841 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
842 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
843 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
844 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
845 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
846 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
847 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
848 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
849 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
850 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
851 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
852 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
853 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
854 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
855 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
856 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
857 BC_LEX_INVALID
858};
859
860static const BcInst dc_parse_insts[] = {
861 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
862 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
863 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
864 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
865 BC_INST_INVALID, BC_INST_INVALID,
866 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
867 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
868 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
869 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
870 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
871 BC_INST_INVALID, BC_INST_INVALID,
872 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
873 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
874 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
875 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
876 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
877 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
878 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
879 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
880 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
881 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
882 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
883 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
884};
885#endif // ENABLE_DC
886
Gavin Howard01055ba2018-11-03 11:00:21 -0600887static const BcNumBinaryOp bc_program_ops[] = {
888 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
889};
890
891static const char bc_program_stdin_name[] = "<stdin>";
Gavin Howard01055ba2018-11-03 11:00:21 -0600892
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100893#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600894static const char *bc_lib_name = "gen/lib.bc";
895
896static const char bc_lib[] = {
897 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
898 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
899 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
900 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
901 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
902 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
903 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
904 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
905 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
906 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
907 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
908 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
909 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
910 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
911 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
912 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
913 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
914 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
915 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
916 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
917 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
918 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
919 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
920 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
921 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
922 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
923 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
924 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
925 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
926 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
927 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
928 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
929 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
930 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
931 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
932 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
933 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
934 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
935 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
936 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
937 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
938 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
939 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
940 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
941 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
942 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
943 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
944 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
945 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
946 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
947 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
948 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
949 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
950 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
951 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
952 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
953 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
954 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
955 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
956 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
957 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
958 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
959 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
960 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
961 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
962 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
963 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
964 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
965 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
966 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
967 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
968 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
969 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
970 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
971 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
972 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
973 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
974 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
975 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
976 117,114,110,40,97,42,114,47,49,41,10,125,10,0
977};
978#endif // ENABLE_BC
979
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100980static void fflush_and_check(void)
981{
982 fflush_all();
983 if (ferror(stdout) || ferror(stderr))
984 bb_perror_msg_and_die("output error");
985}
986
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100987static void quit(void) NORETURN;
988static void quit(void)
989{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100990 if (ferror(stdin))
991 bb_perror_msg_and_die("input error");
992 fflush_and_check();
993 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100994}
995
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100996static int bc_error(const char *fmt, ...)
997{
998 va_list p;
999
1000 va_start(p, fmt);
1001 bb_verror_msg(fmt, p, NULL);
1002 va_end(p);
1003 if (!G.ttyin)
1004 exit(1);
1005 return BC_STATUS_FAILURE;
1006}
1007
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001008static int bc_posix_error(const char *fmt, ...)
1009{
1010 va_list p;
1011
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001012 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001013 return BC_STATUS_SUCCESS;
1014
1015 va_start(p, fmt);
1016 bb_verror_msg(fmt, p, NULL);
1017 va_end(p);
1018
1019 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001020 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001021 return BC_STATUS_SUCCESS; // no, it's a warning
1022 if (!G.ttyin)
1023 exit(1);
1024 return BC_STATUS_FAILURE;
1025}
1026
Gavin Howard01055ba2018-11-03 11:00:21 -06001027static void bc_vec_grow(BcVec *v, size_t n)
1028{
1029 size_t cap = v->cap * 2;
1030 while (cap < v->len + n) cap *= 2;
1031 v->v = xrealloc(v->v, v->size * cap);
1032 v->cap = cap;
1033}
1034
1035static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1036{
1037 v->size = esize;
1038 v->cap = BC_VEC_START_CAP;
1039 v->len = 0;
1040 v->dtor = dtor;
1041 v->v = xmalloc(esize * BC_VEC_START_CAP);
1042}
1043
1044static void bc_vec_expand(BcVec *v, size_t req)
1045{
1046 if (v->cap < req) {
1047 v->v = xrealloc(v->v, v->size * req);
1048 v->cap = req;
1049 }
1050}
1051
1052static void bc_vec_npop(BcVec *v, size_t n)
1053{
1054 if (!v->dtor)
1055 v->len -= n;
1056 else {
1057 size_t len = v->len - n;
1058 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1059 }
1060}
1061
1062static void bc_vec_push(BcVec *v, const void *data)
1063{
1064 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1065 memmove(v->v + (v->size * v->len), data, v->size);
1066 v->len += 1;
1067}
1068
1069static void bc_vec_pushByte(BcVec *v, char data)
1070{
1071 bc_vec_push(v, &data);
1072}
1073
1074static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1075{
1076 if (idx == v->len)
1077 bc_vec_push(v, data);
1078 else {
1079
1080 char *ptr;
1081
1082 if (v->len == v->cap) bc_vec_grow(v, 1);
1083
1084 ptr = v->v + v->size * idx;
1085
1086 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1087 memmove(ptr, data, v->size);
1088 }
1089}
1090
1091static void bc_vec_string(BcVec *v, size_t len, const char *str)
1092{
1093 bc_vec_npop(v, v->len);
1094 bc_vec_expand(v, len + 1);
1095 memcpy(v->v, str, len);
1096 v->len = len;
1097
1098 bc_vec_pushByte(v, '\0');
1099}
1100
1101static void bc_vec_concat(BcVec *v, const char *str)
1102{
1103 size_t len;
1104
1105 if (v->len == 0) bc_vec_pushByte(v, '\0');
1106
1107 len = v->len + strlen(str);
1108
1109 if (v->cap < len) bc_vec_grow(v, len - v->len);
1110 strcat(v->v, str);
1111
1112 v->len = len;
1113}
1114
1115static void *bc_vec_item(const BcVec *v, size_t idx)
1116{
1117 return v->v + v->size * idx;
1118}
1119
1120static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1121{
1122 return v->v + v->size * (v->len - idx - 1);
1123}
1124
1125static void bc_vec_free(void *vec)
1126{
1127 BcVec *v = (BcVec *) vec;
1128 bc_vec_npop(v, v->len);
1129 free(v->v);
1130}
1131
1132static size_t bc_map_find(const BcVec *v, const void *ptr)
1133{
1134 size_t low = 0, high = v->len;
1135
1136 while (low < high) {
1137
1138 size_t mid = (low + high) / 2;
1139 BcId *id = bc_vec_item(v, mid);
1140 int result = bc_id_cmp(ptr, id);
1141
1142 if (result == 0)
1143 return mid;
1144 else if (result < 0)
1145 high = mid;
1146 else
1147 low = mid + 1;
1148 }
1149
1150 return low;
1151}
1152
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001153static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001154{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001155 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001156
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001157 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001158 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001159 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1160 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001161 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001162 bc_vec_pushAt(v, ptr, n);
1163 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001164}
1165
1166static size_t bc_map_index(const BcVec *v, const void *ptr)
1167{
1168 size_t i = bc_map_find(v, ptr);
1169 if (i >= v->len) return BC_VEC_INVALID_IDX;
1170 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1171}
1172
1173static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1174{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001175 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001176
Denys Vlasenko00d77792018-11-30 23:13:42 +01001177 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001178 int i;
1179 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001180
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001181 bad_chars = 0;
1182 bc_vec_npop(vec, vec->len);
1183
1184 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001185#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001186 if (bb_got_signal) { // ^C was pressed
1187 intr:
1188 bb_got_signal = 0; // resets G_interrupt to zero
1189 fputs(IS_BC
1190 ? "\ninterrupt (type \"quit\" to exit)\n"
1191 : "\ninterrupt (type \"q\" to exit)\n"
1192 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001193 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001194#endif
1195 if (G.ttyin && !G_posix)
1196 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001197
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001198#if ENABLE_FEATURE_BC_SIGNALS
1199 errno = 0;
1200#endif
1201 do {
1202 i = fgetc(stdin);
1203 if (i == EOF) {
1204#if ENABLE_FEATURE_BC_SIGNALS
1205 // Both conditions appear simultaneously, check both just in case
1206 if (errno == EINTR || bb_got_signal) {
1207 // ^C was pressed
1208 clearerr(stdin);
1209 goto intr;
1210 }
1211#endif
1212 if (ferror(stdin))
1213 quit(); // this emits error message
1214 G.eof = 1;
1215 // Note: EOF does not append '\n', therefore:
1216 // printf 'print 123\n' | bc - works
1217 // printf 'print 123' | bc - fails (syntax error)
1218 break;
1219 }
1220
1221 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1222 || i > 0x7e
1223 ) {
1224 // Bad chars on this line, ignore entire line
1225 bc_error("illegal character 0x%02x", i);
1226 bad_chars = 1;
1227 }
1228 c = (char) i;
1229 bc_vec_push(vec, &c);
1230 } while (i != '\n');
1231 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001232
1233 bc_vec_pushByte(vec, '\0');
1234
1235 return BC_STATUS_SUCCESS;
1236}
1237
Denys Vlasenkodf515392018-12-02 19:27:48 +01001238static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001239{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001240 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001241 size_t size = ((size_t) -1);
1242 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001243
Denys Vlasenkodf515392018-12-02 19:27:48 +01001244 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001245
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001246 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001247 char c = buf[i];
1248 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1249 || c > 0x7e
1250 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001251 free(buf);
1252 buf = NULL;
1253 break;
1254 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001255 }
1256
Denys Vlasenkodf515392018-12-02 19:27:48 +01001257 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001258}
1259
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001260static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001261{
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001262 unsigned opts;
Gavin Howard01055ba2018-11-03 11:00:21 -06001263 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001264
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001265 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001266#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001267 opts = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001268 "extended-register\0" No_argument "x"
1269 "warn\0" No_argument "w"
1270 "version\0" No_argument "v"
1271 "standard\0" No_argument "s"
1272 "quiet\0" No_argument "q"
1273 "mathlib\0" No_argument "l"
1274 "interactive\0" No_argument "i"
1275 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001276#else
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001277 opts = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001278#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001279 if (getenv("POSIXLY_CORRECT"))
1280 option_mask32 |= BC_FLAG_S;
Gavin Howard01055ba2018-11-03 11:00:21 -06001281
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001282 if (opts & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001283 // should not be necessary, getopt32() handles this??
1284 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001285
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001286 for (i = optind; i < argc; ++i)
1287 bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001288}
1289
1290static void bc_num_setToZero(BcNum *n, size_t scale)
1291{
1292 n->len = 0;
1293 n->neg = false;
1294 n->rdx = scale;
1295}
1296
1297static void bc_num_zero(BcNum *n)
1298{
1299 bc_num_setToZero(n, 0);
1300}
1301
1302static void bc_num_one(BcNum *n)
1303{
1304 bc_num_setToZero(n, 0);
1305 n->len = 1;
1306 n->num[0] = 1;
1307}
1308
1309static void bc_num_ten(BcNum *n)
1310{
1311 bc_num_setToZero(n, 0);
1312 n->len = 2;
1313 n->num[0] = 0;
1314 n->num[1] = 1;
1315}
1316
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001317static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001318 size_t len)
1319{
1320 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001321 for (i = 0; i < len; ++i) {
1322 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001323 a[i + j++] += 10;
1324 a[i + j] -= 1;
1325 }
1326 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001327}
1328
1329static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1330{
1331 size_t i;
1332 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001333 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001334 return BC_NUM_NEG(i + 1, c < 0);
1335}
1336
1337static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1338{
1339 size_t i, min, a_int, b_int, diff;
1340 BcDig *max_num, *min_num;
1341 bool a_max, neg = false;
1342 ssize_t cmp;
1343
1344 if (a == b) return 0;
1345 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1346 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1347 if (a->neg) {
1348 if (b->neg)
1349 neg = true;
1350 else
1351 return -1;
1352 }
1353 else if (b->neg)
1354 return 1;
1355
1356 a_int = BC_NUM_INT(a);
1357 b_int = BC_NUM_INT(b);
1358 a_int -= b_int;
1359 a_max = (a->rdx > b->rdx);
1360
1361 if (a_int != 0) return (ssize_t) a_int;
1362
1363 if (a_max) {
1364 min = b->rdx;
1365 diff = a->rdx - b->rdx;
1366 max_num = a->num + diff;
1367 min_num = b->num;
1368 }
1369 else {
1370 min = a->rdx;
1371 diff = b->rdx - a->rdx;
1372 max_num = b->num + diff;
1373 min_num = a->num;
1374 }
1375
1376 cmp = bc_num_compare(max_num, min_num, b_int + min);
1377 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1378
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001379 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001380 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1381 }
1382
1383 return 0;
1384}
1385
1386static void bc_num_truncate(BcNum *n, size_t places)
1387{
1388 if (places == 0) return;
1389
1390 n->rdx -= places;
1391
1392 if (n->len != 0) {
1393 n->len -= places;
1394 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1395 }
1396}
1397
1398static void bc_num_extend(BcNum *n, size_t places)
1399{
1400 size_t len = n->len + places;
1401
1402 if (places != 0) {
1403
1404 if (n->cap < len) bc_num_expand(n, len);
1405
1406 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1407 memset(n->num, 0, sizeof(BcDig) * places);
1408
1409 n->len += places;
1410 n->rdx += places;
1411 }
1412}
1413
1414static void bc_num_clean(BcNum *n)
1415{
1416 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1417 if (n->len == 0)
1418 n->neg = false;
1419 else if (n->len < n->rdx)
1420 n->len = n->rdx;
1421}
1422
1423static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1424{
1425 if (n->rdx < scale)
1426 bc_num_extend(n, scale - n->rdx);
1427 else
1428 bc_num_truncate(n, n->rdx - scale);
1429
1430 bc_num_clean(n);
1431 if (n->len != 0) n->neg = !neg1 != !neg2;
1432}
1433
1434static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1435 BcNum *restrict b)
1436{
1437 if (idx < n->len) {
1438
1439 b->len = n->len - idx;
1440 a->len = idx;
1441 a->rdx = b->rdx = 0;
1442
1443 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1444 memcpy(a->num, n->num, idx * sizeof(BcDig));
1445 }
1446 else {
1447 bc_num_zero(b);
1448 bc_num_copy(a, n);
1449 }
1450
1451 bc_num_clean(a);
1452 bc_num_clean(b);
1453}
1454
1455static BcStatus bc_num_shift(BcNum *n, size_t places)
1456{
1457 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001458 if (places + n->len > BC_MAX_NUM)
1459 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06001460
1461 if (n->rdx >= places)
1462 n->rdx -= places;
1463 else {
1464 bc_num_extend(n, places - n->rdx);
1465 n->rdx = 0;
1466 }
1467
1468 bc_num_clean(n);
1469
1470 return BC_STATUS_SUCCESS;
1471}
1472
1473static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1474{
1475 BcNum one;
1476 BcDig num[2];
1477
1478 one.cap = 2;
1479 one.num = num;
1480 bc_num_one(&one);
1481
1482 return bc_num_div(&one, a, b, scale);
1483}
1484
1485static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1486{
1487 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1488 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1489 int carry, in;
1490
1491 // Because this function doesn't need to use scale (per the bc spec),
1492 // I am hijacking it to say whether it's doing an add or a subtract.
1493
1494 if (a->len == 0) {
1495 bc_num_copy(c, b);
1496 if (sub && c->len) c->neg = !c->neg;
1497 return BC_STATUS_SUCCESS;
1498 }
1499 else if (b->len == 0) {
1500 bc_num_copy(c, a);
1501 return BC_STATUS_SUCCESS;
1502 }
1503
1504 c->neg = a->neg;
1505 c->rdx = BC_MAX(a->rdx, b->rdx);
1506 min_rdx = BC_MIN(a->rdx, b->rdx);
1507 c->len = 0;
1508
1509 if (a->rdx > b->rdx) {
1510 diff = a->rdx - b->rdx;
1511 ptr = a->num;
1512 ptr_a = a->num + diff;
1513 ptr_b = b->num;
1514 }
1515 else {
1516 diff = b->rdx - a->rdx;
1517 ptr = b->num;
1518 ptr_a = a->num;
1519 ptr_b = b->num + diff;
1520 }
1521
1522 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1523
1524 ptr_c += diff;
1525 a_int = BC_NUM_INT(a);
1526 b_int = BC_NUM_INT(b);
1527
1528 if (a_int > b_int) {
1529 min_int = b_int;
1530 max = a_int;
1531 ptr = ptr_a;
1532 }
1533 else {
1534 min_int = a_int;
1535 max = b_int;
1536 ptr = ptr_b;
1537 }
1538
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001539 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001540 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1541 carry = in / 10;
1542 ptr_c[i] = (BcDig)(in % 10);
1543 }
1544
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001545 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001546 in = ((int) ptr[i]) + carry;
1547 carry = in / 10;
1548 ptr_c[i] = (BcDig)(in % 10);
1549 }
1550
1551 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1552
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001553 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001554}
1555
1556static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1557{
Gavin Howard01055ba2018-11-03 11:00:21 -06001558 ssize_t cmp;
1559 BcNum *minuend, *subtrahend;
1560 size_t start;
1561 bool aneg, bneg, neg;
1562
1563 // Because this function doesn't need to use scale (per the bc spec),
1564 // I am hijacking it to say whether it's doing an add or a subtract.
1565
1566 if (a->len == 0) {
1567 bc_num_copy(c, b);
1568 if (sub && c->len) c->neg = !c->neg;
1569 return BC_STATUS_SUCCESS;
1570 }
1571 else if (b->len == 0) {
1572 bc_num_copy(c, a);
1573 return BC_STATUS_SUCCESS;
1574 }
1575
1576 aneg = a->neg;
1577 bneg = b->neg;
1578 a->neg = b->neg = false;
1579
1580 cmp = bc_num_cmp(a, b);
1581
1582 a->neg = aneg;
1583 b->neg = bneg;
1584
1585 if (cmp == 0) {
1586 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1587 return BC_STATUS_SUCCESS;
1588 }
1589 else if (cmp > 0) {
1590 neg = a->neg;
1591 minuend = a;
1592 subtrahend = b;
1593 }
1594 else {
1595 neg = b->neg;
1596 if (sub) neg = !neg;
1597 minuend = b;
1598 subtrahend = a;
1599 }
1600
1601 bc_num_copy(c, minuend);
1602 c->neg = neg;
1603
1604 if (c->rdx < subtrahend->rdx) {
1605 bc_num_extend(c, subtrahend->rdx - c->rdx);
1606 start = 0;
1607 }
1608 else
1609 start = c->rdx - subtrahend->rdx;
1610
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001611 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001612
1613 bc_num_clean(c);
1614
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001615 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001616}
1617
1618static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1619 BcNum *restrict c)
1620{
1621 BcStatus s;
1622 int carry;
1623 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1624 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1625 bool aone = BC_NUM_ONE(a);
1626
Gavin Howard01055ba2018-11-03 11:00:21 -06001627 if (a->len == 0 || b->len == 0) {
1628 bc_num_zero(c);
1629 return BC_STATUS_SUCCESS;
1630 }
1631 else if (aone || BC_NUM_ONE(b)) {
1632 bc_num_copy(c, aone ? b : a);
1633 return BC_STATUS_SUCCESS;
1634 }
1635
1636 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1637 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1638 {
1639 bc_num_expand(c, a->len + b->len + 1);
1640
1641 memset(c->num, 0, sizeof(BcDig) * c->cap);
1642 c->len = carry = len = 0;
1643
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001644 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001645
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001646 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001647 int in = (int) c->num[i + j];
1648 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1649 carry = in / 10;
1650 c->num[i + j] = (BcDig)(in % 10);
1651 }
1652
1653 c->num[i + j] += (BcDig) carry;
1654 len = BC_MAX(len, i + j + !!carry);
1655 carry = 0;
1656 }
1657
1658 c->len = len;
1659
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001660 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001661 }
1662
1663 bc_num_init(&l1, max);
1664 bc_num_init(&h1, max);
1665 bc_num_init(&l2, max);
1666 bc_num_init(&h2, max);
1667 bc_num_init(&m1, max);
1668 bc_num_init(&m2, max);
1669 bc_num_init(&z0, max);
1670 bc_num_init(&z1, max);
1671 bc_num_init(&z2, max);
1672 bc_num_init(&temp, max + max);
1673
1674 bc_num_split(a, max2, &l1, &h1);
1675 bc_num_split(b, max2, &l2, &h2);
1676
1677 s = bc_num_add(&h1, &l1, &m1, 0);
1678 if (s) goto err;
1679 s = bc_num_add(&h2, &l2, &m2, 0);
1680 if (s) goto err;
1681
1682 s = bc_num_k(&h1, &h2, &z0);
1683 if (s) goto err;
1684 s = bc_num_k(&m1, &m2, &z1);
1685 if (s) goto err;
1686 s = bc_num_k(&l1, &l2, &z2);
1687 if (s) goto err;
1688
1689 s = bc_num_sub(&z1, &z0, &temp, 0);
1690 if (s) goto err;
1691 s = bc_num_sub(&temp, &z2, &z1, 0);
1692 if (s) goto err;
1693
1694 s = bc_num_shift(&z0, max2 * 2);
1695 if (s) goto err;
1696 s = bc_num_shift(&z1, max2);
1697 if (s) goto err;
1698 s = bc_num_add(&z0, &z1, &temp, 0);
1699 if (s) goto err;
1700 s = bc_num_add(&temp, &z2, c, 0);
1701
1702err:
1703 bc_num_free(&temp);
1704 bc_num_free(&z2);
1705 bc_num_free(&z1);
1706 bc_num_free(&z0);
1707 bc_num_free(&m2);
1708 bc_num_free(&m1);
1709 bc_num_free(&h2);
1710 bc_num_free(&l2);
1711 bc_num_free(&h1);
1712 bc_num_free(&l1);
1713 return s;
1714}
1715
1716static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1717{
1718 BcStatus s;
1719 BcNum cpa, cpb;
1720 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1721
1722 scale = BC_MAX(scale, a->rdx);
1723 scale = BC_MAX(scale, b->rdx);
1724 scale = BC_MIN(a->rdx + b->rdx, scale);
1725 maxrdx = BC_MAX(maxrdx, scale);
1726
1727 bc_num_init(&cpa, a->len);
1728 bc_num_init(&cpb, b->len);
1729
1730 bc_num_copy(&cpa, a);
1731 bc_num_copy(&cpb, b);
1732 cpa.neg = cpb.neg = false;
1733
1734 s = bc_num_shift(&cpa, maxrdx);
1735 if (s) goto err;
1736 s = bc_num_shift(&cpb, maxrdx);
1737 if (s) goto err;
1738 s = bc_num_k(&cpa, &cpb, c);
1739 if (s) goto err;
1740
1741 maxrdx += scale;
1742 bc_num_expand(c, c->len + maxrdx);
1743
1744 if (c->len < maxrdx) {
1745 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1746 c->len += maxrdx;
1747 }
1748
1749 c->rdx = maxrdx;
1750 bc_num_retireMul(c, scale, a->neg, b->neg);
1751
1752err:
1753 bc_num_free(&cpb);
1754 bc_num_free(&cpa);
1755 return s;
1756}
1757
1758static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1759{
1760 BcStatus s = BC_STATUS_SUCCESS;
1761 BcDig *n, *p, q;
1762 size_t len, end, i;
1763 BcNum cp;
1764 bool zero = true;
1765
1766 if (b->len == 0)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001767 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001768 else if (a->len == 0) {
1769 bc_num_setToZero(c, scale);
1770 return BC_STATUS_SUCCESS;
1771 }
1772 else if (BC_NUM_ONE(b)) {
1773 bc_num_copy(c, a);
1774 bc_num_retireMul(c, scale, a->neg, b->neg);
1775 return BC_STATUS_SUCCESS;
1776 }
1777
1778 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1779 bc_num_copy(&cp, a);
1780 len = b->len;
1781
1782 if (len > cp.len) {
1783 bc_num_expand(&cp, len + 2);
1784 bc_num_extend(&cp, len - cp.len);
1785 }
1786
1787 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1788 cp.rdx -= b->rdx;
1789 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1790
1791 if (b->rdx == b->len) {
1792 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1793 len -= i - 1;
1794 }
1795
1796 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1797
1798 // We want an extra zero in front to make things simpler.
1799 cp.num[cp.len++] = 0;
1800 end = cp.len - len;
1801
1802 bc_num_expand(c, cp.len);
1803
1804 bc_num_zero(c);
1805 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1806 c->rdx = cp.rdx;
1807 c->len = cp.len;
1808 p = b->num;
1809
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001810 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001811 n = cp.num + i;
1812 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001813 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001814 c->num[i] = q;
1815 }
1816
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001817 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001818 bc_num_free(&cp);
1819
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001820 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001821}
1822
1823static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1824 BcNum *restrict d, size_t scale, size_t ts)
1825{
1826 BcStatus s;
1827 BcNum temp;
1828 bool neg;
1829
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001830 if (b->len == 0)
1831 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06001832
1833 if (a->len == 0) {
1834 bc_num_setToZero(d, ts);
1835 return BC_STATUS_SUCCESS;
1836 }
1837
1838 bc_num_init(&temp, d->cap);
1839 bc_num_d(a, b, c, scale);
1840
1841 if (scale != 0) scale = ts;
1842
1843 s = bc_num_m(c, b, &temp, scale);
1844 if (s) goto err;
1845 s = bc_num_sub(a, &temp, d, scale);
1846 if (s) goto err;
1847
1848 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1849
1850 neg = d->neg;
1851 bc_num_retireMul(d, ts, a->neg, b->neg);
1852 d->neg = neg;
1853
1854err:
1855 bc_num_free(&temp);
1856 return s;
1857}
1858
1859static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1860{
1861 BcStatus s;
1862 BcNum c1;
1863 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1864
1865 bc_num_init(&c1, len);
1866 s = bc_num_r(a, b, &c1, c, scale, ts);
1867 bc_num_free(&c1);
1868
1869 return s;
1870}
1871
1872static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1873{
1874 BcStatus s = BC_STATUS_SUCCESS;
1875 BcNum copy;
1876 unsigned long pow;
1877 size_t i, powrdx, resrdx;
1878 bool neg, zero;
1879
Denys Vlasenko60cf7472018-12-04 20:05:28 +01001880 if (b->rdx) return bc_error("non integer number");
Gavin Howard01055ba2018-11-03 11:00:21 -06001881
1882 if (b->len == 0) {
1883 bc_num_one(c);
1884 return BC_STATUS_SUCCESS;
1885 }
1886 else if (a->len == 0) {
1887 bc_num_setToZero(c, scale);
1888 return BC_STATUS_SUCCESS;
1889 }
1890 else if (BC_NUM_ONE(b)) {
1891 if (!b->neg)
1892 bc_num_copy(c, a);
1893 else
1894 s = bc_num_inv(a, c, scale);
1895 return s;
1896 }
1897
1898 neg = b->neg;
1899 b->neg = false;
1900
1901 s = bc_num_ulong(b, &pow);
1902 if (s) return s;
1903
1904 bc_num_init(&copy, a->len);
1905 bc_num_copy(&copy, a);
1906
1907 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
1908
1909 b->neg = neg;
1910
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001911 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001912 powrdx <<= 1;
1913 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1914 if (s) goto err;
1915 }
1916
Gavin Howard01055ba2018-11-03 11:00:21 -06001917 bc_num_copy(c, &copy);
1918
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001919 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001920
1921 powrdx <<= 1;
1922 s = bc_num_mul(&copy, &copy, &copy, powrdx);
1923 if (s) goto err;
1924
1925 if (pow & 1) {
1926 resrdx += powrdx;
1927 s = bc_num_mul(c, &copy, c, resrdx);
1928 if (s) goto err;
1929 }
1930 }
1931
1932 if (neg) {
1933 s = bc_num_inv(c, c, scale);
1934 if (s) goto err;
1935 }
1936
Gavin Howard01055ba2018-11-03 11:00:21 -06001937 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1938
1939 // We can't use bc_num_clean() here.
1940 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1941 if (zero) bc_num_setToZero(c, scale);
1942
1943err:
1944 bc_num_free(&copy);
1945 return s;
1946}
1947
1948static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1949 BcNumBinaryOp op, size_t req)
1950{
1951 BcStatus s;
1952 BcNum num2, *ptr_a, *ptr_b;
1953 bool init = false;
1954
1955 if (c == a) {
1956 ptr_a = &num2;
1957 memcpy(ptr_a, c, sizeof(BcNum));
1958 init = true;
1959 }
1960 else
1961 ptr_a = a;
1962
1963 if (c == b) {
1964 ptr_b = &num2;
1965 if (c != a) {
1966 memcpy(ptr_b, c, sizeof(BcNum));
1967 init = true;
1968 }
1969 }
1970 else
1971 ptr_b = b;
1972
1973 if (init)
1974 bc_num_init(c, req);
1975 else
1976 bc_num_expand(c, req);
1977
1978 s = op(ptr_a, ptr_b, c, scale);
1979
1980 if (init) bc_num_free(&num2);
1981
1982 return s;
1983}
1984
1985static bool bc_num_strValid(const char *val, size_t base)
1986{
1987 BcDig b;
1988 bool small, radix = false;
1989 size_t i, len = strlen(val);
1990
1991 if (!len) return true;
1992
1993 small = base <= 10;
1994 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
1995
1996 for (i = 0; i < len; ++i) {
1997
1998 BcDig c = val[i];
1999
2000 if (c == '.') {
2001
2002 if (radix) return false;
2003
2004 radix = true;
2005 continue;
2006 }
2007
2008 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2009 return false;
2010 }
2011
2012 return true;
2013}
2014
2015static void bc_num_parseDecimal(BcNum *n, const char *val)
2016{
2017 size_t len, i;
2018 const char *ptr;
2019 bool zero = true;
2020
2021 for (i = 0; val[i] == '0'; ++i);
2022
2023 val += i;
2024 len = strlen(val);
2025 bc_num_zero(n);
2026
2027 if (len != 0) {
2028 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2029 bc_num_expand(n, len);
2030 }
2031
2032 ptr = strchr(val, '.');
2033
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002034 n->rdx = 0;
2035 if (ptr != NULL)
2036 n->rdx = (size_t)((val + len) - (ptr + 1));
Gavin Howard01055ba2018-11-03 11:00:21 -06002037
2038 if (!zero) {
2039 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2040 n->num[n->len] = val[i] - '0';
2041 }
2042}
2043
2044static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2045{
2046 BcStatus s;
2047 BcNum temp, mult, result;
2048 BcDig c = '\0';
2049 bool zero = true;
2050 unsigned long v;
2051 size_t i, digits, len = strlen(val);
2052
2053 bc_num_zero(n);
2054
2055 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2056 if (zero) return;
2057
2058 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2059 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2060
2061 for (i = 0; i < len; ++i) {
2062
2063 c = val[i];
2064 if (c == '.') break;
2065
2066 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2067
2068 s = bc_num_mul(n, base, &mult, 0);
2069 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002070 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002071 s = bc_num_add(&mult, &temp, n, 0);
2072 if (s) goto int_err;
2073 }
2074
2075 if (i == len) {
2076 c = val[i];
2077 if (c == 0) goto int_err;
2078 }
2079
2080 bc_num_init(&result, base->len);
2081 bc_num_zero(&result);
2082 bc_num_one(&mult);
2083
2084 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2085
2086 c = val[i];
2087 if (c == 0) break;
2088
2089 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2090
2091 s = bc_num_mul(&result, base, &result, 0);
2092 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002093 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002094 s = bc_num_add(&result, &temp, &result, 0);
2095 if (s) goto err;
2096 s = bc_num_mul(&mult, base, &mult, 0);
2097 if (s) goto err;
2098 }
2099
2100 s = bc_num_div(&result, &mult, &result, digits);
2101 if (s) goto err;
2102 s = bc_num_add(n, &result, n, digits);
2103 if (s) goto err;
2104
2105 if (n->len != 0) {
2106 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2107 }
2108 else
2109 bc_num_zero(n);
2110
2111err:
2112 bc_num_free(&result);
2113int_err:
2114 bc_num_free(&mult);
2115 bc_num_free(&temp);
2116}
2117
2118static void bc_num_printNewline(size_t *nchars, size_t line_len)
2119{
2120 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002121 bb_putchar('\\');
2122 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002123 *nchars = 0;
2124 }
2125}
2126
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002127#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002128static void bc_num_printChar(size_t num, size_t width, bool radix,
2129 size_t *nchars, size_t line_len)
2130{
2131 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002132 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002133 *nchars = *nchars + width;
2134}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002135#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002136
2137static void bc_num_printDigits(size_t num, size_t width, bool radix,
2138 size_t *nchars, size_t line_len)
2139{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002140 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002141
2142 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002143 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002144 ++(*nchars);
2145
2146 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002147 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2148 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002149
2150 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002151 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002152 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002153 dig = num / pow;
2154 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002155 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002156 }
2157}
2158
2159static void bc_num_printHex(size_t num, size_t width, bool radix,
2160 size_t *nchars, size_t line_len)
2161{
2162 if (radix) {
2163 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002164 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002165 *nchars += 1;
2166 }
2167
2168 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002169 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002170 *nchars = *nchars + width;
2171}
2172
2173static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2174{
2175 size_t i, rdx = n->rdx - 1;
2176
Denys Vlasenko00d77792018-11-30 23:13:42 +01002177 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002178 (*nchars) += n->neg;
2179
2180 for (i = n->len - 1; i < n->len; --i)
2181 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2182}
2183
2184static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2185 size_t *nchars, size_t len, BcNumDigitOp print)
2186{
2187 BcStatus s;
2188 BcVec stack;
2189 BcNum intp, fracp, digit, frac_len;
2190 unsigned long dig, *ptr;
2191 size_t i;
2192 bool radix;
2193
2194 if (n->len == 0) {
2195 print(0, width, false, nchars, len);
2196 return BC_STATUS_SUCCESS;
2197 }
2198
2199 bc_vec_init(&stack, sizeof(long), NULL);
2200 bc_num_init(&intp, n->len);
2201 bc_num_init(&fracp, n->rdx);
2202 bc_num_init(&digit, width);
2203 bc_num_init(&frac_len, BC_NUM_INT(n));
2204 bc_num_copy(&intp, n);
2205 bc_num_one(&frac_len);
2206
2207 bc_num_truncate(&intp, intp.rdx);
2208 s = bc_num_sub(n, &intp, &fracp, 0);
2209 if (s) goto err;
2210
2211 while (intp.len != 0) {
2212 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2213 if (s) goto err;
2214 s = bc_num_ulong(&digit, &dig);
2215 if (s) goto err;
2216 bc_vec_push(&stack, &dig);
2217 }
2218
2219 for (i = 0; i < stack.len; ++i) {
2220 ptr = bc_vec_item_rev(&stack, i);
2221 print(*ptr, width, false, nchars, len);
2222 }
2223
2224 if (!n->rdx) goto err;
2225
2226 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2227 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2228 if (s) goto err;
2229 s = bc_num_ulong(&fracp, &dig);
2230 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002231 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002232 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2233 if (s) goto err;
2234 print(dig, width, radix, nchars, len);
2235 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2236 if (s) goto err;
2237 }
2238
2239err:
2240 bc_num_free(&frac_len);
2241 bc_num_free(&digit);
2242 bc_num_free(&fracp);
2243 bc_num_free(&intp);
2244 bc_vec_free(&stack);
2245 return s;
2246}
2247
2248static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2249 size_t *nchars, size_t line_len)
2250{
2251 BcStatus s;
2252 size_t width, i;
2253 BcNumDigitOp print;
2254 bool neg = n->neg;
2255
Denys Vlasenko00d77792018-11-30 23:13:42 +01002256 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002257 (*nchars) += neg;
2258
2259 n->neg = false;
2260
2261 if (base_t <= BC_NUM_MAX_IBASE) {
2262 width = 1;
2263 print = bc_num_printHex;
2264 }
2265 else {
2266 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2267 print = bc_num_printDigits;
2268 }
2269
2270 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2271 n->neg = neg;
2272
2273 return s;
2274}
2275
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002276#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002277static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2278{
2279 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2280}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002281#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002282
2283static void bc_num_init(BcNum *n, size_t req)
2284{
2285 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2286 memset(n, 0, sizeof(BcNum));
2287 n->num = xmalloc(req);
2288 n->cap = req;
2289}
2290
2291static void bc_num_expand(BcNum *n, size_t req)
2292{
2293 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2294 if (req > n->cap) {
2295 n->num = xrealloc(n->num, req);
2296 n->cap = req;
2297 }
2298}
2299
2300static void bc_num_free(void *num)
2301{
2302 free(((BcNum *) num)->num);
2303}
2304
2305static void bc_num_copy(BcNum *d, BcNum *s)
2306{
2307 if (d != s) {
2308 bc_num_expand(d, s->cap);
2309 d->len = s->len;
2310 d->neg = s->neg;
2311 d->rdx = s->rdx;
2312 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2313 }
2314}
2315
2316static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2317 size_t base_t)
2318{
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002319 if (!bc_num_strValid(val, base_t))
2320 return bc_error("bad number string");
Gavin Howard01055ba2018-11-03 11:00:21 -06002321
2322 if (base_t == 10)
2323 bc_num_parseDecimal(n, val);
2324 else
2325 bc_num_parseBase(n, val, base);
2326
2327 return BC_STATUS_SUCCESS;
2328}
2329
2330static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2331 size_t *nchars, size_t line_len)
2332{
2333 BcStatus s = BC_STATUS_SUCCESS;
2334
2335 bc_num_printNewline(nchars, line_len);
2336
2337 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002338 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002339 ++(*nchars);
2340 }
2341 else if (base_t == 10)
2342 bc_num_printDecimal(n, nchars, line_len);
2343 else
2344 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2345
2346 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002347 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002348 *nchars = 0;
2349 }
2350
2351 return s;
2352}
2353
2354static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2355{
2356 size_t i;
2357 unsigned long pow;
2358
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002359 if (n->neg) return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002360
2361 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2362
2363 unsigned long prev = *result, powprev = pow;
2364
2365 *result += ((unsigned long) n->num[i]) * pow;
2366 pow *= 10;
2367
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002368 if (*result < prev || pow < powprev)
2369 return bc_error("overflow");
Gavin Howard01055ba2018-11-03 11:00:21 -06002370 }
2371
2372 return BC_STATUS_SUCCESS;
2373}
2374
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002375static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002376{
2377 size_t len;
2378 BcDig *ptr;
2379 unsigned long i;
2380
2381 bc_num_zero(n);
2382
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002383 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002384
2385 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2386 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002387}
2388
2389static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2390{
2391 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2392 (void) scale;
2393 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2394}
2395
2396static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2397{
2398 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2399 (void) scale;
2400 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2401}
2402
2403static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2404{
2405 size_t req = BC_NUM_MREQ(a, b, scale);
2406 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2407}
2408
2409static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2410{
2411 size_t req = BC_NUM_MREQ(a, b, scale);
2412 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2413}
2414
2415static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2416{
2417 size_t req = BC_NUM_MREQ(a, b, scale);
2418 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2419}
2420
2421static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2422{
2423 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2424}
2425
2426static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2427{
2428 BcStatus s;
2429 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2430 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2431 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2432
2433 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2434 bc_num_expand(b, req);
2435
2436 if (a->len == 0) {
2437 bc_num_setToZero(b, scale);
2438 return BC_STATUS_SUCCESS;
2439 }
2440 else if (a->neg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002441 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002442 else if (BC_NUM_ONE(a)) {
2443 bc_num_one(b);
2444 bc_num_extend(b, scale);
2445 return BC_STATUS_SUCCESS;
2446 }
2447
2448 scale = BC_MAX(scale, a->rdx) + 1;
2449 len = a->len + scale;
2450
2451 bc_num_init(&num1, len);
2452 bc_num_init(&num2, len);
2453 bc_num_init(&half, BC_NUM_DEF_SIZE);
2454
2455 bc_num_one(&half);
2456 half.num[0] = 5;
2457 half.rdx = 1;
2458
2459 bc_num_init(&f, len);
2460 bc_num_init(&fprime, len);
2461
2462 x0 = &num1;
2463 x1 = &num2;
2464
2465 bc_num_one(x0);
2466 pow = BC_NUM_INT(a);
2467
2468 if (pow) {
2469
2470 if (pow & 1)
2471 x0->num[0] = 2;
2472 else
2473 x0->num[0] = 6;
2474
2475 pow -= 2 - (pow & 1);
2476
2477 bc_num_extend(x0, pow);
2478
2479 // Make sure to move the radix back.
2480 x0->rdx -= pow;
2481 }
2482
2483 x0->rdx = digs = digs1 = 0;
2484 resrdx = scale + 2;
2485 len = BC_NUM_INT(x0) + resrdx - 1;
2486
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002487 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002488
2489 s = bc_num_div(a, x0, &f, resrdx);
2490 if (s) goto err;
2491 s = bc_num_add(x0, &f, &fprime, resrdx);
2492 if (s) goto err;
2493 s = bc_num_mul(&fprime, &half, x1, resrdx);
2494 if (s) goto err;
2495
2496 cmp = bc_num_cmp(x1, x0);
2497 digs = x1->len - (unsigned long long) llabs(cmp);
2498
2499 if (cmp == cmp2 && digs == digs1)
2500 times += 1;
2501 else
2502 times = 0;
2503
2504 resrdx += times > 4;
2505
2506 cmp2 = cmp1;
2507 cmp1 = cmp;
2508 digs1 = digs;
2509
2510 temp = x0;
2511 x0 = x1;
2512 x1 = temp;
2513 }
2514
Gavin Howard01055ba2018-11-03 11:00:21 -06002515 bc_num_copy(b, x0);
2516 scale -= 1;
2517 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2518
2519err:
2520 bc_num_free(&fprime);
2521 bc_num_free(&f);
2522 bc_num_free(&half);
2523 bc_num_free(&num2);
2524 bc_num_free(&num1);
2525 return s;
2526}
2527
2528static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2529 size_t scale)
2530{
2531 BcStatus s;
2532 BcNum num2, *ptr_a;
2533 bool init = false;
2534 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2535
2536 if (c == a) {
2537 memcpy(&num2, c, sizeof(BcNum));
2538 ptr_a = &num2;
2539 bc_num_init(c, len);
2540 init = true;
2541 }
2542 else {
2543 ptr_a = a;
2544 bc_num_expand(c, len);
2545 }
2546
2547 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2548
2549 if (init) bc_num_free(&num2);
2550
2551 return s;
2552}
2553
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002554#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002555static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2556{
2557 BcStatus s;
2558 BcNum base, exp, two, temp;
2559
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002560 if (c->len == 0)
2561 return bc_error("divide by zero");
2562 if (a->rdx || b->rdx || c->rdx)
2563 return bc_error("non integer number");
2564 if (b->neg)
2565 return bc_error("negative number");
Gavin Howard01055ba2018-11-03 11:00:21 -06002566
2567 bc_num_expand(d, c->len);
2568 bc_num_init(&base, c->len);
2569 bc_num_init(&exp, b->len);
2570 bc_num_init(&two, BC_NUM_DEF_SIZE);
2571 bc_num_init(&temp, b->len);
2572
2573 bc_num_one(&two);
2574 two.num[0] = 2;
2575 bc_num_one(d);
2576
2577 s = bc_num_rem(a, c, &base, 0);
2578 if (s) goto err;
2579 bc_num_copy(&exp, b);
2580
2581 while (exp.len != 0) {
2582
2583 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2584 if (s) goto err;
2585
2586 if (BC_NUM_ONE(&temp)) {
2587 s = bc_num_mul(d, &base, &temp, 0);
2588 if (s) goto err;
2589 s = bc_num_rem(&temp, c, d, 0);
2590 if (s) goto err;
2591 }
2592
2593 s = bc_num_mul(&base, &base, &temp, 0);
2594 if (s) goto err;
2595 s = bc_num_rem(&temp, c, &base, 0);
2596 if (s) goto err;
2597 }
2598
2599err:
2600 bc_num_free(&temp);
2601 bc_num_free(&two);
2602 bc_num_free(&exp);
2603 bc_num_free(&base);
2604 return s;
2605}
2606#endif // ENABLE_DC
2607
2608static int bc_id_cmp(const void *e1, const void *e2)
2609{
2610 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2611}
2612
2613static void bc_id_free(void *id)
2614{
2615 free(((BcId *) id)->name);
2616}
2617
2618static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2619{
2620 BcId a;
2621 size_t i;
2622
2623 for (i = 0; i < f->autos.len; ++i) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002624 if (strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name) == 0)
2625 return bc_error("function parameter or auto var has the same name as another");
Gavin Howard01055ba2018-11-03 11:00:21 -06002626 }
2627
2628 a.idx = var;
2629 a.name = name;
2630
2631 bc_vec_push(&f->autos, &a);
2632
2633 return BC_STATUS_SUCCESS;
2634}
2635
2636static void bc_func_init(BcFunc *f)
2637{
2638 bc_vec_init(&f->code, sizeof(char), NULL);
2639 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2640 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2641 f->nparams = 0;
2642}
2643
2644static void bc_func_free(void *func)
2645{
2646 BcFunc *f = (BcFunc *) func;
2647 bc_vec_free(&f->code);
2648 bc_vec_free(&f->autos);
2649 bc_vec_free(&f->labels);
2650}
2651
2652static void bc_array_init(BcVec *a, bool nums)
2653{
2654 if (nums)
2655 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2656 else
2657 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2658 bc_array_expand(a, 1);
2659}
2660
2661static void bc_array_copy(BcVec *d, const BcVec *s)
2662{
2663 size_t i;
2664
2665 bc_vec_npop(d, d->len);
2666 bc_vec_expand(d, s->cap);
2667 d->len = s->len;
2668
2669 for (i = 0; i < s->len; ++i) {
2670 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2671 bc_num_init(dnum, snum->len);
2672 bc_num_copy(dnum, snum);
2673 }
2674}
2675
2676static void bc_array_expand(BcVec *a, size_t len)
2677{
2678 BcResultData data;
2679
2680 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2681 while (len > a->len) {
2682 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2683 bc_vec_push(a, &data.n);
2684 }
2685 }
2686 else {
2687 while (len > a->len) {
2688 bc_array_init(&data.v, true);
2689 bc_vec_push(a, &data.v);
2690 }
2691 }
2692}
2693
2694static void bc_string_free(void *string)
2695{
2696 free(*((char **) string));
2697}
2698
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002699#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002700static void bc_result_copy(BcResult *d, BcResult *src)
2701{
2702 d->t = src->t;
2703
2704 switch (d->t) {
2705
2706 case BC_RESULT_TEMP:
2707 case BC_RESULT_IBASE:
2708 case BC_RESULT_SCALE:
2709 case BC_RESULT_OBASE:
2710 {
2711 bc_num_init(&d->d.n, src->d.n.len);
2712 bc_num_copy(&d->d.n, &src->d.n);
2713 break;
2714 }
2715
2716 case BC_RESULT_VAR:
2717 case BC_RESULT_ARRAY:
2718 case BC_RESULT_ARRAY_ELEM:
2719 {
2720 d->d.id.name = xstrdup(src->d.id.name);
2721 break;
2722 }
2723
2724 case BC_RESULT_CONSTANT:
2725 case BC_RESULT_LAST:
2726 case BC_RESULT_ONE:
2727 case BC_RESULT_STR:
2728 {
2729 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2730 break;
2731 }
2732 }
2733}
2734#endif // ENABLE_DC
2735
2736static void bc_result_free(void *result)
2737{
2738 BcResult *r = (BcResult *) result;
2739
2740 switch (r->t) {
2741
2742 case BC_RESULT_TEMP:
2743 case BC_RESULT_IBASE:
2744 case BC_RESULT_SCALE:
2745 case BC_RESULT_OBASE:
2746 {
2747 bc_num_free(&r->d.n);
2748 break;
2749 }
2750
2751 case BC_RESULT_VAR:
2752 case BC_RESULT_ARRAY:
2753 case BC_RESULT_ARRAY_ELEM:
2754 {
2755 free(r->d.id.name);
2756 break;
2757 }
2758
2759 default:
2760 {
2761 // Do nothing.
2762 break;
2763 }
2764 }
2765}
2766
2767static void bc_lex_lineComment(BcLex *l)
2768{
2769 l->t.t = BC_LEX_WHITESPACE;
2770 while (l->i < l->len && l->buf[l->i++] != '\n');
2771 --l->i;
2772}
2773
2774static void bc_lex_whitespace(BcLex *l)
2775{
2776 char c;
2777 l->t.t = BC_LEX_WHITESPACE;
2778 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2779}
2780
2781static BcStatus bc_lex_number(BcLex *l, char start)
2782{
2783 const char *buf = l->buf + l->i;
2784 size_t len, hits = 0, bslashes = 0, i = 0, j;
2785 char c = buf[i];
2786 bool last_pt, pt = start == '.';
2787
2788 last_pt = pt;
2789 l->t.t = BC_LEX_NUMBER;
2790
2791 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2792 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2793 {
2794 if (c != '\\') {
2795 last_pt = c == '.';
2796 pt = pt || last_pt;
2797 }
2798 else {
2799 ++i;
2800 bslashes += 1;
2801 }
2802
2803 c = buf[++i];
2804 }
2805
Denys Vlasenkod5f77032018-12-04 21:37:56 +01002806 len = i + !last_pt - bslashes * 2;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002807 if (len > BC_MAX_NUM)
2808 return bc_error("number too long: must be [1, BC_NUM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002809
2810 bc_vec_npop(&l->t.v, l->t.v.len);
2811 bc_vec_expand(&l->t.v, len + 1);
2812 bc_vec_push(&l->t.v, &start);
2813
2814 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2815
2816 c = buf[j];
2817
2818 // If we have hit a backslash, skip it. We don't have
2819 // to check for a newline because it's guaranteed.
2820 if (hits < bslashes && c == '\\') {
2821 ++hits;
2822 ++j;
2823 continue;
2824 }
2825
2826 bc_vec_push(&l->t.v, &c);
2827 }
2828
2829 bc_vec_pushByte(&l->t.v, '\0');
2830 l->i += i;
2831
2832 return BC_STATUS_SUCCESS;
2833}
2834
2835static BcStatus bc_lex_name(BcLex *l)
2836{
2837 size_t i = 0;
2838 const char *buf = l->buf + l->i - 1;
2839 char c = buf[i];
2840
2841 l->t.t = BC_LEX_NAME;
2842
2843 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2844
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002845 if (i > BC_MAX_STRING)
2846 return bc_error("name too long: must be [1, BC_NAME_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002847 bc_vec_string(&l->t.v, i, buf);
2848
2849 // Increment the index. We minus 1 because it has already been incremented.
2850 l->i += i - 1;
2851
2852 return BC_STATUS_SUCCESS;
2853}
2854
2855static void bc_lex_init(BcLex *l, BcLexNext next)
2856{
2857 l->next = next;
2858 bc_vec_init(&l->t.v, sizeof(char), NULL);
2859}
2860
2861static void bc_lex_free(BcLex *l)
2862{
2863 bc_vec_free(&l->t.v);
2864}
2865
2866static void bc_lex_file(BcLex *l, const char *file)
2867{
2868 l->line = 1;
2869 l->newline = false;
2870 l->f = file;
2871}
2872
2873static BcStatus bc_lex_next(BcLex *l)
2874{
2875 BcStatus s;
2876
2877 l->t.last = l->t.t;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002878 if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06002879
2880 l->line += l->newline;
2881 l->t.t = BC_LEX_EOF;
2882
2883 l->newline = (l->i == l->len);
2884 if (l->newline) return BC_STATUS_SUCCESS;
2885
2886 // Loop until failure or we don't have whitespace. This
2887 // is so the parser doesn't get inundated with whitespace.
2888 do {
2889 s = l->next(l);
2890 } while (!s && l->t.t == BC_LEX_WHITESPACE);
2891
2892 return s;
2893}
2894
2895static BcStatus bc_lex_text(BcLex *l, const char *text)
2896{
2897 l->buf = text;
2898 l->i = 0;
2899 l->len = strlen(text);
2900 l->t.t = l->t.last = BC_LEX_INVALID;
2901 return bc_lex_next(l);
2902}
2903
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002904#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06002905static BcStatus bc_lex_identifier(BcLex *l)
2906{
2907 BcStatus s;
2908 size_t i;
2909 const char *buf = l->buf + l->i - 1;
2910
2911 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
2912
2913 unsigned long len = (unsigned long) bc_lex_kws[i].len;
2914
2915 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
2916
2917 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
2918
2919 if (!bc_lex_kws[i].posix) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002920 s = bc_posix_error("POSIX does not allow the following keyword:"); // bc_lex_kws[i].name
Gavin Howard01055ba2018-11-03 11:00:21 -06002921 if (s) return s;
2922 }
2923
2924 // We minus 1 because the index has already been incremented.
2925 l->i += len - 1;
2926 return BC_STATUS_SUCCESS;
2927 }
2928 }
2929
2930 s = bc_lex_name(l);
2931 if (s) return s;
2932
2933 if (l->t.v.len - 1 > 1)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01002934 s = bc_posix_error("POSIX only allows one character names; the following is bad:"); // buf
Gavin Howard01055ba2018-11-03 11:00:21 -06002935
2936 return s;
2937}
2938
2939static BcStatus bc_lex_string(BcLex *l)
2940{
2941 size_t len, nls = 0, i = l->i;
2942 char c;
2943
2944 l->t.t = BC_LEX_STR;
2945
2946 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
2947
2948 if (c == '\0') {
2949 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002950 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002951 }
2952
2953 len = i - l->i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002954 if (len > BC_MAX_STRING)
2955 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06002956 bc_vec_string(&l->t.v, len, l->buf + l->i);
2957
2958 l->i = i + 1;
2959 l->line += nls;
2960
2961 return BC_STATUS_SUCCESS;
2962}
2963
2964static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
2965{
2966 if (l->buf[l->i] == '=') {
2967 ++l->i;
2968 l->t.t = with;
2969 }
2970 else
2971 l->t.t = without;
2972}
2973
2974static BcStatus bc_lex_comment(BcLex *l)
2975{
2976 size_t i, nls = 0;
2977 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06002978
2979 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002980 i = ++l->i;
2981 for (;;) {
2982 char c = buf[i];
2983 check_star:
2984 if (c == '*') {
2985 c = buf[++i];
2986 if (c == '/')
2987 break;
2988 goto check_star;
2989 }
2990 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06002991 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002992 return bc_error("comment end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06002993 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002994 nls += (c == '\n');
2995 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06002996 }
2997
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01002998 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06002999 l->line += nls;
3000
3001 return BC_STATUS_SUCCESS;
3002}
3003
3004static BcStatus bc_lex_token(BcLex *l)
3005{
3006 BcStatus s = BC_STATUS_SUCCESS;
3007 char c = l->buf[l->i++], c2;
3008
3009 // This is the workhorse of the lexer.
3010 switch (c) {
3011
3012 case '\0':
3013 case '\n':
3014 {
3015 l->newline = true;
3016 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3017 break;
3018 }
3019
3020 case '\t':
3021 case '\v':
3022 case '\f':
3023 case '\r':
3024 case ' ':
3025 {
3026 bc_lex_whitespace(l);
3027 break;
3028 }
3029
3030 case '!':
3031 {
3032 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3033
3034 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003035 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "!"
Gavin Howard01055ba2018-11-03 11:00:21 -06003036 if (s) return s;
3037 }
3038
3039 break;
3040 }
3041
3042 case '"':
3043 {
3044 s = bc_lex_string(l);
3045 break;
3046 }
3047
3048 case '#':
3049 {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003050 s = bc_posix_error("POSIX does not allow '#' script comments");
Gavin Howard01055ba2018-11-03 11:00:21 -06003051 if (s) return s;
3052
3053 bc_lex_lineComment(l);
3054
3055 break;
3056 }
3057
3058 case '%':
3059 {
3060 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3061 break;
3062 }
3063
3064 case '&':
3065 {
3066 c2 = l->buf[l->i];
3067 if (c2 == '&') {
3068
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003069 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "&&"
Gavin Howard01055ba2018-11-03 11:00:21 -06003070 if (s) return s;
3071
3072 ++l->i;
3073 l->t.t = BC_LEX_OP_BOOL_AND;
3074 }
3075 else {
3076 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003077 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003078 }
3079
3080 break;
3081 }
3082
3083 case '(':
3084 case ')':
3085 {
3086 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3087 break;
3088 }
3089
3090 case '*':
3091 {
3092 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3093 break;
3094 }
3095
3096 case '+':
3097 {
3098 c2 = l->buf[l->i];
3099 if (c2 == '+') {
3100 ++l->i;
3101 l->t.t = BC_LEX_OP_INC;
3102 }
3103 else
3104 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3105 break;
3106 }
3107
3108 case ',':
3109 {
3110 l->t.t = BC_LEX_COMMA;
3111 break;
3112 }
3113
3114 case '-':
3115 {
3116 c2 = l->buf[l->i];
3117 if (c2 == '-') {
3118 ++l->i;
3119 l->t.t = BC_LEX_OP_DEC;
3120 }
3121 else
3122 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3123 break;
3124 }
3125
3126 case '.':
3127 {
3128 if (isdigit(l->buf[l->i]))
3129 s = bc_lex_number(l, c);
3130 else {
3131 l->t.t = BC_LEX_KEY_LAST;
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003132 s = bc_posix_error("POSIX does not allow a period ('.') as a shortcut for the last result");
Gavin Howard01055ba2018-11-03 11:00:21 -06003133 }
3134 break;
3135 }
3136
3137 case '/':
3138 {
3139 c2 = l->buf[l->i];
3140 if (c2 == '*')
3141 s = bc_lex_comment(l);
3142 else
3143 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3144 break;
3145 }
3146
3147 case '0':
3148 case '1':
3149 case '2':
3150 case '3':
3151 case '4':
3152 case '5':
3153 case '6':
3154 case '7':
3155 case '8':
3156 case '9':
3157 case 'A':
3158 case 'B':
3159 case 'C':
3160 case 'D':
3161 case 'E':
3162 case 'F':
3163 {
3164 s = bc_lex_number(l, c);
3165 break;
3166 }
3167
3168 case ';':
3169 {
3170 l->t.t = BC_LEX_SCOLON;
3171 break;
3172 }
3173
3174 case '<':
3175 {
3176 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3177 break;
3178 }
3179
3180 case '=':
3181 {
3182 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3183 break;
3184 }
3185
3186 case '>':
3187 {
3188 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3189 break;
3190 }
3191
3192 case '[':
3193 case ']':
3194 {
3195 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3196 break;
3197 }
3198
3199 case '\\':
3200 {
3201 if (l->buf[l->i] == '\n') {
3202 l->t.t = BC_LEX_WHITESPACE;
3203 ++l->i;
3204 }
3205 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003206 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003207 break;
3208 }
3209
3210 case '^':
3211 {
3212 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3213 break;
3214 }
3215
3216 case 'a':
3217 case 'b':
3218 case 'c':
3219 case 'd':
3220 case 'e':
3221 case 'f':
3222 case 'g':
3223 case 'h':
3224 case 'i':
3225 case 'j':
3226 case 'k':
3227 case 'l':
3228 case 'm':
3229 case 'n':
3230 case 'o':
3231 case 'p':
3232 case 'q':
3233 case 'r':
3234 case 's':
3235 case 't':
3236 case 'u':
3237 case 'v':
3238 case 'w':
3239 case 'x':
3240 case 'y':
3241 case 'z':
3242 {
3243 s = bc_lex_identifier(l);
3244 break;
3245 }
3246
3247 case '{':
3248 case '}':
3249 {
3250 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3251 break;
3252 }
3253
3254 case '|':
3255 {
3256 c2 = l->buf[l->i];
3257
3258 if (c2 == '|') {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003259 s = bc_posix_error("POSIX does not allow boolean operators; the following is bad:"); // "||"
Gavin Howard01055ba2018-11-03 11:00:21 -06003260 if (s) return s;
3261
3262 ++l->i;
3263 l->t.t = BC_LEX_OP_BOOL_OR;
3264 }
3265 else {
3266 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003267 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003268 }
3269
3270 break;
3271 }
3272
3273 default:
3274 {
3275 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003276 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003277 break;
3278 }
3279 }
3280
3281 return s;
3282}
3283#endif // ENABLE_BC
3284
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003285#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003286static BcStatus dc_lex_register(BcLex *l)
3287{
3288 BcStatus s = BC_STATUS_SUCCESS;
3289
3290 if (isspace(l->buf[l->i - 1])) {
3291 bc_lex_whitespace(l);
3292 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003293 if (!G_exreg)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003294 s = bc_error("extended register");
Gavin Howard01055ba2018-11-03 11:00:21 -06003295 else
3296 s = bc_lex_name(l);
3297 }
3298 else {
3299 bc_vec_npop(&l->t.v, l->t.v.len);
3300 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3301 bc_vec_pushByte(&l->t.v, '\0');
3302 l->t.t = BC_LEX_NAME;
3303 }
3304
3305 return s;
3306}
3307
3308static BcStatus dc_lex_string(BcLex *l)
3309{
3310 size_t depth = 1, nls = 0, i = l->i;
3311 char c;
3312
3313 l->t.t = BC_LEX_STR;
3314 bc_vec_npop(&l->t.v, l->t.v.len);
3315
3316 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3317
3318 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3319 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3320 nls += (c == '\n');
3321
3322 if (depth) bc_vec_push(&l->t.v, &c);
3323 }
3324
3325 if (c == '\0') {
3326 l->i = i;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003327 return bc_error("string end could not be found");
Gavin Howard01055ba2018-11-03 11:00:21 -06003328 }
3329
3330 bc_vec_pushByte(&l->t.v, '\0');
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003331 if (i - l->i > BC_MAX_STRING)
3332 return bc_error("string too long: must be [1, BC_STRING_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06003333
3334 l->i = i;
3335 l->line += nls;
3336
3337 return BC_STATUS_SUCCESS;
3338}
3339
3340static BcStatus dc_lex_token(BcLex *l)
3341{
3342 BcStatus s = BC_STATUS_SUCCESS;
3343 char c = l->buf[l->i++], c2;
3344 size_t i;
3345
3346 for (i = 0; i < dc_lex_regs_len; ++i) {
3347 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3348 }
3349
3350 if (c >= '%' && c <= '~' &&
3351 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3352 {
3353 return s;
3354 }
3355
3356 // This is the workhorse of the lexer.
3357 switch (c) {
3358
3359 case '\0':
3360 {
3361 l->t.t = BC_LEX_EOF;
3362 break;
3363 }
3364
3365 case '\n':
3366 case '\t':
3367 case '\v':
3368 case '\f':
3369 case '\r':
3370 case ' ':
3371 {
3372 l->newline = (c == '\n');
3373 bc_lex_whitespace(l);
3374 break;
3375 }
3376
3377 case '!':
3378 {
3379 c2 = l->buf[l->i];
3380
3381 if (c2 == '=')
3382 l->t.t = BC_LEX_OP_REL_NE;
3383 else if (c2 == '<')
3384 l->t.t = BC_LEX_OP_REL_LE;
3385 else if (c2 == '>')
3386 l->t.t = BC_LEX_OP_REL_GE;
3387 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003388 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003389
3390 ++l->i;
3391 break;
3392 }
3393
3394 case '#':
3395 {
3396 bc_lex_lineComment(l);
3397 break;
3398 }
3399
3400 case '.':
3401 {
3402 if (isdigit(l->buf[l->i]))
3403 s = bc_lex_number(l, c);
3404 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003405 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003406 break;
3407 }
3408
3409 case '0':
3410 case '1':
3411 case '2':
3412 case '3':
3413 case '4':
3414 case '5':
3415 case '6':
3416 case '7':
3417 case '8':
3418 case '9':
3419 case 'A':
3420 case 'B':
3421 case 'C':
3422 case 'D':
3423 case 'E':
3424 case 'F':
3425 {
3426 s = bc_lex_number(l, c);
3427 break;
3428 }
3429
3430 case '[':
3431 {
3432 s = dc_lex_string(l);
3433 break;
3434 }
3435
3436 default:
3437 {
3438 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003439 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003440 break;
3441 }
3442 }
3443
3444 return s;
3445}
3446#endif // ENABLE_DC
3447
3448static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3449{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003450 bc_program_addFunc(name, idx);
3451 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003452}
3453
3454static void bc_parse_pushName(BcParse *p, char *name)
3455{
3456 size_t i = 0, len = strlen(name);
3457
3458 for (; i < len; ++i) bc_parse_push(p, name[i]);
3459 bc_parse_push(p, BC_PARSE_STREND);
3460
3461 free(name);
3462}
3463
3464static void bc_parse_pushIndex(BcParse *p, size_t idx)
3465{
3466 unsigned char amt, i, nums[sizeof(size_t)];
3467
3468 for (amt = 0; idx; ++amt) {
3469 nums[amt] = (char) idx;
3470 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3471 }
3472
3473 bc_parse_push(p, amt);
3474 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3475}
3476
3477static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3478{
3479 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003480 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003481
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003482 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003483
3484 bc_parse_push(p, BC_INST_NUM);
3485 bc_parse_pushIndex(p, idx);
3486
3487 ++(*nexs);
3488 (*prev) = BC_INST_NUM;
3489}
3490
3491static BcStatus bc_parse_text(BcParse *p, const char *text)
3492{
3493 BcStatus s;
3494
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003495 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003496
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003497 if (!text[0] && !BC_PARSE_CAN_EXEC(p)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003498 p->l.t.t = BC_LEX_INVALID;
3499 s = p->parse(p);
3500 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003501 if (!BC_PARSE_CAN_EXEC(p))
3502 return bc_error("file is not executable");
Gavin Howard01055ba2018-11-03 11:00:21 -06003503 }
3504
3505 return bc_lex_text(&p->l, text);
3506}
3507
Denys Vlasenkod38af482018-12-04 19:11:02 +01003508// Called when bc/dc_parse_parse() detects a failure,
3509// resets parsing structures.
3510static void bc_parse_reset(BcParse *p)
Gavin Howard01055ba2018-11-03 11:00:21 -06003511{
3512 if (p->fidx != BC_PROG_MAIN) {
3513
3514 p->func->nparams = 0;
3515 bc_vec_npop(&p->func->code, p->func->code.len);
3516 bc_vec_npop(&p->func->autos, p->func->autos.len);
3517 bc_vec_npop(&p->func->labels, p->func->labels.len);
3518
3519 bc_parse_updateFunc(p, BC_PROG_MAIN);
3520 }
3521
3522 p->l.i = p->l.len;
3523 p->l.t.t = BC_LEX_EOF;
3524 p->auto_part = (p->nbraces = 0);
3525
3526 bc_vec_npop(&p->flags, p->flags.len - 1);
3527 bc_vec_npop(&p->exits, p->exits.len);
3528 bc_vec_npop(&p->conds, p->conds.len);
3529 bc_vec_npop(&p->ops, p->ops.len);
3530
Denys Vlasenkod38af482018-12-04 19:11:02 +01003531 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003532}
3533
3534static void bc_parse_free(BcParse *p)
3535{
3536 bc_vec_free(&p->flags);
3537 bc_vec_free(&p->exits);
3538 bc_vec_free(&p->conds);
3539 bc_vec_free(&p->ops);
3540 bc_lex_free(&p->l);
3541}
3542
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003543static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003544 BcParseParse parse, BcLexNext next)
3545{
3546 memset(p, 0, sizeof(BcParse));
3547
3548 bc_lex_init(&p->l, next);
3549 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3550 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3551 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3552 bc_vec_pushByte(&p->flags, 0);
3553 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3554
3555 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003556 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003557 bc_parse_updateFunc(p, func);
3558}
3559
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003560#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003561static BcStatus bc_parse_else(BcParse *p);
3562static BcStatus bc_parse_stmt(BcParse *p);
3563
3564static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3565 size_t *nexprs, bool next)
3566{
3567 BcStatus s = BC_STATUS_SUCCESS;
3568 BcLexType t;
3569 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3570 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3571
3572 while (p->ops.len > start) {
3573
3574 t = BC_PARSE_TOP_OP(p);
3575 if (t == BC_LEX_LPAREN) break;
3576
3577 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3578 if (l >= r && (l != r || !left)) break;
3579
3580 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3581 bc_vec_pop(&p->ops);
3582 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3583 }
3584
3585 bc_vec_push(&p->ops, &type);
3586 if (next) s = bc_lex_next(&p->l);
3587
3588 return s;
3589}
3590
3591static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3592{
3593 BcLexType top;
3594
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003595 if (p->ops.len <= ops_bgn)
3596 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003597 top = BC_PARSE_TOP_OP(p);
3598
3599 while (top != BC_LEX_LPAREN) {
3600
3601 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3602
3603 bc_vec_pop(&p->ops);
3604 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3605
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003606 if (p->ops.len <= ops_bgn)
3607 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003608 top = BC_PARSE_TOP_OP(p);
3609 }
3610
3611 bc_vec_pop(&p->ops);
3612
3613 return bc_lex_next(&p->l);
3614}
3615
3616static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3617{
3618 BcStatus s;
3619 bool comma = false;
3620 size_t nparams;
3621
3622 s = bc_lex_next(&p->l);
3623 if (s) return s;
3624
3625 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3626
3627 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3628 s = bc_parse_expr(p, flags, bc_parse_next_param);
3629 if (s) return s;
3630
3631 comma = p->l.t.t == BC_LEX_COMMA;
3632 if (comma) {
3633 s = bc_lex_next(&p->l);
3634 if (s) return s;
3635 }
3636 }
3637
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003638 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003639 bc_parse_push(p, BC_INST_CALL);
3640 bc_parse_pushIndex(p, nparams);
3641
3642 return BC_STATUS_SUCCESS;
3643}
3644
3645static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3646{
3647 BcStatus s;
3648 BcId entry, *entry_ptr;
3649 size_t idx;
3650
3651 entry.name = name;
3652
3653 s = bc_parse_params(p, flags);
3654 if (s) goto err;
3655
3656 if (p->l.t.t != BC_LEX_RPAREN) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003657 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003658 goto err;
3659 }
3660
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003661 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003662
3663 if (idx == BC_VEC_INVALID_IDX) {
3664 name = xstrdup(entry.name);
3665 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003666 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003667 free(entry.name);
3668 }
3669 else
3670 free(name);
3671
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003672 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003673 bc_parse_pushIndex(p, entry_ptr->idx);
3674
3675 return bc_lex_next(&p->l);
3676
3677err:
3678 free(name);
3679 return s;
3680}
3681
3682static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3683{
3684 BcStatus s;
3685 char *name;
3686
3687 name = xstrdup(p->l.t.v.v);
3688 s = bc_lex_next(&p->l);
3689 if (s) goto err;
3690
3691 if (p->l.t.t == BC_LEX_LBRACKET) {
3692
3693 s = bc_lex_next(&p->l);
3694 if (s) goto err;
3695
3696 if (p->l.t.t == BC_LEX_RBRACKET) {
3697
3698 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003699 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06003700 goto err;
3701 }
3702
3703 *type = BC_INST_ARRAY;
3704 }
3705 else {
3706
3707 *type = BC_INST_ARRAY_ELEM;
3708
3709 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3710 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3711 if (s) goto err;
3712 }
3713
3714 s = bc_lex_next(&p->l);
3715 if (s) goto err;
3716 bc_parse_push(p, *type);
3717 bc_parse_pushName(p, name);
3718 }
3719 else if (p->l.t.t == BC_LEX_LPAREN) {
3720
3721 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003722 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003723 goto err;
3724 }
3725
3726 *type = BC_INST_CALL;
3727 s = bc_parse_call(p, name, flags);
3728 }
3729 else {
3730 *type = BC_INST_VAR;
3731 bc_parse_push(p, BC_INST_VAR);
3732 bc_parse_pushName(p, name);
3733 }
3734
3735 return s;
3736
3737err:
3738 free(name);
3739 return s;
3740}
3741
3742static BcStatus bc_parse_read(BcParse *p)
3743{
3744 BcStatus s;
3745
3746 s = bc_lex_next(&p->l);
3747 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003748 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003749
3750 s = bc_lex_next(&p->l);
3751 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003752 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003753
3754 bc_parse_push(p, BC_INST_READ);
3755
3756 return bc_lex_next(&p->l);
3757}
3758
3759static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3760 BcInst *prev)
3761{
3762 BcStatus s;
3763
3764 s = bc_lex_next(&p->l);
3765 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003766 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003767
3768 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3769
3770 s = bc_lex_next(&p->l);
3771 if (s) return s;
3772
3773 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3774 if (s) return s;
3775
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003776 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003777
3778 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3779 bc_parse_push(p, *prev);
3780
3781 return bc_lex_next(&p->l);
3782}
3783
3784static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3785{
3786 BcStatus s;
3787
3788 s = bc_lex_next(&p->l);
3789 if (s) return s;
3790
3791 if (p->l.t.t != BC_LEX_LPAREN) {
3792 *type = BC_INST_SCALE;
3793 bc_parse_push(p, BC_INST_SCALE);
3794 return BC_STATUS_SUCCESS;
3795 }
3796
3797 *type = BC_INST_SCALE_FUNC;
3798 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3799
3800 s = bc_lex_next(&p->l);
3801 if (s) return s;
3802
3803 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3804 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003805 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003806 bc_parse_push(p, BC_INST_SCALE_FUNC);
3807
3808 return bc_lex_next(&p->l);
3809}
3810
3811static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3812 size_t *nexprs, uint8_t flags)
3813{
3814 BcStatus s;
3815 BcLexType type;
3816 char inst;
3817 BcInst etype = *prev;
3818
3819 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3820 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3821 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3822 {
3823 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3824 bc_parse_push(p, inst);
3825 s = bc_lex_next(&p->l);
3826 }
3827 else {
3828
3829 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3830 *paren_expr = true;
3831
3832 s = bc_lex_next(&p->l);
3833 if (s) return s;
3834 type = p->l.t.t;
3835
3836 // Because we parse the next part of the expression
3837 // right here, we need to increment this.
3838 *nexprs = *nexprs + 1;
3839
3840 switch (type) {
3841
3842 case BC_LEX_NAME:
3843 {
3844 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3845 break;
3846 }
3847
3848 case BC_LEX_KEY_IBASE:
3849 case BC_LEX_KEY_LAST:
3850 case BC_LEX_KEY_OBASE:
3851 {
3852 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3853 s = bc_lex_next(&p->l);
3854 break;
3855 }
3856
3857 case BC_LEX_KEY_SCALE:
3858 {
3859 s = bc_lex_next(&p->l);
3860 if (s) return s;
3861 if (p->l.t.t == BC_LEX_LPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003862 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003863 else
3864 bc_parse_push(p, BC_INST_SCALE);
3865 break;
3866 }
3867
3868 default:
3869 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003870 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003871 break;
3872 }
3873 }
3874
3875 if (!s) bc_parse_push(p, inst);
3876 }
3877
3878 return s;
3879}
3880
3881static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3882 bool rparen, size_t *nexprs)
3883{
3884 BcStatus s;
3885 BcLexType type;
3886 BcInst etype = *prev;
3887
3888 s = bc_lex_next(&p->l);
3889 if (s) return s;
3890
3891 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
3892 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
3893 BC_LEX_OP_MINUS :
3894 BC_LEX_NEG;
3895 *prev = BC_PARSE_TOKEN_INST(type);
3896
3897 // We can just push onto the op stack because this is the largest
3898 // precedence operator that gets pushed. Inc/dec does not.
3899 if (type != BC_LEX_OP_MINUS)
3900 bc_vec_push(&p->ops, &type);
3901 else
3902 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
3903
3904 return s;
3905}
3906
3907static BcStatus bc_parse_string(BcParse *p, char inst)
3908{
3909 char *str = xstrdup(p->l.t.v.v);
3910
3911 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003912 bc_parse_pushIndex(p, G.prog.strs.len);
3913 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06003914 bc_parse_push(p, inst);
3915
3916 return bc_lex_next(&p->l);
3917}
3918
3919static BcStatus bc_parse_print(BcParse *p)
3920{
3921 BcStatus s;
3922 BcLexType type;
3923 bool comma = false;
3924
3925 s = bc_lex_next(&p->l);
3926 if (s) return s;
3927
3928 type = p->l.t.t;
3929
3930 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003931 return bc_error("bad print statement");
Gavin Howard01055ba2018-11-03 11:00:21 -06003932
3933 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
3934
3935 if (type == BC_LEX_STR)
3936 s = bc_parse_string(p, BC_INST_PRINT_POP);
3937 else {
3938 s = bc_parse_expr(p, 0, bc_parse_next_print);
3939 if (s) return s;
3940 bc_parse_push(p, BC_INST_PRINT_POP);
3941 }
3942
3943 if (s) return s;
3944
3945 comma = p->l.t.t == BC_LEX_COMMA;
3946 if (comma) s = bc_lex_next(&p->l);
3947 type = p->l.t.t;
3948 }
3949
3950 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003951 if (comma) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003952
3953 return bc_lex_next(&p->l);
3954}
3955
3956static BcStatus bc_parse_return(BcParse *p)
3957{
3958 BcStatus s;
3959 BcLexType t;
3960 bool paren;
3961
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003962 if (!BC_PARSE_FUNC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06003963
3964 s = bc_lex_next(&p->l);
3965 if (s) return s;
3966
3967 t = p->l.t.t;
3968 paren = t == BC_LEX_LPAREN;
3969
3970 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
3971 bc_parse_push(p, BC_INST_RET0);
3972 else {
3973
3974 s = bc_parse_expr(p, 0, bc_parse_next_expr);
3975 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
3976 return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003977
3978 if (s == BC_STATUS_PARSE_EMPTY_EXP) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003979 bc_parse_push(p, BC_INST_RET0);
3980 s = bc_lex_next(&p->l);
3981 if (s) return s;
3982 }
3983
3984 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01003985 s = bc_posix_error("POSIX requires parentheses around return expressions");
Gavin Howard01055ba2018-11-03 11:00:21 -06003986 if (s) return s;
3987 }
3988
3989 bc_parse_push(p, BC_INST_RET);
3990 }
3991
3992 return s;
3993}
3994
3995static BcStatus bc_parse_endBody(BcParse *p, bool brace)
3996{
3997 BcStatus s = BC_STATUS_SUCCESS;
3998
3999 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004000 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004001
4002 if (brace) {
4003
4004 if (p->l.t.t == BC_LEX_RBRACE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004005 if (!p->nbraces) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004006 --p->nbraces;
4007 s = bc_lex_next(&p->l);
4008 if (s) return s;
4009 }
4010 else
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004011 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004012 }
4013
4014 if (BC_PARSE_IF(p)) {
4015
4016 uint8_t *flag_ptr;
4017
4018 while (p->l.t.t == BC_LEX_NLINE) {
4019 s = bc_lex_next(&p->l);
4020 if (s) return s;
4021 }
4022
4023 bc_vec_pop(&p->flags);
4024
4025 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4026 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4027
4028 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4029 }
4030 else if (BC_PARSE_ELSE(p)) {
4031
4032 BcInstPtr *ip;
4033 size_t *label;
4034
4035 bc_vec_pop(&p->flags);
4036
4037 ip = bc_vec_top(&p->exits);
4038 label = bc_vec_item(&p->func->labels, ip->idx);
4039 *label = p->func->code.len;
4040
4041 bc_vec_pop(&p->exits);
4042 }
4043 else if (BC_PARSE_FUNC_INNER(p)) {
4044 bc_parse_push(p, BC_INST_RET0);
4045 bc_parse_updateFunc(p, BC_PROG_MAIN);
4046 bc_vec_pop(&p->flags);
4047 }
4048 else {
4049
4050 BcInstPtr *ip = bc_vec_top(&p->exits);
4051 size_t *label = bc_vec_top(&p->conds);
4052
4053 bc_parse_push(p, BC_INST_JUMP);
4054 bc_parse_pushIndex(p, *label);
4055
4056 label = bc_vec_item(&p->func->labels, ip->idx);
4057 *label = p->func->code.len;
4058
4059 bc_vec_pop(&p->flags);
4060 bc_vec_pop(&p->exits);
4061 bc_vec_pop(&p->conds);
4062 }
4063
4064 return s;
4065}
4066
4067static void bc_parse_startBody(BcParse *p, uint8_t flags)
4068{
4069 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4070 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4071 flags |= BC_PARSE_FLAG_BODY;
4072 bc_vec_push(&p->flags, &flags);
4073}
4074
4075static void bc_parse_noElse(BcParse *p)
4076{
4077 BcInstPtr *ip;
4078 size_t *label;
4079 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4080
4081 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4082
4083 ip = bc_vec_top(&p->exits);
4084 label = bc_vec_item(&p->func->labels, ip->idx);
4085 *label = p->func->code.len;
4086
4087 bc_vec_pop(&p->exits);
4088}
4089
4090static BcStatus bc_parse_if(BcParse *p)
4091{
4092 BcStatus s;
4093 BcInstPtr ip;
4094
4095 s = bc_lex_next(&p->l);
4096 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004097 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004098
4099 s = bc_lex_next(&p->l);
4100 if (s) return s;
4101 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4102 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004103 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004104
4105 s = bc_lex_next(&p->l);
4106 if (s) return s;
4107 bc_parse_push(p, BC_INST_JUMP_ZERO);
4108
4109 ip.idx = p->func->labels.len;
4110 ip.func = ip.len = 0;
4111
4112 bc_parse_pushIndex(p, ip.idx);
4113 bc_vec_push(&p->exits, &ip);
4114 bc_vec_push(&p->func->labels, &ip.idx);
4115 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4116
4117 return BC_STATUS_SUCCESS;
4118}
4119
4120static BcStatus bc_parse_else(BcParse *p)
4121{
4122 BcInstPtr ip;
4123
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004124 if (!BC_PARSE_IF_END(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004125
4126 ip.idx = p->func->labels.len;
4127 ip.func = ip.len = 0;
4128
4129 bc_parse_push(p, BC_INST_JUMP);
4130 bc_parse_pushIndex(p, ip.idx);
4131
4132 bc_parse_noElse(p);
4133
4134 bc_vec_push(&p->exits, &ip);
4135 bc_vec_push(&p->func->labels, &ip.idx);
4136 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4137
4138 return bc_lex_next(&p->l);
4139}
4140
4141static BcStatus bc_parse_while(BcParse *p)
4142{
4143 BcStatus s;
4144 BcInstPtr ip;
4145
4146 s = bc_lex_next(&p->l);
4147 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004148 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004149 s = bc_lex_next(&p->l);
4150 if (s) return s;
4151
4152 ip.idx = p->func->labels.len;
4153
4154 bc_vec_push(&p->func->labels, &p->func->code.len);
4155 bc_vec_push(&p->conds, &ip.idx);
4156
4157 ip.idx = p->func->labels.len;
4158 ip.func = 1;
4159 ip.len = 0;
4160
4161 bc_vec_push(&p->exits, &ip);
4162 bc_vec_push(&p->func->labels, &ip.idx);
4163
4164 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4165 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004166 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004167 s = bc_lex_next(&p->l);
4168 if (s) return s;
4169
4170 bc_parse_push(p, BC_INST_JUMP_ZERO);
4171 bc_parse_pushIndex(p, ip.idx);
4172 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4173
4174 return BC_STATUS_SUCCESS;
4175}
4176
4177static BcStatus bc_parse_for(BcParse *p)
4178{
4179 BcStatus s;
4180 BcInstPtr ip;
4181 size_t cond_idx, exit_idx, body_idx, update_idx;
4182
4183 s = bc_lex_next(&p->l);
4184 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004185 if (p->l.t.t != BC_LEX_LPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004186 s = bc_lex_next(&p->l);
4187 if (s) return s;
4188
4189 if (p->l.t.t != BC_LEX_SCOLON)
4190 s = bc_parse_expr(p, 0, bc_parse_next_for);
4191 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004192 s = bc_posix_error("POSIX does not allow an empty init expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004193
4194 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004195 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004196 s = bc_lex_next(&p->l);
4197 if (s) return s;
4198
4199 cond_idx = p->func->labels.len;
4200 update_idx = cond_idx + 1;
4201 body_idx = update_idx + 1;
4202 exit_idx = body_idx + 1;
4203
4204 bc_vec_push(&p->func->labels, &p->func->code.len);
4205
4206 if (p->l.t.t != BC_LEX_SCOLON)
4207 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4208 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004209 s = bc_posix_error("POSIX does not allow an empty condition expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004210
4211 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004212 if (p->l.t.t != BC_LEX_SCOLON) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004213
4214 s = bc_lex_next(&p->l);
4215 if (s) return s;
4216
4217 bc_parse_push(p, BC_INST_JUMP_ZERO);
4218 bc_parse_pushIndex(p, exit_idx);
4219 bc_parse_push(p, BC_INST_JUMP);
4220 bc_parse_pushIndex(p, body_idx);
4221
4222 ip.idx = p->func->labels.len;
4223
4224 bc_vec_push(&p->conds, &update_idx);
4225 bc_vec_push(&p->func->labels, &p->func->code.len);
4226
4227 if (p->l.t.t != BC_LEX_RPAREN)
4228 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4229 else
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004230 s = bc_posix_error("POSIX does not allow an empty update expression in a for loop");
Gavin Howard01055ba2018-11-03 11:00:21 -06004231
4232 if (s) return s;
4233
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004234 if (p->l.t.t != BC_LEX_RPAREN) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004235 bc_parse_push(p, BC_INST_JUMP);
4236 bc_parse_pushIndex(p, cond_idx);
4237 bc_vec_push(&p->func->labels, &p->func->code.len);
4238
4239 ip.idx = exit_idx;
4240 ip.func = 1;
4241 ip.len = 0;
4242
4243 bc_vec_push(&p->exits, &ip);
4244 bc_vec_push(&p->func->labels, &ip.idx);
4245 bc_lex_next(&p->l);
4246 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4247
4248 return BC_STATUS_SUCCESS;
4249}
4250
4251static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4252{
4253 BcStatus s;
4254 size_t i;
4255 BcInstPtr *ip;
4256
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004257 if (!BC_PARSE_LOOP(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004258
4259 if (type == BC_LEX_KEY_BREAK) {
4260
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004261 if (p->exits.len == 0) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004262
4263 i = p->exits.len - 1;
4264 ip = bc_vec_item(&p->exits, i);
4265
4266 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004267 if (i >= p->exits.len && !ip->func) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004268
4269 i = ip->idx;
4270 }
4271 else
4272 i = *((size_t *) bc_vec_top(&p->conds));
4273
4274 bc_parse_push(p, BC_INST_JUMP);
4275 bc_parse_pushIndex(p, i);
4276
4277 s = bc_lex_next(&p->l);
4278 if (s) return s;
4279
4280 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004281 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004282
4283 return bc_lex_next(&p->l);
4284}
4285
4286static BcStatus bc_parse_func(BcParse *p)
4287{
4288 BcStatus s;
4289 bool var, comma = false;
4290 uint8_t flags;
4291 char *name;
4292
4293 s = bc_lex_next(&p->l);
4294 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004295 if (p->l.t.t != BC_LEX_NAME)
4296 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004297
4298 name = xstrdup(p->l.t.v.v);
4299 bc_parse_addFunc(p, name, &p->fidx);
4300
4301 s = bc_lex_next(&p->l);
4302 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004303 if (p->l.t.t != BC_LEX_LPAREN)
4304 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004305 s = bc_lex_next(&p->l);
4306 if (s) return s;
4307
4308 while (p->l.t.t != BC_LEX_RPAREN) {
4309
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004310 if (p->l.t.t != BC_LEX_NAME)
4311 return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004312
4313 ++p->func->nparams;
4314
4315 name = xstrdup(p->l.t.v.v);
4316 s = bc_lex_next(&p->l);
4317 if (s) goto err;
4318
4319 var = p->l.t.t != BC_LEX_LBRACKET;
4320
4321 if (!var) {
4322
4323 s = bc_lex_next(&p->l);
4324 if (s) goto err;
4325
4326 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004327 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004328 goto err;
4329 }
4330
4331 s = bc_lex_next(&p->l);
4332 if (s) goto err;
4333 }
4334
4335 comma = p->l.t.t == BC_LEX_COMMA;
4336 if (comma) {
4337 s = bc_lex_next(&p->l);
4338 if (s) goto err;
4339 }
4340
4341 s = bc_func_insert(p->func, name, var);
4342 if (s) goto err;
4343 }
4344
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004345 if (comma) return bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004346
4347 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4348 bc_parse_startBody(p, flags);
4349
4350 s = bc_lex_next(&p->l);
4351 if (s) return s;
4352
4353 if (p->l.t.t != BC_LEX_LBRACE)
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004354 s = bc_posix_error("POSIX requires the left brace be on the same line as the function header");
Gavin Howard01055ba2018-11-03 11:00:21 -06004355
4356 return s;
4357
4358err:
4359 free(name);
4360 return s;
4361}
4362
4363static BcStatus bc_parse_auto(BcParse *p)
4364{
4365 BcStatus s;
4366 bool comma, var, one;
4367 char *name;
4368
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004369 if (!p->auto_part) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004370 s = bc_lex_next(&p->l);
4371 if (s) return s;
4372
4373 p->auto_part = comma = false;
4374 one = p->l.t.t == BC_LEX_NAME;
4375
4376 while (p->l.t.t == BC_LEX_NAME) {
4377
4378 name = xstrdup(p->l.t.v.v);
4379 s = bc_lex_next(&p->l);
4380 if (s) goto err;
4381
4382 var = p->l.t.t != BC_LEX_LBRACKET;
4383 if (!var) {
4384
4385 s = bc_lex_next(&p->l);
4386 if (s) goto err;
4387
4388 if (p->l.t.t != BC_LEX_RBRACKET) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004389 s = bc_error("bad function definition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004390 goto err;
4391 }
4392
4393 s = bc_lex_next(&p->l);
4394 if (s) goto err;
4395 }
4396
4397 comma = p->l.t.t == BC_LEX_COMMA;
4398 if (comma) {
4399 s = bc_lex_next(&p->l);
4400 if (s) goto err;
4401 }
4402
4403 s = bc_func_insert(p->func, name, var);
4404 if (s) goto err;
4405 }
4406
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004407 if (comma) return bc_error("bad function definition");
Denys Vlasenkoabbc4332018-12-03 21:46:41 +01004408 if (!one) return bc_error("no auto variable found");
Gavin Howard01055ba2018-11-03 11:00:21 -06004409
4410 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004411 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004412
4413 return bc_lex_next(&p->l);
4414
4415err:
4416 free(name);
4417 return s;
4418}
4419
4420static BcStatus bc_parse_body(BcParse *p, bool brace)
4421{
4422 BcStatus s = BC_STATUS_SUCCESS;
4423 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4424
4425 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4426
4427 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4428
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004429 if (!brace) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004430 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4431
4432 if (!p->auto_part) {
4433 s = bc_parse_auto(p);
4434 if (s) return s;
4435 }
4436
4437 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4438 }
4439 else {
4440 s = bc_parse_stmt(p);
4441 if (!s && !brace) s = bc_parse_endBody(p, false);
4442 }
4443
4444 return s;
4445}
4446
4447static BcStatus bc_parse_stmt(BcParse *p)
4448{
4449 BcStatus s = BC_STATUS_SUCCESS;
4450
4451 switch (p->l.t.t) {
4452
4453 case BC_LEX_NLINE:
4454 {
4455 return bc_lex_next(&p->l);
4456 }
4457
4458 case BC_LEX_KEY_ELSE:
4459 {
4460 p->auto_part = false;
4461 break;
4462 }
4463
4464 case BC_LEX_LBRACE:
4465 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004466 if (!BC_PARSE_BODY(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004467
4468 ++p->nbraces;
4469 s = bc_lex_next(&p->l);
4470 if (s) return s;
4471
4472 return bc_parse_body(p, true);
4473 }
4474
4475 case BC_LEX_KEY_AUTO:
4476 {
4477 return bc_parse_auto(p);
4478 }
4479
4480 default:
4481 {
4482 p->auto_part = false;
4483
4484 if (BC_PARSE_IF_END(p)) {
4485 bc_parse_noElse(p);
4486 return BC_STATUS_SUCCESS;
4487 }
4488 else if (BC_PARSE_BODY(p))
4489 return bc_parse_body(p, false);
4490
4491 break;
4492 }
4493 }
4494
4495 switch (p->l.t.t) {
4496
4497 case BC_LEX_OP_INC:
4498 case BC_LEX_OP_DEC:
4499 case BC_LEX_OP_MINUS:
4500 case BC_LEX_OP_BOOL_NOT:
4501 case BC_LEX_LPAREN:
4502 case BC_LEX_NAME:
4503 case BC_LEX_NUMBER:
4504 case BC_LEX_KEY_IBASE:
4505 case BC_LEX_KEY_LAST:
4506 case BC_LEX_KEY_LENGTH:
4507 case BC_LEX_KEY_OBASE:
4508 case BC_LEX_KEY_READ:
4509 case BC_LEX_KEY_SCALE:
4510 case BC_LEX_KEY_SQRT:
4511 {
4512 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4513 break;
4514 }
4515
4516 case BC_LEX_KEY_ELSE:
4517 {
4518 s = bc_parse_else(p);
4519 break;
4520 }
4521
4522 case BC_LEX_SCOLON:
4523 {
4524 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4525 break;
4526 }
4527
4528 case BC_LEX_RBRACE:
4529 {
4530 s = bc_parse_endBody(p, true);
4531 break;
4532 }
4533
4534 case BC_LEX_STR:
4535 {
4536 s = bc_parse_string(p, BC_INST_PRINT_STR);
4537 break;
4538 }
4539
4540 case BC_LEX_KEY_BREAK:
4541 case BC_LEX_KEY_CONTINUE:
4542 {
4543 s = bc_parse_loopExit(p, p->l.t.t);
4544 break;
4545 }
4546
4547 case BC_LEX_KEY_FOR:
4548 {
4549 s = bc_parse_for(p);
4550 break;
4551 }
4552
4553 case BC_LEX_KEY_HALT:
4554 {
4555 bc_parse_push(p, BC_INST_HALT);
4556 s = bc_lex_next(&p->l);
4557 break;
4558 }
4559
4560 case BC_LEX_KEY_IF:
4561 {
4562 s = bc_parse_if(p);
4563 break;
4564 }
4565
4566 case BC_LEX_KEY_LIMITS:
4567 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004568 // "limits" is a compile-time command,
4569 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004570 s = bc_lex_next(&p->l);
4571 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004572 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4573 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4574 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4575 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4576 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4577 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4578 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4579 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004580 break;
4581 }
4582
4583 case BC_LEX_KEY_PRINT:
4584 {
4585 s = bc_parse_print(p);
4586 break;
4587 }
4588
4589 case BC_LEX_KEY_QUIT:
4590 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004591 // "quit" is a compile-time command. For example,
4592 // "if (0 == 1) quit" terminates when parsing the statement,
4593 // not when it is executed
4594 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004595 }
4596
4597 case BC_LEX_KEY_RETURN:
4598 {
4599 s = bc_parse_return(p);
4600 break;
4601 }
4602
4603 case BC_LEX_KEY_WHILE:
4604 {
4605 s = bc_parse_while(p);
4606 break;
4607 }
4608
4609 default:
4610 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004611 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004612 break;
4613 }
4614 }
4615
4616 return s;
4617}
4618
4619static BcStatus bc_parse_parse(BcParse *p)
4620{
4621 BcStatus s;
4622
4623 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004624 s = p->flags.len > 0 ? bc_error("block end could not be found") : bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06004625 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004626 if (!BC_PARSE_CAN_EXEC(p)) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004627 s = bc_parse_func(p);
4628 }
4629 else
4630 s = bc_parse_stmt(p);
4631
Denys Vlasenkod38af482018-12-04 19:11:02 +01004632 if (s || G_interrupt) {
4633 bc_parse_reset(p);
4634 s = BC_STATUS_FAILURE;
4635 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004636
4637 return s;
4638}
4639
4640static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4641{
4642 BcStatus s = BC_STATUS_SUCCESS;
4643 BcInst prev = BC_INST_PRINT;
4644 BcLexType top, t = p->l.t.t;
4645 size_t nexprs = 0, ops_bgn = p->ops.len;
4646 uint32_t i, nparens, nrelops;
4647 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4648
4649 paren_first = p->l.t.t == BC_LEX_LPAREN;
4650 nparens = nrelops = 0;
4651 paren_expr = rprn = done = get_token = assign = false;
4652 bin_last = true;
4653
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004654 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004655 switch (t) {
4656
4657 case BC_LEX_OP_INC:
4658 case BC_LEX_OP_DEC:
4659 {
4660 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4661 rprn = get_token = bin_last = false;
4662 break;
4663 }
4664
4665 case BC_LEX_OP_MINUS:
4666 {
4667 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4668 rprn = get_token = false;
4669 bin_last = prev == BC_INST_MINUS;
4670 break;
4671 }
4672
4673 case BC_LEX_OP_ASSIGN_POWER:
4674 case BC_LEX_OP_ASSIGN_MULTIPLY:
4675 case BC_LEX_OP_ASSIGN_DIVIDE:
4676 case BC_LEX_OP_ASSIGN_MODULUS:
4677 case BC_LEX_OP_ASSIGN_PLUS:
4678 case BC_LEX_OP_ASSIGN_MINUS:
4679 case BC_LEX_OP_ASSIGN:
4680 {
4681 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4682 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4683 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4684 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004685 s = bc_error("bad assignment:"
4686 " left side must be scale,"
4687 " ibase, obase, last, var,"
4688 " or array element"
4689 );
Gavin Howard01055ba2018-11-03 11:00:21 -06004690 break;
4691 }
4692 }
4693 // Fallthrough.
4694 case BC_LEX_OP_POWER:
4695 case BC_LEX_OP_MULTIPLY:
4696 case BC_LEX_OP_DIVIDE:
4697 case BC_LEX_OP_MODULUS:
4698 case BC_LEX_OP_PLUS:
4699 case BC_LEX_OP_REL_EQ:
4700 case BC_LEX_OP_REL_LE:
4701 case BC_LEX_OP_REL_GE:
4702 case BC_LEX_OP_REL_NE:
4703 case BC_LEX_OP_REL_LT:
4704 case BC_LEX_OP_REL_GT:
4705 case BC_LEX_OP_BOOL_NOT:
4706 case BC_LEX_OP_BOOL_OR:
4707 case BC_LEX_OP_BOOL_AND:
4708 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004709 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last)
4710 || (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT)
4711 ) {
4712 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004713 }
4714
4715 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4716 prev = BC_PARSE_TOKEN_INST(t);
4717 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4718 rprn = get_token = false;
4719 bin_last = t != BC_LEX_OP_BOOL_NOT;
4720
4721 break;
4722 }
4723
4724 case BC_LEX_LPAREN:
4725 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004726 if (BC_PARSE_LEAF(prev, rprn))
4727 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004728 ++nparens;
4729 paren_expr = rprn = bin_last = false;
4730 get_token = true;
4731 bc_vec_push(&p->ops, &t);
4732
4733 break;
4734 }
4735
4736 case BC_LEX_RPAREN:
4737 {
4738 if (bin_last || prev == BC_INST_BOOL_NOT)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004739 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004740
4741 if (nparens == 0) {
4742 s = BC_STATUS_SUCCESS;
4743 done = true;
4744 get_token = false;
4745 break;
4746 }
4747 else if (!paren_expr)
4748 return BC_STATUS_PARSE_EMPTY_EXP;
4749
4750 --nparens;
4751 paren_expr = rprn = true;
4752 get_token = bin_last = false;
4753
4754 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4755
4756 break;
4757 }
4758
4759 case BC_LEX_NAME:
4760 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004761 if (BC_PARSE_LEAF(prev, rprn))
4762 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004763 paren_expr = true;
4764 rprn = get_token = bin_last = false;
4765 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4766 ++nexprs;
4767
4768 break;
4769 }
4770
4771 case BC_LEX_NUMBER:
4772 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004773 if (BC_PARSE_LEAF(prev, rprn))
4774 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004775 bc_parse_number(p, &prev, &nexprs);
4776 paren_expr = get_token = true;
4777 rprn = bin_last = false;
4778
4779 break;
4780 }
4781
4782 case BC_LEX_KEY_IBASE:
4783 case BC_LEX_KEY_LAST:
4784 case BC_LEX_KEY_OBASE:
4785 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004786 if (BC_PARSE_LEAF(prev, rprn))
4787 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004788 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4789 bc_parse_push(p, (char) prev);
4790
4791 paren_expr = get_token = true;
4792 rprn = bin_last = false;
4793 ++nexprs;
4794
4795 break;
4796 }
4797
4798 case BC_LEX_KEY_LENGTH:
4799 case BC_LEX_KEY_SQRT:
4800 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004801 if (BC_PARSE_LEAF(prev, rprn))
4802 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004803 s = bc_parse_builtin(p, t, flags, &prev);
4804 paren_expr = true;
4805 rprn = get_token = bin_last = false;
4806 ++nexprs;
4807
4808 break;
4809 }
4810
4811 case BC_LEX_KEY_READ:
4812 {
4813 if (BC_PARSE_LEAF(prev, rprn))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004814 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004815 else if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004816 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06004817 else
4818 s = bc_parse_read(p);
4819
4820 paren_expr = true;
4821 rprn = get_token = bin_last = false;
4822 ++nexprs;
4823 prev = BC_INST_READ;
4824
4825 break;
4826 }
4827
4828 case BC_LEX_KEY_SCALE:
4829 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004830 if (BC_PARSE_LEAF(prev, rprn))
4831 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004832 s = bc_parse_scale(p, &prev, flags);
4833 paren_expr = true;
4834 rprn = get_token = bin_last = false;
4835 ++nexprs;
4836 prev = BC_INST_SCALE;
4837
4838 break;
4839 }
4840
4841 default:
4842 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004843 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004844 break;
4845 }
4846 }
4847
4848 if (!s && get_token) s = bc_lex_next(&p->l);
4849 }
4850
4851 if (s) return s;
Denys Vlasenkod38af482018-12-04 19:11:02 +01004852 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
Gavin Howard01055ba2018-11-03 11:00:21 -06004853
4854 while (p->ops.len > ops_bgn) {
4855
4856 top = BC_PARSE_TOP_OP(p);
4857 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4858
4859 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004860 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004861
4862 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4863
4864 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4865 bc_vec_pop(&p->ops);
4866 }
4867
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004868 if (prev == BC_INST_BOOL_NOT || nexprs != 1)
4869 return bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06004870
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004871 for (i = 0; i < next.len; ++i)
4872 if (t == next.tokens[i])
4873 goto ok;
4874 return bc_error("bad expression");
4875 ok:
Gavin Howard01055ba2018-11-03 11:00:21 -06004876
4877 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004878 s = bc_posix_error("POSIX does not allow comparison operators outside if or loops");
Gavin Howard01055ba2018-11-03 11:00:21 -06004879 if (s) return s;
4880 }
4881 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01004882 s = bc_posix_error("POSIX requires exactly one comparison operator per condition");
Gavin Howard01055ba2018-11-03 11:00:21 -06004883 if (s) return s;
4884 }
4885
4886 if (flags & BC_PARSE_PRINT) {
4887 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4888 bc_parse_push(p, BC_INST_POP);
4889 }
4890
4891 return s;
4892}
4893
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004894static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004895{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004896 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004897}
4898
4899static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4900{
4901 return bc_parse_expr(p, flags, bc_parse_next_read);
4902}
4903#endif // ENABLE_BC
4904
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004905#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06004906static BcStatus dc_parse_register(BcParse *p)
4907{
4908 BcStatus s;
4909 char *name;
4910
4911 s = bc_lex_next(&p->l);
4912 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01004913 if (p->l.t.t != BC_LEX_NAME) return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06004914
4915 name = xstrdup(p->l.t.v.v);
4916 bc_parse_pushName(p, name);
4917
4918 return s;
4919}
4920
4921static BcStatus dc_parse_string(BcParse *p)
4922{
4923 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004924 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06004925
4926 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
4927 name = xstrdup(b);
4928
4929 str = xstrdup(p->l.t.v.v);
4930 bc_parse_push(p, BC_INST_STR);
4931 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004932 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004933 bc_parse_addFunc(p, name, &idx);
4934
4935 return bc_lex_next(&p->l);
4936}
4937
4938static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
4939{
4940 BcStatus s;
4941
4942 bc_parse_push(p, inst);
4943 if (name) {
4944 s = dc_parse_register(p);
4945 if (s) return s;
4946 }
4947
4948 if (store) {
4949 bc_parse_push(p, BC_INST_SWAP);
4950 bc_parse_push(p, BC_INST_ASSIGN);
4951 bc_parse_push(p, BC_INST_POP);
4952 }
4953
4954 return bc_lex_next(&p->l);
4955}
4956
4957static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
4958{
4959 BcStatus s;
4960
4961 bc_parse_push(p, inst);
4962 bc_parse_push(p, BC_INST_EXEC_COND);
4963
4964 s = dc_parse_register(p);
4965 if (s) return s;
4966
4967 s = bc_lex_next(&p->l);
4968 if (s) return s;
4969
4970 if (p->l.t.t == BC_LEX_ELSE) {
4971 s = dc_parse_register(p);
4972 if (s) return s;
4973 s = bc_lex_next(&p->l);
4974 }
4975 else
4976 bc_parse_push(p, BC_PARSE_STREND);
4977
4978 return s;
4979}
4980
4981static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
4982{
4983 BcStatus s = BC_STATUS_SUCCESS;
4984 BcInst prev;
4985 uint8_t inst;
4986 bool assign, get_token = false;
4987
4988 switch (t) {
4989
4990 case BC_LEX_OP_REL_EQ:
4991 case BC_LEX_OP_REL_LE:
4992 case BC_LEX_OP_REL_GE:
4993 case BC_LEX_OP_REL_NE:
4994 case BC_LEX_OP_REL_LT:
4995 case BC_LEX_OP_REL_GT:
4996 {
4997 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
4998 break;
4999 }
5000
5001 case BC_LEX_SCOLON:
5002 case BC_LEX_COLON:
5003 {
5004 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5005 break;
5006 }
5007
5008 case BC_LEX_STR:
5009 {
5010 s = dc_parse_string(p);
5011 break;
5012 }
5013
5014 case BC_LEX_NEG:
5015 case BC_LEX_NUMBER:
5016 {
5017 if (t == BC_LEX_NEG) {
5018 s = bc_lex_next(&p->l);
5019 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005020 if (p->l.t.t != BC_LEX_NUMBER)
5021 return bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005022 }
5023
5024 bc_parse_number(p, &prev, &p->nbraces);
5025
5026 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5027 get_token = true;
5028
5029 break;
5030 }
5031
5032 case BC_LEX_KEY_READ:
5033 {
5034 if (flags & BC_PARSE_NOREAD)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005035 s = bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005036 else
5037 bc_parse_push(p, BC_INST_READ);
5038 get_token = true;
5039 break;
5040 }
5041
5042 case BC_LEX_OP_ASSIGN:
5043 case BC_LEX_STORE_PUSH:
5044 {
5045 assign = t == BC_LEX_OP_ASSIGN;
5046 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5047 s = dc_parse_mem(p, inst, true, assign);
5048 break;
5049 }
5050
5051 case BC_LEX_LOAD:
5052 case BC_LEX_LOAD_POP:
5053 {
5054 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5055 s = dc_parse_mem(p, inst, true, false);
5056 break;
5057 }
5058
5059 case BC_LEX_STORE_IBASE:
5060 case BC_LEX_STORE_SCALE:
5061 case BC_LEX_STORE_OBASE:
5062 {
5063 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5064 s = dc_parse_mem(p, inst, false, true);
5065 break;
5066 }
5067
5068 default:
5069 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005070 s = bc_error("bad token");
Gavin Howard01055ba2018-11-03 11:00:21 -06005071 get_token = true;
5072 break;
5073 }
5074 }
5075
5076 if (!s && get_token) s = bc_lex_next(&p->l);
5077
5078 return s;
5079}
5080
5081static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5082{
5083 BcStatus s = BC_STATUS_SUCCESS;
5084 BcInst inst;
5085 BcLexType t;
5086
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005087 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005088
5089 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5090
5091 inst = dc_parse_insts[t];
5092
5093 if (inst != BC_INST_INVALID) {
5094 bc_parse_push(p, inst);
5095 s = bc_lex_next(&p->l);
5096 }
5097 else
5098 s = dc_parse_token(p, t, flags);
5099 }
5100
5101 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5102 bc_parse_push(p, BC_INST_POP_EXEC);
5103
5104 return s;
5105}
5106
5107static BcStatus dc_parse_parse(BcParse *p)
5108{
5109 BcStatus s;
5110
5111 if (p->l.t.t == BC_LEX_EOF)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005112 s = bc_error("end of file");
Gavin Howard01055ba2018-11-03 11:00:21 -06005113 else
5114 s = dc_parse_expr(p, 0);
5115
Denys Vlasenkod38af482018-12-04 19:11:02 +01005116 if (s || G_interrupt) {
5117 bc_parse_reset(p);
5118 s = BC_STATUS_FAILURE;
5119 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005120
5121 return s;
5122}
5123
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005124static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005125{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005126 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005127}
5128#endif // ENABLE_DC
5129
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005130static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005131{
5132 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005133 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005134 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005135 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005136 }
5137}
5138
5139static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5140{
5141 if (IS_BC) {
5142 return bc_parse_expression(p, flags);
5143 } else {
5144 return dc_parse_expr(p, flags);
5145 }
5146}
5147
Denys Vlasenkodf515392018-12-02 19:27:48 +01005148static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005149{
Gavin Howard01055ba2018-11-03 11:00:21 -06005150 BcId e, *ptr;
5151 BcVec *v, *map;
5152 size_t i;
5153 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005154 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005155
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005156 v = var ? &G.prog.vars : &G.prog.arrs;
5157 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005158
5159 e.name = id;
5160 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005161 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005162
5163 if (new) {
5164 bc_array_init(&data.v, var);
5165 bc_vec_push(v, &data.v);
5166 }
5167
5168 ptr = bc_vec_item(map, i);
5169 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005170 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005171}
5172
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005173static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005174{
5175 BcStatus s = BC_STATUS_SUCCESS;
5176
5177 switch (r->t) {
5178
5179 case BC_RESULT_STR:
5180 case BC_RESULT_TEMP:
5181 case BC_RESULT_IBASE:
5182 case BC_RESULT_SCALE:
5183 case BC_RESULT_OBASE:
5184 {
5185 *num = &r->d.n;
5186 break;
5187 }
5188
5189 case BC_RESULT_CONSTANT:
5190 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005191 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005192 size_t base_t, len = strlen(*str);
5193 BcNum *base;
5194
5195 bc_num_init(&r->d.n, len);
5196
5197 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005198 base = hex ? &G.prog.hexb : &G.prog.ib;
5199 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005200 s = bc_num_parse(&r->d.n, *str, base, base_t);
5201
5202 if (s) {
5203 bc_num_free(&r->d.n);
5204 return s;
5205 }
5206
5207 *num = &r->d.n;
5208 r->t = BC_RESULT_TEMP;
5209
5210 break;
5211 }
5212
5213 case BC_RESULT_VAR:
5214 case BC_RESULT_ARRAY:
5215 case BC_RESULT_ARRAY_ELEM:
5216 {
5217 BcVec *v;
5218
Denys Vlasenkodf515392018-12-02 19:27:48 +01005219 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005220
5221 if (r->t == BC_RESULT_ARRAY_ELEM) {
5222 v = bc_vec_top(v);
5223 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5224 *num = bc_vec_item(v, r->d.id.idx);
5225 }
5226 else
5227 *num = bc_vec_top(v);
5228
5229 break;
5230 }
5231
5232 case BC_RESULT_LAST:
5233 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005234 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005235 break;
5236 }
5237
5238 case BC_RESULT_ONE:
5239 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005240 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005241 break;
5242 }
5243 }
5244
5245 return s;
5246}
5247
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005248static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005249 BcResult **r, BcNum **rn, bool assign)
5250{
5251 BcStatus s;
5252 bool hex;
5253 BcResultType lt, rt;
5254
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005255 if (!BC_PROG_STACK(&G.prog.results, 2))
5256 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005257
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005258 *r = bc_vec_item_rev(&G.prog.results, 0);
5259 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005260
5261 lt = (*l)->t;
5262 rt = (*r)->t;
5263 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5264
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005265 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005266 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005267 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005268 if (s) return s;
5269
5270 // We run this again under these conditions in case any vector has been
5271 // reallocated out from under the BcNums or arrays we had.
5272 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005273 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005274 if (s) return s;
5275 }
5276
5277 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005278 return bc_error("variable is wrong type");
5279 if (!assign && !BC_PROG_NUM((*r), (*ln)))
5280 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005281
Gavin Howard01055ba2018-11-03 11:00:21 -06005282 return s;
5283}
5284
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005285static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005286{
5287 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005288 bc_vec_pop(&G.prog.results);
5289 bc_vec_pop(&G.prog.results);
5290 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005291}
5292
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005293static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005294{
5295 BcStatus s;
5296
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005297 if (!BC_PROG_STACK(&G.prog.results, 1))
5298 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005299 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005300
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005301 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005302 if (s) return s;
5303
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005304 if (!BC_PROG_NUM((*r), (*n)))
5305 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005306
5307 return s;
5308}
5309
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005310static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005311{
5312 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005313 bc_vec_pop(&G.prog.results);
5314 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005315}
5316
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005317static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005318{
5319 BcStatus s;
5320 BcResult *opd1, *opd2, res;
5321 BcNum *n1, *n2 = NULL;
5322
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005323 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005324 if (s) return s;
5325 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5326
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005327 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005328 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005329 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005330
5331 return s;
5332
5333err:
5334 bc_num_free(&res.d.n);
5335 return s;
5336}
5337
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005338static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005339{
5340 BcStatus s;
5341 BcParse parse;
5342 BcVec buf;
5343 BcInstPtr ip;
5344 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005345 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005346
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005347 for (i = 0; i < G.prog.stack.len; ++i) {
5348 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005349 if (ip_ptr->func == BC_PROG_READ)
5350 return bc_error("read() call inside of a read() call");
Gavin Howard01055ba2018-11-03 11:00:21 -06005351 }
5352
5353 bc_vec_npop(&f->code, f->code.len);
5354 bc_vec_init(&buf, sizeof(char), NULL);
5355
5356 s = bc_read_line(&buf, "read> ");
5357 if (s) goto io_err;
5358
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005359 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005360 bc_lex_file(&parse.l, bc_program_stdin_name);
5361
5362 s = bc_parse_text(&parse, buf.v);
5363 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005364 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005365 if (s) goto exec_err;
5366
5367 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005368 s = bc_error("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005369 goto exec_err;
5370 }
5371
5372 ip.func = BC_PROG_READ;
5373 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005374 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005375
5376 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005377 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005378
5379 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005380 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005381
5382exec_err:
5383 bc_parse_free(&parse);
5384io_err:
5385 bc_vec_free(&buf);
5386 return s;
5387}
5388
5389static size_t bc_program_index(char *code, size_t *bgn)
5390{
5391 char amt = code[(*bgn)++], i = 0;
5392 size_t res = 0;
5393
5394 for (; i < amt; ++i, ++(*bgn))
5395 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5396
5397 return res;
5398}
5399
5400static char *bc_program_name(char *code, size_t *bgn)
5401{
5402 size_t i;
5403 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5404
5405 s = xmalloc(ptr - str + 1);
5406 c = code[(*bgn)++];
5407
5408 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5409 s[i] = c;
5410
5411 s[i] = '\0';
5412
5413 return s;
5414}
5415
5416static void bc_program_printString(const char *str, size_t *nchars)
5417{
5418 size_t i, len = strlen(str);
5419
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005420#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005421 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005422 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005423 return;
5424 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005425#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005426
5427 for (i = 0; i < len; ++i, ++(*nchars)) {
5428
5429 int c = str[i];
5430
5431 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005432 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005433 else {
5434
5435 c = str[++i];
5436
5437 switch (c) {
5438
5439 case 'a':
5440 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005441 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005442 break;
5443 }
5444
5445 case 'b':
5446 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005447 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005448 break;
5449 }
5450
5451 case '\\':
5452 case 'e':
5453 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005454 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005455 break;
5456 }
5457
5458 case 'f':
5459 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005460 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005461 break;
5462 }
5463
5464 case 'n':
5465 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005466 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005467 *nchars = SIZE_MAX;
5468 break;
5469 }
5470
5471 case 'r':
5472 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005473 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005474 break;
5475 }
5476
5477 case 'q':
5478 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005479 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005480 break;
5481 }
5482
5483 case 't':
5484 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005485 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005486 break;
5487 }
5488
5489 default:
5490 {
5491 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005492 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005493 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005494 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005495 break;
5496 }
5497 }
5498 }
5499 }
5500}
5501
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005502static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005503{
5504 BcStatus s = BC_STATUS_SUCCESS;
5505 BcResult *r;
5506 size_t len, i;
5507 char *str;
5508 BcNum *num = NULL;
5509 bool pop = inst != BC_INST_PRINT;
5510
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005511 if (!BC_PROG_STACK(&G.prog.results, idx + 1))
5512 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005513
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005514 r = bc_vec_item_rev(&G.prog.results, idx);
5515 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005516 if (s) return s;
5517
5518 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005519 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5520 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005521 }
5522 else {
5523
5524 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005525 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005526
5527 if (inst == BC_INST_PRINT_STR) {
5528 for (i = 0, len = strlen(str); i < len; ++i) {
5529 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005530 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005531 if (c == '\n') G.prog.nchars = SIZE_MAX;
5532 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005533 }
5534 }
5535 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005536 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005537 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005538 }
5539 }
5540
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005541 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005542
5543 return s;
5544}
5545
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005546static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005547{
5548 BcStatus s;
5549 BcResult res, *ptr;
5550 BcNum *num = NULL;
5551
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005552 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005553 if (s) return s;
5554
5555 bc_num_init(&res.d.n, num->len);
5556 bc_num_copy(&res.d.n, num);
5557 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5558
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005559 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005560
5561 return s;
5562}
5563
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005564static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005565{
5566 BcStatus s;
5567 BcResult *opd1, *opd2, res;
5568 BcNum *n1, *n2;
5569 bool cond = 0;
5570 ssize_t cmp;
5571
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005572 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005573 if (s) return s;
5574 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5575
5576 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005577 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005578 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005579 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005580 else {
5581
5582 cmp = bc_num_cmp(n1, n2);
5583
5584 switch (inst) {
5585
5586 case BC_INST_REL_EQ:
5587 {
5588 cond = cmp == 0;
5589 break;
5590 }
5591
5592 case BC_INST_REL_LE:
5593 {
5594 cond = cmp <= 0;
5595 break;
5596 }
5597
5598 case BC_INST_REL_GE:
5599 {
5600 cond = cmp >= 0;
5601 break;
5602 }
5603
5604 case BC_INST_REL_NE:
5605 {
5606 cond = cmp != 0;
5607 break;
5608 }
5609
5610 case BC_INST_REL_LT:
5611 {
5612 cond = cmp < 0;
5613 break;
5614 }
5615
5616 case BC_INST_REL_GT:
5617 {
5618 cond = cmp > 0;
5619 break;
5620 }
5621 }
5622 }
5623
5624 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5625
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005626 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005627
5628 return s;
5629}
5630
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005631#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005632static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005633 bool push)
5634{
5635 BcNum n2;
5636 BcResult res;
5637
5638 memset(&n2, 0, sizeof(BcNum));
5639 n2.rdx = res.d.id.idx = r->d.id.idx;
5640 res.t = BC_RESULT_STR;
5641
5642 if (!push) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005643 if (!BC_PROG_STACK(&G.prog.results, 2))
5644 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005645 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005646 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005647 }
5648
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005650
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005651 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005652 bc_vec_push(v, &n2);
5653
5654 return BC_STATUS_SUCCESS;
5655}
5656#endif // ENABLE_DC
5657
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005658static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005659{
5660 BcStatus s;
5661 BcResult *ptr, r;
5662 BcVec *v;
5663 BcNum *n;
5664
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005665 if (!BC_PROG_STACK(&G.prog.results, 1))
5666 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005667
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005668 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005669 if ((ptr->t == BC_RESULT_ARRAY) != !var)
5670 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005671 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005672
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005673#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005674 if (ptr->t == BC_RESULT_STR && !var)
5675 return bc_error("variable is wrong type");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005676 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005677#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005678
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005679 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005680 if (s) return s;
5681
5682 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005683 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005684
5685 if (var) {
5686 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5687 bc_num_copy(&r.d.n, n);
5688 }
5689 else {
5690 bc_array_init(&r.d.v, true);
5691 bc_array_copy(&r.d.v, (BcVec *) n);
5692 }
5693
5694 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005695 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005696
5697 return s;
5698}
5699
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005700static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005701{
5702 BcStatus s;
5703 BcResult *left, *right, res;
5704 BcNum *l = NULL, *r = NULL;
5705 unsigned long val, max;
5706 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5707
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005708 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005709 if (s) return s;
5710
5711 ib = left->t == BC_RESULT_IBASE;
5712 sc = left->t == BC_RESULT_SCALE;
5713
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005714#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005715
5716 if (right->t == BC_RESULT_STR) {
5717
5718 BcVec *v;
5719
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005720 if (left->t != BC_RESULT_VAR)
5721 return bc_error("variable is wrong type");
Denys Vlasenkodf515392018-12-02 19:27:48 +01005722 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005723
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005724 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005725 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005726#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005727
5728 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005729 return bc_error("bad assignment:"
5730 " left side must be scale,"
5731 " ibase, obase, last, var,"
5732 " or array element"
5733 );
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005735#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005736 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005737 return bc_error("divide by zero");
Gavin Howard01055ba2018-11-03 11:00:21 -06005738
5739 if (assign)
5740 bc_num_copy(l, r);
5741 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005742 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005743
5744 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005745#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005746 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005747#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005748
5749 if (ib || sc || left->t == BC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005750 static const char *const msg[] = {
5751 "bad ibase; must be [2, 16]", //BC_RESULT_IBASE
5752 "bad scale; must be [0, BC_SCALE_MAX]", //BC_RESULT_SCALE
5753 "?1", //BC_RESULT_LAST
5754 "?2", //BC_RESULT_CONSTANT
5755 "?3", //BC_RESULT_ONE
5756 "bad obase; must be [2, BC_BASE_MAX]", //BC_RESULT_OBASE
5757 };
Gavin Howard01055ba2018-11-03 11:00:21 -06005758 size_t *ptr;
5759
5760 s = bc_num_ulong(l, &val);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005761 if (s)
5762 return s;
5763 s = left->t - BC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005764 if (sc) {
5765 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005766 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005767 }
5768 else {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005769 if (val < BC_NUM_MIN_BASE)
5770 return bc_error(msg[s]);
Gavin Howard01055ba2018-11-03 11:00:21 -06005771 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005772 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005773 }
5774
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005775 if (val > max)
5776 return bc_error(msg[s]);
5777 if (!sc)
5778 bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005779
5780 *ptr = (size_t) val;
5781 s = BC_STATUS_SUCCESS;
5782 }
5783
5784 bc_num_init(&res.d.n, l->len);
5785 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005786 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005787
5788 return s;
5789}
5790
Denys Vlasenko416ce762018-12-02 20:57:17 +01005791#if !ENABLE_DC
5792#define bc_program_pushVar(code, bgn, pop, copy) \
5793 bc_program_pushVar(code, bgn)
5794// for bc, 'pop' and 'copy' are always false
5795#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005796static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005797 bool pop, bool copy)
5798{
5799 BcStatus s = BC_STATUS_SUCCESS;
5800 BcResult r;
5801 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005802
5803 r.t = BC_RESULT_VAR;
5804 r.d.id.name = name;
5805
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005806#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005807 {
5808 BcVec *v = bc_program_search(name, true);
5809 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005810
Denys Vlasenko416ce762018-12-02 20:57:17 +01005811 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005812
Denys Vlasenko416ce762018-12-02 20:57:17 +01005813 if (!BC_PROG_STACK(v, 2 - copy)) {
5814 free(name);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005815 return bc_error("stack has too few elements");
Denys Vlasenko416ce762018-12-02 20:57:17 +01005816 }
5817
Gavin Howard01055ba2018-11-03 11:00:21 -06005818 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005819 name = NULL;
5820
5821 if (!BC_PROG_STR(num)) {
5822
5823 r.t = BC_RESULT_TEMP;
5824
5825 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5826 bc_num_copy(&r.d.n, num);
5827 }
5828 else {
5829 r.t = BC_RESULT_STR;
5830 r.d.id.idx = num->rdx;
5831 }
5832
5833 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005834 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005835 }
5836#endif // ENABLE_DC
5837
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005838 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005839
5840 return s;
5841}
5842
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005843static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005844 char inst)
5845{
5846 BcStatus s = BC_STATUS_SUCCESS;
5847 BcResult r;
5848 BcNum *num;
5849
5850 r.d.id.name = bc_program_name(code, bgn);
5851
5852 if (inst == BC_INST_ARRAY) {
5853 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005854 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005855 }
5856 else {
5857
5858 BcResult *operand;
5859 unsigned long temp;
5860
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005861 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005862 if (s) goto err;
5863 s = bc_num_ulong(num, &temp);
5864 if (s) goto err;
5865
5866 if (temp > BC_MAX_DIM) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005867 s = bc_error("array too long; must be [1, BC_DIM_MAX]");
Gavin Howard01055ba2018-11-03 11:00:21 -06005868 goto err;
5869 }
5870
5871 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005872 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005873 }
5874
5875err:
5876 if (s) free(r.d.id.name);
5877 return s;
5878}
5879
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005880#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005881static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005882{
5883 BcStatus s;
5884 BcResult *ptr, res, copy;
5885 BcNum *num = NULL;
5886 char inst2 = inst;
5887
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005888 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005889 if (s) return s;
5890
5891 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5892 copy.t = BC_RESULT_TEMP;
5893 bc_num_init(&copy.d.n, num->len);
5894 bc_num_copy(&copy.d.n, num);
5895 }
5896
5897 res.t = BC_RESULT_ONE;
5898 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5899 BC_INST_ASSIGN_PLUS :
5900 BC_INST_ASSIGN_MINUS;
5901
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005902 bc_vec_push(&G.prog.results, &res);
5903 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005904
5905 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005906 bc_vec_pop(&G.prog.results);
5907 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005908 }
5909
5910 return s;
5911}
5912
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005913static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005914{
5915 BcStatus s = BC_STATUS_SUCCESS;
5916 BcInstPtr ip;
5917 size_t i, nparams = bc_program_index(code, idx);
5918 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005919 BcId *a;
5920 BcResultData param;
5921 BcResult *arg;
5922
5923 ip.idx = 0;
5924 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005925 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005926
Denys Vlasenko04a1c762018-12-03 21:10:57 +01005927 if (func->code.len == 0) {
5928 return bc_error("undefined function");
5929 }
5930 if (nparams != func->nparams) {
5931 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
5932 }
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005933 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005934
5935 for (i = 0; i < nparams; ++i) {
5936
5937 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005938 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005939
5940 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005941 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06005942
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005943 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005944 if (s) return s;
5945 }
5946
5947 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01005948 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06005949
5950 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005951 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005952
5953 if (a->idx) {
5954 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5955 bc_vec_push(v, &param.n);
5956 }
5957 else {
5958 bc_array_init(&param.v, true);
5959 bc_vec_push(v, &param.v);
5960 }
5961 }
5962
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005963 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005964
5965 return BC_STATUS_SUCCESS;
5966}
5967
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005968static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005969{
5970 BcStatus s;
5971 BcResult res;
5972 BcFunc *f;
5973 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005974 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06005975
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005976 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005977 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06005978
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005979 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005980 res.t = BC_RESULT_TEMP;
5981
5982 if (inst == BC_INST_RET) {
5983
5984 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005985 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005986
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005987 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005988 if (s) return s;
5989 bc_num_init(&res.d.n, num->len);
5990 bc_num_copy(&res.d.n, num);
5991 }
5992 else {
5993 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5994 bc_num_zero(&res.d.n);
5995 }
5996
5997 // We need to pop arguments as well, so this takes that into account.
5998 for (i = 0; i < f->autos.len; ++i) {
5999
6000 BcVec *v;
6001 BcId *a = bc_vec_item(&f->autos, i);
6002
Denys Vlasenkodf515392018-12-02 19:27:48 +01006003 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006004 bc_vec_pop(v);
6005 }
6006
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006007 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6008 bc_vec_push(&G.prog.results, &res);
6009 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006010
6011 return BC_STATUS_SUCCESS;
6012}
6013#endif // ENABLE_BC
6014
6015static unsigned long bc_program_scale(BcNum *n)
6016{
6017 return (unsigned long) n->rdx;
6018}
6019
6020static unsigned long bc_program_len(BcNum *n)
6021{
6022 unsigned long len = n->len;
6023 size_t i;
6024
6025 if (n->rdx != n->len) return len;
6026 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6027
6028 return len;
6029}
6030
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006031static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006032{
6033 BcStatus s;
6034 BcResult *opnd;
6035 BcNum *num = NULL;
6036 BcResult res;
6037 bool len = inst == BC_INST_LENGTH;
6038
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006039 if (!BC_PROG_STACK(&G.prog.results, 1))
6040 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006041 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006042
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006043 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006044 if (s) return s;
6045
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006046#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006047 if (!BC_PROG_NUM(opnd, num) && !len)
6048 return bc_error("variable is wrong type");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006049#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006050
6051 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6052
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006053 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006054#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006055 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006056 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006057 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006058#endif
6059#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006060 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6061
6062 char **str;
6063 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6064
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006065 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006066 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006067 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006068#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006069 else {
6070 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006071 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006072 }
6073
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006074 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006075
6076 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006077}
6078
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006079#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006080static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006081{
6082 BcStatus s;
6083 BcResult *opd1, *opd2, res, res2;
6084 BcNum *n1, *n2 = NULL;
6085
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006086 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006087 if (s) return s;
6088
6089 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6090 bc_num_init(&res2.d.n, n2->len);
6091
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006092 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006093 if (s) goto err;
6094
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006095 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006096 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006097 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006098
6099 return s;
6100
6101err:
6102 bc_num_free(&res2.d.n);
6103 bc_num_free(&res.d.n);
6104 return s;
6105}
6106
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006107static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006108{
6109 BcStatus s;
6110 BcResult *r1, *r2, *r3, res;
6111 BcNum *n1, *n2, *n3;
6112
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006113 if (!BC_PROG_STACK(&G.prog.results, 3))
6114 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006115 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006116 if (s) return s;
6117
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006118 r1 = bc_vec_item_rev(&G.prog.results, 2);
6119 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006120 if (s) return s;
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006121 if (!BC_PROG_NUM(r1, n1))
6122 return bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006123
6124 // Make sure that the values have their pointers updated, if necessary.
6125 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6126
6127 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006128 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006129 if (s) return s;
6130 }
6131
6132 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006133 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006134 if (s) return s;
6135 }
6136 }
6137
6138 bc_num_init(&res.d.n, n3->len);
6139 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6140 if (s) goto err;
6141
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006142 bc_vec_pop(&G.prog.results);
6143 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006144
6145 return s;
6146
6147err:
6148 bc_num_free(&res.d.n);
6149 return s;
6150}
6151
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006152static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006153{
Gavin Howard01055ba2018-11-03 11:00:21 -06006154 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006155 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006156
6157 res.t = BC_RESULT_TEMP;
6158
6159 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006160 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006161 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006162}
6163
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006164static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006165{
6166 BcStatus s;
6167 BcResult *r, res;
6168 BcNum *num = NULL, n;
6169 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006170 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006171 unsigned long val;
6172
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006173 if (!BC_PROG_STACK(&G.prog.results, 1))
6174 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006175 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006176
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006177 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006178 if (s) return s;
6179
6180 if (BC_PROG_NUM(r, num)) {
6181
6182 bc_num_init(&n, BC_NUM_DEF_SIZE);
6183 bc_num_copy(&n, num);
6184 bc_num_truncate(&n, n.rdx);
6185
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006186 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006187 if (s) goto num_err;
6188 s = bc_num_ulong(&n, &val);
6189 if (s) goto num_err;
6190
6191 c = (char) val;
6192
6193 bc_num_free(&n);
6194 }
6195 else {
6196 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006197 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006198 c = str2[0];
6199 }
6200
6201 str = xmalloc(2);
6202 str[0] = c;
6203 str[1] = '\0';
6204
6205 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006206 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006207
6208 if (idx != len + BC_PROG_REQ_FUNCS) {
6209
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006210 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6211 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006212 len = idx;
6213 break;
6214 }
6215 }
6216
6217 free(str);
6218 }
6219 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006220 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006221
6222 res.t = BC_RESULT_STR;
6223 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006224 bc_vec_pop(&G.prog.results);
6225 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006226
6227 return BC_STATUS_SUCCESS;
6228
6229num_err:
6230 bc_num_free(&n);
6231 return s;
6232}
6233
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006234static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006235{
6236 BcStatus s;
6237 BcResult *r;
6238 BcNum *n = NULL;
6239 size_t idx;
6240 char *str;
6241
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006242 if (!BC_PROG_STACK(&G.prog.results, 1))
6243 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006244 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006245
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006246 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006247 if (s) return s;
6248
6249 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006250 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006251 else {
6252 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006253 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006254 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006255 }
6256
6257 return s;
6258}
6259
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006260static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006261{
6262 BcStatus s;
6263 BcResult *opnd;
6264 BcNum *num = NULL;
6265 unsigned long val;
6266
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006267 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006268 if (s) return s;
6269 s = bc_num_ulong(num, &val);
6270 if (s) return s;
6271
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006272 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006273
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006274 if (G.prog.stack.len < val)
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006275 return bc_error("stack has too few elements");
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006276 if (G.prog.stack.len == val)
6277 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006278
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006279 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006280
6281 return s;
6282}
6283
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006284static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006285 bool cond)
6286{
6287 BcStatus s = BC_STATUS_SUCCESS;
6288 BcResult *r;
6289 char **str;
6290 BcFunc *f;
6291 BcParse prs;
6292 BcInstPtr ip;
6293 size_t fidx, sidx;
6294 BcNum *n;
6295 bool exec;
6296
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006297 if (!BC_PROG_STACK(&G.prog.results, 1))
6298 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006299
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006300 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006301
6302 if (cond) {
6303
Gavin Howard01055ba2018-11-03 11:00:21 -06006304 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6305
6306 if (code[*bgn] == BC_PARSE_STREND)
6307 (*bgn) += 1;
6308 else
6309 else_name = bc_program_name(code, bgn);
6310
6311 exec = r->d.n.len != 0;
6312
6313 if (exec)
6314 name = then_name;
6315 else if (else_name != NULL) {
6316 exec = true;
6317 name = else_name;
6318 }
6319
6320 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006321 BcVec *v;
6322 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006323 n = bc_vec_top(v);
6324 }
6325
6326 free(then_name);
6327 free(else_name);
6328
6329 if (!exec) goto exit;
6330 if (!BC_PROG_STR(n)) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006331 s = bc_error("variable is wrong type");
Gavin Howard01055ba2018-11-03 11:00:21 -06006332 goto exit;
6333 }
6334
6335 sidx = n->rdx;
6336 }
6337 else {
6338
6339 if (r->t == BC_RESULT_STR)
6340 sidx = r->d.id.idx;
6341 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006342 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006343 if (s || !BC_PROG_STR(n)) goto exit;
6344 sidx = n->rdx;
6345 }
6346 else
6347 goto exit;
6348 }
6349
6350 fidx = sidx + BC_PROG_REQ_FUNCS;
6351
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006352 str = bc_vec_item(&G.prog.strs, sidx);
6353 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006354
6355 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006356 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006357 s = bc_parse_text(&prs, *str);
6358 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006359 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006360 if (s) goto err;
6361
6362 if (prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006363 s = bc_error("bad expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06006364 goto err;
6365 }
6366
6367 bc_parse_free(&prs);
6368 }
6369
6370 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006371 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006372 ip.func = fidx;
6373
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006374 bc_vec_pop(&G.prog.results);
6375 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006376
6377 return BC_STATUS_SUCCESS;
6378
6379err:
6380 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006381 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006382 bc_vec_npop(&f->code, f->code.len);
6383exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006384 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006385 return s;
6386}
6387#endif // ENABLE_DC
6388
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006389static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006390{
Gavin Howard01055ba2018-11-03 11:00:21 -06006391 BcResult res;
6392 unsigned long val;
6393
6394 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6395 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006396 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006397 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006398 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006399 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006400 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006401
6402 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006403 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006404 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006405}
6406
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006407static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006408{
Gavin Howard01055ba2018-11-03 11:00:21 -06006409 BcId entry, *entry_ptr;
6410 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006411 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006412
6413 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006414 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006415
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006416 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6417 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006418
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006419 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006420 *idx = entry_ptr->idx;
6421
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006422 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006423
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006424 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006425
6426 // We need to reset these, so the function can be repopulated.
6427 func->nparams = 0;
6428 bc_vec_npop(&func->autos, func->autos.len);
6429 bc_vec_npop(&func->code, func->code.len);
6430 bc_vec_npop(&func->labels, func->labels.len);
6431 }
6432 else {
6433 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006434 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006435 }
6436}
6437
Denys Vlasenkod38af482018-12-04 19:11:02 +01006438// Called when parsing or execution detects a failure,
6439// resets execution structures.
6440static void bc_program_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006441{
6442 BcFunc *f;
6443 BcInstPtr *ip;
6444
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006445 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6446 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006447
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006448 f = bc_vec_item(&G.prog.fns, 0);
6449 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006450 ip->idx = f->code.len;
6451
Denys Vlasenkod38af482018-12-04 19:11:02 +01006452 // If !tty, no need to check for ^C: we don't have ^C handler,
6453 // we would be killed by a signal and won't reach this place
Gavin Howard01055ba2018-11-03 11:00:21 -06006454}
6455
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006456static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006457{
6458 BcStatus s = BC_STATUS_SUCCESS;
6459 size_t idx;
6460 BcResult r, *ptr;
6461 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006462 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6463 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 char *code = func->code.v;
6465 bool cond = false;
6466
6467 while (!s && ip->idx < func->code.len) {
6468
6469 char inst = code[(ip->idx)++];
6470
6471 switch (inst) {
6472
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006473#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006474 case BC_INST_JUMP_ZERO:
6475 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006476 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006477 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006478 cond = !bc_num_cmp(num, &G.prog.zero);
6479 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006480 }
6481 // Fallthrough.
6482 case BC_INST_JUMP:
6483 {
6484 size_t *addr;
6485 idx = bc_program_index(code, &ip->idx);
6486 addr = bc_vec_item(&func->labels, idx);
6487 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6488 break;
6489 }
6490
6491 case BC_INST_CALL:
6492 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006493 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006494 break;
6495 }
6496
6497 case BC_INST_INC_PRE:
6498 case BC_INST_DEC_PRE:
6499 case BC_INST_INC_POST:
6500 case BC_INST_DEC_POST:
6501 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006502 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006503 break;
6504 }
6505
6506 case BC_INST_HALT:
6507 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006508 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006509 break;
6510 }
6511
6512 case BC_INST_RET:
6513 case BC_INST_RET0:
6514 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006515 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006516 break;
6517 }
6518
6519 case BC_INST_BOOL_OR:
6520 case BC_INST_BOOL_AND:
6521#endif // ENABLE_BC
6522 case BC_INST_REL_EQ:
6523 case BC_INST_REL_LE:
6524 case BC_INST_REL_GE:
6525 case BC_INST_REL_NE:
6526 case BC_INST_REL_LT:
6527 case BC_INST_REL_GT:
6528 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006529 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530 break;
6531 }
6532
6533 case BC_INST_READ:
6534 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006535 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006536 break;
6537 }
6538
6539 case BC_INST_VAR:
6540 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006541 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006542 break;
6543 }
6544
6545 case BC_INST_ARRAY_ELEM:
6546 case BC_INST_ARRAY:
6547 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006548 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006549 break;
6550 }
6551
6552 case BC_INST_LAST:
6553 {
6554 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006555 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 break;
6557 }
6558
6559 case BC_INST_IBASE:
6560 case BC_INST_SCALE:
6561 case BC_INST_OBASE:
6562 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006563 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006564 break;
6565 }
6566
6567 case BC_INST_SCALE_FUNC:
6568 case BC_INST_LENGTH:
6569 case BC_INST_SQRT:
6570 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006571 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006572 break;
6573 }
6574
6575 case BC_INST_NUM:
6576 {
6577 r.t = BC_RESULT_CONSTANT;
6578 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006579 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006580 break;
6581 }
6582
6583 case BC_INST_POP:
6584 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006585 if (!BC_PROG_STACK(&G.prog.results, 1))
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006586 s = bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006587 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006588 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006589 break;
6590 }
6591
6592 case BC_INST_POP_EXEC:
6593 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006594 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006595 break;
6596 }
6597
6598 case BC_INST_PRINT:
6599 case BC_INST_PRINT_POP:
6600 case BC_INST_PRINT_STR:
6601 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006602 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006603 break;
6604 }
6605
6606 case BC_INST_STR:
6607 {
6608 r.t = BC_RESULT_STR;
6609 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006610 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006611 break;
6612 }
6613
6614 case BC_INST_POWER:
6615 case BC_INST_MULTIPLY:
6616 case BC_INST_DIVIDE:
6617 case BC_INST_MODULUS:
6618 case BC_INST_PLUS:
6619 case BC_INST_MINUS:
6620 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006621 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006622 break;
6623 }
6624
6625 case BC_INST_BOOL_NOT:
6626 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006627 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006628 if (s) return s;
6629
6630 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006631 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6632 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006633
6634 break;
6635 }
6636
6637 case BC_INST_NEG:
6638 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006639 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006640 break;
6641 }
6642
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006643#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006644 case BC_INST_ASSIGN_POWER:
6645 case BC_INST_ASSIGN_MULTIPLY:
6646 case BC_INST_ASSIGN_DIVIDE:
6647 case BC_INST_ASSIGN_MODULUS:
6648 case BC_INST_ASSIGN_PLUS:
6649 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006650#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006651 case BC_INST_ASSIGN:
6652 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006653 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006654 break;
6655 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006656#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006657 case BC_INST_MODEXP:
6658 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006659 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006660 break;
6661 }
6662
6663 case BC_INST_DIVMOD:
6664 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006665 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006666 break;
6667 }
6668
6669 case BC_INST_EXECUTE:
6670 case BC_INST_EXEC_COND:
6671 {
6672 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006673 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006674 break;
6675 }
6676
6677 case BC_INST_PRINT_STACK:
6678 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006679 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6680 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006681 break;
6682 }
6683
6684 case BC_INST_CLEAR_STACK:
6685 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006686 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006687 break;
6688 }
6689
6690 case BC_INST_STACK_LEN:
6691 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006692 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006693 break;
6694 }
6695
6696 case BC_INST_DUPLICATE:
6697 {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006698 if (!BC_PROG_STACK(&G.prog.results, 1))
6699 return bc_error("stack has too few elements");
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006700 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006701 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006702 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006703 break;
6704 }
6705
6706 case BC_INST_SWAP:
6707 {
6708 BcResult *ptr2;
6709
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006710 if (!BC_PROG_STACK(&G.prog.results, 2))
6711 return bc_error("stack has too few elements");
Gavin Howard01055ba2018-11-03 11:00:21 -06006712
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006713 ptr = bc_vec_item_rev(&G.prog.results, 0);
6714 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006715 memcpy(&r, ptr, sizeof(BcResult));
6716 memcpy(ptr, ptr2, sizeof(BcResult));
6717 memcpy(ptr2, &r, sizeof(BcResult));
6718
6719 break;
6720 }
6721
6722 case BC_INST_ASCIIFY:
6723 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006724 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006725 break;
6726 }
6727
6728 case BC_INST_PRINT_STREAM:
6729 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006730 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006731 break;
6732 }
6733
6734 case BC_INST_LOAD:
6735 case BC_INST_PUSH_VAR:
6736 {
6737 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006738 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006739 break;
6740 }
6741
6742 case BC_INST_PUSH_TO_VAR:
6743 {
6744 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006745 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006746 free(name);
6747 break;
6748 }
6749
6750 case BC_INST_QUIT:
6751 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006752 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006753 quit();
6754 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006755 break;
6756 }
6757
6758 case BC_INST_NQUIT:
6759 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006760 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006761 break;
6762 }
6763#endif // ENABLE_DC
6764 }
6765
Denys Vlasenkod38af482018-12-04 19:11:02 +01006766 if (s || G_interrupt) {
6767 bc_program_reset();
6768 break;
6769 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006770
6771 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006772 ip = bc_vec_top(&G.prog.stack);
6773 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006774 code = func->code.v;
6775 }
6776
6777 return s;
6778}
6779
Denys Vlasenko00d77792018-11-30 23:13:42 +01006780static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006781{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006782 printf("%s "BB_VER"\n"
6783 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006784 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006785 "This is free software with ABSOLUTELY NO WARRANTY\n"
6786 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006787}
6788
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006789#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006790static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006791{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006792 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6793
Gavin Howard01055ba2018-11-03 11:00:21 -06006794 BcVec v;
6795 char *env_args = getenv(bc_args_env_name), *buf;
6796
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006797 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006798
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006799 G.env_args = xstrdup(env_args);
6800 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006801
6802 bc_vec_init(&v, sizeof(char *), NULL);
6803 bc_vec_push(&v, &bc_args_env_name);
6804
6805 while (*buf != 0) {
6806 if (!isspace(*buf)) {
6807 bc_vec_push(&v, &buf);
6808 while (*buf != 0 && !isspace(*buf)) ++buf;
6809 if (*buf != 0) (*(buf++)) = '\0';
6810 }
6811 else
6812 ++buf;
6813 }
6814
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006815 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816
6817 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006818}
6819#endif // ENABLE_BC
6820
6821static size_t bc_vm_envLen(const char *var)
6822{
6823 char *lenv = getenv(var);
6824 size_t i, len = BC_NUM_PRINT_WIDTH;
6825 int num;
6826
6827 if (!lenv) return len;
6828
6829 len = strlen(lenv);
6830
6831 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6832 if (num) {
6833 len = (size_t) atoi(lenv) - 1;
6834 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6835 }
6836 else
6837 len = BC_NUM_PRINT_WIDTH;
6838
6839 return len;
6840}
6841
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006842static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006843{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006844 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006845
Gavin Howard01055ba2018-11-03 11:00:21 -06006846 if (s) return s;
6847
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006848 while (G.prs.l.t.t != BC_LEX_EOF) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006849 s = G.prs.parse(&G.prs);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006850 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006851 }
6852
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006853 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006854 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006855 fflush_and_check();
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006856 if (s)
Denys Vlasenkod38af482018-12-04 19:11:02 +01006857 bc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06006858 }
6859
6860 return s;
6861}
6862
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006863static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006864{
6865 BcStatus s;
6866 char *data;
6867 BcFunc *main_func;
6868 BcInstPtr *ip;
6869
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006870 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006871 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01006872 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006873
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006874 bc_lex_file(&G.prs.l, file);
6875 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006876 if (s) goto err;
6877
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006878 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6879 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006880
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006881 if (main_func->code.len < ip->idx)
6882 s = bc_error("file '%s' is not executable", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006883
6884err:
6885 free(data);
6886 return s;
6887}
6888
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006889static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006890{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006891 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006892 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006893 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006894 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006895
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006896 G.prog.file = bc_program_stdin_name;
6897 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006898
6899 bc_vec_init(&buffer, sizeof(char), NULL);
6900 bc_vec_init(&buf, sizeof(char), NULL);
6901 bc_vec_pushByte(&buffer, '\0');
6902
6903 // This loop is complex because the vm tries not to send any lines that end
6904 // with a backslash to the parser. The reason for that is because the parser
6905 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6906 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006907 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006908
6909 char *string = buf.v;
6910
6911 len = buf.len - 1;
6912
6913 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006914 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006915 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006916 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006917 str += 1;
6918 }
6919 else if (len > 1 || comment) {
6920
6921 for (i = 0; i < len; ++i) {
6922
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006923 bool notend = len > i + 1;
6924 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06006925
6926 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006927 if (G.sbgn == G.send)
6928 str ^= c == G.sbgn;
6929 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06006930 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006931 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06006932 str += 1;
6933 }
6934
6935 if (c == '/' && notend && !comment && string[i + 1] == '*') {
6936 comment = true;
6937 break;
6938 }
6939 else if (c == '*' && notend && comment && string[i + 1] == '/')
6940 comment = false;
6941 }
6942
6943 if (str || comment || string[len - 2] == '\\') {
6944 bc_vec_concat(&buffer, buf.v);
6945 continue;
6946 }
6947 }
6948
6949 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006950 s = bc_vm_process(buffer.v);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006951 if (s) {
6952 fflush_and_check();
6953 fputs("ready for more input\n", stderr);
6954 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006955
6956 bc_vec_npop(&buffer, buffer.len);
6957 }
6958
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006959 if (str) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006960 s = bc_error("string end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006961 }
6962 else if (comment) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006963 s = bc_error("comment end could not be found");
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006964 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006965
Gavin Howard01055ba2018-11-03 11:00:21 -06006966 bc_vec_free(&buf);
6967 bc_vec_free(&buffer);
6968 return s;
6969}
6970
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006971static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006972{
6973 BcStatus s = BC_STATUS_SUCCESS;
6974 size_t i;
6975
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006976#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01006977 if (option_mask32 & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006978
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006979 bc_lex_file(&G.prs.l, bc_lib_name);
6980 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06006981
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006982 while (!s && G.prs.l.t.t != BC_LEX_EOF)
6983 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006984
6985 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006986 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06006987 if (s) return s;
6988 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006989#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006990
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006991 for (i = 0; !s && i < G.files.len; ++i)
6992 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006993 if (s) {
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006994 fflush_and_check();
6995 fputs("ready for more input\n", stderr);
6996 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006997
Denys Vlasenko9b70f192018-12-04 20:51:40 +01006998 if (IS_BC || !G.files.len)
6999 s = bc_vm_stdin();
7000 if (!s && !BC_PARSE_CAN_EXEC(&G.prs))
7001 s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007002
Denys Vlasenko00d77792018-11-30 23:13:42 +01007003 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007004}
7005
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007006#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007007static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007008{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007009 bc_num_free(&G.prog.ib);
7010 bc_num_free(&G.prog.ob);
7011 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007012# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007013 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007014# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007015 bc_vec_free(&G.prog.fns);
7016 bc_vec_free(&G.prog.fn_map);
7017 bc_vec_free(&G.prog.vars);
7018 bc_vec_free(&G.prog.var_map);
7019 bc_vec_free(&G.prog.arrs);
7020 bc_vec_free(&G.prog.arr_map);
7021 bc_vec_free(&G.prog.strs);
7022 bc_vec_free(&G.prog.consts);
7023 bc_vec_free(&G.prog.results);
7024 bc_vec_free(&G.prog.stack);
7025 bc_num_free(&G.prog.last);
7026 bc_num_free(&G.prog.zero);
7027 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007028}
7029
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007030static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007031{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007032 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007033 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007034 bc_parse_free(&G.prs);
7035 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007036}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007037#endif
7038
7039static void bc_program_init(size_t line_len)
7040{
7041 size_t idx;
7042 BcInstPtr ip;
7043
7044 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7045 memset(&ip, 0, sizeof(BcInstPtr));
7046
7047 /* G.prog.nchars = G.prog.scale = 0; - already is */
7048 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007049
7050 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7051 bc_num_ten(&G.prog.ib);
7052 G.prog.ib_t = 10;
7053
7054 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7055 bc_num_ten(&G.prog.ob);
7056 G.prog.ob_t = 10;
7057
7058 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7059 bc_num_ten(&G.prog.hexb);
7060 G.prog.hexb.num[0] = 6;
7061
7062#if ENABLE_DC
7063 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7064 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7065#endif
7066
7067 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7068 bc_num_zero(&G.prog.last);
7069
7070 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7071 bc_num_zero(&G.prog.zero);
7072
7073 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7074 bc_num_one(&G.prog.one);
7075
7076 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7077 bc_map_init(&G.prog.fn_map);
7078
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007079 bc_program_addFunc(xstrdup("(main)"), &idx);
7080 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007081
7082 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7083 bc_map_init(&G.prog.var_map);
7084
7085 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7086 bc_map_init(&G.prog.arr_map);
7087
7088 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7089 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7090 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7091 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7092 bc_vec_push(&G.prog.stack, &ip);
7093}
Gavin Howard01055ba2018-11-03 11:00:21 -06007094
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007095static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007096{
Gavin Howard01055ba2018-11-03 11:00:21 -06007097 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007098
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007099 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007100
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007101 if (IS_BC) {
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007102 bc_vm_envArgs();
7103 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007104
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007105 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007106 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007107 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007108 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007109 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007110 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007111}
7112
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007113static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007114 const char *env_len)
7115{
7116 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007117
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007118 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007119 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007120
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007121 G.ttyin = isatty(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06007122
Denys Vlasenkod38af482018-12-04 19:11:02 +01007123 if (G.ttyin) {
7124#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenko17c54722018-12-04 21:21:32 +01007125 // With SA_RESTART, most system calls will restart
7126 // (IOW: they won't fail with EINTR).
7127 // In particular, this means ^C won't cause
7128 // stdout to get into "error state" if SIGINT hits
7129 // within write() syscall.
7130 // The downside is that ^C while line input is taken
7131 // will only be handled after [Enter] since read()
7132 // from stdin is not interrupted by ^C either,
7133 // it restarts, thus fgetc() does not return on ^C.
7134 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7135
7136 // Without SA_RESTART, this exhibits a bug:
7137 // "while (1) print 1" and try ^C-ing it.
7138 // Intermittently, instead of returning to input line,
7139 // you'll get "output error: Interrupted system call"
7140 // and exit.
7141 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007142#endif
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007143 if (!(option_mask32 & BC_FLAG_Q))
Denys Vlasenkod38af482018-12-04 19:11:02 +01007144 bc_vm_info();
7145 }
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007146 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007147
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007148#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007149 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007150#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007151 return st;
7152}
7153
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007154#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007155int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7156int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007157{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007158 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007159 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007160
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007161 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007162}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007163#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007164
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007165#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007166int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7167int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007168{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007169 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007170 G.sbgn = '[';
7171 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007172
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007173 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007174}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007175#endif