1 /* vi: set sw=4 ts=4: */
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 * Copyright (c) 2018 Gavin D. Howard and contributors.
6 * ** Automatically generated from https://github.com/gavinhoward/bc **
7 * ** Do not edit unless you know what you are doing. **
10 //config: bool "bc (45 kb; 49 kb when combined with dc)"
13 //config: bc is a command-line, arbitrary-precision calculator with a
14 //config: Turing-complete language. See the GNU bc manual
15 //config: (https://www.gnu.org/software/bc/manual/bc.html) and bc spec
16 //config: (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html)
17 //config: for details.
19 //config: This bc has four differences to the GNU bc:
21 //config: 1) The period (.) can also be used as a shortcut for "last", as in
23 //config: 2) Arrays are copied before being passed as arguments to
24 //config: functions. This behavior is required by the bc spec.
25 //config: 3) Arrays can be passed to the builtin "length" function to get
26 //config: the number of elements currently in the array. The following
27 //config: example prints "1":
32 //config: 4) The precedence of the boolean "not" operator (!) is equal to
33 //config: that of the unary minus (-), or negation, operator. This still
34 //config: allows POSIX-compliant scripts to work while somewhat
35 //config: preserving expected behavior (versus C) and making parsing
40 //config: -i --interactive force interactive mode
41 //config: -l --mathlib use predefined math routines:
43 //config: s(expr) = sine of expr in radians
44 //config: c(expr) = cosine of expr in radians
45 //config: a(expr) = arctangent of expr, returning
47 //config: l(expr) = natural log of expr
48 //config: e(expr) = raises e to the power of expr
49 //config: j(n, x) = Bessel function of integer order
52 //config: -q --quiet don't print version and copyright.
53 //config: -s --standard error if any non-POSIX extensions are used.
54 //config: -w --warn warn if any non-POSIX extensions are used.
55 //config: -v --version print version and copyright and exit.
57 //config: Long options are only available if FEATURE_BC_LONG_OPTIONS is
61 //config: bool "dc (38 kb; 49 kb when combined with bc)"
64 //config: dc is a reverse-polish notation command-line calculator which
65 //config: supports unlimited precision arithmetic. See the FreeBSD man page
66 //config: (https://www.unix.com/man-page/FreeBSD/1/dc/) and GNU dc manual
67 //config: (https://www.gnu.org/software/bc/manual/dc-1.05/html_mono/dc.html)
68 //config: for details.
70 //config: This dc has a few differences from the two above:
72 //config: 1) When printing a byte stream (command "P"), this bc follows what
73 //config: the FreeBSD dc does.
74 //config: 2) This dc implements the GNU extensions for divmod ("~") and
75 //config: modular exponentiation ("|").
76 //config: 3) This dc implements all FreeBSD extensions, except for "J" and
78 //config: 4) Like the FreeBSD dc, this dc supports extended registers.
79 //config: However, they are implemented differently. When it encounters
80 //config: whitespace where a register should be, it skips the whitespace.
81 //config: If the character following is not a lowercase letter, an error
82 //config: is issued. Otherwise, the register name is parsed by the
83 //config: following regex:
85 //config: [a-z][a-z0-9_]*
87 //config: This generally means that register names will be surrounded by
92 //config: l idx s temp L index S temp2 < do_thing
94 //config: Also note that, like the FreeBSD dc, extended registers are not
95 //config: allowed unless the "-x" option is given.
97 //config:config FEATURE_BC_SIGNALS
98 //config: bool "Enable bc/dc signal handling"
100 //config: depends on BC || DC
102 //config: Enable signal handling for bc and dc.
104 //config:config FEATURE_BC_LONG_OPTIONS
105 //config: bool "Enable bc/dc long options"
107 //config: depends on BC || DC
109 //config: Enable long options for bc and dc.
111 //applet:IF_BC(APPLET(bc, BB_DIR_USR_BIN, BB_SUID_DROP))
112 //applet:IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP))
114 //kbuild:lib-$(CONFIG_BC) += bc.o
115 //kbuild:lib-$(CONFIG_DC) += bc.o
117 //See www.gnu.org/software/bc/manual/bc.html
118 //usage:#define bc_trivial_usage
119 //usage: "[-sqli] FILE..."
121 //usage:#define bc_full_usage "\n"
122 //usage: "\nArbitrary precision calculator"
124 //usage: "\n -i Interactive"
125 //usage: "\n -l Load standard math library"
126 //usage: "\n -s Be POSIX compatible"
127 //usage: "\n -q Quiet"
128 //usage: "\n -w Warn if extensions are used"
129 ///////: "\n -v Version"
131 //usage:#define bc_example_usage
132 //usage: "3 + 4.129\n"
133 //usage: "1903 - 2893\n"
134 //usage: "-129 * 213.28935\n"
135 //usage: "12 / -1932\n"
137 //usage: "34 ^ 189\n"
138 //usage: "scale = 13\n"
139 //usage: "ibase = 2\n"
140 //usage: "obase = A\n"
142 //usage:#define dc_trivial_usage
143 //usage: "EXPRESSION..."
145 //usage:#define dc_full_usage "\n\n"
146 //usage: "Tiny RPN calculator. Operations:\n"
147 //usage: "+, add, -, sub, *, mul, /, div, %, mod, ^, exp, ~, divmod, |, "
148 //usage: "modular exponentiation,\n"
149 //usage: "p - print top of the stack (without popping),\n"
150 //usage: "f - print entire stack,\n"
151 //usage: "k - pop the value and set the precision.\n"
152 //usage: "i - pop the value and set input radix.\n"
153 //usage: "o - pop the value and set output radix.\n"
154 //usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16"
156 //usage:#define dc_example_usage
157 //usage: "$ dc 2 2 + p\n"
159 //usage: "$ dc 8 8 \\* 2 2 + / p\n"
161 //usage: "$ dc 0 1 and p\n"
163 //usage: "$ dc 0 1 or p\n"
165 //usage: "$ echo 72 9 div 8 mul p | dc\n"
170 typedef enum BcStatus {
174 // BC_STATUS_ALLOC_ERR,
175 // BC_STATUS_INPUT_EOF,
176 // BC_STATUS_BIN_FILE,
177 // BC_STATUS_PATH_IS_DIR,
179 // BC_STATUS_LEX_BAD_CHAR,
180 BC_STATUS_LEX_NO_STRING_END,
181 BC_STATUS_LEX_NO_COMMENT_END,
184 BC_STATUS_LEX_EXTENDED_REG,
186 BC_STATUS_PARSE_BAD_TOKEN,
187 BC_STATUS_PARSE_BAD_EXP,
188 BC_STATUS_PARSE_EMPTY_EXP,
189 BC_STATUS_PARSE_BAD_PRINT,
190 BC_STATUS_PARSE_BAD_FUNC,
191 BC_STATUS_PARSE_BAD_ASSIGN,
192 // BC_STATUS_PARSE_NO_AUTO,
193 BC_STATUS_PARSE_DUPLICATE_LOCAL,
194 BC_STATUS_PARSE_NO_BLOCK_END,
196 BC_STATUS_MATH_NEGATIVE,
197 BC_STATUS_MATH_NON_INTEGER,
198 BC_STATUS_MATH_OVERFLOW,
199 BC_STATUS_MATH_DIVIDE_BY_ZERO,
200 BC_STATUS_MATH_BAD_STRING,
202 // BC_STATUS_EXEC_FILE_ERR,
203 // BC_STATUS_EXEC_MISMATCHED_PARAMS,
204 // BC_STATUS_EXEC_UNDEFINED_FUNC,
205 BC_STATUS_EXEC_FILE_NOT_EXECUTABLE,
206 BC_STATUS_EXEC_NUM_LEN,
207 BC_STATUS_EXEC_NAME_LEN,
208 BC_STATUS_EXEC_STRING_LEN,
209 BC_STATUS_EXEC_ARRAY_LEN,
210 BC_STATUS_EXEC_BAD_IBASE,
211 // BC_STATUS_EXEC_BAD_SCALE,
212 BC_STATUS_EXEC_BAD_READ_EXPR,
213 BC_STATUS_EXEC_REC_READ,
214 BC_STATUS_EXEC_BAD_TYPE,
215 // BC_STATUS_EXEC_BAD_OBASE,
216 // BC_STATUS_EXEC_SIGNAL,
217 BC_STATUS_EXEC_STACK,
219 // BC_STATUS_VEC_OUT_OF_BOUNDS,
220 // BC_STATUS_VEC_ITEM_EXISTS,
221 BC_STATUS_BEFORE_POSIX = BC_STATUS_EXEC_STACK,
223 BC_STATUS_POSIX_NAME_LEN,
224 BC_STATUS_POSIX_COMMENT,
225 BC_STATUS_POSIX_BAD_KW,
228 BC_STATUS_POSIX_BOOL,
229 BC_STATUS_POSIX_REL_POS,
230 BC_STATUS_POSIX_MULTIREL,
231 BC_STATUS_POSIX_FOR1,
232 BC_STATUS_POSIX_FOR2,
233 BC_STATUS_POSIX_FOR3,
234 BC_STATUS_POSIX_BRACE,
239 // BC_STATUS_INVALID_OPTION,
241 // Keep enum above and messages below in sync!
242 static const char *const bc_err_msgs[] = {
245 // "memory allocation error",
247 // "file is not text:",
248 // "path is a directory:",
251 "string end could not be found",
252 "comment end could not be found",
260 "bad print statement",
261 "bad function definition",
262 "bad assignment: left side must be scale, ibase, "
263 "obase, last, var, or array element",
264 // "no auto variable found",
265 "function parameter or auto var has the same name as another",
266 "block end could not be found",
269 "non integer number",
274 // "could not open file:",
275 // "mismatched parameters", // wrong number of them, to be exact
276 // "undefined function",
277 "file is not executable:",
278 "number too long: must be [1, BC_NUM_MAX]",
279 "name too long: must be [1, BC_NAME_MAX]",
280 "string too long: must be [1, BC_STRING_MAX]",
281 "array too long; must be [1, BC_DIM_MAX]",
282 "bad ibase; must be [2, 16]",
283 // "bad scale; must be [0, BC_SCALE_MAX]",
284 "bad read() expression",
285 "read() call inside of a read() call",
286 "variable is wrong type",
287 // "bad obase; must be [2, BC_BASE_MAX]",
288 // "signal caught and not handled",
289 "stack has too few elements",
291 // "index is out of bounds",
292 // "item already exists",
294 "POSIX only allows one character names; the following is bad:",
295 "POSIX does not allow '#' script comments",
296 "POSIX does not allow the following keyword:",
297 "POSIX does not allow a period ('.') as a shortcut for the last result",
298 "POSIX requires parentheses around return expressions",
299 "POSIX does not allow boolean operators; the following is bad:",
300 "POSIX does not allow comparison operators outside if or loops",
301 "POSIX requires exactly one comparison operator per condition",
302 "POSIX does not allow an empty init expression in a for loop",
303 "POSIX does not allow an empty condition expression in a for loop",
304 "POSIX does not allow an empty update expression in a for loop",
305 "POSIX requires the left brace be on the same line as the function header",
309 #define BC_VEC_INVALID_IDX ((size_t) -1)
310 #define BC_VEC_START_CAP (1 << 5)
312 typedef void (*BcVecFree)(void *);
314 typedef struct BcVec {
322 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
323 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
325 #define bc_map_init(v) (bc_vec_init((v), sizeof(BcId), bc_id_free))
327 typedef signed char BcDig;
329 typedef struct BcNum {
337 #define BC_NUM_MIN_BASE ((unsigned long) 2)
338 #define BC_NUM_MAX_IBASE ((unsigned long) 16)
339 #define BC_NUM_DEF_SIZE (16)
340 #define BC_NUM_PRINT_WIDTH (69)
342 #define BC_NUM_KARATSUBA_LEN (32)
344 #define BC_NUM_NEG(n, neg) ((((ssize_t)(n)) ^ -((ssize_t)(neg))) + (neg))
345 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
346 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
347 #define BC_NUM_AREQ(a, b) \
348 (BC_MAX((a)->rdx, (b)->rdx) + BC_MAX(BC_NUM_INT(a), BC_NUM_INT(b)) + 1)
349 #define BC_NUM_MREQ(a, b, scale) \
350 (BC_NUM_INT(a) + BC_NUM_INT(b) + BC_MAX((scale), (a)->rdx + (b)->rdx) + 1)
352 typedef BcStatus (*BcNumBinaryOp)(BcNum *, BcNum *, BcNum *, size_t);
353 typedef void (*BcNumDigitOp)(size_t, size_t, bool, size_t *, size_t);
355 static void bc_num_init(BcNum *n, size_t req);
356 static void bc_num_expand(BcNum *n, size_t req);
357 static void bc_num_copy(BcNum *d, BcNum *s);
358 static void bc_num_free(void *num);
360 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
361 static void bc_num_ulong2num(BcNum *n, unsigned long val);
363 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
364 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
365 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
366 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
367 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
368 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
369 static BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
370 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
373 typedef enum BcInst {
403 BC_INST_ASSIGN_POWER,
404 BC_INST_ASSIGN_MULTIPLY,
405 BC_INST_ASSIGN_DIVIDE,
406 BC_INST_ASSIGN_MODULUS,
408 BC_INST_ASSIGN_MINUS,
454 BC_INST_PRINT_STREAM,
469 BC_INST_INVALID = -1,
474 typedef struct BcId {
479 typedef struct BcFunc {
486 typedef enum BcResultType {
491 BC_RESULT_ARRAY_ELEM,
500 // These are between to calculate ibase, obase, and last from instructions.
508 typedef union BcResultData {
514 typedef struct BcResult {
519 typedef struct BcInstPtr {
525 static void bc_array_expand(BcVec *a, size_t len);
526 static int bc_id_cmp(const void *e1, const void *e2);
528 // BC_LEX_NEG is not used in lexing; it is only for parsing.
529 typedef enum BcLexType {
557 BC_LEX_OP_ASSIGN_POWER,
558 BC_LEX_OP_ASSIGN_MULTIPLY,
559 BC_LEX_OP_ASSIGN_DIVIDE,
560 BC_LEX_OP_ASSIGN_MODULUS,
561 BC_LEX_OP_ASSIGN_PLUS,
562 BC_LEX_OP_ASSIGN_MINUS,
636 typedef BcStatus (*BcLexNext)(struct BcLex *);
638 typedef struct BcLex {
657 #define BC_PARSE_STREND ((char) UCHAR_MAX)
659 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, (char) (i)))
660 #define bc_parse_updateFunc(p, f) \
661 ((p)->func = bc_vec_item(&G.prog.fns, ((p)->fidx = (f))))
663 #define BC_PARSE_REL (1 << 0)
664 #define BC_PARSE_PRINT (1 << 1)
665 #define BC_PARSE_NOCALL (1 << 2)
666 #define BC_PARSE_NOREAD (1 << 3)
667 #define BC_PARSE_ARRAY (1 << 4)
669 #define BC_PARSE_TOP_FLAG_PTR(parse) ((uint8_t *) bc_vec_top(&(parse)->flags))
670 #define BC_PARSE_TOP_FLAG(parse) (*(BC_PARSE_TOP_FLAG_PTR(parse)))
672 #define BC_PARSE_FLAG_FUNC_INNER (1 << 0)
673 #define BC_PARSE_FUNC_INNER(parse) \
674 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC_INNER)
676 #define BC_PARSE_FLAG_FUNC (1 << 1)
677 #define BC_PARSE_FUNC(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_FUNC)
679 #define BC_PARSE_FLAG_BODY (1 << 2)
680 #define BC_PARSE_BODY(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_BODY)
682 #define BC_PARSE_FLAG_LOOP (1 << 3)
683 #define BC_PARSE_LOOP(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP)
685 #define BC_PARSE_FLAG_LOOP_INNER (1 << 4)
686 #define BC_PARSE_LOOP_INNER(parse) \
687 (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_LOOP_INNER)
689 #define BC_PARSE_FLAG_IF (1 << 5)
690 #define BC_PARSE_IF(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF)
692 #define BC_PARSE_FLAG_ELSE (1 << 6)
693 #define BC_PARSE_ELSE(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_ELSE)
695 #define BC_PARSE_FLAG_IF_END (1 << 7)
696 #define BC_PARSE_IF_END(parse) (BC_PARSE_TOP_FLAG(parse) & BC_PARSE_FLAG_IF_END)
698 #define BC_PARSE_CAN_EXEC(parse) \
699 (!(BC_PARSE_TOP_FLAG(parse) & \
700 (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_BODY | \
701 BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF | \
702 BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
704 typedef struct BcOp {
709 typedef struct BcParseNext {
714 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
715 #define BC_PARSE_NEXT(a, ...) \
717 .len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
724 typedef BcStatus (*BcParseParse)(struct BcParse *);
726 typedef struct BcParse {
749 typedef struct BcLexKeyword {
755 #define BC_LEX_KW_ENTRY(a, b, c) \
757 .name = a, .len = (b), .posix = (c) \
760 static BcStatus bc_lex_token(BcLex *l);
762 #define BC_PARSE_TOP_OP(p) (*((BcLexType *) bc_vec_top(&(p)->ops)))
763 #define BC_PARSE_LEAF(p, rparen) \
764 (((p) >= BC_INST_NUM && (p) <= BC_INST_SQRT) || (rparen) || \
765 (p) == BC_INST_INC_POST || (p) == BC_INST_DEC_POST)
767 // We can calculate the conversion between tokens and exprs by subtracting the
768 // position of the first operator in the lex enum and adding the position of the
769 // first in the expr enum. Note: This only works for binary operators.
770 #define BC_PARSE_TOKEN_INST(t) ((char) ((t) -BC_LEX_NEG + BC_INST_NEG))
772 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next);
778 #define DC_PARSE_BUF_LEN ((int) (sizeof(uint32_t) * CHAR_BIT))
780 static BcStatus dc_lex_token(BcLex *l);
782 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags);
786 typedef struct BcProgram {
827 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) n))
829 #define BC_PROG_MAIN (0)
830 #define BC_PROG_READ (1)
833 #define BC_PROG_REQ_FUNCS (2)
836 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
837 #define BC_PROG_NUM(r, n) \
838 ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
840 typedef unsigned long (*BcProgramBuiltIn)(BcNum *);
842 static void bc_program_addFunc(char *name, size_t *idx);
843 static void bc_program_reset(void);
845 #define BC_FLAG_X (1 << 0)
846 #define BC_FLAG_W (1 << 1)
847 #define BC_FLAG_V (1 << 2)
848 #define BC_FLAG_S (1 << 3)
849 #define BC_FLAG_Q (1 << 4)
850 #define BC_FLAG_L (1 << 5)
851 #define BC_FLAG_I (1 << 6)
853 #define BC_MAX(a, b) ((a) > (b) ? (a) : (b))
854 #define BC_MIN(a, b) ((a) < (b) ? (a) : (b))
856 #define BC_MAX_OBASE ((unsigned) 999)
857 #define BC_MAX_DIM ((unsigned) INT_MAX)
858 #define BC_MAX_SCALE ((unsigned) UINT_MAX)
859 #define BC_MAX_STRING ((unsigned) UINT_MAX - 1)
860 #define BC_MAX_NAME BC_MAX_STRING
861 #define BC_MAX_NUM BC_MAX_STRING
862 #define BC_MAX_EXP ((unsigned long) LONG_MAX)
863 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
881 #define G (*ptr_to_globals)
882 #define INIT_G() do { \
883 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
885 #define G_posix (ENABLE_BC && (G.flags & BC_FLAG_S))
886 #define G_warn (ENABLE_BC && (G.flags & BC_FLAG_W))
887 #define G_exreg (ENABLE_DC && (G.flags & BC_FLAG_X))
888 #define G_interrupt (ENABLE_FEATURE_BC_SIGNALS ? bb_got_signal : 0)
891 #define IS_BC (ENABLE_BC && (!ENABLE_DC || applet_name[0] == 'b'))
894 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
898 static void bc_vm_info(void);
900 static const char bc_err_fmt[] = "\nerror: %s\n";
901 static const char bc_warn_fmt[] = "\nwarning: %s\n";
902 static const char bc_err_line[] = ":%zu\n\n";
905 static const BcLexKeyword bc_lex_kws[20] = {
906 BC_LEX_KW_ENTRY("auto", 4, true),
907 BC_LEX_KW_ENTRY("break", 5, true),
908 BC_LEX_KW_ENTRY("continue", 8, false),
909 BC_LEX_KW_ENTRY("define", 6, true),
910 BC_LEX_KW_ENTRY("else", 4, false),
911 BC_LEX_KW_ENTRY("for", 3, true),
912 BC_LEX_KW_ENTRY("halt", 4, false),
913 BC_LEX_KW_ENTRY("ibase", 5, true),
914 BC_LEX_KW_ENTRY("if", 2, true),
915 BC_LEX_KW_ENTRY("last", 4, false),
916 BC_LEX_KW_ENTRY("length", 6, true),
917 BC_LEX_KW_ENTRY("limits", 6, false),
918 BC_LEX_KW_ENTRY("obase", 5, true),
919 BC_LEX_KW_ENTRY("print", 5, false),
920 BC_LEX_KW_ENTRY("quit", 4, true),
921 BC_LEX_KW_ENTRY("read", 4, false),
922 BC_LEX_KW_ENTRY("return", 6, true),
923 BC_LEX_KW_ENTRY("scale", 5, true),
924 BC_LEX_KW_ENTRY("sqrt", 4, true),
925 BC_LEX_KW_ENTRY("while", 5, true),
928 // This is an array that corresponds to token types. An entry is
929 // true if the token is valid in an expression, false otherwise.
930 static const bool bc_parse_exprs[] = {
931 false, false, true, true, true, true, true, true, true, true, true, true,
932 true, true, true, true, true, true, true, true, true, true, true, true,
933 true, true, true, false, false, true, true, false, false, false, false,
934 false, false, false, true, true, false, false, false, false, false, false,
935 false, true, false, true, true, true, true, false, false, true, false, true,
939 // This is an array of data for operators that correspond to token types.
940 static const BcOp bc_parse_ops[] = {
941 { 0, false }, { 0, false },
944 { 3, true }, { 3, true }, { 3, true },
945 { 4, true }, { 4, true },
946 { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true }, { 6, true },
948 { 7, true }, { 7, true },
949 { 5, false }, { 5, false }, { 5, false }, { 5, false }, { 5, false },
950 { 5, false }, { 5, false },
953 // These identify what tokens can come after expressions in certain cases.
954 static const BcParseNext bc_parse_next_expr =
955 BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
956 static const BcParseNext bc_parse_next_param =
957 BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
958 static const BcParseNext bc_parse_next_print =
959 BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
960 static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
961 static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
962 static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
963 static const BcParseNext bc_parse_next_read =
964 BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
968 static const BcLexType dc_lex_regs[] = {
969 BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
970 BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
971 BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
975 static const size_t dc_lex_regs_len = sizeof(dc_lex_regs) / sizeof(BcLexType);
977 static const BcLexType dc_lex_tokens[] = {
978 BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
979 BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
980 BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
981 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
982 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
983 BC_LEX_INVALID, BC_LEX_INVALID,
984 BC_LEX_COLON, BC_LEX_SCOLON, BC_LEX_OP_REL_GT, BC_LEX_OP_REL_EQ,
985 BC_LEX_OP_REL_LT, BC_LEX_KEY_READ, BC_LEX_INVALID,
986 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
987 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_EQ_NO_REG, BC_LEX_INVALID,
988 BC_LEX_KEY_IBASE, BC_LEX_INVALID, BC_LEX_KEY_SCALE, BC_LEX_LOAD_POP,
989 BC_LEX_INVALID, BC_LEX_OP_BOOL_NOT, BC_LEX_KEY_OBASE, BC_LEX_PRINT_STREAM,
990 BC_LEX_NQUIT, BC_LEX_POP, BC_LEX_STORE_PUSH, BC_LEX_INVALID, BC_LEX_INVALID,
991 BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_SCALE_FACTOR, BC_LEX_INVALID,
992 BC_LEX_KEY_LENGTH, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_INVALID,
993 BC_LEX_OP_POWER, BC_LEX_NEG, BC_LEX_INVALID,
994 BC_LEX_ASCIIFY, BC_LEX_INVALID, BC_LEX_CLEAR_STACK, BC_LEX_DUPLICATE,
995 BC_LEX_ELSE, BC_LEX_PRINT_STACK, BC_LEX_INVALID, BC_LEX_INVALID,
996 BC_LEX_STORE_IBASE, BC_LEX_INVALID, BC_LEX_STORE_SCALE, BC_LEX_LOAD,
997 BC_LEX_INVALID, BC_LEX_PRINT_POP, BC_LEX_STORE_OBASE, BC_LEX_KEY_PRINT,
998 BC_LEX_KEY_QUIT, BC_LEX_SWAP, BC_LEX_OP_ASSIGN, BC_LEX_INVALID,
999 BC_LEX_INVALID, BC_LEX_KEY_SQRT, BC_LEX_INVALID, BC_LEX_EXECUTE,
1000 BC_LEX_INVALID, BC_LEX_STACK_LEVEL,
1001 BC_LEX_LBRACE, BC_LEX_OP_MODEXP, BC_LEX_INVALID, BC_LEX_OP_DIVMOD,
1005 static const BcInst dc_parse_insts[] = {
1006 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1007 BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
1008 BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
1009 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1010 BC_INST_INVALID, BC_INST_INVALID,
1011 BC_INST_BOOL_NOT, BC_INST_INVALID, BC_INST_INVALID,
1012 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1013 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1014 BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GT, BC_INST_INVALID,
1015 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
1016 BC_INST_INVALID, BC_INST_INVALID,
1017 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1018 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1019 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_IBASE,
1020 BC_INST_INVALID, BC_INST_INVALID, BC_INST_LENGTH, BC_INST_INVALID,
1021 BC_INST_OBASE, BC_INST_PRINT, BC_INST_QUIT, BC_INST_INVALID,
1022 BC_INST_INVALID, BC_INST_SCALE, BC_INST_SQRT, BC_INST_INVALID,
1023 BC_INST_REL_EQ, BC_INST_MODEXP, BC_INST_DIVMOD, BC_INST_INVALID,
1024 BC_INST_INVALID, BC_INST_EXECUTE, BC_INST_PRINT_STACK, BC_INST_CLEAR_STACK,
1025 BC_INST_STACK_LEN, BC_INST_DUPLICATE, BC_INST_SWAP, BC_INST_POP,
1026 BC_INST_ASCIIFY, BC_INST_PRINT_STREAM, BC_INST_INVALID, BC_INST_INVALID,
1027 BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID,
1028 BC_INST_PRINT, BC_INST_NQUIT, BC_INST_SCALE_FUNC,
1032 static const BcNumBinaryOp bc_program_ops[] = {
1033 bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
1036 static const char bc_program_stdin_name[] = "<stdin>";
1039 static const char *bc_lib_name = "gen/lib.bc";
1041 static const char bc_lib[] = {
1042 115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
1043 10,9,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,
1044 44,118,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,105,102,
1045 40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,10,9,125,10,9,115,
1046 61,115,99,97,108,101,10,9,114,61,54,43,115,43,48,46,52,52,42,120,10,9,115,99,
1047 97,108,101,61,115,99,97,108,101,40,120,41,43,49,10,9,119,104,105,108,101,40,
1048 120,62,49,41,123,10,9,9,100,43,61,49,10,9,9,120,47,61,50,10,9,9,115,99,97,108,
1049 101,43,61,49,10,9,125,10,9,115,99,97,108,101,61,114,10,9,114,61,120,43,49,10,
1050 9,112,61,120,10,9,102,61,118,61,49,10,9,102,111,114,40,105,61,50,59,118,33,
1051 61,48,59,43,43,105,41,123,10,9,9,112,42,61,120,10,9,9,102,42,61,105,10,9,9,
1052 118,61,112,47,102,10,9,9,114,43,61,118,10,9,125,10,9,119,104,105,108,101,40,
1053 40,100,45,45,41,33,61,48,41,114,42,61,114,10,9,115,99,97,108,101,61,115,10,
1054 9,105,98,97,115,101,61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,
1055 110,40,49,47,114,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,
1056 100,101,102,105,110,101,32,108,40,120,41,123,10,9,97,117,116,111,32,98,44,115,
1057 44,114,44,112,44,97,44,113,44,105,44,118,10,9,98,61,105,98,97,115,101,10,9,
1058 105,98,97,115,101,61,65,10,9,105,102,40,120,60,61,48,41,123,10,9,9,114,61,40,
1059 49,45,49,48,94,115,99,97,108,101,41,47,49,10,9,9,105,98,97,115,101,61,98,10,
1060 9,9,114,101,116,117,114,110,40,114,41,10,9,125,10,9,115,61,115,99,97,108,101,
1061 10,9,115,99,97,108,101,43,61,54,10,9,112,61,50,10,9,119,104,105,108,101,40,
1062 120,62,61,50,41,123,10,9,9,112,42,61,50,10,9,9,120,61,115,113,114,116,40,120,
1063 41,10,9,125,10,9,119,104,105,108,101,40,120,60,61,48,46,53,41,123,10,9,9,112,
1064 42,61,50,10,9,9,120,61,115,113,114,116,40,120,41,10,9,125,10,9,114,61,97,61,
1065 40,120,45,49,41,47,40,120,43,49,41,10,9,113,61,97,42,97,10,9,118,61,49,10,9,
1066 102,111,114,40,105,61,51,59,118,33,61,48,59,105,43,61,50,41,123,10,9,9,97,42,
1067 61,113,10,9,9,118,61,97,47,105,10,9,9,114,43,61,118,10,9,125,10,9,114,42,61,
1068 112,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,101,
1069 116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,115,40,
1070 120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,113,44,105,
1071 10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,
1072 97,108,101,10,9,115,99,97,108,101,61,49,46,49,42,115,43,50,10,9,97,61,97,40,
1073 49,41,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,49,10,9,9,120,61,45,120,
1074 10,9,125,10,9,115,99,97,108,101,61,48,10,9,113,61,40,120,47,97,43,50,41,47,
1075 52,10,9,120,61,120,45,52,42,113,42,97,10,9,105,102,40,113,37,50,33,61,48,41,
1076 120,61,45,120,10,9,115,99,97,108,101,61,115,43,50,10,9,114,61,97,61,120,10,
1077 9,113,61,45,120,42,120,10,9,102,111,114,40,105,61,51,59,97,33,61,48,59,105,
1078 43,61,50,41,123,10,9,9,97,42,61,113,47,40,105,42,40,105,45,49,41,41,10,9,9,
1079 114,43,61,97,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,
1080 61,98,10,9,105,102,40,110,33,61,48,41,114,101,116,117,114,110,40,45,114,47,
1081 49,41,10,9,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,
1082 110,101,32,99,40,120,41,123,10,9,97,117,116,111,32,98,44,115,10,9,98,61,105,
1083 98,97,115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,
1084 9,115,99,97,108,101,42,61,49,46,50,10,9,120,61,115,40,50,42,97,40,49,41,43,
1085 120,41,10,9,115,99,97,108,101,61,115,10,9,105,98,97,115,101,61,98,10,9,114,
1086 101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,97,
1087 40,120,41,123,10,9,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,44,
1088 116,44,102,44,105,44,117,10,9,98,61,105,98,97,115,101,10,9,105,98,97,115,101,
1089 61,65,10,9,110,61,49,10,9,105,102,40,120,60,48,41,123,10,9,9,110,61,45,49,10,
1090 9,9,120,61,45,120,10,9,125,10,9,105,102,40,120,61,61,49,41,123,10,9,9,105,102,
1091 40,115,99,97,108,101,60,54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,
1092 55,56,53,51,57,56,49,54,51,51,57,55,52,52,56,51,48,57,54,49,53,54,54,48,56,
1093 52,53,56,49,57,56,55,53,55,50,49,48,52,57,50,57,50,51,52,57,56,52,51,55,55,
1094 54,52,53,53,50,52,51,55,51,54,49,52,56,48,47,110,41,10,9,9,125,10,9,125,10,
1095 9,105,102,40,120,61,61,46,50,41,123,10,9,9,105,102,40,115,99,97,108,101,60,
1096 54,53,41,123,10,9,9,9,114,101,116,117,114,110,40,46,49,57,55,51,57,53,53,53,
1097 57,56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,
1098 50,57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,
1099 56,56,57,52,48,50,47,110,41,10,9,9,125,10,9,125,10,9,115,61,115,99,97,108,101,
1100 10,9,105,102,40,120,62,46,50,41,123,10,9,9,115,99,97,108,101,43,61,53,10,9,
1101 9,97,61,97,40,46,50,41,10,9,125,10,9,115,99,97,108,101,61,115,43,51,10,9,119,
1102 104,105,108,101,40,120,62,46,50,41,123,10,9,9,109,43,61,49,10,9,9,120,61,40,
1103 120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,9,125,10,9,114,61,117,61,120,
1104 10,9,102,61,45,120,42,120,10,9,116,61,49,10,9,102,111,114,40,105,61,51,59,116,
1105 33,61,48,59,105,43,61,50,41,123,10,9,9,117,42,61,102,10,9,9,116,61,117,47,105,
1106 10,9,9,114,43,61,116,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,97,
1107 115,101,61,98,10,9,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,
1108 41,10,125,10,100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,9,97,117,
1109 116,111,32,98,44,115,44,111,44,97,44,105,44,118,44,102,10,9,98,61,105,98,97,
1110 115,101,10,9,105,98,97,115,101,61,65,10,9,115,61,115,99,97,108,101,10,9,115,
1111 99,97,108,101,61,48,10,9,110,47,61,49,10,9,105,102,40,110,60,48,41,123,10,9,
1112 9,110,61,45,110,10,9,9,105,102,40,110,37,50,61,61,49,41,111,61,49,10,9,125,
1113 10,9,97,61,49,10,9,102,111,114,40,105,61,50,59,105,60,61,110,59,43,43,105,41,
1114 97,42,61,105,10,9,115,99,97,108,101,61,49,46,53,42,115,10,9,97,61,40,120,94,
1115 110,41,47,50,94,110,47,97,10,9,114,61,118,61,49,10,9,102,61,45,120,42,120,47,
1116 52,10,9,115,99,97,108,101,61,115,99,97,108,101,43,108,101,110,103,116,104,40,
1117 97,41,45,115,99,97,108,101,40,97,41,10,9,102,111,114,40,105,61,49,59,118,33,
1118 61,48,59,43,43,105,41,123,10,9,9,118,61,118,42,102,47,105,47,40,110,43,105,
1119 41,10,9,9,114,43,61,118,10,9,125,10,9,115,99,97,108,101,61,115,10,9,105,98,
1120 97,115,101,61,98,10,9,105,102,40,111,33,61,48,41,97,61,45,97,10,9,114,101,116,
1121 117,114,110,40,97,42,114,47,49,41,10,125,10,0
1125 static void fflush_and_check(void)
1128 if (ferror(stdout) || ferror(stderr))
1129 bb_perror_msg_and_die("output error");
1132 static void quit(void) NORETURN;
1133 static void quit(void)
1136 bb_perror_msg_and_die("input error");
1141 static int bc_error(const char *fmt, ...)
1146 bb_verror_msg(fmt, p, NULL);
1150 return BC_STATUS_FAILURE;
1153 static void bc_vec_grow(BcVec *v, size_t n)
1155 size_t cap = v->cap * 2;
1156 while (cap < v->len + n) cap *= 2;
1157 v->v = xrealloc(v->v, v->size * cap);
1161 static void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor)
1164 v->cap = BC_VEC_START_CAP;
1167 v->v = xmalloc(esize * BC_VEC_START_CAP);
1170 static void bc_vec_expand(BcVec *v, size_t req)
1173 v->v = xrealloc(v->v, v->size * req);
1178 static void bc_vec_npop(BcVec *v, size_t n)
1183 size_t len = v->len - n;
1184 while (v->len > len) v->dtor(v->v + (v->size * --v->len));
1188 static void bc_vec_push(BcVec *v, const void *data)
1190 if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
1191 memmove(v->v + (v->size * v->len), data, v->size);
1195 static void bc_vec_pushByte(BcVec *v, char data)
1197 bc_vec_push(v, &data);
1200 static void bc_vec_pushAt(BcVec *v, const void *data, size_t idx)
1203 bc_vec_push(v, data);
1208 if (v->len == v->cap) bc_vec_grow(v, 1);
1210 ptr = v->v + v->size * idx;
1212 memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
1213 memmove(ptr, data, v->size);
1217 static void bc_vec_string(BcVec *v, size_t len, const char *str)
1219 bc_vec_npop(v, v->len);
1220 bc_vec_expand(v, len + 1);
1221 memcpy(v->v, str, len);
1224 bc_vec_pushByte(v, '\0');
1227 static void bc_vec_concat(BcVec *v, const char *str)
1231 if (v->len == 0) bc_vec_pushByte(v, '\0');
1233 len = v->len + strlen(str);
1235 if (v->cap < len) bc_vec_grow(v, len - v->len);
1241 static void *bc_vec_item(const BcVec *v, size_t idx)
1243 return v->v + v->size * idx;
1246 static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1248 return v->v + v->size * (v->len - idx - 1);
1251 static void bc_vec_free(void *vec)
1253 BcVec *v = (BcVec *) vec;
1254 bc_vec_npop(v, v->len);
1258 static size_t bc_map_find(const BcVec *v, const void *ptr)
1260 size_t low = 0, high = v->len;
1262 while (low < high) {
1264 size_t mid = (low + high) / 2;
1265 BcId *id = bc_vec_item(v, mid);
1266 int result = bc_id_cmp(ptr, id);
1270 else if (result < 0)
1279 static int bc_map_insert(BcVec *v, const void *ptr, size_t *i)
1281 size_t n = *i = bc_map_find(v, ptr);
1284 bc_vec_push(v, ptr);
1285 else if (!bc_id_cmp(ptr, bc_vec_item(v, n)))
1286 return 0; // "was not inserted"
1288 bc_vec_pushAt(v, ptr, n);
1289 return 1; // "was inserted"
1292 static size_t bc_map_index(const BcVec *v, const void *ptr)
1294 size_t i = bc_map_find(v, ptr);
1295 if (i >= v->len) return BC_VEC_INVALID_IDX;
1296 return bc_id_cmp(ptr, bc_vec_item(v, i)) ? BC_VEC_INVALID_IDX : i;
1299 static BcStatus bc_read_line(BcVec *vec, const char *prompt)
1308 bc_vec_npop(vec, vec->len);
1311 #if ENABLE_FEATURE_BC_SIGNALS
1312 if (bb_got_signal) { // ^C was pressed
1314 bb_got_signal = 0; // resets G_interrupt to zero
1316 ? "\ninterrupt (type \"quit\" to exit)\n"
1317 : "\ninterrupt (type \"q\" to exit)\n"
1321 if (G.ttyin && !G_posix)
1322 fputs(prompt, stderr);
1324 #if ENABLE_FEATURE_BC_SIGNALS
1330 #if ENABLE_FEATURE_BC_SIGNALS
1331 // Both conditions appear simultaneously, check both just in case
1332 if (errno == EINTR || bb_got_signal) {
1339 quit(); // this emits error message
1341 // Note: EOF does not append '\n', therefore:
1342 // printf 'print 123\n' | bc - works
1343 // printf 'print 123' | bc - fails (syntax error)
1347 if ((i < ' ' && i != '\t' && i != '\r' && i != '\n') // also allow '\v' '\f'?
1350 // Bad chars on this line, ignore entire line
1351 bc_error("illegal character 0x%02x", i);
1355 bc_vec_push(vec, &c);
1356 } while (i != '\n');
1357 } while (bad_chars);
1359 bc_vec_pushByte(vec, '\0');
1361 return BC_STATUS_SUCCESS;
1364 static char* bc_read_file(const char *path)
1367 size_t size = ((size_t) -1);
1370 buf = xmalloc_open_read_close(path, &size);
1372 for (i = 0; i < size; ++i) {
1374 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
1386 static void bc_args(int argc, char **argv)
1391 #if ENABLE_FEATURE_BC_LONG_OPTIONS
1392 G.flags = getopt32long(argv, "xwvsqli",
1393 "extended-register\0" No_argument "x"
1394 "warn\0" No_argument "w"
1395 "version\0" No_argument "v"
1396 "standard\0" No_argument "s"
1397 "quiet\0" No_argument "q"
1398 "mathlib\0" No_argument "l"
1399 "interactive\0" No_argument "i"
1402 G.flags = getopt32(argv, "xwvsqli");
1405 if (G.flags & BC_FLAG_V) bc_vm_info();
1406 // should not be necessary, getopt32() handles this??
1407 //if (argv[optind] && !strcmp(argv[optind], "--")) ++optind;
1409 for (i = optind; i < argc; ++i) bc_vec_push(&G.files, argv + i);
1412 static void bc_num_setToZero(BcNum *n, size_t scale)
1419 static void bc_num_zero(BcNum *n)
1421 bc_num_setToZero(n, 0);
1424 static void bc_num_one(BcNum *n)
1426 bc_num_setToZero(n, 0);
1431 static void bc_num_ten(BcNum *n)
1433 bc_num_setToZero(n, 0);
1439 static void bc_num_subArrays(BcDig *restrict a, BcDig *restrict b,
1443 for (i = 0; i < len; ++i) {
1444 for (a[i] -= b[i], j = 0; a[i + j] < 0;) {
1451 static ssize_t bc_num_compare(BcDig *restrict a, BcDig *restrict b, size_t len)
1455 for (i = len - 1; i < len && !(c = a[i] - b[i]); --i);
1456 return BC_NUM_NEG(i + 1, c < 0);
1459 static ssize_t bc_num_cmp(BcNum *a, BcNum *b)
1461 size_t i, min, a_int, b_int, diff;
1462 BcDig *max_num, *min_num;
1463 bool a_max, neg = false;
1466 if (a == b) return 0;
1467 if (a->len == 0) return BC_NUM_NEG(!!b->len, !b->neg);
1468 if (b->len == 0) return BC_NUM_NEG(1, a->neg);
1478 a_int = BC_NUM_INT(a);
1479 b_int = BC_NUM_INT(b);
1481 a_max = (a->rdx > b->rdx);
1483 if (a_int != 0) return (ssize_t) a_int;
1487 diff = a->rdx - b->rdx;
1488 max_num = a->num + diff;
1493 diff = b->rdx - a->rdx;
1494 max_num = b->num + diff;
1498 cmp = bc_num_compare(max_num, min_num, b_int + min);
1499 if (cmp != 0) return BC_NUM_NEG(cmp, (!a_max) != neg);
1501 for (max_num -= diff, i = diff - 1; i < diff; --i) {
1502 if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1508 static void bc_num_truncate(BcNum *n, size_t places)
1510 if (places == 0) return;
1516 memmove(n->num, n->num + places, n->len * sizeof(BcDig));
1520 static void bc_num_extend(BcNum *n, size_t places)
1522 size_t len = n->len + places;
1526 if (n->cap < len) bc_num_expand(n, len);
1528 memmove(n->num + places, n->num, sizeof(BcDig) * n->len);
1529 memset(n->num, 0, sizeof(BcDig) * places);
1536 static void bc_num_clean(BcNum *n)
1538 while (n->len > 0 && n->num[n->len - 1] == 0) --n->len;
1541 else if (n->len < n->rdx)
1545 static void bc_num_retireMul(BcNum *n, size_t scale, bool neg1, bool neg2)
1548 bc_num_extend(n, scale - n->rdx);
1550 bc_num_truncate(n, n->rdx - scale);
1553 if (n->len != 0) n->neg = !neg1 != !neg2;
1556 static void bc_num_split(BcNum *restrict n, size_t idx, BcNum *restrict a,
1561 b->len = n->len - idx;
1563 a->rdx = b->rdx = 0;
1565 memcpy(b->num, n->num + idx, b->len * sizeof(BcDig));
1566 memcpy(a->num, n->num, idx * sizeof(BcDig));
1577 static BcStatus bc_num_shift(BcNum *n, size_t places)
1579 if (places == 0 || n->len == 0) return BC_STATUS_SUCCESS;
1580 if (places + n->len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
1582 if (n->rdx >= places)
1585 bc_num_extend(n, places - n->rdx);
1591 return BC_STATUS_SUCCESS;
1594 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale)
1603 return bc_num_div(&one, a, b, scale);
1606 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1608 BcDig *ptr, *ptr_a, *ptr_b, *ptr_c;
1609 size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1612 // Because this function doesn't need to use scale (per the bc spec),
1613 // I am hijacking it to say whether it's doing an add or a subtract.
1617 if (sub && c->len) c->neg = !c->neg;
1618 return BC_STATUS_SUCCESS;
1620 else if (b->len == 0) {
1622 return BC_STATUS_SUCCESS;
1626 c->rdx = BC_MAX(a->rdx, b->rdx);
1627 min_rdx = BC_MIN(a->rdx, b->rdx);
1630 if (a->rdx > b->rdx) {
1631 diff = a->rdx - b->rdx;
1633 ptr_a = a->num + diff;
1637 diff = b->rdx - a->rdx;
1640 ptr_b = b->num + diff;
1643 for (ptr_c = c->num, i = 0; i < diff; ++i, ++c->len) ptr_c[i] = ptr[i];
1646 a_int = BC_NUM_INT(a);
1647 b_int = BC_NUM_INT(b);
1649 if (a_int > b_int) {
1660 for (carry = 0, i = 0; i < min_rdx + min_int; ++i, ++c->len) {
1661 in = ((int) ptr_a[i]) + ((int) ptr_b[i]) + carry;
1663 ptr_c[i] = (BcDig)(in % 10);
1666 for (; i < max + min_rdx; ++i, ++c->len) {
1667 in = ((int) ptr[i]) + carry;
1669 ptr_c[i] = (BcDig)(in % 10);
1672 if (carry != 0) c->num[c->len++] = (BcDig) carry;
1674 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1677 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *restrict c, size_t sub)
1680 BcNum *minuend, *subtrahend;
1682 bool aneg, bneg, neg;
1684 // Because this function doesn't need to use scale (per the bc spec),
1685 // I am hijacking it to say whether it's doing an add or a subtract.
1689 if (sub && c->len) c->neg = !c->neg;
1690 return BC_STATUS_SUCCESS;
1692 else if (b->len == 0) {
1694 return BC_STATUS_SUCCESS;
1699 a->neg = b->neg = false;
1701 cmp = bc_num_cmp(a, b);
1707 bc_num_setToZero(c, BC_MAX(a->rdx, b->rdx));
1708 return BC_STATUS_SUCCESS;
1717 if (sub) neg = !neg;
1722 bc_num_copy(c, minuend);
1725 if (c->rdx < subtrahend->rdx) {
1726 bc_num_extend(c, subtrahend->rdx - c->rdx);
1730 start = c->rdx - subtrahend->rdx;
1732 bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1736 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1739 static BcStatus bc_num_k(BcNum *restrict a, BcNum *restrict b,
1744 size_t i, j, len, max = BC_MAX(a->len, b->len), max2 = (max + 1) / 2;
1745 BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1746 bool aone = BC_NUM_ONE(a);
1748 if (a->len == 0 || b->len == 0) {
1750 return BC_STATUS_SUCCESS;
1752 else if (aone || BC_NUM_ONE(b)) {
1753 bc_num_copy(c, aone ? b : a);
1754 return BC_STATUS_SUCCESS;
1757 if (a->len + b->len < BC_NUM_KARATSUBA_LEN ||
1758 a->len < BC_NUM_KARATSUBA_LEN || b->len < BC_NUM_KARATSUBA_LEN)
1760 bc_num_expand(c, a->len + b->len + 1);
1762 memset(c->num, 0, sizeof(BcDig) * c->cap);
1763 c->len = carry = len = 0;
1765 for (i = 0; i < b->len; ++i) {
1767 for (j = 0; j < a->len; ++j) {
1768 int in = (int) c->num[i + j];
1769 in += ((int) a->num[j]) * ((int) b->num[i]) + carry;
1771 c->num[i + j] = (BcDig)(in % 10);
1774 c->num[i + j] += (BcDig) carry;
1775 len = BC_MAX(len, i + j + !!carry);
1781 return BC_STATUS_SUCCESS;
1784 bc_num_init(&l1, max);
1785 bc_num_init(&h1, max);
1786 bc_num_init(&l2, max);
1787 bc_num_init(&h2, max);
1788 bc_num_init(&m1, max);
1789 bc_num_init(&m2, max);
1790 bc_num_init(&z0, max);
1791 bc_num_init(&z1, max);
1792 bc_num_init(&z2, max);
1793 bc_num_init(&temp, max + max);
1795 bc_num_split(a, max2, &l1, &h1);
1796 bc_num_split(b, max2, &l2, &h2);
1798 s = bc_num_add(&h1, &l1, &m1, 0);
1800 s = bc_num_add(&h2, &l2, &m2, 0);
1803 s = bc_num_k(&h1, &h2, &z0);
1805 s = bc_num_k(&m1, &m2, &z1);
1807 s = bc_num_k(&l1, &l2, &z2);
1810 s = bc_num_sub(&z1, &z0, &temp, 0);
1812 s = bc_num_sub(&temp, &z2, &z1, 0);
1815 s = bc_num_shift(&z0, max2 * 2);
1817 s = bc_num_shift(&z1, max2);
1819 s = bc_num_add(&z0, &z1, &temp, 0);
1821 s = bc_num_add(&temp, &z2, c, 0);
1837 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1841 size_t maxrdx = BC_MAX(a->rdx, b->rdx);
1843 scale = BC_MAX(scale, a->rdx);
1844 scale = BC_MAX(scale, b->rdx);
1845 scale = BC_MIN(a->rdx + b->rdx, scale);
1846 maxrdx = BC_MAX(maxrdx, scale);
1848 bc_num_init(&cpa, a->len);
1849 bc_num_init(&cpb, b->len);
1851 bc_num_copy(&cpa, a);
1852 bc_num_copy(&cpb, b);
1853 cpa.neg = cpb.neg = false;
1855 s = bc_num_shift(&cpa, maxrdx);
1857 s = bc_num_shift(&cpb, maxrdx);
1859 s = bc_num_k(&cpa, &cpb, c);
1863 bc_num_expand(c, c->len + maxrdx);
1865 if (c->len < maxrdx) {
1866 memset(c->num + c->len, 0, (c->cap - c->len) * sizeof(BcDig));
1871 bc_num_retireMul(c, scale, a->neg, b->neg);
1879 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1881 BcStatus s = BC_STATUS_SUCCESS;
1888 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1889 else if (a->len == 0) {
1890 bc_num_setToZero(c, scale);
1891 return BC_STATUS_SUCCESS;
1893 else if (BC_NUM_ONE(b)) {
1895 bc_num_retireMul(c, scale, a->neg, b->neg);
1896 return BC_STATUS_SUCCESS;
1899 bc_num_init(&cp, BC_NUM_MREQ(a, b, scale));
1900 bc_num_copy(&cp, a);
1904 bc_num_expand(&cp, len + 2);
1905 bc_num_extend(&cp, len - cp.len);
1908 if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1910 if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1912 if (b->rdx == b->len) {
1913 for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1917 if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1919 // We want an extra zero in front to make things simpler.
1920 cp.num[cp.len++] = 0;
1923 bc_num_expand(c, cp.len);
1926 memset(c->num + end, 0, (c->cap - end) * sizeof(BcDig));
1931 for (i = end - 1; !s && i < end; --i) {
1933 for (q = 0; (!s && n[len] != 0) || bc_num_compare(n, p, len) >= 0; ++q)
1934 bc_num_subArrays(n, p, len);
1938 bc_num_retireMul(c, scale, a->neg, b->neg);
1941 return BC_STATUS_SUCCESS; // can't make void, see bc_num_binary()
1944 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *restrict c,
1945 BcNum *restrict d, size_t scale, size_t ts)
1951 if (b->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
1954 bc_num_setToZero(d, ts);
1955 return BC_STATUS_SUCCESS;
1958 bc_num_init(&temp, d->cap);
1959 bc_num_d(a, b, c, scale);
1961 if (scale != 0) scale = ts;
1963 s = bc_num_m(c, b, &temp, scale);
1965 s = bc_num_sub(a, &temp, d, scale);
1968 if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1971 bc_num_retireMul(d, ts, a->neg, b->neg);
1979 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1983 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
1985 bc_num_init(&c1, len);
1986 s = bc_num_r(a, b, &c1, c, scale, ts);
1992 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size_t scale)
1994 BcStatus s = BC_STATUS_SUCCESS;
1997 size_t i, powrdx, resrdx;
2000 if (b->rdx) return BC_STATUS_MATH_NON_INTEGER;
2004 return BC_STATUS_SUCCESS;
2006 else if (a->len == 0) {
2007 bc_num_setToZero(c, scale);
2008 return BC_STATUS_SUCCESS;
2010 else if (BC_NUM_ONE(b)) {
2014 s = bc_num_inv(a, c, scale);
2021 s = bc_num_ulong(b, &pow);
2024 bc_num_init(©, a->len);
2025 bc_num_copy(©, a);
2027 if (!neg) scale = BC_MIN(a->rdx * pow, BC_MAX(scale, a->rdx));
2031 for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
2033 s = bc_num_mul(©, ©, ©, powrdx);
2037 bc_num_copy(c, ©);
2039 for (resrdx = powrdx, pow >>= 1; pow != 0; pow >>= 1) {
2042 s = bc_num_mul(©, ©, ©, powrdx);
2047 s = bc_num_mul(c, ©, c, resrdx);
2053 s = bc_num_inv(c, c, scale);
2057 if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
2059 // We can't use bc_num_clean() here.
2060 for (zero = true, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
2061 if (zero) bc_num_setToZero(c, scale);
2068 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
2069 BcNumBinaryOp op, size_t req)
2072 BcNum num2, *ptr_a, *ptr_b;
2077 memcpy(ptr_a, c, sizeof(BcNum));
2086 memcpy(ptr_b, c, sizeof(BcNum));
2094 bc_num_init(c, req);
2096 bc_num_expand(c, req);
2098 s = op(ptr_a, ptr_b, c, scale);
2100 if (init) bc_num_free(&num2);
2105 static bool bc_num_strValid(const char *val, size_t base)
2108 bool small, radix = false;
2109 size_t i, len = strlen(val);
2111 if (!len) return true;
2114 b = (BcDig)(small ? base + '0' : base - 10 + 'A');
2116 for (i = 0; i < len; ++i) {
2122 if (radix) return false;
2128 if (c < '0' || (small && c >= b) || (c > '9' && (c < 'A' || c >= b)))
2135 static void bc_num_parseDecimal(BcNum *n, const char *val)
2141 for (i = 0; val[i] == '0'; ++i);
2148 for (i = 0; zero && i < len; ++i) zero = val[i] == '0' || val[i] == '.';
2149 bc_num_expand(n, len);
2152 ptr = strchr(val, '.');
2154 // Explicitly test for NULL here to produce either a 0 or 1.
2155 n->rdx = (size_t)((ptr != NULL) * ((val + len) - (ptr + 1)));
2158 for (i = len - 1; i < len; ++n->len, i -= 1 + (i && val[i - 1] == '.'))
2159 n->num[n->len] = val[i] - '0';
2163 static void bc_num_parseBase(BcNum *n, const char *val, BcNum *base)
2166 BcNum temp, mult, result;
2170 size_t i, digits, len = strlen(val);
2174 for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
2177 bc_num_init(&temp, BC_NUM_DEF_SIZE);
2178 bc_num_init(&mult, BC_NUM_DEF_SIZE);
2180 for (i = 0; i < len; ++i) {
2183 if (c == '.') break;
2185 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2187 s = bc_num_mul(n, base, &mult, 0);
2188 if (s) goto int_err;
2189 bc_num_ulong2num(&temp, v);
2190 s = bc_num_add(&mult, &temp, n, 0);
2191 if (s) goto int_err;
2196 if (c == 0) goto int_err;
2199 bc_num_init(&result, base->len);
2200 bc_num_zero(&result);
2203 for (i += 1, digits = 0; i < len; ++i, ++digits) {
2208 v = (unsigned long) (c <= '9' ? c - '0' : c - 'A' + 10);
2210 s = bc_num_mul(&result, base, &result, 0);
2212 bc_num_ulong2num(&temp, v);
2213 s = bc_num_add(&result, &temp, &result, 0);
2215 s = bc_num_mul(&mult, base, &mult, 0);
2219 s = bc_num_div(&result, &mult, &result, digits);
2221 s = bc_num_add(n, &result, n, digits);
2225 if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
2231 bc_num_free(&result);
2237 static void bc_num_printNewline(size_t *nchars, size_t line_len)
2239 if (*nchars == line_len - 1) {
2247 static void bc_num_printChar(size_t num, size_t width, bool radix,
2248 size_t *nchars, size_t line_len)
2250 (void) radix, (void) line_len;
2251 bb_putchar((char) num);
2252 *nchars = *nchars + width;
2256 static void bc_num_printDigits(size_t num, size_t width, bool radix,
2257 size_t *nchars, size_t line_len)
2261 bc_num_printNewline(nchars, line_len);
2262 bb_putchar(radix ? '.' : ' ');
2265 bc_num_printNewline(nchars, line_len);
2266 for (exp = 0, pow = 1; exp < width - 1; ++exp, pow *= 10)
2269 for (exp = 0; exp < width; pow /= 10, ++(*nchars), ++exp) {
2271 bc_num_printNewline(nchars, line_len);
2274 bb_putchar(((char) dig) + '0');
2278 static void bc_num_printHex(size_t num, size_t width, bool radix,
2279 size_t *nchars, size_t line_len)
2282 bc_num_printNewline(nchars, line_len);
2287 bc_num_printNewline(nchars, line_len);
2288 bb_putchar(bb_hexdigits_upcase[num]);
2289 *nchars = *nchars + width;
2292 static void bc_num_printDecimal(BcNum *n, size_t *nchars, size_t len)
2294 size_t i, rdx = n->rdx - 1;
2296 if (n->neg) bb_putchar('-');
2297 (*nchars) += n->neg;
2299 for (i = n->len - 1; i < n->len; --i)
2300 bc_num_printHex((size_t) n->num[i], 1, i == rdx, nchars, len);
2303 static BcStatus bc_num_printNum(BcNum *n, BcNum *base, size_t width,
2304 size_t *nchars, size_t len, BcNumDigitOp print)
2308 BcNum intp, fracp, digit, frac_len;
2309 unsigned long dig, *ptr;
2314 print(0, width, false, nchars, len);
2315 return BC_STATUS_SUCCESS;
2318 bc_vec_init(&stack, sizeof(long), NULL);
2319 bc_num_init(&intp, n->len);
2320 bc_num_init(&fracp, n->rdx);
2321 bc_num_init(&digit, width);
2322 bc_num_init(&frac_len, BC_NUM_INT(n));
2323 bc_num_copy(&intp, n);
2324 bc_num_one(&frac_len);
2326 bc_num_truncate(&intp, intp.rdx);
2327 s = bc_num_sub(n, &intp, &fracp, 0);
2330 while (intp.len != 0) {
2331 s = bc_num_divmod(&intp, base, &intp, &digit, 0);
2333 s = bc_num_ulong(&digit, &dig);
2335 bc_vec_push(&stack, &dig);
2338 for (i = 0; i < stack.len; ++i) {
2339 ptr = bc_vec_item_rev(&stack, i);
2340 print(*ptr, width, false, nchars, len);
2343 if (!n->rdx) goto err;
2345 for (radix = true; frac_len.len <= n->rdx; radix = false) {
2346 s = bc_num_mul(&fracp, base, &fracp, n->rdx);
2348 s = bc_num_ulong(&fracp, &dig);
2350 bc_num_ulong2num(&intp, dig);
2351 s = bc_num_sub(&fracp, &intp, &fracp, 0);
2353 print(dig, width, radix, nchars, len);
2354 s = bc_num_mul(&frac_len, base, &frac_len, 0);
2359 bc_num_free(&frac_len);
2360 bc_num_free(&digit);
2361 bc_num_free(&fracp);
2363 bc_vec_free(&stack);
2367 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t,
2368 size_t *nchars, size_t line_len)
2375 if (neg) bb_putchar('-');
2380 if (base_t <= BC_NUM_MAX_IBASE) {
2382 print = bc_num_printHex;
2385 for (i = base_t - 1, width = 0; i != 0; i /= 10, ++width);
2386 print = bc_num_printDigits;
2389 s = bc_num_printNum(n, base, width, nchars, line_len, print);
2396 static BcStatus bc_num_stream(BcNum *n, BcNum *base, size_t *nchars, size_t len)
2398 return bc_num_printNum(n, base, 1, nchars, len, bc_num_printChar);
2402 static void bc_num_init(BcNum *n, size_t req)
2404 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2405 memset(n, 0, sizeof(BcNum));
2406 n->num = xmalloc(req);
2410 static void bc_num_expand(BcNum *n, size_t req)
2412 req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2414 n->num = xrealloc(n->num, req);
2419 static void bc_num_free(void *num)
2421 free(((BcNum *) num)->num);
2424 static void bc_num_copy(BcNum *d, BcNum *s)
2427 bc_num_expand(d, s->cap);
2431 memcpy(d->num, s->num, sizeof(BcDig) * d->len);
2435 static BcStatus bc_num_parse(BcNum *n, const char *val, BcNum *base,
2438 if (!bc_num_strValid(val, base_t)) return BC_STATUS_MATH_BAD_STRING;
2441 bc_num_parseDecimal(n, val);
2443 bc_num_parseBase(n, val, base);
2445 return BC_STATUS_SUCCESS;
2448 static BcStatus bc_num_print(BcNum *n, BcNum *base, size_t base_t, bool newline,
2449 size_t *nchars, size_t line_len)
2451 BcStatus s = BC_STATUS_SUCCESS;
2453 bc_num_printNewline(nchars, line_len);
2459 else if (base_t == 10)
2460 bc_num_printDecimal(n, nchars, line_len);
2462 s = bc_num_printBase(n, base, base_t, nchars, line_len);
2472 static BcStatus bc_num_ulong(BcNum *n, unsigned long *result)
2477 if (n->neg) return BC_STATUS_MATH_NEGATIVE;
2479 for (*result = 0, pow = 1, i = n->rdx; i < n->len; ++i) {
2481 unsigned long prev = *result, powprev = pow;
2483 *result += ((unsigned long) n->num[i]) * pow;
2486 if (*result < prev || pow < powprev) return BC_STATUS_MATH_OVERFLOW;
2489 return BC_STATUS_SUCCESS;
2492 static void bc_num_ulong2num(BcNum *n, unsigned long val)
2500 if (val == 0) return;
2502 for (len = 1, i = ULONG_MAX; i != 0; i /= 10, ++len) bc_num_expand(n, len);
2503 for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2506 static BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2508 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2510 return bc_num_binary(a, b, c, false, op, BC_NUM_AREQ(a, b));
2513 static BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2515 BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2517 return bc_num_binary(a, b, c, true, op, BC_NUM_AREQ(a, b));
2520 static BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2522 size_t req = BC_NUM_MREQ(a, b, scale);
2523 return bc_num_binary(a, b, c, scale, bc_num_m, req);
2526 static BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2528 size_t req = BC_NUM_MREQ(a, b, scale);
2529 return bc_num_binary(a, b, c, scale, bc_num_d, req);
2532 static BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2534 size_t req = BC_NUM_MREQ(a, b, scale);
2535 return bc_num_binary(a, b, c, scale, bc_num_rem, req);
2538 static BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale)
2540 return bc_num_binary(a, b, c, scale, bc_num_p, a->len * b->len + 1);
2543 static BcStatus bc_num_sqrt(BcNum *a, BcNum *restrict b, size_t scale)
2546 BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2547 size_t pow, len, digs, digs1, resrdx, req, times = 0;
2548 ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2550 req = BC_MAX(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1;
2551 bc_num_expand(b, req);
2554 bc_num_setToZero(b, scale);
2555 return BC_STATUS_SUCCESS;
2558 return BC_STATUS_MATH_NEGATIVE;
2559 else if (BC_NUM_ONE(a)) {
2561 bc_num_extend(b, scale);
2562 return BC_STATUS_SUCCESS;
2565 scale = BC_MAX(scale, a->rdx) + 1;
2566 len = a->len + scale;
2568 bc_num_init(&num1, len);
2569 bc_num_init(&num2, len);
2570 bc_num_init(&half, BC_NUM_DEF_SIZE);
2576 bc_num_init(&f, len);
2577 bc_num_init(&fprime, len);
2583 pow = BC_NUM_INT(a);
2592 pow -= 2 - (pow & 1);
2594 bc_num_extend(x0, pow);
2596 // Make sure to move the radix back.
2600 x0->rdx = digs = digs1 = 0;
2602 len = BC_NUM_INT(x0) + resrdx - 1;
2604 while (cmp != 0 || digs < len) {
2606 s = bc_num_div(a, x0, &f, resrdx);
2608 s = bc_num_add(x0, &f, &fprime, resrdx);
2610 s = bc_num_mul(&fprime, &half, x1, resrdx);
2613 cmp = bc_num_cmp(x1, x0);
2614 digs = x1->len - (unsigned long long) llabs(cmp);
2616 if (cmp == cmp2 && digs == digs1)
2621 resrdx += times > 4;
2634 if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2637 bc_num_free(&fprime);
2645 static BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d,
2651 size_t ts = BC_MAX(scale + b->rdx, a->rdx), len = BC_NUM_MREQ(a, b, ts);
2654 memcpy(&num2, c, sizeof(BcNum));
2656 bc_num_init(c, len);
2661 bc_num_expand(c, len);
2664 s = bc_num_r(ptr_a, b, c, d, scale, ts);
2666 if (init) bc_num_free(&num2);
2672 static BcStatus bc_num_modexp(BcNum *a, BcNum *b, BcNum *c, BcNum *restrict d)
2675 BcNum base, exp, two, temp;
2677 if (c->len == 0) return BC_STATUS_MATH_DIVIDE_BY_ZERO;
2678 if (a->rdx || b->rdx || c->rdx) return BC_STATUS_MATH_NON_INTEGER;
2679 if (b->neg) return BC_STATUS_MATH_NEGATIVE;
2681 bc_num_expand(d, c->len);
2682 bc_num_init(&base, c->len);
2683 bc_num_init(&exp, b->len);
2684 bc_num_init(&two, BC_NUM_DEF_SIZE);
2685 bc_num_init(&temp, b->len);
2691 s = bc_num_rem(a, c, &base, 0);
2693 bc_num_copy(&exp, b);
2695 while (exp.len != 0) {
2697 s = bc_num_divmod(&exp, &two, &exp, &temp, 0);
2700 if (BC_NUM_ONE(&temp)) {
2701 s = bc_num_mul(d, &base, &temp, 0);
2703 s = bc_num_rem(&temp, c, d, 0);
2707 s = bc_num_mul(&base, &base, &temp, 0);
2709 s = bc_num_rem(&temp, c, &base, 0);
2722 static int bc_id_cmp(const void *e1, const void *e2)
2724 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
2727 static void bc_id_free(void *id)
2729 free(((BcId *) id)->name);
2732 static BcStatus bc_func_insert(BcFunc *f, char *name, bool var)
2737 for (i = 0; i < f->autos.len; ++i) {
2738 if (!strcmp(name, ((BcId *) bc_vec_item(&f->autos, i))->name))
2739 return BC_STATUS_PARSE_DUPLICATE_LOCAL;
2745 bc_vec_push(&f->autos, &a);
2747 return BC_STATUS_SUCCESS;
2750 static void bc_func_init(BcFunc *f)
2752 bc_vec_init(&f->code, sizeof(char), NULL);
2753 bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);
2754 bc_vec_init(&f->labels, sizeof(size_t), NULL);
2758 static void bc_func_free(void *func)
2760 BcFunc *f = (BcFunc *) func;
2761 bc_vec_free(&f->code);
2762 bc_vec_free(&f->autos);
2763 bc_vec_free(&f->labels);
2766 static void bc_array_init(BcVec *a, bool nums)
2769 bc_vec_init(a, sizeof(BcNum), bc_num_free);
2771 bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2772 bc_array_expand(a, 1);
2775 static void bc_array_copy(BcVec *d, const BcVec *s)
2779 bc_vec_npop(d, d->len);
2780 bc_vec_expand(d, s->cap);
2783 for (i = 0; i < s->len; ++i) {
2784 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2785 bc_num_init(dnum, snum->len);
2786 bc_num_copy(dnum, snum);
2790 static void bc_array_expand(BcVec *a, size_t len)
2794 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2795 while (len > a->len) {
2796 bc_num_init(&data.n, BC_NUM_DEF_SIZE);
2797 bc_vec_push(a, &data.n);
2801 while (len > a->len) {
2802 bc_array_init(&data.v, true);
2803 bc_vec_push(a, &data.v);
2808 static void bc_string_free(void *string)
2810 free(*((char **) string));
2814 static void bc_result_copy(BcResult *d, BcResult *src)
2820 case BC_RESULT_TEMP:
2821 case BC_RESULT_IBASE:
2822 case BC_RESULT_SCALE:
2823 case BC_RESULT_OBASE:
2825 bc_num_init(&d->d.n, src->d.n.len);
2826 bc_num_copy(&d->d.n, &src->d.n);
2831 case BC_RESULT_ARRAY:
2832 case BC_RESULT_ARRAY_ELEM:
2834 d->d.id.name = xstrdup(src->d.id.name);
2838 case BC_RESULT_CONSTANT:
2839 case BC_RESULT_LAST:
2843 memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
2850 static void bc_result_free(void *result)
2852 BcResult *r = (BcResult *) result;
2856 case BC_RESULT_TEMP:
2857 case BC_RESULT_IBASE:
2858 case BC_RESULT_SCALE:
2859 case BC_RESULT_OBASE:
2861 bc_num_free(&r->d.n);
2866 case BC_RESULT_ARRAY:
2867 case BC_RESULT_ARRAY_ELEM:
2881 static void bc_lex_lineComment(BcLex *l)
2883 l->t.t = BC_LEX_WHITESPACE;
2884 while (l->i < l->len && l->buf[l->i++] != '\n');
2888 static void bc_lex_whitespace(BcLex *l)
2891 l->t.t = BC_LEX_WHITESPACE;
2892 for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2895 static BcStatus bc_lex_number(BcLex *l, char start)
2897 const char *buf = l->buf + l->i;
2898 size_t len, hits = 0, bslashes = 0, i = 0, j;
2900 bool last_pt, pt = start == '.';
2903 l->t.t = BC_LEX_NUMBER;
2905 while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') ||
2906 (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n')))
2920 len = i + 1 * !last_pt - bslashes * 2;
2921 if (len > BC_MAX_NUM) return BC_STATUS_EXEC_NUM_LEN;
2923 bc_vec_npop(&l->t.v, l->t.v.len);
2924 bc_vec_expand(&l->t.v, len + 1);
2925 bc_vec_push(&l->t.v, &start);
2927 for (buf -= 1, j = 1; j < len + hits * 2; ++j) {
2931 // If we have hit a backslash, skip it. We don't have
2932 // to check for a newline because it's guaranteed.
2933 if (hits < bslashes && c == '\\') {
2939 bc_vec_push(&l->t.v, &c);
2942 bc_vec_pushByte(&l->t.v, '\0');
2945 return BC_STATUS_SUCCESS;
2948 static BcStatus bc_lex_name(BcLex *l)
2951 const char *buf = l->buf + l->i - 1;
2954 l->t.t = BC_LEX_NAME;
2956 while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2958 if (i > BC_MAX_STRING) return BC_STATUS_EXEC_NAME_LEN;
2959 bc_vec_string(&l->t.v, i, buf);
2961 // Increment the index. We minus 1 because it has already been incremented.
2964 return BC_STATUS_SUCCESS;
2967 static void bc_lex_init(BcLex *l, BcLexNext next)
2970 bc_vec_init(&l->t.v, sizeof(char), NULL);
2973 static void bc_lex_free(BcLex *l)
2975 bc_vec_free(&l->t.v);
2978 static void bc_lex_file(BcLex *l, const char *file)
2985 static BcStatus bc_lex_next(BcLex *l)
2990 if (l->t.last == BC_LEX_EOF) return BC_STATUS_LEX_EOF;
2992 l->line += l->newline;
2993 l->t.t = BC_LEX_EOF;
2995 l->newline = (l->i == l->len);
2996 if (l->newline) return BC_STATUS_SUCCESS;
2998 // Loop until failure or we don't have whitespace. This
2999 // is so the parser doesn't get inundated with whitespace.
3002 } while (!s && l->t.t == BC_LEX_WHITESPACE);
3007 static BcStatus bc_lex_text(BcLex *l, const char *text)
3011 l->len = strlen(text);
3012 l->t.t = l->t.last = BC_LEX_INVALID;
3013 return bc_lex_next(l);
3017 static BcStatus bc_lex_identifier(BcLex *l)
3021 const char *buf = l->buf + l->i - 1;
3023 for (i = 0; i < sizeof(bc_lex_kws) / sizeof(bc_lex_kws[0]); ++i) {
3025 unsigned long len = (unsigned long) bc_lex_kws[i].len;
3027 if (strncmp(buf, bc_lex_kws[i].name, len) == 0) {
3029 l->t.t = BC_LEX_KEY_AUTO + (BcLexType) i;
3031 if (!bc_lex_kws[i].posix) {
3032 s = bc_vm_posixError(BC_STATUS_POSIX_BAD_KW, l->f, l->line,
3033 bc_lex_kws[i].name);
3037 // We minus 1 because the index has already been incremented.
3039 return BC_STATUS_SUCCESS;
3046 if (l->t.v.len - 1 > 1)
3047 s = bc_vm_posixError(BC_STATUS_POSIX_NAME_LEN, l->f, l->line, buf);
3052 static BcStatus bc_lex_string(BcLex *l)
3054 size_t len, nls = 0, i = l->i;
3057 l->t.t = BC_LEX_STR;
3059 for (c = l->buf[i]; c != 0 && c != '"'; c = l->buf[++i]) nls += (c == '\n');
3063 return BC_STATUS_LEX_NO_STRING_END;
3067 if (len > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3068 bc_vec_string(&l->t.v, len, l->buf + l->i);
3073 return BC_STATUS_SUCCESS;
3076 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without)
3078 if (l->buf[l->i] == '=') {
3086 static BcStatus bc_lex_comment(BcLex *l)
3089 const char *buf = l->buf;
3091 l->t.t = BC_LEX_WHITESPACE;
3104 return BC_STATUS_LEX_NO_COMMENT_END;
3113 return BC_STATUS_SUCCESS;
3116 static BcStatus bc_lex_token(BcLex *l)
3118 BcStatus s = BC_STATUS_SUCCESS;
3119 char c = l->buf[l->i++], c2;
3121 // This is the workhorse of the lexer.
3128 l->t.t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
3138 bc_lex_whitespace(l);
3144 bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
3146 if (l->t.t == BC_LEX_OP_BOOL_NOT) {
3147 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "!");
3156 s = bc_lex_string(l);
3162 s = bc_vm_posixError(BC_STATUS_POSIX_COMMENT, l->f, l->line, NULL);
3165 bc_lex_lineComment(l);
3172 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
3181 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "&&");
3185 l->t.t = BC_LEX_OP_BOOL_AND;
3188 l->t.t = BC_LEX_INVALID;
3189 s = bc_error("bad character '%c'", '&');
3198 l->t.t = (BcLexType)(c - '(' + BC_LEX_LPAREN);
3204 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
3213 l->t.t = BC_LEX_OP_INC;
3216 bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
3222 l->t.t = BC_LEX_COMMA;
3231 l->t.t = BC_LEX_OP_DEC;
3234 bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
3240 if (isdigit(l->buf[l->i]))
3241 s = bc_lex_number(l, c);
3243 l->t.t = BC_LEX_KEY_LAST;
3244 s = bc_vm_posixError(BC_STATUS_POSIX_DOT, l->f, l->line, NULL);
3253 s = bc_lex_comment(l);
3255 bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
3276 s = bc_lex_number(l, c);
3282 l->t.t = BC_LEX_SCOLON;
3288 bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
3294 bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
3300 bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
3307 l->t.t = (BcLexType)(c - '[' + BC_LEX_LBRACKET);
3313 if (l->buf[l->i] == '\n') {
3314 l->t.t = BC_LEX_WHITESPACE;
3318 s = bc_error("bad character '%c'", c);
3324 bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
3355 s = bc_lex_identifier(l);
3362 l->t.t = (BcLexType)(c - '{' + BC_LEX_LBRACE);
3372 s = bc_vm_posixError(BC_STATUS_POSIX_BOOL, l->f, l->line, "||");
3376 l->t.t = BC_LEX_OP_BOOL_OR;
3379 l->t.t = BC_LEX_INVALID;
3380 s = bc_error("bad character '%c'", c);
3388 l->t.t = BC_LEX_INVALID;
3389 s = bc_error("bad character '%c'", c);
3399 static BcStatus dc_lex_register(BcLex *l)
3401 BcStatus s = BC_STATUS_SUCCESS;
3403 if (isspace(l->buf[l->i - 1])) {
3404 bc_lex_whitespace(l);
3407 s = BC_STATUS_LEX_EXTENDED_REG;
3412 bc_vec_npop(&l->t.v, l->t.v.len);
3413 bc_vec_pushByte(&l->t.v, l->buf[l->i - 1]);
3414 bc_vec_pushByte(&l->t.v, '\0');
3415 l->t.t = BC_LEX_NAME;
3421 static BcStatus dc_lex_string(BcLex *l)
3423 size_t depth = 1, nls = 0, i = l->i;
3426 l->t.t = BC_LEX_STR;
3427 bc_vec_npop(&l->t.v, l->t.v.len);
3429 for (c = l->buf[i]; c != 0 && depth; c = l->buf[++i]) {
3431 depth += (c == '[' && (i == l->i || l->buf[i - 1] != '\\'));
3432 depth -= (c == ']' && (i == l->i || l->buf[i - 1] != '\\'));
3435 if (depth) bc_vec_push(&l->t.v, &c);
3440 return BC_STATUS_LEX_NO_STRING_END;
3443 bc_vec_pushByte(&l->t.v, '\0');
3444 if (i - l->i > BC_MAX_STRING) return BC_STATUS_EXEC_STRING_LEN;
3449 return BC_STATUS_SUCCESS;
3452 static BcStatus dc_lex_token(BcLex *l)
3454 BcStatus s = BC_STATUS_SUCCESS;
3455 char c = l->buf[l->i++], c2;
3458 for (i = 0; i < dc_lex_regs_len; ++i) {
3459 if (l->t.last == dc_lex_regs[i]) return dc_lex_register(l);
3462 if (c >= '%' && c <= '~' &&
3463 (l->t.t = dc_lex_tokens[(c - '%')]) != BC_LEX_INVALID)
3468 // This is the workhorse of the lexer.
3473 l->t.t = BC_LEX_EOF;
3484 l->newline = (c == '\n');
3485 bc_lex_whitespace(l);
3494 l->t.t = BC_LEX_OP_REL_NE;
3496 l->t.t = BC_LEX_OP_REL_LE;
3498 l->t.t = BC_LEX_OP_REL_GE;
3500 return bc_error("bad character '%c'", c);
3508 bc_lex_lineComment(l);
3514 if (isdigit(l->buf[l->i]))
3515 s = bc_lex_number(l, c);
3517 s = bc_error("bad character '%c'", c);
3538 s = bc_lex_number(l, c);
3544 s = dc_lex_string(l);
3550 l->t.t = BC_LEX_INVALID;
3551 s = bc_error("bad character '%c'", c);
3560 static void bc_parse_addFunc(BcParse *p, char *name, size_t *idx)
3562 bc_program_addFunc(name, idx);
3563 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3566 static void bc_parse_pushName(BcParse *p, char *name)
3568 size_t i = 0, len = strlen(name);
3570 for (; i < len; ++i) bc_parse_push(p, name[i]);
3571 bc_parse_push(p, BC_PARSE_STREND);
3576 static void bc_parse_pushIndex(BcParse *p, size_t idx)
3578 unsigned char amt, i, nums[sizeof(size_t)];
3580 for (amt = 0; idx; ++amt) {
3581 nums[amt] = (char) idx;
3582 idx = (idx & ((unsigned long) ~(UCHAR_MAX))) >> sizeof(char) * CHAR_BIT;
3585 bc_parse_push(p, amt);
3586 for (i = 0; i < amt; ++i) bc_parse_push(p, nums[i]);
3589 static void bc_parse_number(BcParse *p, BcInst *prev, size_t *nexs)
3591 char *num = xstrdup(p->l.t.v.v);
3592 size_t idx = G.prog.consts.len;
3594 bc_vec_push(&G.prog.consts, &num);
3596 bc_parse_push(p, BC_INST_NUM);
3597 bc_parse_pushIndex(p, idx);
3600 (*prev) = BC_INST_NUM;
3603 static BcStatus bc_parse_text(BcParse *p, const char *text)
3607 p->func = bc_vec_item(&G.prog.fns, p->fidx);
3609 if (!strcmp(text, "") && !BC_PARSE_CAN_EXEC(p)) {
3610 p->l.t.t = BC_LEX_INVALID;
3613 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
3616 return bc_lex_text(&p->l, text);
3619 // Called when bc/dc_parse_parse() detects a failure,
3620 // resets parsing structures.
3621 static void bc_parse_reset(BcParse *p)
3623 if (p->fidx != BC_PROG_MAIN) {
3625 p->func->nparams = 0;
3626 bc_vec_npop(&p->func->code, p->func->code.len);
3627 bc_vec_npop(&p->func->autos, p->func->autos.len);
3628 bc_vec_npop(&p->func->labels, p->func->labels.len);
3630 bc_parse_updateFunc(p, BC_PROG_MAIN);
3634 p->l.t.t = BC_LEX_EOF;
3635 p->auto_part = (p->nbraces = 0);
3637 bc_vec_npop(&p->flags, p->flags.len - 1);
3638 bc_vec_npop(&p->exits, p->exits.len);
3639 bc_vec_npop(&p->conds, p->conds.len);
3640 bc_vec_npop(&p->ops, p->ops.len);
3645 static void bc_parse_free(BcParse *p)
3647 bc_vec_free(&p->flags);
3648 bc_vec_free(&p->exits);
3649 bc_vec_free(&p->conds);
3650 bc_vec_free(&p->ops);
3654 static void bc_parse_create(BcParse *p, size_t func,
3655 BcParseParse parse, BcLexNext next)
3657 memset(p, 0, sizeof(BcParse));
3659 bc_lex_init(&p->l, next);
3660 bc_vec_init(&p->flags, sizeof(uint8_t), NULL);
3661 bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3662 bc_vec_init(&p->conds, sizeof(size_t), NULL);
3663 bc_vec_pushByte(&p->flags, 0);
3664 bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3667 // p->auto_part = p->nbraces = 0; - already is
3668 bc_parse_updateFunc(p, func);
3672 static BcStatus bc_parse_else(BcParse *p);
3673 static BcStatus bc_parse_stmt(BcParse *p);
3675 static BcStatus bc_parse_operator(BcParse *p, BcLexType type, size_t start,
3676 size_t *nexprs, bool next)
3678 BcStatus s = BC_STATUS_SUCCESS;
3680 char l, r = bc_parse_ops[type - BC_LEX_OP_INC].prec;
3681 bool left = bc_parse_ops[type - BC_LEX_OP_INC].left;
3683 while (p->ops.len > start) {
3685 t = BC_PARSE_TOP_OP(p);
3686 if (t == BC_LEX_LPAREN) break;
3688 l = bc_parse_ops[t - BC_LEX_OP_INC].prec;
3689 if (l >= r && (l != r || !left)) break;
3691 bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3692 bc_vec_pop(&p->ops);
3693 *nexprs -= t != BC_LEX_OP_BOOL_NOT && t != BC_LEX_NEG;
3696 bc_vec_push(&p->ops, &type);
3697 if (next) s = bc_lex_next(&p->l);
3702 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs)
3706 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3707 top = BC_PARSE_TOP_OP(p);
3709 while (top != BC_LEX_LPAREN) {
3711 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3713 bc_vec_pop(&p->ops);
3714 *nexs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
3716 if (p->ops.len <= ops_bgn) return BC_STATUS_PARSE_BAD_EXP;
3717 top = BC_PARSE_TOP_OP(p);
3720 bc_vec_pop(&p->ops);
3722 return bc_lex_next(&p->l);
3725 static BcStatus bc_parse_params(BcParse *p, uint8_t flags)
3731 s = bc_lex_next(&p->l);
3734 for (nparams = 0; p->l.t.t != BC_LEX_RPAREN; ++nparams) {
3736 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3737 s = bc_parse_expr(p, flags, bc_parse_next_param);
3740 comma = p->l.t.t == BC_LEX_COMMA;
3742 s = bc_lex_next(&p->l);
3747 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
3748 bc_parse_push(p, BC_INST_CALL);
3749 bc_parse_pushIndex(p, nparams);
3751 return BC_STATUS_SUCCESS;
3754 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags)
3757 BcId entry, *entry_ptr;
3762 s = bc_parse_params(p, flags);
3765 if (p->l.t.t != BC_LEX_RPAREN) {
3766 s = BC_STATUS_PARSE_BAD_TOKEN;
3770 idx = bc_map_index(&G.prog.fn_map, &entry);
3772 if (idx == BC_VEC_INVALID_IDX) {
3773 name = xstrdup(entry.name);
3774 bc_parse_addFunc(p, name, &idx);
3775 idx = bc_map_index(&G.prog.fn_map, &entry);
3781 entry_ptr = bc_vec_item(&G.prog.fn_map, idx);
3782 bc_parse_pushIndex(p, entry_ptr->idx);
3784 return bc_lex_next(&p->l);
3791 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags)
3796 name = xstrdup(p->l.t.v.v);
3797 s = bc_lex_next(&p->l);
3800 if (p->l.t.t == BC_LEX_LBRACKET) {
3802 s = bc_lex_next(&p->l);
3805 if (p->l.t.t == BC_LEX_RBRACKET) {
3807 if (!(flags & BC_PARSE_ARRAY)) {
3808 s = BC_STATUS_PARSE_BAD_EXP;
3812 *type = BC_INST_ARRAY;
3816 *type = BC_INST_ARRAY_ELEM;
3818 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3819 s = bc_parse_expr(p, flags, bc_parse_next_elem);
3823 s = bc_lex_next(&p->l);
3825 bc_parse_push(p, *type);
3826 bc_parse_pushName(p, name);
3828 else if (p->l.t.t == BC_LEX_LPAREN) {
3830 if (flags & BC_PARSE_NOCALL) {
3831 s = BC_STATUS_PARSE_BAD_TOKEN;
3835 *type = BC_INST_CALL;
3836 s = bc_parse_call(p, name, flags);
3839 *type = BC_INST_VAR;
3840 bc_parse_push(p, BC_INST_VAR);
3841 bc_parse_pushName(p, name);
3851 static BcStatus bc_parse_read(BcParse *p)
3855 s = bc_lex_next(&p->l);
3857 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3859 s = bc_lex_next(&p->l);
3861 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3863 bc_parse_push(p, BC_INST_READ);
3865 return bc_lex_next(&p->l);
3868 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type, uint8_t flags,
3873 s = bc_lex_next(&p->l);
3875 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3877 flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3879 s = bc_lex_next(&p->l);
3882 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3885 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3887 *prev = (type == BC_LEX_KEY_LENGTH) ? BC_INST_LENGTH : BC_INST_SQRT;
3888 bc_parse_push(p, *prev);
3890 return bc_lex_next(&p->l);
3893 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags)
3897 s = bc_lex_next(&p->l);
3900 if (p->l.t.t != BC_LEX_LPAREN) {
3901 *type = BC_INST_SCALE;
3902 bc_parse_push(p, BC_INST_SCALE);
3903 return BC_STATUS_SUCCESS;
3906 *type = BC_INST_SCALE_FUNC;
3907 flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3909 s = bc_lex_next(&p->l);
3912 s = bc_parse_expr(p, flags, bc_parse_next_rel);
3914 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
3915 bc_parse_push(p, BC_INST_SCALE_FUNC);
3917 return bc_lex_next(&p->l);
3920 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev, bool *paren_expr,
3921 size_t *nexprs, uint8_t flags)
3926 BcInst etype = *prev;
3928 if (etype == BC_INST_VAR || etype == BC_INST_ARRAY_ELEM ||
3929 etype == BC_INST_SCALE || etype == BC_INST_LAST ||
3930 etype == BC_INST_IBASE || etype == BC_INST_OBASE)
3932 *prev = inst = BC_INST_INC_POST + (p->l.t.t != BC_LEX_OP_INC);
3933 bc_parse_push(p, inst);
3934 s = bc_lex_next(&p->l);
3938 *prev = inst = BC_INST_INC_PRE + (p->l.t.t != BC_LEX_OP_INC);
3941 s = bc_lex_next(&p->l);
3945 // Because we parse the next part of the expression
3946 // right here, we need to increment this.
3947 *nexprs = *nexprs + 1;
3953 s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3957 case BC_LEX_KEY_IBASE:
3958 case BC_LEX_KEY_LAST:
3959 case BC_LEX_KEY_OBASE:
3961 bc_parse_push(p, type - BC_LEX_KEY_IBASE + BC_INST_IBASE);
3962 s = bc_lex_next(&p->l);
3966 case BC_LEX_KEY_SCALE:
3968 s = bc_lex_next(&p->l);
3970 if (p->l.t.t == BC_LEX_LPAREN)
3971 s = BC_STATUS_PARSE_BAD_TOKEN;
3973 bc_parse_push(p, BC_INST_SCALE);
3979 s = BC_STATUS_PARSE_BAD_TOKEN;
3984 if (!s) bc_parse_push(p, inst);
3990 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3991 bool rparen, size_t *nexprs)
3995 BcInst etype = *prev;
3997 s = bc_lex_next(&p->l);
4000 type = rparen || etype == BC_INST_INC_POST || etype == BC_INST_DEC_POST ||
4001 (etype >= BC_INST_NUM && etype <= BC_INST_SQRT) ?
4004 *prev = BC_PARSE_TOKEN_INST(type);
4006 // We can just push onto the op stack because this is the largest
4007 // precedence operator that gets pushed. Inc/dec does not.
4008 if (type != BC_LEX_OP_MINUS)
4009 bc_vec_push(&p->ops, &type);
4011 s = bc_parse_operator(p, type, ops_bgn, nexprs, false);
4016 static BcStatus bc_parse_string(BcParse *p, char inst)
4018 char *str = xstrdup(p->l.t.v.v);
4020 bc_parse_push(p, BC_INST_STR);
4021 bc_parse_pushIndex(p, G.prog.strs.len);
4022 bc_vec_push(&G.prog.strs, &str);
4023 bc_parse_push(p, inst);
4025 return bc_lex_next(&p->l);
4028 static BcStatus bc_parse_print(BcParse *p)
4034 s = bc_lex_next(&p->l);
4039 if (type == BC_LEX_SCOLON || type == BC_LEX_NLINE)
4040 return BC_STATUS_PARSE_BAD_PRINT;
4042 while (!s && type != BC_LEX_SCOLON && type != BC_LEX_NLINE) {
4044 if (type == BC_LEX_STR)
4045 s = bc_parse_string(p, BC_INST_PRINT_POP);
4047 s = bc_parse_expr(p, 0, bc_parse_next_print);
4049 bc_parse_push(p, BC_INST_PRINT_POP);
4054 comma = p->l.t.t == BC_LEX_COMMA;
4055 if (comma) s = bc_lex_next(&p->l);
4060 if (comma) return BC_STATUS_PARSE_BAD_TOKEN;
4062 return bc_lex_next(&p->l);
4065 static BcStatus bc_parse_return(BcParse *p)
4071 if (!BC_PARSE_FUNC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4073 s = bc_lex_next(&p->l);
4077 paren = t == BC_LEX_LPAREN;
4079 if (t == BC_LEX_NLINE || t == BC_LEX_SCOLON)
4080 bc_parse_push(p, BC_INST_RET0);
4083 s = bc_parse_expr(p, 0, bc_parse_next_expr);
4084 if (s && s != BC_STATUS_PARSE_EMPTY_EXP)
4086 else if (s == BC_STATUS_PARSE_EMPTY_EXP) {
4087 bc_parse_push(p, BC_INST_RET0);
4088 s = bc_lex_next(&p->l);
4092 if (!paren || p->l.t.last != BC_LEX_RPAREN) {
4093 s = bc_vm_posixError(BC_STATUS_POSIX_RET, p->l.f, p->l.line, NULL);
4097 bc_parse_push(p, BC_INST_RET);
4103 static BcStatus bc_parse_endBody(BcParse *p, bool brace)
4105 BcStatus s = BC_STATUS_SUCCESS;
4107 if (p->flags.len <= 1 || (brace && p->nbraces == 0))
4108 return BC_STATUS_PARSE_BAD_TOKEN;
4112 if (p->l.t.t == BC_LEX_RBRACE) {
4113 if (!p->nbraces) return BC_STATUS_PARSE_BAD_TOKEN;
4115 s = bc_lex_next(&p->l);
4119 return BC_STATUS_PARSE_BAD_TOKEN;
4122 if (BC_PARSE_IF(p)) {
4126 while (p->l.t.t == BC_LEX_NLINE) {
4127 s = bc_lex_next(&p->l);
4131 bc_vec_pop(&p->flags);
4133 flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4134 *flag_ptr = (*flag_ptr | BC_PARSE_FLAG_IF_END);
4136 if (p->l.t.t == BC_LEX_KEY_ELSE) s = bc_parse_else(p);
4138 else if (BC_PARSE_ELSE(p)) {
4143 bc_vec_pop(&p->flags);
4145 ip = bc_vec_top(&p->exits);
4146 label = bc_vec_item(&p->func->labels, ip->idx);
4147 *label = p->func->code.len;
4149 bc_vec_pop(&p->exits);
4151 else if (BC_PARSE_FUNC_INNER(p)) {
4152 bc_parse_push(p, BC_INST_RET0);
4153 bc_parse_updateFunc(p, BC_PROG_MAIN);
4154 bc_vec_pop(&p->flags);
4158 BcInstPtr *ip = bc_vec_top(&p->exits);
4159 size_t *label = bc_vec_top(&p->conds);
4161 bc_parse_push(p, BC_INST_JUMP);
4162 bc_parse_pushIndex(p, *label);
4164 label = bc_vec_item(&p->func->labels, ip->idx);
4165 *label = p->func->code.len;
4167 bc_vec_pop(&p->flags);
4168 bc_vec_pop(&p->exits);
4169 bc_vec_pop(&p->conds);
4175 static void bc_parse_startBody(BcParse *p, uint8_t flags)
4177 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4178 flags |= (*flag_ptr & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
4179 flags |= BC_PARSE_FLAG_BODY;
4180 bc_vec_push(&p->flags, &flags);
4183 static void bc_parse_noElse(BcParse *p)
4187 uint8_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
4189 *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
4191 ip = bc_vec_top(&p->exits);
4192 label = bc_vec_item(&p->func->labels, ip->idx);
4193 *label = p->func->code.len;
4195 bc_vec_pop(&p->exits);
4198 static BcStatus bc_parse_if(BcParse *p)
4203 s = bc_lex_next(&p->l);
4205 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4207 s = bc_lex_next(&p->l);
4209 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4211 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4213 s = bc_lex_next(&p->l);
4215 bc_parse_push(p, BC_INST_JUMP_ZERO);
4217 ip.idx = p->func->labels.len;
4218 ip.func = ip.len = 0;
4220 bc_parse_pushIndex(p, ip.idx);
4221 bc_vec_push(&p->exits, &ip);
4222 bc_vec_push(&p->func->labels, &ip.idx);
4223 bc_parse_startBody(p, BC_PARSE_FLAG_IF);
4225 return BC_STATUS_SUCCESS;
4228 static BcStatus bc_parse_else(BcParse *p)
4232 if (!BC_PARSE_IF_END(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4234 ip.idx = p->func->labels.len;
4235 ip.func = ip.len = 0;
4237 bc_parse_push(p, BC_INST_JUMP);
4238 bc_parse_pushIndex(p, ip.idx);
4242 bc_vec_push(&p->exits, &ip);
4243 bc_vec_push(&p->func->labels, &ip.idx);
4244 bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
4246 return bc_lex_next(&p->l);
4249 static BcStatus bc_parse_while(BcParse *p)
4254 s = bc_lex_next(&p->l);
4256 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4257 s = bc_lex_next(&p->l);
4260 ip.idx = p->func->labels.len;
4262 bc_vec_push(&p->func->labels, &p->func->code.len);
4263 bc_vec_push(&p->conds, &ip.idx);
4265 ip.idx = p->func->labels.len;
4269 bc_vec_push(&p->exits, &ip);
4270 bc_vec_push(&p->func->labels, &ip.idx);
4272 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_rel);
4274 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4275 s = bc_lex_next(&p->l);
4278 bc_parse_push(p, BC_INST_JUMP_ZERO);
4279 bc_parse_pushIndex(p, ip.idx);
4280 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4282 return BC_STATUS_SUCCESS;
4285 static BcStatus bc_parse_for(BcParse *p)
4289 size_t cond_idx, exit_idx, body_idx, update_idx;
4291 s = bc_lex_next(&p->l);
4293 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4294 s = bc_lex_next(&p->l);
4297 if (p->l.t.t != BC_LEX_SCOLON)
4298 s = bc_parse_expr(p, 0, bc_parse_next_for);
4300 s = bc_vm_posixError(BC_STATUS_POSIX_FOR1, p->l.f, p->l.line, NULL);
4303 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4304 s = bc_lex_next(&p->l);
4307 cond_idx = p->func->labels.len;
4308 update_idx = cond_idx + 1;
4309 body_idx = update_idx + 1;
4310 exit_idx = body_idx + 1;
4312 bc_vec_push(&p->func->labels, &p->func->code.len);
4314 if (p->l.t.t != BC_LEX_SCOLON)
4315 s = bc_parse_expr(p, BC_PARSE_REL, bc_parse_next_for);
4317 s = bc_vm_posixError(BC_STATUS_POSIX_FOR2, p->l.f, p->l.line, NULL);
4320 if (p->l.t.t != BC_LEX_SCOLON) return BC_STATUS_PARSE_BAD_TOKEN;
4322 s = bc_lex_next(&p->l);
4325 bc_parse_push(p, BC_INST_JUMP_ZERO);
4326 bc_parse_pushIndex(p, exit_idx);
4327 bc_parse_push(p, BC_INST_JUMP);
4328 bc_parse_pushIndex(p, body_idx);
4330 ip.idx = p->func->labels.len;
4332 bc_vec_push(&p->conds, &update_idx);
4333 bc_vec_push(&p->func->labels, &p->func->code.len);
4335 if (p->l.t.t != BC_LEX_RPAREN)
4336 s = bc_parse_expr(p, 0, bc_parse_next_rel);
4338 s = bc_vm_posixError(BC_STATUS_POSIX_FOR3, p->l.f, p->l.line, NULL);
4342 if (p->l.t.t != BC_LEX_RPAREN) return BC_STATUS_PARSE_BAD_TOKEN;
4343 bc_parse_push(p, BC_INST_JUMP);
4344 bc_parse_pushIndex(p, cond_idx);
4345 bc_vec_push(&p->func->labels, &p->func->code.len);
4351 bc_vec_push(&p->exits, &ip);
4352 bc_vec_push(&p->func->labels, &ip.idx);
4354 bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
4356 return BC_STATUS_SUCCESS;
4359 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type)
4365 if (!BC_PARSE_LOOP(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4367 if (type == BC_LEX_KEY_BREAK) {
4369 if (p->exits.len == 0) return BC_STATUS_PARSE_BAD_TOKEN;
4371 i = p->exits.len - 1;
4372 ip = bc_vec_item(&p->exits, i);
4374 while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
4375 if (i >= p->exits.len && !ip->func) return BC_STATUS_PARSE_BAD_TOKEN;
4380 i = *((size_t *) bc_vec_top(&p->conds));
4382 bc_parse_push(p, BC_INST_JUMP);
4383 bc_parse_pushIndex(p, i);
4385 s = bc_lex_next(&p->l);
4388 if (p->l.t.t != BC_LEX_SCOLON && p->l.t.t != BC_LEX_NLINE)
4389 return BC_STATUS_PARSE_BAD_TOKEN;
4391 return bc_lex_next(&p->l);
4394 static BcStatus bc_parse_func(BcParse *p)
4397 bool var, comma = false;
4401 s = bc_lex_next(&p->l);
4403 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4405 name = xstrdup(p->l.t.v.v);
4406 bc_parse_addFunc(p, name, &p->fidx);
4408 s = bc_lex_next(&p->l);
4410 if (p->l.t.t != BC_LEX_LPAREN) return BC_STATUS_PARSE_BAD_FUNC;
4411 s = bc_lex_next(&p->l);
4414 while (p->l.t.t != BC_LEX_RPAREN) {
4416 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_FUNC;
4420 name = xstrdup(p->l.t.v.v);
4421 s = bc_lex_next(&p->l);
4424 var = p->l.t.t != BC_LEX_LBRACKET;
4428 s = bc_lex_next(&p->l);
4431 if (p->l.t.t != BC_LEX_RBRACKET) {
4432 s = BC_STATUS_PARSE_BAD_FUNC;
4436 s = bc_lex_next(&p->l);
4440 comma = p->l.t.t == BC_LEX_COMMA;
4442 s = bc_lex_next(&p->l);
4446 s = bc_func_insert(p->func, name, var);
4450 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4452 flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
4453 bc_parse_startBody(p, flags);
4455 s = bc_lex_next(&p->l);
4458 if (p->l.t.t != BC_LEX_LBRACE)
4459 s = bc_vm_posixError(BC_STATUS_POSIX_BRACE, p->l.f, p->l.line, NULL);
4468 static BcStatus bc_parse_auto(BcParse *p)
4471 bool comma, var, one;
4474 if (!p->auto_part) return BC_STATUS_PARSE_BAD_TOKEN;
4475 s = bc_lex_next(&p->l);
4478 p->auto_part = comma = false;
4479 one = p->l.t.t == BC_LEX_NAME;
4481 while (p->l.t.t == BC_LEX_NAME) {
4483 name = xstrdup(p->l.t.v.v);
4484 s = bc_lex_next(&p->l);
4487 var = p->l.t.t != BC_LEX_LBRACKET;
4490 s = bc_lex_next(&p->l);
4493 if (p->l.t.t != BC_LEX_RBRACKET) {
4494 s = BC_STATUS_PARSE_BAD_FUNC;
4498 s = bc_lex_next(&p->l);
4502 comma = p->l.t.t == BC_LEX_COMMA;
4504 s = bc_lex_next(&p->l);
4508 s = bc_func_insert(p->func, name, var);
4512 if (comma) return BC_STATUS_PARSE_BAD_FUNC;
4513 if (!one) return bc_error("no auto variable found");
4515 if (p->l.t.t != BC_LEX_NLINE && p->l.t.t != BC_LEX_SCOLON)
4516 return BC_STATUS_PARSE_BAD_TOKEN;
4518 return bc_lex_next(&p->l);
4525 static BcStatus bc_parse_body(BcParse *p, bool brace)
4527 BcStatus s = BC_STATUS_SUCCESS;
4528 uint8_t *flag_ptr = bc_vec_top(&p->flags);
4530 *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
4532 if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
4534 if (!brace) return BC_STATUS_PARSE_BAD_TOKEN;
4535 p->auto_part = p->l.t.t != BC_LEX_KEY_AUTO;
4537 if (!p->auto_part) {
4538 s = bc_parse_auto(p);
4542 if (p->l.t.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4545 s = bc_parse_stmt(p);
4546 if (!s && !brace) s = bc_parse_endBody(p, false);
4552 static BcStatus bc_parse_stmt(BcParse *p)
4554 BcStatus s = BC_STATUS_SUCCESS;
4560 return bc_lex_next(&p->l);
4563 case BC_LEX_KEY_ELSE:
4565 p->auto_part = false;
4571 if (!BC_PARSE_BODY(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4574 s = bc_lex_next(&p->l);
4577 return bc_parse_body(p, true);
4580 case BC_LEX_KEY_AUTO:
4582 return bc_parse_auto(p);
4587 p->auto_part = false;
4589 if (BC_PARSE_IF_END(p)) {
4591 return BC_STATUS_SUCCESS;
4593 else if (BC_PARSE_BODY(p))
4594 return bc_parse_body(p, false);
4604 case BC_LEX_OP_MINUS:
4605 case BC_LEX_OP_BOOL_NOT:
4609 case BC_LEX_KEY_IBASE:
4610 case BC_LEX_KEY_LAST:
4611 case BC_LEX_KEY_LENGTH:
4612 case BC_LEX_KEY_OBASE:
4613 case BC_LEX_KEY_READ:
4614 case BC_LEX_KEY_SCALE:
4615 case BC_LEX_KEY_SQRT:
4617 s = bc_parse_expr(p, BC_PARSE_PRINT, bc_parse_next_expr);
4621 case BC_LEX_KEY_ELSE:
4623 s = bc_parse_else(p);
4629 while (!s && p->l.t.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4635 s = bc_parse_endBody(p, true);
4641 s = bc_parse_string(p, BC_INST_PRINT_STR);
4645 case BC_LEX_KEY_BREAK:
4646 case BC_LEX_KEY_CONTINUE:
4648 s = bc_parse_loopExit(p, p->l.t.t);
4652 case BC_LEX_KEY_FOR:
4654 s = bc_parse_for(p);
4658 case BC_LEX_KEY_HALT:
4660 bc_parse_push(p, BC_INST_HALT);
4661 s = bc_lex_next(&p->l);
4671 case BC_LEX_KEY_LIMITS:
4673 // "limits" is a compile-time command,
4674 // the output is produced at _parse time_.
4675 s = bc_lex_next(&p->l);
4677 printf("BC_BASE_MAX = %u\n", BC_MAX_OBASE);
4678 printf("BC_DIM_MAX = %u\n", BC_MAX_DIM);
4679 printf("BC_SCALE_MAX = %u\n", BC_MAX_SCALE);
4680 printf("BC_STRING_MAX = %u\n", BC_MAX_STRING);
4681 printf("BC_NAME_MAX = %u\n", BC_MAX_NAME);
4682 printf("BC_NUM_MAX = %u\n", BC_MAX_NUM);
4683 printf("MAX Exponent = %lu\n", BC_MAX_EXP);
4684 printf("Number of vars = %lu\n", BC_MAX_VARS);
4688 case BC_LEX_KEY_PRINT:
4690 s = bc_parse_print(p);
4694 case BC_LEX_KEY_QUIT:
4696 // "quit" is a compile-time command. For example,
4697 // "if (0 == 1) quit" terminates when parsing the statement,
4698 // not when it is executed
4702 case BC_LEX_KEY_RETURN:
4704 s = bc_parse_return(p);
4708 case BC_LEX_KEY_WHILE:
4710 s = bc_parse_while(p);
4716 s = BC_STATUS_PARSE_BAD_TOKEN;
4724 static BcStatus bc_parse_parse(BcParse *p)
4728 if (p->l.t.t == BC_LEX_EOF)
4729 s = p->flags.len > 0 ? BC_STATUS_PARSE_NO_BLOCK_END : BC_STATUS_LEX_EOF;
4730 else if (p->l.t.t == BC_LEX_KEY_DEFINE) {
4731 if (!BC_PARSE_CAN_EXEC(p)) return BC_STATUS_PARSE_BAD_TOKEN;
4732 s = bc_parse_func(p);
4735 s = bc_parse_stmt(p);
4737 if (s || G_interrupt) {
4739 s = BC_STATUS_FAILURE;
4745 static BcStatus bc_parse_expr(BcParse *p, uint8_t flags, BcParseNext next)
4747 BcStatus s = BC_STATUS_SUCCESS;
4748 BcInst prev = BC_INST_PRINT;
4749 BcLexType top, t = p->l.t.t;
4750 size_t nexprs = 0, ops_bgn = p->ops.len;
4751 uint32_t i, nparens, nrelops;
4752 bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
4754 paren_first = p->l.t.t == BC_LEX_LPAREN;
4755 nparens = nrelops = 0;
4756 paren_expr = rprn = done = get_token = assign = false;
4759 for (; !G_interrupt && !s && !done && bc_parse_exprs[t]; t = p->l.t.t) {
4765 s = bc_parse_incdec(p, &prev, &paren_expr, &nexprs, flags);
4766 rprn = get_token = bin_last = false;
4770 case BC_LEX_OP_MINUS:
4772 s = bc_parse_minus(p, &prev, ops_bgn, rprn, &nexprs);
4773 rprn = get_token = false;
4774 bin_last = prev == BC_INST_MINUS;
4778 case BC_LEX_OP_ASSIGN_POWER:
4779 case BC_LEX_OP_ASSIGN_MULTIPLY:
4780 case BC_LEX_OP_ASSIGN_DIVIDE:
4781 case BC_LEX_OP_ASSIGN_MODULUS:
4782 case BC_LEX_OP_ASSIGN_PLUS:
4783 case BC_LEX_OP_ASSIGN_MINUS:
4784 case BC_LEX_OP_ASSIGN:
4786 if (prev != BC_INST_VAR && prev != BC_INST_ARRAY_ELEM &&
4787 prev != BC_INST_SCALE && prev != BC_INST_IBASE &&
4788 prev != BC_INST_OBASE && prev != BC_INST_LAST)
4790 s = BC_STATUS_PARSE_BAD_ASSIGN;
4795 case BC_LEX_OP_POWER:
4796 case BC_LEX_OP_MULTIPLY:
4797 case BC_LEX_OP_DIVIDE:
4798 case BC_LEX_OP_MODULUS:
4799 case BC_LEX_OP_PLUS:
4800 case BC_LEX_OP_REL_EQ:
4801 case BC_LEX_OP_REL_LE:
4802 case BC_LEX_OP_REL_GE:
4803 case BC_LEX_OP_REL_NE:
4804 case BC_LEX_OP_REL_LT:
4805 case BC_LEX_OP_REL_GT:
4806 case BC_LEX_OP_BOOL_NOT:
4807 case BC_LEX_OP_BOOL_OR:
4808 case BC_LEX_OP_BOOL_AND:
4810 if (((t == BC_LEX_OP_BOOL_NOT) != bin_last) ||
4811 (t != BC_LEX_OP_BOOL_NOT && prev == BC_INST_BOOL_NOT))
4813 return BC_STATUS_PARSE_BAD_EXP;
4816 nrelops += t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT;
4817 prev = BC_PARSE_TOKEN_INST(t);
4818 s = bc_parse_operator(p, t, ops_bgn, &nexprs, true);
4819 rprn = get_token = false;
4820 bin_last = t != BC_LEX_OP_BOOL_NOT;
4827 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4830 paren_expr = rprn = bin_last = false;
4832 bc_vec_push(&p->ops, &t);
4839 if (bin_last || prev == BC_INST_BOOL_NOT)
4840 return BC_STATUS_PARSE_BAD_EXP;
4843 s = BC_STATUS_SUCCESS;
4848 else if (!paren_expr)
4849 return BC_STATUS_PARSE_EMPTY_EXP;
4852 paren_expr = rprn = true;
4853 get_token = bin_last = false;
4855 s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4862 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4865 rprn = get_token = bin_last = false;
4866 s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4874 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4876 bc_parse_number(p, &prev, &nexprs);
4877 paren_expr = get_token = true;
4878 rprn = bin_last = false;
4883 case BC_LEX_KEY_IBASE:
4884 case BC_LEX_KEY_LAST:
4885 case BC_LEX_KEY_OBASE:
4887 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4889 prev = (char) (t - BC_LEX_KEY_IBASE + BC_INST_IBASE);
4890 bc_parse_push(p, (char) prev);
4892 paren_expr = get_token = true;
4893 rprn = bin_last = false;
4899 case BC_LEX_KEY_LENGTH:
4900 case BC_LEX_KEY_SQRT:
4902 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4904 s = bc_parse_builtin(p, t, flags, &prev);
4906 rprn = get_token = bin_last = false;
4912 case BC_LEX_KEY_READ:
4914 if (BC_PARSE_LEAF(prev, rprn))
4915 return BC_STATUS_PARSE_BAD_EXP;
4916 else if (flags & BC_PARSE_NOREAD)
4917 s = BC_STATUS_EXEC_REC_READ;
4919 s = bc_parse_read(p);
4922 rprn = get_token = bin_last = false;
4924 prev = BC_INST_READ;
4929 case BC_LEX_KEY_SCALE:
4931 if (BC_PARSE_LEAF(prev, rprn)) return BC_STATUS_PARSE_BAD_EXP;
4933 s = bc_parse_scale(p, &prev, flags);
4935 rprn = get_token = bin_last = false;
4937 prev = BC_INST_SCALE;
4944 s = BC_STATUS_PARSE_BAD_TOKEN;
4949 if (!s && get_token) s = bc_lex_next(&p->l);
4953 if (G_interrupt) return BC_STATUS_FAILURE; // ^C: stop parsing
4955 while (p->ops.len > ops_bgn) {
4957 top = BC_PARSE_TOP_OP(p);
4958 assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4960 if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4961 return BC_STATUS_PARSE_BAD_EXP;
4963 bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4965 nexprs -= top != BC_LEX_OP_BOOL_NOT && top != BC_LEX_NEG;
4966 bc_vec_pop(&p->ops);
4969 s = BC_STATUS_PARSE_BAD_EXP;
4970 if (prev == BC_INST_BOOL_NOT || nexprs != 1) return s;
4972 for (i = 0; s && i < next.len; ++i) s *= t != next.tokens[i];
4975 if (!(flags & BC_PARSE_REL) && nrelops) {
4976 s = bc_vm_posixError(BC_STATUS_POSIX_REL_POS, p->l.f, p->l.line, NULL);
4979 else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4980 s = bc_vm_posixError(BC_STATUS_POSIX_MULTIREL, p->l.f, p->l.line, NULL);
4984 if (flags & BC_PARSE_PRINT) {
4985 if (paren_first || !assign) bc_parse_push(p, BC_INST_PRINT);
4986 bc_parse_push(p, BC_INST_POP);
4992 static void bc_parse_init(BcParse *p, size_t func)
4994 bc_parse_create(p, func, bc_parse_parse, bc_lex_token);
4997 static BcStatus bc_parse_expression(BcParse *p, uint8_t flags)
4999 return bc_parse_expr(p, flags, bc_parse_next_read);
5004 static BcStatus dc_parse_register(BcParse *p)
5009 s = bc_lex_next(&p->l);
5011 if (p->l.t.t != BC_LEX_NAME) return BC_STATUS_PARSE_BAD_TOKEN;
5013 name = xstrdup(p->l.t.v.v);
5014 bc_parse_pushName(p, name);
5019 static BcStatus dc_parse_string(BcParse *p)
5021 char *str, *name, b[DC_PARSE_BUF_LEN + 1];
5022 size_t idx, len = G.prog.strs.len;
5024 sprintf(b, "%0*zu", DC_PARSE_BUF_LEN, len);
5027 str = xstrdup(p->l.t.v.v);
5028 bc_parse_push(p, BC_INST_STR);
5029 bc_parse_pushIndex(p, len);
5030 bc_vec_push(&G.prog.strs, &str);
5031 bc_parse_addFunc(p, name, &idx);
5033 return bc_lex_next(&p->l);
5036 static BcStatus dc_parse_mem(BcParse *p, uint8_t inst, bool name, bool store)
5040 bc_parse_push(p, inst);
5042 s = dc_parse_register(p);
5047 bc_parse_push(p, BC_INST_SWAP);
5048 bc_parse_push(p, BC_INST_ASSIGN);
5049 bc_parse_push(p, BC_INST_POP);
5052 return bc_lex_next(&p->l);
5055 static BcStatus dc_parse_cond(BcParse *p, uint8_t inst)
5059 bc_parse_push(p, inst);
5060 bc_parse_push(p, BC_INST_EXEC_COND);
5062 s = dc_parse_register(p);
5065 s = bc_lex_next(&p->l);
5068 if (p->l.t.t == BC_LEX_ELSE) {
5069 s = dc_parse_register(p);
5071 s = bc_lex_next(&p->l);
5074 bc_parse_push(p, BC_PARSE_STREND);
5079 static BcStatus dc_parse_token(BcParse *p, BcLexType t, uint8_t flags)
5081 BcStatus s = BC_STATUS_SUCCESS;
5084 bool assign, get_token = false;
5088 case BC_LEX_OP_REL_EQ:
5089 case BC_LEX_OP_REL_LE:
5090 case BC_LEX_OP_REL_GE:
5091 case BC_LEX_OP_REL_NE:
5092 case BC_LEX_OP_REL_LT:
5093 case BC_LEX_OP_REL_GT:
5095 s = dc_parse_cond(p, t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
5102 s = dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
5108 s = dc_parse_string(p);
5115 if (t == BC_LEX_NEG) {
5116 s = bc_lex_next(&p->l);
5118 if (p->l.t.t != BC_LEX_NUMBER) return BC_STATUS_PARSE_BAD_TOKEN;
5121 bc_parse_number(p, &prev, &p->nbraces);
5123 if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
5129 case BC_LEX_KEY_READ:
5131 if (flags & BC_PARSE_NOREAD)
5132 s = BC_STATUS_EXEC_REC_READ;
5134 bc_parse_push(p, BC_INST_READ);
5139 case BC_LEX_OP_ASSIGN:
5140 case BC_LEX_STORE_PUSH:
5142 assign = t == BC_LEX_OP_ASSIGN;
5143 inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
5144 s = dc_parse_mem(p, inst, true, assign);
5149 case BC_LEX_LOAD_POP:
5151 inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
5152 s = dc_parse_mem(p, inst, true, false);
5156 case BC_LEX_STORE_IBASE:
5157 case BC_LEX_STORE_SCALE:
5158 case BC_LEX_STORE_OBASE:
5160 inst = t - BC_LEX_STORE_IBASE + BC_INST_IBASE;
5161 s = dc_parse_mem(p, inst, false, true);
5167 s = BC_STATUS_PARSE_BAD_TOKEN;
5173 if (!s && get_token) s = bc_lex_next(&p->l);
5178 static BcStatus dc_parse_expr(BcParse *p, uint8_t flags)
5180 BcStatus s = BC_STATUS_SUCCESS;
5184 if (flags & BC_PARSE_NOCALL) p->nbraces = G.prog.results.len;
5186 for (t = p->l.t.t; !s && t != BC_LEX_EOF; t = p->l.t.t) {
5188 inst = dc_parse_insts[t];
5190 if (inst != BC_INST_INVALID) {
5191 bc_parse_push(p, inst);
5192 s = bc_lex_next(&p->l);
5195 s = dc_parse_token(p, t, flags);
5198 if (!s && p->l.t.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
5199 bc_parse_push(p, BC_INST_POP_EXEC);
5204 static BcStatus dc_parse_parse(BcParse *p)
5208 if (p->l.t.t == BC_LEX_EOF)
5209 s = BC_STATUS_LEX_EOF;
5211 s = dc_parse_expr(p, 0);
5213 if (s || G_interrupt) {
5215 s = BC_STATUS_FAILURE;
5221 static void dc_parse_init(BcParse *p, size_t func)
5223 bc_parse_create(p, func, dc_parse_parse, dc_lex_token);
5227 static void common_parse_init(BcParse *p, size_t func)
5230 bc_parse_init(p, func);
5232 dc_parse_init(p, func);
5236 static BcStatus common_parse_expr(BcParse *p, uint8_t flags)
5239 return bc_parse_expression(p, flags);
5241 return dc_parse_expr(p, flags);
5245 static BcVec* bc_program_search(char *id, bool var)
5253 v = var ? &G.prog.vars : &G.prog.arrs;
5254 map = var ? &G.prog.var_map : &G.prog.arr_map;
5258 new = bc_map_insert(map, &e, &i); // 1 if insertion was successful
5261 bc_array_init(&data.v, var);
5262 bc_vec_push(v, &data.v);
5265 ptr = bc_vec_item(map, i);
5266 if (new) ptr->name = xstrdup(e.name);
5267 return bc_vec_item(v, ptr->idx);
5270 static BcStatus bc_program_num(BcResult *r, BcNum **num, bool hex)
5272 BcStatus s = BC_STATUS_SUCCESS;
5277 case BC_RESULT_TEMP:
5278 case BC_RESULT_IBASE:
5279 case BC_RESULT_SCALE:
5280 case BC_RESULT_OBASE:
5286 case BC_RESULT_CONSTANT:
5288 char **str = bc_vec_item(&G.prog.consts, r->d.id.idx);
5289 size_t base_t, len = strlen(*str);
5292 bc_num_init(&r->d.n, len);
5294 hex = hex && len == 1;
5295 base = hex ? &G.prog.hexb : &G.prog.ib;
5296 base_t = hex ? BC_NUM_MAX_IBASE : G.prog.ib_t;
5297 s = bc_num_parse(&r->d.n, *str, base, base_t);
5300 bc_num_free(&r->d.n);
5305 r->t = BC_RESULT_TEMP;
5311 case BC_RESULT_ARRAY:
5312 case BC_RESULT_ARRAY_ELEM:
5316 v = bc_program_search(r->d.id.name, r->t == BC_RESULT_VAR);
5318 if (r->t == BC_RESULT_ARRAY_ELEM) {
5320 if (v->len <= r->d.id.idx) bc_array_expand(v, r->d.id.idx + 1);
5321 *num = bc_vec_item(v, r->d.id.idx);
5324 *num = bc_vec_top(v);
5329 case BC_RESULT_LAST:
5331 *num = &G.prog.last;
5345 static BcStatus bc_program_binOpPrep(BcResult **l, BcNum **ln,
5346 BcResult **r, BcNum **rn, bool assign)
5350 BcResultType lt, rt;
5352 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5354 *r = bc_vec_item_rev(&G.prog.results, 0);
5355 *l = bc_vec_item_rev(&G.prog.results, 1);
5359 hex = assign && (lt == BC_RESULT_IBASE || lt == BC_RESULT_OBASE);
5361 s = bc_program_num(*l, ln, false);
5363 s = bc_program_num(*r, rn, hex);
5366 // We run this again under these conditions in case any vector has been
5367 // reallocated out from under the BcNums or arrays we had.
5368 if (lt == rt && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM)) {
5369 s = bc_program_num(*l, ln, false);
5373 if (!BC_PROG_NUM((*l), (*ln)) && (!assign || (*l)->t != BC_RESULT_VAR))
5374 return BC_STATUS_EXEC_BAD_TYPE;
5375 if (!assign && !BC_PROG_NUM((*r), (*ln))) return BC_STATUS_EXEC_BAD_TYPE;
5380 static void bc_program_binOpRetire(BcResult *r)
5382 r->t = BC_RESULT_TEMP;
5383 bc_vec_pop(&G.prog.results);
5384 bc_vec_pop(&G.prog.results);
5385 bc_vec_push(&G.prog.results, r);
5388 static BcStatus bc_program_prep(BcResult **r, BcNum **n)
5392 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5393 *r = bc_vec_top(&G.prog.results);
5395 s = bc_program_num(*r, n, false);
5398 if (!BC_PROG_NUM((*r), (*n))) return BC_STATUS_EXEC_BAD_TYPE;
5403 static void bc_program_retire(BcResult *r, BcResultType t)
5406 bc_vec_pop(&G.prog.results);
5407 bc_vec_push(&G.prog.results, r);
5410 static BcStatus bc_program_op(char inst)
5413 BcResult *opd1, *opd2, res;
5414 BcNum *n1, *n2 = NULL;
5416 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5418 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5420 s = bc_program_ops[inst - BC_INST_POWER](n1, n2, &res.d.n, G.prog.scale);
5422 bc_program_binOpRetire(&res);
5427 bc_num_free(&res.d.n);
5431 static BcStatus bc_program_read(void)
5438 BcFunc *f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5440 for (i = 0; i < G.prog.stack.len; ++i) {
5441 BcInstPtr *ip_ptr = bc_vec_item(&G.prog.stack, i);
5442 if (ip_ptr->func == BC_PROG_READ) return BC_STATUS_EXEC_REC_READ;
5445 bc_vec_npop(&f->code, f->code.len);
5446 bc_vec_init(&buf, sizeof(char), NULL);
5448 s = bc_read_line(&buf, "read> ");
5451 common_parse_init(&parse, BC_PROG_READ);
5452 bc_lex_file(&parse.l, bc_program_stdin_name);
5454 s = bc_parse_text(&parse, buf.v);
5455 if (s) goto exec_err;
5456 s = common_parse_expr(&parse, BC_PARSE_NOREAD);
5457 if (s) goto exec_err;
5459 if (parse.l.t.t != BC_LEX_NLINE && parse.l.t.t != BC_LEX_EOF) {
5460 s = BC_STATUS_EXEC_BAD_READ_EXPR;
5464 ip.func = BC_PROG_READ;
5466 ip.len = G.prog.results.len;
5468 // Update this pointer, just in case.
5469 f = bc_vec_item(&G.prog.fns, BC_PROG_READ);
5471 bc_vec_pushByte(&f->code, BC_INST_POP_EXEC);
5472 bc_vec_push(&G.prog.stack, &ip);
5475 bc_parse_free(&parse);
5481 static size_t bc_program_index(char *code, size_t *bgn)
5483 char amt = code[(*bgn)++], i = 0;
5486 for (; i < amt; ++i, ++(*bgn))
5487 res |= (((size_t)((int) code[*bgn]) & UCHAR_MAX) << (i * CHAR_BIT));
5492 static char *bc_program_name(char *code, size_t *bgn)
5495 char c, *s, *str = code + *bgn, *ptr = strchr(str, BC_PARSE_STREND);
5497 s = xmalloc(ptr - str + 1);
5500 for (i = 0; c != 0 && c != BC_PARSE_STREND; c = code[(*bgn)++], ++i)
5508 static void bc_program_printString(const char *str, size_t *nchars)
5510 size_t i, len = strlen(str);
5519 for (i = 0; i < len; ++i, ++(*nchars)) {
5523 if (c != '\\' || i == len - 1)
5583 // Just print the backslash and following character.
5594 static BcStatus bc_program_print(char inst, size_t idx)
5596 BcStatus s = BC_STATUS_SUCCESS;
5601 bool pop = inst != BC_INST_PRINT;
5603 if (!BC_PROG_STACK(&G.prog.results, idx + 1)) return BC_STATUS_EXEC_STACK;
5605 r = bc_vec_item_rev(&G.prog.results, idx);
5606 s = bc_program_num(r, &num, false);
5609 if (BC_PROG_NUM(r, num)) {
5610 s = bc_num_print(num, &G.prog.ob, G.prog.ob_t, !pop, &G.prog.nchars, G.prog.len);
5611 if (!s) bc_num_copy(&G.prog.last, num);
5615 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
5616 str = *((char **) bc_vec_item(&G.prog.strs, idx));
5618 if (inst == BC_INST_PRINT_STR) {
5619 for (i = 0, len = strlen(str); i < len; ++i) {
5622 if (c == '\n') G.prog.nchars = SIZE_MAX;
5627 bc_program_printString(str, &G.prog.nchars);
5628 if (inst == BC_INST_PRINT) bb_putchar('\n');
5632 if (!s && pop) bc_vec_pop(&G.prog.results);
5637 static BcStatus bc_program_negate(void)
5643 s = bc_program_prep(&ptr, &num);
5646 bc_num_init(&res.d.n, num->len);
5647 bc_num_copy(&res.d.n, num);
5648 if (res.d.n.len) res.d.n.neg = !res.d.n.neg;
5650 bc_program_retire(&res, BC_RESULT_TEMP);
5655 static BcStatus bc_program_logical(char inst)
5658 BcResult *opd1, *opd2, res;
5663 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
5665 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5667 if (inst == BC_INST_BOOL_AND)
5668 cond = bc_num_cmp(n1, &G.prog.zero) && bc_num_cmp(n2, &G.prog.zero);
5669 else if (inst == BC_INST_BOOL_OR)
5670 cond = bc_num_cmp(n1, &G.prog.zero) || bc_num_cmp(n2, &G.prog.zero);
5673 cmp = bc_num_cmp(n1, n2);
5677 case BC_INST_REL_EQ:
5683 case BC_INST_REL_LE:
5689 case BC_INST_REL_GE:
5695 case BC_INST_REL_NE:
5701 case BC_INST_REL_LT:
5707 case BC_INST_REL_GT:
5715 (cond ? bc_num_one : bc_num_zero)(&res.d.n);
5717 bc_program_binOpRetire(&res);
5723 static BcStatus bc_program_assignStr(BcResult *r, BcVec *v,
5729 memset(&n2, 0, sizeof(BcNum));
5730 n2.rdx = res.d.id.idx = r->d.id.idx;
5731 res.t = BC_RESULT_STR;
5734 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
5736 bc_vec_pop(&G.prog.results);
5739 bc_vec_pop(&G.prog.results);
5741 bc_vec_push(&G.prog.results, &res);
5742 bc_vec_push(v, &n2);
5744 return BC_STATUS_SUCCESS;
5748 static BcStatus bc_program_copyToVar(char *name, bool var)
5755 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
5757 ptr = bc_vec_top(&G.prog.results);
5758 if ((ptr->t == BC_RESULT_ARRAY) != !var) return BC_STATUS_EXEC_BAD_TYPE;
5759 v = bc_program_search(name, var);
5762 if (ptr->t == BC_RESULT_STR && !var) return BC_STATUS_EXEC_BAD_TYPE;
5763 if (ptr->t == BC_RESULT_STR) return bc_program_assignStr(ptr, v, true);
5766 s = bc_program_num(ptr, &n, false);
5769 // Do this once more to make sure that pointers were not invalidated.
5770 v = bc_program_search(name, var);
5773 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5774 bc_num_copy(&r.d.n, n);
5777 bc_array_init(&r.d.v, true);
5778 bc_array_copy(&r.d.v, (BcVec *) n);
5781 bc_vec_push(v, &r.d);
5782 bc_vec_pop(&G.prog.results);
5787 static BcStatus bc_program_assign(char inst)
5790 BcResult *left, *right, res;
5791 BcNum *l = NULL, *r = NULL;
5792 unsigned long val, max;
5793 bool assign = inst == BC_INST_ASSIGN, ib, sc;
5795 s = bc_program_binOpPrep(&left, &l, &right, &r, assign);
5798 ib = left->t == BC_RESULT_IBASE;
5799 sc = left->t == BC_RESULT_SCALE;
5803 if (right->t == BC_RESULT_STR) {
5807 if (left->t != BC_RESULT_VAR) return BC_STATUS_EXEC_BAD_TYPE;
5808 v = bc_program_search(left->d.id.name, true);
5810 return bc_program_assignStr(right, v, false);
5814 if (left->t == BC_RESULT_CONSTANT || left->t == BC_RESULT_TEMP)
5815 return BC_STATUS_PARSE_BAD_ASSIGN;
5818 if (inst == BC_INST_ASSIGN_DIVIDE && !bc_num_cmp(r, &G.prog.zero))
5819 return BC_STATUS_MATH_DIVIDE_BY_ZERO;
5824 s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, G.prog.scale);
5831 if (ib || sc || left->t == BC_RESULT_OBASE) {
5835 s = bc_num_ulong(l, &val);
5837 s = left->t - BC_RESULT_IBASE + BC_STATUS_EXEC_BAD_IBASE;
5841 ptr = &G.prog.scale;
5844 if (val < BC_NUM_MIN_BASE) return s;
5845 max = ib ? BC_NUM_MAX_IBASE : BC_MAX_OBASE;
5846 ptr = ib ? &G.prog.ib_t : &G.prog.ob_t;
5849 if (val > max) return s;
5850 if (!sc) bc_num_copy(ib ? &G.prog.ib : &G.prog.ob, l);
5852 *ptr = (size_t) val;
5853 s = BC_STATUS_SUCCESS;
5856 bc_num_init(&res.d.n, l->len);
5857 bc_num_copy(&res.d.n, l);
5858 bc_program_binOpRetire(&res);
5864 #define bc_program_pushVar(code, bgn, pop, copy) \
5865 bc_program_pushVar(code, bgn)
5866 // for bc, 'pop' and 'copy' are always false
5868 static BcStatus bc_program_pushVar(char *code, size_t *bgn,
5869 bool pop, bool copy)
5871 BcStatus s = BC_STATUS_SUCCESS;
5873 char *name = bc_program_name(code, bgn);
5875 r.t = BC_RESULT_VAR;
5880 BcVec *v = bc_program_search(name, true);
5881 BcNum *num = bc_vec_top(v);
5885 if (!BC_PROG_STACK(v, 2 - copy)) {
5887 return BC_STATUS_EXEC_STACK;
5893 if (!BC_PROG_STR(num)) {
5895 r.t = BC_RESULT_TEMP;
5897 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
5898 bc_num_copy(&r.d.n, num);
5901 r.t = BC_RESULT_STR;
5902 r.d.id.idx = num->rdx;
5905 if (!copy) bc_vec_pop(v);
5910 bc_vec_push(&G.prog.results, &r);
5915 static BcStatus bc_program_pushArray(char *code, size_t *bgn,
5918 BcStatus s = BC_STATUS_SUCCESS;
5922 r.d.id.name = bc_program_name(code, bgn);
5924 if (inst == BC_INST_ARRAY) {
5925 r.t = BC_RESULT_ARRAY;
5926 bc_vec_push(&G.prog.results, &r);
5933 s = bc_program_prep(&operand, &num);
5935 s = bc_num_ulong(num, &temp);
5938 if (temp > BC_MAX_DIM) {
5939 s = BC_STATUS_EXEC_ARRAY_LEN;
5943 r.d.id.idx = (size_t) temp;
5944 bc_program_retire(&r, BC_RESULT_ARRAY_ELEM);
5948 if (s) free(r.d.id.name);
5953 static BcStatus bc_program_incdec(char inst)
5956 BcResult *ptr, res, copy;
5960 s = bc_program_prep(&ptr, &num);
5963 if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5964 copy.t = BC_RESULT_TEMP;
5965 bc_num_init(©.d.n, num->len);
5966 bc_num_copy(©.d.n, num);
5969 res.t = BC_RESULT_ONE;
5970 inst = inst == BC_INST_INC_PRE || inst == BC_INST_INC_POST ?
5971 BC_INST_ASSIGN_PLUS :
5972 BC_INST_ASSIGN_MINUS;
5974 bc_vec_push(&G.prog.results, &res);
5975 bc_program_assign(inst);
5977 if (inst2 == BC_INST_INC_POST || inst2 == BC_INST_DEC_POST) {
5978 bc_vec_pop(&G.prog.results);
5979 bc_vec_push(&G.prog.results, ©);
5985 static BcStatus bc_program_call(char *code, size_t *idx)
5987 BcStatus s = BC_STATUS_SUCCESS;
5989 size_t i, nparams = bc_program_index(code, idx);
5996 ip.func = bc_program_index(code, idx);
5997 func = bc_vec_item(&G.prog.fns, ip.func);
5999 if (func->code.len == 0) {
6000 return bc_error("undefined function");
6002 if (nparams != func->nparams) {
6003 return bc_error("function has %u parameters, but called with %u", func->nparams, nparams);
6005 ip.len = G.prog.results.len - nparams;
6007 for (i = 0; i < nparams; ++i) {
6009 a = bc_vec_item(&func->autos, nparams - 1 - i);
6010 arg = bc_vec_top(&G.prog.results);
6012 if ((!a->idx) != (arg->t == BC_RESULT_ARRAY) || arg->t == BC_RESULT_STR)
6013 return BC_STATUS_EXEC_BAD_TYPE;
6015 s = bc_program_copyToVar(a->name, a->idx);
6019 for (; i < func->autos.len; ++i) {
6022 a = bc_vec_item(&func->autos, i);
6023 v = bc_program_search(a->name, a->idx);
6026 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
6027 bc_vec_push(v, ¶m.n);
6030 bc_array_init(¶m.v, true);
6031 bc_vec_push(v, ¶m.v);
6035 bc_vec_push(&G.prog.stack, &ip);
6037 return BC_STATUS_SUCCESS;
6040 static BcStatus bc_program_return(char inst)
6046 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6048 if (!BC_PROG_STACK(&G.prog.results, ip->len + inst == BC_INST_RET))
6049 return BC_STATUS_EXEC_STACK;
6051 f = bc_vec_item(&G.prog.fns, ip->func);
6052 res.t = BC_RESULT_TEMP;
6054 if (inst == BC_INST_RET) {
6057 BcResult *operand = bc_vec_top(&G.prog.results);
6059 s = bc_program_num(operand, &num, false);
6061 bc_num_init(&res.d.n, num->len);
6062 bc_num_copy(&res.d.n, num);
6065 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6066 bc_num_zero(&res.d.n);
6069 // We need to pop arguments as well, so this takes that into account.
6070 for (i = 0; i < f->autos.len; ++i) {
6073 BcId *a = bc_vec_item(&f->autos, i);
6075 v = bc_program_search(a->name, a->idx);
6079 bc_vec_npop(&G.prog.results, G.prog.results.len - ip->len);
6080 bc_vec_push(&G.prog.results, &res);
6081 bc_vec_pop(&G.prog.stack);
6083 return BC_STATUS_SUCCESS;
6087 static unsigned long bc_program_scale(BcNum *n)
6089 return (unsigned long) n->rdx;
6092 static unsigned long bc_program_len(BcNum *n)
6094 unsigned long len = n->len;
6097 if (n->rdx != n->len) return len;
6098 for (i = n->len - 1; i < n->len && n->num[i] == 0; --len, --i);
6103 static BcStatus bc_program_builtin(char inst)
6109 bool len = inst == BC_INST_LENGTH;
6111 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6112 opnd = bc_vec_top(&G.prog.results);
6114 s = bc_program_num(opnd, &num, false);
6118 if (!BC_PROG_NUM(opnd, num) && !len) return BC_STATUS_EXEC_BAD_TYPE;
6121 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6123 if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, &res.d.n, G.prog.scale);
6125 else if (len != 0 && opnd->t == BC_RESULT_ARRAY) {
6126 bc_num_ulong2num(&res.d.n, (unsigned long) ((BcVec *) num)->len);
6130 else if (len != 0 && !BC_PROG_NUM(opnd, num)) {
6133 size_t idx = opnd->t == BC_RESULT_STR ? opnd->d.id.idx : num->rdx;
6135 str = bc_vec_item(&G.prog.strs, idx);
6136 bc_num_ulong2num(&res.d.n, strlen(*str));
6140 BcProgramBuiltIn f = len ? bc_program_len : bc_program_scale;
6141 bc_num_ulong2num(&res.d.n, f(num));
6144 bc_program_retire(&res, BC_RESULT_TEMP);
6150 static BcStatus bc_program_divmod(void)
6153 BcResult *opd1, *opd2, res, res2;
6154 BcNum *n1, *n2 = NULL;
6156 s = bc_program_binOpPrep(&opd1, &n1, &opd2, &n2, false);
6159 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6160 bc_num_init(&res2.d.n, n2->len);
6162 s = bc_num_divmod(n1, n2, &res2.d.n, &res.d.n, G.prog.scale);
6165 bc_program_binOpRetire(&res2);
6166 res.t = BC_RESULT_TEMP;
6167 bc_vec_push(&G.prog.results, &res);
6172 bc_num_free(&res2.d.n);
6173 bc_num_free(&res.d.n);
6177 static BcStatus bc_program_modexp(void)
6180 BcResult *r1, *r2, *r3, res;
6181 BcNum *n1, *n2, *n3;
6183 if (!BC_PROG_STACK(&G.prog.results, 3)) return BC_STATUS_EXEC_STACK;
6184 s = bc_program_binOpPrep(&r2, &n2, &r3, &n3, false);
6187 r1 = bc_vec_item_rev(&G.prog.results, 2);
6188 s = bc_program_num(r1, &n1, false);
6190 if (!BC_PROG_NUM(r1, n1)) return BC_STATUS_EXEC_BAD_TYPE;
6192 // Make sure that the values have their pointers updated, if necessary.
6193 if (r1->t == BC_RESULT_VAR || r1->t == BC_RESULT_ARRAY_ELEM) {
6195 if (r1->t == r2->t) {
6196 s = bc_program_num(r2, &n2, false);
6200 if (r1->t == r3->t) {
6201 s = bc_program_num(r3, &n3, false);
6206 bc_num_init(&res.d.n, n3->len);
6207 s = bc_num_modexp(n1, n2, n3, &res.d.n);
6210 bc_vec_pop(&G.prog.results);
6211 bc_program_binOpRetire(&res);
6216 bc_num_free(&res.d.n);
6220 static void bc_program_stackLen(void)
6223 size_t len = G.prog.results.len;
6225 res.t = BC_RESULT_TEMP;
6227 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6228 bc_num_ulong2num(&res.d.n, len);
6229 bc_vec_push(&G.prog.results, &res);
6232 static BcStatus bc_program_asciify(void)
6236 BcNum *num = NULL, n;
6237 char *str, *str2, c;
6238 size_t len = G.prog.strs.len, idx;
6241 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6242 r = bc_vec_top(&G.prog.results);
6244 s = bc_program_num(r, &num, false);
6247 if (BC_PROG_NUM(r, num)) {
6249 bc_num_init(&n, BC_NUM_DEF_SIZE);
6250 bc_num_copy(&n, num);
6251 bc_num_truncate(&n, n.rdx);
6253 s = bc_num_mod(&n, &G.prog.strmb, &n, 0);
6254 if (s) goto num_err;
6255 s = bc_num_ulong(&n, &val);
6256 if (s) goto num_err;
6263 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : num->rdx;
6264 str2 = *((char **) bc_vec_item(&G.prog.strs, idx));
6272 str2 = xstrdup(str);
6273 bc_program_addFunc(str2, &idx);
6275 if (idx != len + BC_PROG_REQ_FUNCS) {
6277 for (idx = 0; idx < G.prog.strs.len; ++idx) {
6278 if (!strcmp(*((char **) bc_vec_item(&G.prog.strs, idx)), str)) {
6287 bc_vec_push(&G.prog.strs, &str);
6289 res.t = BC_RESULT_STR;
6291 bc_vec_pop(&G.prog.results);
6292 bc_vec_push(&G.prog.results, &res);
6294 return BC_STATUS_SUCCESS;
6301 static BcStatus bc_program_printStream(void)
6309 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6310 r = bc_vec_top(&G.prog.results);
6312 s = bc_program_num(r, &n, false);
6315 if (BC_PROG_NUM(r, n))
6316 s = bc_num_stream(n, &G.prog.strmb, &G.prog.nchars, G.prog.len);
6318 idx = (r->t == BC_RESULT_STR) ? r->d.id.idx : n->rdx;
6319 str = *((char **) bc_vec_item(&G.prog.strs, idx));
6326 static BcStatus bc_program_nquit(void)
6333 s = bc_program_prep(&opnd, &num);
6335 s = bc_num_ulong(num, &val);
6338 bc_vec_pop(&G.prog.results);
6340 if (G.prog.stack.len < val)
6341 return BC_STATUS_EXEC_STACK;
6342 if (G.prog.stack.len == val)
6345 bc_vec_npop(&G.prog.stack, val);
6350 static BcStatus bc_program_execStr(char *code, size_t *bgn,
6353 BcStatus s = BC_STATUS_SUCCESS;
6363 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6365 r = bc_vec_top(&G.prog.results);
6369 char *name, *then_name = bc_program_name(code, bgn), *else_name = NULL;
6371 if (code[*bgn] == BC_PARSE_STREND)
6374 else_name = bc_program_name(code, bgn);
6376 exec = r->d.n.len != 0;
6380 else if (else_name != NULL) {
6387 v = bc_program_search(name, true);
6394 if (!exec) goto exit;
6395 if (!BC_PROG_STR(n)) {
6396 s = BC_STATUS_EXEC_BAD_TYPE;
6404 if (r->t == BC_RESULT_STR)
6406 else if (r->t == BC_RESULT_VAR) {
6407 s = bc_program_num(r, &n, false);
6408 if (s || !BC_PROG_STR(n)) goto exit;
6415 fidx = sidx + BC_PROG_REQ_FUNCS;
6417 str = bc_vec_item(&G.prog.strs, sidx);
6418 f = bc_vec_item(&G.prog.fns, fidx);
6420 if (f->code.len == 0) {
6421 common_parse_init(&prs, fidx);
6422 s = bc_parse_text(&prs, *str);
6424 s = common_parse_expr(&prs, BC_PARSE_NOCALL);
6427 if (prs.l.t.t != BC_LEX_EOF) {
6428 s = BC_STATUS_PARSE_BAD_EXP;
6432 bc_parse_free(&prs);
6436 ip.len = G.prog.results.len;
6439 bc_vec_pop(&G.prog.results);
6440 bc_vec_push(&G.prog.stack, &ip);
6442 return BC_STATUS_SUCCESS;
6445 bc_parse_free(&prs);
6446 f = bc_vec_item(&G.prog.fns, fidx);
6447 bc_vec_npop(&f->code, f->code.len);
6449 bc_vec_pop(&G.prog.results);
6454 static void bc_program_pushGlobal(char inst)
6459 res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
6460 if (inst == BC_INST_IBASE)
6461 val = (unsigned long) G.prog.ib_t;
6462 else if (inst == BC_INST_SCALE)
6463 val = (unsigned long) G.prog.scale;
6465 val = (unsigned long) G.prog.ob_t;
6467 bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
6468 bc_num_ulong2num(&res.d.n, val);
6469 bc_vec_push(&G.prog.results, &res);
6472 static void bc_program_addFunc(char *name, size_t *idx)
6474 BcId entry, *entry_ptr;
6479 entry.idx = G.prog.fns.len;
6481 inserted = bc_map_insert(&G.prog.fn_map, &entry, idx);
6482 if (!inserted) free(name);
6484 entry_ptr = bc_vec_item(&G.prog.fn_map, *idx);
6485 *idx = entry_ptr->idx;
6489 BcFunc *func = bc_vec_item(&G.prog.fns, entry_ptr->idx);
6491 // We need to reset these, so the function can be repopulated.
6493 bc_vec_npop(&func->autos, func->autos.len);
6494 bc_vec_npop(&func->code, func->code.len);
6495 bc_vec_npop(&func->labels, func->labels.len);
6499 bc_vec_push(&G.prog.fns, &f);
6503 // Called when parsing or execution detects a failure,
6504 // resets execution structures.
6505 static void bc_program_reset(void)
6510 bc_vec_npop(&G.prog.stack, G.prog.stack.len - 1);
6511 bc_vec_npop(&G.prog.results, G.prog.results.len);
6513 f = bc_vec_item(&G.prog.fns, 0);
6514 ip = bc_vec_top(&G.prog.stack);
6515 ip->idx = f->code.len;
6517 // If !tty, no need to check for ^C: we don't have ^C handler,
6518 // we would be killed by a signal and won't reach this place
6520 fflush_and_check(); // make sure buffered stdout is printed
6521 fputs("ready for more input\n", stderr);
6525 static BcStatus bc_program_exec(void)
6527 BcStatus s = BC_STATUS_SUCCESS;
6531 BcInstPtr *ip = bc_vec_top(&G.prog.stack);
6532 BcFunc *func = bc_vec_item(&G.prog.fns, ip->func);
6533 char *code = func->code.v;
6536 while (!s && ip->idx < func->code.len) {
6538 char inst = code[(ip->idx)++];
6543 case BC_INST_JUMP_ZERO:
6545 s = bc_program_prep(&ptr, &num);
6547 cond = !bc_num_cmp(num, &G.prog.zero);
6548 bc_vec_pop(&G.prog.results);
6554 idx = bc_program_index(code, &ip->idx);
6555 addr = bc_vec_item(&func->labels, idx);
6556 if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
6562 s = bc_program_call(code, &ip->idx);
6566 case BC_INST_INC_PRE:
6567 case BC_INST_DEC_PRE:
6568 case BC_INST_INC_POST:
6569 case BC_INST_DEC_POST:
6571 s = bc_program_incdec(inst);
6584 s = bc_program_return(inst);
6588 case BC_INST_BOOL_OR:
6589 case BC_INST_BOOL_AND:
6591 case BC_INST_REL_EQ:
6592 case BC_INST_REL_LE:
6593 case BC_INST_REL_GE:
6594 case BC_INST_REL_NE:
6595 case BC_INST_REL_LT:
6596 case BC_INST_REL_GT:
6598 s = bc_program_logical(inst);
6604 s = bc_program_read();
6610 s = bc_program_pushVar(code, &ip->idx, false, false);
6614 case BC_INST_ARRAY_ELEM:
6617 s = bc_program_pushArray(code, &ip->idx, inst);
6623 r.t = BC_RESULT_LAST;
6624 bc_vec_push(&G.prog.results, &r);
6632 bc_program_pushGlobal(inst);
6636 case BC_INST_SCALE_FUNC:
6637 case BC_INST_LENGTH:
6640 s = bc_program_builtin(inst);
6646 r.t = BC_RESULT_CONSTANT;
6647 r.d.id.idx = bc_program_index(code, &ip->idx);
6648 bc_vec_push(&G.prog.results, &r);
6654 if (!BC_PROG_STACK(&G.prog.results, 1))
6655 s = BC_STATUS_EXEC_STACK;
6657 bc_vec_pop(&G.prog.results);
6661 case BC_INST_POP_EXEC:
6663 bc_vec_pop(&G.prog.stack);
6668 case BC_INST_PRINT_POP:
6669 case BC_INST_PRINT_STR:
6671 s = bc_program_print(inst, 0);
6677 r.t = BC_RESULT_STR;
6678 r.d.id.idx = bc_program_index(code, &ip->idx);
6679 bc_vec_push(&G.prog.results, &r);
6684 case BC_INST_MULTIPLY:
6685 case BC_INST_DIVIDE:
6686 case BC_INST_MODULUS:
6690 s = bc_program_op(inst);
6694 case BC_INST_BOOL_NOT:
6696 s = bc_program_prep(&ptr, &num);
6699 bc_num_init(&r.d.n, BC_NUM_DEF_SIZE);
6700 (!bc_num_cmp(num, &G.prog.zero) ? bc_num_one : bc_num_zero)(&r.d.n);
6701 bc_program_retire(&r, BC_RESULT_TEMP);
6708 s = bc_program_negate();
6713 case BC_INST_ASSIGN_POWER:
6714 case BC_INST_ASSIGN_MULTIPLY:
6715 case BC_INST_ASSIGN_DIVIDE:
6716 case BC_INST_ASSIGN_MODULUS:
6717 case BC_INST_ASSIGN_PLUS:
6718 case BC_INST_ASSIGN_MINUS:
6720 case BC_INST_ASSIGN:
6722 s = bc_program_assign(inst);
6726 case BC_INST_MODEXP:
6728 s = bc_program_modexp();
6732 case BC_INST_DIVMOD:
6734 s = bc_program_divmod();
6738 case BC_INST_EXECUTE:
6739 case BC_INST_EXEC_COND:
6741 cond = inst == BC_INST_EXEC_COND;
6742 s = bc_program_execStr(code, &ip->idx, cond);
6746 case BC_INST_PRINT_STACK:
6748 for (idx = 0; !s && idx < G.prog.results.len; ++idx)
6749 s = bc_program_print(BC_INST_PRINT, idx);
6753 case BC_INST_CLEAR_STACK:
6755 bc_vec_npop(&G.prog.results, G.prog.results.len);
6759 case BC_INST_STACK_LEN:
6761 bc_program_stackLen();
6765 case BC_INST_DUPLICATE:
6767 if (!BC_PROG_STACK(&G.prog.results, 1)) return BC_STATUS_EXEC_STACK;
6768 ptr = bc_vec_top(&G.prog.results);
6769 bc_result_copy(&r, ptr);
6770 bc_vec_push(&G.prog.results, &r);
6778 if (!BC_PROG_STACK(&G.prog.results, 2)) return BC_STATUS_EXEC_STACK;
6780 ptr = bc_vec_item_rev(&G.prog.results, 0);
6781 ptr2 = bc_vec_item_rev(&G.prog.results, 1);
6782 memcpy(&r, ptr, sizeof(BcResult));
6783 memcpy(ptr, ptr2, sizeof(BcResult));
6784 memcpy(ptr2, &r, sizeof(BcResult));
6789 case BC_INST_ASCIIFY:
6791 s = bc_program_asciify();
6795 case BC_INST_PRINT_STREAM:
6797 s = bc_program_printStream();
6802 case BC_INST_PUSH_VAR:
6804 bool copy = inst == BC_INST_LOAD;
6805 s = bc_program_pushVar(code, &ip->idx, true, copy);
6809 case BC_INST_PUSH_TO_VAR:
6811 char *name = bc_program_name(code, &ip->idx);
6812 s = bc_program_copyToVar(name, true);
6819 if (G.prog.stack.len <= 2)
6821 bc_vec_npop(&G.prog.stack, 2);
6827 s = bc_program_nquit();
6833 if (s || G_interrupt) {
6838 // If the stack has changed, pointers may be invalid.
6839 ip = bc_vec_top(&G.prog.stack);
6840 func = bc_vec_item(&G.prog.fns, ip->func);
6841 code = func->code.v;
6847 static void bc_vm_info(void)
6849 printf("%s "BB_VER"\n"
6850 "Copyright (c) 2018 Gavin D. Howard and contributors\n"
6851 "Report bugs at: https://github.com/gavinhoward/bc\n"
6852 "This is free software with ABSOLUTELY NO WARRANTY\n"
6856 static BcStatus bc_vm_error(BcStatus s, const char *file, size_t line)
6858 if (!s || s > BC_STATUS_BEFORE_POSIX) return s;
6860 if (bc_err_msgs[s]) {
6861 fprintf(stderr, bc_err_fmt, bc_err_msgs[s]);
6862 fprintf(stderr, " %s", file);
6863 fprintf(stderr, bc_err_line + 4 * !line, line);
6866 return s * (!G.ttyin || !!strcmp(file, bc_program_stdin_name));
6870 static BcStatus bc_vm_posixError(BcStatus s, const char *file, size_t line,
6875 if (!(G.flags & (BC_FLAG_S|BC_FLAG_W))) return BC_STATUS_SUCCESS;
6876 if (s < BC_STATUS_POSIX_NAME_LEN) return BC_STATUS_SUCCESS;
6878 fmt = G_posix ? bc_err_fmt : bc_warn_fmt;
6879 fprintf(stderr, fmt, bc_err_msgs[s]);
6880 if (msg) fprintf(stderr, " %s\n", msg);
6881 fprintf(stderr, " %s", file);
6882 fprintf(stderr, bc_err_line + 4 * !line, line);
6884 if (G.ttyin || !G_posix)
6885 s = BC_STATUS_SUCCESS;
6889 static void bc_vm_envArgs(void)
6891 static const char* const bc_args_env_name = "BC_ENV_ARGS";
6894 char *env_args = getenv(bc_args_env_name), *buf;
6896 if (!env_args) return;
6898 G.env_args = xstrdup(env_args);
6901 bc_vec_init(&v, sizeof(char *), NULL);
6902 bc_vec_push(&v, &bc_args_env_name);
6905 if (!isspace(*buf)) {
6906 bc_vec_push(&v, &buf);
6907 while (*buf != 0 && !isspace(*buf)) ++buf;
6908 if (*buf != 0) (*(buf++)) = '\0';
6914 bc_args((int) v.len, (char **) v.v);
6920 static size_t bc_vm_envLen(const char *var)
6922 char *lenv = getenv(var);
6923 size_t i, len = BC_NUM_PRINT_WIDTH;
6926 if (!lenv) return len;
6930 for (num = 1, i = 0; num && i < len; ++i) num = isdigit(lenv[i]);
6932 len = (size_t) atoi(lenv) - 1;
6933 if (len < 2 || len >= INT32_MAX) len = BC_NUM_PRINT_WIDTH;
6936 len = BC_NUM_PRINT_WIDTH;
6941 static BcStatus bc_vm_process(const char *text)
6943 BcStatus s = bc_parse_text(&G.prs, text);
6945 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6948 while (G.prs.l.t.t != BC_LEX_EOF) {
6950 s = G.prs.parse(&G.prs);
6952 s = bc_vm_error(s, G.prs.l.f, G.prs.l.line);
6956 if (BC_PARSE_CAN_EXEC(&G.prs)) {
6957 s = bc_program_exec();
6961 s = bc_vm_error(s, G.prs.l.f, 0);
6968 static BcStatus bc_vm_file(const char *file)
6976 data = bc_read_file(file);
6977 if (!data) return bc_error("file '%s' is not text", file);
6979 bc_lex_file(&G.prs.l, file);
6980 s = bc_vm_process(data);
6983 main_func = bc_vec_item(&G.prog.fns, BC_PROG_MAIN);
6984 ip = bc_vec_item(&G.prog.stack, 0);
6986 if (main_func->code.len < ip->idx) s = BC_STATUS_EXEC_FILE_NOT_EXECUTABLE;
6993 static BcStatus bc_vm_stdin(void)
6997 size_t len, i, str = 0;
6998 bool comment = false;
7000 G.prog.file = bc_program_stdin_name;
7001 bc_lex_file(&G.prs.l, bc_program_stdin_name);
7003 bc_vec_init(&buffer, sizeof(char), NULL);
7004 bc_vec_init(&buf, sizeof(char), NULL);
7005 bc_vec_pushByte(&buffer, '\0');
7007 // This loop is complex because the vm tries not to send any lines that end
7008 // with a backslash to the parser. The reason for that is because the parser
7009 // treats a backslash+newline combo as whitespace, per the bc spec. In that
7010 // case, and for strings and comments, the parser will expect more stuff.
7011 while (!G.eof && (s = bc_read_line(&buf, ">>> ")) == BC_STATUS_SUCCESS) {
7013 char *string = buf.v;
7018 if (str && buf.v[0] == G.send)
7020 else if (buf.v[0] == G.sbgn)
7023 else if (len > 1 || comment) {
7025 for (i = 0; i < len; ++i) {
7027 bool notend = len > i + 1;
7030 if (i - 1 > len || string[i - 1] != '\\') {
7031 if (G.sbgn == G.send)
7033 else if (c == G.send)
7035 else if (c == G.sbgn)
7039 if (c == '/' && notend && !comment && string[i + 1] == '*') {
7043 else if (c == '*' && notend && comment && string[i + 1] == '/')
7047 if (str || comment || string[len - 2] == '\\') {
7048 bc_vec_concat(&buffer, buf.v);
7053 bc_vec_concat(&buffer, buf.v);
7054 s = bc_vm_process(buffer.v);
7057 bc_vec_npop(&buffer, buffer.len);
7061 s = bc_vm_error(BC_STATUS_LEX_NO_STRING_END, G.prs.l.f,
7064 s = bc_vm_error(BC_STATUS_LEX_NO_COMMENT_END, G.prs.l.f,
7069 bc_vec_free(&buffer);
7073 static BcStatus bc_vm_exec(void)
7075 BcStatus s = BC_STATUS_SUCCESS;
7079 if (G.flags & BC_FLAG_L) {
7081 bc_lex_file(&G.prs.l, bc_lib_name);
7082 s = bc_parse_text(&G.prs, bc_lib);
7084 while (!s && G.prs.l.t.t != BC_LEX_EOF) s = G.prs.parse(&G.prs);
7087 s = bc_program_exec();
7092 for (i = 0; !s && i < G.files.len; ++i)
7093 s = bc_vm_file(*((char **) bc_vec_item(&G.files, i)));
7096 if (IS_BC || !G.files.len) s = bc_vm_stdin();
7097 if (!s && !BC_PARSE_CAN_EXEC(&G.prs)) s = bc_vm_process("");
7102 #if ENABLE_FEATURE_CLEAN_UP
7103 static void bc_program_free()
7105 bc_num_free(&G.prog.ib);
7106 bc_num_free(&G.prog.ob);
7107 bc_num_free(&G.prog.hexb);
7109 bc_num_free(&G.prog.strmb);
7111 bc_vec_free(&G.prog.fns);
7112 bc_vec_free(&G.prog.fn_map);
7113 bc_vec_free(&G.prog.vars);
7114 bc_vec_free(&G.prog.var_map);
7115 bc_vec_free(&G.prog.arrs);
7116 bc_vec_free(&G.prog.arr_map);
7117 bc_vec_free(&G.prog.strs);
7118 bc_vec_free(&G.prog.consts);
7119 bc_vec_free(&G.prog.results);
7120 bc_vec_free(&G.prog.stack);
7121 bc_num_free(&G.prog.last);
7122 bc_num_free(&G.prog.zero);
7123 bc_num_free(&G.prog.one);
7126 static void bc_vm_free(void)
7128 bc_vec_free(&G.files);
7130 bc_parse_free(&G.prs);
7135 static void bc_program_init(size_t line_len)
7140 /* memset(&G.prog, 0, sizeof(G.prog)); - already is */
7141 memset(&ip, 0, sizeof(BcInstPtr));
7143 /* G.prog.nchars = G.prog.scale = 0; - already is */
7144 G.prog.len = line_len;
7146 bc_num_init(&G.prog.ib, BC_NUM_DEF_SIZE);
7147 bc_num_ten(&G.prog.ib);
7150 bc_num_init(&G.prog.ob, BC_NUM_DEF_SIZE);
7151 bc_num_ten(&G.prog.ob);
7154 bc_num_init(&G.prog.hexb, BC_NUM_DEF_SIZE);
7155 bc_num_ten(&G.prog.hexb);
7156 G.prog.hexb.num[0] = 6;
7159 bc_num_init(&G.prog.strmb, BC_NUM_DEF_SIZE);
7160 bc_num_ulong2num(&G.prog.strmb, UCHAR_MAX + 1);
7163 bc_num_init(&G.prog.last, BC_NUM_DEF_SIZE);
7164 bc_num_zero(&G.prog.last);
7166 bc_num_init(&G.prog.zero, BC_NUM_DEF_SIZE);
7167 bc_num_zero(&G.prog.zero);
7169 bc_num_init(&G.prog.one, BC_NUM_DEF_SIZE);
7170 bc_num_one(&G.prog.one);
7172 bc_vec_init(&G.prog.fns, sizeof(BcFunc), bc_func_free);
7173 bc_map_init(&G.prog.fn_map);
7175 bc_program_addFunc(xstrdup("(main)"), &idx);
7176 bc_program_addFunc(xstrdup("(read)"), &idx);
7178 bc_vec_init(&G.prog.vars, sizeof(BcVec), bc_vec_free);
7179 bc_map_init(&G.prog.var_map);
7181 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7182 bc_map_init(&G.prog.arr_map);
7184 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
7185 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
7186 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7187 bc_vec_init(&G.prog.stack, sizeof(BcInstPtr), NULL);
7188 bc_vec_push(&G.prog.stack, &ip);
7191 static void bc_vm_init(const char *env_len)
7193 size_t len = bc_vm_envLen(env_len);
7195 bc_vec_init(&G.files, sizeof(char *), NULL);
7198 if (getenv("POSIXLY_CORRECT"))
7199 G.flags |= BC_FLAG_S;
7203 bc_program_init(len);
7205 bc_parse_init(&G.prs, BC_PROG_MAIN);
7207 dc_parse_init(&G.prs, BC_PROG_MAIN);
7211 static BcStatus bc_vm_run(int argc, char *argv[],
7212 const char *env_len)
7216 bc_vm_init(env_len);
7217 bc_args(argc, argv);
7219 G.ttyin = isatty(0);
7220 G.tty = G.ttyin || (G.flags & BC_FLAG_I) || isatty(1);
7223 #if ENABLE_FEATURE_BC_SIGNALS
7224 signal_no_SA_RESTART_empty_mask(SIGINT, record_signo);
7226 if (!(G.flags & BC_FLAG_Q))
7231 #if ENABLE_FEATURE_CLEAN_UP
7238 int bc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7239 int bc_main(int argc, char **argv)
7242 G.sbgn = G.send = '"';
7244 return bc_vm_run(argc, argv, "BC_LINE_LENGTH");
7249 int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
7250 int dc_main(int argc, char **argv)
7256 return bc_vm_run(argc, argv, "DC_LINE_LENGTH");