blob: cc48ed3fe39572a9d5f1c88eea1bfa7dc2368799 [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.
Gavin Howardfa495ce2018-12-18 10:03:14 -07004 * Adapted from https://github.com/gavinhoward/bc
5 * Original code copyright (c) 2018 Gavin D. Howard and contributors.
Gavin Howard01055ba2018-11-03 11:00:21 -06006 */
Denys Vlasenko53799502019-01-25 14:24:03 +01007//TODO:
8// maybe implement a^b for non-integer b?
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01009
10#define DEBUG_LEXER 0
11#define DEBUG_COMPILE 0
12#define DEBUG_EXEC 0
13// This can be left enabled for production as well:
14#define SANITY_CHECKS 1
15
Gavin Howard01055ba2018-11-03 11:00:21 -060016//config:config BC
Denys Vlasenkob097a842018-12-28 03:20:17 +010017//config: bool "bc (45 kb)"
Gavin Howard01055ba2018-11-03 11:00:21 -060018//config: default y
Denys Vlasenkocdadad52018-12-28 15:13:23 +010019//config: select FEATURE_DC_BIG
Gavin Howard01055ba2018-11-03 11:00:21 -060020//config: help
21//config: bc is a command-line, arbitrary-precision calculator with a
22//config: Turing-complete language. See the GNU bc manual
23//config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
Denys Vlasenko89e785a2018-12-13 16:35:52 +010024//config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html).
Gavin Howard01055ba2018-11-03 11:00:21 -060025//config:
Denys Vlasenko89e785a2018-12-13 16:35:52 +010026//config: This bc has five differences to the GNU bc:
27//config: 1) The period (.) is a shortcut for "last", as in the BSD bc.
Gavin Howard01055ba2018-11-03 11:00:21 -060028//config: 2) Arrays are copied before being passed as arguments to
29//config: functions. This behavior is required by the bc spec.
30//config: 3) Arrays can be passed to the builtin "length" function to get
Denys Vlasenko89e785a2018-12-13 16:35:52 +010031//config: the number of elements in the array. This prints "1":
32//config: a[0] = 0; length(a[])
Gavin Howard01055ba2018-11-03 11:00:21 -060033//config: 4) The precedence of the boolean "not" operator (!) is equal to
Denys Vlasenko89e785a2018-12-13 16:35:52 +010034//config: that of the unary minus (-) negation operator. This still
Gavin Howard01055ba2018-11-03 11:00:21 -060035//config: allows POSIX-compliant scripts to work while somewhat
36//config: preserving expected behavior (versus C) and making parsing
37//config: easier.
Denys Vlasenko89e785a2018-12-13 16:35:52 +010038//config: 5) "read()" accepts expressions, not only numeric literals.
Gavin Howard01055ba2018-11-03 11:00:21 -060039//config:
Gavin Howard01055ba2018-11-03 11:00:21 -060040//config:config DC
Denys Vlasenkob097a842018-12-28 03:20:17 +010041//config: bool "dc (36 kb)"
Gavin Howard01055ba2018-11-03 11:00:21 -060042//config: default y
43//config: help
44//config: dc is a reverse-polish notation command-line calculator which
45//config: supports unlimited precision arithmetic. See the FreeBSD man page
46//config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
Denys Vlasenko89e785a2018-12-13 16:35:52 +010047//config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html).
Gavin Howard01055ba2018-11-03 11:00:21 -060048//config:
49//config: This dc has a few differences from the two above:
Denys Vlasenko89e785a2018-12-13 16:35:52 +010050//config: 1) When printing a byte stream (command "P"), this dc follows what
Gavin Howard01055ba2018-11-03 11:00:21 -060051//config: the FreeBSD dc does.
Denys Vlasenko89e785a2018-12-13 16:35:52 +010052//config: 2) Implements the GNU extensions for divmod ("~") and
Gavin Howard01055ba2018-11-03 11:00:21 -060053//config: modular exponentiation ("|").
Denys Vlasenko89e785a2018-12-13 16:35:52 +010054//config: 3) Implements all FreeBSD extensions, except for "J" and "M".
Gavin Howard01055ba2018-11-03 11:00:21 -060055//config: 4) Like the FreeBSD dc, this dc supports extended registers.
56//config: However, they are implemented differently. When it encounters
57//config: whitespace where a register should be, it skips the whitespace.
58//config: If the character following is not a lowercase letter, an error
59//config: is issued. Otherwise, the register name is parsed by the
Denys Vlasenko14767602018-12-27 22:52:13 +010060//config: following regex: [a-z][a-z0-9_]*
Gavin Howard01055ba2018-11-03 11:00:21 -060061//config: This generally means that register names will be surrounded by
Denys Vlasenko89e785a2018-12-13 16:35:52 +010062//config: whitespace. Examples:
63//config: l idx s temp L index S temp2 < do_thing
Gavin Howard01055ba2018-11-03 11:00:21 -060064//config: Also note that, like the FreeBSD dc, extended registers are not
65//config: allowed unless the "-x" option is given.
66//config:
Denys Vlasenko14767602018-12-27 22:52:13 +010067//config:if BC || DC # for menuconfig indenting
68//config:
69//config:config FEATURE_DC_BIG
70//config: bool "Use bc code base for dc (larger, more features)"
Denys Vlasenko14767602018-12-27 22:52:13 +010071//config: default y
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +010072//config:
73//config:config FEATURE_DC_LIBM
74//config: bool "Enable power and exp functions (requires libm)"
75//config: default y
Denys Vlasenko14767602018-12-27 22:52:13 +010076//config: depends on DC && !BC && !FEATURE_DC_BIG
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +010077//config: help
78//config: Enable power and exp functions.
79//config: NOTE: This will require libm to be present for linking.
80//config:
Denys Vlasenko14767602018-12-27 22:52:13 +010081//config:config FEATURE_BC_INTERACTIVE
Denys Vlasenko89e785a2018-12-13 16:35:52 +010082//config: bool "Interactive mode (+4kb)"
Gavin Howard01055ba2018-11-03 11:00:21 -060083//config: default y
Denys Vlasenko14767602018-12-27 22:52:13 +010084//config: depends on BC || (DC && FEATURE_DC_BIG)
Gavin Howard01055ba2018-11-03 11:00:21 -060085//config: help
Denys Vlasenko89e785a2018-12-13 16:35:52 +010086//config: Enable interactive mode: when started on a tty,
87//config: ^C interrupts execution and returns to command line,
88//config: errors also return to command line instead of exiting,
89//config: line editing with history is available.
90//config:
91//config: With this option off, input can still be taken from tty,
92//config: but all errors are fatal, ^C is fatal,
93//config: tty is treated exactly the same as any other
94//config: standard input (IOW: no line editing).
Gavin Howard01055ba2018-11-03 11:00:21 -060095//config:
96//config:config FEATURE_BC_LONG_OPTIONS
97//config: bool "Enable bc/dc long options"
98//config: default y
Denys Vlasenko14767602018-12-27 22:52:13 +010099//config: depends on BC || (DC && FEATURE_DC_BIG)
100//config:
101//config:endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600102
103//applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
104//applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
105
106//kbuild:lib-$(CONFIG_BC) += bc.o
107//kbuild:lib-$(CONFIG_DC) += bc.o
108
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100109//See www.gnu.org/software/bc/manual/bc.html
Gavin Howard01055ba2018-11-03 11:00:21 -0600110//usage:#define bc_trivial_usage
Denys Vlasenko09fe0aa2018-12-18 16:32:25 +0100111//usage: "[-sqlw] FILE..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600112//usage:
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100113//usage:#define bc_full_usage "\n"
114//usage: "\nArbitrary precision calculator"
115//usage: "\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100116///////: "\n -i Interactive" - has no effect for now
117//usage: "\n -q Quiet"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100118//usage: "\n -l Load standard math library"
119//usage: "\n -s Be POSIX compatible"
Denys Vlasenko9721f6c2018-12-02 20:34:03 +0100120//usage: "\n -w Warn if extensions are used"
121///////: "\n -v Version"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100122//usage: "\n"
Denys Vlasenko1a6a4822018-12-06 09:20:32 +0100123//usage: "\n$BC_LINE_LENGTH changes output width"
Gavin Howard01055ba2018-11-03 11:00:21 -0600124//usage:
125//usage:#define bc_example_usage
126//usage: "3 + 4.129\n"
127//usage: "1903 - 2893\n"
128//usage: "-129 * 213.28935\n"
129//usage: "12 / -1932\n"
130//usage: "12 % 12\n"
131//usage: "34 ^ 189\n"
132//usage: "scale = 13\n"
133//usage: "ibase = 2\n"
134//usage: "obase = A\n"
135//usage:
136//usage:#define dc_trivial_usage
Denys Vlasenko14767602018-12-27 22:52:13 +0100137//usage: IF_FEATURE_DC_BIG("[-x] ")"[-eSCRIPT]... [-fFILE]... [FILE]..."
Gavin Howard01055ba2018-11-03 11:00:21 -0600138//usage:
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100139//usage:#define dc_full_usage "\n"
140//usage: "\nTiny RPN calculator. Operations:"
Denys Vlasenko3d88cc12021-02-26 13:26:48 +0100141//usage: "\nArithmetic: + - * / % ^"
142//usage: IF_FEATURE_DC_BIG(
143//usage: "\n~ - divide with remainder"
144//usage: "\n| - modular exponentiation"
145//usage: "\nv - square root"
146//////// "\n_NNN - push neagtive number -NNN
147//////// "\n[string] - push string
148//////// "\nR - DC_LEX_POP pop and discard
149//////// "\nc - DC_LEX_CLEAR_STACK clear stack
150//////// "\nd - DC_LEX_DUPLICATE pop, push, push
151//////// "\nr - DC_LEX_SWAP pop 1, pop 2, push 1, push 2
152//////// "\n:r - DC_LEX_COLON pop index, pop value, store to array 'r'
153//////// "\n;r - DC_LEX_SCOLON pop index, fetch from array 'r', push
154//////// "\nLr - DC_LEX_LOAD_PO, pop register 'r', push
155//////// "\nSr - DC_LEX_STORE_PUSH pop, push to register 'r'
156//////// "\nlr - DC_LEX_LOAD read register 'r', push
157//////// "\nsr - DC_LEX_OP_ASSIGN pop, assign to register 'r'
158//////// "\n? - DC_LEX_READ read line and execute
159//////// "\nx - DC_LEX_EXECUTE pop string and execute
160//////// "\n<r - XC_LEX_OP_REL_GT pop, pop, execute register 'r' if top-of-stack was greater
161//////// "\n>r - XC_LEX_OP_REL_LT pop, pop, execute register 'r' if top-of-stack was less
162//////// "\n=r - XC_LEX_OP_REL_EQ pop, pop, execute register 'r' if equal
163//////// "\n!<r !>r !=r - negated forms
164//////// "\ne - DC_LEX_ELSE >tef: "if greater execute 't' else execute 'f'"
165//////// "\nQ - DC_LEX_NQUIT pop, "break N" from macro invocations
166//////// "\nq - DC_LEX_QUIT "break 2" (if less than 2 levels of macros, exit dc)
167//////// "\nX - DC_LEX_SCALE_FACTOR pop, push number of fractional digits
168//////// "\nZ - DC_LEX_LENGTH pop, push number of digits it has (or number of characters in string)
Denys Vlasenko1a37aa72021-02-26 14:48:04 +0100169//////// "\na - DC_LEX_ASCIIFY pop, push low-order byte as char or 1st char of string
170//////// "\n( - DC_LEX_LPAREN (not in GNU) pop, pop, if top-of-stack was less push 1 else push 0
171//////// "\n{ - DC_LEX_LBRACE (not in GNU) pop, pop, if top-of-stack was less-or-equal push 1 else push 0
172//////// "\nG - DC_LEX_EQ_NO_REG (not in GNU) pop, pop, if equal push 1 else push 0
173//////// "\nN - DC_LEX_OP_BOOL_NOT (not in GNU) pop, if 0 push 1 else push 0
Denys Vlasenko3d88cc12021-02-26 13:26:48 +0100174//////// "\n_ - XC_LEX_NEG (not a command - starts negative number)
Denys Vlasenko3d88cc12021-02-26 13:26:48 +0100175//////// "\nn - DC_LEX_PRINT_POP pop, print without newline
176//////// "\nP - DC_LEX_PRINT_STREAM pop, print string or hex bytes
177//usage: )
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100178//usage: "\np - print top of the stack without popping"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100179//usage: "\nf - print entire stack"
Denys Vlasenko3d88cc12021-02-26 13:26:48 +0100180//////// "\nz - DC_LEX_STACK_LEVEL push stack depth
181//////// "\nK - DC_LEX_SCALE push precision
182//////// "\nI - DC_LEX_IBASE push input radix
183//////// "\nO - DC_LEX_OBASE push output radix
184//usage: IF_FEATURE_DC_BIG(
185//usage: "\nk - pop the value and set precision"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100186//usage: "\ni - pop the value and set input radix"
Denys Vlasenko3d88cc12021-02-26 13:26:48 +0100187//usage: )
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100188//usage: "\no - pop the value and set output radix"
189//usage: "\nExamples: dc -e'2 2 + p' -> 4, dc -e'8 8 * 2 2 + / p' -> 16"
Gavin Howard01055ba2018-11-03 11:00:21 -0600190//usage:
191//usage:#define dc_example_usage
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100192//usage: "$ dc -e'2 2 + p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600193//usage: "4\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100194//usage: "$ dc -e'8 8 \\* 2 2 + / p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600195//usage: "16\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100196//usage: "$ dc -e'0 1 & p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600197//usage: "0\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100198//usage: "$ dc -e'0 1 | p'\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600199//usage: "1\n"
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100200//usage: "$ echo '72 9 / 8 * p' | dc\n"
Gavin Howard01055ba2018-11-03 11:00:21 -0600201//usage: "64\n"
202
203#include "libbb.h"
Denys Vlasenko95f93bd2018-12-06 10:29:12 +0100204#include "common_bufsiz.h"
Gavin Howard01055ba2018-11-03 11:00:21 -0600205
Denys Vlasenko14767602018-12-27 22:52:13 +0100206#if !ENABLE_BC && !ENABLE_FEATURE_DC_BIG
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +0100207# include "dc.c"
208#else
209
Denys Vlasenko2ea53a42018-12-14 17:51:17 +0100210#if DEBUG_LEXER
Denys Vlasenkod1d29b42018-12-16 16:03:03 +0100211static uint8_t lex_indent;
Denys Vlasenko2ea53a42018-12-14 17:51:17 +0100212#define dbg_lex(...) \
213 do { \
214 fprintf(stderr, "%*s", lex_indent, ""); \
215 bb_error_msg(__VA_ARGS__); \
216 } while (0)
217#define dbg_lex_enter(...) \
218 do { \
219 dbg_lex(__VA_ARGS__); \
220 lex_indent++; \
221 } while (0)
222#define dbg_lex_done(...) \
223 do { \
224 lex_indent--; \
225 dbg_lex(__VA_ARGS__); \
226 } while (0)
Denys Vlasenko0a238142018-12-14 16:48:34 +0100227#else
Denys Vlasenko2ea53a42018-12-14 17:51:17 +0100228# define dbg_lex(...) ((void)0)
229# define dbg_lex_enter(...) ((void)0)
230# define dbg_lex_done(...) ((void)0)
Denys Vlasenko0a238142018-12-14 16:48:34 +0100231#endif
232
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +0100233#if DEBUG_COMPILE
234# define dbg_compile(...) bb_error_msg(__VA_ARGS__)
235#else
236# define dbg_compile(...) ((void)0)
237#endif
238
Denys Vlasenko99b37622018-12-15 20:06:59 +0100239#if DEBUG_EXEC
240# define dbg_exec(...) bb_error_msg(__VA_ARGS__)
241#else
242# define dbg_exec(...) ((void)0)
243#endif
244
Gavin Howard01055ba2018-11-03 11:00:21 -0600245typedef enum BcStatus {
Denys Vlasenko60cf7472018-12-04 20:05:28 +0100246 BC_STATUS_SUCCESS = 0,
247 BC_STATUS_FAILURE = 1,
Gavin Howard01055ba2018-11-03 11:00:21 -0600248} BcStatus;
249
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100250#define BC_VEC_INVALID_IDX ((size_t) -1)
251#define BC_VEC_START_CAP (1 << 5)
Gavin Howard01055ba2018-11-03 11:00:21 -0600252
Denys Vlasenko5ba55f12018-12-10 15:37:14 +0100253typedef void (*BcVecFree)(void *) FAST_FUNC;
Gavin Howard01055ba2018-11-03 11:00:21 -0600254
255typedef struct BcVec {
256 char *v;
257 size_t len;
258 size_t cap;
259 size_t size;
260 BcVecFree dtor;
261} BcVec;
262
Gavin Howard01055ba2018-11-03 11:00:21 -0600263typedef signed char BcDig;
264
265typedef struct BcNum {
266 BcDig *restrict num;
267 size_t rdx;
268 size_t len;
269 size_t cap;
270 bool neg;
271} BcNum;
272
Denys Vlasenko680ccd32018-12-31 19:42:13 +0100273#define BC_NUM_MAX_IBASE 36
Denys Vlasenko2fa11b62018-12-06 12:34:39 +0100274// larger value might speed up BIGNUM calculations a bit:
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100275#define BC_NUM_DEF_SIZE 16
Denys Vlasenko29a90432020-12-29 18:50:56 +0100276#define BC_NUM_PRINT_WIDTH 70
Gavin Howard01055ba2018-11-03 11:00:21 -0600277
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100278#define BC_NUM_KARATSUBA_LEN 32
Gavin Howard01055ba2018-11-03 11:00:21 -0600279
Gavin Howard01055ba2018-11-03 11:00:21 -0600280typedef enum BcInst {
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100281#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600282 BC_INST_INC_PRE,
283 BC_INST_DEC_PRE,
284 BC_INST_INC_POST,
285 BC_INST_DEC_POST,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100286#endif
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100287 XC_INST_NEG, // order
Gavin Howard01055ba2018-11-03 11:00:21 -0600288
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100289 XC_INST_REL_EQ, // should
290 XC_INST_REL_LE, // match
291 XC_INST_REL_GE, // LEX
292 XC_INST_REL_NE, // constants
293 XC_INST_REL_LT, // for
294 XC_INST_REL_GT, // these
Gavin Howard01055ba2018-11-03 11:00:21 -0600295
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100296 XC_INST_POWER, // operations
297 XC_INST_MULTIPLY, // |
298 XC_INST_DIVIDE, // |
299 XC_INST_MODULUS, // |
300 XC_INST_PLUS, // |
301 XC_INST_MINUS, // |
Gavin Howard01055ba2018-11-03 11:00:21 -0600302
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100303 XC_INST_BOOL_NOT, // |
304 XC_INST_BOOL_OR, // |
305 XC_INST_BOOL_AND, // |
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100306#if ENABLE_BC
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100307 BC_INST_ASSIGN_POWER, // |
308 BC_INST_ASSIGN_MULTIPLY,// |
309 BC_INST_ASSIGN_DIVIDE, // |
310 BC_INST_ASSIGN_MODULUS, // |
311 BC_INST_ASSIGN_PLUS, // |
312 BC_INST_ASSIGN_MINUS, // |
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100313#endif
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100314 XC_INST_ASSIGN, // V
Gavin Howard01055ba2018-11-03 11:00:21 -0600315
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100316 XC_INST_NUM,
317 XC_INST_VAR,
318 XC_INST_ARRAY_ELEM,
319 XC_INST_ARRAY,
320 XC_INST_SCALE_FUNC,
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100321
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100322 XC_INST_IBASE, // order of these constans should match other enums
323 XC_INST_OBASE, // order of these constans should match other enums
324 XC_INST_SCALE, // order of these constans should match other enums
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100325 IF_BC(BC_INST_LAST,) // order of these constans should match other enums
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100326 XC_INST_LENGTH,
327 XC_INST_READ,
328 XC_INST_SQRT,
Gavin Howard01055ba2018-11-03 11:00:21 -0600329
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100330 XC_INST_PRINT,
331 XC_INST_PRINT_POP,
332 XC_INST_STR,
333 XC_INST_PRINT_STR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600334
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100335#if ENABLE_BC
Denys Vlasenko39287e02018-12-22 02:23:08 +0100336 BC_INST_HALT,
Gavin Howard01055ba2018-11-03 11:00:21 -0600337 BC_INST_JUMP,
338 BC_INST_JUMP_ZERO,
339
340 BC_INST_CALL,
Gavin Howard01055ba2018-11-03 11:00:21 -0600341 BC_INST_RET0,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100342#endif
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100343 XC_INST_RET,
Gavin Howard01055ba2018-11-03 11:00:21 -0600344
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100345 XC_INST_POP,
Denys Vlasenko8c1e7232018-12-22 01:34:10 +0100346#if ENABLE_DC
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100347 DC_INST_POP_EXEC,
Gavin Howard01055ba2018-11-03 11:00:21 -0600348
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100349 DC_INST_MODEXP,
350 DC_INST_DIVMOD,
Gavin Howard01055ba2018-11-03 11:00:21 -0600351
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100352 DC_INST_EXECUTE,
353 DC_INST_EXEC_COND,
Gavin Howard01055ba2018-11-03 11:00:21 -0600354
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100355 DC_INST_ASCIIFY,
356 DC_INST_PRINT_STREAM,
Gavin Howard01055ba2018-11-03 11:00:21 -0600357
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100358 DC_INST_PRINT_STACK,
359 DC_INST_CLEAR_STACK,
360 DC_INST_STACK_LEN,
361 DC_INST_DUPLICATE,
362 DC_INST_SWAP,
Gavin Howard01055ba2018-11-03 11:00:21 -0600363
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100364 DC_INST_LOAD,
365 DC_INST_PUSH_VAR,
366 DC_INST_PUSH_TO_VAR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600367
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100368 DC_INST_QUIT,
369 DC_INST_NQUIT,
Gavin Howard01055ba2018-11-03 11:00:21 -0600370
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100371 DC_INST_INVALID = -1,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100372#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600373} BcInst;
374
375typedef struct BcId {
376 char *name;
377 size_t idx;
378} BcId;
379
380typedef struct BcFunc {
381 BcVec code;
Denys Vlasenko503faf92018-12-20 16:24:18 +0100382 IF_BC(BcVec labels;)
383 IF_BC(BcVec autos;)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +0100384 IF_BC(BcVec strs;)
385 IF_BC(BcVec consts;)
Denys Vlasenko503faf92018-12-20 16:24:18 +0100386 IF_BC(size_t nparams;)
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +0100387 IF_BC(bool voidfunc;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600388} BcFunc;
389
390typedef enum BcResultType {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +0100391 XC_RESULT_TEMP,
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +0100392 IF_BC(BC_RESULT_VOID,) // same as TEMP, but INST_PRINT will ignore it
Gavin Howard01055ba2018-11-03 11:00:21 -0600393
Denys Vlasenkod897c9a2018-12-24 23:41:31 +0100394 XC_RESULT_VAR,
395 XC_RESULT_ARRAY_ELEM,
396 XC_RESULT_ARRAY,
Gavin Howard01055ba2018-11-03 11:00:21 -0600397
Denys Vlasenkod897c9a2018-12-24 23:41:31 +0100398 XC_RESULT_STR,
Gavin Howard01055ba2018-11-03 11:00:21 -0600399
Denys Vlasenkod897c9a2018-12-24 23:41:31 +0100400 //code uses "inst - XC_INST_IBASE + XC_RESULT_IBASE" construct,
401 XC_RESULT_IBASE, // relative order should match for: XC_INST_IBASE
402 XC_RESULT_OBASE, // relative order should match for: XC_INST_OBASE
403 XC_RESULT_SCALE, // relative order should match for: XC_INST_SCALE
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100404 IF_BC(BC_RESULT_LAST,) // relative order should match for: BC_INST_LAST
Denys Vlasenkod897c9a2018-12-24 23:41:31 +0100405 XC_RESULT_CONSTANT,
406 IF_BC(BC_RESULT_ONE,)
Gavin Howard01055ba2018-11-03 11:00:21 -0600407} BcResultType;
408
409typedef union BcResultData {
410 BcNum n;
411 BcVec v;
412 BcId id;
413} BcResultData;
414
415typedef struct BcResult {
416 BcResultType t;
417 BcResultData d;
418} BcResult;
419
420typedef struct BcInstPtr {
421 size_t func;
Denys Vlasenko24e41942018-12-21 23:01:26 +0100422 size_t inst_idx;
Gavin Howard01055ba2018-11-03 11:00:21 -0600423} BcInstPtr;
424
Denys Vlasenko53799502019-01-25 14:24:03 +0100425typedef enum BcType {
426 BC_TYPE_VAR,
427 BC_TYPE_ARRAY,
428 BC_TYPE_REF,
429} BcType;
430
Gavin Howard01055ba2018-11-03 11:00:21 -0600431typedef enum BcLexType {
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100432 XC_LEX_EOF,
433 XC_LEX_INVALID,
Gavin Howard01055ba2018-11-03 11:00:21 -0600434
Denys Vlasenko23ea0732018-12-24 15:05:49 +0100435 XC_LEX_NLINE,
436 XC_LEX_WHITESPACE,
437 XC_LEX_STR,
438 XC_LEX_NAME,
439 XC_LEX_NUMBER,
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100440
Denys Vlasenko69560f42018-12-24 14:14:23 +0100441 XC_LEX_1st_op,
442 XC_LEX_NEG = XC_LEX_1st_op, // order
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100443
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100444 XC_LEX_OP_REL_EQ, // should
445 XC_LEX_OP_REL_LE, // match
446 XC_LEX_OP_REL_GE, // INST
447 XC_LEX_OP_REL_NE, // constants
448 XC_LEX_OP_REL_LT, // for
449 XC_LEX_OP_REL_GT, // these
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100450
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100451 XC_LEX_OP_POWER, // operations
452 XC_LEX_OP_MULTIPLY, // |
453 XC_LEX_OP_DIVIDE, // |
454 XC_LEX_OP_MODULUS, // |
455 XC_LEX_OP_PLUS, // |
456 XC_LEX_OP_MINUS, // |
457 XC_LEX_OP_last = XC_LEX_OP_MINUS,
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100458#if ENABLE_BC
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100459 BC_LEX_OP_BOOL_NOT, // |
460 BC_LEX_OP_BOOL_OR, // |
461 BC_LEX_OP_BOOL_AND, // |
462
463 BC_LEX_OP_ASSIGN_POWER, // |
464 BC_LEX_OP_ASSIGN_MULTIPLY, // |
465 BC_LEX_OP_ASSIGN_DIVIDE, // |
466 BC_LEX_OP_ASSIGN_MODULUS, // |
467 BC_LEX_OP_ASSIGN_PLUS, // |
468 BC_LEX_OP_ASSIGN_MINUS, // |
469
470 BC_LEX_OP_ASSIGN, // V
471
Gavin Howard01055ba2018-11-03 11:00:21 -0600472 BC_LEX_OP_INC,
473 BC_LEX_OP_DEC,
474
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100475 BC_LEX_LPAREN, // () are 0x28 and 0x29
476 BC_LEX_RPAREN, // must be LPAREN+1: code uses (c - '(' + BC_LEX_LPAREN)
Gavin Howard01055ba2018-11-03 11:00:21 -0600477
Denys Vlasenko10bde142018-12-27 18:23:58 +0100478 BC_LEX_LBRACKET, // [] are 0x5B and 0x5D
Gavin Howard01055ba2018-11-03 11:00:21 -0600479 BC_LEX_COMMA,
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100480 BC_LEX_RBRACKET, // must be LBRACKET+2: code uses (c - '[' + BC_LEX_LBRACKET)
Gavin Howard01055ba2018-11-03 11:00:21 -0600481
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100482 BC_LEX_LBRACE, // {} are 0x7B and 0x7D
Gavin Howard01055ba2018-11-03 11:00:21 -0600483 BC_LEX_SCOLON,
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100484 BC_LEX_RBRACE, // must be LBRACE+2: code uses (c - '{' + BC_LEX_LBRACE)
Gavin Howard01055ba2018-11-03 11:00:21 -0600485
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100486 BC_LEX_KEY_1st_keyword,
487 BC_LEX_KEY_AUTO = BC_LEX_KEY_1st_keyword,
Gavin Howard01055ba2018-11-03 11:00:21 -0600488 BC_LEX_KEY_BREAK,
489 BC_LEX_KEY_CONTINUE,
490 BC_LEX_KEY_DEFINE,
491 BC_LEX_KEY_ELSE,
492 BC_LEX_KEY_FOR,
493 BC_LEX_KEY_HALT,
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100494 // code uses "type - BC_LEX_KEY_IBASE + XC_INST_IBASE" construct,
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100495 BC_LEX_KEY_IBASE, // relative order should match for: XC_INST_IBASE
496 BC_LEX_KEY_OBASE, // relative order should match for: XC_INST_OBASE
Gavin Howard01055ba2018-11-03 11:00:21 -0600497 BC_LEX_KEY_IF,
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100498 BC_LEX_KEY_LAST, // relative order should match for: BC_INST_LAST
Gavin Howard01055ba2018-11-03 11:00:21 -0600499 BC_LEX_KEY_LENGTH,
500 BC_LEX_KEY_LIMITS,
Gavin Howard01055ba2018-11-03 11:00:21 -0600501 BC_LEX_KEY_PRINT,
502 BC_LEX_KEY_QUIT,
503 BC_LEX_KEY_READ,
504 BC_LEX_KEY_RETURN,
505 BC_LEX_KEY_SCALE,
506 BC_LEX_KEY_SQRT,
507 BC_LEX_KEY_WHILE,
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100508#endif // ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -0600509
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100510#if ENABLE_DC
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100511 DC_LEX_OP_BOOL_NOT = XC_LEX_OP_last + 1,
512 DC_LEX_OP_ASSIGN,
513
514 DC_LEX_LPAREN,
515 DC_LEX_SCOLON,
516 DC_LEX_READ,
517 DC_LEX_IBASE,
518 DC_LEX_SCALE,
519 DC_LEX_OBASE,
520 DC_LEX_LENGTH,
521 DC_LEX_PRINT,
522 DC_LEX_QUIT,
523 DC_LEX_SQRT,
524 DC_LEX_LBRACE,
525
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100526 DC_LEX_EQ_NO_REG,
527 DC_LEX_OP_MODEXP,
528 DC_LEX_OP_DIVMOD,
Gavin Howard01055ba2018-11-03 11:00:21 -0600529
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100530 DC_LEX_COLON,
531 DC_LEX_ELSE,
532 DC_LEX_EXECUTE,
533 DC_LEX_PRINT_STACK,
534 DC_LEX_CLEAR_STACK,
535 DC_LEX_STACK_LEVEL,
536 DC_LEX_DUPLICATE,
537 DC_LEX_SWAP,
538 DC_LEX_POP,
Gavin Howard01055ba2018-11-03 11:00:21 -0600539
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100540 DC_LEX_ASCIIFY,
541 DC_LEX_PRINT_STREAM,
Gavin Howard01055ba2018-11-03 11:00:21 -0600542
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100543 // code uses "t - DC_LEX_STORE_IBASE + XC_INST_IBASE" construct,
544 DC_LEX_STORE_IBASE, // relative order should match for: XC_INST_IBASE
545 DC_LEX_STORE_OBASE, // relative order should match for: XC_INST_OBASE
546 DC_LEX_STORE_SCALE, // relative order should match for: XC_INST_SCALE
547 DC_LEX_LOAD,
548 DC_LEX_LOAD_POP,
549 DC_LEX_STORE_PUSH,
550 DC_LEX_PRINT_POP,
551 DC_LEX_NQUIT,
552 DC_LEX_SCALE_FACTOR,
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100553#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600554} BcLexType;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100555// must match order of BC_LEX_KEY_foo etc above
556#if ENABLE_BC
557struct BcLexKeyword {
558 char name8[8];
559};
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100560#define LEX_KW_ENTRY(a, b) \
Denys Vlasenkod00d2f92018-12-06 12:59:40 +0100561 { .name8 = a /*, .posix = b */ }
Denys Vlasenko6cc49622020-11-30 14:58:02 +0100562static const struct BcLexKeyword bc_lex_kws[20] ALIGN8 = {
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100563 LEX_KW_ENTRY("auto" , 1), // 0
564 LEX_KW_ENTRY("break" , 1), // 1
565 LEX_KW_ENTRY("continue", 0), // 2 note: this one has no terminating NUL
566 LEX_KW_ENTRY("define" , 1), // 3
567 LEX_KW_ENTRY("else" , 0), // 4
568 LEX_KW_ENTRY("for" , 1), // 5
569 LEX_KW_ENTRY("halt" , 0), // 6
570 LEX_KW_ENTRY("ibase" , 1), // 7
571 LEX_KW_ENTRY("obase" , 1), // 8
572 LEX_KW_ENTRY("if" , 1), // 9
573 LEX_KW_ENTRY("last" , 0), // 10
574 LEX_KW_ENTRY("length" , 1), // 11
575 LEX_KW_ENTRY("limits" , 0), // 12
576 LEX_KW_ENTRY("print" , 0), // 13
577 LEX_KW_ENTRY("quit" , 1), // 14
578 LEX_KW_ENTRY("read" , 0), // 15
579 LEX_KW_ENTRY("return" , 1), // 16
580 LEX_KW_ENTRY("scale" , 1), // 17
581 LEX_KW_ENTRY("sqrt" , 1), // 18
582 LEX_KW_ENTRY("while" , 1), // 19
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100583};
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100584#undef LEX_KW_ENTRY
Denys Vlasenko59d4ce92018-12-17 10:42:31 +0100585#define STRING_else (bc_lex_kws[4].name8)
Denys Vlasenko59d4ce92018-12-17 10:42:31 +0100586#define STRING_for (bc_lex_kws[5].name8)
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100587#define STRING_if (bc_lex_kws[9].name8)
588#define STRING_while (bc_lex_kws[19].name8)
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100589enum {
590 POSIX_KWORD_MASK = 0
Denys Vlasenko82269122018-12-14 16:30:56 +0100591 | (1 << 0) // 0
592 | (1 << 1) // 1
593 | (0 << 2) // 2
594 | (1 << 3) // 3
595 | (0 << 4) // 4
596 | (1 << 5) // 5
597 | (0 << 6) // 6
598 | (1 << 7) // 7
599 | (1 << 8) // 8
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100600 | (1 << 9) // 9
601 | (0 << 10) // 10
602 | (1 << 11) // 11
603 | (0 << 12) // 12
Denys Vlasenko82269122018-12-14 16:30:56 +0100604 | (0 << 13) // 13
605 | (1 << 14) // 14
606 | (0 << 15) // 15
607 | (1 << 16) // 16
608 | (1 << 17) // 17
609 | (1 << 18) // 18
610 | (1 << 19) // 19
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100611};
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100612#define keyword_is_POSIX(i) ((1 << (i)) & POSIX_KWORD_MASK)
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100613
614// This is a bit array that corresponds to token types. An entry is
615// true if the token is valid in an expression, false otherwise.
616// Used to figure out when expr parsing should stop *without error message*
617// - 0 element indicates this condition. 1 means "this token is to be eaten
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100618// as part of the expression", it can then still be determined to be invalid
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100619// by later processing.
620enum {
621#define EXBITS(a,b,c,d,e,f,g,h) \
622 ((uint64_t)((a << 0)+(b << 1)+(c << 2)+(d << 3)+(e << 4)+(f << 5)+(g << 6)+(h << 7)))
Denys Vlasenkoad0bd382018-12-24 00:50:32 +0100623 BC_PARSE_EXPRS_BITS = 0 // corresponding BC_LEX_xyz:
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100624 + (EXBITS(0,0,0,0,0,1,1,1) << (0*8)) // 0: EOF INVAL NL WS STR NAME NUM -
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100625 + (EXBITS(1,1,1,1,1,1,1,1) << (1*8)) // 8: == <= >= != < > ^ *
626 + (EXBITS(1,1,1,1,1,1,1,1) << (2*8)) // 16: / % + - ! || && ^=
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100627 + (EXBITS(1,1,1,1,1,1,1,1) << (3*8)) // 24: *= /= %= += -= = ++ --
628 + (EXBITS(1,1,0,0,0,0,0,0) << (4*8)) // 32: ( ) [ , ] { ; }
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100629 + (EXBITS(0,0,0,0,0,0,0,1) << (5*8)) // 40: auto break cont define else for halt ibase
630 + (EXBITS(1,0,1,1,0,0,0,1) << (6*8)) // 48: obase if last length limits print quit read
631 + (EXBITS(0,1,1,0,0,0,0,0) << (7*8)) // 56: return scale sqrt while
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100632#undef EXBITS
633};
Denys Vlasenkod0238d82018-12-25 01:21:16 +0100634static ALWAYS_INLINE long lex_allowed_in_bc_expr(unsigned i)
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100635{
636#if ULONG_MAX > 0xffffffff
637 // 64-bit version (will not work correctly for 32-bit longs!)
638 return BC_PARSE_EXPRS_BITS & (1UL << i);
639#else
640 // 32-bit version
641 unsigned long m = (uint32_t)BC_PARSE_EXPRS_BITS;
642 if (i >= 32) {
643 m = (uint32_t)(BC_PARSE_EXPRS_BITS >> 32);
644 i &= 31;
645 }
646 return m & (1UL << i);
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +0100647#endif
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100648}
649
650// This is an array of data for operators that correspond to
Denys Vlasenko69560f42018-12-24 14:14:23 +0100651// [XC_LEX_1st_op...] token types.
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100652static const uint8_t bc_ops_prec_and_assoc[] ALIGN1 = {
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100653#define OP(p,l) ((int)(l) * 0x10 + (p))
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100654 OP(1, false), // neg
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +0100655 OP(6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), OP( 6, true ), // == <= >= != < >
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100656 OP(2, false), // pow
657 OP(3, true ), OP( 3, true ), OP( 3, true ), // mul div mod
658 OP(4, true ), OP( 4, true ), // + -
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100659 OP(1, false), // not
660 OP(7, true ), OP( 7, true ), // or and
661 OP(5, false), OP( 5, false ), OP( 5, false ), OP( 5, false ), OP( 5, false ), // ^= *= /= %= +=
662 OP(5, false), OP( 5, false ), // -= =
Denys Vlasenkoabf6cf62018-12-24 13:20:57 +0100663 OP(0, false), OP( 0, false ), // inc dec
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100664#undef OP
665};
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100666#define bc_operation_PREC(i) (bc_ops_prec_and_assoc[i] & 0x0f)
667#define bc_operation_LEFT(i) (bc_ops_prec_and_assoc[i] & 0x10)
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100668#endif // ENABLE_BC
669
670#if ENABLE_DC
Denys Vlasenko73b2c602018-12-24 01:02:59 +0100671static const //BcLexType - should be this type
672uint8_t
Denys Vlasenko2beb1f62018-12-26 21:17:12 +0100673dc_char_to_LEX[] ALIGN1 = {
Denys Vlasenko10bde142018-12-27 18:23:58 +0100674 // %&'(
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100675 XC_LEX_OP_MODULUS, XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_LPAREN,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100676 // )*+,
Denys Vlasenko69560f42018-12-24 14:14:23 +0100677 XC_LEX_INVALID, XC_LEX_OP_MULTIPLY, XC_LEX_OP_PLUS, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100678 // -./
Denys Vlasenko69560f42018-12-24 14:14:23 +0100679 XC_LEX_OP_MINUS, XC_LEX_INVALID, XC_LEX_OP_DIVIDE,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100680 // 0123456789
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100681 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
682 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
683 XC_LEX_INVALID, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100684 // :;<=>?@
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100685 DC_LEX_COLON, DC_LEX_SCOLON, XC_LEX_OP_REL_GT, XC_LEX_OP_REL_EQ,
686 XC_LEX_OP_REL_LT, DC_LEX_READ, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100687 // ABCDEFGH
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100688 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
689 XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_EQ_NO_REG, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100690 // IJKLMNOP
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100691 DC_LEX_IBASE, XC_LEX_INVALID, DC_LEX_SCALE, DC_LEX_LOAD_POP,
692 XC_LEX_INVALID, DC_LEX_OP_BOOL_NOT, DC_LEX_OBASE, DC_LEX_PRINT_STREAM,
Denys Vlasenkof11b5b92019-01-04 15:54:40 +0100693 // QRSTUVWX
694 DC_LEX_NQUIT, DC_LEX_POP, DC_LEX_STORE_PUSH, XC_LEX_INVALID,
695 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID, DC_LEX_SCALE_FACTOR,
696 // YZ
697 XC_LEX_INVALID, DC_LEX_LENGTH,
698 // [\]
699 XC_LEX_INVALID, XC_LEX_INVALID, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100700 // ^_`
Denys Vlasenko69560f42018-12-24 14:14:23 +0100701 XC_LEX_OP_POWER, XC_LEX_NEG, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100702 // abcdefgh
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100703 DC_LEX_ASCIIFY, XC_LEX_INVALID, DC_LEX_CLEAR_STACK, DC_LEX_DUPLICATE,
704 DC_LEX_ELSE, DC_LEX_PRINT_STACK, XC_LEX_INVALID, XC_LEX_INVALID,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100705 // ijklmnop
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100706 DC_LEX_STORE_IBASE, XC_LEX_INVALID, DC_LEX_STORE_SCALE, DC_LEX_LOAD,
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100707 XC_LEX_INVALID, DC_LEX_PRINT_POP, DC_LEX_STORE_OBASE, DC_LEX_PRINT,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100708 // qrstuvwx
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100709 DC_LEX_QUIT, DC_LEX_SWAP, DC_LEX_OP_ASSIGN, XC_LEX_INVALID,
710 XC_LEX_INVALID, DC_LEX_SQRT, XC_LEX_INVALID, DC_LEX_EXECUTE,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100711 // yz
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +0100712 XC_LEX_INVALID, DC_LEX_STACK_LEVEL,
Denys Vlasenko10bde142018-12-27 18:23:58 +0100713 // {|}~
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100714 DC_LEX_LBRACE, DC_LEX_OP_MODEXP, XC_LEX_INVALID, DC_LEX_OP_DIVMOD,
Denys Vlasenko73b2c602018-12-24 01:02:59 +0100715};
Denys Vlasenkoa7732d12018-12-24 04:26:07 +0100716static const //BcInst - should be this type. Using signed narrow type since DC_INST_INVALID is -1
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100717int8_t
Denys Vlasenko10bde142018-12-27 18:23:58 +0100718dc_LEX_to_INST[] ALIGN1 = { //starts at XC_LEX_OP_POWER // corresponding XC/DC_LEX_xyz:
719 XC_INST_POWER, XC_INST_MULTIPLY, // XC_LEX_OP_POWER XC_LEX_OP_MULTIPLY
720 XC_INST_DIVIDE, XC_INST_MODULUS, // XC_LEX_OP_DIVIDE XC_LEX_OP_MODULUS
721 XC_INST_PLUS, XC_INST_MINUS, // XC_LEX_OP_PLUS XC_LEX_OP_MINUS
Denys Vlasenko4accb6b2018-12-24 15:29:08 +0100722 XC_INST_BOOL_NOT, // DC_LEX_OP_BOOL_NOT
723 DC_INST_INVALID, // DC_LEX_OP_ASSIGN
724 XC_INST_REL_GT, // DC_LEX_LPAREN
725 DC_INST_INVALID, // DC_LEX_SCOLON
726 DC_INST_INVALID, // DC_LEX_READ
727 XC_INST_IBASE, // DC_LEX_IBASE
728 XC_INST_SCALE, // DC_LEX_SCALE
729 XC_INST_OBASE, // DC_LEX_OBASE
730 XC_INST_LENGTH, // DC_LEX_LENGTH
731 XC_INST_PRINT, // DC_LEX_PRINT
732 DC_INST_QUIT, // DC_LEX_QUIT
733 XC_INST_SQRT, // DC_LEX_SQRT
734 XC_INST_REL_GE, // DC_LEX_LBRACE
735 XC_INST_REL_EQ, // DC_LEX_EQ_NO_REG
Denys Vlasenko10bde142018-12-27 18:23:58 +0100736 DC_INST_MODEXP, DC_INST_DIVMOD, // DC_LEX_OP_MODEXP DC_LEX_OP_DIVMOD
737 DC_INST_INVALID, DC_INST_INVALID, // DC_LEX_COLON DC_LEX_ELSE
738 DC_INST_EXECUTE, // DC_LEX_EXECUTE
739 DC_INST_PRINT_STACK, DC_INST_CLEAR_STACK, // DC_LEX_PRINT_STACK DC_LEX_CLEAR_STACK
740 DC_INST_STACK_LEN, DC_INST_DUPLICATE, // DC_LEX_STACK_LEVEL DC_LEX_DUPLICATE
741 DC_INST_SWAP, XC_INST_POP, // DC_LEX_SWAP DC_LEX_POP
742 DC_INST_ASCIIFY, DC_INST_PRINT_STREAM, // DC_LEX_ASCIIFY DC_LEX_PRINT_STREAM
743 DC_INST_INVALID, DC_INST_INVALID, // DC_LEX_STORE_IBASE DC_LEX_STORE_OBASE
744 DC_INST_INVALID, DC_INST_INVALID, // DC_LEX_STORE_SCALE DC_LEX_LOAD
745 DC_INST_INVALID, DC_INST_INVALID, // DC_LEX_LOAD_POP DC_LEX_STORE_PUSH
746 XC_INST_PRINT, DC_INST_NQUIT, // DC_LEX_PRINT_POP DC_LEX_NQUIT
747 XC_INST_SCALE_FUNC, // DC_LEX_SCALE_FACTOR
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +0100748 // DC_INST_INVALID in this table either means that corresponding LEX
749 // is not possible for dc, or that it does not compile one-to-one
750 // to a single INST.
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +0100751};
752#endif // ENABLE_DC
753
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +0100754typedef struct BcParse {
Denys Vlasenko6e618232018-12-25 22:20:14 +0100755 smallint lex; // was BcLexType // first member is most used
756 smallint lex_last; // was BcLexType
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100757 size_t lex_line;
Denys Vlasenko6e618232018-12-25 22:20:14 +0100758 const char *lex_inbuf;
759 const char *lex_next_at; // last lex_next() was called at this string
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +0100760 const char *lex_filename;
761 FILE *lex_input_fp;
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +0100762 BcVec lex_strnumbuf;
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +0100763
Gavin Howard01055ba2018-11-03 11:00:21 -0600764 BcFunc *func;
765 size_t fidx;
Denys Vlasenko503faf92018-12-20 16:24:18 +0100766 IF_BC(size_t in_funcdef;)
Denys Vlasenko6e618232018-12-25 22:20:14 +0100767 IF_BC(BcVec exits;)
768 IF_BC(BcVec conds;)
769 IF_BC(BcVec ops;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600770} BcParse;
771
Gavin Howard01055ba2018-11-03 11:00:21 -0600772typedef struct BcProgram {
Gavin Howard01055ba2018-11-03 11:00:21 -0600773 size_t len;
Denys Vlasenko503faf92018-12-20 16:24:18 +0100774 size_t nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -0600775
Denys Vlasenko503faf92018-12-20 16:24:18 +0100776 size_t scale;
Gavin Howard01055ba2018-11-03 11:00:21 -0600777 size_t ib_t;
Gavin Howard01055ba2018-11-03 11:00:21 -0600778 size_t ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -0600779
Gavin Howard01055ba2018-11-03 11:00:21 -0600780 BcVec results;
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +0100781 BcVec exestack;
Gavin Howard01055ba2018-11-03 11:00:21 -0600782
783 BcVec fns;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +0100784 IF_BC(BcVec fn_map;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600785
786 BcVec vars;
787 BcVec var_map;
788
789 BcVec arrs;
790 BcVec arr_map;
791
Denys Vlasenko5d57bc42018-12-21 16:22:26 +0100792 IF_DC(BcVec strs;)
793 IF_DC(BcVec consts;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600794
Gavin Howard01055ba2018-11-03 11:00:21 -0600795 BcNum zero;
Denys Vlasenko503faf92018-12-20 16:24:18 +0100796 IF_BC(BcNum one;)
797 IF_BC(BcNum last;)
Gavin Howard01055ba2018-11-03 11:00:21 -0600798} BcProgram;
799
Denys Vlasenko6e618232018-12-25 22:20:14 +0100800struct globals {
801 BcParse prs; // first member is most used
802
803 // For error messages. Can be set to current parsed line,
804 // or [TODO] to current executing line (can be before last parsed one)
Denys Vlasenkoae6c44e2019-01-02 16:30:24 +0100805 size_t err_line;
Denys Vlasenko6e618232018-12-25 22:20:14 +0100806
807 BcVec input_buffer;
808
Denys Vlasenko14767602018-12-27 22:52:13 +0100809 IF_FEATURE_BC_INTERACTIVE(smallint ttyin;)
Denys Vlasenko6e618232018-12-25 22:20:14 +0100810 IF_FEATURE_CLEAN_UP(smallint exiting;)
811
812 BcProgram prog;
813
814 BcVec files;
815
816 char *env_args;
817
818#if ENABLE_FEATURE_EDITING
819 line_input_t *line_input_state;
820#endif
821} FIX_ALIASING;
822#define G (*ptr_to_globals)
823#define INIT_G() do { \
824 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
825} while (0)
826#define FREE_G() do { \
827 FREE_PTR_TO_GLOBALS(); \
828} while (0)
829#define G_posix (ENABLE_BC && (option_mask32 & BC_FLAG_S))
830#define G_warn (ENABLE_BC && (option_mask32 & BC_FLAG_W))
831#define G_exreg (ENABLE_DC && (option_mask32 & DC_FLAG_X))
Denys Vlasenko14767602018-12-27 22:52:13 +0100832#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenko6e618232018-12-25 22:20:14 +0100833# define G_interrupt bb_got_signal
834# define G_ttyin G.ttyin
835#else
836# define G_interrupt 0
837# define G_ttyin 0
838#endif
839#if ENABLE_FEATURE_CLEAN_UP
840# define G_exiting G.exiting
841#else
842# define G_exiting 0
843#endif
844#define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
845#define IS_DC (ENABLE_DC && (!ENABLE_BC || applet_name[0] != 'b'))
846
Denys Vlasenko6e618232018-12-25 22:20:14 +0100847#if ENABLE_BC
848# define BC_PARSE_REL (1 << 0)
849# define BC_PARSE_PRINT (1 << 1)
850# define BC_PARSE_ARRAY (1 << 2)
851# define BC_PARSE_NOCALL (1 << 3)
852#endif
853
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100854#define BC_PROG_MAIN 0
855#define BC_PROG_READ 1
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100856#if ENABLE_DC
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100857#define BC_PROG_REQ_FUNCS 2
Denys Vlasenkoef869ec2018-12-02 18:49:16 +0100858#endif
Gavin Howard01055ba2018-11-03 11:00:21 -0600859
Denys Vlasenko6d0be102018-12-06 18:41:59 +0100860#define BC_FLAG_W (1 << 0)
861#define BC_FLAG_V (1 << 1)
862#define BC_FLAG_S (1 << 2)
863#define BC_FLAG_Q (1 << 3)
864#define BC_FLAG_L (1 << 4)
Denys Vlasenko10bde142018-12-27 18:23:58 +0100865#define BC_FLAG_I ((1 << 5) * ENABLE_DC)
866#define DC_FLAG_X ((1 << 6) * ENABLE_DC)
Gavin Howard01055ba2018-11-03 11:00:21 -0600867
Denys Vlasenko64074a12018-12-07 15:50:14 +0100868#define BC_MAX_OBASE ((unsigned) 999)
869#define BC_MAX_DIM ((unsigned) INT_MAX)
870#define BC_MAX_SCALE ((unsigned) UINT_MAX)
871#define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
872#define BC_MAX_NUM BC_MAX_STRING
873// Unused apart from "limits" message. Just show a "biggish number" there.
Denys Vlasenko64074a12018-12-07 15:50:14 +0100874//#define BC_MAX_EXP ((unsigned long) LONG_MAX)
875//#define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
Denys Vlasenko64074a12018-12-07 15:50:14 +0100876#define BC_MAX_EXP_STR "999999999"
877#define BC_MAX_VARS_STR "999999999"
878
879#define BC_MAX_OBASE_STR "999"
880
881#if INT_MAX == 2147483647
882# define BC_MAX_DIM_STR "2147483647"
883#elif INT_MAX == 9223372036854775807
884# define BC_MAX_DIM_STR "9223372036854775807"
885#else
886# error Strange INT_MAX
887#endif
888
Kang-Che Sungf1593522019-09-05 23:40:38 +0800889#if UINT_MAX == 4294967295U
Denys Vlasenko64074a12018-12-07 15:50:14 +0100890# define BC_MAX_SCALE_STR "4294967295"
891# define BC_MAX_STRING_STR "4294967294"
Kang-Che Sungf1593522019-09-05 23:40:38 +0800892#elif UINT_MAX == 18446744073709551615U
Denys Vlasenko64074a12018-12-07 15:50:14 +0100893# define BC_MAX_SCALE_STR "18446744073709551615"
894# define BC_MAX_STRING_STR "18446744073709551614"
895#else
896# error Strange UINT_MAX
897#endif
898#define BC_MAX_NUM_STR BC_MAX_STRING_STR
Gavin Howard01055ba2018-11-03 11:00:21 -0600899
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100900// In configurations where errors abort instead of propagating error
901// return code up the call chain, functions returning BC_STATUS
902// actually don't return anything, they always succeed and return "void".
903// A macro wrapper is provided, which makes this statement work:
904// s = zbc_func(...)
905// and makes it visible to the compiler that s is always zero,
906// allowing compiler to optimize dead code after the statement.
907//
908// To make code more readable, each such function has a "z"
909// ("always returning zero") prefix, i.e. zbc_foo or zdc_foo.
910//
Denys Vlasenko14767602018-12-27 22:52:13 +0100911#if ENABLE_FEATURE_BC_INTERACTIVE || ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko7f4daa42018-12-11 19:04:44 +0100912# define ERRORS_ARE_FATAL 0
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100913# define ERRORFUNC /*nothing*/
Denys Vlasenkoec603182018-12-17 10:34:02 +0100914# define IF_ERROR_RETURN_POSSIBLE(a) a
915# define BC_STATUS BcStatus
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100916# define RETURN_STATUS(v) return (v)
Denys Vlasenkoec603182018-12-17 10:34:02 +0100917# define COMMA_SUCCESS /*nothing*/
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100918#else
Denys Vlasenko7f4daa42018-12-11 19:04:44 +0100919# define ERRORS_ARE_FATAL 1
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100920# define ERRORFUNC NORETURN
Denys Vlasenkoec603182018-12-17 10:34:02 +0100921# define IF_ERROR_RETURN_POSSIBLE(a) /*nothing*/
922# define BC_STATUS void
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100923# define RETURN_STATUS(v) do { ((void)(v)); return; } while (0)
Denys Vlasenkoec603182018-12-17 10:34:02 +0100924# define COMMA_SUCCESS ,BC_STATUS_SUCCESS
Denys Vlasenkoc2d15df2018-12-11 17:56:09 +0100925#endif
926
Denys Vlasenko2097ac82018-12-24 05:00:36 +0100927//
928// Utility routines
929//
Gavin Howard01055ba2018-11-03 11:00:21 -0600930
Denys Vlasenko2cd8c042018-12-30 15:56:36 +0100931#define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
932#define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
933
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100934static void fflush_and_check(void)
935{
936 fflush_all();
937 if (ferror(stdout) || ferror(stderr))
James Byrne69374872019-07-02 11:35:03 +0200938 bb_simple_perror_msg_and_die("output error");
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100939}
940
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100941#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100942#define QUIT_OR_RETURN_TO_MAIN \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100943do { \
Denys Vlasenko14767602018-12-27 22:52:13 +0100944 IF_FEATURE_BC_INTERACTIVE(G_ttyin = 0;) /* do not loop in main loop anymore */ \
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +0100945 G_exiting = 1; \
Denys Vlasenkoe873ff92018-12-06 00:29:22 +0100946 return BC_STATUS_FAILURE; \
947} while (0)
948#else
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100949static void quit(void) NORETURN;
950static void quit(void)
951{
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100952 if (ferror(stdin))
James Byrne69374872019-07-02 11:35:03 +0200953 bb_simple_perror_msg_and_die("input error");
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100954 fflush_and_check();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +0100955 dbg_exec("quit(): exiting with exitcode SUCCESS");
Denys Vlasenkod4744ad2018-12-03 14:28:51 +0100956 exit(0);
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100957}
Denys Vlasenko10bde142018-12-27 18:23:58 +0100958#define QUIT_OR_RETURN_TO_MAIN quit()
959#endif
Denys Vlasenkocfdc1332018-12-03 14:02:35 +0100960
Denys Vlasenko5318f812018-12-05 17:48:01 +0100961static void bc_verror_msg(const char *fmt, va_list p)
962{
Denys Vlasenko82269122018-12-14 16:30:56 +0100963 const char *sv = sv; // for compiler
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +0100964 if (G.prs.lex_filename) {
Denys Vlasenko5318f812018-12-05 17:48:01 +0100965 sv = applet_name;
Denys Vlasenkoae6c44e2019-01-02 16:30:24 +0100966 applet_name = xasprintf("%s: %s:%lu", applet_name,
967 G.prs.lex_filename, (unsigned long)G.err_line
968 );
Denys Vlasenko5318f812018-12-05 17:48:01 +0100969 }
970 bb_verror_msg(fmt, p, NULL);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +0100971 if (G.prs.lex_filename) {
Denys Vlasenko5318f812018-12-05 17:48:01 +0100972 free((char*)applet_name);
973 applet_name = sv;
974 }
975}
976
Denys Vlasenko86e63cd2018-12-10 19:46:53 +0100977static NOINLINE ERRORFUNC int bc_error_fmt(const char *fmt, ...)
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100978{
979 va_list p;
980
981 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +0100982 bc_verror_msg(fmt, p);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100983 va_end(p);
Denys Vlasenko0409ad32018-12-05 16:39:22 +0100984
Denys Vlasenkoec603182018-12-17 10:34:02 +0100985 if (ENABLE_FEATURE_CLEAN_UP || G_ttyin)
986 IF_ERROR_RETURN_POSSIBLE(return BC_STATUS_FAILURE);
987 exit(1);
Denys Vlasenkoc1c24702018-12-03 16:06:02 +0100988}
989
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +0100990#if ENABLE_BC
Denys Vlasenko79587cb2018-12-24 18:11:41 +0100991static NOINLINE BC_STATUS zbc_posix_error_fmt(const char *fmt, ...)
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100992{
993 va_list p;
994
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +0100995 // Are non-POSIX constructs totally ok?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +0100996 if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
Denys Vlasenko79587cb2018-12-24 18:11:41 +0100997 RETURN_STATUS(BC_STATUS_SUCCESS); // yes
Denys Vlasenko9b70f192018-12-04 20:51:40 +0100998
999 va_start(p, fmt);
Denys Vlasenko5318f812018-12-05 17:48:01 +01001000 bc_verror_msg(fmt, p);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001001 va_end(p);
1002
1003 // Do we treat non-POSIX constructs as errors?
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01001004 if (!(option_mask32 & BC_FLAG_S))
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001005 RETURN_STATUS(BC_STATUS_SUCCESS); // no, it's a warning
1006
Denys Vlasenkoec603182018-12-17 10:34:02 +01001007 if (ENABLE_FEATURE_CLEAN_UP || G_ttyin)
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001008 RETURN_STATUS(BC_STATUS_FAILURE);
Denys Vlasenkoec603182018-12-17 10:34:02 +01001009 exit(1);
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001010}
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001011#define zbc_posix_error_fmt(...) (zbc_posix_error_fmt(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001012#endif
Denys Vlasenko9b70f192018-12-04 20:51:40 +01001013
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001014// We use error functions with "return bc_error(FMT[, PARAMS])" idiom.
1015// This idiom begs for tail-call optimization, but for it to work,
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01001016// function must not have caller-cleaned parameters on stack.
1017// Unfortunately, vararg function API does exactly that on most arches.
1018// Thus, use these shims for the cases when we have no vararg PARAMS:
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001019static ERRORFUNC int bc_error(const char *msg)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001020{
Denys Vlasenkoec603182018-12-17 10:34:02 +01001021 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg);
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001022}
Denys Vlasenko22314682019-01-01 21:50:14 +01001023static ERRORFUNC int bc_error_at(const char *msg)
1024{
1025 const char *err_at = G.prs.lex_next_at;
1026 if (err_at) {
1027 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt(
1028 "%s at '%.*s'",
1029 msg,
1030 (int)(strchrnul(err_at, '\n') - err_at),
1031 err_at
1032 );
1033 }
1034 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("%s", msg);
1035}
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001036static ERRORFUNC int bc_error_bad_character(char c)
1037{
Denys Vlasenkob44a7f12018-12-17 11:58:20 +01001038 if (!c)
1039 IF_ERROR_RETURN_POSSIBLE(return) bc_error("NUL character");
Denys Vlasenkoec603182018-12-17 10:34:02 +01001040 IF_ERROR_RETURN_POSSIBLE(return) bc_error_fmt("bad character '%c'", c);
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001041}
Denys Vlasenko7a4e5542019-06-08 12:39:30 +02001042#if ENABLE_BC
Denys Vlasenko22314682019-01-01 21:50:14 +01001043static ERRORFUNC int bc_error_bad_function_definition(void)
1044{
1045 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad function definition");
1046}
Denys Vlasenko7a4e5542019-06-08 12:39:30 +02001047#endif
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001048static ERRORFUNC int bc_error_bad_expression(void)
1049{
Denys Vlasenko22314682019-01-01 21:50:14 +01001050 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad expression");
1051}
1052static ERRORFUNC int bc_error_bad_assignment(void)
1053{
1054 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at(
1055 "bad assignment: left side must be variable or array element"
1056 );
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001057}
1058static ERRORFUNC int bc_error_bad_token(void)
1059{
Denys Vlasenko22314682019-01-01 21:50:14 +01001060 IF_ERROR_RETURN_POSSIBLE(return) bc_error_at("bad token");
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001061}
1062static ERRORFUNC int bc_error_stack_has_too_few_elements(void)
1063{
Denys Vlasenkoec603182018-12-17 10:34:02 +01001064 IF_ERROR_RETURN_POSSIBLE(return) bc_error("stack has too few elements");
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001065}
1066static ERRORFUNC int bc_error_variable_is_wrong_type(void)
1067{
Denys Vlasenkoec603182018-12-17 10:34:02 +01001068 IF_ERROR_RETURN_POSSIBLE(return) bc_error("variable is wrong type");
Denys Vlasenko86e63cd2018-12-10 19:46:53 +01001069}
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001070#if ENABLE_BC
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001071static BC_STATUS zbc_POSIX_requires(const char *msg)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001072{
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001073 RETURN_STATUS(zbc_posix_error_fmt("POSIX requires %s", msg));
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001074}
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001075#define zbc_POSIX_requires(...) (zbc_POSIX_requires(__VA_ARGS__) COMMA_SUCCESS)
1076static BC_STATUS zbc_POSIX_does_not_allow(const char *msg)
Denys Vlasenko00646792018-12-05 18:12:27 +01001077{
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001078 RETURN_STATUS(zbc_posix_error_fmt("%s%s", "POSIX does not allow ", msg));
Denys Vlasenko00646792018-12-05 18:12:27 +01001079}
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001080#define zbc_POSIX_does_not_allow(...) (zbc_POSIX_does_not_allow(__VA_ARGS__) COMMA_SUCCESS)
1081static BC_STATUS zbc_POSIX_does_not_allow_bool_ops_this_is_bad(const char *msg)
Denys Vlasenko00646792018-12-05 18:12:27 +01001082{
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01001083 RETURN_STATUS(zbc_posix_error_fmt("%s%s %s", "POSIX does not allow ", "boolean operators; this is bad:", msg));
Denys Vlasenko00646792018-12-05 18:12:27 +01001084}
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001085#define zbc_POSIX_does_not_allow_bool_ops_this_is_bad(...) (zbc_POSIX_does_not_allow_bool_ops_this_is_bad(__VA_ARGS__) COMMA_SUCCESS)
1086static BC_STATUS zbc_POSIX_does_not_allow_empty_X_expression_in_for(const char *msg)
Denys Vlasenko00646792018-12-05 18:12:27 +01001087{
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01001088 RETURN_STATUS(zbc_posix_error_fmt("%san empty %s expression in 'for()'", "POSIX does not allow ", msg));
Denys Vlasenko00646792018-12-05 18:12:27 +01001089}
Denys Vlasenko79587cb2018-12-24 18:11:41 +01001090#define zbc_POSIX_does_not_allow_empty_X_expression_in_for(...) (zbc_POSIX_does_not_allow_empty_X_expression_in_for(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko23c2e9f2018-12-06 11:43:17 +01001091#endif
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01001092
Gavin Howard01055ba2018-11-03 11:00:21 -06001093static void bc_vec_grow(BcVec *v, size_t n)
1094{
1095 size_t cap = v->cap * 2;
1096 while (cap < v->len + n) cap *= 2;
1097 v->v = xrealloc(v->v, v->size * cap);
1098 v->cap = cap;
1099}
1100
1101static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1102{
1103 v->size = esize;
1104 v->cap = BC_VEC_START_CAP;
1105 v->len = 0;
1106 v->dtor = dtor;
1107 v->v = xmalloc(esize * BC_VEC_START_CAP);
1108}
1109
Denys Vlasenko7d628012018-12-04 21:46:47 +01001110static void bc_char_vec_init(BcVec *v)
1111{
1112 bc_vec_init(v, sizeof(char), NULL);
1113}
1114
Gavin Howard01055ba2018-11-03 11:00:21 -06001115static void bc_vec_expand(BcVec *v, size_t req)
1116{
1117 if (v->cap < req) {
1118 v->v = xrealloc(v->v, v->size * req);
1119 v->cap = req;
1120 }
1121}
1122
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001123static void bc_vec_pop(BcVec *v)
1124{
1125 v->len--;
1126 if (v->dtor)
1127 v->dtor(v->v + (v->size * v->len));
1128}
Denys Vlasenko2fa11b62018-12-06 12:34:39 +01001129
Gavin Howard01055ba2018-11-03 11:00:21 -06001130static void bc_vec_npop(BcVec *v, size_t n)
1131{
1132 if (!v->dtor)
1133 v->len -= n;
1134 else {
1135 size_t len = v->len - n;
1136 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1137 }
1138}
1139
Denys Vlasenko7d628012018-12-04 21:46:47 +01001140static void bc_vec_pop_all(BcVec *v)
1141{
1142 bc_vec_npop(v, v->len);
1143}
1144
Denys Vlasenko53799502019-01-25 14:24:03 +01001145static size_t bc_vec_npush(BcVec *v, size_t n, const void *data)
Gavin Howard01055ba2018-11-03 11:00:21 -06001146{
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001147 size_t len = v->len;
Denys Vlasenko53799502019-01-25 14:24:03 +01001148 if (len + n > v->cap) bc_vec_grow(v, n);
1149 memmove(v->v + (v->size * len), data, v->size * n);
1150 v->len = len + n;
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001151 return len;
Gavin Howard01055ba2018-11-03 11:00:21 -06001152}
1153
Denys Vlasenko53799502019-01-25 14:24:03 +01001154static size_t bc_vec_push(BcVec *v, const void *data)
1155{
1156 return bc_vec_npush(v, 1, data);
1157 //size_t len = v->len;
1158 //if (len >= v->cap) bc_vec_grow(v, 1);
1159 //memmove(v->v + (v->size * len), data, v->size);
1160 //v->len = len + 1;
1161 //return len;
1162}
1163
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01001164// G.prog.results often needs "pop old operand, push result" idiom.
1165// Can do this without a few extra ops
1166static size_t bc_result_pop_and_push(const void *data)
1167{
1168 BcVec *v = &G.prog.results;
1169 char *last;
1170 size_t len = v->len - 1;
1171
1172 last = v->v + (v->size * len);
1173 if (v->dtor)
1174 v->dtor(last);
1175 memmove(last, data, v->size);
1176 return len;
1177}
1178
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001179static size_t bc_vec_pushByte(BcVec *v, char data)
Gavin Howard01055ba2018-11-03 11:00:21 -06001180{
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001181 return bc_vec_push(v, &data);
Gavin Howard01055ba2018-11-03 11:00:21 -06001182}
1183
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001184static size_t bc_vec_pushZeroByte(BcVec *v)
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001185{
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001186 //return bc_vec_pushByte(v, '\0');
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001187 // better:
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01001188 return bc_vec_push(v, &const_int_0);
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001189}
1190
Gavin Howard01055ba2018-11-03 11:00:21 -06001191static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1192{
1193 if (idx == v->len)
1194 bc_vec_push(v, data);
1195 else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001196 char *ptr;
1197
1198 if (v->len == v->cap) bc_vec_grow(v, 1);
1199
1200 ptr = v->v + v->size * idx;
1201
1202 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1203 memmove(ptr, data, v->size);
1204 }
1205}
1206
1207static void bc_vec_string(BcVec *v, size_t len, const char *str)
1208{
Denys Vlasenko7d628012018-12-04 21:46:47 +01001209 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001210 bc_vec_expand(v, len + 1);
1211 memcpy(v->v, str, len);
1212 v->len = len;
1213
Denys Vlasenko08c033c2018-12-05 16:55:08 +01001214 bc_vec_pushZeroByte(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001215}
1216
Gavin Howard01055ba2018-11-03 11:00:21 -06001217static void *bc_vec_item(const BcVec *v, size_t idx)
1218{
1219 return v->v + v->size * idx;
1220}
1221
1222static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1223{
1224 return v->v + v->size * (v->len - idx - 1);
1225}
1226
Denys Vlasenkob23ac512018-12-06 13:10:56 +01001227static void *bc_vec_top(const BcVec *v)
1228{
1229 return v->v + v->size * (v->len - 1);
1230}
1231
Denys Vlasenko5ba55f12018-12-10 15:37:14 +01001232static FAST_FUNC void bc_vec_free(void *vec)
Gavin Howard01055ba2018-11-03 11:00:21 -06001233{
1234 BcVec *v = (BcVec *) vec;
Denys Vlasenko7d628012018-12-04 21:46:47 +01001235 bc_vec_pop_all(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06001236 free(v->v);
1237}
1238
Denys Vlasenko10bde142018-12-27 18:23:58 +01001239static BcFunc* xc_program_func(size_t idx)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01001240{
1241 return bc_vec_item(&G.prog.fns, idx);
1242}
1243// BC_PROG_MAIN is zeroth element, so:
Denys Vlasenko10bde142018-12-27 18:23:58 +01001244#define xc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01001245
1246#if ENABLE_BC
1247static BcFunc* bc_program_current_func(void)
1248{
1249 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
Denys Vlasenko10bde142018-12-27 18:23:58 +01001250 BcFunc *func = xc_program_func(ip->func);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01001251 return func;
1252}
1253#endif
1254
Denys Vlasenko10bde142018-12-27 18:23:58 +01001255static char** xc_program_str(size_t idx)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01001256{
1257#if ENABLE_BC
1258 if (IS_BC) {
1259 BcFunc *func = bc_program_current_func();
1260 return bc_vec_item(&func->strs, idx);
1261 }
1262#endif
1263 IF_DC(return bc_vec_item(&G.prog.strs, idx);)
1264}
1265
Denys Vlasenko10bde142018-12-27 18:23:58 +01001266static char** xc_program_const(size_t idx)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01001267{
1268#if ENABLE_BC
1269 if (IS_BC) {
1270 BcFunc *func = bc_program_current_func();
1271 return bc_vec_item(&func->consts, idx);
1272 }
1273#endif
1274 IF_DC(return bc_vec_item(&G.prog.consts, idx);)
1275}
1276
Denys Vlasenkocca79a02018-12-05 21:15:46 +01001277static int bc_id_cmp(const void *e1, const void *e2)
1278{
1279 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
1280}
1281
Denys Vlasenko5ba55f12018-12-10 15:37:14 +01001282static FAST_FUNC void bc_id_free(void *id)
Denys Vlasenkocca79a02018-12-05 21:15:46 +01001283{
1284 free(((BcId *) id)->name);
1285}
1286
Denys Vlasenko5aa54832018-12-19 13:55:53 +01001287static size_t bc_map_find_ge(const BcVec *v, const void *ptr)
Gavin Howard01055ba2018-11-03 11:00:21 -06001288{
1289 size_t low = 0, high = v->len;
1290
1291 while (low < high) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001292 size_t mid = (low + high) / 2;
1293 BcId *id = bc_vec_item(v, mid);
1294 int result = bc_id_cmp(ptr, id);
1295
1296 if (result == 0)
1297 return mid;
Denys Vlasenkoe3d3d202018-12-19 13:19:44 +01001298 if (result < 0)
Gavin Howard01055ba2018-11-03 11:00:21 -06001299 high = mid;
1300 else
1301 low = mid + 1;
1302 }
1303
1304 return low;
1305}
1306
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001307static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
Gavin Howard01055ba2018-11-03 11:00:21 -06001308{
Denys Vlasenko5aa54832018-12-19 13:55:53 +01001309 size_t n = *i = bc_map_find_ge(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001310
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001311 if (n == v->len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001312 bc_vec_push(v, ptr);
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001313 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1314 return 0; // "was not inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001315 else
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01001316 bc_vec_pushAt(v, ptr, n);
1317 return 1; // "was inserted"
Gavin Howard01055ba2018-11-03 11:00:21 -06001318}
1319
Denys Vlasenko5aa54832018-12-19 13:55:53 +01001320static size_t bc_map_find_exact(const BcVec *v, const void *ptr)
Gavin Howard01055ba2018-11-03 11:00:21 -06001321{
Denys Vlasenko5aa54832018-12-19 13:55:53 +01001322 size_t i = bc_map_find_ge(v, ptr);
Gavin Howard01055ba2018-11-03 11:00:21 -06001323 if (i >= v->len) return BC_VEC_INVALID_IDX;
1324 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1325}
1326
Gavin Howard01055ba2018-11-03 11:00:21 -06001327static void bc_num_setToZero(BcNum *n, size_t scale)
1328{
1329 n->len = 0;
1330 n->neg = false;
1331 n->rdx = scale;
1332}
1333
1334static void bc_num_zero(BcNum *n)
1335{
1336 bc_num_setToZero(n, 0);
1337}
1338
1339static void bc_num_one(BcNum *n)
1340{
1341 bc_num_setToZero(n, 0);
1342 n->len = 1;
1343 n->num[0] = 1;
1344}
1345
Denys Vlasenko3129f702018-12-09 12:04:44 +01001346// Note: this also sets BcNum to zero
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001347static void bc_num_init(BcNum *n, size_t req)
1348{
1349 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
Denys Vlasenko3129f702018-12-09 12:04:44 +01001350 //memset(n, 0, sizeof(BcNum)); - cleared by assignments below
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001351 n->num = xmalloc(req);
1352 n->cap = req;
Denys Vlasenko3129f702018-12-09 12:04:44 +01001353 n->rdx = 0;
1354 n->len = 0;
1355 n->neg = false;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001356}
1357
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01001358static void bc_num_init_DEF_SIZE(BcNum *n)
1359{
1360 bc_num_init(n, BC_NUM_DEF_SIZE);
1361}
1362
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001363static void bc_num_expand(BcNum *n, size_t req)
1364{
1365 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
1366 if (req > n->cap) {
1367 n->num = xrealloc(n->num, req);
1368 n->cap = req;
1369 }
1370}
1371
Denys Vlasenko5ba55f12018-12-10 15:37:14 +01001372static FAST_FUNC void bc_num_free(void *num)
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001373{
1374 free(((BcNum *) num)->num);
1375}
1376
1377static void bc_num_copy(BcNum *d, BcNum *s)
1378{
1379 if (d != s) {
1380 bc_num_expand(d, s->cap);
1381 d->len = s->len;
1382 d->neg = s->neg;
1383 d->rdx = s->rdx;
1384 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
1385 }
1386}
1387
Denys Vlasenkoa9f59db2018-12-22 21:52:30 +01001388static BC_STATUS zbc_num_ulong_abs(BcNum *n, unsigned long *result_p)
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001389{
1390 size_t i;
Denys Vlasenko1557b762018-12-22 21:37:46 +01001391 unsigned long result;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001392
Denys Vlasenko1557b762018-12-22 21:37:46 +01001393 result = 0;
1394 i = n->len;
1395 while (i > n->rdx) {
1396 unsigned long prev = result;
1397 result = result * 10 + n->num[--i];
1398 // Even overflowed N*10 can still satisfy N*10>=N. For example,
1399 // 0x1ff00000 * 10 is 0x13f600000,
1400 // or 0x3f600000 truncated to 32 bits. Which is larger.
1401 // However, (N*10)/8 < N check is always correct.
1402 if ((result / 8) < prev)
Denys Vlasenko29301232018-12-11 15:29:32 +01001403 RETURN_STATUS(bc_error("overflow"));
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001404 }
Denys Vlasenkoffdcebd2018-12-07 15:10:05 +01001405 *result_p = result;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001406
Denys Vlasenko29301232018-12-11 15:29:32 +01001407 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001408}
Denys Vlasenkoa9f59db2018-12-22 21:52:30 +01001409#define zbc_num_ulong_abs(...) (zbc_num_ulong_abs(__VA_ARGS__) COMMA_SUCCESS)
1410
1411static BC_STATUS zbc_num_ulong(BcNum *n, unsigned long *result_p)
1412{
1413 if (n->neg) RETURN_STATUS(bc_error("negative number"));
1414
1415 RETURN_STATUS(zbc_num_ulong_abs(n, result_p));
1416}
Denys Vlasenkoec603182018-12-17 10:34:02 +01001417#define zbc_num_ulong(...) (zbc_num_ulong(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001418
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01001419#if ULONG_MAX == 0xffffffffUL // 10 digits: 4294967295
1420# define ULONG_NUM_BUFSIZE (10 > BC_NUM_DEF_SIZE ? 10 : BC_NUM_DEF_SIZE)
1421#elif ULONG_MAX == 0xffffffffffffffffULL // 20 digits: 18446744073709551615
1422# define ULONG_NUM_BUFSIZE (20 > BC_NUM_DEF_SIZE ? 20 : BC_NUM_DEF_SIZE)
1423#endif
1424// minimum BC_NUM_DEF_SIZE, so that bc_num_expand() in bc_num_ulong2num()
1425// would not hit realloc() code path - not good if num[] is not malloced
1426
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001427static void bc_num_ulong2num(BcNum *n, unsigned long val)
1428{
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001429 BcDig *ptr;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001430
1431 bc_num_zero(n);
1432
1433 if (val == 0) return;
1434
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01001435 bc_num_expand(n, ULONG_NUM_BUFSIZE);
Denys Vlasenkob696d9e2018-12-10 12:22:15 +01001436
1437 ptr = n->num;
1438 for (;;) {
1439 n->len++;
1440 *ptr++ = val % 10;
1441 val /= 10;
1442 if (val == 0) break;
1443 }
Denys Vlasenkob0e37612018-12-05 21:03:16 +01001444}
1445
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01001446static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b, size_t len)
Gavin Howard01055ba2018-11-03 11:00:21 -06001447{
1448 size_t i, j;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001449 for (i = 0; i < len; ++i) {
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001450 a[i] -= b[i];
1451 for (j = i; a[j] < 0;) {
1452 a[j++] += 10;
1453 a[j] -= 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06001454 }
1455 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001456}
1457
1458static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1459{
Denys Vlasenko4113e1f2018-12-18 00:39:24 +01001460 size_t i = len;
1461 for (;;) {
1462 int c;
1463 if (i == 0)
1464 return 0;
1465 i--;
1466 c = a[i] - b[i];
1467 if (c != 0) {
1468 i++;
1469 if (c < 0)
1470 return -i;
1471 return i;
1472 }
1473 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001474}
1475
Denys Vlasenko2097ac82018-12-24 05:00:36 +01001476#define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
1477#define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
1478#define BC_NUM_INT(n) ((n)->len - (n)->rdx)
1479//#define BC_NUM_AREQ(a, b) (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
1480static /*ALWAYS_INLINE*/ size_t BC_NUM_AREQ(BcNum *a, BcNum *b)
1481{
1482 return BC_MAX(a->rdx, b->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
1483}
1484//#define BC_NUM_MREQ(a, b, scale) (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
1485static /*ALWAYS_INLINE*/ size_t BC_NUM_MREQ(BcNum *a, BcNum *b, size_t scale)
1486{
1487 return BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX(scale, a->rdx + b->rdx) + 1;
1488}
1489
Gavin Howard01055ba2018-11-03 11:00:21 -06001490static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1491{
1492 size_t i, min, a_int, b_int, diff;
1493 BcDig *max_num, *min_num;
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001494 bool a_max, neg;
Gavin Howard01055ba2018-11-03 11:00:21 -06001495 ssize_t cmp;
1496
1497 if (a == b) return 0;
1498 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1499 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001500
1501 if (a->neg != b->neg) // signs of a and b differ
1502 // +a,-b = a>b = 1 or -a,+b = a<b = -1
1503 return (int)b->neg - (int)a->neg;
1504 neg = a->neg; // 1 if both negative, 0 if both positive
Gavin Howard01055ba2018-11-03 11:00:21 -06001505
1506 a_int = BC_NUM_INT(a);
1507 b_int = BC_NUM_INT(b);
1508 a_int -= b_int;
Gavin Howard01055ba2018-11-03 11:00:21 -06001509
Denys Vlasenko00841372019-11-23 17:25:21 +01001510 if (a_int != 0) {
1511 if (neg) return - (ssize_t) a_int;
1512 return (ssize_t) a_int;
1513 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001514
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001515 a_max = (a->rdx > b->rdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06001516 if (a_max) {
1517 min = b->rdx;
1518 diff = a->rdx - b->rdx;
1519 max_num = a->num + diff;
1520 min_num = b->num;
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001521 // neg = (a_max == neg); - NOP (maps 1->1 and 0->0)
1522 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001523 min = a->rdx;
1524 diff = b->rdx - a->rdx;
1525 max_num = b->num + diff;
1526 min_num = a->num;
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001527 neg = !neg; // same as "neg = (a_max == neg)"
Gavin Howard01055ba2018-11-03 11:00:21 -06001528 }
1529
1530 cmp = bc_num_compare(max_num, min_num, b_int + min);
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001531 if (cmp != 0) return BC_NUM_NEG(cmp, neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001532
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001533 for (max_num -= diff, i = diff - 1; i < diff; --i) {
Denys Vlasenko251fbb52018-12-12 11:51:32 +01001534 if (max_num[i]) return BC_NUM_NEG(1, neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06001535 }
1536
1537 return 0;
1538}
1539
1540static void bc_num_truncate(BcNum *n, size_t places)
1541{
1542 if (places == 0) return;
1543
1544 n->rdx -= places;
1545
1546 if (n->len != 0) {
1547 n->len -= places;
1548 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1549 }
1550}
1551
1552static void bc_num_extend(BcNum *n, size_t places)
1553{
1554 size_t len = n->len + places;
1555
1556 if (places != 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001557 if (n->cap < len) bc_num_expand(n, len);
1558
1559 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1560 memset(n->num, 0, sizeof(BcDig) * places);
1561
1562 n->len += places;
1563 n->rdx += places;
1564 }
1565}
1566
1567static void bc_num_clean(BcNum *n)
1568{
1569 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1570 if (n->len == 0)
1571 n->neg = false;
1572 else if (n->len < n->rdx)
1573 n->len = n->rdx;
1574}
1575
1576static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1577{
1578 if (n->rdx < scale)
1579 bc_num_extend(n, scale - n->rdx);
1580 else
1581 bc_num_truncate(n, n->rdx - scale);
1582
1583 bc_num_clean(n);
1584 if (n->len != 0) n->neg = !neg1 != !neg2;
1585}
1586
1587static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1588 BcNum *restrict b)
1589{
1590 if (idx < n->len) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001591 b->len = n->len - idx;
1592 a->len = idx;
1593 a->rdx = b->rdx = 0;
1594
1595 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1596 memcpy(a->num, n->num, idx * sizeof(BcDig));
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01001597 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001598 bc_num_zero(b);
1599 bc_num_copy(a, n);
1600 }
1601
1602 bc_num_clean(a);
1603 bc_num_clean(b);
1604}
1605
Denys Vlasenko29301232018-12-11 15:29:32 +01001606static BC_STATUS zbc_num_shift(BcNum *n, size_t places)
Gavin Howard01055ba2018-11-03 11:00:21 -06001607{
Denys Vlasenko29301232018-12-11 15:29:32 +01001608 if (places == 0 || n->len == 0) RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenko64074a12018-12-07 15:50:14 +01001609
1610 // This check makes sense only if size_t is (much) larger than BC_MAX_NUM.
1611 if (SIZE_MAX > (BC_MAX_NUM | 0xff)) {
1612 if (places + n->len > BC_MAX_NUM)
Denys Vlasenko29301232018-12-11 15:29:32 +01001613 RETURN_STATUS(bc_error("number too long: must be [1,"BC_MAX_NUM_STR"]"));
Denys Vlasenko64074a12018-12-07 15:50:14 +01001614 }
Gavin Howard01055ba2018-11-03 11:00:21 -06001615
1616 if (n->rdx >= places)
1617 n->rdx -= places;
1618 else {
1619 bc_num_extend(n, places - n->rdx);
1620 n->rdx = 0;
1621 }
1622
1623 bc_num_clean(n);
1624
Denys Vlasenko29301232018-12-11 15:29:32 +01001625 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001626}
Denys Vlasenkoec603182018-12-17 10:34:02 +01001627#define zbc_num_shift(...) (zbc_num_shift(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06001628
Denys Vlasenko2097ac82018-12-24 05:00:36 +01001629typedef BC_STATUS (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t) FAST_FUNC;
1630
1631static BC_STATUS zbc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1632 BcNumBinaryOp op, size_t req)
1633{
1634 BcStatus s;
1635 BcNum num2, *ptr_a, *ptr_b;
1636 bool init = false;
1637
1638 if (c == a) {
1639 ptr_a = &num2;
1640 memcpy(ptr_a, c, sizeof(BcNum));
1641 init = true;
1642 } else
1643 ptr_a = a;
1644
1645 if (c == b) {
1646 ptr_b = &num2;
1647 if (c != a) {
1648 memcpy(ptr_b, c, sizeof(BcNum));
1649 init = true;
1650 }
1651 } else
1652 ptr_b = b;
1653
1654 if (init)
1655 bc_num_init(c, req);
1656 else
1657 bc_num_expand(c, req);
1658
1659 s = BC_STATUS_SUCCESS;
1660 IF_ERROR_RETURN_POSSIBLE(s =) op(ptr_a, ptr_b, c, scale);
1661
1662 if (init) bc_num_free(&num2);
1663
1664 RETURN_STATUS(s);
1665}
1666#define zbc_num_binary(...) (zbc_num_binary(__VA_ARGS__) COMMA_SUCCESS)
1667
1668static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1669static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1670static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1671static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1672static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1673static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale);
1674
1675static FAST_FUNC BC_STATUS zbc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1676{
1677 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_a : zbc_num_s;
1678 (void) scale;
1679 RETURN_STATUS(zbc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b)));
1680}
1681
1682static FAST_FUNC BC_STATUS zbc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1683{
1684 BcNumBinaryOp op = (!a->neg == !b->neg) ? zbc_num_s : zbc_num_a;
1685 (void) scale;
1686 RETURN_STATUS(zbc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b)));
1687}
1688
1689static FAST_FUNC BC_STATUS zbc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1690{
1691 size_t req = BC_NUM_MREQ(a, b, scale);
1692 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_m, req));
1693}
1694
1695static FAST_FUNC BC_STATUS zbc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1696{
1697 size_t req = BC_NUM_MREQ(a, b, scale);
1698 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_d, req));
1699}
1700
1701static FAST_FUNC BC_STATUS zbc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1702{
1703 size_t req = BC_NUM_MREQ(a, b, scale);
1704 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_rem, req));
1705}
1706
1707static FAST_FUNC BC_STATUS zbc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
1708{
1709 RETURN_STATUS(zbc_num_binary(a, b, c, scale, zbc_num_p, a->len * b->len + 1));
1710}
1711
Denys Vlasenko10bde142018-12-27 18:23:58 +01001712static const BcNumBinaryOp zxc_program_ops[] = {
Denys Vlasenko2097ac82018-12-24 05:00:36 +01001713 zbc_num_pow, zbc_num_mul, zbc_num_div, zbc_num_mod, zbc_num_add, zbc_num_sub,
1714};
1715#define zbc_num_add(...) (zbc_num_add(__VA_ARGS__) COMMA_SUCCESS)
1716#define zbc_num_sub(...) (zbc_num_sub(__VA_ARGS__) COMMA_SUCCESS)
1717#define zbc_num_mul(...) (zbc_num_mul(__VA_ARGS__) COMMA_SUCCESS)
1718#define zbc_num_div(...) (zbc_num_div(__VA_ARGS__) COMMA_SUCCESS)
1719#define zbc_num_mod(...) (zbc_num_mod(__VA_ARGS__) COMMA_SUCCESS)
1720#define zbc_num_pow(...) (zbc_num_pow(__VA_ARGS__) COMMA_SUCCESS)
1721
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001722static BC_STATUS zbc_num_inv(BcNum *a, BcNum *b, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06001723{
1724 BcNum one;
1725 BcDig num[2];
1726
1727 one.cap = 2;
1728 one.num = num;
1729 bc_num_one(&one);
1730
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001731 RETURN_STATUS(zbc_num_div(&one, a, b, scale));
Gavin Howard01055ba2018-11-03 11:00:21 -06001732}
Denys Vlasenkoec603182018-12-17 10:34:02 +01001733#define zbc_num_inv(...) (zbc_num_inv(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06001734
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001735static FAST_FUNC BC_STATUS zbc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
Gavin Howard01055ba2018-11-03 11:00:21 -06001736{
1737 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1738 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001739 unsigned carry;
Gavin Howard01055ba2018-11-03 11:00:21 -06001740
1741 // Because this function doesn't need to use scale (per the bc spec),
1742 // I am hijacking it to say whether it's doing an add or a subtract.
1743
1744 if (a->len == 0) {
1745 bc_num_copy(c, b);
1746 if (sub && c->len) c->neg = !c->neg;
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001747 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001748 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001749 if (b->len == 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001750 bc_num_copy(c, a);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001751 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001752 }
1753
1754 c->neg = a->neg;
1755 c->rdx = BC_MAX(a->rdx, b->rdx);
1756 min_rdx = BC_MIN(a->rdx, b->rdx);
1757 c->len = 0;
1758
1759 if (a->rdx > b->rdx) {
1760 diff = a->rdx - b->rdx;
1761 ptr = a->num;
1762 ptr_a = a->num + diff;
1763 ptr_b = b->num;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001764 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001765 diff = b->rdx - a->rdx;
1766 ptr = b->num;
1767 ptr_a = a->num;
1768 ptr_b = b->num + diff;
1769 }
1770
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001771 ptr_c = c->num;
1772 for (i = 0; i < diff; ++i, ++c->len)
1773 ptr_c[i] = ptr[i];
Gavin Howard01055ba2018-11-03 11:00:21 -06001774
1775 ptr_c += diff;
1776 a_int = BC_NUM_INT(a);
1777 b_int = BC_NUM_INT(b);
1778
1779 if (a_int > b_int) {
1780 min_int = b_int;
1781 max = a_int;
1782 ptr = ptr_a;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001783 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001784 min_int = a_int;
1785 max = b_int;
1786 ptr = ptr_b;
1787 }
1788
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001789 carry = 0;
1790 for (i = 0; i < min_rdx + min_int; ++i) {
1791 unsigned in = (unsigned)ptr_a[i] + (unsigned)ptr_b[i] + carry;
Gavin Howard01055ba2018-11-03 11:00:21 -06001792 carry = in / 10;
1793 ptr_c[i] = (BcDig)(in % 10);
1794 }
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001795 for (; i < max + min_rdx; ++i) {
1796 unsigned in = (unsigned)ptr[i] + carry;
Gavin Howard01055ba2018-11-03 11:00:21 -06001797 carry = in / 10;
1798 ptr_c[i] = (BcDig)(in % 10);
1799 }
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001800 c->len += i;
Gavin Howard01055ba2018-11-03 11:00:21 -06001801
1802 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1803
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001804 RETURN_STATUS(BC_STATUS_SUCCESS); // can't make void, see zbc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001805}
1806
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001807static FAST_FUNC BC_STATUS zbc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
Gavin Howard01055ba2018-11-03 11:00:21 -06001808{
Gavin Howard01055ba2018-11-03 11:00:21 -06001809 ssize_t cmp;
1810 BcNum *minuend, *subtrahend;
1811 size_t start;
1812 bool aneg, bneg, neg;
1813
1814 // Because this function doesn't need to use scale (per the bc spec),
1815 // I am hijacking it to say whether it's doing an add or a subtract.
1816
1817 if (a->len == 0) {
1818 bc_num_copy(c, b);
1819 if (sub && c->len) c->neg = !c->neg;
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001820 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001821 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001822 if (b->len == 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001823 bc_num_copy(c, a);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001824 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001825 }
1826
1827 aneg = a->neg;
1828 bneg = b->neg;
1829 a->neg = b->neg = false;
1830
1831 cmp = bc_num_cmp(a, b);
1832
1833 a->neg = aneg;
1834 b->neg = bneg;
1835
1836 if (cmp == 0) {
1837 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001838 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001839 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001840 if (cmp > 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001841 neg = a->neg;
1842 minuend = a;
1843 subtrahend = b;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001844 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06001845 neg = b->neg;
1846 if (sub) neg = !neg;
1847 minuend = b;
1848 subtrahend = a;
1849 }
1850
1851 bc_num_copy(c, minuend);
1852 c->neg = neg;
1853
1854 if (c->rdx < subtrahend->rdx) {
1855 bc_num_extend(c, subtrahend->rdx - c->rdx);
1856 start = 0;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001857 } else
Gavin Howard01055ba2018-11-03 11:00:21 -06001858 start = c->rdx - subtrahend->rdx;
1859
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001860 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001861
1862 bc_num_clean(c);
1863
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001864 RETURN_STATUS(BC_STATUS_SUCCESS); // can't make void, see zbc_num_binary()
Gavin Howard01055ba2018-11-03 11:00:21 -06001865}
1866
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001867static FAST_FUNC BC_STATUS zbc_num_k(BcNum *restrict a, BcNum *restrict b,
Gavin Howard01055ba2018-11-03 11:00:21 -06001868 BcNum *restrict c)
Denys Vlasenkoec603182018-12-17 10:34:02 +01001869#define zbc_num_k(...) (zbc_num_k(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06001870{
1871 BcStatus s;
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01001872 size_t max, max2;
Gavin Howard01055ba2018-11-03 11:00:21 -06001873 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001874 bool aone;
Gavin Howard01055ba2018-11-03 11:00:21 -06001875
Gavin Howard01055ba2018-11-03 11:00:21 -06001876 if (a->len == 0 || b->len == 0) {
1877 bc_num_zero(c);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001878 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001879 }
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001880 aone = BC_NUM_ONE(a);
1881 if (aone || BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06001882 bc_num_copy(c, aone ? b : a);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001883 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001884 }
1885
Denys Vlasenkocc4303f2021-01-06 14:00:53 +01001886 if (a->len < BC_NUM_KARATSUBA_LEN
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001887 || b->len < BC_NUM_KARATSUBA_LEN
Denys Vlasenkocc4303f2021-01-06 14:00:53 +01001888 /* || a->len + b->len < BC_NUM_KARATSUBA_LEN - redundant check */
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001889 ) {
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001890 size_t i, j, len;
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001891
Gavin Howard01055ba2018-11-03 11:00:21 -06001892 bc_num_expand(c, a->len + b->len + 1);
1893
1894 memset(c->num, 0, sizeof(BcDig) * c->cap);
Denys Vlasenkob692c2f2018-12-05 18:56:14 +01001895 c->len = len = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06001896
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001897 for (i = 0; i < b->len; ++i) {
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001898 unsigned carry = 0;
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01001899 for (j = 0; j < a->len; ++j) {
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001900 unsigned in = c->num[i + j];
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01001901 in += (unsigned)a->num[j] * (unsigned)b->num[i] + carry;
Denys Vlasenkob3cb9012018-12-05 19:05:32 +01001902 // note: compilers prefer _unsigned_ div/const
Gavin Howard01055ba2018-11-03 11:00:21 -06001903 carry = in / 10;
1904 c->num[i + j] = (BcDig)(in % 10);
1905 }
1906
1907 c->num[i + j] += (BcDig) carry;
1908 len = BC_MAX(len, i + j + !!carry);
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01001909
Denys Vlasenko14767602018-12-27 22:52:13 +01001910#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01001911 // a=2^1000000
1912 // a*a <- without check below, this will not be interruptible
1913 if (G_interrupt) return BC_STATUS_FAILURE;
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001914#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06001915 }
1916
1917 c->len = len;
1918
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001919 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06001920 }
1921
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01001922 max = BC_MAX(a->len, b->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06001923 bc_num_init(&l1, max);
1924 bc_num_init(&h1, max);
1925 bc_num_init(&l2, max);
1926 bc_num_init(&h2, max);
1927 bc_num_init(&m1, max);
1928 bc_num_init(&m2, max);
1929 bc_num_init(&z0, max);
1930 bc_num_init(&z1, max);
1931 bc_num_init(&z2, max);
1932 bc_num_init(&temp, max + max);
1933
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01001934 max2 = (max + 1) / 2;
Gavin Howard01055ba2018-11-03 11:00:21 -06001935 bc_num_split(a, max2, &l1, &h1);
1936 bc_num_split(b, max2, &l2, &h2);
1937
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001938 s = zbc_num_add(&h1, &l1, &m1, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001939 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001940 s = zbc_num_add(&h2, &l2, &m2, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001941 if (s) goto err;
1942
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001943 s = zbc_num_k(&h1, &h2, &z0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001944 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001945 s = zbc_num_k(&m1, &m2, &z1);
Gavin Howard01055ba2018-11-03 11:00:21 -06001946 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001947 s = zbc_num_k(&l1, &l2, &z2);
Gavin Howard01055ba2018-11-03 11:00:21 -06001948 if (s) goto err;
1949
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001950 s = zbc_num_sub(&z1, &z0, &temp, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001951 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001952 s = zbc_num_sub(&temp, &z2, &z1, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001953 if (s) goto err;
1954
Denys Vlasenko29301232018-12-11 15:29:32 +01001955 s = zbc_num_shift(&z0, max2 * 2);
Gavin Howard01055ba2018-11-03 11:00:21 -06001956 if (s) goto err;
Denys Vlasenko29301232018-12-11 15:29:32 +01001957 s = zbc_num_shift(&z1, max2);
Gavin Howard01055ba2018-11-03 11:00:21 -06001958 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001959 s = zbc_num_add(&z0, &z1, &temp, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06001960 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001961 s = zbc_num_add(&temp, &z2, c, 0);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01001962 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06001963 bc_num_free(&temp);
1964 bc_num_free(&z2);
1965 bc_num_free(&z1);
1966 bc_num_free(&z0);
1967 bc_num_free(&m2);
1968 bc_num_free(&m1);
1969 bc_num_free(&h2);
1970 bc_num_free(&l2);
1971 bc_num_free(&h1);
1972 bc_num_free(&l1);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001973 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06001974}
1975
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01001976static FAST_FUNC BC_STATUS zbc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06001977{
1978 BcStatus s;
1979 BcNum cpa, cpb;
1980 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1981
1982 scale = BC_MAX(scale, a->rdx);
1983 scale = BC_MAX(scale, b->rdx);
1984 scale = BC_MIN(a->rdx + b->rdx, scale);
1985 maxrdx = BC_MAX(maxrdx, scale);
1986
1987 bc_num_init(&cpa, a->len);
1988 bc_num_init(&cpb, b->len);
1989
1990 bc_num_copy(&cpa, a);
1991 bc_num_copy(&cpb, b);
1992 cpa.neg = cpb.neg = false;
1993
Denys Vlasenko29301232018-12-11 15:29:32 +01001994 s = zbc_num_shift(&cpa, maxrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06001995 if (s) goto err;
Denys Vlasenko29301232018-12-11 15:29:32 +01001996 s = zbc_num_shift(&cpb, maxrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06001997 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01001998 s = zbc_num_k(&cpa, &cpb, c);
Gavin Howard01055ba2018-11-03 11:00:21 -06001999 if (s) goto err;
2000
2001 maxrdx += scale;
2002 bc_num_expand(c, c->len + maxrdx);
2003
2004 if (c->len < maxrdx) {
2005 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
2006 c->len += maxrdx;
2007 }
2008
2009 c->rdx = maxrdx;
2010 bc_num_retireMul(c, scale, a->neg, b->neg);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01002011 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06002012 bc_num_free(&cpb);
2013 bc_num_free(&cpa);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002014 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002015}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002016#define zbc_num_m(...) (zbc_num_m(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002017
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002018static FAST_FUNC BC_STATUS zbc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06002019{
Denys Vlasenko5c0c5ab2018-12-18 13:15:55 +01002020 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06002021 size_t len, end, i;
2022 BcNum cp;
Gavin Howard01055ba2018-11-03 11:00:21 -06002023
2024 if (b->len == 0)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002025 RETURN_STATUS(bc_error("divide by zero"));
2026 if (a->len == 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002027 bc_num_setToZero(c, scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002028 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002029 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002030 if (BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002031 bc_num_copy(c, a);
2032 bc_num_retireMul(c, scale, a->neg, b->neg);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002033 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002034 }
2035
2036 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
2037 bc_num_copy(&cp, a);
2038 len = b->len;
2039
2040 if (len > cp.len) {
2041 bc_num_expand(&cp, len + 2);
2042 bc_num_extend(&cp, len - cp.len);
2043 }
2044
2045 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
2046 cp.rdx -= b->rdx;
2047 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
2048
2049 if (b->rdx == b->len) {
Denys Vlasenko71c82d12018-12-18 12:43:21 +01002050 for (;;) {
2051 if (len == 0) break;
2052 len--;
2053 if (b->num[len] != 0)
2054 break;
2055 }
2056 len++;
Gavin Howard01055ba2018-11-03 11:00:21 -06002057 }
2058
2059 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
2060
2061 // We want an extra zero in front to make things simpler.
2062 cp.num[cp.len++] = 0;
2063 end = cp.len - len;
2064
2065 bc_num_expand(c, cp.len);
2066
2067 bc_num_zero(c);
2068 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
2069 c->rdx = cp.rdx;
2070 c->len = cp.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06002071
Denys Vlasenko5c0c5ab2018-12-18 13:15:55 +01002072 s = BC_STATUS_SUCCESS;
2073 for (i = end - 1; i < end; --i) {
2074 BcDig *n, q;
Gavin Howard01055ba2018-11-03 11:00:21 -06002075 n = cp.num + i;
Denys Vlasenko5c0c5ab2018-12-18 13:15:55 +01002076 for (q = 0; n[len] != 0 || bc_num_compare(n, b->num, len) >= 0; ++q)
2077 bc_num_subArrays(n, b->num, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06002078 c->num[i] = q;
Denys Vlasenko14767602018-12-27 22:52:13 +01002079#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenkof381a882018-12-05 19:21:34 +01002080 // a=2^100000
2081 // scale=40000
2082 // 1/a <- without check below, this will not be interruptible
2083 if (G_interrupt) {
2084 s = BC_STATUS_FAILURE;
2085 break;
2086 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002087#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06002088 }
2089
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002090 bc_num_retireMul(c, scale, a->neg, b->neg);
Gavin Howard01055ba2018-11-03 11:00:21 -06002091 bc_num_free(&cp);
2092
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002093 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002094}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002095#define zbc_num_d(...) (zbc_num_d(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002096
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002097static FAST_FUNC BC_STATUS zbc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
Gavin Howard01055ba2018-11-03 11:00:21 -06002098 BcNum *restrict d, size_t scale, size_t ts)
2099{
2100 BcStatus s;
2101 BcNum temp;
2102 bool neg;
2103
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002104 if (b->len == 0)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002105 RETURN_STATUS(bc_error("divide by zero"));
Gavin Howard01055ba2018-11-03 11:00:21 -06002106
2107 if (a->len == 0) {
2108 bc_num_setToZero(d, ts);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002109 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002110 }
2111
2112 bc_num_init(&temp, d->cap);
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002113 s = zbc_num_d(a, b, c, scale);
Denys Vlasenkof381a882018-12-05 19:21:34 +01002114 if (s) goto err;
Gavin Howard01055ba2018-11-03 11:00:21 -06002115
2116 if (scale != 0) scale = ts;
2117
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002118 s = zbc_num_m(c, b, &temp, scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06002119 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002120 s = zbc_num_sub(a, &temp, d, scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06002121 if (s) goto err;
2122
2123 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
2124
2125 neg = d->neg;
2126 bc_num_retireMul(d, ts, a->neg, b->neg);
2127 d->neg = neg;
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01002128 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06002129 bc_num_free(&temp);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002130 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002131}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002132#define zbc_num_r(...) (zbc_num_r(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002133
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002134static FAST_FUNC BC_STATUS zbc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06002135{
2136 BcStatus s;
2137 BcNum c1;
2138 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2139
2140 bc_num_init(&c1, len);
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002141 s = zbc_num_r(a, b, &c1, c, scale, ts);
Gavin Howard01055ba2018-11-03 11:00:21 -06002142 bc_num_free(&c1);
2143
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002144 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002145}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002146#define zbc_num_rem(...) (zbc_num_rem(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002147
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002148static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06002149{
2150 BcStatus s = BC_STATUS_SUCCESS;
2151 BcNum copy;
2152 unsigned long pow;
2153 size_t i, powrdx, resrdx;
Denys Vlasenko6b0fbd12018-12-18 12:55:40 +01002154 bool neg;
Gavin Howard01055ba2018-11-03 11:00:21 -06002155
Denys Vlasenko1acac7f2018-12-22 23:14:48 +01002156 // GNU bc does not allow 2^2.0 - we do
2157 for (i = 0; i < b->rdx; i++)
2158 if (b->num[i] != 0)
2159 RETURN_STATUS(bc_error("not an integer"));
Gavin Howard01055ba2018-11-03 11:00:21 -06002160
2161 if (b->len == 0) {
2162 bc_num_one(c);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002163 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002164 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002165 if (a->len == 0) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002166 bc_num_setToZero(c, scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002167 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002168 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002169 if (BC_NUM_ONE(b)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002170 if (!b->neg)
2171 bc_num_copy(c, a);
2172 else
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002173 s = zbc_num_inv(a, c, scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002174 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002175 }
2176
2177 neg = b->neg;
Denys Vlasenkoa9f59db2018-12-22 21:52:30 +01002178 s = zbc_num_ulong_abs(b, &pow);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002179 if (s) RETURN_STATUS(s);
Denys Vlasenko2ea8ddf2018-12-22 21:45:18 +01002180 // b is not used beyond this point
Gavin Howard01055ba2018-11-03 11:00:21 -06002181
2182 bc_num_init(&copy, a->len);
2183 bc_num_copy(&copy, a);
2184
Denys Vlasenko2d615fe2018-12-07 16:22:45 +01002185 if (!neg) {
2186 if (a->rdx > scale)
2187 scale = a->rdx;
2188 if (a->rdx * pow < scale)
2189 scale = a->rdx * pow;
2190 }
Gavin Howard01055ba2018-11-03 11:00:21 -06002191
Gavin Howard01055ba2018-11-03 11:00:21 -06002192
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002193 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002194 powrdx <<= 1;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002195 s = zbc_num_mul(&copy, &copy, &copy, powrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002196 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002197 // Not needed: zbc_num_mul() has a check for ^C:
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002198 //if (G_interrupt) {
2199 // s = BC_STATUS_FAILURE;
2200 // goto err;
2201 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002202 }
2203
Gavin Howard01055ba2018-11-03 11:00:21 -06002204 bc_num_copy(c, &copy);
2205
Denys Vlasenko71e1fc62018-12-02 19:43:34 +01002206 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002207 powrdx <<= 1;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002208 s = zbc_num_mul(&copy, &copy, &copy, powrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002209 if (s) goto err;
2210
2211 if (pow & 1) {
2212 resrdx += powrdx;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002213 s = zbc_num_mul(c, &copy, c, resrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002214 if (s) goto err;
2215 }
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002216 // Not needed: zbc_num_mul() has a check for ^C:
Denys Vlasenko06fa65b2018-12-05 19:00:58 +01002217 //if (G_interrupt) {
2218 // s = BC_STATUS_FAILURE;
2219 // goto err;
2220 //}
Gavin Howard01055ba2018-11-03 11:00:21 -06002221 }
2222
2223 if (neg) {
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002224 s = zbc_num_inv(c, c, scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06002225 if (s) goto err;
2226 }
2227
Gavin Howard01055ba2018-11-03 11:00:21 -06002228 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2229
2230 // We can't use bc_num_clean() here.
Denys Vlasenko6b0fbd12018-12-18 12:55:40 +01002231 for (i = 0; i < c->len; ++i)
2232 if (c->num[i] != 0)
2233 goto skip;
2234 bc_num_setToZero(c, scale);
2235 skip:
Gavin Howard01055ba2018-11-03 11:00:21 -06002236
Denys Vlasenko6b0fbd12018-12-18 12:55:40 +01002237 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06002238 bc_num_free(&copy);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002239 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002240}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002241#define zbc_num_p(...) (zbc_num_p(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002242
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002243static BC_STATUS zbc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
Gavin Howard01055ba2018-11-03 11:00:21 -06002244{
2245 BcStatus s;
2246 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01002247 BcDig half_digs[1];
Denys Vlasenko40f9fe22020-12-29 16:54:37 +01002248 size_t pow, len, digs, digs1, resrdx, req, times;
2249 ssize_t cmp, cmp1, cmp2;
Gavin Howard01055ba2018-11-03 11:00:21 -06002250
2251 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2252 bc_num_expand(b, req);
2253
2254 if (a->len == 0) {
2255 bc_num_setToZero(b, scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002256 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01002257 }
2258 if (a->neg) {
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002259 RETURN_STATUS(bc_error("negative number"));
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01002260 }
2261 if (BC_NUM_ONE(a)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002262 bc_num_one(b);
2263 bc_num_extend(b, scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002264 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06002265 }
2266
2267 scale = BC_MAX(scale, a->rdx) + 1;
2268 len = a->len + scale;
2269
2270 bc_num_init(&num1, len);
2271 bc_num_init(&num2, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06002272
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01002273 half.cap = ARRAY_SIZE(half_digs);
2274 half.num = half_digs;
Gavin Howard01055ba2018-11-03 11:00:21 -06002275 bc_num_one(&half);
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01002276 half_digs[0] = 5;
Gavin Howard01055ba2018-11-03 11:00:21 -06002277 half.rdx = 1;
2278
2279 bc_num_init(&f, len);
2280 bc_num_init(&fprime, len);
2281
2282 x0 = &num1;
2283 x1 = &num2;
2284
2285 bc_num_one(x0);
2286 pow = BC_NUM_INT(a);
2287
2288 if (pow) {
Gavin Howard01055ba2018-11-03 11:00:21 -06002289 if (pow & 1)
2290 x0->num[0] = 2;
2291 else
2292 x0->num[0] = 6;
2293
2294 pow -= 2 - (pow & 1);
2295
2296 bc_num_extend(x0, pow);
2297
2298 // Make sure to move the radix back.
2299 x0->rdx -= pow;
2300 }
2301
Denys Vlasenko40f9fe22020-12-29 16:54:37 +01002302 x0->rdx = digs = digs1 = times = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06002303 resrdx = scale + 2;
Denys Vlasenko40f9fe22020-12-29 16:54:37 +01002304 len = x0->len + resrdx - 1;
2305 cmp = 1;
2306 cmp1 = cmp2 = SSIZE_MAX;
2307 do {
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002308 s = zbc_num_div(a, x0, &f, resrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002309 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002310 s = zbc_num_add(x0, &f, &fprime, resrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002311 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002312 s = zbc_num_mul(&fprime, &half, x1, resrdx);
Gavin Howard01055ba2018-11-03 11:00:21 -06002313 if (s) goto err;
2314
2315 cmp = bc_num_cmp(x1, x0);
2316 digs = x1->len - (unsigned long long) llabs(cmp);
2317
2318 if (cmp == cmp2 && digs == digs1)
2319 times += 1;
2320 else
2321 times = 0;
2322
2323 resrdx += times > 4;
2324
2325 cmp2 = cmp1;
2326 cmp1 = cmp;
2327 digs1 = digs;
2328
2329 temp = x0;
2330 x0 = x1;
2331 x1 = temp;
Denys Vlasenko40f9fe22020-12-29 16:54:37 +01002332 } while (cmp != 0 || digs < len);
Gavin Howard01055ba2018-11-03 11:00:21 -06002333
Gavin Howard01055ba2018-11-03 11:00:21 -06002334 bc_num_copy(b, x0);
2335 scale -= 1;
Denys Vlasenko40f9fe22020-12-29 16:54:37 +01002336 if (b->rdx > scale)
2337 bc_num_truncate(b, b->rdx - scale);
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01002338 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06002339 bc_num_free(&fprime);
2340 bc_num_free(&f);
Gavin Howard01055ba2018-11-03 11:00:21 -06002341 bc_num_free(&num2);
2342 bc_num_free(&num1);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002343 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002344}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002345#define zbc_num_sqrt(...) (zbc_num_sqrt(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002346
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002347static BC_STATUS zbc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
Gavin Howard01055ba2018-11-03 11:00:21 -06002348 size_t scale)
2349{
2350 BcStatus s;
2351 BcNum num2, *ptr_a;
2352 bool init = false;
2353 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2354
2355 if (c == a) {
2356 memcpy(&num2, c, sizeof(BcNum));
2357 ptr_a = &num2;
2358 bc_num_init(c, len);
2359 init = true;
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01002360 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06002361 ptr_a = a;
2362 bc_num_expand(c, len);
2363 }
2364
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002365 s = zbc_num_r(ptr_a, b, c, d, scale, ts);
Gavin Howard01055ba2018-11-03 11:00:21 -06002366
2367 if (init) bc_num_free(&num2);
2368
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002369 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002370}
Denys Vlasenkoec603182018-12-17 10:34:02 +01002371#define zbc_num_divmod(...) (zbc_num_divmod(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002372
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002373#if ENABLE_DC
Denys Vlasenkofa210792018-12-19 19:35:40 +01002374static BC_STATUS zdc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
Gavin Howard01055ba2018-11-03 11:00:21 -06002375{
2376 BcStatus s;
2377 BcNum base, exp, two, temp;
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01002378 BcDig two_digs[1];
Gavin Howard01055ba2018-11-03 11:00:21 -06002379
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002380 if (c->len == 0)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002381 RETURN_STATUS(bc_error("divide by zero"));
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002382 if (a->rdx || b->rdx || c->rdx)
Denys Vlasenko1acac7f2018-12-22 23:14:48 +01002383 RETURN_STATUS(bc_error("not an integer"));
Denys Vlasenko60cf7472018-12-04 20:05:28 +01002384 if (b->neg)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002385 RETURN_STATUS(bc_error("negative number"));
Gavin Howard01055ba2018-11-03 11:00:21 -06002386
2387 bc_num_expand(d, c->len);
2388 bc_num_init(&base, c->len);
2389 bc_num_init(&exp, b->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06002390 bc_num_init(&temp, b->len);
2391
Denys Vlasenko01eb5e92018-12-22 23:59:21 +01002392 two.cap = ARRAY_SIZE(two_digs);
2393 two.num = two_digs;
Gavin Howard01055ba2018-11-03 11:00:21 -06002394 bc_num_one(&two);
Denys Vlasenko01eb5e92018-12-22 23:59:21 +01002395 two_digs[0] = 2;
2396
Gavin Howard01055ba2018-11-03 11:00:21 -06002397 bc_num_one(d);
2398
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002399 s = zbc_num_rem(a, c, &base, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002400 if (s) goto err;
2401 bc_num_copy(&exp, b);
2402
2403 while (exp.len != 0) {
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002404 s = zbc_num_divmod(&exp, &two, &exp, &temp, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002405 if (s) goto err;
2406
2407 if (BC_NUM_ONE(&temp)) {
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002408 s = zbc_num_mul(d, &base, &temp, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002409 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002410 s = zbc_num_rem(&temp, c, d, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002411 if (s) goto err;
2412 }
2413
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002414 s = zbc_num_mul(&base, &base, &temp, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002415 if (s) goto err;
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01002416 s = zbc_num_rem(&temp, c, &base, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06002417 if (s) goto err;
2418 }
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01002419 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06002420 bc_num_free(&temp);
Gavin Howard01055ba2018-11-03 11:00:21 -06002421 bc_num_free(&exp);
2422 bc_num_free(&base);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01002423 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06002424}
Denys Vlasenkofa210792018-12-19 19:35:40 +01002425#define zdc_num_modexp(...) (zdc_num_modexp(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06002426#endif // ENABLE_DC
2427
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01002428static FAST_FUNC void bc_string_free(void *string)
2429{
2430 free(*(char**)string);
2431}
2432
Gavin Howard01055ba2018-11-03 11:00:21 -06002433static void bc_func_init(BcFunc *f)
2434{
Denys Vlasenko7d628012018-12-04 21:46:47 +01002435 bc_char_vec_init(&f->code);
Denys Vlasenko503faf92018-12-20 16:24:18 +01002436 IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);)
2437 IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01002438 IF_BC(bc_vec_init(&f->strs, sizeof(char *), bc_string_free);)
2439 IF_BC(bc_vec_init(&f->consts, sizeof(char *), bc_string_free);)
Denys Vlasenko503faf92018-12-20 16:24:18 +01002440 IF_BC(f->nparams = 0;)
Gavin Howard01055ba2018-11-03 11:00:21 -06002441}
2442
Denys Vlasenko5ba55f12018-12-10 15:37:14 +01002443static FAST_FUNC void bc_func_free(void *func)
Gavin Howard01055ba2018-11-03 11:00:21 -06002444{
2445 BcFunc *f = (BcFunc *) func;
2446 bc_vec_free(&f->code);
Denys Vlasenko503faf92018-12-20 16:24:18 +01002447 IF_BC(bc_vec_free(&f->labels);)
2448 IF_BC(bc_vec_free(&f->autos);)
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01002449 IF_BC(bc_vec_free(&f->strs);)
2450 IF_BC(bc_vec_free(&f->consts);)
Gavin Howard01055ba2018-11-03 11:00:21 -06002451}
2452
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002453static void bc_array_expand(BcVec *a, size_t len);
2454
Gavin Howard01055ba2018-11-03 11:00:21 -06002455static void bc_array_init(BcVec *a, bool nums)
2456{
2457 if (nums)
2458 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2459 else
2460 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2461 bc_array_expand(a, 1);
2462}
2463
Gavin Howard01055ba2018-11-03 11:00:21 -06002464static void bc_array_expand(BcVec *a, size_t len)
2465{
Denys Vlasenkod6e24bd2018-12-18 20:10:48 +01002466 if (a->dtor == bc_num_free
2467 // && a->size == sizeof(BcNum) - always true
2468 ) {
2469 BcNum n;
Gavin Howard01055ba2018-11-03 11:00:21 -06002470 while (len > a->len) {
Denys Vlasenkod6e24bd2018-12-18 20:10:48 +01002471 bc_num_init_DEF_SIZE(&n);
2472 bc_vec_push(a, &n);
Gavin Howard01055ba2018-11-03 11:00:21 -06002473 }
Denys Vlasenkoe2e6ffd2018-12-18 12:23:16 +01002474 } else {
Denys Vlasenkod6e24bd2018-12-18 20:10:48 +01002475 BcVec v;
Gavin Howard01055ba2018-11-03 11:00:21 -06002476 while (len > a->len) {
Denys Vlasenkod6e24bd2018-12-18 20:10:48 +01002477 bc_array_init(&v, true);
2478 bc_vec_push(a, &v);
Gavin Howard01055ba2018-11-03 11:00:21 -06002479 }
2480 }
2481}
2482
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002483static void bc_array_copy(BcVec *d, const BcVec *s)
2484{
Denys Vlasenkoeac0de52018-12-19 17:59:30 +01002485 BcNum *dnum, *snum;
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002486 size_t i;
2487
2488 bc_vec_pop_all(d);
2489 bc_vec_expand(d, s->cap);
2490 d->len = s->len;
2491
Denys Vlasenkoeac0de52018-12-19 17:59:30 +01002492 dnum = (void*)d->v;
2493 snum = (void*)s->v;
2494 for (i = 0; i < s->len; i++, dnum++, snum++) {
Denys Vlasenkob0e37612018-12-05 21:03:16 +01002495 bc_num_init(dnum, snum->len);
2496 bc_num_copy(dnum, snum);
2497 }
2498}
2499
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01002500#if ENABLE_DC
Denys Vlasenkofa210792018-12-19 19:35:40 +01002501static void dc_result_copy(BcResult *d, BcResult *src)
Gavin Howard01055ba2018-11-03 11:00:21 -06002502{
2503 d->t = src->t;
2504
2505 switch (d->t) {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002506 case XC_RESULT_TEMP:
2507 case XC_RESULT_IBASE:
2508 case XC_RESULT_SCALE:
2509 case XC_RESULT_OBASE:
Gavin Howard01055ba2018-11-03 11:00:21 -06002510 bc_num_init(&d->d.n, src->d.n.len);
2511 bc_num_copy(&d->d.n, &src->d.n);
2512 break;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002513 case XC_RESULT_VAR:
2514 case XC_RESULT_ARRAY:
2515 case XC_RESULT_ARRAY_ELEM:
Gavin Howard01055ba2018-11-03 11:00:21 -06002516 d->d.id.name = xstrdup(src->d.id.name);
2517 break;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002518 case XC_RESULT_CONSTANT:
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002519 case XC_RESULT_STR:
Gavin Howard01055ba2018-11-03 11:00:21 -06002520 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2521 break;
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01002522 default: // placate compiler
2523 // BC_RESULT_VOID, BC_RESULT_LAST, BC_RESULT_ONE - do not happen
2524 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06002525 }
2526}
2527#endif // ENABLE_DC
2528
Denys Vlasenko5ba55f12018-12-10 15:37:14 +01002529static FAST_FUNC void bc_result_free(void *result)
Gavin Howard01055ba2018-11-03 11:00:21 -06002530{
2531 BcResult *r = (BcResult *) result;
2532
2533 switch (r->t) {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002534 case XC_RESULT_TEMP:
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01002535 IF_BC(case BC_RESULT_VOID:)
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002536 case XC_RESULT_IBASE:
2537 case XC_RESULT_SCALE:
2538 case XC_RESULT_OBASE:
Gavin Howard01055ba2018-11-03 11:00:21 -06002539 bc_num_free(&r->d.n);
2540 break;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01002541 case XC_RESULT_VAR:
2542 case XC_RESULT_ARRAY:
2543 case XC_RESULT_ARRAY_ELEM:
Gavin Howard01055ba2018-11-03 11:00:21 -06002544 free(r->d.id.name);
2545 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06002546 default:
Gavin Howard01055ba2018-11-03 11:00:21 -06002547 // Do nothing.
2548 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06002549 }
2550}
2551
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002552static int bad_input_byte(char c)
2553{
2554 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
2555 || c > 0x7e
2556 ) {
2557 bc_error_fmt("illegal character 0x%02x", c);
2558 return 1;
2559 }
2560 return 0;
2561}
2562
Denys Vlasenko10bde142018-12-27 18:23:58 +01002563static void xc_read_line(BcVec *vec, FILE *fp)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002564{
2565 again:
Denys Vlasenkob1b79962018-12-26 18:46:03 +01002566 bc_vec_pop_all(vec);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002567 fflush_and_check();
2568
Denys Vlasenko14767602018-12-27 22:52:13 +01002569#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002570 if (G_interrupt) { // ^C was pressed
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002571 if (fp != stdin) {
2572 // ^C while running a script (bc SCRIPT): die.
2573 // We do not return to interactive prompt:
2574 // user might be running us from a shell,
2575 // and SCRIPT might be intended to terminate
2576 // (e.g. contain a "halt" stmt).
2577 // ^C dropping user into a bc prompt instead of
2578 // the shell would be unexpected.
2579 xfunc_die();
2580 }
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01002581 // There was ^C while running calculations
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002582 G_interrupt = 0;
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01002583 // GNU bc says "interrupted execution." (to stdout, not stderr)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002584 // GNU dc says "Interrupt!"
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01002585 puts("\ninterrupted execution");
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002586 }
2587
2588# if ENABLE_FEATURE_EDITING
2589 if (G_ttyin && fp == stdin) {
2590 int n, i;
Denys Vlasenko00eb23b2020-12-21 21:36:58 +01002591 if (!G.line_input_state)
2592 G.line_input_state = new_line_input_t(DO_HISTORY);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002593# define line_buf bb_common_bufsiz1
2594 n = read_line_input(G.line_input_state, "", line_buf, COMMON_BUFSIZE);
2595 if (n <= 0) { // read errors or EOF, or ^D, or ^C
Denys Vlasenko0197fbf2021-01-04 14:41:20 +01002596 //GNU bc prints this on ^C:
2597 //if (n == 0) // ^C
2598 // puts("(interrupt) Exiting bc.");
2599 bc_vec_pushZeroByte(vec);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002600 return;
2601 }
2602 i = 0;
2603 for (;;) {
2604 char c = line_buf[i++];
Denys Vlasenko51b510a2019-01-01 02:19:02 +01002605 if (c == '\0') break;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002606 if (bad_input_byte(c)) goto again;
2607 }
Denys Vlasenkob1b79962018-12-26 18:46:03 +01002608 bc_vec_string(vec, n, line_buf);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002609# undef line_buf
2610 } else
2611# endif
2612#endif
2613 {
2614 int c;
2615 bool bad_chars = 0;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002616
2617 do {
Denys Vlasenko51b510a2019-01-01 02:19:02 +01002618 get_char:
Denys Vlasenko14767602018-12-27 22:52:13 +01002619#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002620 if (G_interrupt) {
2621 // ^C was pressed: ignore entire line, get another one
Denys Vlasenko51b510a2019-01-01 02:19:02 +01002622 goto again;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002623 }
2624#endif
Denys Vlasenko51b510a2019-01-01 02:19:02 +01002625 c = fgetc(fp);
2626 if (c == '\0')
2627 goto get_char;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002628 if (c == EOF) {
2629 if (ferror(fp))
James Byrne69374872019-07-02 11:35:03 +02002630 bb_simple_perror_msg_and_die("input error");
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002631 // Note: EOF does not append '\n'
2632 break;
2633 }
2634 bad_chars |= bad_input_byte(c);
2635 bc_vec_pushByte(vec, (char)c);
2636 } while (c != '\n');
2637
2638 if (bad_chars) {
2639 // Bad chars on this line
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01002640 if (!G.prs.lex_filename) { // stdin
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002641 // ignore entire line, get another one
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002642 goto again;
2643 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01002644 bb_perror_msg_and_die("file '%s' is not text", G.prs.lex_filename);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002645 }
2646 bc_vec_pushZeroByte(vec);
2647 }
2648}
2649
2650//
2651// Parsing routines
2652//
2653
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002654// "Input numbers may contain the characters 0-9 and A-Z.
2655// (Note: They must be capitals. Lower case letters are variable names.)
2656// Single digit numbers always have the value of the digit regardless of
2657// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
2658// all input digits greater or equal to ibase to the value of ibase-1.
2659// This makes the number ZZZ always be the largest 3 digit number of the
2660// input base."
2661static bool xc_num_strValid(const char *val)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002662{
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002663 bool radix = false;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002664 for (;;) {
2665 BcDig c = *val++;
2666 if (c == '\0')
2667 break;
2668 if (c == '.') {
2669 if (radix) return false;
2670 radix = true;
2671 continue;
2672 }
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002673 if ((c < '0' || c > '9') && (c < 'A' || c > 'Z'))
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002674 return false;
2675 }
2676 return true;
2677}
2678
2679// Note: n is already "bc_num_zero()"ed,
2680// leading zeroes in "val" are removed
2681static void bc_num_parseDecimal(BcNum *n, const char *val)
2682{
2683 size_t len, i;
2684 const char *ptr;
2685
2686 len = strlen(val);
2687 if (len == 0)
2688 return;
2689
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002690 bc_num_expand(n, len + 1); // +1 for e.g. "A" converting into 10
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002691
2692 ptr = strchr(val, '.');
2693
2694 n->rdx = 0;
2695 if (ptr != NULL)
2696 n->rdx = (size_t)((val + len) - (ptr + 1));
2697
2698 for (i = 0; val[i]; ++i) {
2699 if (val[i] != '0' && val[i] != '.') {
2700 // Not entirely zero value - convert it, and exit
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002701 if (len == 1) {
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002702 unsigned c = val[0] - '0';
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002703 n->len = 1;
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002704 if (c > 9) { // A-Z => 10-36
2705 n->len = 2;
2706 c -= ('A' - '9' - 1);
2707 n->num[1] = c/10;
2708 c = c%10;
2709 }
2710 n->num[0] = c;
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002711 break;
2712 }
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002713 i = len - 1;
2714 for (;;) {
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002715 char c = val[i] - '0';
2716 if (c > 9) // A-Z => 9
2717 c = 9;
2718 n->num[n->len] = c;
2719 n->len++;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002720 skip_dot:
2721 if (i == 0) break;
2722 if (val[--i] == '.') goto skip_dot;
2723 }
2724 break;
2725 }
2726 }
2727 // if for() exits without hitting if(), the value is entirely zero
2728}
2729
2730// Note: n is already "bc_num_zero()"ed,
2731// leading zeroes in "val" are removed
2732static void bc_num_parseBase(BcNum *n, const char *val, unsigned base_t)
2733{
2734 BcStatus s;
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002735 BcNum mult, result;
2736 BcNum temp;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002737 BcNum base;
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002738 BcDig temp_digs[ULONG_NUM_BUFSIZE];
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002739 BcDig base_digs[ULONG_NUM_BUFSIZE];
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002740 size_t digits;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002741
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002742 bc_num_init_DEF_SIZE(&mult);
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002743
2744 temp.cap = ARRAY_SIZE(temp_digs);
2745 temp.num = temp_digs;
2746
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002747 base.cap = ARRAY_SIZE(base_digs);
2748 base.num = base_digs;
2749 bc_num_ulong2num(&base, base_t);
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002750 base_t--;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002751
2752 for (;;) {
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002753 unsigned v;
Denys Vlasenko8797adc2018-12-31 19:50:06 +01002754 char c;
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002755
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002756 c = *val++;
2757 if (c == '\0') goto int_err;
2758 if (c == '.') break;
2759
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002760 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2761 if (v > base_t) v = base_t;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002762
2763 s = zbc_num_mul(n, &base, &mult, 0);
2764 if (s) goto int_err;
2765 bc_num_ulong2num(&temp, v);
2766 s = zbc_num_add(&mult, &temp, n, 0);
2767 if (s) goto int_err;
2768 }
2769
2770 bc_num_init(&result, base.len);
2771 //bc_num_zero(&result); - already is
2772 bc_num_one(&mult);
2773
2774 digits = 0;
2775 for (;;) {
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002776 unsigned v;
Denys Vlasenko8797adc2018-12-31 19:50:06 +01002777 char c;
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002778
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002779 c = *val++;
2780 if (c == '\0') break;
2781 digits++;
2782
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002783 v = (unsigned)(c <= '9' ? c - '0' : c - 'A' + 10);
2784 if (v > base_t) v = base_t;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002785
2786 s = zbc_num_mul(&result, &base, &result, 0);
2787 if (s) goto err;
2788 bc_num_ulong2num(&temp, v);
2789 s = zbc_num_add(&result, &temp, &result, 0);
2790 if (s) goto err;
2791 s = zbc_num_mul(&mult, &base, &mult, 0);
2792 if (s) goto err;
2793 }
2794
2795 s = zbc_num_div(&result, &mult, &result, digits);
2796 if (s) goto err;
2797 s = zbc_num_add(n, &result, n, digits);
2798 if (s) goto err;
2799
2800 if (n->len != 0) {
2801 if (n->rdx < digits)
2802 bc_num_extend(n, digits - n->rdx);
2803 } else
2804 bc_num_zero(n);
2805 err:
2806 bc_num_free(&result);
2807 int_err:
2808 bc_num_free(&mult);
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002809}
2810
Denys Vlasenko10bde142018-12-27 18:23:58 +01002811static BC_STATUS zxc_num_parse(BcNum *n, const char *val, unsigned base_t)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002812{
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002813 size_t i;
2814
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002815 if (!xc_num_strValid(val))
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002816 RETURN_STATUS(bc_error("bad number string"));
2817
2818 bc_num_zero(n);
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002819 while (*val == '0')
2820 val++;
2821 for (i = 0; ; ++i) {
2822 if (val[i] == '\0')
2823 RETURN_STATUS(BC_STATUS_SUCCESS);
2824 if (val[i] != '.' && val[i] != '0')
2825 break;
2826 }
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002827
Denys Vlasenko680ccd32018-12-31 19:42:13 +01002828 if (base_t == 10 || val[1] == '\0')
2829 // Decimal, or single-digit number
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002830 bc_num_parseDecimal(n, val);
2831 else
2832 bc_num_parseBase(n, val, base_t);
2833
2834 RETURN_STATUS(BC_STATUS_SUCCESS);
2835}
Denys Vlasenko10bde142018-12-27 18:23:58 +01002836#define zxc_num_parse(...) (zxc_num_parse(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01002837
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002838// p->lex_inbuf points to the current string to be parsed.
2839// if p->lex_inbuf points to '\0', it's either EOF or it points after
2840// last processed line's terminating '\n' (and more reading needs to be done
2841// to get next character).
2842//
2843// If you are in a situation where that is a possibility, call peek_inbuf().
2844// If necessary, it performs more reading and changes p->lex_inbuf,
2845// then it returns *p->lex_inbuf (which will be '\0' only if it's EOF).
2846// After it, just referencing *p->lex_inbuf is valid, and if it wasn't '\0',
2847// it's ok to do p->lex_inbuf++ once without end-of-buffer checking.
2848//
2849// eat_inbuf() is equvalent to "peek_inbuf(); if (c) p->lex_inbuf++":
2850// it returns current char and advances the pointer (if not EOF).
2851// After eat_inbuf(), referencing p->lex_inbuf[-1] and *p->lex_inbuf is valid.
2852//
2853// In many cases, you can use fast *p->lex_inbuf instead of peek_inbuf():
2854// unless prev char might have been '\n', *p->lex_inbuf is '\0' ONLY
2855// on real EOF, not end-of-buffer.
Denys Vlasenkob1b79962018-12-26 18:46:03 +01002856//
2857// bc cases to test interactively:
2858// 1 #comment\ - prints "1<newline>" at once (comment is not continued)
2859// 1 #comment/* - prints "1<newline>" at once
2860// 1 #comment" - prints "1<newline>" at once
2861// 1\#comment - error at once (\ is not a line continuation)
2862// 1 + /*"*/2 - prints "3<newline>" at once
2863// 1 + /*#*/2 - prints "3<newline>" at once
2864// "str\" - prints "str\" at once
2865// "str#" - prints "str#" at once
2866// "str/*" - prints "str/*" at once
2867// "str#\ - waits for second line
2868// end" - ...prints "str#\<newline>end"
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002869static char peek_inbuf(void)
2870{
Denys Vlasenko2747f612018-12-31 18:48:10 +01002871 if (*G.prs.lex_inbuf == '\0'
2872 && G.prs.lex_input_fp
2873 ) {
2874 xc_read_line(&G.input_buffer, G.prs.lex_input_fp);
2875 G.prs.lex_inbuf = G.input_buffer.v;
2876 if (G.input_buffer.len <= 1) // on EOF, len is 1 (NUL byte)
2877 G.prs.lex_input_fp = NULL;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002878 }
2879 return *G.prs.lex_inbuf;
2880}
2881static char eat_inbuf(void)
2882{
2883 char c = peek_inbuf();
2884 if (c) G.prs.lex_inbuf++;
2885 return c;
2886}
2887
Denys Vlasenko10bde142018-12-27 18:23:58 +01002888static void xc_lex_lineComment(void)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002889{
2890 BcParse *p = &G.prs;
2891 char c;
2892
2893 // Try: echo -n '#foo' | bc
2894 p->lex = XC_LEX_WHITESPACE;
2895
Denys Vlasenko2747f612018-12-31 18:48:10 +01002896 // Not peek_inbuf(): we depend on input being done in whole lines:
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002897 // '\0' which isn't the EOF can only be seen after '\n'.
2898 while ((c = *p->lex_inbuf) != '\n' && c != '\0')
2899 p->lex_inbuf++;
2900}
2901
Denys Vlasenko10bde142018-12-27 18:23:58 +01002902static void xc_lex_whitespace(void)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002903{
2904 BcParse *p = &G.prs;
2905
2906 p->lex = XC_LEX_WHITESPACE;
2907 for (;;) {
2908 // We depend here on input being done in whole lines:
2909 // '\0' which isn't the EOF can only be seen after '\n'.
2910 char c = *p->lex_inbuf;
2911 if (c == '\n') // this is XC_LEX_NLINE, not XC_LEX_WHITESPACE
2912 break;
2913 if (!isspace(c))
2914 break;
2915 p->lex_inbuf++;
2916 }
2917}
2918
Denys Vlasenko10bde142018-12-27 18:23:58 +01002919static BC_STATUS zxc_lex_number(char last)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002920{
2921 BcParse *p = &G.prs;
2922 bool pt;
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002923 char last_valid_ch;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002924
2925 bc_vec_pop_all(&p->lex_strnumbuf);
2926 bc_vec_pushByte(&p->lex_strnumbuf, last);
2927
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002928// bc: "Input numbers may contain the characters 0-9 and A-Z.
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002929// (Note: They must be capitals. Lower case letters are variable names.)
2930// Single digit numbers always have the value of the digit regardless of
2931// the value of ibase. (i.e. A = 10.) For multi-digit numbers, bc changes
2932// all input digits greater or equal to ibase to the value of ibase-1.
2933// This makes the number ZZZ always be the largest 3 digit number of the
2934// input base."
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002935// dc only allows A-F, the rules about single-char and multi-char are the same.
2936 last_valid_ch = (IS_BC ? 'Z' : 'F');
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002937 pt = (last == '.');
2938 p->lex = XC_LEX_NUMBER;
2939 for (;;) {
2940 // We depend here on input being done in whole lines:
2941 // '\0' which isn't the EOF can only be seen after '\n'.
2942 char c = *p->lex_inbuf;
2943 check_c:
2944 if (c == '\0')
2945 break;
2946 if (c == '\\' && p->lex_inbuf[1] == '\n') {
2947 p->lex_inbuf += 2;
2948 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01002949 dbg_lex("++p->lex_line=%zd", p->lex_line);
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002950 c = peek_inbuf(); // force next line to be read
2951 goto check_c;
2952 }
Denys Vlasenkod5b0fa62018-12-29 02:40:03 +01002953 if (!isdigit(c) && (c < 'A' || c > last_valid_ch)) {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002954 if (c != '.') break;
2955 // if '.' was already seen, stop on second one:
2956 if (pt) break;
2957 pt = true;
2958 }
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01002959 // c is one of "0-9A-Z."
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002960 last = c;
2961 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
2962 p->lex_inbuf++;
2963 }
2964 if (last == '.') // remove trailing '.' if any
2965 bc_vec_pop(&p->lex_strnumbuf);
2966 bc_vec_pushZeroByte(&p->lex_strnumbuf);
2967
2968 G.err_line = G.prs.lex_line;
2969 RETURN_STATUS(BC_STATUS_SUCCESS);
2970}
Denys Vlasenko10bde142018-12-27 18:23:58 +01002971#define zxc_lex_number(...) (zxc_lex_number(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002972
Denys Vlasenko10bde142018-12-27 18:23:58 +01002973static void xc_lex_name(void)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01002974{
2975 BcParse *p = &G.prs;
2976 size_t i;
2977 const char *buf;
2978
2979 p->lex = XC_LEX_NAME;
2980
2981 // Since names can't cross lines with \<newline>,
2982 // we depend on the fact that whole line is in the buffer
2983 i = 0;
2984 buf = p->lex_inbuf - 1;
2985 for (;;) {
2986 char c = buf[i];
2987 if ((c < 'a' || c > 'z') && !isdigit(c) && c != '_') break;
2988 i++;
2989 }
2990
2991#if 0 // We do not protect against people with gigabyte-long names
2992 // This check makes sense only if size_t is (much) larger than BC_MAX_STRING.
2993 if (SIZE_MAX > (BC_MAX_STRING | 0xff)) {
2994 if (i > BC_MAX_STRING)
2995 return bc_error("name too long: must be [1,"BC_MAX_STRING_STR"]");
2996 }
2997#endif
2998 bc_vec_string(&p->lex_strnumbuf, i, buf);
2999
3000 // Increment the index. We minus 1 because it has already been incremented.
3001 p->lex_inbuf += i - 1;
3002
3003 //return BC_STATUS_SUCCESS;
3004}
3005
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003006IF_BC(static BC_STATUS zbc_lex_token(void);)
3007IF_DC(static BC_STATUS zdc_lex_token(void);)
Denys Vlasenko5cf0b2d2018-12-22 18:24:19 +01003008#define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
3009#define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003010
Denys Vlasenko10bde142018-12-27 18:23:58 +01003011static BC_STATUS zxc_lex_next(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003012{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003013 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003014 BcStatus s;
3015
Denys Vlasenko22314682019-01-01 21:50:14 +01003016 G.err_line = p->lex_line;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003017 p->lex_last = p->lex;
Denys Vlasenko2f7352b2018-12-26 18:59:42 +01003018//why?
3019// if (p->lex_last == XC_LEX_EOF)
3020// RETURN_STATUS(bc_error("end of file"));
Gavin Howard01055ba2018-11-03 11:00:21 -06003021
3022 // Loop until failure or we don't have whitespace. This
3023 // is so the parser doesn't get inundated with whitespace.
Denys Vlasenko23ea0732018-12-24 15:05:49 +01003024 // Comments are also XC_LEX_WHITESPACE tokens and eaten here.
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003025 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003026 do {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003027 if (*p->lex_inbuf == '\0') {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003028 p->lex = XC_LEX_EOF;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003029 if (peek_inbuf() == '\0')
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01003030 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01003031 }
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003032 p->lex_next_at = p->lex_inbuf;
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01003033 dbg_lex("next string to parse:'%.*s'",
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003034 (int)(strchrnul(p->lex_next_at, '\n') - p->lex_next_at),
3035 p->lex_next_at
Denys Vlasenko26384542018-12-25 18:37:52 +01003036 );
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003037 if (IS_BC) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003038 IF_BC(s = zbc_lex_token());
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003039 } else {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003040 IF_DC(s = zdc_lex_token());
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003041 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003042 } while (!s && p->lex == XC_LEX_WHITESPACE);
3043 dbg_lex("p->lex from string:%d", p->lex);
Gavin Howard01055ba2018-11-03 11:00:21 -06003044
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003045 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003046}
Denys Vlasenko10bde142018-12-27 18:23:58 +01003047#define zxc_lex_next(...) (zxc_lex_next(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003048
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003049#if ENABLE_BC
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003050static BC_STATUS zbc_lex_skip_if_at_NLINE(void)
Denys Vlasenko202dd192018-12-16 17:30:35 +01003051{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003052 if (G.prs.lex == XC_LEX_NLINE)
Denys Vlasenko10bde142018-12-27 18:23:58 +01003053 RETURN_STATUS(zxc_lex_next());
Denys Vlasenko202dd192018-12-16 17:30:35 +01003054 RETURN_STATUS(BC_STATUS_SUCCESS);
3055}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003056#define zbc_lex_skip_if_at_NLINE(...) (zbc_lex_skip_if_at_NLINE(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko202dd192018-12-16 17:30:35 +01003057
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003058static BC_STATUS zbc_lex_next_and_skip_NLINE(void)
Denys Vlasenko202dd192018-12-16 17:30:35 +01003059{
3060 BcStatus s;
Denys Vlasenko10bde142018-12-27 18:23:58 +01003061 s = zxc_lex_next();
Denys Vlasenko202dd192018-12-16 17:30:35 +01003062 if (s) RETURN_STATUS(s);
3063 // if(cond)<newline>stmt is accepted too (but not 2+ newlines)
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003064 s = zbc_lex_skip_if_at_NLINE();
Denys Vlasenko202dd192018-12-16 17:30:35 +01003065 RETURN_STATUS(s);
3066}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003067#define zbc_lex_next_and_skip_NLINE(...) (zbc_lex_next_and_skip_NLINE(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko202dd192018-12-16 17:30:35 +01003068
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003069static BC_STATUS zbc_lex_identifier(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003070{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003071 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003072 BcStatus s;
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003073 unsigned i;
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003074 const char *buf = p->lex_inbuf - 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06003075
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003076 for (i = 0; i < ARRAY_SIZE(bc_lex_kws); ++i) {
3077 const char *keyword8 = bc_lex_kws[i].name8;
3078 unsigned j = 0;
3079 while (buf[j] != '\0' && buf[j] == keyword8[j]) {
3080 j++;
3081 if (j == 8) goto match;
Gavin Howard01055ba2018-11-03 11:00:21 -06003082 }
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003083 if (keyword8[j] != '\0')
3084 continue;
3085 match:
3086 // buf starts with keyword bc_lex_kws[i]
Denys Vlasenko5acd14b2018-12-20 16:48:50 +01003087 if (isalnum(buf[j]) || buf[j]=='_')
3088 continue; // "ifz" does not match "if" keyword, "if." does
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003089 p->lex = BC_LEX_KEY_1st_keyword + i;
Denys Vlasenko0b0e8d02018-12-25 21:44:10 +01003090 if (!keyword_is_POSIX(i)) {
Denys Vlasenko79587cb2018-12-24 18:11:41 +01003091 s = zbc_posix_error_fmt("%sthe '%.8s' keyword", "POSIX does not allow ", bc_lex_kws[i].name8);
3092 if (s) RETURN_STATUS(s);
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003093 }
3094
3095 // We minus 1 because the index has already been incremented.
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003096 p->lex_inbuf += j - 1;
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003097 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003098 }
3099
Denys Vlasenko10bde142018-12-27 18:23:58 +01003100 xc_lex_name();
Denys Vlasenko0f31a5c2018-12-18 03:16:48 +01003101 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06003102
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003103 if (p->lex_strnumbuf.len > 2) {
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003104 // Prevent this:
3105 // >>> qwe=1
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01003106 // bc: POSIX only allows one character names; this is bad: 'qwe=1
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003107 // '
3108 unsigned len = strchrnul(buf, '\n') - buf;
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01003109 s = zbc_posix_error_fmt("POSIX only allows one character names; this is bad: '%.*s'", len, buf);
Denys Vlasenko0d7e46b2018-12-05 18:31:19 +01003110 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003111
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003112 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003113}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003114#define zbc_lex_identifier(...) (zbc_lex_identifier(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003115
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003116static BC_STATUS zbc_lex_string(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003117{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003118 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003119
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003120 p->lex = XC_LEX_STR;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003121 bc_vec_pop_all(&p->lex_strnumbuf);
Denys Vlasenko07597cd2018-12-18 14:03:20 +01003122 for (;;) {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003123 char c = peek_inbuf(); // strings can cross lines
Denys Vlasenko07597cd2018-12-18 14:03:20 +01003124 if (c == '\0') {
Denys Vlasenko8af11082018-12-26 21:01:41 +01003125 RETURN_STATUS(bc_error("unterminated string"));
Denys Vlasenko07597cd2018-12-18 14:03:20 +01003126 }
3127 if (c == '"')
3128 break;
Denys Vlasenko22314682019-01-01 21:50:14 +01003129 if (c == '\n') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003130 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01003131 dbg_lex("++p->lex_line=%zd", p->lex_line);
3132 }
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003133 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
3134 p->lex_inbuf++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003135 }
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003136 bc_vec_pushZeroByte(&p->lex_strnumbuf);
3137 p->lex_inbuf++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003138
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003139 G.err_line = p->lex_line;
Denys Vlasenko26819db2018-12-12 16:08:46 +01003140 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003141}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003142#define zbc_lex_string(...) (zbc_lex_string(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003143
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003144static void parse_lex_by_checking_eq_sign(unsigned with_and_without)
Gavin Howard01055ba2018-11-03 11:00:21 -06003145{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003146 BcParse *p = &G.prs;
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003147 if (*p->lex_inbuf == '=') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003148 // ^^^ not using peek_inbuf() since '==' etc can't be split across lines
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003149 p->lex_inbuf++;
Denys Vlasenko0a238142018-12-14 16:48:34 +01003150 with_and_without >>= 8; // store "with" value
3151 } // else store "without" value
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003152 p->lex = (with_and_without & 0xff);
Gavin Howard01055ba2018-11-03 11:00:21 -06003153}
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003154#define parse_lex_by_checking_eq_sign(with, without) \
3155 parse_lex_by_checking_eq_sign(((with)<<8)|(without))
Gavin Howard01055ba2018-11-03 11:00:21 -06003156
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003157static BC_STATUS zbc_lex_comment(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003158{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003159 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003160
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003161 p->lex = XC_LEX_WHITESPACE;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003162 // here lex_inbuf is at '*' of opening comment delimiter
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003163 for (;;) {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003164 char c;
3165
3166 p->lex_inbuf++;
3167 c = peek_inbuf();
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003168 check_star:
3169 if (c == '*') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003170 p->lex_inbuf++;
Denys Vlasenko8af11082018-12-26 21:01:41 +01003171 c = *p->lex_inbuf; // no need to peek_inbuf()
Denys Vlasenkobc5ce662018-12-03 19:12:29 +01003172 if (c == '/')
3173 break;
3174 goto check_star;
3175 }
3176 if (c == '\0') {
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01003177 RETURN_STATUS(bc_error("unterminated comment"));
Gavin Howard01055ba2018-11-03 11:00:21 -06003178 }
Denys Vlasenko22314682019-01-01 21:50:14 +01003179 if (c == '\n') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003180 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01003181 dbg_lex("++p->lex_line=%zd", p->lex_line);
3182 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003183 }
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003184 p->lex_inbuf++; // skip trailing '/'
Gavin Howard01055ba2018-11-03 11:00:21 -06003185
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003186 G.err_line = p->lex_line;
Denys Vlasenko29301232018-12-11 15:29:32 +01003187 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003188}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003189#define zbc_lex_comment(...) (zbc_lex_comment(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003190
Denys Vlasenko5cf0b2d2018-12-22 18:24:19 +01003191#undef zbc_lex_token
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003192static BC_STATUS zbc_lex_token(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003193{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003194 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003195 BcStatus s = BC_STATUS_SUCCESS;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003196 char c = eat_inbuf();
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003197 char c2;
Gavin Howard01055ba2018-11-03 11:00:21 -06003198
3199 // This is the workhorse of the lexer.
3200 switch (c) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003201// case '\0': // probably never reached
3202// p->lex_inbuf--;
3203// p->lex = XC_LEX_EOF;
3204// break;
3205 case '\n':
3206 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01003207 dbg_lex("++p->lex_line=%zd", p->lex_line);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003208 p->lex = XC_LEX_NLINE;
3209 break;
3210 case '\t':
3211 case '\v':
3212 case '\f':
3213 case '\r':
3214 case ' ':
Denys Vlasenko10bde142018-12-27 18:23:58 +01003215 xc_lex_whitespace();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003216 break;
3217 case '!':
3218 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3219 if (p->lex == BC_LEX_OP_BOOL_NOT) {
3220 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("!");
Denys Vlasenko79587cb2018-12-24 18:11:41 +01003221 if (s) RETURN_STATUS(s);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003222 }
3223 break;
3224 case '"':
3225 s = zbc_lex_string();
3226 break;
3227 case '#':
3228 s = zbc_POSIX_does_not_allow("'#' script comments");
3229 if (s) RETURN_STATUS(s);
Denys Vlasenko10bde142018-12-27 18:23:58 +01003230 xc_lex_lineComment();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003231 break;
3232 case '%':
3233 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MODULUS, XC_LEX_OP_MODULUS);
3234 break;
3235 case '&':
3236 c2 = *p->lex_inbuf;
3237 if (c2 == '&') {
3238 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("&&");
3239 if (s) RETURN_STATUS(s);
3240 p->lex_inbuf++;
3241 p->lex = BC_LEX_OP_BOOL_AND;
3242 } else {
3243 p->lex = XC_LEX_INVALID;
3244 s = bc_error_bad_character('&');
3245 }
3246 break;
3247 case '(':
3248 case ')':
3249 p->lex = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3250 break;
3251 case '*':
3252 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MULTIPLY, XC_LEX_OP_MULTIPLY);
3253 break;
3254 case '+':
3255 c2 = *p->lex_inbuf;
3256 if (c2 == '+') {
3257 p->lex_inbuf++;
3258 p->lex = BC_LEX_OP_INC;
3259 } else
3260 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_PLUS, XC_LEX_OP_PLUS);
3261 break;
3262 case ',':
3263 p->lex = BC_LEX_COMMA;
3264 break;
3265 case '-':
3266 c2 = *p->lex_inbuf;
3267 if (c2 == '-') {
3268 p->lex_inbuf++;
3269 p->lex = BC_LEX_OP_DEC;
3270 } else
3271 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_MINUS, XC_LEX_OP_MINUS);
3272 break;
3273 case '.':
3274 if (isdigit(*p->lex_inbuf))
Denys Vlasenko10bde142018-12-27 18:23:58 +01003275 s = zxc_lex_number(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003276 else {
3277 p->lex = BC_LEX_KEY_LAST;
3278 s = zbc_POSIX_does_not_allow("'.' as 'last'");
3279 }
3280 break;
3281 case '/':
3282 c2 = *p->lex_inbuf;
3283 if (c2 == '*')
3284 s = zbc_lex_comment();
3285 else
3286 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_DIVIDE, XC_LEX_OP_DIVIDE);
3287 break;
3288 case '0':
3289 case '1':
3290 case '2':
3291 case '3':
3292 case '4':
3293 case '5':
3294 case '6':
3295 case '7':
3296 case '8':
3297 case '9':
3298 case 'A':
3299 case 'B':
3300 case 'C':
3301 case 'D':
3302 case 'E':
3303 case 'F':
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01003304 case 'G':
3305 case 'H':
3306 case 'I':
3307 case 'J':
3308 case 'K':
3309 case 'L':
3310 case 'M':
3311 case 'N':
3312 case 'O':
3313 case 'P':
3314 case 'Q':
3315 case 'R':
3316 case 'S':
3317 case 'T':
3318 case 'U':
3319 case 'V':
3320 case 'W':
3321 case 'X':
3322 case 'Y':
3323 case 'Z':
Denys Vlasenko10bde142018-12-27 18:23:58 +01003324 s = zxc_lex_number(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003325 break;
3326 case ';':
3327 p->lex = BC_LEX_SCOLON;
3328 break;
3329 case '<':
3330 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_LE, XC_LEX_OP_REL_LT);
3331 break;
3332 case '=':
3333 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3334 break;
3335 case '>':
3336 parse_lex_by_checking_eq_sign(XC_LEX_OP_REL_GE, XC_LEX_OP_REL_GT);
3337 break;
3338 case '[':
3339 case ']':
3340 p->lex = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3341 break;
3342 case '\\':
3343 if (*p->lex_inbuf == '\n') {
3344 p->lex = XC_LEX_WHITESPACE;
3345 p->lex_inbuf++;
3346 } else
3347 s = bc_error_bad_character(c);
3348 break;
3349 case '^':
3350 parse_lex_by_checking_eq_sign(BC_LEX_OP_ASSIGN_POWER, XC_LEX_OP_POWER);
3351 break;
3352 case 'a':
3353 case 'b':
3354 case 'c':
3355 case 'd':
3356 case 'e':
3357 case 'f':
3358 case 'g':
3359 case 'h':
3360 case 'i':
3361 case 'j':
3362 case 'k':
3363 case 'l':
3364 case 'm':
3365 case 'n':
3366 case 'o':
3367 case 'p':
3368 case 'q':
3369 case 'r':
3370 case 's':
3371 case 't':
3372 case 'u':
3373 case 'v':
3374 case 'w':
3375 case 'x':
3376 case 'y':
3377 case 'z':
3378 s = zbc_lex_identifier();
3379 break;
3380 case '{':
3381 case '}':
3382 p->lex = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3383 break;
3384 case '|':
3385 c2 = *p->lex_inbuf;
3386 if (c2 == '|') {
3387 s = zbc_POSIX_does_not_allow_bool_ops_this_is_bad("||");
3388 if (s) RETURN_STATUS(s);
3389 p->lex_inbuf++;
3390 p->lex = BC_LEX_OP_BOOL_OR;
3391 } else {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003392 p->lex = XC_LEX_INVALID;
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003393 s = bc_error_bad_character(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003394 }
3395 break;
3396 default:
3397 p->lex = XC_LEX_INVALID;
3398 s = bc_error_bad_character(c);
3399 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06003400 }
3401
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003402 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003403}
Denys Vlasenko5cf0b2d2018-12-22 18:24:19 +01003404#define zbc_lex_token(...) (zbc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003405#endif // ENABLE_BC
3406
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01003407#if ENABLE_DC
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003408static BC_STATUS zdc_lex_register(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003409{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003410 BcParse *p = &G.prs;
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003411 if (G_exreg && isspace(*p->lex_inbuf)) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01003412 xc_lex_whitespace(); // eats whitespace (but not newline)
3413 p->lex_inbuf++; // xc_lex_name() expects this
3414 xc_lex_name();
Denys Vlasenko81293c82018-12-24 01:53:55 +01003415 } else {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003416 bc_vec_pop_all(&p->lex_strnumbuf);
Denys Vlasenkoc192b042018-12-25 23:15:59 +01003417 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf++);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003418 bc_vec_pushZeroByte(&p->lex_strnumbuf);
3419 p->lex = XC_LEX_NAME;
Gavin Howard01055ba2018-11-03 11:00:21 -06003420 }
3421
Denys Vlasenko29301232018-12-11 15:29:32 +01003422 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003423}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003424#define zdc_lex_register(...) (zdc_lex_register(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003425
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003426static BC_STATUS zdc_lex_string(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003427{
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003428 BcParse *p = &G.prs;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003429 size_t depth;
Gavin Howard01055ba2018-11-03 11:00:21 -06003430
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003431 p->lex = XC_LEX_STR;
3432 bc_vec_pop_all(&p->lex_strnumbuf);
Gavin Howard01055ba2018-11-03 11:00:21 -06003433
Denys Vlasenkoef271da2018-12-18 13:48:37 +01003434 depth = 1;
Denys Vlasenkoef271da2018-12-18 13:48:37 +01003435 for (;;) {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003436 char c = peek_inbuf();
Denys Vlasenkoef271da2018-12-18 13:48:37 +01003437 if (c == '\0') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003438 RETURN_STATUS(bc_error("unterminated string"));
Denys Vlasenkoef271da2018-12-18 13:48:37 +01003439 }
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003440 if (c == '[') depth++;
3441 if (c == ']')
3442 if (--depth == 0)
3443 break;
Denys Vlasenko22314682019-01-01 21:50:14 +01003444 if (c == '\n') {
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003445 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01003446 dbg_lex("++p->lex_line=%zd", p->lex_line);
3447 }
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003448 bc_vec_push(&p->lex_strnumbuf, p->lex_inbuf);
3449 p->lex_inbuf++;
Gavin Howard01055ba2018-11-03 11:00:21 -06003450 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003451 bc_vec_pushZeroByte(&p->lex_strnumbuf);
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003452 p->lex_inbuf++; // skip trailing ']'
Gavin Howard01055ba2018-11-03 11:00:21 -06003453
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003454 G.err_line = p->lex_line;
Denys Vlasenko29301232018-12-11 15:29:32 +01003455 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003456}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003457#define zdc_lex_string(...) (zdc_lex_string(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003458
Denys Vlasenko5cf0b2d2018-12-22 18:24:19 +01003459#undef zdc_lex_token
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003460static BC_STATUS zdc_lex_token(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003461{
Denys Vlasenkob44a7f12018-12-17 11:58:20 +01003462 static const //BcLexType - should be this type, but narrower type saves size:
3463 uint8_t
Denys Vlasenko2beb1f62018-12-26 21:17:12 +01003464 dc_lex_regs[] ALIGN1 = {
Denys Vlasenko69560f42018-12-24 14:14:23 +01003465 XC_LEX_OP_REL_EQ, XC_LEX_OP_REL_LE, XC_LEX_OP_REL_GE, XC_LEX_OP_REL_NE,
Denys Vlasenko9d9c97e2018-12-24 15:00:56 +01003466 XC_LEX_OP_REL_LT, XC_LEX_OP_REL_GT, DC_LEX_SCOLON, DC_LEX_COLON,
3467 DC_LEX_ELSE, DC_LEX_LOAD, DC_LEX_LOAD_POP, DC_LEX_OP_ASSIGN,
Denys Vlasenko7d9be0b2018-12-24 12:25:20 +01003468 DC_LEX_STORE_PUSH,
Denys Vlasenkob44a7f12018-12-17 11:58:20 +01003469 };
Denys Vlasenkob44a7f12018-12-17 11:58:20 +01003470
Denys Vlasenko10bde142018-12-27 18:23:58 +01003471 BcParse *p = &G.prs;
Denys Vlasenko81293c82018-12-24 01:53:55 +01003472 BcStatus s;
3473 char c, c2;
Gavin Howard01055ba2018-11-03 11:00:21 -06003474 size_t i;
3475
Denys Vlasenko51fb8aa2018-12-05 00:22:34 +01003476 for (i = 0; i < ARRAY_SIZE(dc_lex_regs); ++i) {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003477 if (p->lex_last == dc_lex_regs[i])
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003478 RETURN_STATUS(zdc_lex_register());
Gavin Howard01055ba2018-11-03 11:00:21 -06003479 }
3480
Denys Vlasenko81293c82018-12-24 01:53:55 +01003481 s = BC_STATUS_SUCCESS;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003482 c = eat_inbuf();
Denys Vlasenko12b9eaf2018-12-11 23:50:14 +01003483 if (c >= '%' && c <= '~'
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003484 && (p->lex = dc_char_to_LEX[c - '%']) != XC_LEX_INVALID
Denys Vlasenko12b9eaf2018-12-11 23:50:14 +01003485 ) {
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003486 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003487 }
3488
3489 // This is the workhorse of the lexer.
3490 switch (c) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003491// case '\0': // probably never reached
3492// p->lex = XC_LEX_EOF;
3493// break;
3494 case '\n':
3495 // '\n' is XC_LEX_NLINE, not XC_LEX_WHITESPACE
3496 // (and "case '\n':" is not just empty here)
3497 // only to allow interactive dc have a way to exit
3498 // "parse" stage of "parse,execute" loop
3499 // on <enter>, not on _next_ token (which would mean
3500 // commands are not executed on pressing <enter>).
3501 // IOW: typing "1p<enter>" should print "1" _at once_,
3502 // not after some more input.
3503 p->lex_line++;
Denys Vlasenko22314682019-01-01 21:50:14 +01003504 dbg_lex("++p->lex_line=%zd", p->lex_line);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003505 p->lex = XC_LEX_NLINE;
3506 break;
3507 case '\t':
3508 case '\v':
3509 case '\f':
3510 case '\r':
3511 case ' ':
Denys Vlasenko10bde142018-12-27 18:23:58 +01003512 xc_lex_whitespace();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003513 break;
3514 case '!':
3515 c2 = *p->lex_inbuf;
3516 if (c2 == '=')
3517 p->lex = XC_LEX_OP_REL_NE;
3518 else if (c2 == '<')
3519 p->lex = XC_LEX_OP_REL_LE;
3520 else if (c2 == '>')
3521 p->lex = XC_LEX_OP_REL_GE;
3522 else
3523 RETURN_STATUS(bc_error_bad_character(c));
3524 p->lex_inbuf++;
3525 break;
3526 case '#':
Denys Vlasenko10bde142018-12-27 18:23:58 +01003527 xc_lex_lineComment();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003528 break;
3529 case '.':
3530 if (isdigit(*p->lex_inbuf))
Denys Vlasenko10bde142018-12-27 18:23:58 +01003531 s = zxc_lex_number(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003532 else
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003533 s = bc_error_bad_character(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003534 break;
3535 case '0':
3536 case '1':
3537 case '2':
3538 case '3':
3539 case '4':
3540 case '5':
3541 case '6':
3542 case '7':
3543 case '8':
3544 case '9':
3545 case 'A':
3546 case 'B':
3547 case 'C':
3548 case 'D':
3549 case 'E':
3550 case 'F':
Denys Vlasenko10bde142018-12-27 18:23:58 +01003551 s = zxc_lex_number(c);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003552 break;
3553 case '[':
3554 s = zdc_lex_string();
3555 break;
3556 default:
3557 p->lex = XC_LEX_INVALID;
3558 s = bc_error_bad_character(c);
3559 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06003560 }
3561
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003562 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003563}
Denys Vlasenko5cf0b2d2018-12-22 18:24:19 +01003564#define zdc_lex_token(...) (zdc_lex_token(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003565#endif // ENABLE_DC
3566
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003567static void xc_parse_push(unsigned i)
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01003568{
Denys Vlasenkof706a182018-12-26 20:02:09 +01003569 BcVec *code = &G.prs.func->code;
3570 dbg_compile("%s:%d pushing bytecode %zd:%d", __func__, __LINE__, code->len, i);
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003571 bc_vec_pushByte(code, (uint8_t)i);
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01003572}
Denys Vlasenkob23ac512018-12-06 13:10:56 +01003573
Denys Vlasenko10bde142018-12-27 18:23:58 +01003574static void xc_parse_pushName(char *name)
Gavin Howard01055ba2018-11-03 11:00:21 -06003575{
Denys Vlasenkoab9a9862018-12-26 20:30:47 +01003576#if 1
3577 BcVec *code = &G.prs.func->code;
3578 size_t pos = code->len;
3579 size_t len = strlen(name) + 1;
3580
3581 bc_vec_expand(code, pos + len);
3582 strcpy(code->v + pos, name);
3583 code->len = pos + len;
3584#else
3585 // Smaller code, but way slow:
Denys Vlasenkof706a182018-12-26 20:02:09 +01003586 do {
Denys Vlasenko10bde142018-12-27 18:23:58 +01003587 xc_parse_push(*name);
Denys Vlasenkof706a182018-12-26 20:02:09 +01003588 } while (*name++);
Denys Vlasenkoab9a9862018-12-26 20:30:47 +01003589#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06003590}
3591
Denys Vlasenkoab9a9862018-12-26 20:30:47 +01003592// Indexes < 0xfc are encoded verbatim, else first byte is
3593// 0xfc, 0xfd, 0xfe or 0xff, encoding "1..4 bytes",
3594// followed by that many bytes, lsb first.
3595// (The above describes 32-bit case).
3596#define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t))
3597
Denys Vlasenko53799502019-01-25 14:24:03 +01003598static void bc_vec_pushIndex(BcVec *v, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06003599{
Denys Vlasenkoc2da68e2018-12-12 16:44:34 +01003600 size_t mask;
3601 unsigned amt;
Gavin Howard01055ba2018-11-03 11:00:21 -06003602
Denys Vlasenkof4f10722018-12-18 02:23:53 +01003603 dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx);
Denys Vlasenkoab9a9862018-12-26 20:30:47 +01003604 if (idx < SMALL_INDEX_LIMIT) {
Denys Vlasenko53799502019-01-25 14:24:03 +01003605 bc_vec_pushByte(v, idx);
Denys Vlasenkoae6c44e2019-01-02 16:30:24 +01003606 return;
Denys Vlasenkoab9a9862018-12-26 20:30:47 +01003607 }
3608
Denys Vlasenkoc2da68e2018-12-12 16:44:34 +01003609 mask = ((size_t)0xff) << (sizeof(idx) * 8 - 8);
3610 amt = sizeof(idx);
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01003611 for (;;) {
Denys Vlasenkoc2da68e2018-12-12 16:44:34 +01003612 if (idx & mask) break;
3613 mask >>= 8;
3614 amt--;
Denys Vlasenkoe16a5222018-12-29 02:24:19 +01003615 }
3616 // amt is at least 1 here - "one byte of length data follows"
Gavin Howard01055ba2018-11-03 11:00:21 -06003617
Denys Vlasenko53799502019-01-25 14:24:03 +01003618 bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt);
Denys Vlasenkoc2da68e2018-12-12 16:44:34 +01003619
Denys Vlasenkoae6c44e2019-01-02 16:30:24 +01003620 do {
Denys Vlasenko53799502019-01-25 14:24:03 +01003621 bc_vec_pushByte(v, (unsigned char)idx);
Denys Vlasenkoc2da68e2018-12-12 16:44:34 +01003622 idx >>= 8;
Denys Vlasenkoae6c44e2019-01-02 16:30:24 +01003623 } while (idx != 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06003624}
3625
Denys Vlasenko53799502019-01-25 14:24:03 +01003626static void xc_parse_pushIndex(size_t idx)
3627{
3628 bc_vec_pushIndex(&G.prs.func->code, idx);
3629}
3630
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003631static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx)
3632{
3633 xc_parse_push(inst);
3634 xc_parse_pushIndex(idx);
3635}
3636
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003637#if ENABLE_BC
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003638static void bc_parse_pushJUMP(size_t idx)
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003639{
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003640 xc_parse_pushInst_and_Index(BC_INST_JUMP, idx);
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003641}
3642
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003643static void bc_parse_pushJUMP_ZERO(size_t idx)
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003644{
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003645 xc_parse_pushInst_and_Index(BC_INST_JUMP_ZERO, idx);
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003646}
3647
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003648static BC_STATUS zbc_parse_pushSTR(void)
Denys Vlasenko44dbe672018-12-19 19:10:40 +01003649{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003650 BcParse *p = &G.prs;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003651 char *str = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenko44dbe672018-12-19 19:10:40 +01003652
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003653 xc_parse_pushInst_and_Index(XC_INST_STR, p->func->strs.len);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01003654 bc_vec_push(&p->func->strs, &str);
Denys Vlasenko44dbe672018-12-19 19:10:40 +01003655
Denys Vlasenko10bde142018-12-27 18:23:58 +01003656 RETURN_STATUS(zxc_lex_next());
Denys Vlasenko44dbe672018-12-19 19:10:40 +01003657}
Denys Vlasenko8c1e7232018-12-22 01:34:10 +01003658#define zbc_parse_pushSTR(...) (zbc_parse_pushSTR(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003659#endif
3660
Denys Vlasenko10bde142018-12-27 18:23:58 +01003661static void xc_parse_pushNUM(void)
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003662{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003663 BcParse *p = &G.prs;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003664 char *num = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01003665#if ENABLE_BC && ENABLE_DC
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01003666 size_t idx = bc_vec_push(IS_BC ? &p->func->consts : &G.prog.consts, &num);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01003667#elif ENABLE_BC
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01003668 size_t idx = bc_vec_push(&p->func->consts, &num);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01003669#else // DC
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01003670 size_t idx = bc_vec_push(&G.prog.consts, &num);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01003671#endif
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003672 xc_parse_pushInst_and_Index(XC_INST_NUM, idx);
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003673}
Denys Vlasenko44dbe672018-12-19 19:10:40 +01003674
Denys Vlasenko10bde142018-12-27 18:23:58 +01003675static BC_STATUS zxc_parse_text_init(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06003676{
Denys Vlasenko10bde142018-12-27 18:23:58 +01003677 G.prs.func = xc_program_func(G.prs.fidx);
3678 G.prs.lex_inbuf = text;
3679 G.prs.lex = G.prs.lex_last = XC_LEX_INVALID;
3680 RETURN_STATUS(zxc_lex_next());
Gavin Howard01055ba2018-11-03 11:00:21 -06003681}
Denys Vlasenko10bde142018-12-27 18:23:58 +01003682#define zxc_parse_text_init(...) (zxc_parse_text_init(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003683
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003684// Called when parsing or execution detects a failure,
3685// resets execution structures.
Denys Vlasenko10bde142018-12-27 18:23:58 +01003686static void xc_program_reset(void)
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003687{
3688 BcFunc *f;
3689 BcInstPtr *ip;
3690
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01003691 bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003692 bc_vec_pop_all(&G.prog.results);
3693
Denys Vlasenko10bde142018-12-27 18:23:58 +01003694 f = xc_program_func_BC_PROG_MAIN();
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01003695 ip = bc_vec_top(&G.prog.exestack);
Denys Vlasenko24e41942018-12-21 23:01:26 +01003696 ip->inst_idx = f->code.len;
Denys Vlasenkob6f60862018-12-06 12:54:26 +01003697}
3698
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003699// Called when parsing code detects a failure,
Denys Vlasenkod38af482018-12-04 19:11:02 +01003700// resets parsing structures.
Denys Vlasenko10bde142018-12-27 18:23:58 +01003701static void xc_parse_reset(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003702{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003703 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003704 if (p->fidx != BC_PROG_MAIN) {
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01003705 bc_func_free(p->func);
3706 bc_func_init(p->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06003707
Denys Vlasenko65e10462018-12-19 15:13:14 +01003708 p->fidx = BC_PROG_MAIN;
Denys Vlasenko10bde142018-12-27 18:23:58 +01003709 p->func = xc_program_func_BC_PROG_MAIN();
Gavin Howard01055ba2018-11-03 11:00:21 -06003710 }
3711
Denys Vlasenkob1b79962018-12-26 18:46:03 +01003712 p->lex_inbuf += strlen(p->lex_inbuf);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003713 p->lex = XC_LEX_EOF;
Gavin Howard01055ba2018-11-03 11:00:21 -06003714
Denys Vlasenko503faf92018-12-20 16:24:18 +01003715 IF_BC(bc_vec_pop_all(&p->exits);)
3716 IF_BC(bc_vec_pop_all(&p->conds);)
3717 IF_BC(bc_vec_pop_all(&p->ops);)
Gavin Howard01055ba2018-11-03 11:00:21 -06003718
Denys Vlasenko10bde142018-12-27 18:23:58 +01003719 xc_program_reset();
Gavin Howard01055ba2018-11-03 11:00:21 -06003720}
3721
Denys Vlasenko10bde142018-12-27 18:23:58 +01003722static void xc_parse_free(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003723{
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003724 IF_BC(bc_vec_free(&G.prs.exits);)
3725 IF_BC(bc_vec_free(&G.prs.conds);)
3726 IF_BC(bc_vec_free(&G.prs.ops);)
Denys Vlasenko7d32e252018-12-26 18:32:43 +01003727 bc_vec_free(&G.prs.lex_strnumbuf);
Gavin Howard01055ba2018-11-03 11:00:21 -06003728}
3729
Denys Vlasenko10bde142018-12-27 18:23:58 +01003730static void xc_parse_create(size_t fidx)
Gavin Howard01055ba2018-11-03 11:00:21 -06003731{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003732 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003733 memset(p, 0, sizeof(BcParse));
3734
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01003735 bc_char_vec_init(&p->lex_strnumbuf);
Denys Vlasenko503faf92018-12-20 16:24:18 +01003736 IF_BC(bc_vec_init(&p->exits, sizeof(size_t), NULL);)
3737 IF_BC(bc_vec_init(&p->conds, sizeof(size_t), NULL);)
3738 IF_BC(bc_vec_init(&p->ops, sizeof(BcLexType), NULL);)
Gavin Howard01055ba2018-11-03 11:00:21 -06003739
Denys Vlasenkofa210792018-12-19 19:35:40 +01003740 p->fidx = fidx;
Denys Vlasenko10bde142018-12-27 18:23:58 +01003741 p->func = xc_program_func(fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003742}
3743
Denys Vlasenko10bde142018-12-27 18:23:58 +01003744static void xc_program_add_fn(void)
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01003745{
Denys Vlasenko04715442018-12-21 00:10:26 +01003746 //size_t idx;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01003747 BcFunc f;
3748 bc_func_init(&f);
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01003749 //idx =
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01003750 bc_vec_push(&G.prog.fns, &f);
Denys Vlasenko04715442018-12-21 00:10:26 +01003751 //return idx;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01003752}
3753
3754#if ENABLE_BC
3755
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003756// Note: takes ownership of 'name' (must be malloced)
3757static size_t bc_program_addFunc(char *name)
3758{
3759 size_t idx;
3760 BcId entry, *entry_ptr;
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003761 int inserted;
3762
3763 entry.name = name;
3764 entry.idx = G.prog.fns.len;
3765
3766 inserted = bc_map_insert(&G.prog.fn_map, &entry, &idx);
3767 if (!inserted) free(name);
3768
3769 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3770 idx = entry_ptr->idx;
3771
3772 if (!inserted) {
Denys Vlasenkoeaa3b002018-12-19 20:05:50 +01003773 // There is already a function with this name.
3774 // It'll be redefined now, clear old definition.
Denys Vlasenko10bde142018-12-27 18:23:58 +01003775 BcFunc *func = xc_program_func(entry_ptr->idx);
Denys Vlasenkoeaa3b002018-12-19 20:05:50 +01003776 bc_func_free(func);
3777 bc_func_init(func);
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003778 } else {
Denys Vlasenko10bde142018-12-27 18:23:58 +01003779 xc_program_add_fn();
Denys Vlasenko408b7d42018-12-19 19:43:03 +01003780 }
3781
3782 return idx;
3783}
3784
Denys Vlasenko0c45bb222018-12-24 23:22:40 +01003785#define BC_PARSE_TOP_OP(p) (*(BcLexType*)bc_vec_top(&(p)->ops))
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003786// We can calculate the conversion between tokens and exprs by subtracting the
3787// position of the first operator in the lex enum and adding the position of the
3788// first in the expr enum. Note: This only works for binary operators.
Denys Vlasenko69560f42018-12-24 14:14:23 +01003789#define BC_TOKEN_2_INST(t) ((char) ((t) - XC_LEX_OP_POWER + XC_INST_POWER))
Denys Vlasenkocca79a02018-12-05 21:15:46 +01003790
Denys Vlasenko132d7c02019-01-08 19:29:35 +01003791static BC_STATUS zbc_parse_expr(uint8_t flags);
Denys Vlasenkoec603182018-12-17 10:34:02 +01003792#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003793
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003794static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed);
Denys Vlasenkoec603182018-12-17 10:34:02 +01003795#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01003796
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003797static BC_STATUS zbc_parse_stmt(void)
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01003798{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003799 RETURN_STATUS(zbc_parse_stmt_possibly_auto(false));
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01003800}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003801#define zbc_parse_stmt(...) (zbc_parse_stmt(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003802
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003803static BC_STATUS zbc_parse_stmt_allow_NLINE_before(const char *after_X)
Denys Vlasenko2e8be022018-12-16 20:41:32 +01003804{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003805 BcParse *p = &G.prs;
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003806 // "if(cond)<newline>stmt" is accepted too, but not 2+ newlines.
3807 // Same for "else", "while()", "for()".
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003808 BcStatus s = zbc_lex_next_and_skip_NLINE();
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003809 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003810 if (p->lex == XC_LEX_NLINE)
Denys Vlasenko2e8be022018-12-16 20:41:32 +01003811 RETURN_STATUS(bc_error_fmt("no statement after '%s'", after_X));
Denys Vlasenko94f72a32018-12-17 00:07:48 +01003812
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003813 RETURN_STATUS(zbc_parse_stmt());
Denys Vlasenko2e8be022018-12-16 20:41:32 +01003814}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003815#define zbc_parse_stmt_allow_NLINE_before(...) (zbc_parse_stmt_allow_NLINE_before(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko2e8be022018-12-16 20:41:32 +01003816
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003817static void bc_parse_operator(BcLexType type, size_t start, size_t *nexprs)
Gavin Howard01055ba2018-11-03 11:00:21 -06003818{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003819 BcParse *p = &G.prs;
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01003820 char l, r = bc_operation_PREC(type - XC_LEX_1st_op);
3821 bool left = bc_operation_LEFT(type - XC_LEX_1st_op);
Gavin Howard01055ba2018-11-03 11:00:21 -06003822
3823 while (p->ops.len > start) {
Denys Vlasenko7b1df3d2018-12-14 23:12:48 +01003824 BcLexType t = BC_PARSE_TOP_OP(p);
Gavin Howard01055ba2018-11-03 11:00:21 -06003825 if (t == BC_LEX_LPAREN) break;
3826
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01003827 l = bc_operation_PREC(t - XC_LEX_1st_op);
Gavin Howard01055ba2018-11-03 11:00:21 -06003828 if (l >= r && (l != r || !left)) break;
3829
Denys Vlasenko10bde142018-12-27 18:23:58 +01003830 xc_parse_push(BC_TOKEN_2_INST(t));
Gavin Howard01055ba2018-11-03 11:00:21 -06003831 bc_vec_pop(&p->ops);
Denys Vlasenko69560f42018-12-24 14:14:23 +01003832 *nexprs -= (t != BC_LEX_OP_BOOL_NOT && t != XC_LEX_NEG);
Gavin Howard01055ba2018-11-03 11:00:21 -06003833 }
3834
3835 bc_vec_push(&p->ops, &type);
Gavin Howard01055ba2018-11-03 11:00:21 -06003836}
3837
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003838static BC_STATUS zbc_parse_rightParen(size_t ops_bgn, size_t *nexs)
Gavin Howard01055ba2018-11-03 11:00:21 -06003839{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003840 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003841 BcLexType top;
3842
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003843 if (p->ops.len <= ops_bgn)
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003844 RETURN_STATUS(bc_error_bad_expression());
Gavin Howard01055ba2018-11-03 11:00:21 -06003845 top = BC_PARSE_TOP_OP(p);
3846
3847 while (top != BC_LEX_LPAREN) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01003848 xc_parse_push(BC_TOKEN_2_INST(top));
Gavin Howard01055ba2018-11-03 11:00:21 -06003849
3850 bc_vec_pop(&p->ops);
Denys Vlasenko69560f42018-12-24 14:14:23 +01003851 *nexs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
Gavin Howard01055ba2018-11-03 11:00:21 -06003852
Denys Vlasenko60cf7472018-12-04 20:05:28 +01003853 if (p->ops.len <= ops_bgn)
Denys Vlasenko9a34e892018-12-12 13:58:55 +01003854 RETURN_STATUS(bc_error_bad_expression());
Gavin Howard01055ba2018-11-03 11:00:21 -06003855 top = BC_PARSE_TOP_OP(p);
3856 }
3857
3858 bc_vec_pop(&p->ops);
3859
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01003860 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003861}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003862#define zbc_parse_rightParen(...) (zbc_parse_rightParen(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003863
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003864static BC_STATUS zbc_parse_params(uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06003865{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003866 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003867 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06003868 size_t nparams;
3869
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003870 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003871 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3872
Denys Vlasenko10bde142018-12-27 18:23:58 +01003873 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01003874 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003875
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003876 nparams = 0;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003877 if (p->lex != BC_LEX_RPAREN) {
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003878 for (;;) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003879 s = zbc_parse_expr(flags);
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003880 if (s) RETURN_STATUS(s);
3881 nparams++;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003882 if (p->lex != BC_LEX_COMMA) {
3883 if (p->lex == BC_LEX_RPAREN)
Denys Vlasenko4b72aeb2018-12-17 16:54:37 +01003884 break;
3885 RETURN_STATUS(bc_error_bad_token());
3886 }
Denys Vlasenko10bde142018-12-27 18:23:58 +01003887 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01003888 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003889 }
3890 }
3891
Denys Vlasenkocfc25462019-01-09 11:17:19 +01003892 xc_parse_pushInst_and_Index(BC_INST_CALL, nparams);
Gavin Howard01055ba2018-11-03 11:00:21 -06003893
Denys Vlasenko26819db2018-12-12 16:08:46 +01003894 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06003895}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003896#define zbc_parse_params(...) (zbc_parse_params(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003897
Denys Vlasenkoe3d3d202018-12-19 13:19:44 +01003898// Note: takes ownership of 'name' (must be malloced)
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003899static BC_STATUS zbc_parse_call(char *name, uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06003900{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003901 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003902 BcStatus s;
3903 BcId entry, *entry_ptr;
3904 size_t idx;
3905
3906 entry.name = name;
3907
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003908 s = zbc_parse_params(flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003909 if (s) goto err;
3910
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003911 if (p->lex != BC_LEX_RPAREN) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003912 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003913 goto err;
3914 }
3915
Denys Vlasenko5aa54832018-12-19 13:55:53 +01003916 idx = bc_map_find_exact(&G.prog.fn_map, &entry);
Gavin Howard01055ba2018-11-03 11:00:21 -06003917
3918 if (idx == BC_VEC_INVALID_IDX) {
Denys Vlasenko5aa54832018-12-19 13:55:53 +01003919 // No such function exists, create an empty one
Denys Vlasenko684d4412018-12-19 14:57:23 +01003920 bc_program_addFunc(name);
Denys Vlasenko5aa54832018-12-19 13:55:53 +01003921 idx = bc_map_find_exact(&G.prog.fn_map, &entry);
Denys Vlasenko26819db2018-12-12 16:08:46 +01003922 } else
Gavin Howard01055ba2018-11-03 11:00:21 -06003923 free(name);
3924
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01003925 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
Denys Vlasenko10bde142018-12-27 18:23:58 +01003926 xc_parse_pushIndex(entry_ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06003927
Denys Vlasenko10bde142018-12-27 18:23:58 +01003928 RETURN_STATUS(zxc_lex_next());
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01003929 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06003930 free(name);
Denys Vlasenko26819db2018-12-12 16:08:46 +01003931 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003932}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003933#define zbc_parse_call(...) (zbc_parse_call(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003934
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003935static BC_STATUS zbc_parse_name(BcInst *type, uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06003936{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003937 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003938 BcStatus s;
3939 char *name;
3940
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003941 name = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenko10bde142018-12-27 18:23:58 +01003942 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06003943 if (s) goto err;
3944
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003945 if (p->lex == BC_LEX_LBRACKET) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01003946 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06003947 if (s) goto err;
3948
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003949 if (p->lex == BC_LEX_RBRACKET) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003950 if (!(flags & BC_PARSE_ARRAY)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003951 s = bc_error_bad_expression();
Gavin Howard01055ba2018-11-03 11:00:21 -06003952 goto err;
3953 }
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01003954 *type = XC_INST_ARRAY;
Denys Vlasenko26819db2018-12-12 16:08:46 +01003955 } else {
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01003956 *type = XC_INST_ARRAY_ELEM;
Gavin Howard01055ba2018-11-03 11:00:21 -06003957 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003958 s = zbc_parse_expr(flags);
Gavin Howard01055ba2018-11-03 11:00:21 -06003959 if (s) goto err;
3960 }
Denys Vlasenko10bde142018-12-27 18:23:58 +01003961 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06003962 if (s) goto err;
Denys Vlasenko10bde142018-12-27 18:23:58 +01003963 xc_parse_push(*type);
3964 xc_parse_pushName(name);
Denys Vlasenkoe6c40c42018-12-16 20:32:58 +01003965 free(name);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003966 } else if (p->lex == BC_LEX_LPAREN) {
Gavin Howard01055ba2018-11-03 11:00:21 -06003967 if (flags & BC_PARSE_NOCALL) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01003968 s = bc_error_bad_token();
Gavin Howard01055ba2018-11-03 11:00:21 -06003969 goto err;
3970 }
Gavin Howard01055ba2018-11-03 11:00:21 -06003971 *type = BC_INST_CALL;
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003972 s = zbc_parse_call(name, flags);
Denys Vlasenko26819db2018-12-12 16:08:46 +01003973 } else {
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01003974 *type = XC_INST_VAR;
Denys Vlasenko10bde142018-12-27 18:23:58 +01003975 xc_parse_push(XC_INST_VAR);
3976 xc_parse_pushName(name);
Denys Vlasenkoe6c40c42018-12-16 20:32:58 +01003977 free(name);
Gavin Howard01055ba2018-11-03 11:00:21 -06003978 }
3979
Denys Vlasenko26819db2018-12-12 16:08:46 +01003980 RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01003981 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06003982 free(name);
Denys Vlasenko26819db2018-12-12 16:08:46 +01003983 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06003984}
Denys Vlasenkoec603182018-12-17 10:34:02 +01003985#define zbc_parse_name(...) (zbc_parse_name(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06003986
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003987static BC_STATUS zbc_parse_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06003988{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01003989 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06003990 BcStatus s;
3991
Denys Vlasenko10bde142018-12-27 18:23:58 +01003992 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01003993 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003994 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06003995
Denys Vlasenko10bde142018-12-27 18:23:58 +01003996 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01003997 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01003998 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06003999
Denys Vlasenko10bde142018-12-27 18:23:58 +01004000 xc_parse_push(XC_INST_READ);
Gavin Howard01055ba2018-11-03 11:00:21 -06004001
Denys Vlasenko5fa74b92018-12-25 17:07:51 +01004002 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004003}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004004#define zbc_parse_read(...) (zbc_parse_read(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004005
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004006static BC_STATUS zbc_parse_builtin(BcLexType type, uint8_t flags, BcInst *prev)
Gavin Howard01055ba2018-11-03 11:00:21 -06004007{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004008 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004009 BcStatus s;
4010
Denys Vlasenko10bde142018-12-27 18:23:58 +01004011 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01004012 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004013 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06004014
4015 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
4016
Denys Vlasenko10bde142018-12-27 18:23:58 +01004017 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01004018 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004019
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004020 s = zbc_parse_expr(flags);
Denys Vlasenko26819db2018-12-12 16:08:46 +01004021 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004022
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004023 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06004024
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004025 *prev = (type == BC_LEX_KEY_LENGTH) ? XC_INST_LENGTH : XC_INST_SQRT;
Denys Vlasenko10bde142018-12-27 18:23:58 +01004026 xc_parse_push(*prev);
Gavin Howard01055ba2018-11-03 11:00:21 -06004027
Denys Vlasenko5fa74b92018-12-25 17:07:51 +01004028 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004029}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004030#define zbc_parse_builtin(...) (zbc_parse_builtin(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004031
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004032static BC_STATUS zbc_parse_scale(BcInst *type, uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06004033{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004034 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004035 BcStatus s;
4036
Denys Vlasenko10bde142018-12-27 18:23:58 +01004037 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01004038 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004039
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004040 if (p->lex != BC_LEX_LPAREN) {
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004041 *type = XC_INST_SCALE;
Denys Vlasenko10bde142018-12-27 18:23:58 +01004042 xc_parse_push(XC_INST_SCALE);
Denys Vlasenko26819db2018-12-12 16:08:46 +01004043 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004044 }
4045
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004046 *type = XC_INST_SCALE_FUNC;
Gavin Howard01055ba2018-11-03 11:00:21 -06004047 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
4048
Denys Vlasenko10bde142018-12-27 18:23:58 +01004049 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01004050 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004051
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004052 s = zbc_parse_expr(flags);
Denys Vlasenko26819db2018-12-12 16:08:46 +01004053 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004054 if (p->lex != BC_LEX_RPAREN)
Denys Vlasenko26819db2018-12-12 16:08:46 +01004055 RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004056 xc_parse_push(XC_INST_SCALE_FUNC);
Gavin Howard01055ba2018-11-03 11:00:21 -06004057
Denys Vlasenko10bde142018-12-27 18:23:58 +01004058 RETURN_STATUS(zxc_lex_next());
Gavin Howard01055ba2018-11-03 11:00:21 -06004059}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004060#define zbc_parse_scale(...) (zbc_parse_scale(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004061
Denys Vlasenko22314682019-01-01 21:50:14 +01004062static BC_STATUS zbc_parse_incdec(BcInst *prev, size_t *nexs, uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06004063{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004064 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004065 BcStatus s;
4066 BcLexType type;
4067 char inst;
4068 BcInst etype = *prev;
4069
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004070 if (etype == XC_INST_VAR || etype == XC_INST_ARRAY_ELEM
4071 || etype == XC_INST_SCALE || etype == BC_INST_LAST
4072 || etype == XC_INST_IBASE || etype == XC_INST_OBASE
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01004073 ) {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004074 *prev = inst = BC_INST_INC_POST + (p->lex != BC_LEX_OP_INC);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004075 xc_parse_push(inst);
4076 s = zxc_lex_next();
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01004077 } else {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004078 *prev = inst = BC_INST_INC_PRE + (p->lex != BC_LEX_OP_INC);
Gavin Howard01055ba2018-11-03 11:00:21 -06004079
Denys Vlasenko10bde142018-12-27 18:23:58 +01004080 s = zxc_lex_next();
Denys Vlasenko26819db2018-12-12 16:08:46 +01004081 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004082 type = p->lex;
Gavin Howard01055ba2018-11-03 11:00:21 -06004083
4084 // Because we parse the next part of the expression
4085 // right here, we need to increment this.
Denys Vlasenko22314682019-01-01 21:50:14 +01004086 *nexs = *nexs + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06004087
4088 switch (type) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004089 case XC_LEX_NAME:
4090 s = zbc_parse_name(prev, flags | BC_PARSE_NOCALL);
4091 break;
4092 case BC_LEX_KEY_IBASE:
4093 case BC_LEX_KEY_LAST:
4094 case BC_LEX_KEY_OBASE:
Denys Vlasenko10bde142018-12-27 18:23:58 +01004095 xc_parse_push(type - BC_LEX_KEY_IBASE + XC_INST_IBASE);
4096 s = zxc_lex_next();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004097 break;
4098 case BC_LEX_KEY_SCALE:
Denys Vlasenko10bde142018-12-27 18:23:58 +01004099 s = zxc_lex_next();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004100 if (s) RETURN_STATUS(s);
4101 if (p->lex == BC_LEX_LPAREN)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01004102 s = bc_error_bad_token();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004103 else
Denys Vlasenko10bde142018-12-27 18:23:58 +01004104 xc_parse_push(XC_INST_SCALE);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004105 break;
4106 default:
4107 s = bc_error_bad_token();
4108 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06004109 }
4110
Denys Vlasenko10bde142018-12-27 18:23:58 +01004111 if (!s) xc_parse_push(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06004112 }
4113
Denys Vlasenko26819db2018-12-12 16:08:46 +01004114 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004115}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004116#define zbc_parse_incdec(...) (zbc_parse_incdec(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004117
Denys Vlasenko22314682019-01-01 21:50:14 +01004118static int bc_parse_inst_isLeaf(BcInst p)
Denys Vlasenko0c45bb222018-12-24 23:22:40 +01004119{
4120 return (p >= XC_INST_NUM && p <= XC_INST_SQRT)
4121 || p == BC_INST_INC_POST
4122 || p == BC_INST_DEC_POST
4123 ;
4124}
Denys Vlasenko22314682019-01-01 21:50:14 +01004125#define BC_PARSE_LEAF(prev, bin_last, rparen) \
4126 (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
Denys Vlasenko0c45bb222018-12-24 23:22:40 +01004127
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004128static BC_STATUS zbc_parse_minus(BcInst *prev, size_t ops_bgn,
Denys Vlasenko22314682019-01-01 21:50:14 +01004129 bool rparen, bool bin_last, size_t *nexprs)
Gavin Howard01055ba2018-11-03 11:00:21 -06004130{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004131 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004132 BcStatus s;
4133 BcLexType type;
Gavin Howard01055ba2018-11-03 11:00:21 -06004134
Denys Vlasenko10bde142018-12-27 18:23:58 +01004135 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004136 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004137
Denys Vlasenko22314682019-01-01 21:50:14 +01004138 type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? XC_LEX_OP_MINUS : XC_LEX_NEG;
Denys Vlasenko0154d782018-12-14 23:32:51 +01004139 *prev = BC_TOKEN_2_INST(type);
Gavin Howard01055ba2018-11-03 11:00:21 -06004140
4141 // We can just push onto the op stack because this is the largest
4142 // precedence operator that gets pushed. Inc/dec does not.
Denys Vlasenko69560f42018-12-24 14:14:23 +01004143 if (type != XC_LEX_OP_MINUS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004144 bc_vec_push(&p->ops, &type);
4145 else
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004146 bc_parse_operator(type, ops_bgn, nexprs);
Gavin Howard01055ba2018-11-03 11:00:21 -06004147
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004148 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004149}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004150#define zbc_parse_minus(...) (zbc_parse_minus(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004151
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004152static BC_STATUS zbc_parse_print(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004153{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004154 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004155 BcStatus s;
4156 BcLexType type;
Gavin Howard01055ba2018-11-03 11:00:21 -06004157
Denys Vlasenko5d18f6b2018-12-16 21:08:30 +01004158 for (;;) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01004159 s = zxc_lex_next();
Denys Vlasenko5d18f6b2018-12-16 21:08:30 +01004160 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004161 type = p->lex;
Denys Vlasenko23ea0732018-12-24 15:05:49 +01004162 if (type == XC_LEX_STR) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004163 s = zbc_parse_pushSTR();
Denys Vlasenkoebc41c92018-12-08 23:36:28 +01004164 } else {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004165 s = zbc_parse_expr(0);
Gavin Howard01055ba2018-11-03 11:00:21 -06004166 }
Denys Vlasenko5d18f6b2018-12-16 21:08:30 +01004167 if (s) RETURN_STATUS(s);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004168 xc_parse_push(XC_INST_PRINT_POP);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004169 if (p->lex != BC_LEX_COMMA)
Denys Vlasenko5d18f6b2018-12-16 21:08:30 +01004170 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06004171 }
4172
Denys Vlasenko5d18f6b2018-12-16 21:08:30 +01004173 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004174}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004175#define zbc_parse_print(...) (zbc_parse_print(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004176
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004177static BC_STATUS zbc_parse_return(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004178{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004179 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004180 BcStatus s;
4181 BcLexType t;
Gavin Howard01055ba2018-11-03 11:00:21 -06004182
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004183 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004184 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004185 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004186
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004187 t = p->lex;
Denys Vlasenko96b5ec12019-01-03 23:34:36 +01004188 if (t == XC_LEX_NLINE || t == BC_LEX_SCOLON || t == BC_LEX_RBRACE)
Denys Vlasenko10bde142018-12-27 18:23:58 +01004189 xc_parse_push(BC_INST_RET0);
Gavin Howard01055ba2018-11-03 11:00:21 -06004190 else {
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004191//TODO: if (p->func->voidfunc) ERROR
Denys Vlasenko96b5ec12019-01-03 23:34:36 +01004192 s = zbc_parse_expr(0);
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004193 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004194
Denys Vlasenko96b5ec12019-01-03 23:34:36 +01004195 if (t != BC_LEX_LPAREN // "return EXPR", no ()
4196 || p->lex_last != BC_LEX_RPAREN // example: "return (a) + b"
4197 ) {
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004198 s = zbc_POSIX_requires("parentheses around return expressions");
4199 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004200 }
4201
Denys Vlasenko10bde142018-12-27 18:23:58 +01004202 xc_parse_push(XC_INST_RET);
Gavin Howard01055ba2018-11-03 11:00:21 -06004203 }
4204
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004205 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004206 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004207}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004208#define zbc_parse_return(...) (zbc_parse_return(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004209
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004210static void rewrite_label_to_current(size_t idx)
Denys Vlasenko94f72a32018-12-17 00:07:48 +01004211{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004212 BcParse *p = &G.prs;
Denys Vlasenko94f72a32018-12-17 00:07:48 +01004213 size_t *label = bc_vec_item(&p->func->labels, idx);
4214 *label = p->func->code.len;
4215}
4216
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004217static BC_STATUS zbc_parse_if(void)
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004218{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004219 BcParse *p = &G.prs;
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004220 BcStatus s;
Denys Vlasenko15850832018-12-16 21:40:54 +01004221 size_t ip_idx;
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004222
4223 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004224 s = zxc_lex_next();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004225 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004226 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004227
Denys Vlasenko10bde142018-12-27 18:23:58 +01004228 s = zxc_lex_next();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004229 if (s) RETURN_STATUS(s);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004230 s = zbc_parse_expr(BC_PARSE_REL);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004231 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004232 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004233
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01004234 // Encode "if zero, jump to ..."
4235 // Pushed value (destination of the jump) is uninitialized,
4236 // will be rewritten to be address of "end of if()" or of "else".
4237 ip_idx = bc_vec_push(&p->func->labels, &ip_idx);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004238 bc_parse_pushJUMP_ZERO(ip_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004239
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004240 s = zbc_parse_stmt_allow_NLINE_before(STRING_if);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004241 if (s) RETURN_STATUS(s);
Denys Vlasenkoa50576a2018-12-16 19:21:57 +01004242
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004243 dbg_lex("%s:%d in if after stmt: p->lex:%d", __func__, __LINE__, p->lex);
4244 if (p->lex == BC_LEX_KEY_ELSE) {
Denys Vlasenko15850832018-12-16 21:40:54 +01004245 size_t ip2_idx;
Denys Vlasenko74156332018-12-16 21:21:27 +01004246
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01004247 // Encode "after then_stmt, jump to end of if()"
4248 ip2_idx = bc_vec_push(&p->func->labels, &ip2_idx);
4249 dbg_lex("%s:%d after if() then_stmt: BC_INST_JUMP to %zd", __func__, __LINE__, ip2_idx);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004250 bc_parse_pushJUMP(ip2_idx);
Denys Vlasenkoa50576a2018-12-16 19:21:57 +01004251
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004252 dbg_lex("%s:%d rewriting 'if_zero' label to jump to 'else'-> %zd", __func__, __LINE__, p->func->code.len);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004253 rewrite_label_to_current(ip_idx);
Denys Vlasenkoa50576a2018-12-16 19:21:57 +01004254
Denys Vlasenko15850832018-12-16 21:40:54 +01004255 ip_idx = ip2_idx;
Denys Vlasenkoa50576a2018-12-16 19:21:57 +01004256
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004257 s = zbc_parse_stmt_allow_NLINE_before(STRING_else);
Denys Vlasenkoa50576a2018-12-16 19:21:57 +01004258 if (s) RETURN_STATUS(s);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004259 }
4260
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004261 dbg_lex("%s:%d rewriting label to jump after 'if' body-> %zd", __func__, __LINE__, p->func->code.len);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004262 rewrite_label_to_current(ip_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004263
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004264 dbg_lex_done("%s:%d done", __func__, __LINE__);
4265 RETURN_STATUS(s);
4266}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004267#define zbc_parse_if(...) (zbc_parse_if(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004268
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004269static BC_STATUS zbc_parse_while(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004270{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004271 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004272 BcStatus s;
Denys Vlasenkode24e9d2018-12-16 23:02:22 +01004273 size_t cond_idx;
Denys Vlasenko5ebd2a62018-12-16 23:35:04 +01004274 size_t ip_idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06004275
Denys Vlasenko10bde142018-12-27 18:23:58 +01004276 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004277 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004278 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004279 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004280 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004281
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01004282 cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
Denys Vlasenko5ebd2a62018-12-16 23:35:04 +01004283 ip_idx = cond_idx + 1;
Denys Vlasenkode24e9d2018-12-16 23:02:22 +01004284 bc_vec_push(&p->conds, &cond_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06004285
Denys Vlasenko5ebd2a62018-12-16 23:35:04 +01004286 bc_vec_push(&p->exits, &ip_idx);
4287 bc_vec_push(&p->func->labels, &ip_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06004288
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004289 s = zbc_parse_expr(BC_PARSE_REL);
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004290 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004291 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko202dd192018-12-16 17:30:35 +01004292
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004293 bc_parse_pushJUMP_ZERO(ip_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06004294
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004295 s = zbc_parse_stmt_allow_NLINE_before(STRING_while);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004296 if (s) RETURN_STATUS(s);
4297
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004298 dbg_lex("%s:%d BC_INST_JUMP to %zd", __func__, __LINE__, cond_idx);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004299 bc_parse_pushJUMP(cond_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004300
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004301 dbg_lex("%s:%d rewriting label-> %zd", __func__, __LINE__, p->func->code.len);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004302 rewrite_label_to_current(ip_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004303
4304 bc_vec_pop(&p->exits);
4305 bc_vec_pop(&p->conds);
4306
4307 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004308}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004309#define zbc_parse_while(...) (zbc_parse_while(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004310
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004311static BC_STATUS zbc_parse_for(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004312{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004313 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004314 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06004315 size_t cond_idx, exit_idx, body_idx, update_idx;
4316
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004317 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004318 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004319 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004320 if (p->lex != BC_LEX_LPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004321 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004322 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004323
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004324 if (p->lex != BC_LEX_SCOLON) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004325 s = zbc_parse_expr(0);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004326 xc_parse_push(XC_INST_POP);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004327 if (s) RETURN_STATUS(s);
4328 } else {
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004329 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("init");
4330 if (s) RETURN_STATUS(s);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004331 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004332
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004333 if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004334 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004335 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004336
Denys Vlasenko6ed7fb02018-12-21 22:16:17 +01004337 cond_idx = bc_vec_push(&p->func->labels, &p->func->code.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06004338 update_idx = cond_idx + 1;
4339 body_idx = update_idx + 1;
4340 exit_idx = body_idx + 1;
4341
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004342 if (p->lex != BC_LEX_SCOLON)
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004343 s = zbc_parse_expr(BC_PARSE_REL);
Denys Vlasenko52caa002018-12-21 00:35:22 +01004344 else {
Denys Vlasenko10bde142018-12-27 18:23:58 +01004345 // Set this for the next call to xc_parse_pushNUM().
Denys Vlasenko52caa002018-12-21 00:35:22 +01004346 // This is safe to set because the current token is a semicolon,
4347 // which has no string requirement.
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004348 bc_vec_string(&p->lex_strnumbuf, 1, "1");
Denys Vlasenko10bde142018-12-27 18:23:58 +01004349 xc_parse_pushNUM();
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004350 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
Denys Vlasenko52caa002018-12-21 00:35:22 +01004351 }
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004352 if (s) RETURN_STATUS(s);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004353
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004354 if (p->lex != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06004355
Denys Vlasenko10bde142018-12-27 18:23:58 +01004356 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004357 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004358
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004359 bc_parse_pushJUMP_ZERO(exit_idx);
4360 bc_parse_pushJUMP(body_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06004361
Gavin Howard01055ba2018-11-03 11:00:21 -06004362 bc_vec_push(&p->conds, &update_idx);
4363 bc_vec_push(&p->func->labels, &p->func->code.len);
4364
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004365 if (p->lex != BC_LEX_RPAREN) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004366 s = zbc_parse_expr(0);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004367 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004368 if (p->lex != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004369 xc_parse_push(XC_INST_POP);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004370 } else {
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004371 s = zbc_POSIX_does_not_allow_empty_X_expression_in_for("update");
4372 if (s) RETURN_STATUS(s);
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01004373 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004374
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004375 bc_parse_pushJUMP(cond_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06004376 bc_vec_push(&p->func->labels, &p->func->code.len);
4377
Denys Vlasenko5ebd2a62018-12-16 23:35:04 +01004378 bc_vec_push(&p->exits, &exit_idx);
4379 bc_vec_push(&p->func->labels, &exit_idx);
Denys Vlasenko202dd192018-12-16 17:30:35 +01004380
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004381 s = zbc_parse_stmt_allow_NLINE_before(STRING_for);
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004382 if (s) RETURN_STATUS(s);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004383
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004384 dbg_lex("%s:%d BC_INST_JUMP to %zd", __func__, __LINE__, update_idx);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004385 bc_parse_pushJUMP(update_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004386
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004387 dbg_lex("%s:%d rewriting label-> %zd", __func__, __LINE__, p->func->code.len);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004388 rewrite_label_to_current(exit_idx);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004389
4390 bc_vec_pop(&p->exits);
4391 bc_vec_pop(&p->conds);
Gavin Howard01055ba2018-11-03 11:00:21 -06004392
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004393 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004394}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004395#define zbc_parse_for(...) (zbc_parse_for(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004396
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004397static BC_STATUS zbc_parse_break_or_continue(BcLexType type)
Gavin Howard01055ba2018-11-03 11:00:21 -06004398{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004399 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004400 size_t i;
Gavin Howard01055ba2018-11-03 11:00:21 -06004401
Gavin Howard01055ba2018-11-03 11:00:21 -06004402 if (type == BC_LEX_KEY_BREAK) {
Denys Vlasenko8e7686e2018-12-16 23:18:28 +01004403 if (p->exits.len == 0) // none of the enclosing blocks is a loop
4404 RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko266aa002018-12-16 23:24:25 +01004405 i = *(size_t*)bc_vec_top(&p->exits);
Denys Vlasenko8e7686e2018-12-16 23:18:28 +01004406 } else {
Denys Vlasenko266aa002018-12-16 23:24:25 +01004407 i = *(size_t*)bc_vec_top(&p->conds);
Denys Vlasenko8e7686e2018-12-16 23:18:28 +01004408 }
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004409 bc_parse_pushJUMP(i);
Gavin Howard01055ba2018-11-03 11:00:21 -06004410
Denys Vlasenko10bde142018-12-27 18:23:58 +01004411 RETURN_STATUS(zxc_lex_next());
Gavin Howard01055ba2018-11-03 11:00:21 -06004412}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004413#define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004414
Denys Vlasenko53799502019-01-25 14:24:03 +01004415static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type)
Denys Vlasenko2097ac82018-12-24 05:00:36 +01004416{
4417 BcId *autoid;
4418 BcId a;
4419 size_t i;
4420
4421 autoid = (void*)f->autos.v;
4422 for (i = 0; i < f->autos.len; i++, autoid++) {
Denys Vlasenko22314682019-01-01 21:50:14 +01004423 if (strcmp(name, autoid->name) == 0
Denys Vlasenko53799502019-01-25 14:24:03 +01004424 && type == (BcType) autoid->idx
Denys Vlasenko22314682019-01-01 21:50:14 +01004425 ) {
Denys Vlasenko3f8752c2018-12-25 21:28:25 +01004426 RETURN_STATUS(bc_error("duplicate function parameter or auto name"));
Denys Vlasenko22314682019-01-01 21:50:14 +01004427 }
Denys Vlasenko2097ac82018-12-24 05:00:36 +01004428 }
4429
Denys Vlasenko53799502019-01-25 14:24:03 +01004430 a.idx = type;
Denys Vlasenko2097ac82018-12-24 05:00:36 +01004431 a.name = name;
4432
4433 bc_vec_push(&f->autos, &a);
4434
4435 RETURN_STATUS(BC_STATUS_SUCCESS);
4436}
4437#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
4438
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004439static BC_STATUS zbc_parse_funcdef(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004440{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004441 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004442 BcStatus s;
Denys Vlasenko53799502019-01-25 14:24:03 +01004443 bool comma, voidfunc;
Gavin Howard01055ba2018-11-03 11:00:21 -06004444 char *name;
4445
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004446 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004447 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004448 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004449 if (p->lex != XC_LEX_NAME)
Denys Vlasenko22314682019-01-01 21:50:14 +01004450 RETURN_STATUS(bc_error_bad_function_definition());
Gavin Howard01055ba2018-11-03 11:00:21 -06004451
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004452 // To be maximally both POSIX and GNU-compatible,
4453 // "void" is not treated as a normal keyword:
4454 // you can have variable named "void", and even a function
4455 // named "void": "define void() { return 6; }" is ok.
4456 // _Only_ "define void f() ..." syntax treats "void"
4457 // specially.
4458 voidfunc = (strcmp(p->lex_strnumbuf.v, "void") == 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06004459
Denys Vlasenko10bde142018-12-27 18:23:58 +01004460 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004461 if (s) RETURN_STATUS(s);
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004462
4463 voidfunc = (voidfunc && p->lex == XC_LEX_NAME);
4464 if (voidfunc) {
4465 s = zxc_lex_next();
4466 if (s) RETURN_STATUS(s);
4467 }
4468
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004469 if (p->lex != BC_LEX_LPAREN)
Denys Vlasenko22314682019-01-01 21:50:14 +01004470 RETURN_STATUS(bc_error_bad_function_definition());
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004471
4472 p->fidx = bc_program_addFunc(xstrdup(p->lex_strnumbuf.v));
4473 p->func = xc_program_func(p->fidx);
4474 p->func->voidfunc = voidfunc;
4475
Denys Vlasenko10bde142018-12-27 18:23:58 +01004476 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004477 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004478
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004479 comma = false;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004480 while (p->lex != BC_LEX_RPAREN) {
Denys Vlasenko53799502019-01-25 14:24:03 +01004481 BcType t = BC_TYPE_VAR;
4482
4483 if (p->lex == XC_LEX_OP_MULTIPLY) {
4484 t = BC_TYPE_REF;
4485 s = zxc_lex_next();
4486 if (s) RETURN_STATUS(s);
4487 s = zbc_POSIX_does_not_allow("references");
4488 if (s) RETURN_STATUS(s);
4489 }
4490
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004491 if (p->lex != XC_LEX_NAME)
Denys Vlasenko22314682019-01-01 21:50:14 +01004492 RETURN_STATUS(bc_error_bad_function_definition());
Gavin Howard01055ba2018-11-03 11:00:21 -06004493
4494 ++p->func->nparams;
4495
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004496 name = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004497 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004498 if (s) goto err;
4499
Denys Vlasenko53799502019-01-25 14:24:03 +01004500 if (p->lex == BC_LEX_LBRACKET) {
4501 if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
Denys Vlasenko10bde142018-12-27 18:23:58 +01004502 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004503 if (s) goto err;
4504
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004505 if (p->lex != BC_LEX_RBRACKET) {
Denys Vlasenko22314682019-01-01 21:50:14 +01004506 s = bc_error_bad_function_definition();
Gavin Howard01055ba2018-11-03 11:00:21 -06004507 goto err;
4508 }
4509
Denys Vlasenko10bde142018-12-27 18:23:58 +01004510 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004511 if (s) goto err;
4512 }
Denys Vlasenko53799502019-01-25 14:24:03 +01004513 else if (t == BC_TYPE_REF) {
4514 s = bc_error_at("vars can't be references");
4515 goto err;
4516 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004517
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004518 comma = p->lex == BC_LEX_COMMA;
Gavin Howard01055ba2018-11-03 11:00:21 -06004519 if (comma) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01004520 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004521 if (s) goto err;
4522 }
4523
Denys Vlasenko53799502019-01-25 14:24:03 +01004524 s = zbc_func_insert(p->func, name, t);
Gavin Howard01055ba2018-11-03 11:00:21 -06004525 if (s) goto err;
4526 }
4527
Denys Vlasenko22314682019-01-01 21:50:14 +01004528 if (comma) RETURN_STATUS(bc_error_bad_function_definition());
Gavin Howard01055ba2018-11-03 11:00:21 -06004529
Denys Vlasenko10bde142018-12-27 18:23:58 +01004530 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004531 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004532
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004533 if (p->lex != BC_LEX_LBRACE) {
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004534 s = zbc_POSIX_requires("the left brace be on the same line as the function header");
Denys Vlasenkod279d802018-12-24 18:28:56 +01004535 if (s) RETURN_STATUS(s);
4536 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004537
Denys Vlasenko202dd192018-12-16 17:30:35 +01004538 // Prevent "define z()<newline>" from being interpreted as function with empty stmt as body
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004539 s = zbc_lex_skip_if_at_NLINE();
Denys Vlasenko202dd192018-12-16 17:30:35 +01004540 if (s) RETURN_STATUS(s);
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01004541 // GNU bc requires a {} block even if function body has single stmt, enforce this
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004542 if (p->lex != BC_LEX_LBRACE)
Denys Vlasenko94f72a32018-12-17 00:07:48 +01004543 RETURN_STATUS(bc_error("function { body } expected"));
Denys Vlasenkoe9519e42018-12-16 17:06:07 +01004544
4545 p->in_funcdef++; // to determine whether "return" stmt is allowed, and such
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004546 s = zbc_parse_stmt_possibly_auto(true);
Denys Vlasenkoe9519e42018-12-16 17:06:07 +01004547 p->in_funcdef--;
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004548 if (s) RETURN_STATUS(s);
4549
Denys Vlasenko10bde142018-12-27 18:23:58 +01004550 xc_parse_push(BC_INST_RET0);
Denys Vlasenko65e10462018-12-19 15:13:14 +01004551
4552 // Subsequent code generation is into main program
4553 p->fidx = BC_PROG_MAIN;
Denys Vlasenko10bde142018-12-27 18:23:58 +01004554 p->func = xc_program_func_BC_PROG_MAIN();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004555
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004556 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004557 RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01004558 err:
Denys Vlasenkof4f10722018-12-18 02:23:53 +01004559 dbg_lex_done("%s:%d done (error)", __func__, __LINE__);
Gavin Howard01055ba2018-11-03 11:00:21 -06004560 free(name);
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004561 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004562}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004563#define zbc_parse_funcdef(...) (zbc_parse_funcdef(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004564
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004565static BC_STATUS zbc_parse_auto(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004566{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004567 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004568 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06004569 char *name;
4570
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004571 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004572 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004573 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004574
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004575 for (;;) {
Denys Vlasenko53799502019-01-25 14:24:03 +01004576 BcType t;
Gavin Howard01055ba2018-11-03 11:00:21 -06004577
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004578 if (p->lex != XC_LEX_NAME)
Denys Vlasenko22314682019-01-01 21:50:14 +01004579 RETURN_STATUS(bc_error_at("bad 'auto' syntax"));
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004580
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004581 name = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004582 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004583 if (s) goto err;
4584
Denys Vlasenko53799502019-01-25 14:24:03 +01004585 t = BC_TYPE_VAR;
4586 if (p->lex == BC_LEX_LBRACKET) {
4587 t = BC_TYPE_ARRAY;
Denys Vlasenko10bde142018-12-27 18:23:58 +01004588 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004589 if (s) goto err;
4590
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004591 if (p->lex != BC_LEX_RBRACKET) {
Denys Vlasenko22314682019-01-01 21:50:14 +01004592 s = bc_error_at("bad 'auto' syntax");
Gavin Howard01055ba2018-11-03 11:00:21 -06004593 goto err;
4594 }
Denys Vlasenko10bde142018-12-27 18:23:58 +01004595 s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06004596 if (s) goto err;
4597 }
4598
Denys Vlasenko53799502019-01-25 14:24:03 +01004599 s = zbc_func_insert(p->func, name, t);
Gavin Howard01055ba2018-11-03 11:00:21 -06004600 if (s) goto err;
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004601
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004602 if (p->lex == XC_LEX_NLINE
4603 || p->lex == BC_LEX_SCOLON
4604 //|| p->lex == BC_LEX_RBRACE // allow "define f() {auto a}"
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004605 ) {
4606 break;
4607 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004608 if (p->lex != BC_LEX_COMMA)
Denys Vlasenko22314682019-01-01 21:50:14 +01004609 RETURN_STATUS(bc_error_at("bad 'auto' syntax"));
Denys Vlasenko10bde142018-12-27 18:23:58 +01004610 s = zxc_lex_next(); // skip comma
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004611 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004612 }
4613
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004614 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenkod4b721c2018-12-25 16:39:01 +01004615 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01004616 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06004617 free(name);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004618 dbg_lex_done("%s:%d done (ERROR)", __func__, __LINE__);
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01004619 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004620}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004621#define zbc_parse_auto(...) (zbc_parse_auto(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004622
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004623#undef zbc_parse_stmt_possibly_auto
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004624static BC_STATUS zbc_parse_stmt_possibly_auto(bool auto_allowed)
Gavin Howard01055ba2018-11-03 11:00:21 -06004625{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004626 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004627 BcStatus s = BC_STATUS_SUCCESS;
4628
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004629 dbg_lex_enter("%s:%d entered, p->lex:%d", __func__, __LINE__, p->lex);
Gavin Howard01055ba2018-11-03 11:00:21 -06004630
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004631 if (p->lex == XC_LEX_NLINE) {
Denys Vlasenko23ea0732018-12-24 15:05:49 +01004632 dbg_lex_done("%s:%d done (seen XC_LEX_NLINE)", __func__, __LINE__);
Denys Vlasenkofc7aa7a2019-01-08 18:08:48 +01004633 RETURN_STATUS(s);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004634 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004635 if (p->lex == BC_LEX_SCOLON) {
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004636 dbg_lex_done("%s:%d done (seen BC_LEX_SCOLON)", __func__, __LINE__);
Denys Vlasenkofc7aa7a2019-01-08 18:08:48 +01004637 RETURN_STATUS(s);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004638 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004639
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004640 if (p->lex == BC_LEX_LBRACE) {
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004641 dbg_lex("%s:%d BC_LEX_LBRACE: (auto_allowed:%d)", __func__, __LINE__, auto_allowed);
4642 do {
Denys Vlasenko10bde142018-12-27 18:23:58 +01004643 s = zxc_lex_next();
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004644 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004645 } while (p->lex == XC_LEX_NLINE);
4646 if (auto_allowed && p->lex == BC_LEX_KEY_AUTO) {
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004647 dbg_lex("%s:%d calling zbc_parse_auto()", __func__, __LINE__);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004648 s = zbc_parse_auto();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004649 if (s) RETURN_STATUS(s);
4650 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004651 while (p->lex != BC_LEX_RBRACE) {
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004652 dbg_lex("%s:%d block parsing loop", __func__, __LINE__);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004653 s = zbc_parse_stmt();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004654 if (s) RETURN_STATUS(s);
Denys Vlasenkofc7aa7a2019-01-08 18:08:48 +01004655 // Check that next token is a correct stmt delimiter -
4656 // disallows "print 1 print 2" and such.
4657 if (p->lex == BC_LEX_RBRACE)
4658 break;
4659 if (p->lex != BC_LEX_SCOLON
4660 && p->lex != XC_LEX_NLINE
4661 ) {
4662 RETURN_STATUS(bc_error_at("bad statement terminator"));
4663 }
4664 s = zxc_lex_next();
4665 if (s) RETURN_STATUS(s);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004666 }
Denys Vlasenko10bde142018-12-27 18:23:58 +01004667 s = zxc_lex_next();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01004668 dbg_lex_done("%s:%d done (seen BC_LEX_RBRACE)", __func__, __LINE__);
4669 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004670 }
4671
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004672 dbg_lex("%s:%d p->lex:%d", __func__, __LINE__, p->lex);
4673 switch (p->lex) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004674 case XC_LEX_OP_MINUS:
4675 case BC_LEX_OP_INC:
4676 case BC_LEX_OP_DEC:
4677 case BC_LEX_OP_BOOL_NOT:
4678 case BC_LEX_LPAREN:
4679 case XC_LEX_NAME:
4680 case XC_LEX_NUMBER:
4681 case BC_LEX_KEY_IBASE:
4682 case BC_LEX_KEY_LAST:
4683 case BC_LEX_KEY_LENGTH:
4684 case BC_LEX_KEY_OBASE:
4685 case BC_LEX_KEY_READ:
4686 case BC_LEX_KEY_SCALE:
4687 case BC_LEX_KEY_SQRT:
4688 s = zbc_parse_expr(BC_PARSE_PRINT);
4689 break;
4690 case XC_LEX_STR:
4691 s = zbc_parse_pushSTR();
Denys Vlasenko10bde142018-12-27 18:23:58 +01004692 xc_parse_push(XC_INST_PRINT_STR);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004693 break;
4694 case BC_LEX_KEY_BREAK:
4695 case BC_LEX_KEY_CONTINUE:
4696 s = zbc_parse_break_or_continue(p->lex);
4697 break;
4698 case BC_LEX_KEY_FOR:
4699 s = zbc_parse_for();
4700 break;
4701 case BC_LEX_KEY_HALT:
Denys Vlasenko10bde142018-12-27 18:23:58 +01004702 xc_parse_push(BC_INST_HALT);
4703 s = zxc_lex_next();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004704 break;
4705 case BC_LEX_KEY_IF:
4706 s = zbc_parse_if();
4707 break;
4708 case BC_LEX_KEY_LIMITS:
4709 // "limits" is a compile-time command,
4710 // the output is produced at _parse time_.
4711 printf(
4712 "BC_BASE_MAX = "BC_MAX_OBASE_STR "\n"
4713 "BC_DIM_MAX = "BC_MAX_DIM_STR "\n"
4714 "BC_SCALE_MAX = "BC_MAX_SCALE_STR "\n"
4715 "BC_STRING_MAX = "BC_MAX_STRING_STR"\n"
Denys Vlasenkoe05ec6e2019-01-04 16:26:19 +01004716 // "BC_NUM_MAX = "BC_MAX_NUM_STR "\n" - GNU bc does not show this
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004717 "MAX Exponent = "BC_MAX_EXP_STR "\n"
4718 "Number of vars = "BC_MAX_VARS_STR "\n"
4719 );
Denys Vlasenko10bde142018-12-27 18:23:58 +01004720 s = zxc_lex_next();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004721 break;
4722 case BC_LEX_KEY_PRINT:
4723 s = zbc_parse_print();
4724 break;
4725 case BC_LEX_KEY_QUIT:
4726 // "quit" is a compile-time command. For example,
4727 // "if (0 == 1) quit" terminates when parsing the statement,
4728 // not when it is executed
4729 QUIT_OR_RETURN_TO_MAIN;
4730 case BC_LEX_KEY_RETURN:
4731 if (!p->in_funcdef)
4732 RETURN_STATUS(bc_error("'return' not in a function"));
4733 s = zbc_parse_return();
4734 break;
4735 case BC_LEX_KEY_WHILE:
4736 s = zbc_parse_while();
4737 break;
4738 default:
4739 s = bc_error_bad_token();
4740 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06004741 }
4742
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01004743 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenkoae0faf92018-12-12 15:19:54 +01004744 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004745}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004746#define zbc_parse_stmt_possibly_auto(...) (zbc_parse_stmt_possibly_auto(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004747
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004748static BC_STATUS zbc_parse_stmt_or_funcdef(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06004749{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004750 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06004751 BcStatus s;
4752
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01004753 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenkofc7aa7a2019-01-08 18:08:48 +01004754//why?
4755// if (p->lex == XC_LEX_EOF)
4756// s = bc_error("end of file");
4757// else
4758 if (p->lex == BC_LEX_KEY_DEFINE) {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004759 dbg_lex("%s:%d p->lex:BC_LEX_KEY_DEFINE", __func__, __LINE__);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004760 s = zbc_parse_funcdef();
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01004761 } else {
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004762 dbg_lex("%s:%d p->lex:%d (not BC_LEX_KEY_DEFINE)", __func__, __LINE__, p->lex);
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004763 s = zbc_parse_stmt();
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01004764 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004765
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01004766 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenko26819db2018-12-12 16:08:46 +01004767 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004768}
Denys Vlasenkoec603182018-12-17 10:34:02 +01004769#define zbc_parse_stmt_or_funcdef(...) (zbc_parse_stmt_or_funcdef(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004770
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004771#undef zbc_parse_expr
4772static BC_STATUS zbc_parse_expr(uint8_t flags)
Gavin Howard01055ba2018-11-03 11:00:21 -06004773{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01004774 BcParse *p = &G.prs;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004775 BcInst prev = XC_INST_PRINT;
Gavin Howard01055ba2018-11-03 11:00:21 -06004776 size_t nexprs = 0, ops_bgn = p->ops.len;
Denys Vlasenko18c6b542018-12-07 12:57:32 +01004777 unsigned nparens, nrelops;
Denys Vlasenko22314682019-01-01 21:50:14 +01004778 bool paren_first, rprn, assign, bin_last, incdec;
Gavin Howard01055ba2018-11-03 11:00:21 -06004779
Denys Vlasenko17df8822018-12-14 23:00:24 +01004780 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004781 paren_first = (p->lex == BC_LEX_LPAREN);
Gavin Howard01055ba2018-11-03 11:00:21 -06004782 nparens = nrelops = 0;
Denys Vlasenko22314682019-01-01 21:50:14 +01004783 rprn = assign = incdec = false;
Gavin Howard01055ba2018-11-03 11:00:21 -06004784 bin_last = true;
4785
Denys Vlasenkod0238d82018-12-25 01:21:16 +01004786 for (;;) {
Denys Vlasenko73b3ebc2018-12-25 01:43:52 +01004787 bool get_token;
Denys Vlasenkod0238d82018-12-25 01:21:16 +01004788 BcStatus s;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01004789 BcLexType t = p->lex;
Denys Vlasenkod0238d82018-12-25 01:21:16 +01004790
4791 if (!lex_allowed_in_bc_expr(t))
4792 break;
Denys Vlasenkobb116032018-12-25 01:16:37 +01004793
Denys Vlasenko8c1e7232018-12-22 01:34:10 +01004794 dbg_lex("%s:%d t:%d", __func__, __LINE__, t);
Denys Vlasenko73b3ebc2018-12-25 01:43:52 +01004795 get_token = false;
Denys Vlasenkod0238d82018-12-25 01:21:16 +01004796 s = BC_STATUS_SUCCESS;
Gavin Howard01055ba2018-11-03 11:00:21 -06004797 switch (t) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004798 case BC_LEX_OP_INC:
4799 case BC_LEX_OP_DEC:
4800 dbg_lex("%s:%d LEX_OP_INC/DEC", __func__, __LINE__);
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004801 if (incdec) RETURN_STATUS(bc_error_bad_assignment());
Denys Vlasenko22314682019-01-01 21:50:14 +01004802 s = zbc_parse_incdec(&prev, &nexprs, flags);
4803 incdec = true;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004804 rprn = bin_last = false;
4805 //get_token = false; - already is
4806 break;
4807 case XC_LEX_OP_MINUS:
4808 dbg_lex("%s:%d LEX_OP_MINUS", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004809 s = zbc_parse_minus(&prev, ops_bgn, rprn, bin_last, &nexprs);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004810 rprn = false;
4811 //get_token = false; - already is
4812 bin_last = (prev == XC_INST_MINUS);
Denys Vlasenko22314682019-01-01 21:50:14 +01004813 if (bin_last) incdec = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004814 break;
4815 case BC_LEX_OP_ASSIGN_POWER:
4816 case BC_LEX_OP_ASSIGN_MULTIPLY:
4817 case BC_LEX_OP_ASSIGN_DIVIDE:
4818 case BC_LEX_OP_ASSIGN_MODULUS:
4819 case BC_LEX_OP_ASSIGN_PLUS:
4820 case BC_LEX_OP_ASSIGN_MINUS:
4821 case BC_LEX_OP_ASSIGN:
4822 dbg_lex("%s:%d LEX_ASSIGNxyz", __func__, __LINE__);
4823 if (prev != XC_INST_VAR && prev != XC_INST_ARRAY_ELEM
4824 && prev != XC_INST_SCALE && prev != XC_INST_IBASE
4825 && prev != XC_INST_OBASE && prev != BC_INST_LAST
4826 ) {
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004827 RETURN_STATUS(bc_error_bad_assignment());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004828 }
4829 // Fallthrough.
4830 case XC_LEX_OP_POWER:
4831 case XC_LEX_OP_MULTIPLY:
4832 case XC_LEX_OP_DIVIDE:
4833 case XC_LEX_OP_MODULUS:
4834 case XC_LEX_OP_PLUS:
4835 case XC_LEX_OP_REL_EQ:
4836 case XC_LEX_OP_REL_LE:
4837 case XC_LEX_OP_REL_GE:
4838 case XC_LEX_OP_REL_NE:
4839 case XC_LEX_OP_REL_LT:
4840 case XC_LEX_OP_REL_GT:
4841 case BC_LEX_OP_BOOL_NOT:
4842 case BC_LEX_OP_BOOL_OR:
4843 case BC_LEX_OP_BOOL_AND:
4844 dbg_lex("%s:%d LEX_OP_xyz", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004845 if (t == BC_LEX_OP_BOOL_NOT) {
4846 if (!bin_last && p->lex_last != BC_LEX_OP_BOOL_NOT)
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004847 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko22314682019-01-01 21:50:14 +01004848 } else if (prev == XC_INST_BOOL_NOT) {
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004849 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004850 }
Denys Vlasenko22314682019-01-01 21:50:14 +01004851
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004852 nrelops += (t >= XC_LEX_OP_REL_EQ && t <= XC_LEX_OP_REL_GT);
4853 prev = BC_TOKEN_2_INST(t);
4854 bc_parse_operator(t, ops_bgn, &nexprs);
Denys Vlasenko22314682019-01-01 21:50:14 +01004855 rprn = incdec = false;
4856 get_token = true;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004857 bin_last = (t != BC_LEX_OP_BOOL_NOT);
4858 break;
4859 case BC_LEX_LPAREN:
4860 dbg_lex("%s:%d LEX_LPAREN", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004861 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004862 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004863 bc_vec_push(&p->ops, &t);
4864 nparens++;
4865 get_token = true;
Denys Vlasenko22314682019-01-01 21:50:14 +01004866 rprn = incdec = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004867 break;
4868 case BC_LEX_RPAREN:
4869 dbg_lex("%s:%d LEX_RPAREN", __func__, __LINE__);
Denys Vlasenkoa1698a12019-01-08 19:32:38 +01004870//why?
4871// if (p->lex_last == BC_LEX_LPAREN) {
4872// RETURN_STATUS(bc_error_at("empty expression"));
4873// }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004874 if (bin_last || prev == XC_INST_BOOL_NOT)
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004875 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004876 if (nparens == 0) {
4877 goto exit_loop;
4878 }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004879 s = zbc_parse_rightParen(ops_bgn, &nexprs);
4880 nparens--;
4881 get_token = true;
Denys Vlasenko22314682019-01-01 21:50:14 +01004882 rprn = true;
4883 bin_last = incdec = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004884 break;
4885 case XC_LEX_NAME:
4886 dbg_lex("%s:%d LEX_NAME", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004887 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004888 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004889 s = zbc_parse_name(&prev, flags & ~BC_PARSE_NOCALL);
Denys Vlasenko22314682019-01-01 21:50:14 +01004890 rprn = (prev == BC_INST_CALL);
4891 bin_last = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004892 //get_token = false; - already is
4893 nexprs++;
4894 break;
4895 case XC_LEX_NUMBER:
4896 dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004897 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004898 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko10bde142018-12-27 18:23:58 +01004899 xc_parse_pushNUM();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004900 prev = XC_INST_NUM;
4901 get_token = true;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004902 rprn = bin_last = false;
4903 nexprs++;
4904 break;
4905 case BC_LEX_KEY_IBASE:
4906 case BC_LEX_KEY_LAST:
4907 case BC_LEX_KEY_OBASE:
4908 dbg_lex("%s:%d LEX_IBASE/LAST/OBASE", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004909 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004910 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004911 prev = (char) (t - BC_LEX_KEY_IBASE + XC_INST_IBASE);
Denys Vlasenko10bde142018-12-27 18:23:58 +01004912 xc_parse_push((char) prev);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004913 get_token = true;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004914 rprn = bin_last = false;
4915 nexprs++;
4916 break;
4917 case BC_LEX_KEY_LENGTH:
4918 case BC_LEX_KEY_SQRT:
4919 dbg_lex("%s:%d LEX_LEN/SQRT", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004920 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004921 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004922 s = zbc_parse_builtin(t, flags, &prev);
4923 get_token = true;
Denys Vlasenko22314682019-01-01 21:50:14 +01004924 rprn = bin_last = incdec = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004925 nexprs++;
4926 break;
4927 case BC_LEX_KEY_READ:
4928 dbg_lex("%s:%d LEX_READ", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004929 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004930 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004931 s = zbc_parse_read();
4932 prev = XC_INST_READ;
4933 get_token = true;
Denys Vlasenko22314682019-01-01 21:50:14 +01004934 rprn = bin_last = incdec = false;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004935 nexprs++;
4936 break;
4937 case BC_LEX_KEY_SCALE:
4938 dbg_lex("%s:%d LEX_SCALE", __func__, __LINE__);
Denys Vlasenko22314682019-01-01 21:50:14 +01004939 if (BC_PARSE_LEAF(prev, bin_last, rprn))
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004940 RETURN_STATUS(bc_error_bad_expression());
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004941 s = zbc_parse_scale(&prev, flags);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004942 //get_token = false; - already is
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01004943 rprn = bin_last = false;
4944 nexprs++;
4945 break;
4946 default:
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004947 RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06004948 }
4949
Denys Vlasenkobb116032018-12-25 01:16:37 +01004950 if (s || G_interrupt) // error, or ^C: stop parsing
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004951 RETURN_STATUS(BC_STATUS_FAILURE);
Denys Vlasenkobb116032018-12-25 01:16:37 +01004952 if (get_token) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01004953 s = zxc_lex_next();
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004954 if (s) RETURN_STATUS(s);
Denys Vlasenkobb116032018-12-25 01:16:37 +01004955 }
Gavin Howard01055ba2018-11-03 11:00:21 -06004956 }
Denys Vlasenkobb116032018-12-25 01:16:37 +01004957 exit_loop:
Gavin Howard01055ba2018-11-03 11:00:21 -06004958
4959 while (p->ops.len > ops_bgn) {
Denys Vlasenkod0238d82018-12-25 01:21:16 +01004960 BcLexType top = BC_PARSE_TOP_OP(p);
Denys Vlasenkoa5bf53e2018-12-24 17:06:37 +01004961 assign = (top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN);
Gavin Howard01055ba2018-11-03 11:00:21 -06004962
4963 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004964 RETURN_STATUS(bc_error_bad_expression());
Gavin Howard01055ba2018-11-03 11:00:21 -06004965
Denys Vlasenko10bde142018-12-27 18:23:58 +01004966 xc_parse_push(BC_TOKEN_2_INST(top));
Gavin Howard01055ba2018-11-03 11:00:21 -06004967
Denys Vlasenko69560f42018-12-24 14:14:23 +01004968 nexprs -= (top != BC_LEX_OP_BOOL_NOT && top != XC_LEX_NEG);
Gavin Howard01055ba2018-11-03 11:00:21 -06004969 bc_vec_pop(&p->ops);
4970 }
4971
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01004972 if (prev == XC_INST_BOOL_NOT || nexprs != 1)
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004973 RETURN_STATUS(bc_error_bad_expression());
Gavin Howard01055ba2018-11-03 11:00:21 -06004974
Gavin Howard01055ba2018-11-03 11:00:21 -06004975 if (!(flags & BC_PARSE_REL) && nrelops) {
Denys Vlasenkobb116032018-12-25 01:16:37 +01004976 BcStatus s;
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004977 s = zbc_POSIX_does_not_allow("comparison operators outside if or loops");
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004978 if (s) RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01004979 } else if ((flags & BC_PARSE_REL) && nrelops > 1) {
Denys Vlasenkobb116032018-12-25 01:16:37 +01004980 BcStatus s;
Denys Vlasenko79587cb2018-12-24 18:11:41 +01004981 s = zbc_POSIX_requires("exactly one comparison operator per condition");
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004982 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06004983 }
4984
4985 if (flags & BC_PARSE_PRINT) {
Denys Vlasenkobb116032018-12-25 01:16:37 +01004986 if (paren_first || !assign)
Denys Vlasenko10bde142018-12-27 18:23:58 +01004987 xc_parse_push(XC_INST_PRINT);
4988 xc_parse_push(XC_INST_POP);
Gavin Howard01055ba2018-11-03 11:00:21 -06004989 }
4990
Denys Vlasenko17df8822018-12-14 23:00:24 +01004991 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004992 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06004993}
Denys Vlasenko132d7c02019-01-08 19:29:35 +01004994#define zbc_parse_expr(...) (zbc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06004995
Gavin Howard01055ba2018-11-03 11:00:21 -06004996#endif // ENABLE_BC
4997
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01004998#if ENABLE_DC
Denys Vlasenkocca79a02018-12-05 21:15:46 +01004999
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005000static BC_STATUS zdc_parse_register(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005001{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005002 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06005003 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06005004
Denys Vlasenko10bde142018-12-27 18:23:58 +01005005 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005006 if (s) RETURN_STATUS(s);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005007 if (p->lex != XC_LEX_NAME) RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06005008
Denys Vlasenko10bde142018-12-27 18:23:58 +01005009 xc_parse_pushName(p->lex_strnumbuf.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005010
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005011 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005012}
Denys Vlasenkoec603182018-12-17 10:34:02 +01005013#define zdc_parse_register(...) (zdc_parse_register(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005014
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005015static void dc_parse_string(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005016{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005017 BcParse *p = &G.prs;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005018 char *str;
Denys Vlasenko684d4412018-12-19 14:57:23 +01005019 size_t len = G.prog.strs.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06005020
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005021 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Gavin Howard01055ba2018-11-03 11:00:21 -06005022
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005023 str = xstrdup(p->lex_strnumbuf.v);
Denys Vlasenkocfc25462019-01-09 11:17:19 +01005024 xc_parse_pushInst_and_Index(XC_INST_STR, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005025 bc_vec_push(&G.prog.strs, &str);
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005026
Brian Foleyb64470b2019-09-05 10:50:13 +02005027 // Add an empty function so that if zdc_program_execStr ever needs to
5028 // parse the string into code (from the 'x' command) there's somewhere
5029 // to store the bytecode.
Denys Vlasenko10bde142018-12-27 18:23:58 +01005030 xc_program_add_fn();
5031 p->func = xc_program_func(p->fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005032
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005033 dbg_lex_done("%s:%d done", __func__, __LINE__);
Gavin Howard01055ba2018-11-03 11:00:21 -06005034}
5035
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005036static BC_STATUS zdc_parse_mem(uint8_t inst, bool name, bool store)
Gavin Howard01055ba2018-11-03 11:00:21 -06005037{
5038 BcStatus s;
5039
Denys Vlasenko10bde142018-12-27 18:23:58 +01005040 xc_parse_push(inst);
Gavin Howard01055ba2018-11-03 11:00:21 -06005041 if (name) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005042 s = zdc_parse_register();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005043 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005044 }
5045
5046 if (store) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01005047 xc_parse_push(DC_INST_SWAP);
5048 xc_parse_push(XC_INST_ASSIGN);
5049 xc_parse_push(XC_INST_POP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005050 }
5051
Denys Vlasenko5daa1a02018-12-22 16:40:38 +01005052 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06005053}
Denys Vlasenkoec603182018-12-17 10:34:02 +01005054#define zdc_parse_mem(...) (zdc_parse_mem(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005055
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005056static BC_STATUS zdc_parse_cond(uint8_t inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005057{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005058 BcParse *p = &G.prs;
Gavin Howard01055ba2018-11-03 11:00:21 -06005059 BcStatus s;
5060
Denys Vlasenko10bde142018-12-27 18:23:58 +01005061 xc_parse_push(inst);
5062 xc_parse_push(DC_INST_EXEC_COND);
Gavin Howard01055ba2018-11-03 11:00:21 -06005063
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005064 s = zdc_parse_register();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005065 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005066
Denys Vlasenko10bde142018-12-27 18:23:58 +01005067 s = zxc_lex_next();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005068 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005069
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005070 // Note that 'else' part can not be on the next line:
5071 // echo -e '[1p]sa [2p]sb 2 1>a eb' | dc - OK, prints "2"
5072 // echo -e '[1p]sa [2p]sb 2 1>a\neb' | dc - parse error
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005073 if (p->lex == DC_LEX_ELSE) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005074 s = zdc_parse_register();
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005075 if (s) RETURN_STATUS(s);
Denys Vlasenko10bde142018-12-27 18:23:58 +01005076 s = zxc_lex_next();
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005077 } else {
Denys Vlasenko10bde142018-12-27 18:23:58 +01005078 xc_parse_push('\0');
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005079 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005080
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005081 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005082}
Denys Vlasenkoec603182018-12-17 10:34:02 +01005083#define zdc_parse_cond(...) (zdc_parse_cond(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005084
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005085static BC_STATUS zdc_parse_token(BcLexType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005086{
Denys Vlasenko5daa1a02018-12-22 16:40:38 +01005087 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06005088 uint8_t inst;
Denys Vlasenko5daa1a02018-12-22 16:40:38 +01005089 bool assign, get_token;
Gavin Howard01055ba2018-11-03 11:00:21 -06005090
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005091 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko5daa1a02018-12-22 16:40:38 +01005092 s = BC_STATUS_SUCCESS;
5093 get_token = true;
Gavin Howard01055ba2018-11-03 11:00:21 -06005094 switch (t) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005095 case XC_LEX_OP_REL_EQ:
5096 case XC_LEX_OP_REL_LE:
5097 case XC_LEX_OP_REL_GE:
5098 case XC_LEX_OP_REL_NE:
5099 case XC_LEX_OP_REL_LT:
5100 case XC_LEX_OP_REL_GT:
5101 dbg_lex("%s:%d LEX_OP_REL_xyz", __func__, __LINE__);
5102 s = zdc_parse_cond(t - XC_LEX_OP_REL_EQ + XC_INST_REL_EQ);
5103 get_token = false;
5104 break;
5105 case DC_LEX_SCOLON:
5106 case DC_LEX_COLON:
5107 dbg_lex("%s:%d LEX_[S]COLON", __func__, __LINE__);
5108 s = zdc_parse_mem(XC_INST_ARRAY_ELEM, true, t == DC_LEX_COLON);
5109 break;
5110 case XC_LEX_STR:
5111 dbg_lex("%s:%d LEX_STR", __func__, __LINE__);
5112 dc_parse_string();
5113 break;
5114 case XC_LEX_NEG:
5115 dbg_lex("%s:%d LEX_NEG", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01005116 s = zxc_lex_next();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005117 if (s) RETURN_STATUS(s);
5118 if (G.prs.lex != XC_LEX_NUMBER)
Denys Vlasenko5daa1a02018-12-22 16:40:38 +01005119 RETURN_STATUS(bc_error_bad_token());
Denys Vlasenko10bde142018-12-27 18:23:58 +01005120 xc_parse_pushNUM();
5121 xc_parse_push(XC_INST_NEG);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005122 break;
5123 case XC_LEX_NUMBER:
5124 dbg_lex("%s:%d LEX_NUMBER", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01005125 xc_parse_pushNUM();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005126 break;
5127 case DC_LEX_READ:
5128 dbg_lex("%s:%d LEX_KEY_READ", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01005129 xc_parse_push(XC_INST_READ);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005130 break;
5131 case DC_LEX_OP_ASSIGN:
5132 case DC_LEX_STORE_PUSH:
5133 dbg_lex("%s:%d LEX_OP_ASSIGN/STORE_PUSH", __func__, __LINE__);
5134 assign = (t == DC_LEX_OP_ASSIGN);
5135 inst = assign ? XC_INST_VAR : DC_INST_PUSH_TO_VAR;
5136 s = zdc_parse_mem(inst, true, assign);
5137 break;
5138 case DC_LEX_LOAD:
5139 case DC_LEX_LOAD_POP:
5140 dbg_lex("%s:%d LEX_OP_LOAD[_POP]", __func__, __LINE__);
5141 inst = t == DC_LEX_LOAD_POP ? DC_INST_PUSH_VAR : DC_INST_LOAD;
5142 s = zdc_parse_mem(inst, true, false);
5143 break;
5144 case DC_LEX_STORE_IBASE:
5145 case DC_LEX_STORE_SCALE:
5146 case DC_LEX_STORE_OBASE:
5147 dbg_lex("%s:%d LEX_OP_STORE_I/OBASE/SCALE", __func__, __LINE__);
5148 inst = t - DC_LEX_STORE_IBASE + XC_INST_IBASE;
5149 s = zdc_parse_mem(inst, false, true);
5150 break;
5151 default:
5152 dbg_lex_done("%s:%d done (bad token)", __func__, __LINE__);
5153 RETURN_STATUS(bc_error_bad_token());
Gavin Howard01055ba2018-11-03 11:00:21 -06005154 }
5155
Denys Vlasenko10bde142018-12-27 18:23:58 +01005156 if (!s && get_token) s = zxc_lex_next();
Gavin Howard01055ba2018-11-03 11:00:21 -06005157
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005158 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenko8cd468f2018-12-12 14:54:38 +01005159 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005160}
Denys Vlasenkoec603182018-12-17 10:34:02 +01005161#define zdc_parse_token(...) (zdc_parse_token(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005162
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005163static BC_STATUS zdc_parse_expr(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005164{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005165 BcParse *p = &G.prs;
Denys Vlasenko4accb6b2018-12-24 15:29:08 +01005166 int i;
Gavin Howard01055ba2018-11-03 11:00:21 -06005167
Denys Vlasenko6842c602019-01-04 05:41:47 +01005168 if (p->lex == XC_LEX_NLINE)
5169 RETURN_STATUS(zxc_lex_next());
5170
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005171 i = (int)p->lex - (int)XC_LEX_OP_POWER;
Denys Vlasenko4accb6b2018-12-24 15:29:08 +01005172 if (i >= 0) {
5173 BcInst inst = dc_LEX_to_INST[i];
5174 if (inst != DC_INST_INVALID) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01005175 xc_parse_push(inst);
5176 RETURN_STATUS(zxc_lex_next());
Denys Vlasenko4accb6b2018-12-24 15:29:08 +01005177 }
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005178 }
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005179 RETURN_STATUS(zdc_parse_token(p->lex));
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005180}
5181#define zdc_parse_expr(...) (zdc_parse_expr(__VA_ARGS__) COMMA_SUCCESS)
5182
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005183static BC_STATUS zdc_parse_exprs_until_eof(void)
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005184{
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005185 BcParse *p = &G.prs;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005186 dbg_lex_enter("%s:%d entered, p->lex:%d", __func__, __LINE__, p->lex);
5187 while (p->lex != XC_LEX_EOF) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005188 BcStatus s = zdc_parse_expr();
Denys Vlasenkoa199cc92018-12-18 14:11:35 +01005189 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005190 }
5191
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01005192 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenkoa199cc92018-12-18 14:11:35 +01005193 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06005194}
Denys Vlasenkobadf6832018-12-22 18:04:08 +01005195#define zdc_parse_exprs_until_eof(...) (zdc_parse_exprs_until_eof(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005196
Gavin Howard01055ba2018-11-03 11:00:21 -06005197#endif // ENABLE_DC
5198
Denys Vlasenko2097ac82018-12-24 05:00:36 +01005199//
5200// Execution engine
5201//
5202
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01005203#define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
5204#define BC_PROG_NUM(r, n) \
5205 ((r)->t != XC_RESULT_ARRAY && (r)->t != XC_RESULT_STR && !BC_PROG_STR(n))
5206
Denys Vlasenko2097ac82018-12-24 05:00:36 +01005207#define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n)))
5208#define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n)))
5209
Denys Vlasenko53799502019-01-25 14:24:03 +01005210static size_t xc_program_index(char *code, size_t *bgn)
5211{
5212 unsigned char *bytes = (void*)(code + *bgn);
5213 unsigned amt;
5214 unsigned i;
5215 size_t res;
5216
5217 amt = *bytes++;
5218 if (amt < SMALL_INDEX_LIMIT) {
5219 *bgn += 1;
5220 return amt;
5221 }
5222 amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here
5223 *bgn += amt + 1;
5224
5225 res = 0;
5226 i = 0;
5227 do {
5228 res |= (size_t)(*bytes++) << i;
5229 i += 8;
5230 } while (--amt != 0);
5231
5232 return res;
5233}
5234
5235static char *xc_program_name(char *code, size_t *bgn)
5236{
5237 code += *bgn;
5238 *bgn += strlen(code) + 1;
5239
5240 return xstrdup(code);
5241}
5242
5243static BcVec* xc_program_dereference(BcVec *vec)
5244{
5245 BcVec *v;
5246 size_t vidx, nidx, i = 0;
5247
5248 //assert(vec->size == sizeof(uint8_t));
5249
5250 vidx = xc_program_index(vec->v, &i);
5251 nidx = xc_program_index(vec->v, &i);
5252
5253 v = bc_vec_item(&G.prog.arrs, vidx);
5254 v = bc_vec_item(v, nidx);
5255
5256 //assert(v->size != sizeof(uint8_t));
5257
5258 return v;
5259}
5260
5261static BcVec* xc_program_search(char *id, BcType type)
Gavin Howard01055ba2018-11-03 11:00:21 -06005262{
Gavin Howard01055ba2018-11-03 11:00:21 -06005263 BcId e, *ptr;
5264 BcVec *v, *map;
5265 size_t i;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005266 int new;
Denys Vlasenko53799502019-01-25 14:24:03 +01005267 bool var = (type == BC_TYPE_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005268
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005269 v = var ? &G.prog.vars : &G.prog.arrs;
5270 map = var ? &G.prog.var_map : &G.prog.arr_map;
Gavin Howard01055ba2018-11-03 11:00:21 -06005271
5272 e.name = id;
5273 e.idx = v->len;
Denys Vlasenkoa02f8442018-12-03 20:35:16 +01005274 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
Gavin Howard01055ba2018-11-03 11:00:21 -06005275
5276 if (new) {
Denys Vlasenkof36a0ad2018-12-19 17:15:04 +01005277 BcVec v2;
5278 bc_array_init(&v2, var);
5279 bc_vec_push(v, &v2);
Gavin Howard01055ba2018-11-03 11:00:21 -06005280 }
5281
5282 ptr = bc_vec_item(map, i);
5283 if (new) ptr->name = xstrdup(e.name);
Denys Vlasenkodf515392018-12-02 19:27:48 +01005284 return bc_vec_item(v, ptr->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005285}
5286
Denys Vlasenko8287b1c2018-12-21 22:43:53 +01005287// 'num' need not be initialized on entry
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005288static BC_STATUS zxc_program_num(BcResult *r, BcNum **num)
Gavin Howard01055ba2018-11-03 11:00:21 -06005289{
Gavin Howard01055ba2018-11-03 11:00:21 -06005290 switch (r->t) {
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005291 case XC_RESULT_STR:
5292 case XC_RESULT_TEMP:
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005293 IF_BC(case BC_RESULT_VOID:)
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005294 case XC_RESULT_IBASE:
5295 case XC_RESULT_SCALE:
5296 case XC_RESULT_OBASE:
5297 *num = &r->d.n;
5298 break;
5299 case XC_RESULT_CONSTANT: {
5300 BcStatus s;
5301 char *str;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005302 size_t len;
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01005303
Denys Vlasenko10bde142018-12-27 18:23:58 +01005304 str = *xc_program_const(r->d.id.idx);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005305 len = strlen(str);
Gavin Howard01055ba2018-11-03 11:00:21 -06005306
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005307 bc_num_init(&r->d.n, len);
Gavin Howard01055ba2018-11-03 11:00:21 -06005308
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005309 s = zxc_num_parse(&r->d.n, str, G.prog.ib_t);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005310 if (s) {
5311 bc_num_free(&r->d.n);
5312 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005313 }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005314 *num = &r->d.n;
5315 r->t = XC_RESULT_TEMP;
5316 break;
5317 }
5318 case XC_RESULT_VAR:
5319 case XC_RESULT_ARRAY:
5320 case XC_RESULT_ARRAY_ELEM: {
Denys Vlasenko53799502019-01-25 14:24:03 +01005321 BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
5322 BcVec *v = xc_program_search(r->d.id.name, type);
5323 void *p = bc_vec_top(v);
5324
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005325 if (r->t == XC_RESULT_ARRAY_ELEM) {
Denys Vlasenko53799502019-01-25 14:24:03 +01005326 size_t idx = r->d.id.idx;
5327
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01005328 v = p;
Denys Vlasenko53799502019-01-25 14:24:03 +01005329 if (v->size == sizeof(uint8_t))
5330 v = xc_program_dereference(v);
5331 //assert(v->size == sizeof(BcNum));
5332 if (v->len <= idx)
5333 bc_array_expand(v, idx + 1);
5334 *num = bc_vec_item(v, idx);
Denys Vlasenko8ab209f2018-12-29 16:23:34 +01005335 } else {
5336 *num = p;
5337 }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005338 break;
5339 }
Denys Vlasenko503faf92018-12-20 16:24:18 +01005340#if ENABLE_BC
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005341 case BC_RESULT_LAST:
5342 *num = &G.prog.last;
5343 break;
5344 case BC_RESULT_ONE:
5345 *num = &G.prog.one;
5346 break;
Denys Vlasenko503faf92018-12-20 16:24:18 +01005347#endif
Denys Vlasenkoad0bd382018-12-24 00:50:32 +01005348#if SANITY_CHECKS
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01005349 default:
5350 // Testing the theory that dc does not reach LAST/ONE
5351 bb_error_msg_and_die("BUG:%d", r->t);
Denys Vlasenkoad0bd382018-12-24 00:50:32 +01005352#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005353 }
5354
Denys Vlasenko29301232018-12-11 15:29:32 +01005355 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06005356}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005357#define zxc_program_num(...) (zxc_program_num(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005358
Denys Vlasenko10bde142018-12-27 18:23:58 +01005359static BC_STATUS zxc_program_binOpPrep(BcResult **l, BcNum **ln,
Gavin Howard01055ba2018-11-03 11:00:21 -06005360 BcResult **r, BcNum **rn, bool assign)
5361{
5362 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06005363 BcResultType lt, rt;
5364
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01005365 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
Denys Vlasenko29301232018-12-11 15:29:32 +01005366 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06005367
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005368 *r = bc_vec_item_rev(&G.prog.results, 0);
5369 *l = bc_vec_item_rev(&G.prog.results, 1);
Gavin Howard01055ba2018-11-03 11:00:21 -06005370
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005371 s = zxc_program_num(*l, ln);
5372 if (s) RETURN_STATUS(s);
5373 s = zxc_program_num(*r, rn);
5374 if (s) RETURN_STATUS(s);
5375
Gavin Howard01055ba2018-11-03 11:00:21 -06005376 lt = (*l)->t;
5377 rt = (*r)->t;
Gavin Howard01055ba2018-11-03 11:00:21 -06005378
5379 // We run this again under these conditions in case any vector has been
5380 // reallocated out from under the BcNums or arrays we had.
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005381 if (lt == rt && (lt == XC_RESULT_VAR || lt == XC_RESULT_ARRAY_ELEM)) {
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005382 s = zxc_program_num(*l, ln);
Denys Vlasenko29301232018-12-11 15:29:32 +01005383 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005384 }
5385
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005386 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != XC_RESULT_VAR))
Denys Vlasenko29301232018-12-11 15:29:32 +01005387 RETURN_STATUS(bc_error_variable_is_wrong_type());
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005388 if (!assign && !BC_PROG_NUM((*r), (*ln)))
Denys Vlasenko29301232018-12-11 15:29:32 +01005389 RETURN_STATUS(bc_error_variable_is_wrong_type());
Gavin Howard01055ba2018-11-03 11:00:21 -06005390
Denys Vlasenko29301232018-12-11 15:29:32 +01005391 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005392}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005393#define zxc_program_binOpPrep(...) (zxc_program_binOpPrep(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005394
Denys Vlasenko10bde142018-12-27 18:23:58 +01005395static void xc_program_binOpRetire(BcResult *r)
Gavin Howard01055ba2018-11-03 11:00:21 -06005396{
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005397 r->t = XC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005398 bc_vec_pop(&G.prog.results);
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01005399 bc_result_pop_and_push(r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005400}
5401
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01005402// Note: *r and *n need not be initialized by caller
Denys Vlasenko10bde142018-12-27 18:23:58 +01005403static BC_STATUS zxc_program_prep(BcResult **r, BcNum **n)
Gavin Howard01055ba2018-11-03 11:00:21 -06005404{
5405 BcStatus s;
5406
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01005407 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenko29301232018-12-11 15:29:32 +01005408 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005409 *r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005410
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005411 s = zxc_program_num(*r, n);
Denys Vlasenko29301232018-12-11 15:29:32 +01005412 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005413
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005414 if (!BC_PROG_NUM((*r), (*n)))
Denys Vlasenko29301232018-12-11 15:29:32 +01005415 RETURN_STATUS(bc_error_variable_is_wrong_type());
Gavin Howard01055ba2018-11-03 11:00:21 -06005416
Denys Vlasenko29301232018-12-11 15:29:32 +01005417 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005418}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005419#define zxc_program_prep(...) (zxc_program_prep(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005420
Denys Vlasenko10bde142018-12-27 18:23:58 +01005421static void xc_program_retire(BcResult *r, BcResultType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005422{
5423 r->t = t;
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01005424 bc_result_pop_and_push(r);
Gavin Howard01055ba2018-11-03 11:00:21 -06005425}
5426
Denys Vlasenko10bde142018-12-27 18:23:58 +01005427static BC_STATUS zxc_program_op(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005428{
5429 BcStatus s;
5430 BcResult *opd1, *opd2, res;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01005431 BcNum *n1, *n2;
Gavin Howard01055ba2018-11-03 11:00:21 -06005432
Denys Vlasenko10bde142018-12-27 18:23:58 +01005433 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Denys Vlasenko259137d2018-12-11 19:42:05 +01005434 if (s) RETURN_STATUS(s);
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005435 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005436
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005437 s = BC_STATUS_SUCCESS;
Denys Vlasenko10bde142018-12-27 18:23:58 +01005438 IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - XC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06005439 if (s) goto err;
Denys Vlasenko10bde142018-12-27 18:23:58 +01005440 xc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005441
Denys Vlasenko259137d2018-12-11 19:42:05 +01005442 RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005443 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06005444 bc_num_free(&res.d.n);
Denys Vlasenko259137d2018-12-11 19:42:05 +01005445 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005446}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005447#define zxc_program_op(...) (zxc_program_op(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005448
Denys Vlasenko10bde142018-12-27 18:23:58 +01005449static BC_STATUS zxc_program_read(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005450{
5451 BcStatus s;
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005452 BcParse sv_parse;
Gavin Howard01055ba2018-11-03 11:00:21 -06005453 BcVec buf;
5454 BcInstPtr ip;
Denys Vlasenko69171dc2018-12-12 00:29:24 +01005455 BcFunc *f;
Gavin Howard01055ba2018-11-03 11:00:21 -06005456
Denys Vlasenko82ea67f2018-12-13 19:23:45 +01005457 bc_char_vec_init(&buf);
Denys Vlasenko10bde142018-12-27 18:23:58 +01005458 xc_read_line(&buf, stdin);
Gavin Howard01055ba2018-11-03 11:00:21 -06005459
Denys Vlasenko10bde142018-12-27 18:23:58 +01005460 f = xc_program_func(BC_PROG_READ);
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005461 bc_vec_pop_all(&f->code);
Gavin Howard01055ba2018-11-03 11:00:21 -06005462
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005463 sv_parse = G.prs; // struct copy
Denys Vlasenko10bde142018-12-27 18:23:58 +01005464 xc_parse_create(BC_PROG_READ);
Denys Vlasenko7d32e252018-12-26 18:32:43 +01005465 //G.err_line = G.prs.lex_line = 1; - not needed, error line info is not printed for read()
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005466
Denys Vlasenko10bde142018-12-27 18:23:58 +01005467 s = zxc_parse_text_init(buf.v);
Gavin Howard01055ba2018-11-03 11:00:21 -06005468 if (s) goto exec_err;
Denys Vlasenko514967d2018-12-22 03:38:52 +01005469 if (IS_BC) {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005470 IF_BC(s = zbc_parse_expr(0));
Denys Vlasenko514967d2018-12-22 03:38:52 +01005471 } else {
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01005472 IF_DC(s = zdc_parse_exprs_until_eof());
Denys Vlasenko514967d2018-12-22 03:38:52 +01005473 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005474 if (s) goto exec_err;
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01005475 if (G.prs.lex != XC_LEX_NLINE && G.prs.lex != XC_LEX_EOF) {
Denys Vlasenko22314682019-01-01 21:50:14 +01005476 s = bc_error_at("bad read() expression");
Gavin Howard01055ba2018-11-03 11:00:21 -06005477 goto exec_err;
5478 }
Denys Vlasenko2747f612018-12-31 18:48:10 +01005479 xc_parse_push(XC_INST_RET);
Gavin Howard01055ba2018-11-03 11:00:21 -06005480
5481 ip.func = BC_PROG_READ;
Denys Vlasenko24e41942018-12-21 23:01:26 +01005482 ip.inst_idx = 0;
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01005483 bc_vec_push(&G.prog.exestack, &ip);
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005484
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005485 exec_err:
Denys Vlasenko10bde142018-12-27 18:23:58 +01005486 xc_parse_free();
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01005487 G.prs = sv_parse; // struct copy
Gavin Howard01055ba2018-11-03 11:00:21 -06005488 bc_vec_free(&buf);
Denys Vlasenko26819db2018-12-12 16:08:46 +01005489 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005490}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005491#define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005492
Denys Vlasenko10bde142018-12-27 18:23:58 +01005493static void xc_program_printString(const char *str)
Gavin Howard01055ba2018-11-03 11:00:21 -06005494{
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005495#if ENABLE_DC
Denys Vlasenko266bec82019-01-02 05:03:53 +01005496 if (!str[0] && IS_DC) {
Denys Vlasenko2c6f5632018-12-11 21:21:14 +01005497 // Example: echo '[]ap' | dc
5498 // should print two bytes: 0x00, 0x0A
Denys Vlasenko00d77792018-11-30 23:13:42 +01005499 bb_putchar('\0');
Gavin Howard01055ba2018-11-03 11:00:21 -06005500 return;
5501 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005502#endif
Denys Vlasenko9f657e02018-12-11 19:52:25 +01005503 while (*str) {
Denys Vlasenko266bec82019-01-02 05:03:53 +01005504 char c = *str++;
5505 if (c == '\\') {
5506 static const char esc[] ALIGN1 = "nabfrt""e\\";
5507 char *n;
5508
Denys Vlasenko9f657e02018-12-11 19:52:25 +01005509 c = *str++;
Brian Foley10509a72019-09-05 10:53:21 +02005510 n = strchr(esc, c); // note: if c is NUL, n = \0 at end of esc
5511 if (!n || !c) {
Denys Vlasenko266bec82019-01-02 05:03:53 +01005512 // Just print the backslash and following character
Denys Vlasenko9f657e02018-12-11 19:52:25 +01005513 bb_putchar('\\');
5514 ++G.prog.nchars;
Brian Foley10509a72019-09-05 10:53:21 +02005515 // But if we're at the end of the string, stop
5516 if (!c) break;
Denys Vlasenko266bec82019-01-02 05:03:53 +01005517 } else {
5518 if (n - esc == 0) // "\n" ?
5519 G.prog.nchars = SIZE_MAX;
5520 c = "\n\a\b\f\r\t""\\\\""\\"[n - esc];
5521 // n a b f r t e \ \<end of line>
Gavin Howard01055ba2018-11-03 11:00:21 -06005522 }
5523 }
Denys Vlasenko266bec82019-01-02 05:03:53 +01005524 putchar(c);
Denys Vlasenko9f657e02018-12-11 19:52:25 +01005525 ++G.prog.nchars;
Gavin Howard01055ba2018-11-03 11:00:21 -06005526 }
5527}
5528
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005529static void bc_num_printNewline(void)
5530{
5531 if (G.prog.nchars == G.prog.len - 1) {
5532 bb_putchar('\\');
5533 bb_putchar('\n');
5534 G.prog.nchars = 0;
5535 }
5536}
5537
5538#if ENABLE_DC
Denys Vlasenkofa210792018-12-19 19:35:40 +01005539static FAST_FUNC void dc_num_printChar(size_t num, size_t width, bool radix)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005540{
5541 (void) radix;
5542 bb_putchar((char) num);
5543 G.prog.nchars += width;
5544}
5545#endif
5546
5547static FAST_FUNC void bc_num_printDigits(size_t num, size_t width, bool radix)
5548{
5549 size_t exp, pow;
5550
5551 bc_num_printNewline();
5552 bb_putchar(radix ? '.' : ' ');
5553 ++G.prog.nchars;
5554
5555 bc_num_printNewline();
5556 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
5557 continue;
5558
5559 for (exp = 0; exp < width; pow /= 10, ++G.prog.nchars, ++exp) {
5560 size_t dig;
5561 bc_num_printNewline();
5562 dig = num / pow;
5563 num -= dig * pow;
5564 bb_putchar(((char) dig) + '0');
5565 }
5566}
5567
5568static FAST_FUNC void bc_num_printHex(size_t num, size_t width, bool radix)
5569{
5570 if (radix) {
5571 bc_num_printNewline();
5572 bb_putchar('.');
Denys Vlasenko30a8e0c2018-12-18 19:20:04 +01005573 G.prog.nchars++;
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005574 }
5575
5576 bc_num_printNewline();
5577 bb_putchar(bb_hexdigits_upcase[num]);
5578 G.prog.nchars += width;
5579}
5580
5581static void bc_num_printDecimal(BcNum *n)
5582{
5583 size_t i, rdx = n->rdx - 1;
5584
Denys Vlasenko30a8e0c2018-12-18 19:20:04 +01005585 if (n->neg) {
5586 bb_putchar('-');
5587 G.prog.nchars++;
5588 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005589
5590 for (i = n->len - 1; i < n->len; --i)
5591 bc_num_printHex((size_t) n->num[i], 1, i == rdx);
5592}
5593
Denys Vlasenko2097ac82018-12-24 05:00:36 +01005594typedef void (*BcNumDigitOp)(size_t, size_t, bool) FAST_FUNC;
5595
Denys Vlasenko10bde142018-12-27 18:23:58 +01005596static BC_STATUS zxc_num_printNum(BcNum *n, unsigned base_t, size_t width, BcNumDigitOp print)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005597{
5598 BcStatus s;
5599 BcVec stack;
Denys Vlasenkod3401432018-12-18 17:00:35 +01005600 BcNum base;
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01005601 BcDig base_digs[ULONG_NUM_BUFSIZE];
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005602 BcNum intp, fracp, digit, frac_len;
5603 unsigned long dig, *ptr;
5604 size_t i;
5605 bool radix;
5606
5607 if (n->len == 0) {
5608 print(0, width, false);
5609 RETURN_STATUS(BC_STATUS_SUCCESS);
5610 }
5611
5612 bc_vec_init(&stack, sizeof(long), NULL);
5613 bc_num_init(&intp, n->len);
5614 bc_num_init(&fracp, n->rdx);
5615 bc_num_init(&digit, width);
5616 bc_num_init(&frac_len, BC_NUM_INT(n));
5617 bc_num_copy(&intp, n);
5618 bc_num_one(&frac_len);
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01005619 base.cap = ARRAY_SIZE(base_digs);
5620 base.num = base_digs;
Denys Vlasenkod3401432018-12-18 17:00:35 +01005621 bc_num_ulong2num(&base, base_t);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005622
5623 bc_num_truncate(&intp, intp.rdx);
5624 s = zbc_num_sub(n, &intp, &fracp, 0);
5625 if (s) goto err;
5626
5627 while (intp.len != 0) {
Denys Vlasenkod3401432018-12-18 17:00:35 +01005628 s = zbc_num_divmod(&intp, &base, &intp, &digit, 0);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005629 if (s) goto err;
5630 s = zbc_num_ulong(&digit, &dig);
5631 if (s) goto err;
5632 bc_vec_push(&stack, &dig);
5633 }
5634
5635 for (i = 0; i < stack.len; ++i) {
5636 ptr = bc_vec_item_rev(&stack, i);
5637 print(*ptr, width, false);
5638 }
5639
5640 if (!n->rdx) goto err;
5641
5642 for (radix = true; frac_len.len <= n->rdx; radix = false) {
Denys Vlasenkod3401432018-12-18 17:00:35 +01005643 s = zbc_num_mul(&fracp, &base, &fracp, n->rdx);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005644 if (s) goto err;
5645 s = zbc_num_ulong(&fracp, &dig);
5646 if (s) goto err;
5647 bc_num_ulong2num(&intp, dig);
5648 s = zbc_num_sub(&fracp, &intp, &fracp, 0);
5649 if (s) goto err;
5650 print(dig, width, radix);
Denys Vlasenkod3401432018-12-18 17:00:35 +01005651 s = zbc_num_mul(&frac_len, &base, &frac_len, 0);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005652 if (s) goto err;
5653 }
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005654 err:
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005655 bc_num_free(&frac_len);
5656 bc_num_free(&digit);
5657 bc_num_free(&fracp);
5658 bc_num_free(&intp);
5659 bc_vec_free(&stack);
5660 RETURN_STATUS(s);
5661}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005662#define zxc_num_printNum(...) (zxc_num_printNum(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005663
Denys Vlasenko10bde142018-12-27 18:23:58 +01005664static BC_STATUS zxc_num_printBase(BcNum *n)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005665{
5666 BcStatus s;
Denys Vlasenkod4258dd2018-12-18 13:22:23 +01005667 size_t width;
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005668 BcNumDigitOp print;
5669 bool neg = n->neg;
5670
5671 if (neg) {
5672 bb_putchar('-');
5673 G.prog.nchars++;
5674 }
5675
5676 n->neg = false;
5677
Denys Vlasenko680ccd32018-12-31 19:42:13 +01005678 if (G.prog.ob_t <= 16) {
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005679 width = 1;
5680 print = bc_num_printHex;
Denys Vlasenkof6e3f852018-12-17 21:05:09 +01005681 } else {
Denys Vlasenkod4258dd2018-12-18 13:22:23 +01005682 unsigned i = G.prog.ob_t - 1;
5683 width = 0;
5684 for (;;) {
5685 width++;
5686 i /= 10;
5687 if (i == 0)
5688 break;
5689 }
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005690 print = bc_num_printDigits;
5691 }
5692
Denys Vlasenko10bde142018-12-27 18:23:58 +01005693 s = zxc_num_printNum(n, G.prog.ob_t, width, print);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005694 n->neg = neg;
5695
5696 RETURN_STATUS(s);
5697}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005698#define zxc_num_printBase(...) (zxc_num_printBase(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005699
Denys Vlasenko10bde142018-12-27 18:23:58 +01005700static BC_STATUS zxc_num_print(BcNum *n, bool newline)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005701{
5702 BcStatus s = BC_STATUS_SUCCESS;
5703
5704 bc_num_printNewline();
5705
5706 if (n->len == 0) {
5707 bb_putchar('0');
5708 ++G.prog.nchars;
Denys Vlasenkof6e3f852018-12-17 21:05:09 +01005709 } else if (G.prog.ob_t == 10)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005710 bc_num_printDecimal(n);
5711 else
Denys Vlasenko10bde142018-12-27 18:23:58 +01005712 s = zxc_num_printBase(n);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005713
5714 if (newline) {
5715 bb_putchar('\n');
5716 G.prog.nchars = 0;
5717 }
5718
5719 RETURN_STATUS(s);
5720}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005721#define zxc_num_print(...) (zxc_num_print(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005722
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005723#if !ENABLE_DC
5724// for bc, idx is always 0
5725#define xc_program_print(inst, idx) \
5726 xc_program_print(inst)
5727#endif
5728static BC_STATUS xc_program_print(char inst, size_t idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06005729{
Denys Vlasenkofa35e592018-12-10 20:17:24 +01005730 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06005731 BcResult *r;
Denys Vlasenko44d79d82018-12-10 12:33:40 +01005732 BcNum *num;
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005733 IF_NOT_DC(size_t idx = 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06005734
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01005735 if (!STACK_HAS_MORE_THAN(&G.prog.results, idx))
Denys Vlasenko29301232018-12-11 15:29:32 +01005736 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06005737
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005738 r = bc_vec_item_rev(&G.prog.results, idx);
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005739#if ENABLE_BC
5740 if (inst == XC_INST_PRINT && r->t == BC_RESULT_VOID)
5741 // void function's result on stack, ignore
5742 RETURN_STATUS(BC_STATUS_SUCCESS);
5743#endif
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005744 s = zxc_program_num(r, &num);
Denys Vlasenko29301232018-12-11 15:29:32 +01005745 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005746
5747 if (BC_PROG_NUM(r, num)) {
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005748 s = zxc_num_print(num, /*newline:*/ inst == XC_INST_PRINT);
Denys Vlasenko503faf92018-12-20 16:24:18 +01005749#if ENABLE_BC
5750 if (!s && IS_BC) bc_num_copy(&G.prog.last, num);
5751#endif
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005752 } else {
Denys Vlasenko44d79d82018-12-10 12:33:40 +01005753 char *str;
Gavin Howard01055ba2018-11-03 11:00:21 -06005754
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005755 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenko10bde142018-12-27 18:23:58 +01005756 str = *xc_program_str(idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06005757
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005758 if (inst == XC_INST_PRINT_STR) {
Denys Vlasenko266bec82019-01-02 05:03:53 +01005759 char *nl;
5760 G.prog.nchars += printf("%s", str);
5761 nl = strrchr(str, '\n');
5762 if (nl)
5763 G.prog.nchars = strlen(nl + 1);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005764 } else {
Denys Vlasenko10bde142018-12-27 18:23:58 +01005765 xc_program_printString(str);
Denys Vlasenko266bec82019-01-02 05:03:53 +01005766 if (inst == XC_INST_PRINT)
5767 bb_putchar('\n');
Gavin Howard01055ba2018-11-03 11:00:21 -06005768 }
5769 }
5770
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005771 if (!s && inst != XC_INST_PRINT) bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005772
Denys Vlasenko29301232018-12-11 15:29:32 +01005773 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005774}
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005775#define zxc_program_print(...) (xc_program_print(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005776
Denys Vlasenko10bde142018-12-27 18:23:58 +01005777static BC_STATUS zxc_program_negate(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06005778{
5779 BcStatus s;
5780 BcResult res, *ptr;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01005781 BcNum *num;
Gavin Howard01055ba2018-11-03 11:00:21 -06005782
Denys Vlasenko10bde142018-12-27 18:23:58 +01005783 s = zxc_program_prep(&ptr, &num);
Denys Vlasenko29301232018-12-11 15:29:32 +01005784 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005785
5786 bc_num_init(&res.d.n, num->len);
5787 bc_num_copy(&res.d.n, num);
5788 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5789
Denys Vlasenko10bde142018-12-27 18:23:58 +01005790 xc_program_retire(&res, XC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06005791
Denys Vlasenko29301232018-12-11 15:29:32 +01005792 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005793}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005794#define zxc_program_negate(...) (zxc_program_negate(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005795
Denys Vlasenko10bde142018-12-27 18:23:58 +01005796static BC_STATUS zxc_program_logical(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005797{
5798 BcStatus s;
5799 BcResult *opd1, *opd2, res;
5800 BcNum *n1, *n2;
Denys Vlasenko16494f52018-12-12 00:50:23 +01005801 ssize_t cond;
Gavin Howard01055ba2018-11-03 11:00:21 -06005802
Denys Vlasenko10bde142018-12-27 18:23:58 +01005803 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Denys Vlasenko728e7c92018-12-11 19:37:00 +01005804 if (s) RETURN_STATUS(s);
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005805
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005806 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005807
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005808 if (inst == XC_INST_BOOL_AND)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005809 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005810 else if (inst == XC_INST_BOOL_OR)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005811 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
Gavin Howard01055ba2018-11-03 11:00:21 -06005812 else {
Denys Vlasenko16494f52018-12-12 00:50:23 +01005813 cond = bc_num_cmp(n1, n2);
Gavin Howard01055ba2018-11-03 11:00:21 -06005814 switch (inst) {
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005815 case XC_INST_REL_EQ:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005816 cond = (cond == 0);
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005817 break;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005818 case XC_INST_REL_LE:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005819 cond = (cond <= 0);
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005820 break;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005821 case XC_INST_REL_GE:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005822 cond = (cond >= 0);
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005823 break;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005824 case XC_INST_REL_LT:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005825 cond = (cond < 0);
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005826 break;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005827 case XC_INST_REL_GT:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005828 cond = (cond > 0);
5829 break;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01005830 default: // = case XC_INST_REL_NE:
Denys Vlasenko16494f52018-12-12 00:50:23 +01005831 //cond = (cond != 0); - not needed
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005832 break;
Gavin Howard01055ba2018-11-03 11:00:21 -06005833 }
5834 }
5835
Denys Vlasenko09d8df82018-12-11 19:29:35 +01005836 if (cond) bc_num_one(&res.d.n);
5837 //else bc_num_zero(&res.d.n); - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06005838
Denys Vlasenko10bde142018-12-27 18:23:58 +01005839 xc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005840
Denys Vlasenko728e7c92018-12-11 19:37:00 +01005841 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005842}
Denys Vlasenko10bde142018-12-27 18:23:58 +01005843#define zxc_program_logical(...) (zxc_program_logical(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005844
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005845#if ENABLE_DC
Denys Vlasenkofa210792018-12-19 19:35:40 +01005846static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push)
Gavin Howard01055ba2018-11-03 11:00:21 -06005847{
5848 BcNum n2;
5849 BcResult res;
5850
5851 memset(&n2, 0, sizeof(BcNum));
5852 n2.rdx = res.d.id.idx = r->d.id.idx;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005853 res.t = XC_RESULT_STR;
Gavin Howard01055ba2018-11-03 11:00:21 -06005854
5855 if (!push) {
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01005856 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
Denys Vlasenko29301232018-12-11 15:29:32 +01005857 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06005858 bc_vec_pop(v);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005859 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005860 }
5861
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01005862 bc_result_pop_and_push(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06005863 bc_vec_push(v, &n2);
5864
Denys Vlasenko29301232018-12-11 15:29:32 +01005865 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06005866}
Denys Vlasenkofa210792018-12-19 19:35:40 +01005867#define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005868#endif // ENABLE_DC
5869
Denys Vlasenko53799502019-01-25 14:24:03 +01005870static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t)
Gavin Howard01055ba2018-11-03 11:00:21 -06005871{
5872 BcStatus s;
5873 BcResult *ptr, r;
Denys Vlasenko53799502019-01-25 14:24:03 +01005874 BcVec *vec;
Gavin Howard01055ba2018-11-03 11:00:21 -06005875 BcNum *n;
Denys Vlasenko53799502019-01-25 14:24:03 +01005876 bool var = (t == BC_TYPE_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005877
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01005878 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenko29301232018-12-11 15:29:32 +01005879 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06005880
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005881 ptr = bc_vec_top(&G.prog.results);
Denys Vlasenko53799502019-01-25 14:24:03 +01005882 if ((ptr->t == XC_RESULT_ARRAY) == var)
Denys Vlasenko29301232018-12-11 15:29:32 +01005883 RETURN_STATUS(bc_error_variable_is_wrong_type());
Denys Vlasenko53799502019-01-25 14:24:03 +01005884 vec = xc_program_search(name, t);
Gavin Howard01055ba2018-11-03 11:00:21 -06005885
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005886#if ENABLE_DC
Denys Vlasenko53799502019-01-25 14:24:03 +01005887 if (ptr->t == XC_RESULT_STR) {
5888 if (!var)
5889 RETURN_STATUS(bc_error_variable_is_wrong_type());
5890 RETURN_STATUS(zdc_program_assignStr(ptr, vec, true));
5891 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005892#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005893
Denys Vlasenko374d2c42018-12-29 14:52:30 +01005894 s = zxc_program_num(ptr, &n);
Denys Vlasenko29301232018-12-11 15:29:32 +01005895 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005896
5897 // Do this once more to make sure that pointers were not invalidated.
Denys Vlasenko53799502019-01-25 14:24:03 +01005898 vec = xc_program_search(name, t);
Gavin Howard01055ba2018-11-03 11:00:21 -06005899
5900 if (var) {
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01005901 bc_num_init_DEF_SIZE(&r.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06005902 bc_num_copy(&r.d.n, n);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01005903 } else {
Denys Vlasenko53799502019-01-25 14:24:03 +01005904 BcVec *v = (BcVec*) n;
5905 bool ref, ref_size;
Gavin Howard01055ba2018-11-03 11:00:21 -06005906
Denys Vlasenko53799502019-01-25 14:24:03 +01005907 ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY);
5908 ref_size = (v->size == sizeof(uint8_t));
5909
5910 if (ref || (ref_size && t == BC_TYPE_REF)) {
5911 bc_vec_init(&r.d.v, sizeof(uint8_t), NULL);
5912 if (ref) {
5913 size_t vidx, idx;
5914 BcId id;
5915
5916 id.name = ptr->d.id.name;
5917 v = xc_program_search(ptr->d.id.name, BC_TYPE_REF);
5918
5919 // Make sure the pointer was not invalidated.
5920 vec = xc_program_search(name, t);
5921
5922 vidx = bc_map_find_exact(&G.prog.arr_map, &id);
5923 //assert(vidx != BC_VEC_INVALID_IDX);
5924 vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx;
5925 idx = v->len - 1;
5926
5927 bc_vec_pushIndex(&r.d.v, vidx);
5928 bc_vec_pushIndex(&r.d.v, idx);
5929 }
5930 // If we get here, we are copying a ref to a ref.
5931 else bc_vec_npush(&r.d.v, v->len, v->v);
5932
5933 // We need to return early.
5934 goto ret;
5935 }
5936
5937 if (ref_size && t != BC_TYPE_REF)
5938 v = xc_program_dereference(v);
5939
5940 bc_array_init(&r.d.v, true);
5941 bc_array_copy(&r.d.v, v);
5942 }
5943 ret:
5944 bc_vec_push(vec, &r.d);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01005945 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06005946
Denys Vlasenko29301232018-12-11 15:29:32 +01005947 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005948}
Denys Vlasenko02c3d7a2019-01-04 00:21:29 +01005949#define zxc_program_popResultAndCopyToVar(...) (zxc_program_popResultAndCopyToVar(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06005950
Denys Vlasenko10bde142018-12-27 18:23:58 +01005951static BC_STATUS zxc_program_assign(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06005952{
5953 BcStatus s;
5954 BcResult *left, *right, res;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01005955 BcNum *l, *r;
5956 bool assign = (inst == XC_INST_ASSIGN);
5957 bool ib, sc;
Gavin Howard01055ba2018-11-03 11:00:21 -06005958
Denys Vlasenko10bde142018-12-27 18:23:58 +01005959 s = zxc_program_binOpPrep(&left, &l, &right, &r, assign);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005960 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06005961
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005962 ib = left->t == XC_RESULT_IBASE;
5963 sc = left->t == XC_RESULT_SCALE;
Gavin Howard01055ba2018-11-03 11:00:21 -06005964
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005965#if ENABLE_DC
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005966 if (right->t == XC_RESULT_STR) {
Gavin Howard01055ba2018-11-03 11:00:21 -06005967 BcVec *v;
5968
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005969 if (left->t != XC_RESULT_VAR)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005970 RETURN_STATUS(bc_error_variable_is_wrong_type());
Denys Vlasenko53799502019-01-25 14:24:03 +01005971 v = xc_program_search(left->d.id.name, BC_TYPE_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06005972
Denys Vlasenkofa210792018-12-19 19:35:40 +01005973 RETURN_STATUS(zdc_program_assignStr(right, v, false));
Gavin Howard01055ba2018-11-03 11:00:21 -06005974 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005975#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005976
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005977 if (left->t == XC_RESULT_CONSTANT
5978 || left->t == XC_RESULT_TEMP
5979 IF_BC(|| left->t == BC_RESULT_VOID)
5980 ) {
Denys Vlasenko22314682019-01-01 21:50:14 +01005981 RETURN_STATUS(bc_error_bad_assignment());
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01005982 }
Gavin Howard01055ba2018-11-03 11:00:21 -06005983
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005984#if ENABLE_BC
Gavin Howard01055ba2018-11-03 11:00:21 -06005985 if (assign)
5986 bc_num_copy(l, r);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005987 else {
5988 s = BC_STATUS_SUCCESS;
Denys Vlasenko10bde142018-12-27 18:23:58 +01005989 IF_ERROR_RETURN_POSSIBLE(s =) zxc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01005990 }
5991 if (s) RETURN_STATUS(s);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005992#else
Gavin Howard01055ba2018-11-03 11:00:21 -06005993 bc_num_copy(l, r);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01005994#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06005995
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005996 if (ib || sc || left->t == XC_RESULT_OBASE) {
Denys Vlasenko60cf7472018-12-04 20:05:28 +01005997 static const char *const msg[] = {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01005998 "bad ibase; must be [2,16]", //XC_RESULT_IBASE
5999 "bad obase; must be [2,"BC_MAX_OBASE_STR"]", //XC_RESULT_OBASE
6000 "bad scale; must be [0,"BC_MAX_SCALE_STR"]", //XC_RESULT_SCALE
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006001 };
Gavin Howard01055ba2018-11-03 11:00:21 -06006002 size_t *ptr;
Denys Vlasenkof6e3f852018-12-17 21:05:09 +01006003 size_t max;
6004 unsigned long val;
Gavin Howard01055ba2018-11-03 11:00:21 -06006005
Denys Vlasenko29301232018-12-11 15:29:32 +01006006 s = zbc_num_ulong(l, &val);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006007 if (s) RETURN_STATUS(s);
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006008 s = left->t - XC_RESULT_IBASE;
Gavin Howard01055ba2018-11-03 11:00:21 -06006009 if (sc) {
6010 max = BC_MAX_SCALE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006011 ptr = &G.prog.scale;
Denys Vlasenkof6e3f852018-12-17 21:05:09 +01006012 } else {
6013 if (val < 2)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006014 RETURN_STATUS(bc_error(msg[s]));
Gavin Howard01055ba2018-11-03 11:00:21 -06006015 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006016 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006017 }
6018
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006019 if (val > max)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006020 RETURN_STATUS(bc_error(msg[s]));
Gavin Howard01055ba2018-11-03 11:00:21 -06006021
6022 *ptr = (size_t) val;
6023 s = BC_STATUS_SUCCESS;
6024 }
6025
6026 bc_num_init(&res.d.n, l->len);
6027 bc_num_copy(&res.d.n, l);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006028 xc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006029
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006030 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006031}
Denys Vlasenko10bde142018-12-27 18:23:58 +01006032#define zxc_program_assign(...) (zxc_program_assign(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006033
Denys Vlasenko416ce762018-12-02 20:57:17 +01006034#if !ENABLE_DC
Denys Vlasenko10bde142018-12-27 18:23:58 +01006035#define xc_program_pushVar(code, bgn, pop, copy) \
6036 xc_program_pushVar(code, bgn)
Denys Vlasenko416ce762018-12-02 20:57:17 +01006037// for bc, 'pop' and 'copy' are always false
6038#endif
Denys Vlasenko10bde142018-12-27 18:23:58 +01006039static BC_STATUS xc_program_pushVar(char *code, size_t *bgn,
Gavin Howard01055ba2018-11-03 11:00:21 -06006040 bool pop, bool copy)
6041{
Gavin Howard01055ba2018-11-03 11:00:21 -06006042 BcResult r;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006043 char *name = xc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06006044
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006045 r.t = XC_RESULT_VAR;
Gavin Howard01055ba2018-11-03 11:00:21 -06006046 r.d.id.name = name;
6047
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006048#if ENABLE_DC
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006049 if (pop || copy) {
Denys Vlasenko53799502019-01-25 14:24:03 +01006050 BcVec *v = xc_program_search(name, BC_TYPE_VAR);
Denys Vlasenko416ce762018-12-02 20:57:17 +01006051 BcNum *num = bc_vec_top(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006052
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006053 free(name);
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006054 if (!STACK_HAS_MORE_THAN(v, 1 - copy)) {
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006055 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06006056 }
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006057
6058 if (!BC_PROG_STR(num)) {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006059 r.t = XC_RESULT_TEMP;
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006060 bc_num_init_DEF_SIZE(&r.d.n);
6061 bc_num_copy(&r.d.n, num);
6062 } else {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006063 r.t = XC_RESULT_STR;
Denys Vlasenko7b30bc02018-12-18 17:14:34 +01006064 r.d.id.idx = num->rdx;
6065 }
6066
6067 if (!copy) bc_vec_pop(v);
Gavin Howard01055ba2018-11-03 11:00:21 -06006068 }
6069#endif // ENABLE_DC
6070
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006071 bc_vec_push(&G.prog.results, &r);
Gavin Howard01055ba2018-11-03 11:00:21 -06006072
Denys Vlasenkob402ff82018-12-11 15:45:15 +01006073 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06006074}
Denys Vlasenko10bde142018-12-27 18:23:58 +01006075#define zxc_program_pushVar(...) (xc_program_pushVar(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006076
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006077static BC_STATUS zbc_program_pushArray(char *code, size_t *bgn, char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006078{
6079 BcStatus s = BC_STATUS_SUCCESS;
6080 BcResult r;
6081 BcNum *num;
6082
Denys Vlasenko10bde142018-12-27 18:23:58 +01006083 r.d.id.name = xc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06006084
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01006085 if (inst == XC_INST_ARRAY) {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006086 r.t = XC_RESULT_ARRAY;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006087 bc_vec_push(&G.prog.results, &r);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006088 } else {
Gavin Howard01055ba2018-11-03 11:00:21 -06006089 BcResult *operand;
6090 unsigned long temp;
6091
Denys Vlasenko10bde142018-12-27 18:23:58 +01006092 s = zxc_program_prep(&operand, &num);
Gavin Howard01055ba2018-11-03 11:00:21 -06006093 if (s) goto err;
Denys Vlasenko29301232018-12-11 15:29:32 +01006094 s = zbc_num_ulong(num, &temp);
Gavin Howard01055ba2018-11-03 11:00:21 -06006095 if (s) goto err;
6096
6097 if (temp > BC_MAX_DIM) {
Denys Vlasenko64074a12018-12-07 15:50:14 +01006098 s = bc_error("array too long; must be [1,"BC_MAX_DIM_STR"]");
Gavin Howard01055ba2018-11-03 11:00:21 -06006099 goto err;
6100 }
6101
6102 r.d.id.idx = (size_t) temp;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006103 xc_program_retire(&r, XC_RESULT_ARRAY_ELEM);
Gavin Howard01055ba2018-11-03 11:00:21 -06006104 }
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006105 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06006106 if (s) free(r.d.id.name);
Denys Vlasenko29301232018-12-11 15:29:32 +01006107 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006108}
Denys Vlasenkoec603182018-12-17 10:34:02 +01006109#define zbc_program_pushArray(...) (zbc_program_pushArray(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006110
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006111#if ENABLE_BC
Denys Vlasenko29301232018-12-11 15:29:32 +01006112static BC_STATUS zbc_program_incdec(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006113{
6114 BcStatus s;
6115 BcResult *ptr, res, copy;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006116 BcNum *num;
Gavin Howard01055ba2018-11-03 11:00:21 -06006117 char inst2 = inst;
6118
Denys Vlasenko10bde142018-12-27 18:23:58 +01006119 s = zxc_program_prep(&ptr, &num);
Denys Vlasenko29301232018-12-11 15:29:32 +01006120 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006121
6122 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006123 copy.t = XC_RESULT_TEMP;
Gavin Howard01055ba2018-11-03 11:00:21 -06006124 bc_num_init(&copy.d.n, num->len);
6125 bc_num_copy(&copy.d.n, num);
6126 }
6127
6128 res.t = BC_RESULT_ONE;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006129 inst = (inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST)
6130 ? BC_INST_ASSIGN_PLUS
6131 : BC_INST_ASSIGN_MINUS;
Gavin Howard01055ba2018-11-03 11:00:21 -06006132
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006133 bc_vec_push(&G.prog.results, &res);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006134 s = zxc_program_assign(inst);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006135 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006136
6137 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01006138 bc_result_pop_and_push(&copy);
Gavin Howard01055ba2018-11-03 11:00:21 -06006139 }
6140
Denys Vlasenko29301232018-12-11 15:29:32 +01006141 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006142}
Denys Vlasenkoec603182018-12-17 10:34:02 +01006143#define zbc_program_incdec(...) (zbc_program_incdec(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006144
Denys Vlasenko29301232018-12-11 15:29:32 +01006145static BC_STATUS zbc_program_call(char *code, size_t *idx)
Gavin Howard01055ba2018-11-03 11:00:21 -06006146{
Gavin Howard01055ba2018-11-03 11:00:21 -06006147 BcInstPtr ip;
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006148 size_t i, nparams;
Gavin Howard01055ba2018-11-03 11:00:21 -06006149 BcId *a;
Denys Vlasenko19c3eb02019-01-04 00:05:07 +01006150 BcFunc *func;
Gavin Howard01055ba2018-11-03 11:00:21 -06006151
Denys Vlasenko10bde142018-12-27 18:23:58 +01006152 nparams = xc_program_index(code, idx);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006153 ip.func = xc_program_index(code, idx);
6154 func = xc_program_func(ip.func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006155
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006156 if (func->code.len == 0) {
Denys Vlasenko29301232018-12-11 15:29:32 +01006157 RETURN_STATUS(bc_error("undefined function"));
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006158 }
6159 if (nparams != func->nparams) {
Denys Vlasenko29301232018-12-11 15:29:32 +01006160 RETURN_STATUS(bc_error_fmt("function has %u parameters, but called with %u", func->nparams, nparams));
Denys Vlasenko04a1c762018-12-03 21:10:57 +01006161 }
Denys Vlasenko19c3eb02019-01-04 00:05:07 +01006162 ip.inst_idx = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06006163
6164 for (i = 0; i < nparams; ++i) {
Denys Vlasenko19c3eb02019-01-04 00:05:07 +01006165 BcResult *arg;
Denys Vlasenko628bf1b2018-12-10 20:41:05 +01006166 BcStatus s;
Denys Vlasenko53799502019-01-25 14:24:03 +01006167 bool arr;
Gavin Howard01055ba2018-11-03 11:00:21 -06006168
6169 a = bc_vec_item(&func->autos, nparams - 1 - i);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006170 arg = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006171
Denys Vlasenko53799502019-01-25 14:24:03 +01006172 arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF);
6173
6174 if (arr != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch
Denys Vlasenko19c3eb02019-01-04 00:05:07 +01006175 // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions)
6176 ) {
Denys Vlasenko29301232018-12-11 15:29:32 +01006177 RETURN_STATUS(bc_error_variable_is_wrong_type());
Denys Vlasenko19c3eb02019-01-04 00:05:07 +01006178 }
Denys Vlasenko53799502019-01-25 14:24:03 +01006179 s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx);
Denys Vlasenko29301232018-12-11 15:29:32 +01006180 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006181 }
6182
Denys Vlasenko87888ce2018-12-19 17:55:23 +01006183 a = bc_vec_item(&func->autos, i);
6184 for (; i < func->autos.len; i++, a++) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006185 BcVec *v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006186
Denys Vlasenko53799502019-01-25 14:24:03 +01006187 v = xc_program_search(a->name, (BcType) a->idx);
6188 if (a->idx == BC_TYPE_VAR) {
Denys Vlasenkof36a0ad2018-12-19 17:15:04 +01006189 BcNum n2;
6190 bc_num_init_DEF_SIZE(&n2);
6191 bc_vec_push(v, &n2);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006192 } else {
Denys Vlasenko53799502019-01-25 14:24:03 +01006193 //assert(a->idx == BC_TYPE_ARRAY);
Denys Vlasenkof36a0ad2018-12-19 17:15:04 +01006194 BcVec v2;
6195 bc_array_init(&v2, true);
6196 bc_vec_push(v, &v2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006197 }
6198 }
6199
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006200 bc_vec_push(&G.prog.exestack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006201
Denys Vlasenko29301232018-12-11 15:29:32 +01006202 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06006203}
Denys Vlasenkoec603182018-12-17 10:34:02 +01006204#define zbc_program_call(...) (zbc_program_call(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006205
Denys Vlasenko29301232018-12-11 15:29:32 +01006206static BC_STATUS zbc_program_return(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006207{
Gavin Howard01055ba2018-11-03 11:00:21 -06006208 BcResult res;
6209 BcFunc *f;
Denys Vlasenko87888ce2018-12-19 17:55:23 +01006210 BcId *a;
Gavin Howard01055ba2018-11-03 11:00:21 -06006211 size_t i;
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006212 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006213
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01006214 f = xc_program_func(ip->func);
6215
6216 res.t = XC_RESULT_TEMP;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01006217 if (inst == XC_INST_RET) {
Denys Vlasenko1db367a2019-01-04 06:18:00 +01006218 // bc needs this for e.g. RESULT_CONSTANT ("return 5")
6219 // because bc constants are per-function.
6220 // TODO: maybe avoid if value is already RESULT_TEMP?
Denys Vlasenko628bf1b2018-12-10 20:41:05 +01006221 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006222 BcNum *num;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006223 BcResult *operand = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006224
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006225 s = zxc_program_num(operand, &num);
Denys Vlasenko29301232018-12-11 15:29:32 +01006226 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006227 bc_num_init(&res.d.n, num->len);
6228 bc_num_copy(&res.d.n, num);
Denys Vlasenko377cc972019-01-04 00:34:52 +01006229 bc_vec_pop(&G.prog.results);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006230 } else {
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01006231 if (f->voidfunc)
6232 res.t = BC_RESULT_VOID;
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006233 bc_num_init_DEF_SIZE(&res.d.n);
Denys Vlasenko3129f702018-12-09 12:04:44 +01006234 //bc_num_zero(&res.d.n); - already is
Gavin Howard01055ba2018-11-03 11:00:21 -06006235 }
Denys Vlasenko02c3d7a2019-01-04 00:21:29 +01006236 bc_vec_push(&G.prog.results, &res);
6237
6238 bc_vec_pop(&G.prog.exestack);
Gavin Howard01055ba2018-11-03 11:00:21 -06006239
6240 // We need to pop arguments as well, so this takes that into account.
Denys Vlasenko87888ce2018-12-19 17:55:23 +01006241 a = (void*)f->autos.v;
6242 for (i = 0; i < f->autos.len; i++, a++) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006243 BcVec *v;
Denys Vlasenko53799502019-01-25 14:24:03 +01006244 v = xc_program_search(a->name, (BcType) a->idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006245 bc_vec_pop(v);
6246 }
6247
Denys Vlasenko29301232018-12-11 15:29:32 +01006248 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06006249}
Denys Vlasenkoec603182018-12-17 10:34:02 +01006250#define zbc_program_return(...) (zbc_program_return(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006251#endif // ENABLE_BC
6252
Denys Vlasenko10bde142018-12-27 18:23:58 +01006253static unsigned long xc_program_scale(BcNum *n)
Gavin Howard01055ba2018-11-03 11:00:21 -06006254{
6255 return (unsigned long) n->rdx;
6256}
6257
Denys Vlasenko10bde142018-12-27 18:23:58 +01006258static unsigned long xc_program_len(BcNum *n)
Gavin Howard01055ba2018-11-03 11:00:21 -06006259{
Denys Vlasenkoa7f1a362018-12-10 12:57:01 +01006260 size_t len = n->len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006261
Denys Vlasenkoace81cd2021-02-26 14:05:28 +01006262 if (n->rdx != len)
6263 // length(100): rdx 0 len 3, return 3
6264 // length(0.01-0.01): rdx 2 len 0, return 2
6265 // dc: 0.01 0.01 - Zp: rdx 2 len 0, return 1
6266 return len != 0 ? len : (IS_BC ? n->rdx : 1);
6267
6268 // length(0): return 1
6269 // length(0.000nnn): count nnn
Denys Vlasenkoa7f1a362018-12-10 12:57:01 +01006270 for (;;) {
6271 if (len == 0) break;
6272 len--;
6273 if (n->num[len] != 0) break;
6274 }
Denys Vlasenkoace81cd2021-02-26 14:05:28 +01006275 return len + 1;
Gavin Howard01055ba2018-11-03 11:00:21 -06006276}
6277
Denys Vlasenko10bde142018-12-27 18:23:58 +01006278static BC_STATUS zxc_program_builtin(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006279{
6280 BcStatus s;
6281 BcResult *opnd;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006282 BcNum *num;
Gavin Howard01055ba2018-11-03 11:00:21 -06006283 BcResult res;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006284 bool len = (inst == XC_INST_LENGTH);
Gavin Howard01055ba2018-11-03 11:00:21 -06006285
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006286 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006287 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006288 opnd = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006289
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006290 s = zxc_program_num(opnd, &num);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006291 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006292
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006293#if ENABLE_DC
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006294 if (!BC_PROG_NUM(opnd, num) && !len)
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006295 RETURN_STATUS(bc_error_variable_is_wrong_type());
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006296#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006297
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006298 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006299
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01006300 if (inst == XC_INST_SQRT)
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006301 s = zbc_num_sqrt(num, &res.d.n, G.prog.scale);
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006302#if ENABLE_BC
Denys Vlasenkoace81cd2021-02-26 14:05:28 +01006303 else if (len && opnd->t == XC_RESULT_ARRAY) {
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006304 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006305 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006306#endif
6307#if ENABLE_DC
Denys Vlasenkoace81cd2021-02-26 14:05:28 +01006308 else if (len && !BC_PROG_NUM(opnd, num)) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006309 char **str;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006310 size_t idx = opnd->t == XC_RESULT_STR ? opnd->d.id.idx : num->rdx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006311
Denys Vlasenko10bde142018-12-27 18:23:58 +01006312 str = xc_program_str(idx);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006313 bc_num_ulong2num(&res.d.n, strlen(*str));
Gavin Howard01055ba2018-11-03 11:00:21 -06006314 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006315#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06006316 else {
Denys Vlasenkoace81cd2021-02-26 14:05:28 +01006317//TODO: length(.00) and scale(.00) should return 2, they return 1 and 0 now
6318//(don't forget to check that dc Z and X commands do not break)
Denys Vlasenko10bde142018-12-27 18:23:58 +01006319 bc_num_ulong2num(&res.d.n, len ? xc_program_len(num) : xc_program_scale(num));
Gavin Howard01055ba2018-11-03 11:00:21 -06006320 }
6321
Denys Vlasenko10bde142018-12-27 18:23:58 +01006322 xc_program_retire(&res, XC_RESULT_TEMP);
Gavin Howard01055ba2018-11-03 11:00:21 -06006323
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006324 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006325}
Denys Vlasenko10bde142018-12-27 18:23:58 +01006326#define zxc_program_builtin(...) (zxc_program_builtin(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006327
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006328#if ENABLE_DC
Denys Vlasenkofa210792018-12-19 19:35:40 +01006329static BC_STATUS zdc_program_divmod(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006330{
6331 BcStatus s;
6332 BcResult *opd1, *opd2, res, res2;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006333 BcNum *n1, *n2;
Gavin Howard01055ba2018-11-03 11:00:21 -06006334
Denys Vlasenko10bde142018-12-27 18:23:58 +01006335 s = zxc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006336 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006337
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006338 bc_num_init_DEF_SIZE(&res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006339 bc_num_init(&res2.d.n, n2->len);
6340
Denys Vlasenko1aeacef2018-12-11 19:12:13 +01006341 s = zbc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
Gavin Howard01055ba2018-11-03 11:00:21 -06006342 if (s) goto err;
6343
Denys Vlasenko10bde142018-12-27 18:23:58 +01006344 xc_program_binOpRetire(&res2);
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006345 res.t = XC_RESULT_TEMP;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006346 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006347
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006348 RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006349 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06006350 bc_num_free(&res2.d.n);
6351 bc_num_free(&res.d.n);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006352 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006353}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006354#define zdc_program_divmod(...) (zdc_program_divmod(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006355
Denys Vlasenkofa210792018-12-19 19:35:40 +01006356static BC_STATUS zdc_program_modexp(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006357{
6358 BcStatus s;
6359 BcResult *r1, *r2, *r3, res;
6360 BcNum *n1, *n2, *n3;
6361
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006362 if (!STACK_HAS_MORE_THAN(&G.prog.results, 2))
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006363 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Denys Vlasenko10bde142018-12-27 18:23:58 +01006364 s = zxc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006365 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006366
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006367 r1 = bc_vec_item_rev(&G.prog.results, 2);
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006368 s = zxc_program_num(r1, &n1);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006369 if (s) RETURN_STATUS(s);
Denys Vlasenko60cf7472018-12-04 20:05:28 +01006370 if (!BC_PROG_NUM(r1, n1))
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006371 RETURN_STATUS(bc_error_variable_is_wrong_type());
Gavin Howard01055ba2018-11-03 11:00:21 -06006372
6373 // Make sure that the values have their pointers updated, if necessary.
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006374 if (r1->t == XC_RESULT_VAR || r1->t == XC_RESULT_ARRAY_ELEM) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006375 if (r1->t == r2->t) {
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006376 s = zxc_program_num(r2, &n2);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006377 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006378 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006379 if (r1->t == r3->t) {
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006380 s = zxc_program_num(r3, &n3);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006381 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006382 }
6383 }
6384
6385 bc_num_init(&res.d.n, n3->len);
Denys Vlasenkofa210792018-12-19 19:35:40 +01006386 s = zdc_num_modexp(n1, n2, n3, &res.d.n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006387 if (s) goto err;
6388
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006389 bc_vec_pop(&G.prog.results);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006390 xc_program_binOpRetire(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006391
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006392 RETURN_STATUS(s);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006393 err:
Gavin Howard01055ba2018-11-03 11:00:21 -06006394 bc_num_free(&res.d.n);
Denys Vlasenko7f4daa42018-12-11 19:04:44 +01006395 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006396}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006397#define zdc_program_modexp(...) (zdc_program_modexp(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006398
Denys Vlasenkofa210792018-12-19 19:35:40 +01006399static void dc_program_stackLen(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006400{
Gavin Howard01055ba2018-11-03 11:00:21 -06006401 BcResult res;
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006402 size_t len = G.prog.results.len;
Gavin Howard01055ba2018-11-03 11:00:21 -06006403
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006404 res.t = XC_RESULT_TEMP;
Gavin Howard01055ba2018-11-03 11:00:21 -06006405
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006406 bc_num_init_DEF_SIZE(&res.d.n);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006407 bc_num_ulong2num(&res.d.n, len);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006408 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006409}
6410
Denys Vlasenkofa210792018-12-19 19:35:40 +01006411static BC_STATUS zdc_program_asciify(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006412{
6413 BcStatus s;
6414 BcResult *r, res;
Denys Vlasenko4a024c72018-12-09 13:21:54 +01006415 BcNum *num, n;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006416 char **strs;
6417 char *str;
6418 char c;
6419 size_t idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006420
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006421 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenkoc008a732018-12-11 20:57:53 +01006422 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06006423
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01006424 r = bc_vec_top(&G.prog.results);
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006425 s = zxc_program_num(r, &num);
Denys Vlasenkoc008a732018-12-11 20:57:53 +01006426 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006427
6428 if (BC_PROG_NUM(r, num)) {
Denys Vlasenkoa9f59db2018-12-22 21:52:30 +01006429 unsigned long val;
Denys Vlasenkod3401432018-12-18 17:00:35 +01006430 BcNum strmb;
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01006431 BcDig strmb_digs[ULONG_NUM_BUFSIZE];
Denys Vlasenkod3401432018-12-18 17:00:35 +01006432
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006433 bc_num_init_DEF_SIZE(&n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006434 bc_num_copy(&n, num);
6435 bc_num_truncate(&n, n.rdx);
6436
Denys Vlasenkoe8e7bda2018-12-21 22:36:04 +01006437 strmb.cap = ARRAY_SIZE(strmb_digs);
6438 strmb.num = strmb_digs;
Denys Vlasenkod3401432018-12-18 17:00:35 +01006439 bc_num_ulong2num(&strmb, 0x100);
Denys Vlasenkod3401432018-12-18 17:00:35 +01006440
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01006441 s = zbc_num_mod(&n, &strmb, &n, 0);
Gavin Howard01055ba2018-11-03 11:00:21 -06006442 if (s) goto num_err;
Denys Vlasenko29301232018-12-11 15:29:32 +01006443 s = zbc_num_ulong(&n, &val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006444 if (s) goto num_err;
6445
6446 c = (char) val;
6447
6448 bc_num_free(&n);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006449 } else {
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006450 char *sp;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006451 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : num->rdx;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006452 sp = *xc_program_str(idx);
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006453 c = sp[0];
Gavin Howard01055ba2018-11-03 11:00:21 -06006454 }
6455
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006456 strs = (void*)G.prog.strs.v;
6457 for (idx = 0; idx < G.prog.strs.len; idx++) {
6458 if (strs[idx][0] == c && strs[idx][1] == '\0') {
6459 goto dup;
6460 }
6461 }
Denys Vlasenkofa35e592018-12-10 20:17:24 +01006462 str = xzalloc(2);
Gavin Howard01055ba2018-11-03 11:00:21 -06006463 str[0] = c;
Denys Vlasenkofa35e592018-12-10 20:17:24 +01006464 //str[1] = '\0'; - already is
Brian Foleyb64470b2019-09-05 10:50:13 +02006465 idx = bc_vec_push(&G.prog.strs, &str);
6466 // Add an empty function so that if zdc_program_execStr ever needs to
6467 // parse the string into code (from the 'x' command) there's somewhere
6468 // to store the bytecode.
6469 xc_program_add_fn();
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006470 dup:
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006471 res.t = XC_RESULT_STR;
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01006472 res.d.id.idx = idx;
Denys Vlasenko1dc4de92018-12-21 23:13:48 +01006473 bc_result_pop_and_push(&res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006474
Denys Vlasenkoc008a732018-12-11 20:57:53 +01006475 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006476 num_err:
Gavin Howard01055ba2018-11-03 11:00:21 -06006477 bc_num_free(&n);
Denys Vlasenkoc008a732018-12-11 20:57:53 +01006478 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006479}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006480#define zdc_program_asciify(...) (zdc_program_asciify(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006481
Denys Vlasenkofa210792018-12-19 19:35:40 +01006482static BC_STATUS zdc_program_printStream(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006483{
6484 BcStatus s;
6485 BcResult *r;
Denys Vlasenkofa210792018-12-19 19:35:40 +01006486 BcNum *n;
Gavin Howard01055ba2018-11-03 11:00:21 -06006487 size_t idx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006488
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006489 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenko29301232018-12-11 15:29:32 +01006490 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006491 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006492
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006493 s = zxc_program_num(r, &n);
Denys Vlasenko29301232018-12-11 15:29:32 +01006494 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006495
Denys Vlasenko57734c92018-12-17 21:14:05 +01006496 if (BC_PROG_NUM(r, n)) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006497 s = zxc_num_printNum(n, 0x100, 1, dc_num_printChar);
Denys Vlasenko57734c92018-12-17 21:14:05 +01006498 } else {
Denys Vlasenkofa210792018-12-19 19:35:40 +01006499 char *str;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006500 idx = (r->t == XC_RESULT_STR) ? r->d.id.idx : n->rdx;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006501 str = *xc_program_str(idx);
Ron Yorstoncad3fc72021-02-03 20:47:14 +01006502 fputs_stdout(str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006503 }
6504
Denys Vlasenko29301232018-12-11 15:29:32 +01006505 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006506}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006507#define zdc_program_printStream(...) (zdc_program_printStream(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006508
Denys Vlasenkofa210792018-12-19 19:35:40 +01006509static BC_STATUS zdc_program_nquit(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006510{
6511 BcStatus s;
6512 BcResult *opnd;
Denys Vlasenko65b6fe02018-12-24 17:15:34 +01006513 BcNum *num;
Gavin Howard01055ba2018-11-03 11:00:21 -06006514 unsigned long val;
6515
Denys Vlasenko10bde142018-12-27 18:23:58 +01006516 s = zxc_program_prep(&opnd, &num);
Denys Vlasenko29301232018-12-11 15:29:32 +01006517 if (s) RETURN_STATUS(s);
6518 s = zbc_num_ulong(num, &val);
6519 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006520
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006521 bc_vec_pop(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006522
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006523 if (G.prog.exestack.len < val)
Denys Vlasenko29301232018-12-11 15:29:32 +01006524 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006525 if (G.prog.exestack.len == val) {
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01006526 QUIT_OR_RETURN_TO_MAIN;
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01006527 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006528
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006529 bc_vec_npop(&G.prog.exestack, val);
Gavin Howard01055ba2018-11-03 11:00:21 -06006530
Denys Vlasenko29301232018-12-11 15:29:32 +01006531 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006532}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006533#define zdc_program_nquit(...) (zdc_program_nquit(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006534
Denys Vlasenkofa210792018-12-19 19:35:40 +01006535static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond)
Gavin Howard01055ba2018-11-03 11:00:21 -06006536{
6537 BcStatus s = BC_STATUS_SUCCESS;
6538 BcResult *r;
Gavin Howard01055ba2018-11-03 11:00:21 -06006539 BcFunc *f;
Gavin Howard01055ba2018-11-03 11:00:21 -06006540 BcInstPtr ip;
6541 size_t fidx, sidx;
Gavin Howard01055ba2018-11-03 11:00:21 -06006542
Denys Vlasenkodfe1dd22018-12-19 17:09:01 +01006543 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006544 RETURN_STATUS(bc_error_stack_has_too_few_elements());
Gavin Howard01055ba2018-11-03 11:00:21 -06006545
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006546 r = bc_vec_top(&G.prog.results);
Gavin Howard01055ba2018-11-03 11:00:21 -06006547
6548 if (cond) {
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006549 BcNum *n = n; // for compiler
6550 bool exec;
6551 char *name;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006552 char *then_name = xc_program_name(code, bgn);
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006553 char *else_name = NULL;
Gavin Howard01055ba2018-11-03 11:00:21 -06006554
Denys Vlasenkof706a182018-12-26 20:02:09 +01006555 if (code[*bgn] == '\0')
Gavin Howard01055ba2018-11-03 11:00:21 -06006556 (*bgn) += 1;
6557 else
Denys Vlasenko10bde142018-12-27 18:23:58 +01006558 else_name = xc_program_name(code, bgn);
Gavin Howard01055ba2018-11-03 11:00:21 -06006559
6560 exec = r->d.n.len != 0;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006561 name = then_name;
6562 if (!exec && else_name != NULL) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006563 exec = true;
6564 name = else_name;
6565 }
6566
6567 if (exec) {
Denys Vlasenkodf515392018-12-02 19:27:48 +01006568 BcVec *v;
Denys Vlasenko53799502019-01-25 14:24:03 +01006569 v = xc_program_search(name, BC_TYPE_VAR);
Gavin Howard01055ba2018-11-03 11:00:21 -06006570 n = bc_vec_top(v);
6571 }
6572
6573 free(then_name);
6574 free(else_name);
6575
6576 if (!exec) goto exit;
6577 if (!BC_PROG_STR(n)) {
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006578 s = bc_error_variable_is_wrong_type();
Gavin Howard01055ba2018-11-03 11:00:21 -06006579 goto exit;
6580 }
6581
6582 sidx = n->rdx;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006583 } else {
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006584 if (r->t == XC_RESULT_STR) {
Gavin Howard01055ba2018-11-03 11:00:21 -06006585 sidx = r->d.id.idx;
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006586 } else if (r->t == XC_RESULT_VAR) {
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006587 BcNum *n;
Denys Vlasenko374d2c42018-12-29 14:52:30 +01006588 s = zxc_program_num(r, &n);
Gavin Howard01055ba2018-11-03 11:00:21 -06006589 if (s || !BC_PROG_STR(n)) goto exit;
6590 sidx = n->rdx;
Denys Vlasenko5ec4b492018-12-09 02:54:06 +01006591 } else
Brian Foley74548792019-09-05 10:46:22 +02006592 goto exit_nopop;
Gavin Howard01055ba2018-11-03 11:00:21 -06006593 }
6594
6595 fidx = sidx + BC_PROG_REQ_FUNCS;
6596
Denys Vlasenko10bde142018-12-27 18:23:58 +01006597 f = xc_program_func(fidx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006598
6599 if (f->code.len == 0) {
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01006600 BcParse sv_parse;
Denys Vlasenkofa210792018-12-19 19:35:40 +01006601 char *str;
6602
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01006603 sv_parse = G.prs; // struct copy
Denys Vlasenko10bde142018-12-27 18:23:58 +01006604 xc_parse_create(fidx);
6605 str = *xc_program_str(sidx);
6606 s = zxc_parse_text_init(str);
Gavin Howard01055ba2018-11-03 11:00:21 -06006607 if (s) goto err;
Denys Vlasenkobadf6832018-12-22 18:04:08 +01006608
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01006609 s = zdc_parse_exprs_until_eof();
Gavin Howard01055ba2018-11-03 11:00:21 -06006610 if (s) goto err;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006611 xc_parse_push(DC_INST_POP_EXEC);
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01006612 if (G.prs.lex != XC_LEX_EOF)
Denys Vlasenko24fb2cd2018-12-05 16:03:46 +01006613 s = bc_error_bad_expression();
Denys Vlasenko10bde142018-12-27 18:23:58 +01006614 xc_parse_free();
Denys Vlasenko1fbe35a2018-12-25 19:38:13 +01006615 G.prs = sv_parse; // struct copy
6616 if (s) {
Denys Vlasenkofa210792018-12-19 19:35:40 +01006617 err:
Denys Vlasenkofa210792018-12-19 19:35:40 +01006618 bc_vec_pop_all(&f->code);
6619 goto exit;
Gavin Howard01055ba2018-11-03 11:00:21 -06006620 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006621 }
6622
Denys Vlasenko24e41942018-12-21 23:01:26 +01006623 ip.inst_idx = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06006624 ip.func = fidx;
6625
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006626 bc_vec_pop(&G.prog.results);
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006627 bc_vec_push(&G.prog.exestack, &ip);
Gavin Howard01055ba2018-11-03 11:00:21 -06006628
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006629 RETURN_STATUS(BC_STATUS_SUCCESS);
Denys Vlasenko7f2d59c2018-12-18 16:24:07 +01006630 exit:
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006631 bc_vec_pop(&G.prog.results);
Brian Foley74548792019-09-05 10:46:22 +02006632 exit_nopop:
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006633 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006634}
Denys Vlasenkofa210792018-12-19 19:35:40 +01006635#define zdc_program_execStr(...) (zdc_program_execStr(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006636#endif // ENABLE_DC
6637
Denys Vlasenko10bde142018-12-27 18:23:58 +01006638static void xc_program_pushGlobal(char inst)
Gavin Howard01055ba2018-11-03 11:00:21 -06006639{
Gavin Howard01055ba2018-11-03 11:00:21 -06006640 BcResult res;
6641 unsigned long val;
6642
Denys Vlasenkod897c9a2018-12-24 23:41:31 +01006643 res.t = inst - XC_INST_IBASE + XC_RESULT_IBASE;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01006644 if (inst == XC_INST_IBASE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006645 val = (unsigned long) G.prog.ib_t;
Denys Vlasenkoa7732d12018-12-24 04:26:07 +01006646 else if (inst == XC_INST_SCALE)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006647 val = (unsigned long) G.prog.scale;
Gavin Howard01055ba2018-11-03 11:00:21 -06006648 else
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006649 val = (unsigned long) G.prog.ob_t;
Gavin Howard01055ba2018-11-03 11:00:21 -06006650
Denys Vlasenkoe20e00d2018-12-09 11:44:20 +01006651 bc_num_init_DEF_SIZE(&res.d.n);
Denys Vlasenkoe3b4f232018-12-02 18:44:40 +01006652 bc_num_ulong2num(&res.d.n, val);
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01006653 bc_vec_push(&G.prog.results, &res);
Gavin Howard01055ba2018-11-03 11:00:21 -06006654}
6655
Denys Vlasenko10bde142018-12-27 18:23:58 +01006656static BC_STATUS zxc_program_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06006657{
Gavin Howard01055ba2018-11-03 11:00:21 -06006658 BcResult r, *ptr;
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006659 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006660 BcFunc *func = xc_program_func(ip->func);
Gavin Howard01055ba2018-11-03 11:00:21 -06006661 char *code = func->code.v;
Gavin Howard01055ba2018-11-03 11:00:21 -06006662
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01006663 dbg_exec("func:%zd bytes:%zd ip:%zd results.len:%d",
Denys Vlasenko24e41942018-12-21 23:01:26 +01006664 ip->func, func->code.len, ip->inst_idx, G.prog.results.len);
6665 while (ip->inst_idx < func->code.len) {
Denys Vlasenkofa35e592018-12-10 20:17:24 +01006666 BcStatus s = BC_STATUS_SUCCESS;
Denys Vlasenko24e41942018-12-21 23:01:26 +01006667 char inst = code[ip->inst_idx++];
Gavin Howard01055ba2018-11-03 11:00:21 -06006668
Denys Vlasenko24e41942018-12-21 23:01:26 +01006669 dbg_exec("inst at %zd:%d results.len:%d", ip->inst_idx - 1, inst, G.prog.results.len);
Gavin Howard01055ba2018-11-03 11:00:21 -06006670 switch (inst) {
Denys Vlasenko1db367a2019-01-04 06:18:00 +01006671 case XC_INST_RET:
6672 if (IS_DC) { // end of '?' reached
6673 bc_vec_pop(&G.prog.exestack);
6674 goto read_updated_ip;
6675 }
6676 // bc: fall through
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006677#if ENABLE_BC
Denys Vlasenko1db367a2019-01-04 06:18:00 +01006678 case BC_INST_RET0:
6679 dbg_exec("BC_INST_RET[0]:");
6680 s = zbc_program_return(inst);
6681 goto read_updated_ip;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006682 case BC_INST_JUMP_ZERO: {
6683 BcNum *num;
6684 bool zero;
6685 dbg_exec("BC_INST_JUMP_ZERO:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006686 s = zxc_program_prep(&ptr, &num);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006687 if (s) RETURN_STATUS(s);
6688 zero = (bc_num_cmp(num, &G.prog.zero) == 0);
6689 bc_vec_pop(&G.prog.results);
6690 if (!zero) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006691 xc_program_index(code, &ip->inst_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006692 break;
6693 }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006694 // else: fall through
6695 }
6696 case BC_INST_JUMP: {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006697 size_t idx = xc_program_index(code, &ip->inst_idx);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006698 size_t *addr = bc_vec_item(&func->labels, idx);
6699 dbg_exec("BC_INST_JUMP: to %ld", (long)*addr);
6700 ip->inst_idx = *addr;
6701 break;
6702 }
6703 case BC_INST_CALL:
6704 dbg_exec("BC_INST_CALL:");
6705 s = zbc_program_call(code, &ip->inst_idx);
6706 goto read_updated_ip;
6707 case BC_INST_INC_PRE:
6708 case BC_INST_DEC_PRE:
6709 case BC_INST_INC_POST:
6710 case BC_INST_DEC_POST:
6711 dbg_exec("BC_INST_INCDEC:");
6712 s = zbc_program_incdec(inst);
6713 break;
6714 case BC_INST_HALT:
6715 dbg_exec("BC_INST_HALT:");
6716 QUIT_OR_RETURN_TO_MAIN;
6717 break;
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006718 case XC_INST_BOOL_OR:
6719 case XC_INST_BOOL_AND:
Gavin Howard01055ba2018-11-03 11:00:21 -06006720#endif // ENABLE_BC
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006721 case XC_INST_REL_EQ:
6722 case XC_INST_REL_LE:
6723 case XC_INST_REL_GE:
6724 case XC_INST_REL_NE:
6725 case XC_INST_REL_LT:
6726 case XC_INST_REL_GT:
6727 dbg_exec("BC_INST_BOOL:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006728 s = zxc_program_logical(inst);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006729 break;
6730 case XC_INST_READ:
6731 dbg_exec("XC_INST_READ:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006732 s = zxc_program_read();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006733 goto read_updated_ip;
6734 case XC_INST_VAR:
6735 dbg_exec("XC_INST_VAR:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006736 s = zxc_program_pushVar(code, &ip->inst_idx, false, false);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006737 break;
6738 case XC_INST_ARRAY_ELEM:
6739 case XC_INST_ARRAY:
6740 dbg_exec("XC_INST_ARRAY[_ELEM]:");
6741 s = zbc_program_pushArray(code, &ip->inst_idx, inst);
6742 break;
Denys Vlasenkoad0bd382018-12-24 00:50:32 +01006743#if ENABLE_BC
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006744 case BC_INST_LAST:
6745 dbg_exec("BC_INST_LAST:");
6746 r.t = BC_RESULT_LAST;
6747 bc_vec_push(&G.prog.results, &r);
6748 break;
Denys Vlasenkoad0bd382018-12-24 00:50:32 +01006749#endif
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006750 case XC_INST_IBASE:
6751 case XC_INST_OBASE:
6752 case XC_INST_SCALE:
6753 dbg_exec("XC_INST_internalvar(%d):", inst - XC_INST_IBASE);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006754 xc_program_pushGlobal(inst);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006755 break;
6756 case XC_INST_SCALE_FUNC:
6757 case XC_INST_LENGTH:
6758 case XC_INST_SQRT:
6759 dbg_exec("BC_INST_builtin:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006760 s = zxc_program_builtin(inst);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006761 break;
6762 case XC_INST_NUM:
6763 dbg_exec("XC_INST_NUM:");
6764 r.t = XC_RESULT_CONSTANT;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006765 r.d.id.idx = xc_program_index(code, &ip->inst_idx);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006766 bc_vec_push(&G.prog.results, &r);
6767 break;
6768 case XC_INST_POP:
6769 dbg_exec("XC_INST_POP:");
6770 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6771 s = bc_error_stack_has_too_few_elements();
6772 else
6773 bc_vec_pop(&G.prog.results);
6774 break;
6775 case XC_INST_PRINT:
6776 case XC_INST_PRINT_POP:
6777 case XC_INST_PRINT_STR:
Denys Vlasenko54f5c1d2019-01-04 13:58:46 +01006778 dbg_exec("XC_INST_PRINTxyz(%d):", inst - XC_INST_PRINT);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006779 s = zxc_program_print(inst, 0);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006780 break;
6781 case XC_INST_STR:
6782 dbg_exec("XC_INST_STR:");
6783 r.t = XC_RESULT_STR;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006784 r.d.id.idx = xc_program_index(code, &ip->inst_idx);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006785 bc_vec_push(&G.prog.results, &r);
6786 break;
6787 case XC_INST_POWER:
6788 case XC_INST_MULTIPLY:
6789 case XC_INST_DIVIDE:
6790 case XC_INST_MODULUS:
6791 case XC_INST_PLUS:
6792 case XC_INST_MINUS:
6793 dbg_exec("BC_INST_binaryop:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006794 s = zxc_program_op(inst);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006795 break;
6796 case XC_INST_BOOL_NOT: {
6797 BcNum *num;
6798 dbg_exec("XC_INST_BOOL_NOT:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006799 s = zxc_program_prep(&ptr, &num);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006800 if (s) RETURN_STATUS(s);
6801 bc_num_init_DEF_SIZE(&r.d.n);
6802 if (bc_num_cmp(num, &G.prog.zero) == 0)
6803 bc_num_one(&r.d.n);
6804 //else bc_num_zero(&r.d.n); - already is
Denys Vlasenko10bde142018-12-27 18:23:58 +01006805 xc_program_retire(&r, XC_RESULT_TEMP);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006806 break;
6807 }
6808 case XC_INST_NEG:
6809 dbg_exec("XC_INST_NEG:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006810 s = zxc_program_negate();
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006811 break;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006812#if ENABLE_BC
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006813 case BC_INST_ASSIGN_POWER:
6814 case BC_INST_ASSIGN_MULTIPLY:
6815 case BC_INST_ASSIGN_DIVIDE:
6816 case BC_INST_ASSIGN_MODULUS:
6817 case BC_INST_ASSIGN_PLUS:
6818 case BC_INST_ASSIGN_MINUS:
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006819#endif
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006820 case XC_INST_ASSIGN:
6821 dbg_exec("BC_INST_ASSIGNxyz:");
Denys Vlasenko10bde142018-12-27 18:23:58 +01006822 s = zxc_program_assign(inst);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006823 break;
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01006824#if ENABLE_DC
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006825 case DC_INST_POP_EXEC:
6826 dbg_exec("DC_INST_POP_EXEC:");
6827 bc_vec_pop(&G.prog.exestack);
6828 goto read_updated_ip;
6829 case DC_INST_MODEXP:
6830 dbg_exec("DC_INST_MODEXP:");
6831 s = zdc_program_modexp();
6832 break;
6833 case DC_INST_DIVMOD:
6834 dbg_exec("DC_INST_DIVMOD:");
6835 s = zdc_program_divmod();
6836 break;
6837 case DC_INST_EXECUTE:
6838 case DC_INST_EXEC_COND:
6839 dbg_exec("DC_INST_EXEC[_COND]:");
6840 s = zdc_program_execStr(code, &ip->inst_idx, inst == DC_INST_EXEC_COND);
6841 goto read_updated_ip;
6842 case DC_INST_PRINT_STACK: {
6843 size_t idx;
6844 dbg_exec("DC_INST_PRINT_STACK:");
6845 for (idx = 0; idx < G.prog.results.len; ++idx) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006846 s = zxc_program_print(XC_INST_PRINT, idx);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006847 if (s) break;
Gavin Howard01055ba2018-11-03 11:00:21 -06006848 }
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006849 break;
6850 }
6851 case DC_INST_CLEAR_STACK:
6852 dbg_exec("DC_INST_CLEAR_STACK:");
6853 bc_vec_pop_all(&G.prog.results);
6854 break;
6855 case DC_INST_STACK_LEN:
6856 dbg_exec("DC_INST_STACK_LEN:");
6857 dc_program_stackLen();
6858 break;
6859 case DC_INST_DUPLICATE:
6860 dbg_exec("DC_INST_DUPLICATE:");
6861 if (!STACK_HAS_MORE_THAN(&G.prog.results, 0))
6862 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6863 ptr = bc_vec_top(&G.prog.results);
6864 dc_result_copy(&r, ptr);
6865 bc_vec_push(&G.prog.results, &r);
6866 break;
6867 case DC_INST_SWAP: {
6868 BcResult *ptr2;
6869 dbg_exec("DC_INST_SWAP:");
6870 if (!STACK_HAS_MORE_THAN(&G.prog.results, 1))
6871 RETURN_STATUS(bc_error_stack_has_too_few_elements());
6872 ptr = bc_vec_item_rev(&G.prog.results, 0);
6873 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6874 memcpy(&r, ptr, sizeof(BcResult));
6875 memcpy(ptr, ptr2, sizeof(BcResult));
6876 memcpy(ptr2, &r, sizeof(BcResult));
6877 break;
6878 }
6879 case DC_INST_ASCIIFY:
6880 dbg_exec("DC_INST_ASCIIFY:");
6881 s = zdc_program_asciify();
6882 break;
6883 case DC_INST_PRINT_STREAM:
6884 dbg_exec("DC_INST_PRINT_STREAM:");
6885 s = zdc_program_printStream();
6886 break;
6887 case DC_INST_LOAD:
6888 case DC_INST_PUSH_VAR: {
6889 bool copy = inst == DC_INST_LOAD;
Denys Vlasenko10bde142018-12-27 18:23:58 +01006890 s = zxc_program_pushVar(code, &ip->inst_idx, true, copy);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006891 break;
6892 }
6893 case DC_INST_PUSH_TO_VAR: {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006894 char *name = xc_program_name(code, &ip->inst_idx);
Denys Vlasenko53799502019-01-25 14:24:03 +01006895 s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006896 free(name);
6897 break;
6898 }
6899 case DC_INST_QUIT:
6900 dbg_exec("DC_INST_QUIT:");
6901 if (G.prog.exestack.len <= 2)
6902 QUIT_OR_RETURN_TO_MAIN;
6903 bc_vec_npop(&G.prog.exestack, 2);
6904 goto read_updated_ip;
6905 case DC_INST_NQUIT:
6906 dbg_exec("DC_INST_NQUIT:");
6907 s = zdc_program_nquit();
6908 //goto read_updated_ip; - just fall through to it
Gavin Howard01055ba2018-11-03 11:00:21 -06006909#endif // ENABLE_DC
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01006910 read_updated_ip:
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006911 // Instruction stack has changed, read new pointers
6912 ip = bc_vec_top(&G.prog.exestack);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006913 func = xc_program_func(ip->func);
Denys Vlasenko1c69ec12018-12-26 19:24:15 +01006914 code = func->code.v;
6915 dbg_exec("func:%zd bytes:%zd ip:%zd", ip->func, func->code.len, ip->inst_idx);
Gavin Howard01055ba2018-11-03 11:00:21 -06006916 }
6917
Denys Vlasenkod38af482018-12-04 19:11:02 +01006918 if (s || G_interrupt) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006919 xc_program_reset();
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006920 RETURN_STATUS(s);
Denys Vlasenkod38af482018-12-04 19:11:02 +01006921 }
Gavin Howard01055ba2018-11-03 11:00:21 -06006922
Denys Vlasenkoc5774a32018-12-17 01:22:53 +01006923 fflush_and_check();
Gavin Howard01055ba2018-11-03 11:00:21 -06006924 }
6925
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006926 RETURN_STATUS(BC_STATUS_SUCCESS);
Gavin Howard01055ba2018-11-03 11:00:21 -06006927}
Denys Vlasenko10bde142018-12-27 18:23:58 +01006928#define zxc_program_exec(...) (zxc_program_exec(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06006929
Denys Vlasenko10bde142018-12-27 18:23:58 +01006930static BC_STATUS zxc_vm_process(const char *text)
Gavin Howard01055ba2018-11-03 11:00:21 -06006931{
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01006932 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06006933
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01006934 dbg_lex_enter("%s:%d entered", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006935 s = zxc_parse_text_init(text); // does the first zxc_lex_next()
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01006936 if (s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06006937
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01006938 while (G.prs.lex != XC_LEX_EOF) {
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01006939 BcInstPtr *ip;
6940 BcFunc *f;
6941
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01006942 dbg_lex("%s:%d G.prs.lex:%d, parsing...", __func__, __LINE__, G.prs.lex);
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01006943 if (IS_BC) {
Denys Vlasenko26384542018-12-25 18:37:52 +01006944#if ENABLE_BC
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01006945 s = zbc_parse_stmt_or_funcdef();
Denys Vlasenko26384542018-12-25 18:37:52 +01006946 if (s) goto err;
6947
Denys Vlasenko53e569c2018-12-25 19:37:23 +01006948 // Check that next token is a correct stmt delimiter -
6949 // disallows "print 1 print 2" and such.
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01006950 if (G.prs.lex != BC_LEX_SCOLON
6951 && G.prs.lex != XC_LEX_NLINE
6952 && G.prs.lex != XC_LEX_EOF
Denys Vlasenko53e569c2018-12-25 19:37:23 +01006953 ) {
Denys Vlasenko22314682019-01-01 21:50:14 +01006954 bc_error_at("bad statement terminator");
Denys Vlasenko53e569c2018-12-25 19:37:23 +01006955 goto err;
Denys Vlasenko26384542018-12-25 18:37:52 +01006956 }
Denys Vlasenko53e569c2018-12-25 19:37:23 +01006957 // The above logic is fragile. Check these examples:
Denys Vlasenko10bde142018-12-27 18:23:58 +01006958 // - interactive read() still works
Denys Vlasenko26384542018-12-25 18:37:52 +01006959#endif
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01006960 } else {
Denys Vlasenko26384542018-12-25 18:37:52 +01006961#if ENABLE_DC
Denys Vlasenkoa2e62e32018-12-25 20:40:55 +01006962 s = zdc_parse_expr();
Denys Vlasenko26384542018-12-25 18:37:52 +01006963#endif
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01006964 }
6965 if (s || G_interrupt) {
Denys Vlasenko9471bd42018-12-23 00:13:15 +01006966 err:
Denys Vlasenko10bde142018-12-27 18:23:58 +01006967 xc_parse_reset(); // includes xc_program_reset()
Denys Vlasenko88fcd5c2018-12-22 06:00:25 +01006968 RETURN_STATUS(BC_STATUS_FAILURE);
6969 }
Denys Vlasenko53e569c2018-12-25 19:37:23 +01006970
Denys Vlasenko39287e02018-12-22 02:23:08 +01006971 dbg_lex("%s:%d executing...", __func__, __LINE__);
Denys Vlasenko10bde142018-12-27 18:23:58 +01006972 s = zxc_program_exec();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01006973 if (s) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01006974 xc_program_reset();
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01006975 break;
6976 }
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01006977
6978 ip = (void*)G.prog.exestack.v;
6979#if SANITY_CHECKS
6980 if (G.prog.exestack.len != 1) // should have only main's IP
James Byrne69374872019-07-02 11:35:03 +02006981 bb_simple_error_msg_and_die("BUG:call stack");
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01006982 if (ip->func != BC_PROG_MAIN)
James Byrne69374872019-07-02 11:35:03 +02006983 bb_simple_error_msg_and_die("BUG:not MAIN");
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01006984#endif
Denys Vlasenko10bde142018-12-27 18:23:58 +01006985 f = xc_program_func_BC_PROG_MAIN();
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01006986 // bc discards strings, constants and code after each
6987 // top-level statement in the "main program".
6988 // This prevents "yes 1 | bc" from growing its memory
6989 // without bound. This can be done because data stack
6990 // is empty and thus can't hold any references to
6991 // strings or constants, there is no generated code
6992 // which can hold references (after we discard one
6993 // we just executed). Code of functions can have references,
6994 // but bc stores function strings/constants in per-function
6995 // storage.
6996 if (IS_BC) {
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01006997#if SANITY_CHECKS
Denys Vlasenko7c1c9dc2018-12-22 14:18:47 +01006998 if (G.prog.results.len != 0) // should be empty
James Byrne69374872019-07-02 11:35:03 +02006999 bb_simple_error_msg_and_die("BUG:data stack");
Denys Vlasenko19eee8e2018-12-21 20:29:34 +01007000#endif
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01007001 IF_BC(bc_vec_pop_all(&f->strs);)
7002 IF_BC(bc_vec_pop_all(&f->consts);)
Denys Vlasenkofc7aa7a2019-01-08 18:08:48 +01007003 // We are at SCOLON/NLINE, skip it:
7004 s = zxc_lex_next();
7005 if (s) goto err;
Denys Vlasenkobadf6832018-12-22 18:04:08 +01007006 } else {
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01007007 if (G.prog.results.len == 0
7008 && G.prog.vars.len == 0
7009 ) {
7010 // If stack is empty and no registers exist (TODO: or they are all empty),
7011 // we can get rid of accumulated strings and constants.
7012 // In this example dc process should not grow
7013 // its memory consumption with time:
7014 // yes 1pc | dc
7015 IF_DC(bc_vec_pop_all(&G.prog.strs);)
7016 IF_DC(bc_vec_pop_all(&G.prog.consts);)
7017 }
7018 // The code is discarded always (below), thus this example
7019 // should also not grow its memory consumption with time,
7020 // even though its data stack is not empty:
7021 // { echo 1; yes dk; } | dc
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01007022 }
Denys Vlasenkoec74a9c2018-12-22 19:23:46 +01007023 // We drop generated and executed code for both bc and dc:
7024 bc_vec_pop_all(&f->code);
7025 ip->inst_idx = 0;
Gavin Howard01055ba2018-11-03 11:00:21 -06007026 }
Denys Vlasenko6842c602019-01-04 05:41:47 +01007027
Denys Vlasenko2ea53a42018-12-14 17:51:17 +01007028 dbg_lex_done("%s:%d done", __func__, __LINE__);
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01007029 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06007030}
Denys Vlasenko10bde142018-12-27 18:23:58 +01007031#define zxc_vm_process(...) (zxc_vm_process(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06007032
Denys Vlasenko10bde142018-12-27 18:23:58 +01007033static BC_STATUS zxc_vm_execute_FILE(FILE *fp, const char *filename)
Gavin Howard01055ba2018-11-03 11:00:21 -06007034{
Denys Vlasenko0fe270e2018-12-13 19:58:58 +01007035 // So far bc/dc have no way to include a file from another file,
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01007036 // therefore we know G.prs.lex_filename == NULL on entry
Denys Vlasenko0fe270e2018-12-13 19:58:58 +01007037 //const char *sv_file;
Denys Vlasenko0409ad32018-12-05 16:39:22 +01007038 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007039
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01007040 G.prs.lex_filename = filename;
7041 G.prs.lex_input_fp = fp;
Denys Vlasenko7d32e252018-12-26 18:32:43 +01007042 G.err_line = G.prs.lex_line = 1;
Denys Vlasenko22314682019-01-01 21:50:14 +01007043 dbg_lex("p->lex_line reset to 1");
Gavin Howard01055ba2018-11-03 11:00:21 -06007044
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007045 do {
Denys Vlasenko10bde142018-12-27 18:23:58 +01007046 s = zxc_vm_process("");
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007047 // We do not stop looping on errors here if reading stdin.
7048 // Example: start interactive bc and enter "return".
7049 // It should say "'return' not in a function"
7050 // but should not exit.
Denys Vlasenkoecb62ed2018-12-25 22:32:41 +01007051 } while (G.prs.lex_input_fp == stdin);
7052 G.prs.lex_filename = NULL;
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007053 RETURN_STATUS(s);
7054}
Denys Vlasenko10bde142018-12-27 18:23:58 +01007055#define zxc_vm_execute_FILE(...) (zxc_vm_execute_FILE(__VA_ARGS__) COMMA_SUCCESS)
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007056
Denys Vlasenko10bde142018-12-27 18:23:58 +01007057static BC_STATUS zxc_vm_file(const char *file)
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007058{
7059 BcStatus s;
7060 FILE *fp;
7061
7062 fp = xfopen_for_read(file);
Denys Vlasenko10bde142018-12-27 18:23:58 +01007063 s = zxc_vm_execute_FILE(fp, file);
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007064 fclose(fp);
7065
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01007066 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06007067}
Denys Vlasenko10bde142018-12-27 18:23:58 +01007068#define zxc_vm_file(...) (zxc_vm_file(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06007069
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007070#if ENABLE_BC
Denys Vlasenko57b69182018-12-14 00:12:13 +01007071static void bc_vm_info(void)
7072{
7073 printf("%s "BB_VER"\n"
Gavin Howardfa495ce2018-12-18 10:03:14 -07007074 "Adapted from https://github.com/gavinhoward/bc\n"
7075 "Original code (c) 2018 Gavin D. Howard and contributors\n"
Denys Vlasenko57b69182018-12-14 00:12:13 +01007076 , applet_name);
7077}
7078
7079static void bc_args(char **argv)
7080{
7081 unsigned opts;
7082 int i;
7083
7084 GETOPT_RESET();
7085#if ENABLE_FEATURE_BC_LONG_OPTIONS
7086 opts = option_mask32 |= getopt32long(argv, "wvsqli",
7087 "warn\0" No_argument "w"
7088 "version\0" No_argument "v"
7089 "standard\0" No_argument "s"
7090 "quiet\0" No_argument "q"
7091 "mathlib\0" No_argument "l"
7092 "interactive\0" No_argument "i"
7093 );
7094#else
7095 opts = option_mask32 |= getopt32(argv, "wvsqli");
7096#endif
7097 if (getenv("POSIXLY_CORRECT"))
7098 option_mask32 |= BC_FLAG_S;
7099
7100 if (opts & BC_FLAG_V) {
7101 bc_vm_info();
7102 exit(0);
7103 }
7104
7105 for (i = optind; argv[i]; ++i)
7106 bc_vec_push(&G.files, argv + i);
7107}
7108
7109static void bc_vm_envArgs(void)
7110{
7111 BcVec v;
7112 char *buf;
7113 char *env_args = getenv("BC_ENV_ARGS");
7114
7115 if (!env_args) return;
7116
7117 G.env_args = xstrdup(env_args);
7118 buf = G.env_args;
7119
7120 bc_vec_init(&v, sizeof(char *), NULL);
7121
7122 while (*(buf = skip_whitespace(buf)) != '\0') {
7123 bc_vec_push(&v, &buf);
7124 buf = skip_non_whitespace(buf);
7125 if (!*buf)
7126 break;
7127 *buf++ = '\0';
7128 }
7129
7130 // NULL terminate, and pass argv[] so that first arg is argv[1]
7131 if (sizeof(int) == sizeof(char*)) {
7132 bc_vec_push(&v, &const_int_0);
7133 } else {
7134 static char *const nullptr = NULL;
7135 bc_vec_push(&v, &nullptr);
7136 }
7137 bc_args(((char **)v.v) - 1);
7138
7139 bc_vec_free(&v);
7140}
7141
7142static const char bc_lib[] ALIGN1 = {
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007143 "scale=20"
7144"\n" "define e(x){"
7145"\n" "auto b,s,n,r,d,i,p,f,v"
Denys Vlasenko203210e2018-12-14 09:53:50 +01007146////////////////"if(x<0)return(1/e(-x))" // and drop 'n' and x<0 logic below
7147//^^^^^^^^^^^^^^^^ this would work, and is even more precise than GNU bc:
7148//e(-.998896): GNU:.36828580434569428695
7149// above code:.36828580434569428696
7150// actual value:.3682858043456942869594...
7151// but for now let's be "GNU compatible"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007152"\n" "b=ibase"
7153"\n" "ibase=A"
7154"\n" "if(x<0){"
7155"\n" "n=1"
7156"\n" "x=-x"
7157"\n" "}"
7158"\n" "s=scale"
Denys Vlasenko146a79d2018-12-16 21:46:11 +01007159"\n" "r=6+s+.44*x"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007160"\n" "scale=scale(x)+1"
7161"\n" "while(x>1){"
7162"\n" "d+=1"
7163"\n" "x/=2"
7164"\n" "scale+=1"
7165"\n" "}"
7166"\n" "scale=r"
7167"\n" "r=x+1"
7168"\n" "p=x"
7169"\n" "f=v=1"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007170"\n" "for(i=2;v;++i){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007171"\n" "p*=x"
7172"\n" "f*=i"
7173"\n" "v=p/f"
7174"\n" "r+=v"
7175"\n" "}"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007176"\n" "while(d--)r*=r"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007177"\n" "scale=s"
7178"\n" "ibase=b"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007179"\n" "if(n)return(1/r)"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007180"\n" "return(r/1)"
7181"\n" "}"
7182"\n" "define l(x){"
7183"\n" "auto b,s,r,p,a,q,i,v"
7184"\n" "b=ibase"
7185"\n" "ibase=A"
7186"\n" "if(x<=0){"
7187"\n" "r=(1-10^scale)/1"
7188"\n" "ibase=b"
7189"\n" "return(r)"
7190"\n" "}"
7191"\n" "s=scale"
7192"\n" "scale+=6"
7193"\n" "p=2"
7194"\n" "while(x>=2){"
7195"\n" "p*=2"
7196"\n" "x=sqrt(x)"
7197"\n" "}"
Denys Vlasenko146a79d2018-12-16 21:46:11 +01007198"\n" "while(x<=.5){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007199"\n" "p*=2"
7200"\n" "x=sqrt(x)"
7201"\n" "}"
7202"\n" "r=a=(x-1)/(x+1)"
7203"\n" "q=a*a"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007204"\n" "v=1"
7205"\n" "for(i=3;v;i+=2){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007206"\n" "a*=q"
7207"\n" "v=a/i"
7208"\n" "r+=v"
7209"\n" "}"
7210"\n" "r*=p"
7211"\n" "scale=s"
7212"\n" "ibase=b"
7213"\n" "return(r/1)"
7214"\n" "}"
7215"\n" "define s(x){"
Denys Vlasenko240d7ee2018-12-14 11:27:09 +01007216"\n" "auto b,s,r,a,q,i"
7217"\n" "if(x<0)return(-s(-x))"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007218"\n" "b=ibase"
7219"\n" "ibase=A"
7220"\n" "s=scale"
7221"\n" "scale=1.1*s+2"
7222"\n" "a=a(1)"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007223"\n" "scale=0"
7224"\n" "q=(x/a+2)/4"
Denys Vlasenko203210e2018-12-14 09:53:50 +01007225"\n" "x-=4*q*a"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007226"\n" "if(q%2)x=-x"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007227"\n" "scale=s+2"
7228"\n" "r=a=x"
7229"\n" "q=-x*x"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007230"\n" "for(i=3;a;i+=2){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007231"\n" "a*=q/(i*(i-1))"
7232"\n" "r+=a"
7233"\n" "}"
7234"\n" "scale=s"
7235"\n" "ibase=b"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007236"\n" "return(r/1)"
7237"\n" "}"
7238"\n" "define c(x){"
7239"\n" "auto b,s"
7240"\n" "b=ibase"
7241"\n" "ibase=A"
7242"\n" "s=scale"
7243"\n" "scale*=1.2"
7244"\n" "x=s(2*a(1)+x)"
7245"\n" "scale=s"
7246"\n" "ibase=b"
7247"\n" "return(x/1)"
7248"\n" "}"
7249"\n" "define a(x){"
7250"\n" "auto b,s,r,n,a,m,t,f,i,u"
7251"\n" "b=ibase"
7252"\n" "ibase=A"
7253"\n" "n=1"
7254"\n" "if(x<0){"
7255"\n" "n=-1"
7256"\n" "x=-x"
7257"\n" "}"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007258"\n" "if(scale<65){"
7259"\n" "if(x==1)return(.7853981633974483096156608458198757210492923498437764552437361480/n)"
7260"\n" "if(x==.2)return(.1973955598498807583700497651947902934475851037878521015176889402/n)"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007261"\n" "}"
7262"\n" "s=scale"
7263"\n" "if(x>.2){"
7264"\n" "scale+=5"
7265"\n" "a=a(.2)"
7266"\n" "}"
7267"\n" "scale=s+3"
7268"\n" "while(x>.2){"
7269"\n" "m+=1"
7270"\n" "x=(x-.2)/(1+.2*x)"
7271"\n" "}"
7272"\n" "r=u=x"
7273"\n" "f=-x*x"
7274"\n" "t=1"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007275"\n" "for(i=3;t;i+=2){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007276"\n" "u*=f"
7277"\n" "t=u/i"
7278"\n" "r+=t"
7279"\n" "}"
7280"\n" "scale=s"
7281"\n" "ibase=b"
7282"\n" "return((m*a+r)/n)"
7283"\n" "}"
7284"\n" "define j(n,x){"
7285"\n" "auto b,s,o,a,i,v,f"
7286"\n" "b=ibase"
7287"\n" "ibase=A"
7288"\n" "s=scale"
7289"\n" "scale=0"
7290"\n" "n/=1"
7291"\n" "if(n<0){"
7292"\n" "n=-n"
Denys Vlasenko203210e2018-12-14 09:53:50 +01007293"\n" "o=n%2"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007294"\n" "}"
7295"\n" "a=1"
7296"\n" "for(i=2;i<=n;++i)a*=i"
7297"\n" "scale=1.5*s"
7298"\n" "a=(x^n)/2^n/a"
7299"\n" "r=v=1"
7300"\n" "f=-x*x/4"
Denys Vlasenkoc06537d2018-12-14 10:10:37 +01007301"\n" "scale+=length(a)-scale(a)"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007302"\n" "for(i=1;v;++i){"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007303"\n" "v=v*f/i/(n+i)"
7304"\n" "r+=v"
7305"\n" "}"
7306"\n" "scale=s"
7307"\n" "ibase=b"
Denys Vlasenko3ac0c212018-12-14 01:01:01 +01007308"\n" "if(o)a=-a"
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007309"\n" "return(a*r/1)"
7310"\n" "}"
7311};
7312#endif // ENABLE_BC
7313
Denys Vlasenko10bde142018-12-27 18:23:58 +01007314static BC_STATUS zxc_vm_exec(void)
Gavin Howard01055ba2018-11-03 11:00:21 -06007315{
Denys Vlasenkoea5cad22018-12-19 18:09:31 +01007316 char **fname;
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007317 BcStatus s;
Gavin Howard01055ba2018-11-03 11:00:21 -06007318 size_t i;
7319
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007320#if ENABLE_BC
Denys Vlasenkod70d4a02018-12-04 20:58:40 +01007321 if (option_mask32 & BC_FLAG_L) {
Denys Vlasenko0ad36c42018-12-05 16:21:43 +01007322 // We know that internal library is not buggy,
7323 // thus error checking is normally disabled.
7324# define DEBUG_LIB 0
Denys Vlasenko10bde142018-12-27 18:23:58 +01007325 s = zxc_vm_process(bc_lib);
Denys Vlasenko19f11072018-12-12 22:48:19 +01007326 if (DEBUG_LIB && s) RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06007327 }
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007328#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007329
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007330 s = BC_STATUS_SUCCESS;
Denys Vlasenkoea5cad22018-12-19 18:09:31 +01007331 fname = (void*)G.files.v;
7332 for (i = 0; i < G.files.len; i++) {
Denys Vlasenko10bde142018-12-27 18:23:58 +01007333 s = zxc_vm_file(*fname++);
Denys Vlasenkoea5cad22018-12-19 18:09:31 +01007334 if (ENABLE_FEATURE_CLEAN_UP && !G_ttyin && s) {
7335 // Debug config, non-interactive mode:
7336 // return all the way back to main.
7337 // Non-debug builds do not come here
7338 // in non-interactive mode, they exit.
7339 RETURN_STATUS(s);
7340 }
Denys Vlasenko9b70f192018-12-04 20:51:40 +01007341 }
Gavin Howard01055ba2018-11-03 11:00:21 -06007342
Denys Vlasenko91cde952018-12-10 20:56:08 +01007343 if (IS_BC || (option_mask32 & BC_FLAG_I))
Denys Vlasenko10bde142018-12-27 18:23:58 +01007344 s = zxc_vm_execute_FILE(stdin, /*filename:*/ NULL);
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007345
Denys Vlasenko19f11072018-12-12 22:48:19 +01007346 RETURN_STATUS(s);
Gavin Howard01055ba2018-11-03 11:00:21 -06007347}
Denys Vlasenko10bde142018-12-27 18:23:58 +01007348#define zxc_vm_exec(...) (zxc_vm_exec(__VA_ARGS__) COMMA_SUCCESS)
Gavin Howard01055ba2018-11-03 11:00:21 -06007349
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007350#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenko10bde142018-12-27 18:23:58 +01007351static void xc_program_free(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007352{
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007353 bc_vec_free(&G.prog.fns);
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007354 IF_BC(bc_vec_free(&G.prog.fn_map);)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007355 bc_vec_free(&G.prog.vars);
7356 bc_vec_free(&G.prog.var_map);
7357 bc_vec_free(&G.prog.arrs);
7358 bc_vec_free(&G.prog.arr_map);
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01007359 IF_DC(bc_vec_free(&G.prog.strs);)
7360 IF_DC(bc_vec_free(&G.prog.consts);)
Denys Vlasenkoa1d3ca22018-12-02 18:26:38 +01007361 bc_vec_free(&G.prog.results);
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01007362 bc_vec_free(&G.prog.exestack);
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007363 IF_BC(bc_num_free(&G.prog.last);)
Denys Vlasenkodb8d6072018-12-27 18:08:30 +01007364 //IF_BC(bc_num_free(&G.prog.zero);)
Denys Vlasenko503faf92018-12-20 16:24:18 +01007365 IF_BC(bc_num_free(&G.prog.one);)
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007366 bc_vec_free(&G.input_buffer);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007367}
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007368#endif
7369
Denys Vlasenko10bde142018-12-27 18:23:58 +01007370static void xc_program_init(void)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007371{
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007372 BcInstPtr ip;
7373
Denys Vlasenko82269122018-12-14 16:30:56 +01007374 // memset(&G.prog, 0, sizeof(G.prog)); - already is
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007375 memset(&ip, 0, sizeof(BcInstPtr));
7376
Denys Vlasenko82269122018-12-14 16:30:56 +01007377 // G.prog.nchars = G.prog.scale = 0; - already is
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007378 G.prog.ib_t = 10;
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007379 G.prog.ob_t = 10;
7380
Denys Vlasenko503faf92018-12-20 16:24:18 +01007381 IF_BC(bc_num_init_DEF_SIZE(&G.prog.last);)
7382 //IF_BC(bc_num_zero(&G.prog.last);) - already is
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007383
Denys Vlasenkodb8d6072018-12-27 18:08:30 +01007384 //bc_num_init_DEF_SIZE(&G.prog.zero); - not needed
Denys Vlasenko3129f702018-12-09 12:04:44 +01007385 //bc_num_zero(&G.prog.zero); - already is
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007386
Denys Vlasenko503faf92018-12-20 16:24:18 +01007387 IF_BC(bc_num_init_DEF_SIZE(&G.prog.one);)
7388 IF_BC(bc_num_one(&G.prog.one);)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007389
7390 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007391 IF_BC(bc_vec_init(&G.prog.fn_map, sizeof(BcId), bc_id_free);)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007392
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007393 if (IS_BC) {
Denys Vlasenko8c1e7232018-12-22 01:34:10 +01007394 // Names are chosen simply to be distinct and never match
Denys Vlasenko04715442018-12-21 00:10:26 +01007395 // a valid function name (and be short)
7396 IF_BC(bc_program_addFunc(xstrdup(""))); // func #0: main
Denys Vlasenko8c1e7232018-12-22 01:34:10 +01007397 IF_BC(bc_program_addFunc(xstrdup("1"))); // func #1: for read()
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007398 } else {
Denys Vlasenko8c1e7232018-12-22 01:34:10 +01007399 // in dc, functions have no names
Denys Vlasenko10bde142018-12-27 18:23:58 +01007400 xc_program_add_fn();
7401 xc_program_add_fn();
Denys Vlasenko44a99ca2018-12-20 20:34:09 +01007402 }
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007403
7404 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007405 bc_vec_init(&G.prog.var_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007406
7407 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
Denys Vlasenkocb9a99f2018-12-04 21:54:33 +01007408 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007409
Denys Vlasenko5d57bc42018-12-21 16:22:26 +01007410 IF_DC(bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);)
7411 IF_DC(bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);)
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007412 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
Denys Vlasenkob80d7aa2018-12-19 12:35:27 +01007413 bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL);
7414 bc_vec_push(&G.prog.exestack, &ip);
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01007415
Denys Vlasenkoe4ba4c42018-12-17 09:51:43 +01007416 bc_char_vec_init(&G.input_buffer);
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007417}
Gavin Howard01055ba2018-11-03 11:00:21 -06007418
Denys Vlasenko00eb23b2020-12-21 21:36:58 +01007419static unsigned xc_vm_envLen(const char *var)
7420{
7421 char *lenv;
7422 unsigned len;
7423
7424 lenv = getenv(var);
7425 len = BC_NUM_PRINT_WIDTH;
Denys Vlasenko29a90432020-12-29 18:50:56 +01007426 if (lenv) {
7427 len = bb_strtou(lenv, NULL, 10);
7428 if (len == 0 || len > INT_MAX)
7429 len = INT_MAX;
7430 if (errno)
7431 len = BC_NUM_PRINT_WIDTH;
7432 }
Denys Vlasenko00eb23b2020-12-21 21:36:58 +01007433
Denys Vlasenko29a90432020-12-29 18:50:56 +01007434 // dc (GNU bc 1.07.1) 1.4.1 seems to use width
7435 // 1 char wider than bc from the same package.
7436 // Both default width, and xC_LINE_LENGTH=N are wider:
7437 // "DC_LINE_LENGTH=5 dc -e'123456 p'" prints:
7438 // |1234\ |
7439 // |56 |
7440 // "echo '123456' | BC_LINE_LENGTH=5 bc" prints:
7441 // |123\ |
7442 // |456 |
7443 // Do the same, but it might be a bug in GNU package
7444 if (IS_BC)
7445 len--;
7446
7447 if (len < 2)
7448 len = IS_BC ? BC_NUM_PRINT_WIDTH - 1 : BC_NUM_PRINT_WIDTH;
Denys Vlasenko00eb23b2020-12-21 21:36:58 +01007449
7450 return len;
7451}
7452
Denys Vlasenko10bde142018-12-27 18:23:58 +01007453static int xc_vm_init(const char *env_len)
Gavin Howard01055ba2018-11-03 11:00:21 -06007454{
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01007455 G.prog.len = xc_vm_envLen(env_len);
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007456 bc_vec_init(&G.files, sizeof(char *), NULL);
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01007457
Denys Vlasenko10bde142018-12-27 18:23:58 +01007458 xc_program_init();
Denys Vlasenko5f263f42018-12-13 22:49:59 +01007459 IF_BC(if (IS_BC) bc_vm_envArgs();)
Denys Vlasenko10bde142018-12-27 18:23:58 +01007460 xc_parse_create(BC_PROG_MAIN);
Gavin Howard01055ba2018-11-03 11:00:21 -06007461
Denys Vlasenko89e785a2018-12-13 16:35:52 +01007462//TODO: in GNU bc, the check is (isatty(0) && isatty(1)),
7463//-i option unconditionally enables this regardless of isatty():
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007464 if (isatty(0)) {
Denys Vlasenko14767602018-12-27 22:52:13 +01007465#if ENABLE_FEATURE_BC_INTERACTIVE
Denys Vlasenko1a6a4822018-12-06 09:20:32 +01007466 G_ttyin = 1;
Denys Vlasenko17c54722018-12-04 21:21:32 +01007467 // With SA_RESTART, most system calls will restart
7468 // (IOW: they won't fail with EINTR).
7469 // In particular, this means ^C won't cause
7470 // stdout to get into "error state" if SIGINT hits
7471 // within write() syscall.
Denys Vlasenko89e785a2018-12-13 16:35:52 +01007472 //
7473 // The downside is that ^C while tty input is taken
Denys Vlasenko17c54722018-12-04 21:21:32 +01007474 // will only be handled after [Enter] since read()
7475 // from stdin is not interrupted by ^C either,
7476 // it restarts, thus fgetc() does not return on ^C.
Denys Vlasenko89e785a2018-12-13 16:35:52 +01007477 // (This problem manifests only if line editing is disabled)
Denys Vlasenko17c54722018-12-04 21:21:32 +01007478 signal_SA_RESTART_empty_mask(SIGINT, record_signo);
7479
7480 // Without SA_RESTART, this exhibits a bug:
7481 // "while (1) print 1" and try ^C-ing it.
7482 // Intermittently, instead of returning to input line,
7483 // you'll get "output error: Interrupted system call"
7484 // and exit.
7485 //signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
Denys Vlasenkod38af482018-12-04 19:11:02 +01007486#endif
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007487 return 1; // "tty"
Denys Vlasenkod38af482018-12-04 19:11:02 +01007488 }
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007489 return 0; // "not a tty"
7490}
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007491
Denys Vlasenko10bde142018-12-27 18:23:58 +01007492static BcStatus xc_vm_run(void)
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007493{
Denys Vlasenko10bde142018-12-27 18:23:58 +01007494 BcStatus st = zxc_vm_exec();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007495#if ENABLE_FEATURE_CLEAN_UP
Denys Vlasenkoc7a7ce02018-12-06 23:06:57 +01007496 if (G_exiting) // it was actually "halt" or "quit"
7497 st = EXIT_SUCCESS;
Denys Vlasenko2cd8c042018-12-30 15:56:36 +01007498
7499 bc_vec_free(&G.files);
7500 xc_program_free();
7501 xc_parse_free();
7502 free(G.env_args);
Denys Vlasenko95f93bd2018-12-06 10:29:12 +01007503# if ENABLE_FEATURE_EDITING
7504 free_line_input_t(G.line_input_state);
7505# endif
Denys Vlasenkoe873ff92018-12-06 00:29:22 +01007506 FREE_G();
Denys Vlasenko785e4b32018-12-02 17:18:52 +01007507#endif
Denys Vlasenkod1d29b42018-12-16 16:03:03 +01007508 dbg_exec("exiting with exitcode %d", st);
Gavin Howard01055ba2018-11-03 11:00:21 -06007509 return st;
7510}
7511
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007512#if ENABLE_BC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007513int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007514int bc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007515{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007516 int is_tty;
7517
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007518 INIT_G();
Gavin Howard01055ba2018-11-03 11:00:21 -06007519
Denys Vlasenko10bde142018-12-27 18:23:58 +01007520 is_tty = xc_vm_init("BC_LINE_LENGTH");
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007521
7522 bc_args(argv);
7523
7524 if (is_tty && !(option_mask32 & BC_FLAG_Q))
7525 bc_vm_info();
7526
Denys Vlasenko10bde142018-12-27 18:23:58 +01007527 return xc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007528}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007529#endif
Gavin Howard01055ba2018-11-03 11:00:21 -06007530
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007531#if ENABLE_DC
Denys Vlasenko5a9fef52018-12-02 14:35:32 +01007532int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denys Vlasenko1ff1c702018-12-06 00:46:09 +01007533int dc_main(int argc UNUSED_PARAM, char **argv)
Gavin Howard01055ba2018-11-03 11:00:21 -06007534{
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007535 int noscript;
7536
Denys Vlasenko6d9146a2018-12-02 15:48:37 +01007537 INIT_G();
Denys Vlasenko82269122018-12-14 16:30:56 +01007538
Denys Vlasenko10bde142018-12-27 18:23:58 +01007539 xc_vm_init("DC_LINE_LENGTH");
Gavin Howard01055ba2018-11-03 11:00:21 -06007540
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007541 // Run -e'SCRIPT' and -fFILE in order of appearance, then handle FILEs
7542 noscript = BC_FLAG_I;
7543 for (;;) {
7544 int n = getopt(argc, argv, "e:f:x");
7545 if (n <= 0)
7546 break;
7547 switch (n) {
7548 case 'e':
7549 noscript = 0;
Denys Vlasenko10bde142018-12-27 18:23:58 +01007550 n = zxc_vm_process(optarg);
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007551 if (n) return n;
7552 break;
7553 case 'f':
7554 noscript = 0;
Denys Vlasenko10bde142018-12-27 18:23:58 +01007555 n = zxc_vm_file(optarg);
Denys Vlasenkod6ad3662018-12-12 21:39:10 +01007556 if (n) return n;
Denys Vlasenko6d0be102018-12-06 18:41:59 +01007557 break;
7558 case 'x':
7559 option_mask32 |= DC_FLAG_X;
7560 break;
7561 default:
7562 bb_show_usage();
7563 }
7564 }
7565 argv += optind;
7566
7567 while (*argv) {
7568 noscript = 0;
7569 bc_vec_push(&G.files, argv++);
7570 }
7571
7572 option_mask32 |= noscript; // set BC_FLAG_I if we need to interpret stdin
7573
Denys Vlasenko10bde142018-12-27 18:23:58 +01007574 return xc_vm_run();
Gavin Howard01055ba2018-11-03 11:00:21 -06007575}
Denys Vlasenkoef869ec2018-12-02 18:49:16 +01007576#endif
Denys Vlasenko9ca9ef22018-12-06 11:31:14 +01007577
Denys Vlasenko14767602018-12-27 22:52:13 +01007578#endif // DC_BIG