blob: b57f741d619e42024f0aa148be294ce0925d34d8 [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 {
Gavin Howard01055ba2018-11-03 11:00:21 -0600171 BC_STATUS_SUCCESS,
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100172 BC_STATUS_FAILURE,
Gavin Howard01055ba2018-11-03 11:00:21 -0600173
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100174// BC_STATUS_ALLOC_ERR,
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100175// BC_STATUS_INPUT_EOF,
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100176// BC_STATUS_BIN_FILE,
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100177// BC_STATUS_PATH_IS_DIR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600178
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100179// BC_STATUS_LEX_BAD_CHAR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
182 BC_STATUS_LEX_EOF,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100183#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600184 BC_STATUS_LEX_EXTENDED_REG,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100185#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600186 BC_STATUS_PARSE_BAD_TOKEN,
187 BC_STATUS_PARSE_BAD_EXP,
188 BC_STATUS_PARSE_EMPTY_EXP,
189 BC_STATUS_PARSE_BAD_PRINT,
190 BC_STATUS_PARSE_BAD_FUNC,
191 BC_STATUS_PARSE_BAD_ASSIGN,
192 BC_STATUS_PARSE_NO_AUTO,
193 BC_STATUS_PARSE_DUPLICATE_LOCAL,
194 BC_STATUS_PARSE_NO_BLOCK_END,
195
196 BC_STATUS_MATH_NEGATIVE,
197 BC_STATUS_MATH_NON_INTEGER,
198 BC_STATUS_MATH_OVERFLOW,
199 BC_STATUS_MATH_DIVIDE_BY_ZERO,
200 BC_STATUS_MATH_BAD_STRING,
201
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100202// BC_STATUS_EXEC_FILE_ERR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600203 BC_STATUS_EXEC_MISMATCHED_PARAMS,
204 BC_STATUS_EXEC_UNDEFINED_FUNC,
205 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
206 BC_STATUS_EXEC_NUM_LEN,
207 BC_STATUS_EXEC_NAME_LEN,
208 BC_STATUS_EXEC_STRING_LEN,
209 BC_STATUS_EXEC_ARRAY_LEN,
210 BC_STATUS_EXEC_BAD_IBASE,
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100211// BC_STATUS_EXEC_BAD_SCALE,
Gavin Howard01055ba2018-11-03 11:00:21 -0600212 BC_STATUS_EXEC_BAD_READ_EXPR,
213 BC_STATUS_EXEC_REC_READ,
214 BC_STATUS_EXEC_BAD_TYPE,
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100215// BC_STATUS_EXEC_BAD_OBASE,
Gavin Howard01055ba2018-11-03 11:00:21 -0600216 BC_STATUS_EXEC_SIGNAL,
217 BC_STATUS_EXEC_STACK,
218
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100219// BC_STATUS_VEC_OUT_OF_BOUNDS,
Denys Vlasenkoa02f8442018-12-03 20:35:16 +0100220// BC_STATUS_VEC_ITEM_EXISTS,
221 BC_STATUS_BEFORE_POSIX = BC_STATUS_EXEC_STACK,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100222#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600223 BC_STATUS_POSIX_NAME_LEN,
224 BC_STATUS_POSIX_COMMENT,
225 BC_STATUS_POSIX_BAD_KW,
226 BC_STATUS_POSIX_DOT,
227 BC_STATUS_POSIX_RET,
228 BC_STATUS_POSIX_BOOL,
229 BC_STATUS_POSIX_REL_POS,
230 BC_STATUS_POSIX_MULTIREL,
231 BC_STATUS_POSIX_FOR1,
232 BC_STATUS_POSIX_FOR2,
233 BC_STATUS_POSIX_FOR3,
234 BC_STATUS_POSIX_BRACE,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100235#endif
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100236// BC_STATUS_QUIT,
237// BC_STATUS_LIMITS,
Gavin Howard01055ba2018-11-03 11:00:21 -0600238
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100239// BC_STATUS_INVALID_OPTION,
Gavin Howard01055ba2018-11-03 11:00:21 -0600240} BcStatus;
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100241// Keep enum above and messages below in sync!
242static const char *const bc_err_msgs[] = {
243 NULL,
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100244 "",
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100245// "memory allocation error",
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100246// "I/O error",
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100247// "file is not text:",
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100248// "path is a directory:",
249
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100250// "bad character",
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100251 "string end could not be found",
252 "comment end could not be found",
253 "end of file",
254#if ENABLE_DC
255 "extended register",
256#endif
257 "bad token",
258 "bad expression",
259 "empty expression",
260 "bad print statement",
261 "bad function definition",
262 "bad assignment: left side must be scale, ibase, "
263 "obase, last, var, or array element",
264 "no auto variable found",
265 "function parameter or auto var has the same name as another",
266 "block end could not be found",
267
268 "negative number",
269 "non integer number",
270 "overflow",
271 "divide by zero",
272 "bad number string",
273
274// "could not open file:",
275 "mismatched parameters", // wrong number of them, to be exact
276 "undefined function",
277 "file is not executable:",
278 "number too long: must be [1, BC_NUM_MAX]",
279 "name too long: must be [1, BC_NAME_MAX]",
280 "string too long: must be [1, BC_STRING_MAX]",
281 "array too long; must be [1, BC_DIM_MAX]",
282 "bad ibase; must be [2, 16]",
283// "bad scale; must be [0, BC_SCALE_MAX]",
284 "bad read() expression",
285 "read() call inside of a read() call",
286 "variable is wrong type",
287// "bad obase; must be [2, BC_BASE_MAX]",
288 "signal caught and not handled",
289 "stack has too few elements",
290
291// "index is out of bounds",
Denys Vlasenkoa02f8442018-12-03 20:35:16 +0100292// "item already exists",
Denys Vlasenko01cabaf2018-12-03 00:51:25 +0100293#if ENABLE_BC
294 "POSIX only allows one character names; the following is bad:",
295 "POSIX does not allow '#' script comments",
296 "POSIX does not allow the following keyword:",
297 "POSIX does not allow a period ('.') as a shortcut for the last result",
298 "POSIX requires parentheses around return expressions",
299 "POSIX does not allow boolean operators; the following is bad:",
300 "POSIX does not allow comparison operators outside if or loops",
301 "POSIX requires exactly one comparison operator per condition",
302 "POSIX does not allow an empty init expression in a for loop",
303 "POSIX does not allow an empty condition expression in a for loop",
304 "POSIX does not allow an empty update expression in a for loop",
305 "POSIX requires the left brace be on the same line as the function header",
306#endif
307};
Gavin Howard01055ba2018-11-03 11:00:21 -0600308
Gavin Howard01055ba2018-11-03 11:00:21 -0600309#define BC_VEC_INVALID_IDX ((size_t) -1)
310#define BC_VEC_START_CAP (1 << 5)
311
312typedef void (*BcVecFree)(void *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600313
314typedef struct BcVec {
315 char *v;
316 size_t len;
317 size_t cap;
318 size_t size;
319 BcVecFree dtor;
320} BcVec;
321
322#define bc_vec_pop(v) (bc_vec_npop((v), 1))
323#define bc_vec_top(v) (bc_vec_item_rev((v), 0))
324
325#define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
326
Gavin Howard01055ba2018-11-03 11:00:21 -0600327typedef signed char BcDig;
328
329typedef struct BcNum {
330 BcDig *restrict num;
331 size_t rdx;
332 size_t len;
333 size_t cap;
334 bool neg;
335} BcNum;
336
337#define BC_NUM_MIN_BASE ((unsigned long) 2)
338#define BC_NUM_MAX_IBASE ((unsigned long) 16)
339#define BC_NUM_DEF_SIZE (16)
340#define BC_NUM_PRINT_WIDTH (69)
341
342#define BC_NUM_KARATSUBA_LEN (32)
343
344#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
345#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
346#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
347#define BC_NUM_AREQ(a, b) \
348 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
349#define BC_NUM_MREQ(a, b, scale) \
350 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
351
352typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
353typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
354
355static void bc_num_init(BcNum *n, size_t req);
356static void bc_num_expand(BcNum *n, size_t req);
357static void bc_num_copy(BcNum *d, BcNum *s);
358static void bc_num_free(void *num);
359
360static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +0100361static void bc_num_ulong2num(BcNum *n, unsigned long val);
Gavin Howard01055ba2018-11-03 11:00:21 -0600362
363static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
364static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
369static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
370static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
371 size_t scale);
372
373typedef enum BcInst {
374
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100375#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600376 BC_INST_INC_PRE,
377 BC_INST_DEC_PRE,
378 BC_INST_INC_POST,
379 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100380#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600381
382 BC_INST_NEG,
383
384 BC_INST_POWER,
385 BC_INST_MULTIPLY,
386 BC_INST_DIVIDE,
387 BC_INST_MODULUS,
388 BC_INST_PLUS,
389 BC_INST_MINUS,
390
391 BC_INST_REL_EQ,
392 BC_INST_REL_LE,
393 BC_INST_REL_GE,
394 BC_INST_REL_NE,
395 BC_INST_REL_LT,
396 BC_INST_REL_GT,
397
398 BC_INST_BOOL_NOT,
399 BC_INST_BOOL_OR,
400 BC_INST_BOOL_AND,
401
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100402#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600403 BC_INST_ASSIGN_POWER,
404 BC_INST_ASSIGN_MULTIPLY,
405 BC_INST_ASSIGN_DIVIDE,
406 BC_INST_ASSIGN_MODULUS,
407 BC_INST_ASSIGN_PLUS,
408 BC_INST_ASSIGN_MINUS,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100409#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600410 BC_INST_ASSIGN,
411
412 BC_INST_NUM,
413 BC_INST_VAR,
414 BC_INST_ARRAY_ELEM,
415 BC_INST_ARRAY,
416
417 BC_INST_SCALE_FUNC,
418 BC_INST_IBASE,
419 BC_INST_SCALE,
420 BC_INST_LAST,
421 BC_INST_LENGTH,
422 BC_INST_READ,
423 BC_INST_OBASE,
424 BC_INST_SQRT,
425
426 BC_INST_PRINT,
427 BC_INST_PRINT_POP,
428 BC_INST_STR,
429 BC_INST_PRINT_STR,
430
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100431#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600432 BC_INST_JUMP,
433 BC_INST_JUMP_ZERO,
434
435 BC_INST_CALL,
436
437 BC_INST_RET,
438 BC_INST_RET0,
439
440 BC_INST_HALT,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100441#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600442
443 BC_INST_POP,
444 BC_INST_POP_EXEC,
445
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100446#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600447 BC_INST_MODEXP,
448 BC_INST_DIVMOD,
449
450 BC_INST_EXECUTE,
451 BC_INST_EXEC_COND,
452
453 BC_INST_ASCIIFY,
454 BC_INST_PRINT_STREAM,
455
456 BC_INST_PRINT_STACK,
457 BC_INST_CLEAR_STACK,
458 BC_INST_STACK_LEN,
459 BC_INST_DUPLICATE,
460 BC_INST_SWAP,
461
462 BC_INST_LOAD,
463 BC_INST_PUSH_VAR,
464 BC_INST_PUSH_TO_VAR,
465
466 BC_INST_QUIT,
467 BC_INST_NQUIT,
468
469 BC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100470#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600471
472} BcInst;
473
474typedef struct BcId {
475 char *name;
476 size_t idx;
477} BcId;
478
479typedef struct BcFunc {
480 BcVec code;
481 BcVec labels;
482 size_t nparams;
483 BcVec autos;
484} BcFunc;
485
486typedef enum BcResultType {
487
488 BC_RESULT_TEMP,
489
490 BC_RESULT_VAR,
491 BC_RESULT_ARRAY_ELEM,
492 BC_RESULT_ARRAY,
493
494 BC_RESULT_STR,
495
496 BC_RESULT_IBASE,
497 BC_RESULT_SCALE,
498 BC_RESULT_LAST,
499
500 // These are between to calculate ibase, obase, and last from instructions.
501 BC_RESULT_CONSTANT,
502 BC_RESULT_ONE,
503
504 BC_RESULT_OBASE,
505
506} BcResultType;
507
508typedef union BcResultData {
509 BcNum n;
510 BcVec v;
511 BcId id;
512} BcResultData;
513
514typedef struct BcResult {
515 BcResultType t;
516 BcResultData d;
517} BcResult;
518
519typedef struct BcInstPtr {
520 size_t func;
521 size_t idx;
522 size_t len;
523} BcInstPtr;
524
525static void bc_array_expand(BcVec *a, size_t len);
526static int bc_id_cmp(const void *e1, const void *e2);
527
528// BC_LEX_NEG is not used in lexing; it is only for parsing.
529typedef enum BcLexType {
530
531 BC_LEX_EOF,
532 BC_LEX_INVALID,
533
534 BC_LEX_OP_INC,
535 BC_LEX_OP_DEC,
536
537 BC_LEX_NEG,
538
539 BC_LEX_OP_POWER,
540 BC_LEX_OP_MULTIPLY,
541 BC_LEX_OP_DIVIDE,
542 BC_LEX_OP_MODULUS,
543 BC_LEX_OP_PLUS,
544 BC_LEX_OP_MINUS,
545
546 BC_LEX_OP_REL_EQ,
547 BC_LEX_OP_REL_LE,
548 BC_LEX_OP_REL_GE,
549 BC_LEX_OP_REL_NE,
550 BC_LEX_OP_REL_LT,
551 BC_LEX_OP_REL_GT,
552
553 BC_LEX_OP_BOOL_NOT,
554 BC_LEX_OP_BOOL_OR,
555 BC_LEX_OP_BOOL_AND,
556
557 BC_LEX_OP_ASSIGN_POWER,
558 BC_LEX_OP_ASSIGN_MULTIPLY,
559 BC_LEX_OP_ASSIGN_DIVIDE,
560 BC_LEX_OP_ASSIGN_MODULUS,
561 BC_LEX_OP_ASSIGN_PLUS,
562 BC_LEX_OP_ASSIGN_MINUS,
563 BC_LEX_OP_ASSIGN,
564
565 BC_LEX_NLINE,
566 BC_LEX_WHITESPACE,
567
568 BC_LEX_LPAREN,
569 BC_LEX_RPAREN,
570
571 BC_LEX_LBRACKET,
572 BC_LEX_COMMA,
573 BC_LEX_RBRACKET,
574
575 BC_LEX_LBRACE,
576 BC_LEX_SCOLON,
577 BC_LEX_RBRACE,
578
579 BC_LEX_STR,
580 BC_LEX_NAME,
581 BC_LEX_NUMBER,
582
583 BC_LEX_KEY_AUTO,
584 BC_LEX_KEY_BREAK,
585 BC_LEX_KEY_CONTINUE,
586 BC_LEX_KEY_DEFINE,
587 BC_LEX_KEY_ELSE,
588 BC_LEX_KEY_FOR,
589 BC_LEX_KEY_HALT,
590 BC_LEX_KEY_IBASE,
591 BC_LEX_KEY_IF,
592 BC_LEX_KEY_LAST,
593 BC_LEX_KEY_LENGTH,
594 BC_LEX_KEY_LIMITS,
595 BC_LEX_KEY_OBASE,
596 BC_LEX_KEY_PRINT,
597 BC_LEX_KEY_QUIT,
598 BC_LEX_KEY_READ,
599 BC_LEX_KEY_RETURN,
600 BC_LEX_KEY_SCALE,
601 BC_LEX_KEY_SQRT,
602 BC_LEX_KEY_WHILE,
603
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100604#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600605 BC_LEX_EQ_NO_REG,
606 BC_LEX_OP_MODEXP,
607 BC_LEX_OP_DIVMOD,
608
609 BC_LEX_COLON,
610 BC_LEX_ELSE,
611 BC_LEX_EXECUTE,
612 BC_LEX_PRINT_STACK,
613 BC_LEX_CLEAR_STACK,
614 BC_LEX_STACK_LEVEL,
615 BC_LEX_DUPLICATE,
616 BC_LEX_SWAP,
617 BC_LEX_POP,
618
619 BC_LEX_ASCIIFY,
620 BC_LEX_PRINT_STREAM,
621
622 BC_LEX_STORE_IBASE,
623 BC_LEX_STORE_SCALE,
624 BC_LEX_LOAD,
625 BC_LEX_LOAD_POP,
626 BC_LEX_STORE_PUSH,
627 BC_LEX_STORE_OBASE,
628 BC_LEX_PRINT_POP,
629 BC_LEX_NQUIT,
630 BC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100631#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600632
633} BcLexType;
634
635struct BcLex;
636typedef BcStatus (*BcLexNext)(struct BcLex *);
637
638typedef struct BcLex {
639
640 const char *buf;
641 size_t i;
642 size_t line;
643 const char *f;
644 size_t len;
645 bool newline;
646
647 struct {
648 BcLexType t;
649 BcLexType last;
650 BcVec v;
651 } t;
652
653 BcLexNext next;
654
655} BcLex;
656
657#define BC_PARSE_STREND ((char) UCHAR_MAX)
658
659#define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
660#define bc_parse_updateFunc(p, f) \
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100661 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
Gavin Howard01055ba2018-11-03 11:00:21 -0600662
663#define BC_PARSE_REL (1 << 0)
664#define BC_PARSE_PRINT (1 << 1)
665#define BC_PARSE_NOCALL (1 << 2)
666#define BC_PARSE_NOREAD (1 << 3)
667#define BC_PARSE_ARRAY (1 << 4)
668
669#define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
670#define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
671
672#define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
673#define BC_PARSE_FUNC_INNER(parse) \
674 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
675
676#define BC_PARSE_FLAG_FUNC (1 << 1)
677#define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
678
679#define BC_PARSE_FLAG_BODY (1 << 2)
680#define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
681
682#define BC_PARSE_FLAG_LOOP (1 << 3)
683#define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
684
685#define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
686#define BC_PARSE_LOOP_INNER(parse) \
687 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
688
689#define BC_PARSE_FLAG_IF (1 << 5)
690#define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
691
692#define BC_PARSE_FLAG_ELSE (1 << 6)
693#define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
694
695#define BC_PARSE_FLAG_IF_END (1 << 7)
696#define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
697
698#define BC_PARSE_CAN_EXEC(parse) \
699 (!(BC_PARSE_TOP_FLAG(parse) & \
700 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
701 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
702 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
703
704typedef struct BcOp {
705 char prec;
706 bool left;
707} BcOp;
708
709typedef struct BcParseNext {
710 uint32_t len;
711 BcLexType tokens[4];
712} BcParseNext;
713
714#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
715#define BC_PARSE_NEXT(a, ...) \
716 { \
717 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
718 }
719
720struct BcParse;
721
722struct BcProgram;
723
Gavin Howard01055ba2018-11-03 11:00:21 -0600724typedef BcStatus (*BcParseParse)(struct BcParse *);
Gavin Howard01055ba2018-11-03 11:00:21 -0600725
726typedef struct BcParse {
727
728 BcParseParse parse;
729
730 BcLex l;
731
732 BcVec flags;
733
734 BcVec exits;
735 BcVec conds;
736
737 BcVec ops;
738
Gavin Howard01055ba2018-11-03 11:00:21 -0600739 BcFunc *func;
740 size_t fidx;
741
742 size_t nbraces;
743 bool auto_part;
744
745} BcParse;
746
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100747#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600748
Gavin Howard01055ba2018-11-03 11:00:21 -0600749typedef struct BcLexKeyword {
750 const char name[9];
751 const char len;
752 const bool posix;
753} BcLexKeyword;
754
755#define BC_LEX_KW_ENTRY(a, b, c) \
756 { \
757 .name = a, .len = (b), .posix = (c) \
758 }
759
760static BcStatus bc_lex_token(BcLex *l);
761
762#define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
763#define BC_PARSE_LEAF(p, rparen) \
764 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
765 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
766
767// We can calculate the conversion between tokens and exprs by subtracting the
768// position of the first operator in the lex enum and adding the position of the
769// first in the expr enum. Note: This only works for binary operators.
770#define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
771
Gavin Howard01055ba2018-11-03 11:00:21 -0600772static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
773
Denys Vlasenko00d77792018-11-30 23:13:42 +0100774#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600775
Denys Vlasenko00d77792018-11-30 23:13:42 +0100776#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600777
778#define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
779
Gavin Howard01055ba2018-11-03 11:00:21 -0600780static BcStatus dc_lex_token(BcLex *l);
781
Gavin Howard01055ba2018-11-03 11:00:21 -0600782static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
783
784#endif // ENABLE_DC
785
786typedef struct BcProgram {
787
788 size_t len;
789 size_t scale;
790
791 BcNum ib;
792 size_t ib_t;
793 BcNum ob;
794 size_t ob_t;
795
796 BcNum hexb;
797
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100798#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600799 BcNum strmb;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100800#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600801
802 BcVec results;
803 BcVec stack;
804
805 BcVec fns;
806 BcVec fn_map;
807
808 BcVec vars;
809 BcVec var_map;
810
811 BcVec arrs;
812 BcVec arr_map;
813
814 BcVec strs;
815 BcVec consts;
816
817 const char *file;
818
819 BcNum last;
820 BcNum zero;
821 BcNum one;
822
823 size_t nchars;
824
Gavin Howard01055ba2018-11-03 11:00:21 -0600825} BcProgram;
826
827#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
828
829#define BC_PROG_MAIN (0)
830#define BC_PROG_READ (1)
831
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100832#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600833#define BC_PROG_REQ_FUNCS (2)
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100834#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600835
836#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
837#define BC_PROG_NUM(r, n) \
838 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
839
840typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
841
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +0100842static void bc_program_addFunc(char *name, size_t *idx);
843static BcStatus bc_program_reset(BcStatus s);
Gavin Howard01055ba2018-11-03 11:00:21 -0600844
845#define BC_FLAG_X (1 << 0)
846#define BC_FLAG_W (1 << 1)
847#define BC_FLAG_V (1 << 2)
848#define BC_FLAG_S (1 << 3)
849#define BC_FLAG_Q (1 << 4)
850#define BC_FLAG_L (1 << 5)
851#define BC_FLAG_I (1 << 6)
852
853#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
854#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
855
Denys Vlasenkod9d66552018-12-02 21:02:54 +0100856#define BC_MAX_OBASE ((unsigned) 999)
857#define BC_MAX_DIM ((unsigned) INT_MAX)
858#define BC_MAX_SCALE ((unsigned) UINT_MAX)
859#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
860#define BC_MAX_NAME BC_MAX_STRING
861#define BC_MAX_NUM BC_MAX_STRING
862#define BC_MAX_EXP ((unsigned long) LONG_MAX)
863#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Gavin Howard01055ba2018-11-03 11:00:21 -0600864
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100865struct globals {
Gavin Howard01055ba2018-11-03 11:00:21 -0600866 char sbgn;
867 char send;
Gavin Howard01055ba2018-11-03 11:00:21 -0600868
869 BcParse prs;
870 BcProgram prog;
871
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100872 unsigned flags;
Gavin Howard01055ba2018-11-03 11:00:21 -0600873 BcVec files;
874
875 char *env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -0600876
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100877 smallint tty;
878 smallint ttyin;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100879 smallint eof;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +0100880} FIX_ALIASING;
881#define G (*ptr_to_globals)
882#define INIT_G() do { \
883 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
884} while (0)
885#define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
886#define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
887#define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
Denys Vlasenkoab3c5682018-12-02 16:32:36 +0100888#define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
Gavin Howard01055ba2018-11-03 11:00:21 -0600889
Gavin Howard01055ba2018-11-03 11:00:21 -0600890
Denys Vlasenko00d77792018-11-30 23:13:42 +0100891#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
892
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100893#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600894static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
895 const char *msg);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100896#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600897
Denys Vlasenko00d77792018-11-30 23:13:42 +0100898static void bc_vm_info(void);
Gavin Howard01055ba2018-11-03 11:00:21 -0600899
Denys Vlasenkob8860a82018-12-03 00:26:12 +0100900static const char bc_err_fmt[] = "\nerror: %s\n";
901static const char bc_warn_fmt[] = "\nwarning: %s\n";
Gavin Howard01055ba2018-11-03 11:00:21 -0600902static const char bc_err_line[] = ":%zu\n\n";
903
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100904#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600905static const BcLexKeyword bc_lex_kws[20] = {
906 BC_LEX_KW_ENTRY("auto", 4, true),
907 BC_LEX_KW_ENTRY("break", 5, true),
908 BC_LEX_KW_ENTRY("continue", 8, false),
909 BC_LEX_KW_ENTRY("define", 6, true),
910 BC_LEX_KW_ENTRY("else", 4, false),
911 BC_LEX_KW_ENTRY("for", 3, true),
912 BC_LEX_KW_ENTRY("halt", 4, false),
913 BC_LEX_KW_ENTRY("ibase", 5, true),
914 BC_LEX_KW_ENTRY("if", 2, true),
915 BC_LEX_KW_ENTRY("last", 4, false),
916 BC_LEX_KW_ENTRY("length", 6, true),
917 BC_LEX_KW_ENTRY("limits", 6, false),
918 BC_LEX_KW_ENTRY("obase", 5, true),
919 BC_LEX_KW_ENTRY("print", 5, false),
920 BC_LEX_KW_ENTRY("quit", 4, true),
921 BC_LEX_KW_ENTRY("read", 4, false),
922 BC_LEX_KW_ENTRY("return", 6, true),
923 BC_LEX_KW_ENTRY("scale", 5, true),
924 BC_LEX_KW_ENTRY("sqrt", 4, true),
925 BC_LEX_KW_ENTRY("while", 5, true),
926};
927
928// This is an array that corresponds to token types. An entry is
929// true if the token is valid in an expression, false otherwise.
930static const bool bc_parse_exprs[] = {
931 false, false, true, true, true, true, true, true, true, true, true, true,
932 true, true, true, true, true, true, true, true, true, true, true, true,
933 true, true, true, false, false, true, true, false, false, false, false,
934 false, false, false, true, true, false, false, false, false, false, false,
935 false, true, false, true, true, true, true, false, false, true, false, true,
936 true, false,
937};
938
939// This is an array of data for operators that correspond to token types.
940static const BcOp bc_parse_ops[] = {
941 { 0, false }, { 0, false },
942 { 1, false },
943 { 2, false },
944 { 3, true }, { 3, true }, { 3, true },
945 { 4, true }, { 4, true },
946 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
947 { 1, false },
948 { 7, true }, { 7, true },
949 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
950 { 5, false }, { 5, false },
951};
952
953// These identify what tokens can come after expressions in certain cases.
954static const BcParseNext bc_parse_next_expr =
955 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
956static const BcParseNext bc_parse_next_param =
957 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
958static const BcParseNext bc_parse_next_print =
959 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
960static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
961static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
962static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
963static const BcParseNext bc_parse_next_read =
964 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
965#endif // ENABLE_BC
966
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100967#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -0600968static const BcLexType dc_lex_regs[] = {
969 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
970 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
971 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
972 BC_LEX_STORE_PUSH,
973};
974
975static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
976
977static const BcLexType dc_lex_tokens[] = {
978 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
979 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
980 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
981 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
982 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
983 BC_LEX_INVALID, BC_LEX_INVALID,
984 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
985 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
986 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
987 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
988 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
989 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
990 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
991 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
992 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
993 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
994 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
995 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
996 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
997 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
998 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
999 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1000 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1001 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1002 BC_LEX_INVALID
1003};
1004
1005static const BcInst dc_parse_insts[] = {
1006 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1007 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1008 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1009 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1010 BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1014 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1015 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1016 BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1020 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1021 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1022 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1023 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1024 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1025 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1026 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1027 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1028 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1029};
1030#endif // ENABLE_DC
1031
Gavin Howard01055ba2018-11-03 11:00:21 -06001032static const BcNumBinaryOp bc_program_ops[] = {
1033 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1034};
1035
1036static const char bc_program_stdin_name[] = "<stdin>";
1037static const char bc_program_ready_msg[] = "ready for more input\n";
1038
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001039#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06001040static const char *bc_lib_name = "gen/lib.bc";
1041
1042static const char bc_lib[] = {
1043 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1044 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1045 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1046 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,
1047 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1048 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1049 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,
1050 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1051 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1052 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,
1053 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1054 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1055 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1056 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1057 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1058 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1059 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1060 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1061 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1062 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1063 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1064 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1065 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1066 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,
1067 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1068 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,
1069 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1070 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1071 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1072 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1073 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1074 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,
1075 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1076 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1077 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1078 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1079 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,
1080 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1081 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1082 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1083 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1084 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1085 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1086 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1087 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1088 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1089 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1090 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,
1091 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,
1092 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1093 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,
1094 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,
1095 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,
1096 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1097 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1098 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,
1099 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,
1100 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,
1101 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1102 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,
1103 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1104 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1105 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1106 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,
1107 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1108 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1109 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1110 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1111 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1112 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1113 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1114 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1115 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1116 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1117 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1118 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1119 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1120 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1121 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1122 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1123};
1124#endif // ENABLE_BC
1125
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001126static void fflush_and_check(void)
1127{
1128 fflush_all();
1129 if (ferror(stdout) || ferror(stderr))
1130 bb_perror_msg_and_die("output error");
1131}
1132
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001133static void quit(void) NORETURN;
1134static void quit(void)
1135{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01001136 if (ferror(stdin))
1137 bb_perror_msg_and_die("input error");
1138 fflush_and_check();
1139 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01001140}
1141
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001142static int bc_error(const char *fmt, ...)
1143{
1144 va_list p;
1145
1146 va_start(p, fmt);
1147 bb_verror_msg(fmt, p, NULL);
1148 va_end(p);
1149 if (!G.ttyin)
1150 exit(1);
1151 return BC_STATUS_FAILURE;
1152}
1153
Gavin Howard01055ba2018-11-03 11:00:21 -06001154static void bc_vec_grow(BcVec *v, size_t n)
1155{
1156 size_t cap = v->cap * 2;
1157 while (cap < v->len + n) cap *= 2;
1158 v->v = xrealloc(v->v, v->size * cap);
1159 v->cap = cap;
1160}
1161
1162static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1163{
1164 v->size = esize;
1165 v->cap = BC_VEC_START_CAP;
1166 v->len = 0;
1167 v->dtor = dtor;
1168 v->v = xmalloc(esize * BC_VEC_START_CAP);
1169}
1170
1171static void bc_vec_expand(BcVec *v, size_t req)
1172{
1173 if (v->cap < req) {
1174 v->v = xrealloc(v->v, v->size * req);
1175 v->cap = req;
1176 }
1177}
1178
1179static void bc_vec_npop(BcVec *v, size_t n)
1180{
1181 if (!v->dtor)
1182 v->len -= n;
1183 else {
1184 size_t len = v->len - n;
1185 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1186 }
1187}
1188
1189static void bc_vec_push(BcVec *v, const void *data)
1190{
1191 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1192 memmove(v->v + (v->size * v->len), data, v->size);
1193 v->len += 1;
1194}
1195
1196static void bc_vec_pushByte(BcVec *v, char data)
1197{
1198 bc_vec_push(v, &data);
1199}
1200
1201static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1202{
1203 if (idx == v->len)
1204 bc_vec_push(v, data);
1205 else {
1206
1207 char *ptr;
1208
1209 if (v->len == v->cap) bc_vec_grow(v, 1);
1210
1211 ptr = v->v + v->size * idx;
1212
1213 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1214 memmove(ptr, data, v->size);
1215 }
1216}
1217
1218static void bc_vec_string(BcVec *v, size_t len, const char *str)
1219{
1220 bc_vec_npop(v, v->len);
1221 bc_vec_expand(v, len + 1);
1222 memcpy(v->v, str, len);
1223 v->len = len;
1224
1225 bc_vec_pushByte(v, '\0');
1226}
1227
1228static void bc_vec_concat(BcVec *v, const char *str)
1229{
1230 size_t len;
1231
1232 if (v->len == 0) bc_vec_pushByte(v, '\0');
1233
1234 len = v->len + strlen(str);
1235
1236 if (v->cap < len) bc_vec_grow(v, len - v->len);
1237 strcat(v->v, str);
1238
1239 v->len = len;
1240}
1241
1242static void *bc_vec_item(const BcVec *v, size_t idx)
1243{
1244 return v->v + v->size * idx;
1245}
1246
1247static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1248{
1249 return v->v + v->size * (v->len - idx - 1);
1250}
1251
1252static void bc_vec_free(void *vec)
1253{
1254 BcVec *v = (BcVec *) vec;
1255 bc_vec_npop(v, v->len);
1256 free(v->v);
1257}
1258
1259static size_t bc_map_find(const BcVec *v, const void *ptr)
1260{
1261 size_t low = 0, high = v->len;
1262
1263 while (low < high) {
1264
1265 size_t mid = (low + high) / 2;
1266 BcId *id = bc_vec_item(v, mid);
1267 int result = bc_id_cmp(ptr, id);
1268
1269 if (result == 0)
1270 return mid;
1271 else if (result < 0)
1272 high = mid;
1273 else
1274 low = mid + 1;
1275 }
1276
1277 return low;
1278}
1279
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001280static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001281{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001282 size_t n = *i = bc_map_find(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001283
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001284 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001285 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001286 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1287 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001288 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001289 bc_vec_pushAt(v, ptr, n);
1290 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001291}
1292
1293static size_t bc_map_index(const BcVec *v, const void *ptr)
1294{
1295 size_t i = bc_map_find(v, ptr);
1296 if (i >= v->len) return BC_VEC_INVALID_IDX;
1297 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1298}
1299
1300static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1301{
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001302 bool bad_chars;
Gavin Howard01055ba2018-11-03 11:00:21 -06001303
Denys Vlasenko00d77792018-11-30 23:13:42 +01001304 do {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001305 int i;
1306 char c;
Gavin Howard01055ba2018-11-03 11:00:21 -06001307
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001308 bad_chars = 0;
1309 bc_vec_npop(vec, vec->len);
1310
1311 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06001312#if ENABLE_FEATURE_BC_SIGNALS
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001313 if (bb_got_signal) { // ^C was pressed
1314 intr:
1315 bb_got_signal = 0; // resets G_interrupt to zero
1316 fputs(IS_BC
1317 ? "\ninterrupt (type \"quit\" to exit)\n"
1318 : "\ninterrupt (type \"q\" to exit)\n"
1319 , stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001320 }
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001321#endif
1322 if (G.ttyin && !G_posix)
1323 fputs(prompt, stderr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001324
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001325#if ENABLE_FEATURE_BC_SIGNALS
1326 errno = 0;
1327#endif
1328 do {
1329 i = fgetc(stdin);
1330 if (i == EOF) {
1331#if ENABLE_FEATURE_BC_SIGNALS
1332 // Both conditions appear simultaneously, check both just in case
1333 if (errno == EINTR || bb_got_signal) {
1334 // ^C was pressed
1335 clearerr(stdin);
1336 goto intr;
1337 }
1338#endif
1339 if (ferror(stdin))
1340 quit(); // this emits error message
1341 G.eof = 1;
1342 // Note: EOF does not append '\n', therefore:
1343 // printf 'print 123\n' | bc - works
1344 // printf 'print 123' | bc - fails (syntax error)
1345 break;
1346 }
1347
1348 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1349 || i > 0x7e
1350 ) {
1351 // Bad chars on this line, ignore entire line
1352 bc_error("illegal character 0x%02x", i);
1353 bad_chars = 1;
1354 }
1355 c = (char) i;
1356 bc_vec_push(vec, &c);
1357 } while (i != '\n');
1358 } while (bad_chars);
Gavin Howard01055ba2018-11-03 11:00:21 -06001359
1360 bc_vec_pushByte(vec, '\0');
1361
1362 return BC_STATUS_SUCCESS;
1363}
1364
Denys Vlasenkodf515392018-12-02 19:27:48 +01001365static char* bc_read_file(const char *path)
Gavin Howard01055ba2018-11-03 11:00:21 -06001366{
Denys Vlasenkodf515392018-12-02 19:27:48 +01001367 char *buf;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001368 size_t size = ((size_t) -1);
1369 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001370
Denys Vlasenkodf515392018-12-02 19:27:48 +01001371 buf = xmalloc_open_read_close(path, &size);
Gavin Howard01055ba2018-11-03 11:00:21 -06001372
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001373 for (i = 0; i < size; ++i) {
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01001374 char c = buf[i];
1375 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1376 || c > 0x7e
1377 ) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01001378 free(buf);
1379 buf = NULL;
1380 break;
1381 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001382 }
1383
Denys Vlasenkodf515392018-12-02 19:27:48 +01001384 return buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06001385}
1386
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001387static void bc_args(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06001388{
Gavin Howard01055ba2018-11-03 11:00:21 -06001389 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001390
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001391 GETOPT_RESET();
Gavin Howard01055ba2018-11-03 11:00:21 -06001392#if ENABLE_FEATURE_BC_LONG_OPTIONS
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001393 G.flags = getopt32long(argv, "xwvsqli",
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001394 "extended-register\0" No_argument "x"
1395 "warn\0" No_argument "w"
1396 "version\0" No_argument "v"
1397 "standard\0" No_argument "s"
1398 "quiet\0" No_argument "q"
1399 "mathlib\0" No_argument "l"
1400 "interactive\0" No_argument "i"
1401 );
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001402#else
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001403 G.flags = getopt32(argv, "xwvsqli");
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01001404#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001405
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001406 if (G.flags & BC_FLAG_V) bc_vm_info();
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01001407 // should not be necessary, getopt32() handles this??
1408 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
Gavin Howard01055ba2018-11-03 11:00:21 -06001409
Denys Vlasenko785e4b32018-12-02 17:18:52 +01001410 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001411}
1412
1413static void bc_num_setToZero(BcNum *n, size_t scale)
1414{
1415 n->len = 0;
1416 n->neg = false;
1417 n->rdx = scale;
1418}
1419
1420static void bc_num_zero(BcNum *n)
1421{
1422 bc_num_setToZero(n, 0);
1423}
1424
1425static void bc_num_one(BcNum *n)
1426{
1427 bc_num_setToZero(n, 0);
1428 n->len = 1;
1429 n->num[0] = 1;
1430}
1431
1432static void bc_num_ten(BcNum *n)
1433{
1434 bc_num_setToZero(n, 0);
1435 n->len = 2;
1436 n->num[0] = 0;
1437 n->num[1] = 1;
1438}
1439
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001440static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001441 size_t len)
1442{
1443 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001444 for (i = 0; i < len; ++i) {
1445 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001446 a[i + j++] += 10;
1447 a[i + j] -= 1;
1448 }
1449 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001450}
1451
1452static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1453{
1454 size_t i;
1455 int c = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001456 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
Gavin Howard01055ba2018-11-03 11:00:21 -06001457 return BC_NUM_NEG(i + 1, c < 0);
1458}
1459
1460static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1461{
1462 size_t i, min, a_int, b_int, diff;
1463 BcDig *max_num, *min_num;
1464 bool a_max, neg = false;
1465 ssize_t cmp;
1466
1467 if (a == b) return 0;
1468 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1469 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1470 if (a->neg) {
1471 if (b->neg)
1472 neg = true;
1473 else
1474 return -1;
1475 }
1476 else if (b->neg)
1477 return 1;
1478
1479 a_int = BC_NUM_INT(a);
1480 b_int = BC_NUM_INT(b);
1481 a_int -= b_int;
1482 a_max = (a->rdx > b->rdx);
1483
1484 if (a_int != 0) return (ssize_t) a_int;
1485
1486 if (a_max) {
1487 min = b->rdx;
1488 diff = a->rdx - b->rdx;
1489 max_num = a->num + diff;
1490 min_num = b->num;
1491 }
1492 else {
1493 min = a->rdx;
1494 diff = b->rdx - a->rdx;
1495 max_num = b->num + diff;
1496 min_num = a->num;
1497 }
1498
1499 cmp = bc_num_compare(max_num, min_num, b_int + min);
1500 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1501
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001502 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001503 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1504 }
1505
1506 return 0;
1507}
1508
1509static void bc_num_truncate(BcNum *n, size_t places)
1510{
1511 if (places == 0) return;
1512
1513 n->rdx -= places;
1514
1515 if (n->len != 0) {
1516 n->len -= places;
1517 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1518 }
1519}
1520
1521static void bc_num_extend(BcNum *n, size_t places)
1522{
1523 size_t len = n->len + places;
1524
1525 if (places != 0) {
1526
1527 if (n->cap < len) bc_num_expand(n, len);
1528
1529 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1530 memset(n->num, 0, sizeof(BcDig) * places);
1531
1532 n->len += places;
1533 n->rdx += places;
1534 }
1535}
1536
1537static void bc_num_clean(BcNum *n)
1538{
1539 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1540 if (n->len == 0)
1541 n->neg = false;
1542 else if (n->len < n->rdx)
1543 n->len = n->rdx;
1544}
1545
1546static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1547{
1548 if (n->rdx < scale)
1549 bc_num_extend(n, scale - n->rdx);
1550 else
1551 bc_num_truncate(n, n->rdx - scale);
1552
1553 bc_num_clean(n);
1554 if (n->len != 0) n->neg = !neg1 != !neg2;
1555}
1556
1557static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1558 BcNum *restrict b)
1559{
1560 if (idx < n->len) {
1561
1562 b->len = n->len - idx;
1563 a->len = idx;
1564 a->rdx = b->rdx = 0;
1565
1566 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1567 memcpy(a->num, n->num, idx * sizeof(BcDig));
1568 }
1569 else {
1570 bc_num_zero(b);
1571 bc_num_copy(a, n);
1572 }
1573
1574 bc_num_clean(a);
1575 bc_num_clean(b);
1576}
1577
1578static BcStatus bc_num_shift(BcNum *n, size_t places)
1579{
1580 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1581 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1582
1583 if (n->rdx >= places)
1584 n->rdx -= places;
1585 else {
1586 bc_num_extend(n, places - n->rdx);
1587 n->rdx = 0;
1588 }
1589
1590 bc_num_clean(n);
1591
1592 return BC_STATUS_SUCCESS;
1593}
1594
1595static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1596{
1597 BcNum one;
1598 BcDig num[2];
1599
1600 one.cap = 2;
1601 one.num = num;
1602 bc_num_one(&one);
1603
1604 return bc_num_div(&one, a, b, scale);
1605}
1606
1607static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1608{
1609 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1610 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1611 int carry, in;
1612
1613 // Because this function doesn't need to use scale (per the bc spec),
1614 // I am hijacking it to say whether it's doing an add or a subtract.
1615
1616 if (a->len == 0) {
1617 bc_num_copy(c, b);
1618 if (sub && c->len) c->neg = !c->neg;
1619 return BC_STATUS_SUCCESS;
1620 }
1621 else if (b->len == 0) {
1622 bc_num_copy(c, a);
1623 return BC_STATUS_SUCCESS;
1624 }
1625
1626 c->neg = a->neg;
1627 c->rdx = BC_MAX(a->rdx, b->rdx);
1628 min_rdx = BC_MIN(a->rdx, b->rdx);
1629 c->len = 0;
1630
1631 if (a->rdx > b->rdx) {
1632 diff = a->rdx - b->rdx;
1633 ptr = a->num;
1634 ptr_a = a->num + diff;
1635 ptr_b = b->num;
1636 }
1637 else {
1638 diff = b->rdx - a->rdx;
1639 ptr = b->num;
1640 ptr_a = a->num;
1641 ptr_b = b->num + diff;
1642 }
1643
1644 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1645
1646 ptr_c += diff;
1647 a_int = BC_NUM_INT(a);
1648 b_int = BC_NUM_INT(b);
1649
1650 if (a_int > b_int) {
1651 min_int = b_int;
1652 max = a_int;
1653 ptr = ptr_a;
1654 }
1655 else {
1656 min_int = a_int;
1657 max = b_int;
1658 ptr = ptr_b;
1659 }
1660
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001661 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001662 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1663 carry = in / 10;
1664 ptr_c[i] = (BcDig)(in % 10);
1665 }
1666
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001667 for (; i < max + min_rdx; ++i, ++c->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001668 in = ((int) ptr[i]) + carry;
1669 carry = in / 10;
1670 ptr_c[i] = (BcDig)(in % 10);
1671 }
1672
1673 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1674
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001675 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001676}
1677
1678static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1679{
Gavin Howard01055ba2018-11-03 11:00:21 -06001680 ssize_t cmp;
1681 BcNum *minuend, *subtrahend;
1682 size_t start;
1683 bool aneg, bneg, neg;
1684
1685 // Because this function doesn't need to use scale (per the bc spec),
1686 // I am hijacking it to say whether it's doing an add or a subtract.
1687
1688 if (a->len == 0) {
1689 bc_num_copy(c, b);
1690 if (sub && c->len) c->neg = !c->neg;
1691 return BC_STATUS_SUCCESS;
1692 }
1693 else if (b->len == 0) {
1694 bc_num_copy(c, a);
1695 return BC_STATUS_SUCCESS;
1696 }
1697
1698 aneg = a->neg;
1699 bneg = b->neg;
1700 a->neg = b->neg = false;
1701
1702 cmp = bc_num_cmp(a, b);
1703
1704 a->neg = aneg;
1705 b->neg = bneg;
1706
1707 if (cmp == 0) {
1708 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1709 return BC_STATUS_SUCCESS;
1710 }
1711 else if (cmp > 0) {
1712 neg = a->neg;
1713 minuend = a;
1714 subtrahend = b;
1715 }
1716 else {
1717 neg = b->neg;
1718 if (sub) neg = !neg;
1719 minuend = b;
1720 subtrahend = a;
1721 }
1722
1723 bc_num_copy(c, minuend);
1724 c->neg = neg;
1725
1726 if (c->rdx < subtrahend->rdx) {
1727 bc_num_extend(c, subtrahend->rdx - c->rdx);
1728 start = 0;
1729 }
1730 else
1731 start = c->rdx - subtrahend->rdx;
1732
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001733 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001734
1735 bc_num_clean(c);
1736
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001737 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001738}
1739
1740static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1741 BcNum *restrict c)
1742{
1743 BcStatus s;
1744 int carry;
1745 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1746 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1747 bool aone = BC_NUM_ONE(a);
1748
Gavin Howard01055ba2018-11-03 11:00:21 -06001749 if (a->len == 0 || b->len == 0) {
1750 bc_num_zero(c);
1751 return BC_STATUS_SUCCESS;
1752 }
1753 else if (aone || BC_NUM_ONE(b)) {
1754 bc_num_copy(c, aone ? b : a);
1755 return BC_STATUS_SUCCESS;
1756 }
1757
1758 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1759 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1760 {
1761 bc_num_expand(c, a->len + b->len + 1);
1762
1763 memset(c->num, 0, sizeof(BcDig) * c->cap);
1764 c->len = carry = len = 0;
1765
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001766 for (i = 0; i < b->len; ++i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001767
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001768 for (j = 0; j < a->len; ++j) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001769 int in = (int) c->num[i + j];
1770 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1771 carry = in / 10;
1772 c->num[i + j] = (BcDig)(in % 10);
1773 }
1774
1775 c->num[i + j] += (BcDig) carry;
1776 len = BC_MAX(len, i + j + !!carry);
1777 carry = 0;
1778 }
1779
1780 c->len = len;
1781
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001782 return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06001783 }
1784
1785 bc_num_init(&l1, max);
1786 bc_num_init(&h1, max);
1787 bc_num_init(&l2, max);
1788 bc_num_init(&h2, max);
1789 bc_num_init(&m1, max);
1790 bc_num_init(&m2, max);
1791 bc_num_init(&z0, max);
1792 bc_num_init(&z1, max);
1793 bc_num_init(&z2, max);
1794 bc_num_init(&temp, max + max);
1795
1796 bc_num_split(a, max2, &l1, &h1);
1797 bc_num_split(b, max2, &l2, &h2);
1798
1799 s = bc_num_add(&h1, &l1, &m1, 0);
1800 if (s) goto err;
1801 s = bc_num_add(&h2, &l2, &m2, 0);
1802 if (s) goto err;
1803
1804 s = bc_num_k(&h1, &h2, &z0);
1805 if (s) goto err;
1806 s = bc_num_k(&m1, &m2, &z1);
1807 if (s) goto err;
1808 s = bc_num_k(&l1, &l2, &z2);
1809 if (s) goto err;
1810
1811 s = bc_num_sub(&z1, &z0, &temp, 0);
1812 if (s) goto err;
1813 s = bc_num_sub(&temp, &z2, &z1, 0);
1814 if (s) goto err;
1815
1816 s = bc_num_shift(&z0, max2 * 2);
1817 if (s) goto err;
1818 s = bc_num_shift(&z1, max2);
1819 if (s) goto err;
1820 s = bc_num_add(&z0, &z1, &temp, 0);
1821 if (s) goto err;
1822 s = bc_num_add(&temp, &z2, c, 0);
1823
1824err:
1825 bc_num_free(&temp);
1826 bc_num_free(&z2);
1827 bc_num_free(&z1);
1828 bc_num_free(&z0);
1829 bc_num_free(&m2);
1830 bc_num_free(&m1);
1831 bc_num_free(&h2);
1832 bc_num_free(&l2);
1833 bc_num_free(&h1);
1834 bc_num_free(&l1);
1835 return s;
1836}
1837
1838static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1839{
1840 BcStatus s;
1841 BcNum cpa, cpb;
1842 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1843
1844 scale = BC_MAX(scale, a->rdx);
1845 scale = BC_MAX(scale, b->rdx);
1846 scale = BC_MIN(a->rdx + b->rdx, scale);
1847 maxrdx = BC_MAX(maxrdx, scale);
1848
1849 bc_num_init(&cpa, a->len);
1850 bc_num_init(&cpb, b->len);
1851
1852 bc_num_copy(&cpa, a);
1853 bc_num_copy(&cpb, b);
1854 cpa.neg = cpb.neg = false;
1855
1856 s = bc_num_shift(&cpa, maxrdx);
1857 if (s) goto err;
1858 s = bc_num_shift(&cpb, maxrdx);
1859 if (s) goto err;
1860 s = bc_num_k(&cpa, &cpb, c);
1861 if (s) goto err;
1862
1863 maxrdx += scale;
1864 bc_num_expand(c, c->len + maxrdx);
1865
1866 if (c->len < maxrdx) {
1867 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1868 c->len += maxrdx;
1869 }
1870
1871 c->rdx = maxrdx;
1872 bc_num_retireMul(c, scale, a->neg, b->neg);
1873
1874err:
1875 bc_num_free(&cpb);
1876 bc_num_free(&cpa);
1877 return s;
1878}
1879
1880static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1881{
1882 BcStatus s = BC_STATUS_SUCCESS;
1883 BcDig *n, *p, q;
1884 size_t len, end, i;
1885 BcNum cp;
1886 bool zero = true;
1887
1888 if (b->len == 0)
1889 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1890 else if (a->len == 0) {
1891 bc_num_setToZero(c, scale);
1892 return BC_STATUS_SUCCESS;
1893 }
1894 else if (BC_NUM_ONE(b)) {
1895 bc_num_copy(c, a);
1896 bc_num_retireMul(c, scale, a->neg, b->neg);
1897 return BC_STATUS_SUCCESS;
1898 }
1899
1900 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1901 bc_num_copy(&cp, a);
1902 len = b->len;
1903
1904 if (len > cp.len) {
1905 bc_num_expand(&cp, len + 2);
1906 bc_num_extend(&cp, len - cp.len);
1907 }
1908
1909 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1910 cp.rdx -= b->rdx;
1911 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1912
1913 if (b->rdx == b->len) {
1914 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1915 len -= i - 1;
1916 }
1917
1918 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1919
1920 // We want an extra zero in front to make things simpler.
1921 cp.num[cp.len++] = 0;
1922 end = cp.len - len;
1923
1924 bc_num_expand(c, cp.len);
1925
1926 bc_num_zero(c);
1927 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1928 c->rdx = cp.rdx;
1929 c->len = cp.len;
1930 p = b->num;
1931
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001932 for (i = end - 1; !s && i < end; --i) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001933 n = cp.num + i;
1934 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001935 bc_num_subArrays(n, p, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001936 c->num[i] = q;
1937 }
1938
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001939 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001940 bc_num_free(&cp);
1941
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001942 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001943}
1944
1945static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1946 BcNum *restrict d, size_t scale, size_t ts)
1947{
1948 BcStatus s;
1949 BcNum temp;
1950 bool neg;
1951
1952 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1953
1954 if (a->len == 0) {
1955 bc_num_setToZero(d, ts);
1956 return BC_STATUS_SUCCESS;
1957 }
1958
1959 bc_num_init(&temp, d->cap);
1960 bc_num_d(a, b, c, scale);
1961
1962 if (scale != 0) scale = ts;
1963
1964 s = bc_num_m(c, b, &temp, scale);
1965 if (s) goto err;
1966 s = bc_num_sub(a, &temp, d, scale);
1967 if (s) goto err;
1968
1969 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1970
1971 neg = d->neg;
1972 bc_num_retireMul(d, ts, a->neg, b->neg);
1973 d->neg = neg;
1974
1975err:
1976 bc_num_free(&temp);
1977 return s;
1978}
1979
1980static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1981{
1982 BcStatus s;
1983 BcNum c1;
1984 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1985
1986 bc_num_init(&c1, len);
1987 s = bc_num_r(a, b, &c1, c, scale, ts);
1988 bc_num_free(&c1);
1989
1990 return s;
1991}
1992
1993static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1994{
1995 BcStatus s = BC_STATUS_SUCCESS;
1996 BcNum copy;
1997 unsigned long pow;
1998 size_t i, powrdx, resrdx;
1999 bool neg, zero;
2000
2001 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2002
2003 if (b->len == 0) {
2004 bc_num_one(c);
2005 return BC_STATUS_SUCCESS;
2006 }
2007 else if (a->len == 0) {
2008 bc_num_setToZero(c, scale);
2009 return BC_STATUS_SUCCESS;
2010 }
2011 else if (BC_NUM_ONE(b)) {
2012 if (!b->neg)
2013 bc_num_copy(c, a);
2014 else
2015 s = bc_num_inv(a, c, scale);
2016 return s;
2017 }
2018
2019 neg = b->neg;
2020 b->neg = false;
2021
2022 s = bc_num_ulong(b, &pow);
2023 if (s) return s;
2024
2025 bc_num_init(&copy, a->len);
2026 bc_num_copy(&copy, a);
2027
2028 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2029
2030 b->neg = neg;
2031
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002032 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002033 powrdx <<= 1;
2034 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2035 if (s) goto err;
2036 }
2037
Gavin Howard01055ba2018-11-03 11:00:21 -06002038 bc_num_copy(c, &copy);
2039
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002040 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002041
2042 powrdx <<= 1;
2043 s = bc_num_mul(&copy, &copy, &copy, powrdx);
2044 if (s) goto err;
2045
2046 if (pow & 1) {
2047 resrdx += powrdx;
2048 s = bc_num_mul(c, &copy, c, resrdx);
2049 if (s) goto err;
2050 }
2051 }
2052
2053 if (neg) {
2054 s = bc_num_inv(c, c, scale);
2055 if (s) goto err;
2056 }
2057
Gavin Howard01055ba2018-11-03 11:00:21 -06002058 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2059
2060 // We can't use bc_num_clean() here.
2061 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2062 if (zero) bc_num_setToZero(c, scale);
2063
2064err:
2065 bc_num_free(&copy);
2066 return s;
2067}
2068
2069static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2070 BcNumBinaryOp op, size_t req)
2071{
2072 BcStatus s;
2073 BcNum num2, *ptr_a, *ptr_b;
2074 bool init = false;
2075
2076 if (c == a) {
2077 ptr_a = &num2;
2078 memcpy(ptr_a, c, sizeof(BcNum));
2079 init = true;
2080 }
2081 else
2082 ptr_a = a;
2083
2084 if (c == b) {
2085 ptr_b = &num2;
2086 if (c != a) {
2087 memcpy(ptr_b, c, sizeof(BcNum));
2088 init = true;
2089 }
2090 }
2091 else
2092 ptr_b = b;
2093
2094 if (init)
2095 bc_num_init(c, req);
2096 else
2097 bc_num_expand(c, req);
2098
2099 s = op(ptr_a, ptr_b, c, scale);
2100
2101 if (init) bc_num_free(&num2);
2102
2103 return s;
2104}
2105
2106static bool bc_num_strValid(const char *val, size_t base)
2107{
2108 BcDig b;
2109 bool small, radix = false;
2110 size_t i, len = strlen(val);
2111
2112 if (!len) return true;
2113
2114 small = base <= 10;
2115 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2116
2117 for (i = 0; i < len; ++i) {
2118
2119 BcDig c = val[i];
2120
2121 if (c == '.') {
2122
2123 if (radix) return false;
2124
2125 radix = true;
2126 continue;
2127 }
2128
2129 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2130 return false;
2131 }
2132
2133 return true;
2134}
2135
2136static void bc_num_parseDecimal(BcNum *n, const char *val)
2137{
2138 size_t len, i;
2139 const char *ptr;
2140 bool zero = true;
2141
2142 for (i = 0; val[i] == '0'; ++i);
2143
2144 val += i;
2145 len = strlen(val);
2146 bc_num_zero(n);
2147
2148 if (len != 0) {
2149 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2150 bc_num_expand(n, len);
2151 }
2152
2153 ptr = strchr(val, '.');
2154
2155 // Explicitly test for NULL here to produce either a 0 or 1.
2156 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2157
2158 if (!zero) {
2159 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2160 n->num[n->len] = val[i] - '0';
2161 }
2162}
2163
2164static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2165{
2166 BcStatus s;
2167 BcNum temp, mult, result;
2168 BcDig c = '\0';
2169 bool zero = true;
2170 unsigned long v;
2171 size_t i, digits, len = strlen(val);
2172
2173 bc_num_zero(n);
2174
2175 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2176 if (zero) return;
2177
2178 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2179 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2180
2181 for (i = 0; i < len; ++i) {
2182
2183 c = val[i];
2184 if (c == '.') break;
2185
2186 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2187
2188 s = bc_num_mul(n, base, &mult, 0);
2189 if (s) goto int_err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002190 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002191 s = bc_num_add(&mult, &temp, n, 0);
2192 if (s) goto int_err;
2193 }
2194
2195 if (i == len) {
2196 c = val[i];
2197 if (c == 0) goto int_err;
2198 }
2199
2200 bc_num_init(&result, base->len);
2201 bc_num_zero(&result);
2202 bc_num_one(&mult);
2203
2204 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2205
2206 c = val[i];
2207 if (c == 0) break;
2208
2209 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2210
2211 s = bc_num_mul(&result, base, &result, 0);
2212 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002213 bc_num_ulong2num(&temp, v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002214 s = bc_num_add(&result, &temp, &result, 0);
2215 if (s) goto err;
2216 s = bc_num_mul(&mult, base, &mult, 0);
2217 if (s) goto err;
2218 }
2219
2220 s = bc_num_div(&result, &mult, &result, digits);
2221 if (s) goto err;
2222 s = bc_num_add(n, &result, n, digits);
2223 if (s) goto err;
2224
2225 if (n->len != 0) {
2226 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2227 }
2228 else
2229 bc_num_zero(n);
2230
2231err:
2232 bc_num_free(&result);
2233int_err:
2234 bc_num_free(&mult);
2235 bc_num_free(&temp);
2236}
2237
2238static void bc_num_printNewline(size_t *nchars, size_t line_len)
2239{
2240 if (*nchars == line_len - 1) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002241 bb_putchar('\\');
2242 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002243 *nchars = 0;
2244 }
2245}
2246
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002247#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002248static void bc_num_printChar(size_t num, size_t width, bool radix,
2249 size_t *nchars, size_t line_len)
2250{
2251 (void) radix, (void) line_len;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002252 bb_putchar((char) num);
Gavin Howard01055ba2018-11-03 11:00:21 -06002253 *nchars = *nchars + width;
2254}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002255#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002256
2257static void bc_num_printDigits(size_t num, size_t width, bool radix,
2258 size_t *nchars, size_t line_len)
2259{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002260 size_t exp, pow;
Gavin Howard01055ba2018-11-03 11:00:21 -06002261
2262 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002263 bb_putchar(radix ? '.' : ' ');
Gavin Howard01055ba2018-11-03 11:00:21 -06002264 ++(*nchars);
2265
2266 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002267 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2268 continue;
Gavin Howard01055ba2018-11-03 11:00:21 -06002269
2270 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002271 size_t dig;
Gavin Howard01055ba2018-11-03 11:00:21 -06002272 bc_num_printNewline(nchars, line_len);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002273 dig = num / pow;
2274 num -= dig * pow;
Denys Vlasenko00d77792018-11-30 23:13:42 +01002275 bb_putchar(((char) dig) + '0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002276 }
2277}
2278
2279static void bc_num_printHex(size_t num, size_t width, bool radix,
2280 size_t *nchars, size_t line_len)
2281{
2282 if (radix) {
2283 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002284 bb_putchar('.');
Gavin Howard01055ba2018-11-03 11:00:21 -06002285 *nchars += 1;
2286 }
2287
2288 bc_num_printNewline(nchars, line_len);
Denys Vlasenko00d77792018-11-30 23:13:42 +01002289 bb_putchar(bb_hexdigits_upcase[num]);
Gavin Howard01055ba2018-11-03 11:00:21 -06002290 *nchars = *nchars + width;
2291}
2292
2293static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2294{
2295 size_t i, rdx = n->rdx - 1;
2296
Denys Vlasenko00d77792018-11-30 23:13:42 +01002297 if (n->neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002298 (*nchars) += n->neg;
2299
2300 for (i = n->len - 1; i < n->len; --i)
2301 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2302}
2303
2304static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2305 size_t *nchars, size_t len, BcNumDigitOp print)
2306{
2307 BcStatus s;
2308 BcVec stack;
2309 BcNum intp, fracp, digit, frac_len;
2310 unsigned long dig, *ptr;
2311 size_t i;
2312 bool radix;
2313
2314 if (n->len == 0) {
2315 print(0, width, false, nchars, len);
2316 return BC_STATUS_SUCCESS;
2317 }
2318
2319 bc_vec_init(&stack, sizeof(long), NULL);
2320 bc_num_init(&intp, n->len);
2321 bc_num_init(&fracp, n->rdx);
2322 bc_num_init(&digit, width);
2323 bc_num_init(&frac_len, BC_NUM_INT(n));
2324 bc_num_copy(&intp, n);
2325 bc_num_one(&frac_len);
2326
2327 bc_num_truncate(&intp, intp.rdx);
2328 s = bc_num_sub(n, &intp, &fracp, 0);
2329 if (s) goto err;
2330
2331 while (intp.len != 0) {
2332 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2333 if (s) goto err;
2334 s = bc_num_ulong(&digit, &dig);
2335 if (s) goto err;
2336 bc_vec_push(&stack, &dig);
2337 }
2338
2339 for (i = 0; i < stack.len; ++i) {
2340 ptr = bc_vec_item_rev(&stack, i);
2341 print(*ptr, width, false, nchars, len);
2342 }
2343
2344 if (!n->rdx) goto err;
2345
2346 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2347 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2348 if (s) goto err;
2349 s = bc_num_ulong(&fracp, &dig);
2350 if (s) goto err;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002351 bc_num_ulong2num(&intp, dig);
Gavin Howard01055ba2018-11-03 11:00:21 -06002352 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2353 if (s) goto err;
2354 print(dig, width, radix, nchars, len);
2355 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2356 if (s) goto err;
2357 }
2358
2359err:
2360 bc_num_free(&frac_len);
2361 bc_num_free(&digit);
2362 bc_num_free(&fracp);
2363 bc_num_free(&intp);
2364 bc_vec_free(&stack);
2365 return s;
2366}
2367
2368static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2369 size_t *nchars, size_t line_len)
2370{
2371 BcStatus s;
2372 size_t width, i;
2373 BcNumDigitOp print;
2374 bool neg = n->neg;
2375
Denys Vlasenko00d77792018-11-30 23:13:42 +01002376 if (neg) bb_putchar('-');
Gavin Howard01055ba2018-11-03 11:00:21 -06002377 (*nchars) += neg;
2378
2379 n->neg = false;
2380
2381 if (base_t <= BC_NUM_MAX_IBASE) {
2382 width = 1;
2383 print = bc_num_printHex;
2384 }
2385 else {
2386 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2387 print = bc_num_printDigits;
2388 }
2389
2390 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2391 n->neg = neg;
2392
2393 return s;
2394}
2395
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002396#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002397static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2398{
2399 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2400}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002401#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002402
2403static void bc_num_init(BcNum *n, size_t req)
2404{
2405 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2406 memset(n, 0, sizeof(BcNum));
2407 n->num = xmalloc(req);
2408 n->cap = req;
2409}
2410
2411static void bc_num_expand(BcNum *n, size_t req)
2412{
2413 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2414 if (req > n->cap) {
2415 n->num = xrealloc(n->num, req);
2416 n->cap = req;
2417 }
2418}
2419
2420static void bc_num_free(void *num)
2421{
2422 free(((BcNum *) num)->num);
2423}
2424
2425static void bc_num_copy(BcNum *d, BcNum *s)
2426{
2427 if (d != s) {
2428 bc_num_expand(d, s->cap);
2429 d->len = s->len;
2430 d->neg = s->neg;
2431 d->rdx = s->rdx;
2432 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2433 }
2434}
2435
2436static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2437 size_t base_t)
2438{
2439 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2440
2441 if (base_t == 10)
2442 bc_num_parseDecimal(n, val);
2443 else
2444 bc_num_parseBase(n, val, base);
2445
2446 return BC_STATUS_SUCCESS;
2447}
2448
2449static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2450 size_t *nchars, size_t line_len)
2451{
2452 BcStatus s = BC_STATUS_SUCCESS;
2453
2454 bc_num_printNewline(nchars, line_len);
2455
2456 if (n->len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002457 bb_putchar('0');
Gavin Howard01055ba2018-11-03 11:00:21 -06002458 ++(*nchars);
2459 }
2460 else if (base_t == 10)
2461 bc_num_printDecimal(n, nchars, line_len);
2462 else
2463 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2464
2465 if (newline) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01002466 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06002467 *nchars = 0;
2468 }
2469
2470 return s;
2471}
2472
2473static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2474{
2475 size_t i;
2476 unsigned long pow;
2477
2478 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2479
2480 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2481
2482 unsigned long prev = *result, powprev = pow;
2483
2484 *result += ((unsigned long) n->num[i]) * pow;
2485 pow *= 10;
2486
2487 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2488 }
2489
2490 return BC_STATUS_SUCCESS;
2491}
2492
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002493static void bc_num_ulong2num(BcNum *n, unsigned long val)
Gavin Howard01055ba2018-11-03 11:00:21 -06002494{
2495 size_t len;
2496 BcDig *ptr;
2497 unsigned long i;
2498
2499 bc_num_zero(n);
2500
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01002501 if (val == 0) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06002502
2503 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2504 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
Gavin Howard01055ba2018-11-03 11:00:21 -06002505}
2506
2507static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2508{
2509 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2510 (void) scale;
2511 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2512}
2513
2514static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2515{
2516 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2517 (void) scale;
2518 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2519}
2520
2521static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2522{
2523 size_t req = BC_NUM_MREQ(a, b, scale);
2524 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2525}
2526
2527static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2528{
2529 size_t req = BC_NUM_MREQ(a, b, scale);
2530 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2531}
2532
2533static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2534{
2535 size_t req = BC_NUM_MREQ(a, b, scale);
2536 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2537}
2538
2539static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2540{
2541 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2542}
2543
2544static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2545{
2546 BcStatus s;
2547 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2548 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2549 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2550
2551 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2552 bc_num_expand(b, req);
2553
2554 if (a->len == 0) {
2555 bc_num_setToZero(b, scale);
2556 return BC_STATUS_SUCCESS;
2557 }
2558 else if (a->neg)
2559 return BC_STATUS_MATH_NEGATIVE;
2560 else if (BC_NUM_ONE(a)) {
2561 bc_num_one(b);
2562 bc_num_extend(b, scale);
2563 return BC_STATUS_SUCCESS;
2564 }
2565
2566 scale = BC_MAX(scale, a->rdx) + 1;
2567 len = a->len + scale;
2568
2569 bc_num_init(&num1, len);
2570 bc_num_init(&num2, len);
2571 bc_num_init(&half, BC_NUM_DEF_SIZE);
2572
2573 bc_num_one(&half);
2574 half.num[0] = 5;
2575 half.rdx = 1;
2576
2577 bc_num_init(&f, len);
2578 bc_num_init(&fprime, len);
2579
2580 x0 = &num1;
2581 x1 = &num2;
2582
2583 bc_num_one(x0);
2584 pow = BC_NUM_INT(a);
2585
2586 if (pow) {
2587
2588 if (pow & 1)
2589 x0->num[0] = 2;
2590 else
2591 x0->num[0] = 6;
2592
2593 pow -= 2 - (pow & 1);
2594
2595 bc_num_extend(x0, pow);
2596
2597 // Make sure to move the radix back.
2598 x0->rdx -= pow;
2599 }
2600
2601 x0->rdx = digs = digs1 = 0;
2602 resrdx = scale + 2;
2603 len = BC_NUM_INT(x0) + resrdx - 1;
2604
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002605 while (cmp != 0 || digs < len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002606
2607 s = bc_num_div(a, x0, &f, resrdx);
2608 if (s) goto err;
2609 s = bc_num_add(x0, &f, &fprime, resrdx);
2610 if (s) goto err;
2611 s = bc_num_mul(&fprime, &half, x1, resrdx);
2612 if (s) goto err;
2613
2614 cmp = bc_num_cmp(x1, x0);
2615 digs = x1->len - (unsigned long long) llabs(cmp);
2616
2617 if (cmp == cmp2 && digs == digs1)
2618 times += 1;
2619 else
2620 times = 0;
2621
2622 resrdx += times > 4;
2623
2624 cmp2 = cmp1;
2625 cmp1 = cmp;
2626 digs1 = digs;
2627
2628 temp = x0;
2629 x0 = x1;
2630 x1 = temp;
2631 }
2632
Gavin Howard01055ba2018-11-03 11:00:21 -06002633 bc_num_copy(b, x0);
2634 scale -= 1;
2635 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2636
2637err:
2638 bc_num_free(&fprime);
2639 bc_num_free(&f);
2640 bc_num_free(&half);
2641 bc_num_free(&num2);
2642 bc_num_free(&num1);
2643 return s;
2644}
2645
2646static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2647 size_t scale)
2648{
2649 BcStatus s;
2650 BcNum num2, *ptr_a;
2651 bool init = false;
2652 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2653
2654 if (c == a) {
2655 memcpy(&num2, c, sizeof(BcNum));
2656 ptr_a = &num2;
2657 bc_num_init(c, len);
2658 init = true;
2659 }
2660 else {
2661 ptr_a = a;
2662 bc_num_expand(c, len);
2663 }
2664
2665 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2666
2667 if (init) bc_num_free(&num2);
2668
2669 return s;
2670}
2671
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002672#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002673static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2674{
2675 BcStatus s;
2676 BcNum base, exp, two, temp;
2677
2678 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2679 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2680 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2681
2682 bc_num_expand(d, c->len);
2683 bc_num_init(&base, c->len);
2684 bc_num_init(&exp, b->len);
2685 bc_num_init(&two, BC_NUM_DEF_SIZE);
2686 bc_num_init(&temp, b->len);
2687
2688 bc_num_one(&two);
2689 two.num[0] = 2;
2690 bc_num_one(d);
2691
2692 s = bc_num_rem(a, c, &base, 0);
2693 if (s) goto err;
2694 bc_num_copy(&exp, b);
2695
2696 while (exp.len != 0) {
2697
2698 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2699 if (s) goto err;
2700
2701 if (BC_NUM_ONE(&temp)) {
2702 s = bc_num_mul(d, &base, &temp, 0);
2703 if (s) goto err;
2704 s = bc_num_rem(&temp, c, d, 0);
2705 if (s) goto err;
2706 }
2707
2708 s = bc_num_mul(&base, &base, &temp, 0);
2709 if (s) goto err;
2710 s = bc_num_rem(&temp, c, &base, 0);
2711 if (s) goto err;
2712 }
2713
2714err:
2715 bc_num_free(&temp);
2716 bc_num_free(&two);
2717 bc_num_free(&exp);
2718 bc_num_free(&base);
2719 return s;
2720}
2721#endif // ENABLE_DC
2722
2723static int bc_id_cmp(const void *e1, const void *e2)
2724{
2725 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2726}
2727
2728static void bc_id_free(void *id)
2729{
2730 free(((BcId *) id)->name);
2731}
2732
2733static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2734{
2735 BcId a;
2736 size_t i;
2737
2738 for (i = 0; i < f->autos.len; ++i) {
2739 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2740 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2741 }
2742
2743 a.idx = var;
2744 a.name = name;
2745
2746 bc_vec_push(&f->autos, &a);
2747
2748 return BC_STATUS_SUCCESS;
2749}
2750
2751static void bc_func_init(BcFunc *f)
2752{
2753 bc_vec_init(&f->code, sizeof(char), NULL);
2754 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2755 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2756 f->nparams = 0;
2757}
2758
2759static void bc_func_free(void *func)
2760{
2761 BcFunc *f = (BcFunc *) func;
2762 bc_vec_free(&f->code);
2763 bc_vec_free(&f->autos);
2764 bc_vec_free(&f->labels);
2765}
2766
2767static void bc_array_init(BcVec *a, bool nums)
2768{
2769 if (nums)
2770 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2771 else
2772 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2773 bc_array_expand(a, 1);
2774}
2775
2776static void bc_array_copy(BcVec *d, const BcVec *s)
2777{
2778 size_t i;
2779
2780 bc_vec_npop(d, d->len);
2781 bc_vec_expand(d, s->cap);
2782 d->len = s->len;
2783
2784 for (i = 0; i < s->len; ++i) {
2785 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2786 bc_num_init(dnum, snum->len);
2787 bc_num_copy(dnum, snum);
2788 }
2789}
2790
2791static void bc_array_expand(BcVec *a, size_t len)
2792{
2793 BcResultData data;
2794
2795 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2796 while (len > a->len) {
2797 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2798 bc_vec_push(a, &data.n);
2799 }
2800 }
2801 else {
2802 while (len > a->len) {
2803 bc_array_init(&data.v, true);
2804 bc_vec_push(a, &data.v);
2805 }
2806 }
2807}
2808
2809static void bc_string_free(void *string)
2810{
2811 free(*((char **) string));
2812}
2813
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002814#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06002815static void bc_result_copy(BcResult *d, BcResult *src)
2816{
2817 d->t = src->t;
2818
2819 switch (d->t) {
2820
2821 case BC_RESULT_TEMP:
2822 case BC_RESULT_IBASE:
2823 case BC_RESULT_SCALE:
2824 case BC_RESULT_OBASE:
2825 {
2826 bc_num_init(&d->d.n, src->d.n.len);
2827 bc_num_copy(&d->d.n, &src->d.n);
2828 break;
2829 }
2830
2831 case BC_RESULT_VAR:
2832 case BC_RESULT_ARRAY:
2833 case BC_RESULT_ARRAY_ELEM:
2834 {
2835 d->d.id.name = xstrdup(src->d.id.name);
2836 break;
2837 }
2838
2839 case BC_RESULT_CONSTANT:
2840 case BC_RESULT_LAST:
2841 case BC_RESULT_ONE:
2842 case BC_RESULT_STR:
2843 {
2844 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2845 break;
2846 }
2847 }
2848}
2849#endif // ENABLE_DC
2850
2851static void bc_result_free(void *result)
2852{
2853 BcResult *r = (BcResult *) result;
2854
2855 switch (r->t) {
2856
2857 case BC_RESULT_TEMP:
2858 case BC_RESULT_IBASE:
2859 case BC_RESULT_SCALE:
2860 case BC_RESULT_OBASE:
2861 {
2862 bc_num_free(&r->d.n);
2863 break;
2864 }
2865
2866 case BC_RESULT_VAR:
2867 case BC_RESULT_ARRAY:
2868 case BC_RESULT_ARRAY_ELEM:
2869 {
2870 free(r->d.id.name);
2871 break;
2872 }
2873
2874 default:
2875 {
2876 // Do nothing.
2877 break;
2878 }
2879 }
2880}
2881
2882static void bc_lex_lineComment(BcLex *l)
2883{
2884 l->t.t = BC_LEX_WHITESPACE;
2885 while (l->i < l->len && l->buf[l->i++] != '\n');
2886 --l->i;
2887}
2888
2889static void bc_lex_whitespace(BcLex *l)
2890{
2891 char c;
2892 l->t.t = BC_LEX_WHITESPACE;
2893 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2894}
2895
2896static BcStatus bc_lex_number(BcLex *l, char start)
2897{
2898 const char *buf = l->buf + l->i;
2899 size_t len, hits = 0, bslashes = 0, i = 0, j;
2900 char c = buf[i];
2901 bool last_pt, pt = start == '.';
2902
2903 last_pt = pt;
2904 l->t.t = BC_LEX_NUMBER;
2905
2906 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2907 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2908 {
2909 if (c != '\\') {
2910 last_pt = c == '.';
2911 pt = pt || last_pt;
2912 }
2913 else {
2914 ++i;
2915 bslashes += 1;
2916 }
2917
2918 c = buf[++i];
2919 }
2920
2921 len = i + 1 * !last_pt - bslashes * 2;
2922 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2923
2924 bc_vec_npop(&l->t.v, l->t.v.len);
2925 bc_vec_expand(&l->t.v, len + 1);
2926 bc_vec_push(&l->t.v, &start);
2927
2928 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2929
2930 c = buf[j];
2931
2932 // If we have hit a backslash, skip it. We don't have
2933 // to check for a newline because it's guaranteed.
2934 if (hits < bslashes && c == '\\') {
2935 ++hits;
2936 ++j;
2937 continue;
2938 }
2939
2940 bc_vec_push(&l->t.v, &c);
2941 }
2942
2943 bc_vec_pushByte(&l->t.v, '\0');
2944 l->i += i;
2945
2946 return BC_STATUS_SUCCESS;
2947}
2948
2949static BcStatus bc_lex_name(BcLex *l)
2950{
2951 size_t i = 0;
2952 const char *buf = l->buf + l->i - 1;
2953 char c = buf[i];
2954
2955 l->t.t = BC_LEX_NAME;
2956
2957 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2958
2959 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2960 bc_vec_string(&l->t.v, i, buf);
2961
2962 // Increment the index. We minus 1 because it has already been incremented.
2963 l->i += i - 1;
2964
2965 return BC_STATUS_SUCCESS;
2966}
2967
2968static void bc_lex_init(BcLex *l, BcLexNext next)
2969{
2970 l->next = next;
2971 bc_vec_init(&l->t.v, sizeof(char), NULL);
2972}
2973
2974static void bc_lex_free(BcLex *l)
2975{
2976 bc_vec_free(&l->t.v);
2977}
2978
2979static void bc_lex_file(BcLex *l, const char *file)
2980{
2981 l->line = 1;
2982 l->newline = false;
2983 l->f = file;
2984}
2985
2986static BcStatus bc_lex_next(BcLex *l)
2987{
2988 BcStatus s;
2989
2990 l->t.last = l->t.t;
2991 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2992
2993 l->line += l->newline;
2994 l->t.t = BC_LEX_EOF;
2995
2996 l->newline = (l->i == l->len);
2997 if (l->newline) return BC_STATUS_SUCCESS;
2998
2999 // Loop until failure or we don't have whitespace. This
3000 // is so the parser doesn't get inundated with whitespace.
3001 do {
3002 s = l->next(l);
3003 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3004
3005 return s;
3006}
3007
3008static BcStatus bc_lex_text(BcLex *l, const char *text)
3009{
3010 l->buf = text;
3011 l->i = 0;
3012 l->len = strlen(text);
3013 l->t.t = l->t.last = BC_LEX_INVALID;
3014 return bc_lex_next(l);
3015}
3016
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003017#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003018static BcStatus bc_lex_identifier(BcLex *l)
3019{
3020 BcStatus s;
3021 size_t i;
3022 const char *buf = l->buf + l->i - 1;
3023
3024 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3025
3026 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3027
3028 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3029
3030 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3031
3032 if (!bc_lex_kws[i].posix) {
3033 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3034 bc_lex_kws[i].name);
3035 if (s) return s;
3036 }
3037
3038 // We minus 1 because the index has already been incremented.
3039 l->i += len - 1;
3040 return BC_STATUS_SUCCESS;
3041 }
3042 }
3043
3044 s = bc_lex_name(l);
3045 if (s) return s;
3046
3047 if (l->t.v.len - 1 > 1)
3048 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3049
3050 return s;
3051}
3052
3053static BcStatus bc_lex_string(BcLex *l)
3054{
3055 size_t len, nls = 0, i = l->i;
3056 char c;
3057
3058 l->t.t = BC_LEX_STR;
3059
3060 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3061
3062 if (c == '\0') {
3063 l->i = i;
3064 return BC_STATUS_LEX_NO_STRING_END;
3065 }
3066
3067 len = i - l->i;
3068 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3069 bc_vec_string(&l->t.v, len, l->buf + l->i);
3070
3071 l->i = i + 1;
3072 l->line += nls;
3073
3074 return BC_STATUS_SUCCESS;
3075}
3076
3077static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3078{
3079 if (l->buf[l->i] == '=') {
3080 ++l->i;
3081 l->t.t = with;
3082 }
3083 else
3084 l->t.t = without;
3085}
3086
3087static BcStatus bc_lex_comment(BcLex *l)
3088{
3089 size_t i, nls = 0;
3090 const char *buf = l->buf;
Gavin Howard01055ba2018-11-03 11:00:21 -06003091
3092 l->t.t = BC_LEX_WHITESPACE;
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003093 i = ++l->i;
3094 for (;;) {
3095 char c = buf[i];
3096 check_star:
3097 if (c == '*') {
3098 c = buf[++i];
3099 if (c == '/')
3100 break;
3101 goto check_star;
3102 }
3103 if (c == '\0') {
Gavin Howard01055ba2018-11-03 11:00:21 -06003104 l->i = i;
3105 return BC_STATUS_LEX_NO_COMMENT_END;
3106 }
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003107 nls += (c == '\n');
3108 i++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003109 }
3110
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003111 l->i = i + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003112 l->line += nls;
3113
3114 return BC_STATUS_SUCCESS;
3115}
3116
3117static BcStatus bc_lex_token(BcLex *l)
3118{
3119 BcStatus s = BC_STATUS_SUCCESS;
3120 char c = l->buf[l->i++], c2;
3121
3122 // This is the workhorse of the lexer.
3123 switch (c) {
3124
3125 case '\0':
3126 case '\n':
3127 {
3128 l->newline = true;
3129 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3130 break;
3131 }
3132
3133 case '\t':
3134 case '\v':
3135 case '\f':
3136 case '\r':
3137 case ' ':
3138 {
3139 bc_lex_whitespace(l);
3140 break;
3141 }
3142
3143 case '!':
3144 {
3145 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3146
3147 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3148 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3149 if (s) return s;
3150 }
3151
3152 break;
3153 }
3154
3155 case '"':
3156 {
3157 s = bc_lex_string(l);
3158 break;
3159 }
3160
3161 case '#':
3162 {
3163 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3164 if (s) return s;
3165
3166 bc_lex_lineComment(l);
3167
3168 break;
3169 }
3170
3171 case '%':
3172 {
3173 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3174 break;
3175 }
3176
3177 case '&':
3178 {
3179 c2 = l->buf[l->i];
3180 if (c2 == '&') {
3181
3182 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3183 if (s) return s;
3184
3185 ++l->i;
3186 l->t.t = BC_LEX_OP_BOOL_AND;
3187 }
3188 else {
3189 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003190 s = bc_error("bad character '%c'", '&');
Gavin Howard01055ba2018-11-03 11:00:21 -06003191 }
3192
3193 break;
3194 }
3195
3196 case '(':
3197 case ')':
3198 {
3199 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3200 break;
3201 }
3202
3203 case '*':
3204 {
3205 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3206 break;
3207 }
3208
3209 case '+':
3210 {
3211 c2 = l->buf[l->i];
3212 if (c2 == '+') {
3213 ++l->i;
3214 l->t.t = BC_LEX_OP_INC;
3215 }
3216 else
3217 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3218 break;
3219 }
3220
3221 case ',':
3222 {
3223 l->t.t = BC_LEX_COMMA;
3224 break;
3225 }
3226
3227 case '-':
3228 {
3229 c2 = l->buf[l->i];
3230 if (c2 == '-') {
3231 ++l->i;
3232 l->t.t = BC_LEX_OP_DEC;
3233 }
3234 else
3235 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3236 break;
3237 }
3238
3239 case '.':
3240 {
3241 if (isdigit(l->buf[l->i]))
3242 s = bc_lex_number(l, c);
3243 else {
3244 l->t.t = BC_LEX_KEY_LAST;
3245 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3246 }
3247 break;
3248 }
3249
3250 case '/':
3251 {
3252 c2 = l->buf[l->i];
3253 if (c2 == '*')
3254 s = bc_lex_comment(l);
3255 else
3256 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3257 break;
3258 }
3259
3260 case '0':
3261 case '1':
3262 case '2':
3263 case '3':
3264 case '4':
3265 case '5':
3266 case '6':
3267 case '7':
3268 case '8':
3269 case '9':
3270 case 'A':
3271 case 'B':
3272 case 'C':
3273 case 'D':
3274 case 'E':
3275 case 'F':
3276 {
3277 s = bc_lex_number(l, c);
3278 break;
3279 }
3280
3281 case ';':
3282 {
3283 l->t.t = BC_LEX_SCOLON;
3284 break;
3285 }
3286
3287 case '<':
3288 {
3289 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3290 break;
3291 }
3292
3293 case '=':
3294 {
3295 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3296 break;
3297 }
3298
3299 case '>':
3300 {
3301 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3302 break;
3303 }
3304
3305 case '[':
3306 case ']':
3307 {
3308 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3309 break;
3310 }
3311
3312 case '\\':
3313 {
3314 if (l->buf[l->i] == '\n') {
3315 l->t.t = BC_LEX_WHITESPACE;
3316 ++l->i;
3317 }
3318 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003319 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003320 break;
3321 }
3322
3323 case '^':
3324 {
3325 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3326 break;
3327 }
3328
3329 case 'a':
3330 case 'b':
3331 case 'c':
3332 case 'd':
3333 case 'e':
3334 case 'f':
3335 case 'g':
3336 case 'h':
3337 case 'i':
3338 case 'j':
3339 case 'k':
3340 case 'l':
3341 case 'm':
3342 case 'n':
3343 case 'o':
3344 case 'p':
3345 case 'q':
3346 case 'r':
3347 case 's':
3348 case 't':
3349 case 'u':
3350 case 'v':
3351 case 'w':
3352 case 'x':
3353 case 'y':
3354 case 'z':
3355 {
3356 s = bc_lex_identifier(l);
3357 break;
3358 }
3359
3360 case '{':
3361 case '}':
3362 {
3363 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3364 break;
3365 }
3366
3367 case '|':
3368 {
3369 c2 = l->buf[l->i];
3370
3371 if (c2 == '|') {
3372
3373 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3374 if (s) return s;
3375
3376 ++l->i;
3377 l->t.t = BC_LEX_OP_BOOL_OR;
3378 }
3379 else {
3380 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003381 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003382 }
3383
3384 break;
3385 }
3386
3387 default:
3388 {
3389 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003390 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003391 break;
3392 }
3393 }
3394
3395 return s;
3396}
3397#endif // ENABLE_BC
3398
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003399#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06003400static BcStatus dc_lex_register(BcLex *l)
3401{
3402 BcStatus s = BC_STATUS_SUCCESS;
3403
3404 if (isspace(l->buf[l->i - 1])) {
3405 bc_lex_whitespace(l);
3406 ++l->i;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01003407 if (!G_exreg)
Gavin Howard01055ba2018-11-03 11:00:21 -06003408 s = BC_STATUS_LEX_EXTENDED_REG;
3409 else
3410 s = bc_lex_name(l);
3411 }
3412 else {
3413 bc_vec_npop(&l->t.v, l->t.v.len);
3414 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3415 bc_vec_pushByte(&l->t.v, '\0');
3416 l->t.t = BC_LEX_NAME;
3417 }
3418
3419 return s;
3420}
3421
3422static BcStatus dc_lex_string(BcLex *l)
3423{
3424 size_t depth = 1, nls = 0, i = l->i;
3425 char c;
3426
3427 l->t.t = BC_LEX_STR;
3428 bc_vec_npop(&l->t.v, l->t.v.len);
3429
3430 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3431
3432 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3433 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3434 nls += (c == '\n');
3435
3436 if (depth) bc_vec_push(&l->t.v, &c);
3437 }
3438
3439 if (c == '\0') {
3440 l->i = i;
3441 return BC_STATUS_LEX_NO_STRING_END;
3442 }
3443
3444 bc_vec_pushByte(&l->t.v, '\0');
3445 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3446
3447 l->i = i;
3448 l->line += nls;
3449
3450 return BC_STATUS_SUCCESS;
3451}
3452
3453static BcStatus dc_lex_token(BcLex *l)
3454{
3455 BcStatus s = BC_STATUS_SUCCESS;
3456 char c = l->buf[l->i++], c2;
3457 size_t i;
3458
3459 for (i = 0; i < dc_lex_regs_len; ++i) {
3460 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3461 }
3462
3463 if (c >= '%' && c <= '~' &&
3464 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3465 {
3466 return s;
3467 }
3468
3469 // This is the workhorse of the lexer.
3470 switch (c) {
3471
3472 case '\0':
3473 {
3474 l->t.t = BC_LEX_EOF;
3475 break;
3476 }
3477
3478 case '\n':
3479 case '\t':
3480 case '\v':
3481 case '\f':
3482 case '\r':
3483 case ' ':
3484 {
3485 l->newline = (c == '\n');
3486 bc_lex_whitespace(l);
3487 break;
3488 }
3489
3490 case '!':
3491 {
3492 c2 = l->buf[l->i];
3493
3494 if (c2 == '=')
3495 l->t.t = BC_LEX_OP_REL_NE;
3496 else if (c2 == '<')
3497 l->t.t = BC_LEX_OP_REL_LE;
3498 else if (c2 == '>')
3499 l->t.t = BC_LEX_OP_REL_GE;
3500 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003501 return bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003502
3503 ++l->i;
3504 break;
3505 }
3506
3507 case '#':
3508 {
3509 bc_lex_lineComment(l);
3510 break;
3511 }
3512
3513 case '.':
3514 {
3515 if (isdigit(l->buf[l->i]))
3516 s = bc_lex_number(l, c);
3517 else
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003518 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003519 break;
3520 }
3521
3522 case '0':
3523 case '1':
3524 case '2':
3525 case '3':
3526 case '4':
3527 case '5':
3528 case '6':
3529 case '7':
3530 case '8':
3531 case '9':
3532 case 'A':
3533 case 'B':
3534 case 'C':
3535 case 'D':
3536 case 'E':
3537 case 'F':
3538 {
3539 s = bc_lex_number(l, c);
3540 break;
3541 }
3542
3543 case '[':
3544 {
3545 s = dc_lex_string(l);
3546 break;
3547 }
3548
3549 default:
3550 {
3551 l->t.t = BC_LEX_INVALID;
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01003552 s = bc_error("bad character '%c'", c);
Gavin Howard01055ba2018-11-03 11:00:21 -06003553 break;
3554 }
3555 }
3556
3557 return s;
3558}
3559#endif // ENABLE_DC
3560
3561static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3562{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003563 bc_program_addFunc(name, idx);
3564 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003565}
3566
3567static void bc_parse_pushName(BcParse *p, char *name)
3568{
3569 size_t i = 0, len = strlen(name);
3570
3571 for (; i < len; ++i) bc_parse_push(p, name[i]);
3572 bc_parse_push(p, BC_PARSE_STREND);
3573
3574 free(name);
3575}
3576
3577static void bc_parse_pushIndex(BcParse *p, size_t idx)
3578{
3579 unsigned char amt, i, nums[sizeof(size_t)];
3580
3581 for (amt = 0; idx; ++amt) {
3582 nums[amt] = (char) idx;
3583 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3584 }
3585
3586 bc_parse_push(p, amt);
3587 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3588}
3589
3590static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3591{
3592 char *num = xstrdup(p->l.t.v.v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003593 size_t idx = G.prog.consts.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06003594
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003595 bc_vec_push(&G.prog.consts, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06003596
3597 bc_parse_push(p, BC_INST_NUM);
3598 bc_parse_pushIndex(p, idx);
3599
3600 ++(*nexs);
3601 (*prev) = BC_INST_NUM;
3602}
3603
3604static BcStatus bc_parse_text(BcParse *p, const char *text)
3605{
3606 BcStatus s;
3607
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003608 p->func = bc_vec_item(&G.prog.fns, p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003609
3610 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3611 p->l.t.t = BC_LEX_INVALID;
3612 s = p->parse(p);
3613 if (s) return s;
3614 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3615 }
3616
3617 return bc_lex_text(&p->l, text);
3618}
3619
3620static BcStatus bc_parse_reset(BcParse *p, BcStatus s)
3621{
3622 if (p->fidx != BC_PROG_MAIN) {
3623
3624 p->func->nparams = 0;
3625 bc_vec_npop(&p->func->code, p->func->code.len);
3626 bc_vec_npop(&p->func->autos, p->func->autos.len);
3627 bc_vec_npop(&p->func->labels, p->func->labels.len);
3628
3629 bc_parse_updateFunc(p, BC_PROG_MAIN);
3630 }
3631
3632 p->l.i = p->l.len;
3633 p->l.t.t = BC_LEX_EOF;
3634 p->auto_part = (p->nbraces = 0);
3635
3636 bc_vec_npop(&p->flags, p->flags.len - 1);
3637 bc_vec_npop(&p->exits, p->exits.len);
3638 bc_vec_npop(&p->conds, p->conds.len);
3639 bc_vec_npop(&p->ops, p->ops.len);
3640
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003641 return bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003642}
3643
3644static void bc_parse_free(BcParse *p)
3645{
3646 bc_vec_free(&p->flags);
3647 bc_vec_free(&p->exits);
3648 bc_vec_free(&p->conds);
3649 bc_vec_free(&p->ops);
3650 bc_lex_free(&p->l);
3651}
3652
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003653static void bc_parse_create(BcParse *p, size_t func,
Gavin Howard01055ba2018-11-03 11:00:21 -06003654 BcParseParse parse, BcLexNext next)
3655{
3656 memset(p, 0, sizeof(BcParse));
3657
3658 bc_lex_init(&p->l, next);
3659 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3660 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3661 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3662 bc_vec_pushByte(&p->flags, 0);
3663 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3664
3665 p->parse = parse;
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01003666 // p->auto_part = p->nbraces = 0; - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06003667 bc_parse_updateFunc(p, func);
3668}
3669
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003670#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06003671static BcStatus bc_parse_else(BcParse *p);
3672static BcStatus bc_parse_stmt(BcParse *p);
3673
3674static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3675 size_t *nexprs, bool next)
3676{
3677 BcStatus s = BC_STATUS_SUCCESS;
3678 BcLexType t;
3679 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3680 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3681
3682 while (p->ops.len > start) {
3683
3684 t = BC_PARSE_TOP_OP(p);
3685 if (t == BC_LEX_LPAREN) break;
3686
3687 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3688 if (l >= r && (l != r || !left)) break;
3689
3690 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3691 bc_vec_pop(&p->ops);
3692 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3693 }
3694
3695 bc_vec_push(&p->ops, &type);
3696 if (next) s = bc_lex_next(&p->l);
3697
3698 return s;
3699}
3700
3701static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3702{
3703 BcLexType top;
3704
3705 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3706 top = BC_PARSE_TOP_OP(p);
3707
3708 while (top != BC_LEX_LPAREN) {
3709
3710 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3711
3712 bc_vec_pop(&p->ops);
3713 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3714
3715 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3716 top = BC_PARSE_TOP_OP(p);
3717 }
3718
3719 bc_vec_pop(&p->ops);
3720
3721 return bc_lex_next(&p->l);
3722}
3723
3724static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3725{
3726 BcStatus s;
3727 bool comma = false;
3728 size_t nparams;
3729
3730 s = bc_lex_next(&p->l);
3731 if (s) return s;
3732
3733 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3734
3735 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3736 s = bc_parse_expr(p, flags, bc_parse_next_param);
3737 if (s) return s;
3738
3739 comma = p->l.t.t == BC_LEX_COMMA;
3740 if (comma) {
3741 s = bc_lex_next(&p->l);
3742 if (s) return s;
3743 }
3744 }
3745
3746 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3747 bc_parse_push(p, BC_INST_CALL);
3748 bc_parse_pushIndex(p, nparams);
3749
3750 return BC_STATUS_SUCCESS;
3751}
3752
3753static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3754{
3755 BcStatus s;
3756 BcId entry, *entry_ptr;
3757 size_t idx;
3758
3759 entry.name = name;
3760
3761 s = bc_parse_params(p, flags);
3762 if (s) goto err;
3763
3764 if (p->l.t.t != BC_LEX_RPAREN) {
3765 s = BC_STATUS_PARSE_BAD_TOKEN;
3766 goto err;
3767 }
3768
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003769 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003770
3771 if (idx == BC_VEC_INVALID_IDX) {
3772 name = xstrdup(entry.name);
3773 bc_parse_addFunc(p, name, &idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003774 idx = bc_map_index(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003775 free(entry.name);
3776 }
3777 else
3778 free(name);
3779
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003780 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003781 bc_parse_pushIndex(p, entry_ptr->idx);
3782
3783 return bc_lex_next(&p->l);
3784
3785err:
3786 free(name);
3787 return s;
3788}
3789
3790static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3791{
3792 BcStatus s;
3793 char *name;
3794
3795 name = xstrdup(p->l.t.v.v);
3796 s = bc_lex_next(&p->l);
3797 if (s) goto err;
3798
3799 if (p->l.t.t == BC_LEX_LBRACKET) {
3800
3801 s = bc_lex_next(&p->l);
3802 if (s) goto err;
3803
3804 if (p->l.t.t == BC_LEX_RBRACKET) {
3805
3806 if (!(flags & BC_PARSE_ARRAY)) {
3807 s = BC_STATUS_PARSE_BAD_EXP;
3808 goto err;
3809 }
3810
3811 *type = BC_INST_ARRAY;
3812 }
3813 else {
3814
3815 *type = BC_INST_ARRAY_ELEM;
3816
3817 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3818 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3819 if (s) goto err;
3820 }
3821
3822 s = bc_lex_next(&p->l);
3823 if (s) goto err;
3824 bc_parse_push(p, *type);
3825 bc_parse_pushName(p, name);
3826 }
3827 else if (p->l.t.t == BC_LEX_LPAREN) {
3828
3829 if (flags & BC_PARSE_NOCALL) {
3830 s = BC_STATUS_PARSE_BAD_TOKEN;
3831 goto err;
3832 }
3833
3834 *type = BC_INST_CALL;
3835 s = bc_parse_call(p, name, flags);
3836 }
3837 else {
3838 *type = BC_INST_VAR;
3839 bc_parse_push(p, BC_INST_VAR);
3840 bc_parse_pushName(p, name);
3841 }
3842
3843 return s;
3844
3845err:
3846 free(name);
3847 return s;
3848}
3849
3850static BcStatus bc_parse_read(BcParse *p)
3851{
3852 BcStatus s;
3853
3854 s = bc_lex_next(&p->l);
3855 if (s) return s;
3856 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3857
3858 s = bc_lex_next(&p->l);
3859 if (s) return s;
3860 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3861
3862 bc_parse_push(p, BC_INST_READ);
3863
3864 return bc_lex_next(&p->l);
3865}
3866
3867static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3868 BcInst *prev)
3869{
3870 BcStatus s;
3871
3872 s = bc_lex_next(&p->l);
3873 if (s) return s;
3874 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3875
3876 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3877
3878 s = bc_lex_next(&p->l);
3879 if (s) return s;
3880
3881 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3882 if (s) return s;
3883
3884 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3885
3886 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3887 bc_parse_push(p, *prev);
3888
3889 return bc_lex_next(&p->l);
3890}
3891
3892static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3893{
3894 BcStatus s;
3895
3896 s = bc_lex_next(&p->l);
3897 if (s) return s;
3898
3899 if (p->l.t.t != BC_LEX_LPAREN) {
3900 *type = BC_INST_SCALE;
3901 bc_parse_push(p, BC_INST_SCALE);
3902 return BC_STATUS_SUCCESS;
3903 }
3904
3905 *type = BC_INST_SCALE_FUNC;
3906 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3907
3908 s = bc_lex_next(&p->l);
3909 if (s) return s;
3910
3911 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3912 if (s) return s;
3913 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3914 bc_parse_push(p, BC_INST_SCALE_FUNC);
3915
3916 return bc_lex_next(&p->l);
3917}
3918
3919static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3920 size_t *nexprs, uint8_t flags)
3921{
3922 BcStatus s;
3923 BcLexType type;
3924 char inst;
3925 BcInst etype = *prev;
3926
3927 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3928 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3929 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3930 {
3931 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3932 bc_parse_push(p, inst);
3933 s = bc_lex_next(&p->l);
3934 }
3935 else {
3936
3937 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3938 *paren_expr = true;
3939
3940 s = bc_lex_next(&p->l);
3941 if (s) return s;
3942 type = p->l.t.t;
3943
3944 // Because we parse the next part of the expression
3945 // right here, we need to increment this.
3946 *nexprs = *nexprs + 1;
3947
3948 switch (type) {
3949
3950 case BC_LEX_NAME:
3951 {
3952 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3953 break;
3954 }
3955
3956 case BC_LEX_KEY_IBASE:
3957 case BC_LEX_KEY_LAST:
3958 case BC_LEX_KEY_OBASE:
3959 {
3960 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3961 s = bc_lex_next(&p->l);
3962 break;
3963 }
3964
3965 case BC_LEX_KEY_SCALE:
3966 {
3967 s = bc_lex_next(&p->l);
3968 if (s) return s;
3969 if (p->l.t.t == BC_LEX_LPAREN)
3970 s = BC_STATUS_PARSE_BAD_TOKEN;
3971 else
3972 bc_parse_push(p, BC_INST_SCALE);
3973 break;
3974 }
3975
3976 default:
3977 {
3978 s = BC_STATUS_PARSE_BAD_TOKEN;
3979 break;
3980 }
3981 }
3982
3983 if (!s) bc_parse_push(p, inst);
3984 }
3985
3986 return s;
3987}
3988
3989static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3990 bool rparen, size_t *nexprs)
3991{
3992 BcStatus s;
3993 BcLexType type;
3994 BcInst etype = *prev;
3995
3996 s = bc_lex_next(&p->l);
3997 if (s) return s;
3998
3999 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4000 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4001 BC_LEX_OP_MINUS :
4002 BC_LEX_NEG;
4003 *prev = BC_PARSE_TOKEN_INST(type);
4004
4005 // We can just push onto the op stack because this is the largest
4006 // precedence operator that gets pushed. Inc/dec does not.
4007 if (type != BC_LEX_OP_MINUS)
4008 bc_vec_push(&p->ops, &type);
4009 else
4010 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4011
4012 return s;
4013}
4014
4015static BcStatus bc_parse_string(BcParse *p, char inst)
4016{
4017 char *str = xstrdup(p->l.t.v.v);
4018
4019 bc_parse_push(p, BC_INST_STR);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004020 bc_parse_pushIndex(p, G.prog.strs.len);
4021 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06004022 bc_parse_push(p, inst);
4023
4024 return bc_lex_next(&p->l);
4025}
4026
4027static BcStatus bc_parse_print(BcParse *p)
4028{
4029 BcStatus s;
4030 BcLexType type;
4031 bool comma = false;
4032
4033 s = bc_lex_next(&p->l);
4034 if (s) return s;
4035
4036 type = p->l.t.t;
4037
4038 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4039 return BC_STATUS_PARSE_BAD_PRINT;
4040
4041 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4042
4043 if (type == BC_LEX_STR)
4044 s = bc_parse_string(p, BC_INST_PRINT_POP);
4045 else {
4046 s = bc_parse_expr(p, 0, bc_parse_next_print);
4047 if (s) return s;
4048 bc_parse_push(p, BC_INST_PRINT_POP);
4049 }
4050
4051 if (s) return s;
4052
4053 comma = p->l.t.t == BC_LEX_COMMA;
4054 if (comma) s = bc_lex_next(&p->l);
4055 type = p->l.t.t;
4056 }
4057
4058 if (s) return s;
4059 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4060
4061 return bc_lex_next(&p->l);
4062}
4063
4064static BcStatus bc_parse_return(BcParse *p)
4065{
4066 BcStatus s;
4067 BcLexType t;
4068 bool paren;
4069
4070 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4071
4072 s = bc_lex_next(&p->l);
4073 if (s) return s;
4074
4075 t = p->l.t.t;
4076 paren = t == BC_LEX_LPAREN;
4077
4078 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4079 bc_parse_push(p, BC_INST_RET0);
4080 else {
4081
4082 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4083 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4084 return s;
4085 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4086 bc_parse_push(p, BC_INST_RET0);
4087 s = bc_lex_next(&p->l);
4088 if (s) return s;
4089 }
4090
4091 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4092 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4093 if (s) return s;
4094 }
4095
4096 bc_parse_push(p, BC_INST_RET);
4097 }
4098
4099 return s;
4100}
4101
4102static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4103{
4104 BcStatus s = BC_STATUS_SUCCESS;
4105
4106 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4107 return BC_STATUS_PARSE_BAD_TOKEN;
4108
4109 if (brace) {
4110
4111 if (p->l.t.t == BC_LEX_RBRACE) {
4112 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4113 --p->nbraces;
4114 s = bc_lex_next(&p->l);
4115 if (s) return s;
4116 }
4117 else
4118 return BC_STATUS_PARSE_BAD_TOKEN;
4119 }
4120
4121 if (BC_PARSE_IF(p)) {
4122
4123 uint8_t *flag_ptr;
4124
4125 while (p->l.t.t == BC_LEX_NLINE) {
4126 s = bc_lex_next(&p->l);
4127 if (s) return s;
4128 }
4129
4130 bc_vec_pop(&p->flags);
4131
4132 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4133 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4134
4135 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4136 }
4137 else if (BC_PARSE_ELSE(p)) {
4138
4139 BcInstPtr *ip;
4140 size_t *label;
4141
4142 bc_vec_pop(&p->flags);
4143
4144 ip = bc_vec_top(&p->exits);
4145 label = bc_vec_item(&p->func->labels, ip->idx);
4146 *label = p->func->code.len;
4147
4148 bc_vec_pop(&p->exits);
4149 }
4150 else if (BC_PARSE_FUNC_INNER(p)) {
4151 bc_parse_push(p, BC_INST_RET0);
4152 bc_parse_updateFunc(p, BC_PROG_MAIN);
4153 bc_vec_pop(&p->flags);
4154 }
4155 else {
4156
4157 BcInstPtr *ip = bc_vec_top(&p->exits);
4158 size_t *label = bc_vec_top(&p->conds);
4159
4160 bc_parse_push(p, BC_INST_JUMP);
4161 bc_parse_pushIndex(p, *label);
4162
4163 label = bc_vec_item(&p->func->labels, ip->idx);
4164 *label = p->func->code.len;
4165
4166 bc_vec_pop(&p->flags);
4167 bc_vec_pop(&p->exits);
4168 bc_vec_pop(&p->conds);
4169 }
4170
4171 return s;
4172}
4173
4174static void bc_parse_startBody(BcParse *p, uint8_t flags)
4175{
4176 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4177 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4178 flags |= BC_PARSE_FLAG_BODY;
4179 bc_vec_push(&p->flags, &flags);
4180}
4181
4182static void bc_parse_noElse(BcParse *p)
4183{
4184 BcInstPtr *ip;
4185 size_t *label;
4186 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4187
4188 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4189
4190 ip = bc_vec_top(&p->exits);
4191 label = bc_vec_item(&p->func->labels, ip->idx);
4192 *label = p->func->code.len;
4193
4194 bc_vec_pop(&p->exits);
4195}
4196
4197static BcStatus bc_parse_if(BcParse *p)
4198{
4199 BcStatus s;
4200 BcInstPtr ip;
4201
4202 s = bc_lex_next(&p->l);
4203 if (s) return s;
4204 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4205
4206 s = bc_lex_next(&p->l);
4207 if (s) return s;
4208 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4209 if (s) return s;
4210 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4211
4212 s = bc_lex_next(&p->l);
4213 if (s) return s;
4214 bc_parse_push(p, BC_INST_JUMP_ZERO);
4215
4216 ip.idx = p->func->labels.len;
4217 ip.func = ip.len = 0;
4218
4219 bc_parse_pushIndex(p, ip.idx);
4220 bc_vec_push(&p->exits, &ip);
4221 bc_vec_push(&p->func->labels, &ip.idx);
4222 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4223
4224 return BC_STATUS_SUCCESS;
4225}
4226
4227static BcStatus bc_parse_else(BcParse *p)
4228{
4229 BcInstPtr ip;
4230
4231 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4232
4233 ip.idx = p->func->labels.len;
4234 ip.func = ip.len = 0;
4235
4236 bc_parse_push(p, BC_INST_JUMP);
4237 bc_parse_pushIndex(p, ip.idx);
4238
4239 bc_parse_noElse(p);
4240
4241 bc_vec_push(&p->exits, &ip);
4242 bc_vec_push(&p->func->labels, &ip.idx);
4243 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4244
4245 return bc_lex_next(&p->l);
4246}
4247
4248static BcStatus bc_parse_while(BcParse *p)
4249{
4250 BcStatus s;
4251 BcInstPtr ip;
4252
4253 s = bc_lex_next(&p->l);
4254 if (s) return s;
4255 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4256 s = bc_lex_next(&p->l);
4257 if (s) return s;
4258
4259 ip.idx = p->func->labels.len;
4260
4261 bc_vec_push(&p->func->labels, &p->func->code.len);
4262 bc_vec_push(&p->conds, &ip.idx);
4263
4264 ip.idx = p->func->labels.len;
4265 ip.func = 1;
4266 ip.len = 0;
4267
4268 bc_vec_push(&p->exits, &ip);
4269 bc_vec_push(&p->func->labels, &ip.idx);
4270
4271 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4272 if (s) return s;
4273 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4274 s = bc_lex_next(&p->l);
4275 if (s) return s;
4276
4277 bc_parse_push(p, BC_INST_JUMP_ZERO);
4278 bc_parse_pushIndex(p, ip.idx);
4279 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4280
4281 return BC_STATUS_SUCCESS;
4282}
4283
4284static BcStatus bc_parse_for(BcParse *p)
4285{
4286 BcStatus s;
4287 BcInstPtr ip;
4288 size_t cond_idx, exit_idx, body_idx, update_idx;
4289
4290 s = bc_lex_next(&p->l);
4291 if (s) return s;
4292 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4293 s = bc_lex_next(&p->l);
4294 if (s) return s;
4295
4296 if (p->l.t.t != BC_LEX_SCOLON)
4297 s = bc_parse_expr(p, 0, bc_parse_next_for);
4298 else
4299 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4300
4301 if (s) return s;
4302 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4303 s = bc_lex_next(&p->l);
4304 if (s) return s;
4305
4306 cond_idx = p->func->labels.len;
4307 update_idx = cond_idx + 1;
4308 body_idx = update_idx + 1;
4309 exit_idx = body_idx + 1;
4310
4311 bc_vec_push(&p->func->labels, &p->func->code.len);
4312
4313 if (p->l.t.t != BC_LEX_SCOLON)
4314 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4315 else
4316 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4317
4318 if (s) return s;
4319 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4320
4321 s = bc_lex_next(&p->l);
4322 if (s) return s;
4323
4324 bc_parse_push(p, BC_INST_JUMP_ZERO);
4325 bc_parse_pushIndex(p, exit_idx);
4326 bc_parse_push(p, BC_INST_JUMP);
4327 bc_parse_pushIndex(p, body_idx);
4328
4329 ip.idx = p->func->labels.len;
4330
4331 bc_vec_push(&p->conds, &update_idx);
4332 bc_vec_push(&p->func->labels, &p->func->code.len);
4333
4334 if (p->l.t.t != BC_LEX_RPAREN)
4335 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4336 else
4337 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4338
4339 if (s) return s;
4340
4341 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4342 bc_parse_push(p, BC_INST_JUMP);
4343 bc_parse_pushIndex(p, cond_idx);
4344 bc_vec_push(&p->func->labels, &p->func->code.len);
4345
4346 ip.idx = exit_idx;
4347 ip.func = 1;
4348 ip.len = 0;
4349
4350 bc_vec_push(&p->exits, &ip);
4351 bc_vec_push(&p->func->labels, &ip.idx);
4352 bc_lex_next(&p->l);
4353 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4354
4355 return BC_STATUS_SUCCESS;
4356}
4357
4358static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4359{
4360 BcStatus s;
4361 size_t i;
4362 BcInstPtr *ip;
4363
4364 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4365
4366 if (type == BC_LEX_KEY_BREAK) {
4367
4368 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4369
4370 i = p->exits.len - 1;
4371 ip = bc_vec_item(&p->exits, i);
4372
4373 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4374 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4375
4376 i = ip->idx;
4377 }
4378 else
4379 i = *((size_t *) bc_vec_top(&p->conds));
4380
4381 bc_parse_push(p, BC_INST_JUMP);
4382 bc_parse_pushIndex(p, i);
4383
4384 s = bc_lex_next(&p->l);
4385 if (s) return s;
4386
4387 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4388 return BC_STATUS_PARSE_BAD_TOKEN;
4389
4390 return bc_lex_next(&p->l);
4391}
4392
4393static BcStatus bc_parse_func(BcParse *p)
4394{
4395 BcStatus s;
4396 bool var, comma = false;
4397 uint8_t flags;
4398 char *name;
4399
4400 s = bc_lex_next(&p->l);
4401 if (s) return s;
4402 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4403
4404 name = xstrdup(p->l.t.v.v);
4405 bc_parse_addFunc(p, name, &p->fidx);
4406
4407 s = bc_lex_next(&p->l);
4408 if (s) return s;
4409 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4410 s = bc_lex_next(&p->l);
4411 if (s) return s;
4412
4413 while (p->l.t.t != BC_LEX_RPAREN) {
4414
4415 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4416
4417 ++p->func->nparams;
4418
4419 name = xstrdup(p->l.t.v.v);
4420 s = bc_lex_next(&p->l);
4421 if (s) goto err;
4422
4423 var = p->l.t.t != BC_LEX_LBRACKET;
4424
4425 if (!var) {
4426
4427 s = bc_lex_next(&p->l);
4428 if (s) goto err;
4429
4430 if (p->l.t.t != BC_LEX_RBRACKET) {
4431 s = BC_STATUS_PARSE_BAD_FUNC;
4432 goto err;
4433 }
4434
4435 s = bc_lex_next(&p->l);
4436 if (s) goto err;
4437 }
4438
4439 comma = p->l.t.t == BC_LEX_COMMA;
4440 if (comma) {
4441 s = bc_lex_next(&p->l);
4442 if (s) goto err;
4443 }
4444
4445 s = bc_func_insert(p->func, name, var);
4446 if (s) goto err;
4447 }
4448
4449 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4450
4451 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4452 bc_parse_startBody(p, flags);
4453
4454 s = bc_lex_next(&p->l);
4455 if (s) return s;
4456
4457 if (p->l.t.t != BC_LEX_LBRACE)
4458 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4459
4460 return s;
4461
4462err:
4463 free(name);
4464 return s;
4465}
4466
4467static BcStatus bc_parse_auto(BcParse *p)
4468{
4469 BcStatus s;
4470 bool comma, var, one;
4471 char *name;
4472
4473 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4474 s = bc_lex_next(&p->l);
4475 if (s) return s;
4476
4477 p->auto_part = comma = false;
4478 one = p->l.t.t == BC_LEX_NAME;
4479
4480 while (p->l.t.t == BC_LEX_NAME) {
4481
4482 name = xstrdup(p->l.t.v.v);
4483 s = bc_lex_next(&p->l);
4484 if (s) goto err;
4485
4486 var = p->l.t.t != BC_LEX_LBRACKET;
4487 if (!var) {
4488
4489 s = bc_lex_next(&p->l);
4490 if (s) goto err;
4491
4492 if (p->l.t.t != BC_LEX_RBRACKET) {
4493 s = BC_STATUS_PARSE_BAD_FUNC;
4494 goto err;
4495 }
4496
4497 s = bc_lex_next(&p->l);
4498 if (s) goto err;
4499 }
4500
4501 comma = p->l.t.t == BC_LEX_COMMA;
4502 if (comma) {
4503 s = bc_lex_next(&p->l);
4504 if (s) goto err;
4505 }
4506
4507 s = bc_func_insert(p->func, name, var);
4508 if (s) goto err;
4509 }
4510
4511 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4512 if (!one) return BC_STATUS_PARSE_NO_AUTO;
4513
4514 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4515 return BC_STATUS_PARSE_BAD_TOKEN;
4516
4517 return bc_lex_next(&p->l);
4518
4519err:
4520 free(name);
4521 return s;
4522}
4523
4524static BcStatus bc_parse_body(BcParse *p, bool brace)
4525{
4526 BcStatus s = BC_STATUS_SUCCESS;
4527 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4528
4529 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4530
4531 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4532
4533 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4534 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4535
4536 if (!p->auto_part) {
4537 s = bc_parse_auto(p);
4538 if (s) return s;
4539 }
4540
4541 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4542 }
4543 else {
4544 s = bc_parse_stmt(p);
4545 if (!s && !brace) s = bc_parse_endBody(p, false);
4546 }
4547
4548 return s;
4549}
4550
4551static BcStatus bc_parse_stmt(BcParse *p)
4552{
4553 BcStatus s = BC_STATUS_SUCCESS;
4554
4555 switch (p->l.t.t) {
4556
4557 case BC_LEX_NLINE:
4558 {
4559 return bc_lex_next(&p->l);
4560 }
4561
4562 case BC_LEX_KEY_ELSE:
4563 {
4564 p->auto_part = false;
4565 break;
4566 }
4567
4568 case BC_LEX_LBRACE:
4569 {
4570 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4571
4572 ++p->nbraces;
4573 s = bc_lex_next(&p->l);
4574 if (s) return s;
4575
4576 return bc_parse_body(p, true);
4577 }
4578
4579 case BC_LEX_KEY_AUTO:
4580 {
4581 return bc_parse_auto(p);
4582 }
4583
4584 default:
4585 {
4586 p->auto_part = false;
4587
4588 if (BC_PARSE_IF_END(p)) {
4589 bc_parse_noElse(p);
4590 return BC_STATUS_SUCCESS;
4591 }
4592 else if (BC_PARSE_BODY(p))
4593 return bc_parse_body(p, false);
4594
4595 break;
4596 }
4597 }
4598
4599 switch (p->l.t.t) {
4600
4601 case BC_LEX_OP_INC:
4602 case BC_LEX_OP_DEC:
4603 case BC_LEX_OP_MINUS:
4604 case BC_LEX_OP_BOOL_NOT:
4605 case BC_LEX_LPAREN:
4606 case BC_LEX_NAME:
4607 case BC_LEX_NUMBER:
4608 case BC_LEX_KEY_IBASE:
4609 case BC_LEX_KEY_LAST:
4610 case BC_LEX_KEY_LENGTH:
4611 case BC_LEX_KEY_OBASE:
4612 case BC_LEX_KEY_READ:
4613 case BC_LEX_KEY_SCALE:
4614 case BC_LEX_KEY_SQRT:
4615 {
4616 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4617 break;
4618 }
4619
4620 case BC_LEX_KEY_ELSE:
4621 {
4622 s = bc_parse_else(p);
4623 break;
4624 }
4625
4626 case BC_LEX_SCOLON:
4627 {
4628 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4629 break;
4630 }
4631
4632 case BC_LEX_RBRACE:
4633 {
4634 s = bc_parse_endBody(p, true);
4635 break;
4636 }
4637
4638 case BC_LEX_STR:
4639 {
4640 s = bc_parse_string(p, BC_INST_PRINT_STR);
4641 break;
4642 }
4643
4644 case BC_LEX_KEY_BREAK:
4645 case BC_LEX_KEY_CONTINUE:
4646 {
4647 s = bc_parse_loopExit(p, p->l.t.t);
4648 break;
4649 }
4650
4651 case BC_LEX_KEY_FOR:
4652 {
4653 s = bc_parse_for(p);
4654 break;
4655 }
4656
4657 case BC_LEX_KEY_HALT:
4658 {
4659 bc_parse_push(p, BC_INST_HALT);
4660 s = bc_lex_next(&p->l);
4661 break;
4662 }
4663
4664 case BC_LEX_KEY_IF:
4665 {
4666 s = bc_parse_if(p);
4667 break;
4668 }
4669
4670 case BC_LEX_KEY_LIMITS:
4671 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004672 // "limits" is a compile-time command,
4673 // the output is produced at _parse time_.
Gavin Howard01055ba2018-11-03 11:00:21 -06004674 s = bc_lex_next(&p->l);
4675 if (s) return s;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004676 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4677 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4678 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4679 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4680 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4681 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4682 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4683 printf("Number of vars = %lu\n", BC_MAX_VARS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004684 break;
4685 }
4686
4687 case BC_LEX_KEY_PRINT:
4688 {
4689 s = bc_parse_print(p);
4690 break;
4691 }
4692
4693 case BC_LEX_KEY_QUIT:
4694 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004695 // "quit" is a compile-time command. For example,
4696 // "if (0 == 1) quit" terminates when parsing the statement,
4697 // not when it is executed
4698 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06004699 }
4700
4701 case BC_LEX_KEY_RETURN:
4702 {
4703 s = bc_parse_return(p);
4704 break;
4705 }
4706
4707 case BC_LEX_KEY_WHILE:
4708 {
4709 s = bc_parse_while(p);
4710 break;
4711 }
4712
4713 default:
4714 {
4715 s = BC_STATUS_PARSE_BAD_TOKEN;
4716 break;
4717 }
4718 }
4719
4720 return s;
4721}
4722
4723static BcStatus bc_parse_parse(BcParse *p)
4724{
4725 BcStatus s;
4726
4727 if (p->l.t.t == BC_LEX_EOF)
4728 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4729 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4730 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4731 s = bc_parse_func(p);
4732 }
4733 else
4734 s = bc_parse_stmt(p);
4735
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01004736 if (s || G_interrupt)
Gavin Howard01055ba2018-11-03 11:00:21 -06004737 s = bc_parse_reset(p, s);
4738
4739 return s;
4740}
4741
4742static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4743{
4744 BcStatus s = BC_STATUS_SUCCESS;
4745 BcInst prev = BC_INST_PRINT;
4746 BcLexType top, t = p->l.t.t;
4747 size_t nexprs = 0, ops_bgn = p->ops.len;
4748 uint32_t i, nparens, nrelops;
4749 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4750
4751 paren_first = p->l.t.t == BC_LEX_LPAREN;
4752 nparens = nrelops = 0;
4753 paren_expr = rprn = done = get_token = assign = false;
4754 bin_last = true;
4755
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004756 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
Gavin Howard01055ba2018-11-03 11:00:21 -06004757 switch (t) {
4758
4759 case BC_LEX_OP_INC:
4760 case BC_LEX_OP_DEC:
4761 {
4762 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4763 rprn = get_token = bin_last = false;
4764 break;
4765 }
4766
4767 case BC_LEX_OP_MINUS:
4768 {
4769 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4770 rprn = get_token = false;
4771 bin_last = prev == BC_INST_MINUS;
4772 break;
4773 }
4774
4775 case BC_LEX_OP_ASSIGN_POWER:
4776 case BC_LEX_OP_ASSIGN_MULTIPLY:
4777 case BC_LEX_OP_ASSIGN_DIVIDE:
4778 case BC_LEX_OP_ASSIGN_MODULUS:
4779 case BC_LEX_OP_ASSIGN_PLUS:
4780 case BC_LEX_OP_ASSIGN_MINUS:
4781 case BC_LEX_OP_ASSIGN:
4782 {
4783 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4784 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4785 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4786 {
4787 s = BC_STATUS_PARSE_BAD_ASSIGN;
4788 break;
4789 }
4790 }
4791 // Fallthrough.
4792 case BC_LEX_OP_POWER:
4793 case BC_LEX_OP_MULTIPLY:
4794 case BC_LEX_OP_DIVIDE:
4795 case BC_LEX_OP_MODULUS:
4796 case BC_LEX_OP_PLUS:
4797 case BC_LEX_OP_REL_EQ:
4798 case BC_LEX_OP_REL_LE:
4799 case BC_LEX_OP_REL_GE:
4800 case BC_LEX_OP_REL_NE:
4801 case BC_LEX_OP_REL_LT:
4802 case BC_LEX_OP_REL_GT:
4803 case BC_LEX_OP_BOOL_NOT:
4804 case BC_LEX_OP_BOOL_OR:
4805 case BC_LEX_OP_BOOL_AND:
4806 {
4807 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4808 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4809 {
4810 return BC_STATUS_PARSE_BAD_EXP;
4811 }
4812
4813 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4814 prev = BC_PARSE_TOKEN_INST(t);
4815 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4816 rprn = get_token = false;
4817 bin_last = t != BC_LEX_OP_BOOL_NOT;
4818
4819 break;
4820 }
4821
4822 case BC_LEX_LPAREN:
4823 {
4824 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4825
4826 ++nparens;
4827 paren_expr = rprn = bin_last = false;
4828 get_token = true;
4829 bc_vec_push(&p->ops, &t);
4830
4831 break;
4832 }
4833
4834 case BC_LEX_RPAREN:
4835 {
4836 if (bin_last || prev == BC_INST_BOOL_NOT)
4837 return BC_STATUS_PARSE_BAD_EXP;
4838
4839 if (nparens == 0) {
4840 s = BC_STATUS_SUCCESS;
4841 done = true;
4842 get_token = false;
4843 break;
4844 }
4845 else if (!paren_expr)
4846 return BC_STATUS_PARSE_EMPTY_EXP;
4847
4848 --nparens;
4849 paren_expr = rprn = true;
4850 get_token = bin_last = false;
4851
4852 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4853
4854 break;
4855 }
4856
4857 case BC_LEX_NAME:
4858 {
4859 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4860
4861 paren_expr = true;
4862 rprn = get_token = bin_last = false;
4863 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4864 ++nexprs;
4865
4866 break;
4867 }
4868
4869 case BC_LEX_NUMBER:
4870 {
4871 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4872
4873 bc_parse_number(p, &prev, &nexprs);
4874 paren_expr = get_token = true;
4875 rprn = bin_last = false;
4876
4877 break;
4878 }
4879
4880 case BC_LEX_KEY_IBASE:
4881 case BC_LEX_KEY_LAST:
4882 case BC_LEX_KEY_OBASE:
4883 {
4884 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4885
4886 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4887 bc_parse_push(p, (char) prev);
4888
4889 paren_expr = get_token = true;
4890 rprn = bin_last = false;
4891 ++nexprs;
4892
4893 break;
4894 }
4895
4896 case BC_LEX_KEY_LENGTH:
4897 case BC_LEX_KEY_SQRT:
4898 {
4899 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4900
4901 s = bc_parse_builtin(p, t, flags, &prev);
4902 paren_expr = true;
4903 rprn = get_token = bin_last = false;
4904 ++nexprs;
4905
4906 break;
4907 }
4908
4909 case BC_LEX_KEY_READ:
4910 {
4911 if (BC_PARSE_LEAF(prev, rprn))
4912 return BC_STATUS_PARSE_BAD_EXP;
4913 else if (flags & BC_PARSE_NOREAD)
4914 s = BC_STATUS_EXEC_REC_READ;
4915 else
4916 s = bc_parse_read(p);
4917
4918 paren_expr = true;
4919 rprn = get_token = bin_last = false;
4920 ++nexprs;
4921 prev = BC_INST_READ;
4922
4923 break;
4924 }
4925
4926 case BC_LEX_KEY_SCALE:
4927 {
4928 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4929
4930 s = bc_parse_scale(p, &prev, flags);
4931 paren_expr = true;
4932 rprn = get_token = bin_last = false;
4933 ++nexprs;
4934 prev = BC_INST_SCALE;
4935
4936 break;
4937 }
4938
4939 default:
4940 {
4941 s = BC_STATUS_PARSE_BAD_TOKEN;
4942 break;
4943 }
4944 }
4945
4946 if (!s && get_token) s = bc_lex_next(&p->l);
4947 }
4948
4949 if (s) return s;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01004950 if (G_interrupt) return BC_STATUS_EXEC_SIGNAL;
Gavin Howard01055ba2018-11-03 11:00:21 -06004951
4952 while (p->ops.len > ops_bgn) {
4953
4954 top = BC_PARSE_TOP_OP(p);
4955 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4956
4957 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4958 return BC_STATUS_PARSE_BAD_EXP;
4959
4960 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4961
4962 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4963 bc_vec_pop(&p->ops);
4964 }
4965
4966 s = BC_STATUS_PARSE_BAD_EXP;
4967 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4968
4969 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4970 if (s) return s;
4971
4972 if (!(flags & BC_PARSE_REL) && nrelops) {
4973 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4974 if (s) return s;
4975 }
4976 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4977 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4978 if (s) return s;
4979 }
4980
4981 if (flags & BC_PARSE_PRINT) {
4982 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4983 bc_parse_push(p, BC_INST_POP);
4984 }
4985
4986 return s;
4987}
4988
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004989static void bc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06004990{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01004991 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06004992}
4993
4994static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4995{
4996 return bc_parse_expr(p, flags, bc_parse_next_read);
4997}
4998#endif // ENABLE_BC
4999
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005000#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005001static BcStatus dc_parse_register(BcParse *p)
5002{
5003 BcStatus s;
5004 char *name;
5005
5006 s = bc_lex_next(&p->l);
5007 if (s) return s;
5008 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5009
5010 name = xstrdup(p->l.t.v.v);
5011 bc_parse_pushName(p, name);
5012
5013 return s;
5014}
5015
5016static BcStatus dc_parse_string(BcParse *p)
5017{
5018 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005019 size_t idx, len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005020
5021 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5022 name = xstrdup(b);
5023
5024 str = xstrdup(p->l.t.v.v);
5025 bc_parse_push(p, BC_INST_STR);
5026 bc_parse_pushIndex(p, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005027 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005028 bc_parse_addFunc(p, name, &idx);
5029
5030 return bc_lex_next(&p->l);
5031}
5032
5033static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5034{
5035 BcStatus s;
5036
5037 bc_parse_push(p, inst);
5038 if (name) {
5039 s = dc_parse_register(p);
5040 if (s) return s;
5041 }
5042
5043 if (store) {
5044 bc_parse_push(p, BC_INST_SWAP);
5045 bc_parse_push(p, BC_INST_ASSIGN);
5046 bc_parse_push(p, BC_INST_POP);
5047 }
5048
5049 return bc_lex_next(&p->l);
5050}
5051
5052static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5053{
5054 BcStatus s;
5055
5056 bc_parse_push(p, inst);
5057 bc_parse_push(p, BC_INST_EXEC_COND);
5058
5059 s = dc_parse_register(p);
5060 if (s) return s;
5061
5062 s = bc_lex_next(&p->l);
5063 if (s) return s;
5064
5065 if (p->l.t.t == BC_LEX_ELSE) {
5066 s = dc_parse_register(p);
5067 if (s) return s;
5068 s = bc_lex_next(&p->l);
5069 }
5070 else
5071 bc_parse_push(p, BC_PARSE_STREND);
5072
5073 return s;
5074}
5075
5076static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5077{
5078 BcStatus s = BC_STATUS_SUCCESS;
5079 BcInst prev;
5080 uint8_t inst;
5081 bool assign, get_token = false;
5082
5083 switch (t) {
5084
5085 case BC_LEX_OP_REL_EQ:
5086 case BC_LEX_OP_REL_LE:
5087 case BC_LEX_OP_REL_GE:
5088 case BC_LEX_OP_REL_NE:
5089 case BC_LEX_OP_REL_LT:
5090 case BC_LEX_OP_REL_GT:
5091 {
5092 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5093 break;
5094 }
5095
5096 case BC_LEX_SCOLON:
5097 case BC_LEX_COLON:
5098 {
5099 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5100 break;
5101 }
5102
5103 case BC_LEX_STR:
5104 {
5105 s = dc_parse_string(p);
5106 break;
5107 }
5108
5109 case BC_LEX_NEG:
5110 case BC_LEX_NUMBER:
5111 {
5112 if (t == BC_LEX_NEG) {
5113 s = bc_lex_next(&p->l);
5114 if (s) return s;
5115 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5116 }
5117
5118 bc_parse_number(p, &prev, &p->nbraces);
5119
5120 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5121 get_token = true;
5122
5123 break;
5124 }
5125
5126 case BC_LEX_KEY_READ:
5127 {
5128 if (flags & BC_PARSE_NOREAD)
5129 s = BC_STATUS_EXEC_REC_READ;
5130 else
5131 bc_parse_push(p, BC_INST_READ);
5132 get_token = true;
5133 break;
5134 }
5135
5136 case BC_LEX_OP_ASSIGN:
5137 case BC_LEX_STORE_PUSH:
5138 {
5139 assign = t == BC_LEX_OP_ASSIGN;
5140 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5141 s = dc_parse_mem(p, inst, true, assign);
5142 break;
5143 }
5144
5145 case BC_LEX_LOAD:
5146 case BC_LEX_LOAD_POP:
5147 {
5148 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5149 s = dc_parse_mem(p, inst, true, false);
5150 break;
5151 }
5152
5153 case BC_LEX_STORE_IBASE:
5154 case BC_LEX_STORE_SCALE:
5155 case BC_LEX_STORE_OBASE:
5156 {
5157 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5158 s = dc_parse_mem(p, inst, false, true);
5159 break;
5160 }
5161
5162 default:
5163 {
5164 s = BC_STATUS_PARSE_BAD_TOKEN;
5165 get_token = true;
5166 break;
5167 }
5168 }
5169
5170 if (!s && get_token) s = bc_lex_next(&p->l);
5171
5172 return s;
5173}
5174
5175static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5176{
5177 BcStatus s = BC_STATUS_SUCCESS;
5178 BcInst inst;
5179 BcLexType t;
5180
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005181 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005182
5183 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5184
5185 inst = dc_parse_insts[t];
5186
5187 if (inst != BC_INST_INVALID) {
5188 bc_parse_push(p, inst);
5189 s = bc_lex_next(&p->l);
5190 }
5191 else
5192 s = dc_parse_token(p, t, flags);
5193 }
5194
5195 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5196 bc_parse_push(p, BC_INST_POP_EXEC);
5197
5198 return s;
5199}
5200
5201static BcStatus dc_parse_parse(BcParse *p)
5202{
5203 BcStatus s;
5204
5205 if (p->l.t.t == BC_LEX_EOF)
5206 s = BC_STATUS_LEX_EOF;
5207 else
5208 s = dc_parse_expr(p, 0);
5209
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01005210 if (s || G_interrupt) s = bc_parse_reset(p, s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005211
5212 return s;
5213}
5214
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005215static void dc_parse_init(BcParse *p, size_t func)
Gavin Howard01055ba2018-11-03 11:00:21 -06005216{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005217 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
Gavin Howard01055ba2018-11-03 11:00:21 -06005218}
5219#endif // ENABLE_DC
5220
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005221static void common_parse_init(BcParse *p, size_t func)
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005222{
5223 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005224 bc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005225 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005226 dc_parse_init(p, func);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005227 }
5228}
5229
5230static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5231{
5232 if (IS_BC) {
5233 return bc_parse_expression(p, flags);
5234 } else {
5235 return dc_parse_expr(p, flags);
5236 }
5237}
5238
Denys Vlasenkodf515392018-12-02 19:27:48 +01005239static BcVec* bc_program_search(char *id, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005240{
Gavin Howard01055ba2018-11-03 11:00:21 -06005241 BcId e, *ptr;
5242 BcVec *v, *map;
5243 size_t i;
5244 BcResultData data;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005245 int new;
Gavin Howard01055ba2018-11-03 11:00:21 -06005246
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005247 v = var ? &G.prog.vars : &G.prog.arrs;
5248 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005249
5250 e.name = id;
5251 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005252 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005253
5254 if (new) {
5255 bc_array_init(&data.v, var);
5256 bc_vec_push(v, &data.v);
5257 }
5258
5259 ptr = bc_vec_item(map, i);
5260 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005261 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005262}
5263
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005264static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
Gavin Howard01055ba2018-11-03 11:00:21 -06005265{
5266 BcStatus s = BC_STATUS_SUCCESS;
5267
5268 switch (r->t) {
5269
5270 case BC_RESULT_STR:
5271 case BC_RESULT_TEMP:
5272 case BC_RESULT_IBASE:
5273 case BC_RESULT_SCALE:
5274 case BC_RESULT_OBASE:
5275 {
5276 *num = &r->d.n;
5277 break;
5278 }
5279
5280 case BC_RESULT_CONSTANT:
5281 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005282 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005283 size_t base_t, len = strlen(*str);
5284 BcNum *base;
5285
5286 bc_num_init(&r->d.n, len);
5287
5288 hex = hex && len == 1;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005289 base = hex ? &G.prog.hexb : &G.prog.ib;
5290 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005291 s = bc_num_parse(&r->d.n, *str, base, base_t);
5292
5293 if (s) {
5294 bc_num_free(&r->d.n);
5295 return s;
5296 }
5297
5298 *num = &r->d.n;
5299 r->t = BC_RESULT_TEMP;
5300
5301 break;
5302 }
5303
5304 case BC_RESULT_VAR:
5305 case BC_RESULT_ARRAY:
5306 case BC_RESULT_ARRAY_ELEM:
5307 {
5308 BcVec *v;
5309
Denys Vlasenkodf515392018-12-02 19:27:48 +01005310 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005311
5312 if (r->t == BC_RESULT_ARRAY_ELEM) {
5313 v = bc_vec_top(v);
5314 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5315 *num = bc_vec_item(v, r->d.id.idx);
5316 }
5317 else
5318 *num = bc_vec_top(v);
5319
5320 break;
5321 }
5322
5323 case BC_RESULT_LAST:
5324 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005325 *num = &G.prog.last;
Gavin Howard01055ba2018-11-03 11:00:21 -06005326 break;
5327 }
5328
5329 case BC_RESULT_ONE:
5330 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005331 *num = &G.prog.one;
Gavin Howard01055ba2018-11-03 11:00:21 -06005332 break;
5333 }
5334 }
5335
5336 return s;
5337}
5338
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005339static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005340 BcResult **r, BcNum **rn, bool assign)
5341{
5342 BcStatus s;
5343 bool hex;
5344 BcResultType lt, rt;
5345
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005346 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005347
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005348 *r = bc_vec_item_rev(&G.prog.results, 0);
5349 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005350
5351 lt = (*l)->t;
5352 rt = (*r)->t;
5353 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5354
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005355 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005356 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005357 s = bc_program_num(*r, rn, hex);
Gavin Howard01055ba2018-11-03 11:00:21 -06005358 if (s) return s;
5359
5360 // We run this again under these conditions in case any vector has been
5361 // reallocated out from under the BcNums or arrays we had.
5362 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005363 s = bc_program_num(*l, ln, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005364 if (s) return s;
5365 }
5366
5367 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5368 return BC_STATUS_EXEC_BAD_TYPE;
5369 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5370
Gavin Howard01055ba2018-11-03 11:00:21 -06005371 return s;
5372}
5373
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005374static void bc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005375{
5376 r->t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005377 bc_vec_pop(&G.prog.results);
5378 bc_vec_pop(&G.prog.results);
5379 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005380}
5381
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005382static BcStatus bc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005383{
5384 BcStatus s;
5385
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005386 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5387 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005388
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005389 s = bc_program_num(*r, n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005390 if (s) return s;
5391
Gavin Howard01055ba2018-11-03 11:00:21 -06005392 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5393
5394 return s;
5395}
5396
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005397static void bc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005398{
5399 r->t = t;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005400 bc_vec_pop(&G.prog.results);
5401 bc_vec_push(&G.prog.results, r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005402}
5403
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005404static BcStatus bc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005405{
5406 BcStatus s;
5407 BcResult *opd1, *opd2, res;
5408 BcNum *n1, *n2 = NULL;
5409
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005410 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005411 if (s) return s;
5412 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5413
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005414 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005415 if (s) goto err;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005416 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005417
5418 return s;
5419
5420err:
5421 bc_num_free(&res.d.n);
5422 return s;
5423}
5424
Denys Vlasenko785e4b32018-12-02 17:18:52 +01005425static BcStatus bc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005426{
5427 BcStatus s;
5428 BcParse parse;
5429 BcVec buf;
5430 BcInstPtr ip;
5431 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005432 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005433
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005434 for (i = 0; i < G.prog.stack.len; ++i) {
5435 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
Gavin Howard01055ba2018-11-03 11:00:21 -06005436 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5437 }
5438
5439 bc_vec_npop(&f->code, f->code.len);
5440 bc_vec_init(&buf, sizeof(char), NULL);
5441
5442 s = bc_read_line(&buf, "read> ");
5443 if (s) goto io_err;
5444
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005445 common_parse_init(&parse, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005446 bc_lex_file(&parse.l, bc_program_stdin_name);
5447
5448 s = bc_parse_text(&parse, buf.v);
5449 if (s) goto exec_err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01005450 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
Gavin Howard01055ba2018-11-03 11:00:21 -06005451 if (s) goto exec_err;
5452
5453 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5454 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5455 goto exec_err;
5456 }
5457
5458 ip.func = BC_PROG_READ;
5459 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005460 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005461
5462 // Update this pointer, just in case.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005463 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06005464
5465 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005466 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06005467
5468exec_err:
5469 bc_parse_free(&parse);
5470io_err:
5471 bc_vec_free(&buf);
5472 return s;
5473}
5474
5475static size_t bc_program_index(char *code, size_t *bgn)
5476{
5477 char amt = code[(*bgn)++], i = 0;
5478 size_t res = 0;
5479
5480 for (; i < amt; ++i, ++(*bgn))
5481 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5482
5483 return res;
5484}
5485
5486static char *bc_program_name(char *code, size_t *bgn)
5487{
5488 size_t i;
5489 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5490
5491 s = xmalloc(ptr - str + 1);
5492 c = code[(*bgn)++];
5493
5494 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5495 s[i] = c;
5496
5497 s[i] = '\0';
5498
5499 return s;
5500}
5501
5502static void bc_program_printString(const char *str, size_t *nchars)
5503{
5504 size_t i, len = strlen(str);
5505
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005506#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005507 if (len == 0) {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005508 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005509 return;
5510 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005511#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005512
5513 for (i = 0; i < len; ++i, ++(*nchars)) {
5514
5515 int c = str[i];
5516
5517 if (c != '\\' || i == len - 1)
Denys Vlasenko00d77792018-11-30 23:13:42 +01005518 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005519 else {
5520
5521 c = str[++i];
5522
5523 switch (c) {
5524
5525 case 'a':
5526 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005527 bb_putchar('\a');
Gavin Howard01055ba2018-11-03 11:00:21 -06005528 break;
5529 }
5530
5531 case 'b':
5532 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005533 bb_putchar('\b');
Gavin Howard01055ba2018-11-03 11:00:21 -06005534 break;
5535 }
5536
5537 case '\\':
5538 case 'e':
5539 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005540 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005541 break;
5542 }
5543
5544 case 'f':
5545 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005546 bb_putchar('\f');
Gavin Howard01055ba2018-11-03 11:00:21 -06005547 break;
5548 }
5549
5550 case 'n':
5551 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005552 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005553 *nchars = SIZE_MAX;
5554 break;
5555 }
5556
5557 case 'r':
5558 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005559 bb_putchar('\r');
Gavin Howard01055ba2018-11-03 11:00:21 -06005560 break;
5561 }
5562
5563 case 'q':
5564 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005565 bb_putchar('"');
Gavin Howard01055ba2018-11-03 11:00:21 -06005566 break;
5567 }
5568
5569 case 't':
5570 {
Denys Vlasenko00d77792018-11-30 23:13:42 +01005571 bb_putchar('\t');
Gavin Howard01055ba2018-11-03 11:00:21 -06005572 break;
5573 }
5574
5575 default:
5576 {
5577 // Just print the backslash and following character.
Denys Vlasenko00d77792018-11-30 23:13:42 +01005578 bb_putchar('\\');
Gavin Howard01055ba2018-11-03 11:00:21 -06005579 ++(*nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005580 bb_putchar(c);
Gavin Howard01055ba2018-11-03 11:00:21 -06005581 break;
5582 }
5583 }
5584 }
5585 }
5586}
5587
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005588static BcStatus bc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005589{
5590 BcStatus s = BC_STATUS_SUCCESS;
5591 BcResult *r;
5592 size_t len, i;
5593 char *str;
5594 BcNum *num = NULL;
5595 bool pop = inst != BC_INST_PRINT;
5596
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005597 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005598
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005599 r = bc_vec_item_rev(&G.prog.results, idx);
5600 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005601 if (s) return s;
5602
5603 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005604 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5605 if (!s) bc_num_copy(&G.prog.last, num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005606 }
5607 else {
5608
5609 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005610 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06005611
5612 if (inst == BC_INST_PRINT_STR) {
5613 for (i = 0, len = strlen(str); i < len; ++i) {
5614 char c = str[i];
Denys Vlasenko00d77792018-11-30 23:13:42 +01005615 bb_putchar(c);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005616 if (c == '\n') G.prog.nchars = SIZE_MAX;
5617 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005618 }
5619 }
5620 else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005621 bc_program_printString(str, &G.prog.nchars);
Denys Vlasenko00d77792018-11-30 23:13:42 +01005622 if (inst == BC_INST_PRINT) bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005623 }
5624 }
5625
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005626 if (!s && pop) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005627
5628 return s;
5629}
5630
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005631static BcStatus bc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005632{
5633 BcStatus s;
5634 BcResult res, *ptr;
5635 BcNum *num = NULL;
5636
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005637 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005638 if (s) return s;
5639
5640 bc_num_init(&res.d.n, num->len);
5641 bc_num_copy(&res.d.n, num);
5642 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5643
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005644 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005645
5646 return s;
5647}
5648
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005649static BcStatus bc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005650{
5651 BcStatus s;
5652 BcResult *opd1, *opd2, res;
5653 BcNum *n1, *n2;
5654 bool cond = 0;
5655 ssize_t cmp;
5656
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005657 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005658 if (s) return s;
5659 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5660
5661 if (inst == BC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005662 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005663 else if (inst == BC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005664 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005665 else {
5666
5667 cmp = bc_num_cmp(n1, n2);
5668
5669 switch (inst) {
5670
5671 case BC_INST_REL_EQ:
5672 {
5673 cond = cmp == 0;
5674 break;
5675 }
5676
5677 case BC_INST_REL_LE:
5678 {
5679 cond = cmp <= 0;
5680 break;
5681 }
5682
5683 case BC_INST_REL_GE:
5684 {
5685 cond = cmp >= 0;
5686 break;
5687 }
5688
5689 case BC_INST_REL_NE:
5690 {
5691 cond = cmp != 0;
5692 break;
5693 }
5694
5695 case BC_INST_REL_LT:
5696 {
5697 cond = cmp < 0;
5698 break;
5699 }
5700
5701 case BC_INST_REL_GT:
5702 {
5703 cond = cmp > 0;
5704 break;
5705 }
5706 }
5707 }
5708
5709 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5710
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005711 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005712
5713 return s;
5714}
5715
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005716#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005717static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
Gavin Howard01055ba2018-11-03 11:00:21 -06005718 bool push)
5719{
5720 BcNum n2;
5721 BcResult res;
5722
5723 memset(&n2, 0, sizeof(BcNum));
5724 n2.rdx = res.d.id.idx = r->d.id.idx;
5725 res.t = BC_RESULT_STR;
5726
5727 if (!push) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005728 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005729 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005730 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005731 }
5732
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005733 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005735 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005736 bc_vec_push(v, &n2);
5737
5738 return BC_STATUS_SUCCESS;
5739}
5740#endif // ENABLE_DC
5741
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005742static BcStatus bc_program_copyToVar(char *name, bool var)
Gavin Howard01055ba2018-11-03 11:00:21 -06005743{
5744 BcStatus s;
5745 BcResult *ptr, r;
5746 BcVec *v;
5747 BcNum *n;
5748
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005749 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06005750
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005751 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005752 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005753 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005754
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005755#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005756 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005757 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005758#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005759
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005760 s = bc_program_num(ptr, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005761 if (s) return s;
5762
5763 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenkodf515392018-12-02 19:27:48 +01005764 v = bc_program_search(name, var);
Gavin Howard01055ba2018-11-03 11:00:21 -06005765
5766 if (var) {
5767 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5768 bc_num_copy(&r.d.n, n);
5769 }
5770 else {
5771 bc_array_init(&r.d.v, true);
5772 bc_array_copy(&r.d.v, (BcVec *) n);
5773 }
5774
5775 bc_vec_push(v, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005776 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005777
5778 return s;
5779}
5780
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005781static BcStatus bc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005782{
5783 BcStatus s;
5784 BcResult *left, *right, res;
5785 BcNum *l = NULL, *r = NULL;
5786 unsigned long val, max;
5787 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5788
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005789 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
Gavin Howard01055ba2018-11-03 11:00:21 -06005790 if (s) return s;
5791
5792 ib = left->t == BC_RESULT_IBASE;
5793 sc = left->t == BC_RESULT_SCALE;
5794
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005795#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06005796
5797 if (right->t == BC_RESULT_STR) {
5798
5799 BcVec *v;
5800
5801 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkodf515392018-12-02 19:27:48 +01005802 v = bc_program_search(left->d.id.name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06005803
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005804 return bc_program_assignStr(right, v, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06005805 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005806#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005807
5808 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5809 return BC_STATUS_PARSE_BAD_ASSIGN;
5810
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005811#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005812 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
Gavin Howard01055ba2018-11-03 11:00:21 -06005813 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5814
5815 if (assign)
5816 bc_num_copy(l, r);
5817 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005818 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005819
5820 if (s) return s;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005821#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005822 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005823#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005824
5825 if (ib || sc || left->t == BC_RESULT_OBASE) {
5826
5827 size_t *ptr;
5828
5829 s = bc_num_ulong(l, &val);
5830 if (s) return s;
5831 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5832
5833 if (sc) {
5834 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005835 ptr = &G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06005836 }
5837 else {
5838 if (val < BC_NUM_MIN_BASE) return s;
5839 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005840 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005841 }
5842
5843 if (val > max) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005844 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
Gavin Howard01055ba2018-11-03 11:00:21 -06005845
5846 *ptr = (size_t) val;
5847 s = BC_STATUS_SUCCESS;
5848 }
5849
5850 bc_num_init(&res.d.n, l->len);
5851 bc_num_copy(&res.d.n, l);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005852 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005853
5854 return s;
5855}
5856
Denys Vlasenko416ce762018-12-02 20:57:17 +01005857#if !ENABLE_DC
5858#define bc_program_pushVar(code, bgn, pop, copy) \
5859 bc_program_pushVar(code, bgn)
5860// for bc, 'pop' and 'copy' are always false
5861#endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005862static BcStatus bc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005863 bool pop, bool copy)
5864{
5865 BcStatus s = BC_STATUS_SUCCESS;
5866 BcResult r;
5867 char *name = bc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06005868
5869 r.t = BC_RESULT_VAR;
5870 r.d.id.name = name;
5871
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005872#if ENABLE_DC
Denys Vlasenko416ce762018-12-02 20:57:17 +01005873 {
5874 BcVec *v = bc_program_search(name, true);
5875 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005876
Denys Vlasenko416ce762018-12-02 20:57:17 +01005877 if (pop || copy) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005878
Denys Vlasenko416ce762018-12-02 20:57:17 +01005879 if (!BC_PROG_STACK(v, 2 - copy)) {
5880 free(name);
5881 return BC_STATUS_EXEC_STACK;
5882 }
5883
Gavin Howard01055ba2018-11-03 11:00:21 -06005884 free(name);
Denys Vlasenko416ce762018-12-02 20:57:17 +01005885 name = NULL;
5886
5887 if (!BC_PROG_STR(num)) {
5888
5889 r.t = BC_RESULT_TEMP;
5890
5891 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5892 bc_num_copy(&r.d.n, num);
5893 }
5894 else {
5895 r.t = BC_RESULT_STR;
5896 r.d.id.idx = num->rdx;
5897 }
5898
5899 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005900 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005901 }
5902#endif // ENABLE_DC
5903
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005904 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005905
5906 return s;
5907}
5908
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005909static BcStatus bc_program_pushArray(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06005910 char inst)
5911{
5912 BcStatus s = BC_STATUS_SUCCESS;
5913 BcResult r;
5914 BcNum *num;
5915
5916 r.d.id.name = bc_program_name(code, bgn);
5917
5918 if (inst == BC_INST_ARRAY) {
5919 r.t = BC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005920 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005921 }
5922 else {
5923
5924 BcResult *operand;
5925 unsigned long temp;
5926
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005927 s = bc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005928 if (s) goto err;
5929 s = bc_num_ulong(num, &temp);
5930 if (s) goto err;
5931
5932 if (temp > BC_MAX_DIM) {
5933 s = BC_STATUS_EXEC_ARRAY_LEN;
5934 goto err;
5935 }
5936
5937 r.d.id.idx = (size_t) temp;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005938 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06005939 }
5940
5941err:
5942 if (s) free(r.d.id.name);
5943 return s;
5944}
5945
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005946#if ENABLE_BC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005947static BcStatus bc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005948{
5949 BcStatus s;
5950 BcResult *ptr, res, copy;
5951 BcNum *num = NULL;
5952 char inst2 = inst;
5953
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005954 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06005955 if (s) return s;
5956
5957 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5958 copy.t = BC_RESULT_TEMP;
5959 bc_num_init(&copy.d.n, num->len);
5960 bc_num_copy(&copy.d.n, num);
5961 }
5962
5963 res.t = BC_RESULT_ONE;
5964 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5965 BC_INST_ASSIGN_PLUS :
5966 BC_INST_ASSIGN_MINUS;
5967
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005968 bc_vec_push(&G.prog.results, &res);
5969 bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005970
5971 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005972 bc_vec_pop(&G.prog.results);
5973 bc_vec_push(&G.prog.results, &copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06005974 }
5975
5976 return s;
5977}
5978
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005979static BcStatus bc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005980{
5981 BcStatus s = BC_STATUS_SUCCESS;
5982 BcInstPtr ip;
5983 size_t i, nparams = bc_program_index(code, idx);
5984 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06005985 BcId *a;
5986 BcResultData param;
5987 BcResult *arg;
5988
5989 ip.idx = 0;
5990 ip.func = bc_program_index(code, idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005991 func = bc_vec_item(&G.prog.fns, ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06005992
5993 if (func->code.len == 0) return BC_STATUS_EXEC_UNDEFINED_FUNC;
5994 if (nparams != func->nparams) return BC_STATUS_EXEC_MISMATCHED_PARAMS;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005995 ip.len = G.prog.results.len - nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06005996
5997 for (i = 0; i < nparams; ++i) {
5998
5999 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006000 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006001
6002 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6003 return BC_STATUS_EXEC_BAD_TYPE;
6004
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006005 s = bc_program_copyToVar(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006006 if (s) return s;
6007 }
6008
6009 for (; i < func->autos.len; ++i) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006010 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006011
6012 a = bc_vec_item(&func->autos, i);
Denys Vlasenkodf515392018-12-02 19:27:48 +01006013 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006014
6015 if (a->idx) {
6016 bc_num_init(&param.n, BC_NUM_DEF_SIZE);
6017 bc_vec_push(v, &param.n);
6018 }
6019 else {
6020 bc_array_init(&param.v, true);
6021 bc_vec_push(v, &param.v);
6022 }
6023 }
6024
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006025 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006026
6027 return BC_STATUS_SUCCESS;
6028}
6029
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006030static BcStatus bc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006031{
6032 BcStatus s;
6033 BcResult res;
6034 BcFunc *f;
6035 size_t i;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006036 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006037
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006038 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
Gavin Howard01055ba2018-11-03 11:00:21 -06006039 return BC_STATUS_EXEC_STACK;
6040
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006041 f = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006042 res.t = BC_RESULT_TEMP;
6043
6044 if (inst == BC_INST_RET) {
6045
6046 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006047 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006048
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006049 s = bc_program_num(operand, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006050 if (s) return s;
6051 bc_num_init(&res.d.n, num->len);
6052 bc_num_copy(&res.d.n, num);
6053 }
6054 else {
6055 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6056 bc_num_zero(&res.d.n);
6057 }
6058
6059 // We need to pop arguments as well, so this takes that into account.
6060 for (i = 0; i < f->autos.len; ++i) {
6061
6062 BcVec *v;
6063 BcId *a = bc_vec_item(&f->autos, i);
6064
Denys Vlasenkodf515392018-12-02 19:27:48 +01006065 v = bc_program_search(a->name, a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006066 bc_vec_pop(v);
6067 }
6068
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006069 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6070 bc_vec_push(&G.prog.results, &res);
6071 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006072
6073 return BC_STATUS_SUCCESS;
6074}
6075#endif // ENABLE_BC
6076
6077static unsigned long bc_program_scale(BcNum *n)
6078{
6079 return (unsigned long) n->rdx;
6080}
6081
6082static unsigned long bc_program_len(BcNum *n)
6083{
6084 unsigned long len = n->len;
6085 size_t i;
6086
6087 if (n->rdx != n->len) return len;
6088 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6089
6090 return len;
6091}
6092
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006093static BcStatus bc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006094{
6095 BcStatus s;
6096 BcResult *opnd;
6097 BcNum *num = NULL;
6098 BcResult res;
6099 bool len = inst == BC_INST_LENGTH;
6100
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006101 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6102 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006103
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006104 s = bc_program_num(opnd, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006105 if (s) return s;
6106
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006107#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006108 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006109#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006110
6111 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6112
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006113 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006114#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006115 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006116 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006117 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006118#endif
6119#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006120 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6121
6122 char **str;
6123 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6124
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006125 str = bc_vec_item(&G.prog.strs, idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006126 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006127 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006128#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006129 else {
6130 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006131 bc_num_ulong2num(&res.d.n, f(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006132 }
6133
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006134 bc_program_retire(&res, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006135
6136 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006137}
6138
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006139#if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006140static BcStatus bc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006141{
6142 BcStatus s;
6143 BcResult *opd1, *opd2, res, res2;
6144 BcNum *n1, *n2 = NULL;
6145
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006146 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006147 if (s) return s;
6148
6149 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6150 bc_num_init(&res2.d.n, n2->len);
6151
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006152 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006153 if (s) goto err;
6154
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006155 bc_program_binOpRetire(&res2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006156 res.t = BC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006157 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006158
6159 return s;
6160
6161err:
6162 bc_num_free(&res2.d.n);
6163 bc_num_free(&res.d.n);
6164 return s;
6165}
6166
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006167static BcStatus bc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006168{
6169 BcStatus s;
6170 BcResult *r1, *r2, *r3, res;
6171 BcNum *n1, *n2, *n3;
6172
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006173 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6174 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006175 if (s) return s;
6176
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006177 r1 = bc_vec_item_rev(&G.prog.results, 2);
6178 s = bc_program_num(r1, &n1, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006179 if (s) return s;
6180 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6181
6182 // Make sure that the values have their pointers updated, if necessary.
6183 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6184
6185 if (r1->t == r2->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006186 s = bc_program_num(r2, &n2, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006187 if (s) return s;
6188 }
6189
6190 if (r1->t == r3->t) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006191 s = bc_program_num(r3, &n3, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006192 if (s) return s;
6193 }
6194 }
6195
6196 bc_num_init(&res.d.n, n3->len);
6197 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6198 if (s) goto err;
6199
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006200 bc_vec_pop(&G.prog.results);
6201 bc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006202
6203 return s;
6204
6205err:
6206 bc_num_free(&res.d.n);
6207 return s;
6208}
6209
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006210static void bc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006211{
Gavin Howard01055ba2018-11-03 11:00:21 -06006212 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006213 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006214
6215 res.t = BC_RESULT_TEMP;
6216
6217 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006218 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006219 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006220}
6221
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006222static BcStatus bc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006223{
6224 BcStatus s;
6225 BcResult *r, res;
6226 BcNum *num = NULL, n;
6227 char *str, *str2, c;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006228 size_t len = G.prog.strs.len, idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006229 unsigned long val;
6230
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006231 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6232 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006233
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006234 s = bc_program_num(r, &num, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006235 if (s) return s;
6236
6237 if (BC_PROG_NUM(r, num)) {
6238
6239 bc_num_init(&n, BC_NUM_DEF_SIZE);
6240 bc_num_copy(&n, num);
6241 bc_num_truncate(&n, n.rdx);
6242
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006243 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006244 if (s) goto num_err;
6245 s = bc_num_ulong(&n, &val);
6246 if (s) goto num_err;
6247
6248 c = (char) val;
6249
6250 bc_num_free(&n);
6251 }
6252 else {
6253 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006254 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
Gavin Howard01055ba2018-11-03 11:00:21 -06006255 c = str2[0];
6256 }
6257
6258 str = xmalloc(2);
6259 str[0] = c;
6260 str[1] = '\0';
6261
6262 str2 = xstrdup(str);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006263 bc_program_addFunc(str2, &idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006264
6265 if (idx != len + BC_PROG_REQ_FUNCS) {
6266
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006267 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6268 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006269 len = idx;
6270 break;
6271 }
6272 }
6273
6274 free(str);
6275 }
6276 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006277 bc_vec_push(&G.prog.strs, &str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006278
6279 res.t = BC_RESULT_STR;
6280 res.d.id.idx = len;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006281 bc_vec_pop(&G.prog.results);
6282 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006283
6284 return BC_STATUS_SUCCESS;
6285
6286num_err:
6287 bc_num_free(&n);
6288 return s;
6289}
6290
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006291static BcStatus bc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006292{
6293 BcStatus s;
6294 BcResult *r;
6295 BcNum *n = NULL;
6296 size_t idx;
6297 char *str;
6298
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006299 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6300 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006301
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006302 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006303 if (s) return s;
6304
6305 if (BC_PROG_NUM(r, n))
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006306 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006307 else {
6308 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006309 str = *((char **) bc_vec_item(&G.prog.strs, idx));
Denys Vlasenko00d77792018-11-30 23:13:42 +01006310 printf("%s", str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006311 }
6312
6313 return s;
6314}
6315
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006316static BcStatus bc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006317{
6318 BcStatus s;
6319 BcResult *opnd;
6320 BcNum *num = NULL;
6321 unsigned long val;
6322
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006323 s = bc_program_prep(&opnd, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006324 if (s) return s;
6325 s = bc_num_ulong(num, &val);
6326 if (s) return s;
6327
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006328 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006329
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006330 if (G.prog.stack.len < val)
Gavin Howard01055ba2018-11-03 11:00:21 -06006331 return BC_STATUS_EXEC_STACK;
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006332 if (G.prog.stack.len == val)
6333 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006334
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006335 bc_vec_npop(&G.prog.stack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006336
6337 return s;
6338}
6339
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006340static BcStatus bc_program_execStr(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006341 bool cond)
6342{
6343 BcStatus s = BC_STATUS_SUCCESS;
6344 BcResult *r;
6345 char **str;
6346 BcFunc *f;
6347 BcParse prs;
6348 BcInstPtr ip;
6349 size_t fidx, sidx;
6350 BcNum *n;
6351 bool exec;
6352
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006353 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006354
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006355 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006356
6357 if (cond) {
6358
Gavin Howard01055ba2018-11-03 11:00:21 -06006359 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6360
6361 if (code[*bgn] == BC_PARSE_STREND)
6362 (*bgn) += 1;
6363 else
6364 else_name = bc_program_name(code, bgn);
6365
6366 exec = r->d.n.len != 0;
6367
6368 if (exec)
6369 name = then_name;
6370 else if (else_name != NULL) {
6371 exec = true;
6372 name = else_name;
6373 }
6374
6375 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006376 BcVec *v;
6377 v = bc_program_search(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006378 n = bc_vec_top(v);
6379 }
6380
6381 free(then_name);
6382 free(else_name);
6383
6384 if (!exec) goto exit;
6385 if (!BC_PROG_STR(n)) {
6386 s = BC_STATUS_EXEC_BAD_TYPE;
6387 goto exit;
6388 }
6389
6390 sidx = n->rdx;
6391 }
6392 else {
6393
6394 if (r->t == BC_RESULT_STR)
6395 sidx = r->d.id.idx;
6396 else if (r->t == BC_RESULT_VAR) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006397 s = bc_program_num(r, &n, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006398 if (s || !BC_PROG_STR(n)) goto exit;
6399 sidx = n->rdx;
6400 }
6401 else
6402 goto exit;
6403 }
6404
6405 fidx = sidx + BC_PROG_REQ_FUNCS;
6406
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006407 str = bc_vec_item(&G.prog.strs, sidx);
6408 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006409
6410 if (f->code.len == 0) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006411 common_parse_init(&prs, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006412 s = bc_parse_text(&prs, *str);
6413 if (s) goto err;
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01006414 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
Gavin Howard01055ba2018-11-03 11:00:21 -06006415 if (s) goto err;
6416
6417 if (prs.l.t.t != BC_LEX_EOF) {
6418 s = BC_STATUS_PARSE_BAD_EXP;
6419 goto err;
6420 }
6421
6422 bc_parse_free(&prs);
6423 }
6424
6425 ip.idx = 0;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006426 ip.len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006427 ip.func = fidx;
6428
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006429 bc_vec_pop(&G.prog.results);
6430 bc_vec_push(&G.prog.stack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006431
6432 return BC_STATUS_SUCCESS;
6433
6434err:
6435 bc_parse_free(&prs);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006436 f = bc_vec_item(&G.prog.fns, fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006437 bc_vec_npop(&f->code, f->code.len);
6438exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006439 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006440 return s;
6441}
6442#endif // ENABLE_DC
6443
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006444static void bc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006445{
Gavin Howard01055ba2018-11-03 11:00:21 -06006446 BcResult res;
6447 unsigned long val;
6448
6449 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6450 if (inst == BC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006451 val = (unsigned long) G.prog.ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006452 else if (inst == BC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006453 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006454 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006455 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006456
6457 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006458 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006459 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006460}
6461
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006462static void bc_program_addFunc(char *name, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006463{
Gavin Howard01055ba2018-11-03 11:00:21 -06006464 BcId entry, *entry_ptr;
6465 BcFunc f;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006466 int inserted;
Gavin Howard01055ba2018-11-03 11:00:21 -06006467
6468 entry.name = name;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006469 entry.idx = G.prog.fns.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006470
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006471 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6472 if (!inserted) free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006473
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006474 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006475 *idx = entry_ptr->idx;
6476
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006477 if (!inserted) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006478
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006479 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006480
6481 // We need to reset these, so the function can be repopulated.
6482 func->nparams = 0;
6483 bc_vec_npop(&func->autos, func->autos.len);
6484 bc_vec_npop(&func->code, func->code.len);
6485 bc_vec_npop(&func->labels, func->labels.len);
6486 }
6487 else {
6488 bc_func_init(&f);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006489 bc_vec_push(&G.prog.fns, &f);
Gavin Howard01055ba2018-11-03 11:00:21 -06006490 }
6491}
6492
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006493static BcStatus bc_program_reset(BcStatus s)
Gavin Howard01055ba2018-11-03 11:00:21 -06006494{
6495 BcFunc *f;
6496 BcInstPtr *ip;
6497
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006498 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6499 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006500
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006501 f = bc_vec_item(&G.prog.fns, 0);
6502 ip = bc_vec_top(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006503 ip->idx = f->code.len;
6504
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006505 if (!s && G_interrupt && !G.tty) quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006506
6507 if (!s || s == BC_STATUS_EXEC_SIGNAL) {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006508 if (!G.ttyin)
6509 quit();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006510 fflush_and_check(); // make sure buffered stdout is printed
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006511 fputs(bc_program_ready_msg, stderr);
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006512 fflush_and_check();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006513 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06006514 }
6515
6516 return s;
6517}
6518
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006519static BcStatus bc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006520{
6521 BcStatus s = BC_STATUS_SUCCESS;
6522 size_t idx;
6523 BcResult r, *ptr;
6524 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006525 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6526 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006527 char *code = func->code.v;
6528 bool cond = false;
6529
6530 while (!s && ip->idx < func->code.len) {
6531
6532 char inst = code[(ip->idx)++];
6533
6534 switch (inst) {
6535
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006536#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006537 case BC_INST_JUMP_ZERO:
6538 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006539 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006540 if (s) return s;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006541 cond = !bc_num_cmp(num, &G.prog.zero);
6542 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006543 }
6544 // Fallthrough.
6545 case BC_INST_JUMP:
6546 {
6547 size_t *addr;
6548 idx = bc_program_index(code, &ip->idx);
6549 addr = bc_vec_item(&func->labels, idx);
6550 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6551 break;
6552 }
6553
6554 case BC_INST_CALL:
6555 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006556 s = bc_program_call(code, &ip->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006557 break;
6558 }
6559
6560 case BC_INST_INC_PRE:
6561 case BC_INST_DEC_PRE:
6562 case BC_INST_INC_POST:
6563 case BC_INST_DEC_POST:
6564 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006565 s = bc_program_incdec(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006566 break;
6567 }
6568
6569 case BC_INST_HALT:
6570 {
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006571 quit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006572 break;
6573 }
6574
6575 case BC_INST_RET:
6576 case BC_INST_RET0:
6577 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006578 s = bc_program_return(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006579 break;
6580 }
6581
6582 case BC_INST_BOOL_OR:
6583 case BC_INST_BOOL_AND:
6584#endif // ENABLE_BC
6585 case BC_INST_REL_EQ:
6586 case BC_INST_REL_LE:
6587 case BC_INST_REL_GE:
6588 case BC_INST_REL_NE:
6589 case BC_INST_REL_LT:
6590 case BC_INST_REL_GT:
6591 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006592 s = bc_program_logical(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006593 break;
6594 }
6595
6596 case BC_INST_READ:
6597 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006598 s = bc_program_read();
Gavin Howard01055ba2018-11-03 11:00:21 -06006599 break;
6600 }
6601
6602 case BC_INST_VAR:
6603 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006604 s = bc_program_pushVar(code, &ip->idx, false, false);
Gavin Howard01055ba2018-11-03 11:00:21 -06006605 break;
6606 }
6607
6608 case BC_INST_ARRAY_ELEM:
6609 case BC_INST_ARRAY:
6610 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006611 s = bc_program_pushArray(code, &ip->idx, inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006612 break;
6613 }
6614
6615 case BC_INST_LAST:
6616 {
6617 r.t = BC_RESULT_LAST;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006618 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006619 break;
6620 }
6621
6622 case BC_INST_IBASE:
6623 case BC_INST_SCALE:
6624 case BC_INST_OBASE:
6625 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006626 bc_program_pushGlobal(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006627 break;
6628 }
6629
6630 case BC_INST_SCALE_FUNC:
6631 case BC_INST_LENGTH:
6632 case BC_INST_SQRT:
6633 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006634 s = bc_program_builtin(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006635 break;
6636 }
6637
6638 case BC_INST_NUM:
6639 {
6640 r.t = BC_RESULT_CONSTANT;
6641 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006642 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006643 break;
6644 }
6645
6646 case BC_INST_POP:
6647 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006648 if (!BC_PROG_STACK(&G.prog.results, 1))
Gavin Howard01055ba2018-11-03 11:00:21 -06006649 s = BC_STATUS_EXEC_STACK;
6650 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006651 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006652 break;
6653 }
6654
6655 case BC_INST_POP_EXEC:
6656 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006657 bc_vec_pop(&G.prog.stack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006658 break;
6659 }
6660
6661 case BC_INST_PRINT:
6662 case BC_INST_PRINT_POP:
6663 case BC_INST_PRINT_STR:
6664 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006665 s = bc_program_print(inst, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006666 break;
6667 }
6668
6669 case BC_INST_STR:
6670 {
6671 r.t = BC_RESULT_STR;
6672 r.d.id.idx = bc_program_index(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006673 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006674 break;
6675 }
6676
6677 case BC_INST_POWER:
6678 case BC_INST_MULTIPLY:
6679 case BC_INST_DIVIDE:
6680 case BC_INST_MODULUS:
6681 case BC_INST_PLUS:
6682 case BC_INST_MINUS:
6683 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006684 s = bc_program_op(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006685 break;
6686 }
6687
6688 case BC_INST_BOOL_NOT:
6689 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006690 s = bc_program_prep(&ptr, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006691 if (s) return s;
6692
6693 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006694 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6695 bc_program_retire(&r, BC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006696
6697 break;
6698 }
6699
6700 case BC_INST_NEG:
6701 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006702 s = bc_program_negate();
Gavin Howard01055ba2018-11-03 11:00:21 -06006703 break;
6704 }
6705
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006706#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006707 case BC_INST_ASSIGN_POWER:
6708 case BC_INST_ASSIGN_MULTIPLY:
6709 case BC_INST_ASSIGN_DIVIDE:
6710 case BC_INST_ASSIGN_MODULUS:
6711 case BC_INST_ASSIGN_PLUS:
6712 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006713#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006714 case BC_INST_ASSIGN:
6715 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006716 s = bc_program_assign(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06006717 break;
6718 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006719#if ENABLE_DC
Gavin Howard01055ba2018-11-03 11:00:21 -06006720 case BC_INST_MODEXP:
6721 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006722 s = bc_program_modexp();
Gavin Howard01055ba2018-11-03 11:00:21 -06006723 break;
6724 }
6725
6726 case BC_INST_DIVMOD:
6727 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006728 s = bc_program_divmod();
Gavin Howard01055ba2018-11-03 11:00:21 -06006729 break;
6730 }
6731
6732 case BC_INST_EXECUTE:
6733 case BC_INST_EXEC_COND:
6734 {
6735 cond = inst == BC_INST_EXEC_COND;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006736 s = bc_program_execStr(code, &ip->idx, cond);
Gavin Howard01055ba2018-11-03 11:00:21 -06006737 break;
6738 }
6739
6740 case BC_INST_PRINT_STACK:
6741 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006742 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6743 s = bc_program_print(BC_INST_PRINT, idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006744 break;
6745 }
6746
6747 case BC_INST_CLEAR_STACK:
6748 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006749 bc_vec_npop(&G.prog.results, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006750 break;
6751 }
6752
6753 case BC_INST_STACK_LEN:
6754 {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006755 bc_program_stackLen();
Gavin Howard01055ba2018-11-03 11:00:21 -06006756 break;
6757 }
6758
6759 case BC_INST_DUPLICATE:
6760 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006761 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6762 ptr = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006763 bc_result_copy(&r, ptr);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006764 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006765 break;
6766 }
6767
6768 case BC_INST_SWAP:
6769 {
6770 BcResult *ptr2;
6771
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006772 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
Gavin Howard01055ba2018-11-03 11:00:21 -06006773
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006774 ptr = bc_vec_item_rev(&G.prog.results, 0);
6775 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06006776 memcpy(&r, ptr, sizeof(BcResult));
6777 memcpy(ptr, ptr2, sizeof(BcResult));
6778 memcpy(ptr2, &r, sizeof(BcResult));
6779
6780 break;
6781 }
6782
6783 case BC_INST_ASCIIFY:
6784 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006785 s = bc_program_asciify();
Gavin Howard01055ba2018-11-03 11:00:21 -06006786 break;
6787 }
6788
6789 case BC_INST_PRINT_STREAM:
6790 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006791 s = bc_program_printStream();
Gavin Howard01055ba2018-11-03 11:00:21 -06006792 break;
6793 }
6794
6795 case BC_INST_LOAD:
6796 case BC_INST_PUSH_VAR:
6797 {
6798 bool copy = inst == BC_INST_LOAD;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006799 s = bc_program_pushVar(code, &ip->idx, true, copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006800 break;
6801 }
6802
6803 case BC_INST_PUSH_TO_VAR:
6804 {
6805 char *name = bc_program_name(code, &ip->idx);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006806 s = bc_program_copyToVar(name, true);
Gavin Howard01055ba2018-11-03 11:00:21 -06006807 free(name);
6808 break;
6809 }
6810
6811 case BC_INST_QUIT:
6812 {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006813 if (G.prog.stack.len <= 2)
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006814 quit();
6815 bc_vec_npop(&G.prog.stack, 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006816 break;
6817 }
6818
6819 case BC_INST_NQUIT:
6820 {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006821 s = bc_program_nquit();
Gavin Howard01055ba2018-11-03 11:00:21 -06006822 break;
6823 }
6824#endif // ENABLE_DC
6825 }
6826
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006827 if (s || G_interrupt) s = bc_program_reset(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006828
6829 // If the stack has changed, pointers may be invalid.
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006830 ip = bc_vec_top(&G.prog.stack);
6831 func = bc_vec_item(&G.prog.fns, ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006832 code = func->code.v;
6833 }
6834
6835 return s;
6836}
6837
Denys Vlasenko00d77792018-11-30 23:13:42 +01006838static void bc_vm_info(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006839{
Denys Vlasenko00d77792018-11-30 23:13:42 +01006840 printf("%s "BB_VER"\n"
6841 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006842 "Report bugs at: https://github.com/gavinhoward/bc\n"
Denys Vlasenko00d77792018-11-30 23:13:42 +01006843 "This is free software with ABSOLUTELY NO WARRANTY\n"
6844 , applet_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006845}
6846
6847static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6848{
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01006849 if (!s || s > BC_STATUS_BEFORE_POSIX) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006850
Denys Vlasenkob8860a82018-12-03 00:26:12 +01006851 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006852 fprintf(stderr, " %s", file);
6853 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006854
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006855 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
Gavin Howard01055ba2018-11-03 11:00:21 -06006856}
6857
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006858#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06006859static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6860 const char *msg)
6861{
Denys Vlasenkob8860a82018-12-03 00:26:12 +01006862 const char *fmt;
Gavin Howard01055ba2018-11-03 11:00:21 -06006863
Denys Vlasenkob8860a82018-12-03 00:26:12 +01006864 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6865 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06006866
Denys Vlasenkob8860a82018-12-03 00:26:12 +01006867 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6868 fprintf(stderr, fmt, bc_err_msgs[s]);
Denys Vlasenko00d77792018-11-30 23:13:42 +01006869 if (msg) fprintf(stderr, " %s\n", msg);
6870 fprintf(stderr, " %s", file);
6871 fprintf(stderr, bc_err_line + 4 * !line, line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006872
Denys Vlasenkob8860a82018-12-03 00:26:12 +01006873 if (G.ttyin || !G_posix)
6874 s = BC_STATUS_SUCCESS;
6875 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006876}
6877
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006878static void bc_vm_envArgs(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006879{
Denys Vlasenko1f67e932018-12-03 00:08:59 +01006880 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6881
Gavin Howard01055ba2018-11-03 11:00:21 -06006882 BcVec v;
6883 char *env_args = getenv(bc_args_env_name), *buf;
6884
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01006885 if (!env_args) return;
Gavin Howard01055ba2018-11-03 11:00:21 -06006886
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006887 G.env_args = xstrdup(env_args);
6888 buf = G.env_args;
Gavin Howard01055ba2018-11-03 11:00:21 -06006889
6890 bc_vec_init(&v, sizeof(char *), NULL);
6891 bc_vec_push(&v, &bc_args_env_name);
6892
6893 while (*buf != 0) {
6894 if (!isspace(*buf)) {
6895 bc_vec_push(&v, &buf);
6896 while (*buf != 0 && !isspace(*buf)) ++buf;
6897 if (*buf != 0) (*(buf++)) = '\0';
6898 }
6899 else
6900 ++buf;
6901 }
6902
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006903 bc_args((int) v.len, (char **) v.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006904
6905 bc_vec_free(&v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006906}
6907#endif // ENABLE_BC
6908
6909static size_t bc_vm_envLen(const char *var)
6910{
6911 char *lenv = getenv(var);
6912 size_t i, len = BC_NUM_PRINT_WIDTH;
6913 int num;
6914
6915 if (!lenv) return len;
6916
6917 len = strlen(lenv);
6918
6919 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6920 if (num) {
6921 len = (size_t) atoi(lenv) - 1;
6922 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6923 }
6924 else
6925 len = BC_NUM_PRINT_WIDTH;
6926
6927 return len;
6928}
6929
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006930static BcStatus bc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006931{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006932 BcStatus s = bc_parse_text(&G.prs, text);
Gavin Howard01055ba2018-11-03 11:00:21 -06006933
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006934 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06006935 if (s) return s;
6936
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006937 while (G.prs.l.t.t != BC_LEX_EOF) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006938
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006939 s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06006940
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006941 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6942 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006943 }
6944
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006945 if (BC_PARSE_CAN_EXEC(&G.prs)) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01006946 s = bc_program_exec();
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006947 fflush_and_check();
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01006948 if (s)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006949 s = bc_vm_error(bc_program_reset(s), G.prs.l.f, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006950 }
6951
6952 return s;
6953}
6954
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006955static BcStatus bc_vm_file(const char *file)
Gavin Howard01055ba2018-11-03 11:00:21 -06006956{
6957 BcStatus s;
6958 char *data;
6959 BcFunc *main_func;
6960 BcInstPtr *ip;
6961
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006962 G.prog.file = file;
Denys Vlasenkodf515392018-12-02 19:27:48 +01006963 data = bc_read_file(file);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +01006964 if (!data) return bc_error("file '%s' is not text", file);
Gavin Howard01055ba2018-11-03 11:00:21 -06006965
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006966 bc_lex_file(&G.prs.l, file);
6967 s = bc_vm_process(data);
Gavin Howard01055ba2018-11-03 11:00:21 -06006968 if (s) goto err;
6969
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006970 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6971 ip = bc_vec_item(&G.prog.stack, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006972
6973 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6974
6975err:
6976 free(data);
6977 return s;
6978}
6979
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006980static BcStatus bc_vm_stdin(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006981{
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006982 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006983 BcVec buf, buffer;
Gavin Howard01055ba2018-11-03 11:00:21 -06006984 size_t len, i, str = 0;
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01006985 bool comment = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06006986
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01006987 G.prog.file = bc_program_stdin_name;
6988 bc_lex_file(&G.prs.l, bc_program_stdin_name);
Gavin Howard01055ba2018-11-03 11:00:21 -06006989
6990 bc_vec_init(&buffer, sizeof(char), NULL);
6991 bc_vec_init(&buf, sizeof(char), NULL);
6992 bc_vec_pushByte(&buffer, '\0');
6993
6994 // This loop is complex because the vm tries not to send any lines that end
6995 // with a backslash to the parser. The reason for that is because the parser
6996 // treats a backslash+newline combo as whitespace, per the bc spec. In that
6997 // case, and for strings and comments, the parser will expect more stuff.
Denys Vlasenkod4744ad2018-12-03 14:28:51 +01006998 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006999
7000 char *string = buf.v;
7001
7002 len = buf.len - 1;
7003
7004 if (len == 1) {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007005 if (str && buf.v[0] == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007006 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007007 else if (buf.v[0] == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007008 str += 1;
7009 }
7010 else if (len > 1 || comment) {
7011
7012 for (i = 0; i < len; ++i) {
7013
Denys Vlasenkoa0c421c2018-12-02 20:16:52 +01007014 bool notend = len > i + 1;
7015 char c = string[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06007016
7017 if (i - 1 > len || string[i - 1] != '\\') {
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007018 if (G.sbgn == G.send)
7019 str ^= c == G.sbgn;
7020 else if (c == G.send)
Gavin Howard01055ba2018-11-03 11:00:21 -06007021 str -= 1;
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007022 else if (c == G.sbgn)
Gavin Howard01055ba2018-11-03 11:00:21 -06007023 str += 1;
7024 }
7025
7026 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7027 comment = true;
7028 break;
7029 }
7030 else if (c == '*' && notend && comment && string[i + 1] == '/')
7031 comment = false;
7032 }
7033
7034 if (str || comment || string[len - 2] == '\\') {
7035 bc_vec_concat(&buffer, buf.v);
7036 continue;
7037 }
7038 }
7039
7040 bc_vec_concat(&buffer, buf.v);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007041 s = bc_vm_process(buffer.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06007042 if (s) goto err;
7043
7044 bc_vec_npop(&buffer, buffer.len);
7045 }
7046
Gavin Howard01055ba2018-11-03 11:00:21 -06007047 if (str)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007048 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7049 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007050 else if (comment)
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007051 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7052 G.prs.l.line);
Gavin Howard01055ba2018-11-03 11:00:21 -06007053
7054err:
7055 bc_vec_free(&buf);
7056 bc_vec_free(&buffer);
7057 return s;
7058}
7059
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007060static BcStatus bc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007061{
7062 BcStatus s = BC_STATUS_SUCCESS;
7063 size_t i;
7064
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007065#if ENABLE_BC
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007066 if (G.flags & BC_FLAG_L) {
Gavin Howard01055ba2018-11-03 11:00:21 -06007067
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007068 bc_lex_file(&G.prs.l, bc_lib_name);
7069 s = bc_parse_text(&G.prs, bc_lib);
Gavin Howard01055ba2018-11-03 11:00:21 -06007070
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007071 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
Gavin Howard01055ba2018-11-03 11:00:21 -06007072
7073 if (s) return s;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007074 s = bc_program_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007075 if (s) return s;
7076 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007077#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007078
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007079 for (i = 0; !s && i < G.files.len; ++i)
7080 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
Denys Vlasenkocfdc1332018-12-03 14:02:35 +01007081 if (s) return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007082
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007083 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7084 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
Gavin Howard01055ba2018-11-03 11:00:21 -06007085
Denys Vlasenko00d77792018-11-30 23:13:42 +01007086 return s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007087}
7088
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007089#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007090static void bc_program_free()
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007091{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007092 bc_num_free(&G.prog.ib);
7093 bc_num_free(&G.prog.ob);
7094 bc_num_free(&G.prog.hexb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007095# if ENABLE_DC
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007096 bc_num_free(&G.prog.strmb);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007097# endif
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007098 bc_vec_free(&G.prog.fns);
7099 bc_vec_free(&G.prog.fn_map);
7100 bc_vec_free(&G.prog.vars);
7101 bc_vec_free(&G.prog.var_map);
7102 bc_vec_free(&G.prog.arrs);
7103 bc_vec_free(&G.prog.arr_map);
7104 bc_vec_free(&G.prog.strs);
7105 bc_vec_free(&G.prog.consts);
7106 bc_vec_free(&G.prog.results);
7107 bc_vec_free(&G.prog.stack);
7108 bc_num_free(&G.prog.last);
7109 bc_num_free(&G.prog.zero);
7110 bc_num_free(&G.prog.one);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007111}
7112
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007113static void bc_vm_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007114{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007115 bc_vec_free(&G.files);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007116 bc_program_free();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007117 bc_parse_free(&G.prs);
7118 free(G.env_args);
Gavin Howard01055ba2018-11-03 11:00:21 -06007119}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007120#endif
7121
7122static void bc_program_init(size_t line_len)
7123{
7124 size_t idx;
7125 BcInstPtr ip;
7126
7127 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7128 memset(&ip, 0, sizeof(BcInstPtr));
7129
7130 /* G.prog.nchars = G.prog.scale = 0; - already is */
7131 G.prog.len = line_len;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007132
7133 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7134 bc_num_ten(&G.prog.ib);
7135 G.prog.ib_t = 10;
7136
7137 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7138 bc_num_ten(&G.prog.ob);
7139 G.prog.ob_t = 10;
7140
7141 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7142 bc_num_ten(&G.prog.hexb);
7143 G.prog.hexb.num[0] = 6;
7144
7145#if ENABLE_DC
7146 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7147 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7148#endif
7149
7150 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7151 bc_num_zero(&G.prog.last);
7152
7153 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7154 bc_num_zero(&G.prog.zero);
7155
7156 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7157 bc_num_one(&G.prog.one);
7158
7159 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7160 bc_map_init(&G.prog.fn_map);
7161
Denys Vlasenko1f67e932018-12-03 00:08:59 +01007162 bc_program_addFunc(xstrdup("(main)"), &idx);
7163 bc_program_addFunc(xstrdup("(read)"), &idx);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007164
7165 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7166 bc_map_init(&G.prog.var_map);
7167
7168 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7169 bc_map_init(&G.prog.arr_map);
7170
7171 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7172 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7173 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7174 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7175 bc_vec_push(&G.prog.stack, &ip);
7176}
Gavin Howard01055ba2018-11-03 11:00:21 -06007177
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007178static void bc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007179{
Gavin Howard01055ba2018-11-03 11:00:21 -06007180 size_t len = bc_vm_envLen(env_len);
Gavin Howard01055ba2018-11-03 11:00:21 -06007181
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007182#if ENABLE_FEATURE_BC_SIGNALS
7183 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007184#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007185
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007186 bc_vec_init(&G.files, sizeof(char *), NULL);
Gavin Howard01055ba2018-11-03 11:00:21 -06007187
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007188 if (IS_BC) {
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007189 if (getenv("POSIXLY_CORRECT"))
7190 G.flags |= BC_FLAG_S;
Denys Vlasenkoab3c5682018-12-02 16:32:36 +01007191 bc_vm_envArgs();
7192 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007193
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007194 bc_program_init(len);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007195 if (IS_BC) {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007196 bc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007197 } else {
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007198 dc_parse_init(&G.prs, BC_PROG_MAIN);
Denys Vlasenkof6c1da52018-12-02 17:36:00 +01007199 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007200}
7201
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007202static BcStatus bc_vm_run(int argc, char *argv[],
Gavin Howard01055ba2018-11-03 11:00:21 -06007203 const char *env_len)
7204{
7205 BcStatus st;
Gavin Howard01055ba2018-11-03 11:00:21 -06007206
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007207 bc_vm_init(env_len);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007208 bc_args(argc, argv);
Gavin Howard01055ba2018-11-03 11:00:21 -06007209
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007210 G.ttyin = isatty(0);
7211 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
Gavin Howard01055ba2018-11-03 11:00:21 -06007212
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007213 if (G.ttyin && !(G.flags & BC_FLAG_Q)) bc_vm_info();
7214 st = bc_vm_exec();
Gavin Howard01055ba2018-11-03 11:00:21 -06007215
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007216#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007217 bc_vm_free();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007218#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007219 return st;
7220}
7221
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007222#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007223int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7224int bc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007225{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007226 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007227 G.sbgn = G.send = '"';
Gavin Howard01055ba2018-11-03 11:00:21 -06007228
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007229 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007230}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007231#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007232
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007233#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007234int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7235int dc_main(int argc, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007236{
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007237 INIT_G();
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007238 G.sbgn = '[';
7239 G.send = ']';
Gavin Howard01055ba2018-11-03 11:00:21 -06007240
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007241 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007242}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007243#endif