1 /* bc.c - An implementation of POSIX bc.
2  *
3  * Copyright 2018 Gavin D. Howard <yzena.tech@gmail.com>
4  *
5  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/bc.html
6 
7 USE_BC(NEWTOY(bc, "i(interactive)l(mathlib)q(quiet)s(standard)w(warn)", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
8 
9 config BC
10   bool "bc"
11   default n
12   help
13     usage: bc [-ilqsw] [file ...]
14 
15     bc is a command-line calculator with a Turing-complete language.
16 
17     options:
18 
19       -i  --interactive  force interactive mode
20       -l  --mathlib      use predefined math routines:
21 
22                          s(expr)  =  sine of expr in radians
23                          c(expr)  =  cosine of expr in radians
24                          a(expr)  =  arctangent of expr, returning radians
25                          l(expr)  =  natural log of expr
26                          e(expr)  =  raises e to the power of expr
27                          j(n, x)  =  Bessel function of integer order n of x
28 
29       -q  --quiet        don't print version and copyright
30       -s  --standard     error if any non-POSIX extensions are used
31       -w  --warn         warn if any non-POSIX extensions are used
32 
33 */
34 
35 #define FOR_bc
36 #include "toys.h"
37 
38 GLOBALS(
39   // This actually needs to be a BcVm*, but the toybox build
40   // system complains if I make it so. Instead, we'll just cast.
41   char *vm;
42 
43   size_t nchars;
44   char *file, sig, max_ibase;
45   uint16_t line_len;
46 )
47 
48 #define BC_VM ((BcVm*) TT.vm)
49 
50 typedef enum BcStatus {
51 
52   BC_STATUS_SUCCESS = 0,
53   BC_STATUS_ERROR,
54   BC_STATUS_EOF,
55   BC_STATUS_EMPTY_EXPR,
56   BC_STATUS_SIGNAL,
57   BC_STATUS_QUIT,
58 
59 } BcStatus;
60 
61 typedef enum BcError {
62 
63   BC_ERROR_VM_ALLOC_ERR,
64   BC_ERROR_VM_IO_ERR,
65   BC_ERROR_VM_BIN_FILE,
66   BC_ERROR_VM_PATH_DIR,
67 
68   BC_ERROR_PARSE_EOF,
69   BC_ERROR_PARSE_CHAR,
70   BC_ERROR_PARSE_STRING,
71   BC_ERROR_PARSE_COMMENT,
72   BC_ERROR_PARSE_TOKEN,
73   BC_ERROR_EXEC_NUM_LEN,
74   BC_ERROR_EXEC_NAME_LEN,
75   BC_ERROR_EXEC_STRING_LEN,
76   BC_ERROR_PARSE_EXPR,
77   BC_ERROR_PARSE_EMPTY_EXPR,
78   BC_ERROR_PARSE_PRINT,
79   BC_ERROR_PARSE_FUNC,
80   BC_ERROR_PARSE_ASSIGN,
81   BC_ERROR_PARSE_NO_AUTO,
82   BC_ERROR_PARSE_DUP_LOCAL,
83   BC_ERROR_PARSE_BLOCK,
84   BC_ERROR_PARSE_RET_VOID,
85 
86   BC_ERROR_MATH_NEGATIVE,
87   BC_ERROR_MATH_NON_INTEGER,
88   BC_ERROR_MATH_OVERFLOW,
89   BC_ERROR_MATH_DIVIDE_BY_ZERO,
90 
91   BC_ERROR_EXEC_FILE_ERR,
92   BC_ERROR_EXEC_ARRAY_LEN,
93   BC_ERROR_EXEC_IBASE,
94   BC_ERROR_EXEC_OBASE,
95   BC_ERROR_EXEC_SCALE,
96   BC_ERROR_EXEC_READ_EXPR,
97   BC_ERROR_EXEC_REC_READ,
98   BC_ERROR_EXEC_TYPE,
99   BC_ERROR_EXEC_PARAMS,
100   BC_ERROR_EXEC_UNDEF_FUNC,
101   BC_ERROR_EXEC_VOID_VAL,
102 
103   BC_ERROR_POSIX_START,
104 
105   BC_ERROR_POSIX_NAME_LEN = BC_ERROR_POSIX_START,
106   BC_ERROR_POSIX_COMMENT,
107   BC_ERROR_POSIX_KW,
108   BC_ERROR_POSIX_DOT,
109   BC_ERROR_POSIX_RET,
110   BC_ERROR_POSIX_BOOL,
111   BC_ERROR_POSIX_REL_POS,
112   BC_ERROR_POSIX_MULTIREL,
113   BC_ERROR_POSIX_FOR1,
114   BC_ERROR_POSIX_FOR2,
115   BC_ERROR_POSIX_FOR3,
116   BC_ERROR_POSIX_BRACE,
117   BC_ERROR_POSIX_REF,
118 
119 } BcError;
120 
121 #define BC_ERR_IDX_VM (0)
122 #define BC_ERR_IDX_PARSE (1)
123 #define BC_ERR_IDX_MATH (2)
124 #define BC_ERR_IDX_EXEC (3)
125 #define BC_ERR_IDX_POSIX (4)
126 
127 #define BC_VEC_START_CAP (1<<5)
128 
129 typedef unsigned char uchar;
130 
131 typedef void (*BcVecFree)(void*);
132 
133 typedef struct BcVec {
134   char *v;
135   size_t len, cap, size;
136   BcVecFree dtor;
137 } BcVec;
138 
139 #define bc_vec_pop(v) (bc_vec_npop((v), 1))
140 #define bc_vec_top(v) (bc_vec_item_rev((v), 0))
141 
142 typedef signed char BcDig;
143 
144 typedef struct BcNum {
145   signed char *num;
146   unsigned long rdx, len, cap;
147   int neg;
148 } BcNum;
149 
150 #define BC_NUM_DEF_SIZE (16)
151 
152 // A crude, but always big enough, calculation of
153 // the size required for ibase and obase BcNum's.
154 #define BC_NUM_LONG_LOG10 ((CHAR_BIT * sizeof(unsigned long) + 1) / 2 + 1)
155 
156 #define BC_NUM_NEG(n, neg) ((((ssize_t) (n)) ^ -((ssize_t) (neg))) + (neg))
157 
158 #define BC_NUM_ONE(n) ((n)->len == 1 && (n)->rdx == 0 && (n)->num[0] == 1)
159 #define BC_NUM_INT(n) ((n)->len - (n)->rdx)
160 #define BC_NUM_CMP_ZERO(a) (BC_NUM_NEG((a)->len != 0, (a)->neg))
161 
162 typedef BcStatus (*BcNumBinaryOp)(BcNum*, BcNum*, BcNum*, size_t);
163 typedef size_t (*BcNumBinaryOpReq)(BcNum*, BcNum*, size_t);
164 typedef void (*BcNumDigitOp)(size_t, size_t, int);
165 
166 void bc_num_init(BcNum *n, size_t req);
167 void bc_num_expand(BcNum *n, size_t req);
168 void bc_num_copy(BcNum *d, BcNum *s);
169 void bc_num_createCopy(BcNum *d, BcNum *s);
170 void bc_num_createFromUlong(BcNum *n, unsigned long val);
171 void bc_num_free(void *num);
172 
173 BcStatus bc_num_ulong(BcNum *n, unsigned long *result);
174 void bc_num_ulong2num(BcNum *n, unsigned long val);
175 
176 BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale);
177 BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale);
178 BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale);
179 BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale);
180 BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale);
181 BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale);
182 BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale);
183 BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale);
184 
185 size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale);
186 
187 size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale);
188 size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale);
189 
190 typedef enum BcInst {
191 
192   BC_INST_INC_POST = 0,
193   BC_INST_DEC_POST,
194   BC_INST_INC_PRE,
195   BC_INST_DEC_PRE,
196 
197   BC_INST_NEG,
198   BC_INST_BOOL_NOT,
199 
200   BC_INST_POWER,
201   BC_INST_MULTIPLY,
202   BC_INST_DIVIDE,
203   BC_INST_MODULUS,
204   BC_INST_PLUS,
205   BC_INST_MINUS,
206 
207   BC_INST_REL_EQ,
208   BC_INST_REL_LE,
209   BC_INST_REL_GE,
210   BC_INST_REL_NE,
211   BC_INST_REL_LT,
212   BC_INST_REL_GT,
213 
214   BC_INST_BOOL_OR,
215   BC_INST_BOOL_AND,
216 
217   BC_INST_ASSIGN_POWER,
218   BC_INST_ASSIGN_MULTIPLY,
219   BC_INST_ASSIGN_DIVIDE,
220   BC_INST_ASSIGN_MODULUS,
221   BC_INST_ASSIGN_PLUS,
222   BC_INST_ASSIGN_MINUS,
223   BC_INST_ASSIGN,
224 
225   BC_INST_NUM,
226   BC_INST_VAR,
227   BC_INST_ARRAY_ELEM,
228   BC_INST_ARRAY,
229 
230   BC_INST_LAST,
231   BC_INST_IBASE,
232   BC_INST_OBASE,
233   BC_INST_SCALE,
234   BC_INST_LENGTH,
235   BC_INST_SCALE_FUNC,
236   BC_INST_SQRT,
237   BC_INST_ABS,
238   BC_INST_READ,
239 
240   BC_INST_PRINT,
241   BC_INST_PRINT_POP,
242   BC_INST_STR,
243   BC_INST_PRINT_STR,
244 
245   BC_INST_JUMP,
246   BC_INST_JUMP_ZERO,
247 
248   BC_INST_CALL,
249 
250   BC_INST_RET,
251   BC_INST_RET0,
252   BC_INST_RET_VOID,
253 
254   BC_INST_HALT,
255 
256   BC_INST_POP,
257   BC_INST_POP_EXEC,
258 
259 } BcInst;
260 
261 typedef struct BcFunc {
262 
263   BcVec code;
264   BcVec labels;
265   BcVec autos;
266   size_t nparams;
267 
268   BcVec strs;
269   BcVec consts;
270 
271   char *name;
272   int voidfn;
273 
274 } BcFunc;
275 
276 typedef enum BcResultType {
277 
278   BC_RESULT_VAR,
279   BC_RESULT_ARRAY_ELEM,
280   BC_RESULT_ARRAY,
281 
282   BC_RESULT_STR,
283 
284   BC_RESULT_CONSTANT,
285   BC_RESULT_TEMP,
286 
287   BC_RESULT_VOID,
288   BC_RESULT_ONE,
289   BC_RESULT_LAST,
290   BC_RESULT_IBASE,
291   BC_RESULT_OBASE,
292   BC_RESULT_SCALE,
293 
294 } BcResultType;
295 
296 typedef union BcResultData {
297   BcNum n;
298   BcVec v;
299   struct str_len id;
300 } BcResultData;
301 
302 typedef struct BcResult {
303   BcResultType t;
304   BcResultData d;
305 } BcResult;
306 
307 typedef struct BcInstPtr {
308   size_t func;
309   size_t idx;
310   size_t len;
311 } BcInstPtr;
312 
313 typedef enum BcType {
314   BC_TYPE_VAR,
315   BC_TYPE_ARRAY,
316 } BcType;
317 
318 void bc_array_expand(BcVec *a, size_t len);
319 int bc_id_cmp(struct str_len *e1, struct str_len *e2);
320 
321 #define bc_lex_err(l, e) (bc_vm_error((e), (l)->line))
322 #define bc_lex_verr(l, e, ...) (bc_vm_error((e), (l)->line, __VA_ARGS__))
323 
324 #define BC_LEX_NUM_CHAR(c, l, pt) \
325   (isdigit(c) || ((c) >= 'A' && (c) <= (l)) || ((c) == '.' && !(pt)))
326 
327 // BC_LEX_NEG is not used in lexing; it is only for parsing.
328 typedef enum BcLexType {
329 
330   BC_LEX_EOF,
331   BC_LEX_INVALID,
332 
333   BC_LEX_OP_INC,
334   BC_LEX_OP_DEC,
335 
336   BC_LEX_NEG,
337   BC_LEX_OP_BOOL_NOT,
338 
339   BC_LEX_OP_POWER,
340   BC_LEX_OP_MULTIPLY,
341   BC_LEX_OP_DIVIDE,
342   BC_LEX_OP_MODULUS,
343   BC_LEX_OP_PLUS,
344   BC_LEX_OP_MINUS,
345 
346   BC_LEX_OP_REL_EQ,
347   BC_LEX_OP_REL_LE,
348   BC_LEX_OP_REL_GE,
349   BC_LEX_OP_REL_NE,
350   BC_LEX_OP_REL_LT,
351   BC_LEX_OP_REL_GT,
352 
353   BC_LEX_OP_BOOL_OR,
354   BC_LEX_OP_BOOL_AND,
355 
356   BC_LEX_OP_ASSIGN_POWER,
357   BC_LEX_OP_ASSIGN_MULTIPLY,
358   BC_LEX_OP_ASSIGN_DIVIDE,
359   BC_LEX_OP_ASSIGN_MODULUS,
360   BC_LEX_OP_ASSIGN_PLUS,
361   BC_LEX_OP_ASSIGN_MINUS,
362   BC_LEX_OP_ASSIGN,
363 
364   BC_LEX_NLINE,
365   BC_LEX_WHITESPACE,
366 
367   BC_LEX_LPAREN,
368   BC_LEX_RPAREN,
369 
370   BC_LEX_LBRACKET,
371   BC_LEX_COMMA,
372   BC_LEX_RBRACKET,
373 
374   BC_LEX_LBRACE,
375   BC_LEX_SCOLON,
376   BC_LEX_RBRACE,
377 
378   BC_LEX_STR,
379   BC_LEX_NAME,
380   BC_LEX_NUMBER,
381 
382   BC_LEX_KEY_AUTO,
383   BC_LEX_KEY_BREAK,
384   BC_LEX_KEY_CONTINUE,
385   BC_LEX_KEY_DEFINE,
386   BC_LEX_KEY_FOR,
387   BC_LEX_KEY_IF,
388   BC_LEX_KEY_LIMITS,
389   BC_LEX_KEY_RETURN,
390   BC_LEX_KEY_WHILE,
391   BC_LEX_KEY_HALT,
392   BC_LEX_KEY_LAST,
393   BC_LEX_KEY_IBASE,
394   BC_LEX_KEY_OBASE,
395   BC_LEX_KEY_SCALE,
396   BC_LEX_KEY_LENGTH,
397   BC_LEX_KEY_PRINT,
398   BC_LEX_KEY_SQRT,
399   BC_LEX_KEY_ABS,
400   BC_LEX_KEY_QUIT,
401   BC_LEX_KEY_READ,
402   BC_LEX_KEY_ELSE,
403 
404 } BcLexType;
405 
406 typedef struct BcLex {
407 
408   char *buf;
409   size_t i;
410   size_t line;
411   size_t len;
412 
413   BcLexType t;
414   BcLexType last;
415   BcVec str;
416 
417 } BcLex;
418 
419 #define BC_PARSE_REL (1<<0)
420 #define BC_PARSE_PRINT (1<<1)
421 #define BC_PARSE_NOCALL (1<<2)
422 #define BC_PARSE_NOREAD (1<<3)
423 #define BC_PARSE_ARRAY (1<<4)
424 
425 #define bc_parse_push(p, i) (bc_vec_pushByte(&(p)->func->code, i))
426 #define bc_parse_number(p)(bc_parse_addId((p), BC_INST_NUM))
427 #define bc_parse_string(p)(bc_parse_addId((p), BC_INST_STR))
428 
429 #define bc_parse_err(p, e) (bc_vm_error((e), (p)->l.line))
430 #define bc_parse_verr(p, e, ...) (bc_vm_error((e), (p)->l.line, __VA_ARGS__))
431 
432 typedef struct BcParseNext {
433   char len, tokens[4];
434 } BcParseNext;
435 
436 #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
437 #define BC_PARSE_NEXT(a, ...) { .len = a, BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }
438 
439 struct BcProgram;
440 
441 typedef struct BcParse {
442 
443   BcLex l;
444 
445   BcVec flags;
446   BcVec exits;
447   BcVec conds;
448   BcVec ops;
449 
450   struct BcProgram *prog;
451   BcFunc *func;
452   size_t fidx;
453 
454   int auto_part;
455 
456 } BcParse;
457 
458 typedef struct BcLexKeyword {
459   char data, name[9];
460 } BcLexKeyword;
461 
462 #define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))
463 
464 #define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))
465 #define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))
466 
467 #define BC_LEX_KW_ENTRY(a, b, c) \
468   { .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c),.name = a }
469 
470 #define bc_lex_posixErr(l, e) (bc_vm_posixError((e), (l)->line))
471 #define bc_lex_vposixErr(l, e, ...) \
472   (bc_vm_posixError((e), (l)->line, __VA_ARGS__))
473 
474 BcStatus bc_lex_token(BcLex *l);
475 
476 #define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))
477 #define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))
478 
479 #define BC_PARSE_FLAG_BRACE (1<<0)
480 #define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)
481 
482 #define BC_PARSE_FLAG_FUNC_INNER (1<<1)
483 #define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)
484 
485 #define BC_PARSE_FLAG_FUNC (1<<2)
486 #define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)
487 
488 #define BC_PARSE_FLAG_BODY (1<<3)
489 #define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)
490 
491 #define BC_PARSE_FLAG_LOOP (1<<4)
492 #define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)
493 
494 #define BC_PARSE_FLAG_LOOP_INNER (1<<5)
495 #define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)
496 
497 #define BC_PARSE_FLAG_IF (1<<6)
498 #define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)
499 
500 #define BC_PARSE_FLAG_ELSE (1<<7)
501 #define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)
502 
503 #define BC_PARSE_FLAG_IF_END (1<<8)
504 #define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)
505 
506 #define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)
507 
508 #define BC_PARSE_DELIMITER(t) \
509   ((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)
510 
511 #define BC_PARSE_BLOCK_STMT(f) \
512   ((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))
513 
514 #define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))
515 
516 #define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)]
517 #define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))
518 #define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))
519 
520 #define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))
521 #define BC_PARSE_LEAF(prev, bin_last, rparen) \
522   (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
523 #define BC_PARSE_INST_VAR(t) \
524   ((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)
525 
526 #define BC_PARSE_PREV_PREFIX(p) \
527   ((p) >= BC_INST_INC_PRE && (p) <= BC_INST_BOOL_NOT)
528 #define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)
529 
530 // We can calculate the conversion between tokens and exprs by subtracting the
531 // position of the first operator in the lex enum and adding the position of
532 // the first in the expr enum. Note: This only works for binary operators.
533 #define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG))
534 
535 #define bc_parse_posixErr(p, e) (bc_vm_posixError((e), (p)->l.line))
536 
537 BcStatus bc_parse_parse(BcParse *p);
538 BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next);
539 void bc_parse_noElse(BcParse *p);
540 
541 #define BC_PROG_ONE_CAP (1)
542 
543 typedef struct BcProgram {
544 
545   size_t scale;
546 
547   BcNum ib;
548   size_t ib_t;
549   BcNum ob;
550   size_t ob_t;
551 
552   BcVec results;
553   BcVec stack;
554 
555   BcVec fns;
556   BcVec fn_map;
557 
558   BcVec vars;
559   BcVec var_map;
560 
561   BcVec arrs;
562   BcVec arr_map;
563 
564   BcNum one;
565   BcNum last;
566 
567   signed char ib_num[BC_NUM_LONG_LOG10], ob_num[BC_NUM_LONG_LOG10],
568          one_num[BC_PROG_ONE_CAP];
569 } BcProgram;
570 
571 #define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) (n)))
572 
573 #define BC_PROG_MAIN (0)
574 #define BC_PROG_READ (1)
575 
576 #define BC_PROG_STR(n) (!(n)->num && !(n)->cap)
577 #define BC_PROG_NUM(r, n) \
578   ((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
579 
580 typedef void (*BcProgramUnary)(BcResult*, BcNum*);
581 
582 void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name);
583 size_t bc_program_insertFunc(BcProgram *p, char *name);
584 BcStatus bc_program_reset(BcProgram *p, BcStatus s);
585 BcStatus bc_program_exec(BcProgram *p);
586 
587 unsigned long bc_program_scale(BcNum *n);
588 unsigned long bc_program_len(BcNum *n);
589 
590 void bc_program_negate(BcResult *r, BcNum *n);
591 void bc_program_not(BcResult *r, BcNum *n);
592 
593 #define BC_FLAG_TTYIN (1<<7)
594 #define BC_TTYIN (toys.optflags & BC_FLAG_TTYIN)
595 
596 #define BC_MAX_OBASE ((unsigned long) INT_MAX)
597 #define BC_MAX_DIM ((unsigned long) INT_MAX)
598 #define BC_MAX_SCALE ((unsigned long) UINT_MAX)
599 #define BC_MAX_STRING ((unsigned long) UINT_MAX - 1)
600 #define BC_MAX_NAME BC_MAX_STRING
601 #define BC_MAX_NUM BC_MAX_STRING
602 #define BC_MAX_EXP ((unsigned long) ULONG_MAX)
603 #define BC_MAX_VARS ((unsigned long) SIZE_MAX - 1)
604 
605 #define bc_vm_err(e) (bc_vm_error((e), 0))
606 #define bc_vm_verr(e, ...) (bc_vm_error((e), 0, __VA_ARGS__))
607 
608 typedef struct BcVm {
609   BcParse prs;
610   BcProgram prog;
611 } BcVm;
612 
613 BcStatus bc_vm_posixError(BcError e, size_t line, ...);
614 
615 BcStatus bc_vm_error(BcError e, size_t line, ...);
616 
617 char bc_sig_msg[] = "\ninterrupt (type \"quit\" to exit)\n";
618 
619 char bc_copyright[] =
620   "Copyright (c) 2018 Gavin D. Howard and contributors\n"
621   "Report bugs at: https://github.com/gavinhoward/bc\n\n"
622   "This is free software with ABSOLUTELY NO WARRANTY.\n";
623 
624 char *bc_err_fmt = "\n%s error: ";
625 char *bc_warn_fmt = "\n%s warning: ";
626 char *bc_err_line = ":%zu";
627 
628 char *bc_errs[] = {
629   "VM",
630   "Parse",
631   "Math",
632   "Runtime",
633   "POSIX",
634 };
635 
636 char bc_err_ids[] = {
637   BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM, BC_ERR_IDX_VM,
638   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
639   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
640   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
641   BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE, BC_ERR_IDX_PARSE,
642   BC_ERR_IDX_PARSE,
643   BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH, BC_ERR_IDX_MATH,
644   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
645   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
646   BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC, BC_ERR_IDX_EXEC,
647   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
648   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
649   BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX, BC_ERR_IDX_POSIX,
650   BC_ERR_IDX_POSIX,
651 };
652 
653 char *bc_err_msgs[] = {
654 
655   "memory allocation error",
656   "I/O error",
657   "file is not ASCII: %s",
658   "path is a directory: %s",
659 
660   "end of file",
661   "bad character (%c)",
662   "string end could not be found",
663   "comment end could not be found",
664   "bad token",
665   "name too long: must be [1, %lu]",
666   "string too long: must be [1, %lu]",
667   "array too long; must be [1, %lu]",
668   "bad expression",
669   "empty expression",
670   "bad print statement",
671   "bad function definition",
672   "bad assignment: left side must be scale, ibase, "
673     "obase, last, var, or array element",
674   "no auto variable found",
675   "function parameter or auto \"%s\" already exists",
676   "block end could not be found",
677   "cannot return a value from void function: %s()",
678 
679   "negative number",
680   "non integer number",
681   "overflow",
682   "divide by zero",
683 
684   "could not open file: %s",
685   "number too long: must be [1, %lu]",
686   "bad ibase; must be [%lu, %lu]",
687   "bad obase; must be [%lu, %lu]",
688   "bad scale; must be [%lu, %lu]",
689   "bad read() expression",
690   "read() call inside of a read() call",
691   "variable is wrong type",
692   "mismatched parameters; need %zu, have %zu",
693   "undefined function: %s()",
694   "cannot use a void value in an expression",
695 
696   "POSIX does not allow names longer than 1 character, like \"%s\"",
697   "POSIX does not allow '#' script comments",
698   "POSIX does not allow \"%s\" as a keyword",
699   "POSIX does not allow a period ('.') as a shortcut for the last result",
700   "POSIX requires parentheses around return expressions",
701   "POSIX does not allow the \"%s\" operators",
702   "POSIX does not allow comparison operators outside if or loops",
703   "POSIX requires zero or one comparison operator per condition",
704   "POSIX does not allow an empty init expression in a for loop",
705   "POSIX does not allow an empty condition expression in a for loop",
706   "POSIX does not allow an empty update expression in a for loop",
707   "POSIX requires the left brace be on the same line as the function header",
708   "POSIX does not allow array references as function parameters",
709 
710 };
711 
712 char bc_func_main[] = "(main)";
713 char bc_func_read[] = "(read)";
714 
715 BcLexKeyword bc_lex_kws[] = {
716   BC_LEX_KW_ENTRY("auto", 4, 1),
717   BC_LEX_KW_ENTRY("break", 5, 1),
718   BC_LEX_KW_ENTRY("continue", 8, 0),
719   BC_LEX_KW_ENTRY("define", 6, 1),
720   BC_LEX_KW_ENTRY("for", 3, 1),
721   BC_LEX_KW_ENTRY("if", 2, 1),
722   BC_LEX_KW_ENTRY("limits", 6, 0),
723   BC_LEX_KW_ENTRY("return", 6, 1),
724   BC_LEX_KW_ENTRY("while", 5, 1),
725   BC_LEX_KW_ENTRY("halt", 4, 0),
726   BC_LEX_KW_ENTRY("last", 4, 0),
727   BC_LEX_KW_ENTRY("ibase", 5, 1),
728   BC_LEX_KW_ENTRY("obase", 5, 1),
729   BC_LEX_KW_ENTRY("scale", 5, 1),
730   BC_LEX_KW_ENTRY("length", 6, 1),
731   BC_LEX_KW_ENTRY("print", 5, 0),
732   BC_LEX_KW_ENTRY("sqrt", 4, 1),
733   BC_LEX_KW_ENTRY("abs", 3, 0),
734   BC_LEX_KW_ENTRY("quit", 4, 1),
735   BC_LEX_KW_ENTRY("read", 4, 0),
736   BC_LEX_KW_ENTRY("else", 4, 0),
737 };
738 
739 size_t bc_lex_kws_len = sizeof(bc_lex_kws) / sizeof(BcLexKeyword);
740 
741 char *bc_parse_const1 = "1";
742 
743 // This is an array of data for operators that correspond to token types.
744 uchar bc_parse_ops[] = {
745   BC_PARSE_OP(0, 0), BC_PARSE_OP(0, 0),
746   BC_PARSE_OP(1, 0), BC_PARSE_OP(1, 0),
747   BC_PARSE_OP(4, 0),
748   BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1), BC_PARSE_OP(5, 1),
749   BC_PARSE_OP(6, 1), BC_PARSE_OP(6, 1),
750   BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1),
751   BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1), BC_PARSE_OP(9, 1),
752   BC_PARSE_OP(11, 1), BC_PARSE_OP(10, 1),
753   BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0),
754   BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0), BC_PARSE_OP(8, 0),
755   BC_PARSE_OP(8, 0),
756 };
757 
758 // These identify what tokens can come after expressions in certain cases.
759 BcParseNext bc_parse_next_expr =
760   BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
761 BcParseNext bc_parse_next_param =
762   BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
763 BcParseNext bc_parse_next_print =
764   BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
765 BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
766 BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
767 BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
768 BcParseNext bc_parse_next_read =
769   BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
770 
771 char bc_num_hex_digits[] = "0123456789ABCDEF";
772 
773 BcNumBinaryOp bc_program_ops[] = {
774   bc_num_pow, bc_num_mul, bc_num_div, bc_num_mod, bc_num_add, bc_num_sub,
775 };
776 
777 BcNumBinaryOpReq bc_program_opReqs[] = {
778   bc_num_powReq, bc_num_mulReq, bc_num_mulReq, bc_num_mulReq,
779   bc_num_addReq, bc_num_addReq,
780 };
781 
782 BcProgramUnary bc_program_unarys[] = {
783   bc_program_negate, bc_program_not,
784 };
785 
786 char bc_program_stdin_name[] = "<stdin>";
787 char bc_program_ready_msg[] = "ready for more input\n";
788 
789 char *bc_lib_name = "gen/lib.bc";
790 
791 char bc_lib[] = {
792   115,99,97,108,101,61,50,48,10,100,101,102,105,110,101,32,101,40,120,41,123,
793   10,97,117,116,111,32,98,44,115,44,110,44,114,44,100,44,105,44,112,44,102,44,
794   118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120,
795   60,48,41,123,10,110,61,49,10,120,61,45,120,10,125,10,115,61,115,99,97,108,101,
796   10,114,61,54,43,115,43,46,52,52,42,120,10,115,99,97,108,101,61,115,99,97,108,
797   101,40,120,41,43,49,10,119,104,105,108,101,40,120,62,49,41,123,10,100,43,61,
798   49,10,120,47,61,50,10,115,99,97,108,101,43,61,49,10,125,10,115,99,97,108,101,
799   61,114,10,114,61,120,43,49,10,112,61,120,10,102,61,118,61,49,10,102,111,114,
800   40,105,61,50,59,118,59,43,43,105,41,123,10,112,42,61,120,10,102,42,61,105,10,
801   118,61,112,47,102,10,114,43,61,118,10,125,10,119,104,105,108,101,40,100,45,
802   45,41,114,42,61,114,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,
803   10,105,102,40,110,41,114,101,116,117,114,110,40,49,47,114,41,10,114,101,116,
804   117,114,110,40,114,47,49,41,10,125,10,100,101,102,105,110,101,32,108,40,120,
805   41,123,10,97,117,116,111,32,98,44,115,44,114,44,112,44,97,44,113,44,105,44,
806   118,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,105,102,40,120,
807   60,61,48,41,123,10,114,61,40,49,45,49,48,94,115,99,97,108,101,41,47,49,10,105,
808   98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125,10,115,61,115,
809   99,97,108,101,10,115,99,97,108,101,43,61,54,10,112,61,50,10,119,104,105,108,
810   101,40,120,62,61,50,41,123,10,112,42,61,50,10,120,61,115,113,114,116,40,120,
811   41,10,125,10,119,104,105,108,101,40,120,60,61,46,53,41,123,10,112,42,61,50,
812   10,120,61,115,113,114,116,40,120,41,10,125,10,114,61,97,61,40,120,45,49,41,
813   47,40,120,43,49,41,10,113,61,97,42,97,10,118,61,49,10,102,111,114,40,105,61,
814   51,59,118,59,105,43,61,50,41,123,10,97,42,61,113,10,118,61,97,47,105,10,114,
815   43,61,118,10,125,10,114,42,61,112,10,115,99,97,108,101,61,115,10,105,98,97,
816   115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10,125,10,100,101,
817   102,105,110,101,32,115,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114,
818   44,97,44,113,44,105,10,105,102,40,120,60,48,41,114,101,116,117,114,110,40,45,
819   115,40,45,120,41,41,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,
820   115,61,115,99,97,108,101,10,115,99,97,108,101,61,49,46,49,42,115,43,50,10,97,
821   61,97,40,49,41,10,115,99,97,108,101,61,48,10,113,61,40,120,47,97,43,50,41,47,
822   52,10,120,45,61,52,42,113,42,97,10,105,102,40,113,37,50,41,120,61,45,120,10,
823   115,99,97,108,101,61,115,43,50,10,114,61,97,61,120,10,113,61,45,120,42,120,
824   10,102,111,114,40,105,61,51,59,97,59,105,43,61,50,41,123,10,97,42,61,113,47,
825   40,105,42,40,105,45,49,41,41,10,114,43,61,97,10,125,10,115,99,97,108,101,61,
826   115,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,47,49,41,10,
827   125,10,100,101,102,105,110,101,32,99,40,120,41,123,10,97,117,116,111,32,98,
828   44,115,10,98,61,105,98,97,115,101,10,105,98,97,115,101,61,65,10,115,61,115,
829   99,97,108,101,10,115,99,97,108,101,42,61,49,46,50,10,120,61,115,40,50,42,97,
830   40,49,41,43,120,41,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10,
831   114,101,116,117,114,110,40,120,47,49,41,10,125,10,100,101,102,105,110,101,32,
832   97,40,120,41,123,10,97,117,116,111,32,98,44,115,44,114,44,110,44,97,44,109,
833   44,116,44,102,44,105,44,117,10,98,61,105,98,97,115,101,10,105,98,97,115,101,
834   61,65,10,110,61,49,10,105,102,40,120,60,48,41,123,10,110,61,45,49,10,120,61,
835   45,120,10,125,10,105,102,40,115,99,97,108,101,60,54,53,41,123,10,105,102,40,
836   120,61,61,49,41,123,10,114,61,46,55,56,53,51,57,56,49,54,51,51,57,55,52,52,
837   56,51,48,57,54,49,53,54,54,48,56,52,53,56,49,57,56,55,53,55,50,49,48,52,57,
838   50,57,50,51,52,57,56,52,51,55,55,54,52,53,53,50,52,51,55,51,54,49,52,56,48,
839   47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,40,114,41,10,125,
840   10,105,102,40,120,61,61,46,50,41,123,10,114,61,46,49,57,55,51,57,53,53,53,57,
841   56,52,57,56,56,48,55,53,56,51,55,48,48,52,57,55,54,53,49,57,52,55,57,48,50,
842   57,51,52,52,55,53,56,53,49,48,51,55,56,55,56,53,50,49,48,49,53,49,55,54,56,
843   56,57,52,48,50,47,110,10,105,98,97,115,101,61,98,10,114,101,116,117,114,110,
844   40,114,41,10,125,10,125,10,115,61,115,99,97,108,101,10,105,102,40,120,62,46,
845   50,41,123,10,115,99,97,108,101,43,61,53,10,97,61,97,40,46,50,41,10,125,10,115,
846   99,97,108,101,61,115,43,51,10,119,104,105,108,101,40,120,62,46,50,41,123,10,
847   109,43,61,49,10,120,61,40,120,45,46,50,41,47,40,49,43,46,50,42,120,41,10,125,
848   10,114,61,117,61,120,10,102,61,45,120,42,120,10,116,61,49,10,102,111,114,40,
849   105,61,51,59,116,59,105,43,61,50,41,123,10,117,42,61,102,10,116,61,117,47,105,
850   10,114,43,61,116,10,125,10,115,99,97,108,101,61,115,10,105,98,97,115,101,61,
851   98,10,114,101,116,117,114,110,40,40,109,42,97,43,114,41,47,110,41,10,125,10,
852   100,101,102,105,110,101,32,106,40,110,44,120,41,123,10,97,117,116,111,32,98,
853   44,115,44,111,44,97,44,105,44,118,44,102,10,98,61,105,98,97,115,101,10,105,
854   98,97,115,101,61,65,10,115,61,115,99,97,108,101,10,115,99,97,108,101,61,48,
855   10,110,47,61,49,10,105,102,40,110,60,48,41,123,10,110,61,45,110,10,111,61,110,
856   37,50,10,125,10,97,61,49,10,102,111,114,40,105,61,50,59,105,60,61,110,59,43,
857   43,105,41,97,42,61,105,10,115,99,97,108,101,61,49,46,53,42,115,10,97,61,40,
858   120,94,110,41,47,50,94,110,47,97,10,114,61,118,61,49,10,102,61,45,120,42,120,
859   47,52,10,115,99,97,108,101,43,61,108,101,110,103,116,104,40,97,41,45,115,99,
860   97,108,101,40,97,41,10,102,111,114,40,105,61,49,59,118,59,43,43,105,41,123,
861   10,118,61,118,42,102,47,105,47,40,110,43,105,41,10,114,43,61,118,10,125,10,
862   115,99,97,108,101,61,115,10,105,98,97,115,101,61,98,10,105,102,40,111,41,97,
863   61,45,97,10,114,101,116,117,114,110,40,97,42,114,47,49,41,10,125,10,0
864 };
865 
bc_vec_grow(BcVec * v,unsigned long n)866 static void bc_vec_grow(BcVec *v, unsigned long n) {
867   unsigned long old = v->cap;
868 
869   while (v->cap < v->len + n) v->cap *= 2;
870   if (old != v->cap) v->v = xrealloc(v->v, v->size * v->cap);
871 }
872 
bc_vec_init(BcVec * v,size_t esize,BcVecFree dtor)873 void bc_vec_init(BcVec *v, size_t esize, BcVecFree dtor) {
874   v->size = esize;
875   v->cap = BC_VEC_START_CAP;
876   v->len = 0;
877   v->dtor = dtor;
878   v->v = xmalloc(esize * BC_VEC_START_CAP);
879 }
880 
bc_vec_expand(BcVec * v,size_t req)881 void bc_vec_expand(BcVec *v, size_t req) {
882   if (v->cap < req) {
883     v->v = xrealloc(v->v, v->size * req);
884     v->cap = req;
885   }
886 }
887 
bc_vec_npop(BcVec * v,size_t n)888 void bc_vec_npop(BcVec *v, size_t n) {
889   if (!v->dtor) v->len -= n;
890   else {
891     size_t len = v->len - n;
892     while (v->len > len) v->dtor(v->v + (v->size * --v->len));
893   }
894 }
895 
bc_vec_npush(BcVec * v,size_t n,void * data)896 void bc_vec_npush(BcVec *v, size_t n, void *data) {
897   bc_vec_grow(v, n);
898   memcpy(v->v + (v->size * v->len), data, v->size * n);
899   v->len += n;
900 }
901 
bc_vec_push(BcVec * v,void * data)902 void bc_vec_push(BcVec *v, void *data) {
903   bc_vec_npush(v, 1, data);
904 }
905 
bc_vec_pushByte(BcVec * v,uchar data)906 void bc_vec_pushByte(BcVec *v, uchar data) {
907   bc_vec_push(v, &data);
908 }
909 
bc_vec_pushIndex(BcVec * v,size_t idx)910 void bc_vec_pushIndex(BcVec *v, size_t idx) {
911 
912   uchar amt, nums[sizeof(size_t)];
913 
914   for (amt = 0; idx; ++amt) {
915     nums[amt] = (uchar) idx;
916     idx &= ((size_t) ~(UCHAR_MAX));
917     idx >>= sizeof(uchar) * CHAR_BIT;
918   }
919 
920   bc_vec_push(v, &amt);
921   bc_vec_npush(v, amt, nums);
922 }
923 
bc_vec_pushAt(BcVec * v,void * data,size_t idx)924 static void bc_vec_pushAt(BcVec *v, void *data, size_t idx) {
925 
926   if (idx == v->len) bc_vec_push(v, data);
927   else {
928 
929     char *ptr;
930 
931     bc_vec_grow(v, 1);
932 
933     ptr = v->v + v->size * idx;
934 
935     memmove(ptr + v->size, ptr, v->size * (v->len++ - idx));
936     memmove(ptr, data, v->size);
937   }
938 }
939 
bc_vec_string(BcVec * v,size_t len,char * str)940 void bc_vec_string(BcVec *v, size_t len, char *str) {
941 
942   bc_vec_npop(v, v->len);
943   bc_vec_expand(v, len + 1);
944   memcpy(v->v, str, len);
945   v->len = len;
946 
947   bc_vec_pushByte(v, '\0');
948 }
949 
bc_vec_concat(BcVec * v,char * str)950 void bc_vec_concat(BcVec *v, char *str) {
951   unsigned long len;
952 
953   if (!v->len) bc_vec_pushByte(v, '\0');
954 
955   len = strlen(str);
956   bc_vec_grow(v, len);
957   strcpy(v->v+v->len-1, str);
958   v->len += len;
959 }
960 
bc_vec_empty(BcVec * v)961 void bc_vec_empty(BcVec *v) {
962   bc_vec_npop(v, v->len);
963   bc_vec_pushByte(v, '\0');
964 }
965 
bc_vec_item(BcVec * v,size_t idx)966 void* bc_vec_item(BcVec *v, size_t idx) {
967   return v->v + v->size * idx;
968 }
969 
bc_vec_item_rev(BcVec * v,size_t idx)970 void* bc_vec_item_rev(BcVec *v, size_t idx) {
971   return v->v + v->size * (v->len - idx - 1);
972 }
973 
bc_vec_free(void * vec)974 void bc_vec_free(void *vec) {
975   BcVec *v = (BcVec*) vec;
976   bc_vec_npop(v, v->len);
977   free(v->v);
978 }
979 
bc_map_find(BcVec * v,struct str_len * ptr)980 static size_t bc_map_find(BcVec *v, struct str_len *ptr) {
981 
982   size_t low = 0, high = v->len;
983 
984   while (low < high) {
985 
986     size_t mid = (low + high) / 2;
987     struct str_len *id = bc_vec_item(v, mid);
988     int result = bc_id_cmp(ptr, id);
989 
990     if (!result) return mid;
991     else if (result < 0) high = mid;
992     else low = mid + 1;
993   }
994 
995   return low;
996 }
997 
bc_map_insert(BcVec * v,struct str_len * ptr,size_t * i)998 int bc_map_insert(BcVec *v, struct str_len *ptr, size_t *i) {
999 
1000   *i = bc_map_find(v, ptr);
1001 
1002   if (*i == v->len) bc_vec_push(v, ptr);
1003   else if (!bc_id_cmp(ptr, bc_vec_item(v, *i))) return 0;
1004   else bc_vec_pushAt(v, ptr, *i);
1005 
1006   return 1;
1007 }
1008 
bc_map_index(BcVec * v,struct str_len * ptr)1009 size_t bc_map_index(BcVec *v, struct str_len *ptr) {
1010   size_t i = bc_map_find(v, ptr);
1011   if (i >= v->len) return SIZE_MAX;
1012   return bc_id_cmp(ptr, bc_vec_item(v, i)) ? SIZE_MAX : i;
1013 }
1014 
bc_read_binary(char * buf,size_t size)1015 static int bc_read_binary(char *buf, size_t size) {
1016 
1017   size_t i;
1018 
1019   for (i = 0; i < size; ++i)
1020     if ((buf[i]<' ' && !isspace(buf[i])) || buf[i]>'~') return 1;
1021 
1022   return 0;
1023 }
1024 
bc_read_chars(BcVec * vec,char * prompt)1025 BcStatus bc_read_chars(BcVec *vec, char *prompt) {
1026 
1027   int i;
1028   signed char c = 0;
1029 
1030   bc_vec_npop(vec, vec->len);
1031 
1032   if (BC_TTYIN && !FLAG(s)) {
1033     fputs(prompt, stderr);
1034     fflush(stderr);
1035   }
1036 
1037   while (!TT.sig && c != '\n') {
1038 
1039     i = fgetc(stdin);
1040 
1041     if (i == EOF) {
1042 
1043       if (errno == EINTR) {
1044 
1045         if (TT.sig == SIGTERM || TT.sig == SIGQUIT) return BC_STATUS_SIGNAL;
1046 
1047         TT.sig = 0;
1048 
1049         if (BC_TTYIN) {
1050           fputs(bc_program_ready_msg, stderr);
1051           if (!FLAG(s)) fputs(prompt, stderr);
1052           fflush(stderr);
1053         }
1054         else return BC_STATUS_SIGNAL;
1055 
1056         continue;
1057       }
1058 
1059       bc_vec_pushByte(vec, '\0');
1060       return BC_STATUS_EOF;
1061     }
1062 
1063     c = (signed char) i;
1064     bc_vec_push(vec, &c);
1065   }
1066 
1067   bc_vec_pushByte(vec, '\0');
1068 
1069   return TT.sig ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1070 }
1071 
bc_read_line(BcVec * vec,char * prompt)1072 BcStatus bc_read_line(BcVec *vec, char *prompt) {
1073 
1074   BcStatus s;
1075 
1076   // We are about to output to stderr, so flush stdout to
1077   // make sure that we don't get the outputs mixed up.
1078   fflush(stdout);
1079 
1080   s = bc_read_chars(vec, prompt);
1081   if (s && s != BC_STATUS_EOF) return s;
1082   if (bc_read_binary(vec->v, vec->len - 1))
1083     return bc_vm_verr(BC_ERROR_VM_BIN_FILE, bc_program_stdin_name);
1084 
1085   return BC_STATUS_SUCCESS;
1086 }
1087 
bc_read_file(char * path,char ** buf)1088 BcStatus bc_read_file(char *path, char **buf) {
1089 
1090   BcError e = BC_ERROR_VM_IO_ERR;
1091   FILE *f;
1092   size_t size, read;
1093   long res;
1094   struct stat pstat;
1095 
1096   f = fopen(path, "r");
1097   if (!f) return bc_vm_verr(BC_ERROR_EXEC_FILE_ERR, path);
1098   if (fstat(fileno(f), &pstat) == -1) goto malloc_err;
1099 
1100   if (S_ISDIR(pstat.st_mode)) {
1101     e = BC_ERROR_VM_PATH_DIR;
1102     goto malloc_err;
1103   }
1104 
1105   if (fseek(f, 0, SEEK_END) == -1) goto malloc_err;
1106   res = ftell(f);
1107   if (res < 0) goto malloc_err;
1108   if (fseek(f, 0, SEEK_SET) == -1) goto malloc_err;
1109 
1110   size = (size_t) res;
1111   *buf = xmalloc(size + 1);
1112 
1113   read = fread(*buf, 1, size, f);
1114   if (read != size) goto read_err;
1115 
1116   (*buf)[size] = '\0';
1117 
1118   if (bc_read_binary(*buf, size)) {
1119     e = BC_ERROR_VM_BIN_FILE;
1120     goto read_err;
1121   }
1122 
1123   fclose(f);
1124 
1125   return BC_STATUS_SUCCESS;
1126 
1127 read_err:
1128   free(*buf);
1129 malloc_err:
1130   fclose(f);
1131   return bc_vm_verr(e, path);
1132 }
1133 
bc_num_setToZero(BcNum * n,size_t scale)1134 static void bc_num_setToZero(BcNum *n, size_t scale) {
1135   n->len = 0;
1136   n->neg = 0;
1137   n->rdx = scale;
1138 }
1139 
bc_num_one(BcNum * n)1140 void bc_num_one(BcNum *n) {
1141   bc_num_setToZero(n, 0);
1142   n->len = 1;
1143   n->num[0] = 1;
1144 }
1145 
bc_num_ten(BcNum * n)1146 void bc_num_ten(BcNum *n) {
1147   bc_num_setToZero(n, 0);
1148   n->len = 2;
1149   n->num[0] = 0;
1150   n->num[1] = 1;
1151 }
1152 
bc_num_log10(size_t i)1153 static size_t bc_num_log10(size_t i) {
1154   size_t len;
1155   for (len = 1; i; i /= 10, ++len);
1156   return len;
1157 }
1158 
bc_num_subArrays(signed char * a,signed char * b,size_t len)1159 static BcStatus bc_num_subArrays(signed char *a, signed char *b, size_t len)
1160 {
1161   size_t i, j;
1162   for (i = 0; !TT.sig && i < len; ++i) {
1163     for (a[i] -= b[i], j = 0; !TT.sig && a[i + j] < 0;) {
1164       a[i + j++] += 10;
1165       a[i + j] -= 1;
1166     }
1167   }
1168   return TT.sig ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1169 }
1170 
bc_num_compare(signed char * a,signed char * b,size_t len)1171 static ssize_t bc_num_compare(signed char *a, signed char *b, size_t len)
1172 {
1173   size_t i;
1174   int c = 0;
1175 
1176   for (i = len - 1; !TT.sig && i < len && !(c = a[i] - b[i]); --i);
1177   return BC_NUM_NEG(i + 1, c < 0);
1178 }
1179 
bc_num_cmp(BcNum * a,BcNum * b)1180 ssize_t bc_num_cmp(BcNum *a, BcNum *b) {
1181 
1182   size_t i, min, a_int, b_int, diff;
1183   signed char *max_num, *min_num;
1184   int a_max, neg = 0;
1185   ssize_t cmp;
1186 
1187   if (a == b) return 0;
1188   if (!a->len) return BC_NUM_NEG(b->len != 0, !b->neg);
1189   if (!b->len) return BC_NUM_CMP_ZERO(a);
1190   if (a->neg) {
1191     if (b->neg) neg = 1;
1192     else return -1;
1193   } else if (b->neg) return 1;
1194 
1195   a_int = BC_NUM_INT(a);
1196   b_int = BC_NUM_INT(b);
1197   a_int -= b_int;
1198   a_max = (a->rdx > b->rdx);
1199 
1200   if (a_int) return neg ? -((ssize_t) a_int) : (ssize_t) a_int;
1201 
1202   if (a_max) {
1203     min = b->rdx;
1204     diff = a->rdx - b->rdx;
1205     max_num = a->num + diff;
1206     min_num = b->num;
1207   } else {
1208     min = a->rdx;
1209     diff = b->rdx - a->rdx;
1210     max_num = b->num + diff;
1211     min_num = a->num;
1212   }
1213 
1214   cmp = bc_num_compare(max_num, min_num, b_int + min);
1215   if (cmp) return BC_NUM_NEG(cmp, (!a_max) != neg);
1216 
1217   for (max_num -= diff, i = diff - 1; !TT.sig && i < diff; --i) {
1218     if (max_num[i]) return BC_NUM_NEG(1, (!a_max) != neg);
1219   }
1220 
1221   return 0;
1222 }
1223 
bc_num_clean(BcNum * n)1224 static void bc_num_clean(BcNum *n) {
1225   while (n->len && !n->num[n->len - 1]) --n->len;
1226   if (!n->len) n->neg = 0;
1227   else if (n->len < n->rdx) n->len = n->rdx;
1228 }
1229 
bc_num_truncate(BcNum * n,size_t places)1230 void bc_num_truncate(BcNum *n, size_t places) {
1231 
1232   if (!places) return;
1233 
1234   n->rdx -= places;
1235 
1236   if (n->len) {
1237     n->len -= places;
1238     memmove(n->num, n->num + places, n->len);
1239     bc_num_clean(n);
1240   }
1241 }
1242 
bc_num_extend(BcNum * n,size_t places)1243 static void bc_num_extend(BcNum *n, size_t places) {
1244 
1245   size_t len = n->len + places;
1246 
1247   if (!places) return;
1248 
1249   if (n->cap < len) bc_num_expand(n, len);
1250 
1251   memmove(n->num + places, n->num, n->len);
1252   memset(n->num, 0, places);
1253 
1254   if (n->len) n->len += places;
1255 
1256   n->rdx += places;
1257 }
1258 
bc_num_retireMul(BcNum * n,size_t scale,int neg1,int neg2)1259 static void bc_num_retireMul(BcNum *n, size_t scale, int neg1, int neg2) {
1260 
1261   if (n->rdx < scale) bc_num_extend(n, scale - n->rdx);
1262   else bc_num_truncate(n, n->rdx - scale);
1263 
1264   bc_num_clean(n);
1265   if (n->len) n->neg = (!neg1 != !neg2);
1266 }
1267 
bc_num_split(BcNum * n,size_t idx,BcNum * a,BcNum * b)1268 static void bc_num_split(BcNum *n, size_t idx, BcNum *a, BcNum *b) {
1269 
1270   if (idx < n->len) {
1271 
1272     b->len = n->len - idx;
1273     a->len = idx;
1274     a->rdx = b->rdx = 0;
1275 
1276     memcpy(b->num, n->num + idx, b->len);
1277     memcpy(a->num, n->num, idx);
1278 
1279     bc_num_clean(b);
1280   }
1281   else bc_num_copy(a, n);
1282 
1283   bc_num_clean(a);
1284 }
1285 
bc_num_shift(BcNum * n,size_t places)1286 static BcStatus bc_num_shift(BcNum *n, size_t places) {
1287 
1288   if (!places || !n->len) return BC_STATUS_SUCCESS;
1289   if (places + n->len > BC_MAX_NUM)
1290     return bc_vm_verr(BC_ERROR_MATH_OVERFLOW, "shifted left too far");
1291 
1292   if (n->rdx >= places) n->rdx -= places;
1293   else {
1294     bc_num_extend(n, places - n->rdx);
1295     n->rdx = 0;
1296   }
1297 
1298   bc_num_clean(n);
1299 
1300   return BC_STATUS_SUCCESS;
1301 }
1302 
bc_num_inv(BcNum * a,BcNum * b,size_t scale)1303 static BcStatus bc_num_inv(BcNum *a, BcNum *b, size_t scale) {
1304 
1305   BcNum one;
1306   signed char num[2];
1307 
1308   one.cap = 2;
1309   one.num = num;
1310   bc_num_one(&one);
1311 
1312   return bc_num_div(&one, a, b, scale);
1313 }
1314 
bc_num_addDigit(signed char * num,unsigned int d,unsigned int c)1315 static unsigned int bc_num_addDigit(signed char *num, unsigned int d, unsigned int c)
1316 {
1317   d += c;
1318   *num = d % 10;
1319   return d / 10;
1320 }
1321 
bc_num_a(BcNum * a,BcNum * b,BcNum * c,size_t sub)1322 static BcStatus bc_num_a(BcNum *a, BcNum *b, BcNum *c, size_t sub) {
1323 
1324   signed char *ptr, *ptr_a, *ptr_b, *ptr_c;
1325   size_t i, max, min_rdx, min_int, diff, a_int, b_int;
1326   unsigned int carry;
1327 
1328   // Because this function doesn't need to use scale (per the bc spec),
1329   // I am hijacking it to say whether it's doing an add or a subtract.
1330 
1331   if (!a->len) {
1332     bc_num_copy(c, b);
1333     if (sub && c->len) c->neg = !c->neg;
1334     return BC_STATUS_SUCCESS;
1335   }
1336   if (!b->len) {
1337     bc_num_copy(c, a);
1338     return BC_STATUS_SUCCESS;
1339   }
1340 
1341   c->neg = a->neg;
1342   c->rdx = maxof(a->rdx, b->rdx);
1343   min_rdx = minof(a->rdx, b->rdx);
1344 
1345   if (a->rdx > b->rdx) {
1346     diff = a->rdx - b->rdx;
1347     ptr = a->num;
1348     ptr_a = a->num + diff;
1349     ptr_b = b->num;
1350   }
1351   else {
1352     diff = b->rdx - a->rdx;
1353     ptr = b->num;
1354     ptr_a = a->num;
1355     ptr_b = b->num + diff;
1356   }
1357 
1358   for (ptr_c = c->num, i = 0; i < diff; ++i) ptr_c[i] = ptr[i];
1359 
1360   c->len = diff;
1361   ptr_c += diff;
1362   a_int = BC_NUM_INT(a);
1363   b_int = BC_NUM_INT(b);
1364 
1365   if (a_int > b_int) {
1366     min_int = b_int;
1367     max = a_int;
1368     ptr = ptr_a;
1369   }
1370   else {
1371     min_int = a_int;
1372     max = b_int;
1373     ptr = ptr_b;
1374   }
1375 
1376   for (carry = 0, i = 0; !TT.sig && i < min_rdx + min_int; ++i) {
1377     unsigned int in = (unsigned int) (ptr_a[i] + ptr_b[i]);
1378     carry = bc_num_addDigit(ptr_c + i, in, carry);
1379   }
1380 
1381   for (; !TT.sig && i < max + min_rdx; ++i)
1382     carry = bc_num_addDigit(ptr_c + i, (unsigned int) ptr[i], carry);
1383 
1384   c->len += i;
1385 
1386   if (carry) c->num[c->len++] = carry;
1387 
1388   return TT.sig ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1389 }
1390 
bc_num_s(BcNum * a,BcNum * b,BcNum * c,size_t sub)1391 static BcStatus bc_num_s(BcNum *a, BcNum *b, BcNum *c, size_t sub) {
1392 
1393   BcStatus s;
1394   ssize_t cmp;
1395   BcNum *minuend, *subtrahend;
1396   size_t start;
1397   int aneg, bneg, neg;
1398 
1399   // Because this function doesn't need to use scale (per the bc spec),
1400   // I am hijacking it to say whether it's doing an add or a subtract.
1401 
1402   if (!a->len) {
1403     bc_num_copy(c, b);
1404     if (sub && c->len) c->neg = !c->neg;
1405     return BC_STATUS_SUCCESS;
1406   }
1407   if (!b->len) {
1408     bc_num_copy(c, a);
1409     return BC_STATUS_SUCCESS;
1410   }
1411 
1412   aneg = a->neg;
1413   bneg = b->neg;
1414   a->neg = b->neg = 0;
1415 
1416   cmp = bc_num_cmp(a, b);
1417 
1418   a->neg = aneg;
1419   b->neg = bneg;
1420 
1421   if (!cmp) {
1422     bc_num_setToZero(c, maxof(a->rdx, b->rdx));
1423     return BC_STATUS_SUCCESS;
1424   }
1425 
1426   if (cmp > 0) {
1427     neg = a->neg;
1428     minuend = a;
1429     subtrahend = b;
1430   }
1431   else {
1432     neg = b->neg;
1433     if (sub) neg = !neg;
1434     minuend = b;
1435     subtrahend = a;
1436   }
1437 
1438   bc_num_copy(c, minuend);
1439   c->neg = neg;
1440 
1441   if (c->rdx < subtrahend->rdx) {
1442     bc_num_extend(c, subtrahend->rdx - c->rdx);
1443     start = 0;
1444   }
1445   else start = c->rdx - subtrahend->rdx;
1446 
1447   s = bc_num_subArrays(c->num + start, subtrahend->num, subtrahend->len);
1448 
1449   bc_num_clean(c);
1450 
1451   return s;
1452 }
1453 
bc_num_k(BcNum * a,BcNum * b,BcNum * c)1454 static BcStatus bc_num_k(BcNum *a, BcNum *b, BcNum *c) {
1455 
1456   BcStatus s;
1457   size_t max = maxof(a->len, b->len), max2 = (max + 1) / 2;
1458   BcNum l1, h1, l2, h2, m2, m1, z0, z1, z2, temp;
1459   int aone = BC_NUM_ONE(a);
1460 
1461   // This is here because the function is recursive.
1462   if (TT.sig) return BC_STATUS_SIGNAL;
1463   if (!a->len || !b->len) {
1464     bc_num_setToZero(c, 0);
1465     return BC_STATUS_SUCCESS;
1466   }
1467   if (aone || BC_NUM_ONE(b)) {
1468     bc_num_copy(c, aone ? b : a);
1469     return BC_STATUS_SUCCESS;
1470   }
1471 
1472   // check karatsuba length
1473   if (a->len + b->len < 32 || a->len < 32 || b->len < 32)
1474   {
1475     size_t i, j, len;
1476     unsigned int carry;
1477     signed char *ptr_c;
1478 
1479     bc_num_expand(c, a->len + b->len + 1);
1480 
1481     ptr_c = c->num;
1482     memset(ptr_c, 0, c->cap);
1483     c->len = len = 0;
1484 
1485     for (i = 0; !TT.sig && i < b->len; ++i) {
1486 
1487       signed char *ptr = ptr_c + i;
1488 
1489       carry = 0;
1490 
1491       for (j = 0; !TT.sig && j < a->len; ++j) {
1492         unsigned int in = (uchar) ptr[j];
1493         in += ((unsigned int) a->num[j]) * ((unsigned int) b->num[i]);
1494         carry = bc_num_addDigit(ptr + j, in, carry);
1495       }
1496 // todo: is this typecast useless?
1497       ptr[j] += (signed) carry;
1498       len = maxof(len, i + j + (carry != 0));
1499     }
1500 
1501     c->len = len;
1502 
1503     return TT.sig ? BC_STATUS_SIGNAL : BC_STATUS_SUCCESS;
1504   }
1505 
1506   bc_num_init(&l1, max);
1507   bc_num_init(&h1, max);
1508   bc_num_init(&l2, max);
1509   bc_num_init(&h2, max);
1510   bc_num_init(&m1, max);
1511   bc_num_init(&m2, max);
1512   bc_num_init(&z0, max);
1513   bc_num_init(&z1, max);
1514   bc_num_init(&z2, max);
1515   bc_num_init(&temp, max + max);
1516 
1517   bc_num_split(a, max2, &l1, &h1);
1518   bc_num_split(b, max2, &l2, &h2);
1519 
1520   s = bc_num_add(&h1, &l1, &m1, 0);
1521   if (s) goto err;
1522   s = bc_num_add(&h2, &l2, &m2, 0);
1523   if (s) goto err;
1524 
1525   s = bc_num_k(&h1, &h2, &z0);
1526   if (s) goto err;
1527   s = bc_num_k(&m1, &m2, &z1);
1528   if (s) goto err;
1529   s = bc_num_k(&l1, &l2, &z2);
1530   if (s) goto err;
1531 
1532   s = bc_num_sub(&z1, &z0, &temp, 0);
1533   if (s) goto err;
1534   s = bc_num_sub(&temp, &z2, &z1, 0);
1535   if (s) goto err;
1536 
1537   s = bc_num_shift(&z0, max2 * 2);
1538   if (s) goto err;
1539   s = bc_num_shift(&z1, max2);
1540   if (s) goto err;
1541   s = bc_num_add(&z0, &z1, &temp, 0);
1542   if (s) goto err;
1543   s = bc_num_add(&temp, &z2, c, 0);
1544 
1545 err:
1546   bc_num_free(&temp);
1547   bc_num_free(&z2);
1548   bc_num_free(&z1);
1549   bc_num_free(&z0);
1550   bc_num_free(&m2);
1551   bc_num_free(&m1);
1552   bc_num_free(&h2);
1553   bc_num_free(&l2);
1554   bc_num_free(&h1);
1555   bc_num_free(&l1);
1556   return s;
1557 }
1558 
bc_num_m(BcNum * a,BcNum * b,BcNum * c,size_t scale)1559 static BcStatus bc_num_m(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1560 
1561   BcStatus s;
1562   BcNum cpa, cpb;
1563   size_t maxrdx = maxof(a->rdx, b->rdx);
1564 
1565   scale = maxof(scale, a->rdx);
1566   scale = maxof(scale, b->rdx);
1567   scale = minof(a->rdx + b->rdx, scale);
1568   maxrdx = maxof(maxrdx, scale);
1569 
1570   bc_num_createCopy(&cpa, a);
1571   bc_num_createCopy(&cpb, b);
1572 
1573   cpa.neg = cpb.neg = 0;
1574 
1575   s = bc_num_shift(&cpa, maxrdx);
1576   if (s) goto err;
1577   s = bc_num_shift(&cpb, maxrdx);
1578   if (s) goto err;
1579   s = bc_num_k(&cpa, &cpb, c);
1580   if (s) goto err;
1581 
1582   maxrdx += scale;
1583   bc_num_expand(c, c->len + maxrdx);
1584 
1585   if (c->len < maxrdx) {
1586     memset(c->num + c->len, 0, c->cap - c->len);
1587     c->len += maxrdx;
1588   }
1589 
1590   c->rdx = maxrdx;
1591   bc_num_retireMul(c, scale, a->neg, b->neg);
1592 
1593 err:
1594   bc_num_free(&cpb);
1595   bc_num_free(&cpa);
1596   return s;
1597 }
1598 
bc_num_d(BcNum * a,BcNum * b,BcNum * c,size_t scale)1599 static BcStatus bc_num_d(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1600 
1601   BcStatus s = BC_STATUS_SUCCESS;
1602   signed char *n, *p, q;
1603   size_t len, end, i;
1604   BcNum cp;
1605   int zero = 1;
1606 
1607   if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1608   if (!a->len) {
1609     bc_num_setToZero(c, scale);
1610     return BC_STATUS_SUCCESS;
1611   }
1612   if (BC_NUM_ONE(b)) {
1613     bc_num_copy(c, a);
1614     bc_num_retireMul(c, scale, a->neg, b->neg);
1615     return BC_STATUS_SUCCESS;
1616   }
1617 
1618   bc_num_init(&cp, bc_num_mulReq(a, b, scale));
1619   bc_num_copy(&cp, a);
1620   len = b->len;
1621 
1622   if (len > cp.len) {
1623     bc_num_expand(&cp, len + 2);
1624     bc_num_extend(&cp, len - cp.len);
1625   }
1626 
1627   if (b->rdx > cp.rdx) bc_num_extend(&cp, b->rdx - cp.rdx);
1628   cp.rdx -= b->rdx;
1629   if (scale > cp.rdx) bc_num_extend(&cp, scale - cp.rdx);
1630 
1631   if (b->rdx == b->len) {
1632     for (i = 0; zero && i < len; ++i) zero = !b->num[len - i - 1];
1633     len -= i - 1;
1634   }
1635 
1636   if (cp.cap == cp.len) bc_num_expand(&cp, cp.len + 1);
1637 
1638   // We want an extra zero in front to make things simpler.
1639   cp.num[cp.len++] = 0;
1640   end = cp.len - len;
1641 
1642   bc_num_expand(c, cp.len);
1643 
1644   memset(c->num + end, 0, c->cap - end);
1645   c->rdx = cp.rdx;
1646   c->len = cp.len;
1647   p = b->num;
1648 
1649   for (i = end - 1; !TT.sig && !s && i < end; --i) {
1650     n = cp.num + i;
1651     for (q = 0; !s && (n[len] || bc_num_compare(n, p, len) >= 0); ++q)
1652       s = bc_num_subArrays(n, p, len);
1653     c->num[i] = q;
1654   }
1655 
1656   if (!s) bc_num_retireMul(c, scale, a->neg, b->neg);
1657   bc_num_free(&cp);
1658 
1659   return s;
1660 }
1661 
bc_num_r(BcNum * a,BcNum * b,BcNum * c,BcNum * d,size_t scale,size_t ts)1662 static BcStatus bc_num_r(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale,
1663                   size_t ts)
1664 {
1665   BcStatus s;
1666   BcNum temp;
1667   int neg;
1668 
1669   if (!b->len) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1670   if (!a->len) {
1671     bc_num_setToZero(c, ts);
1672     bc_num_setToZero(d, ts);
1673     return BC_STATUS_SUCCESS;
1674   }
1675 
1676   bc_num_init(&temp, d->cap);
1677   bc_num_d(a, b, c, scale);
1678 
1679   if (scale) scale = ts;
1680 
1681   s = bc_num_m(c, b, &temp, scale);
1682   if (s) goto err;
1683   s = bc_num_sub(a, &temp, d, scale);
1684   if (s) goto err;
1685 
1686   if (ts > d->rdx && d->len) bc_num_extend(d, ts - d->rdx);
1687 
1688   neg = d->neg;
1689   bc_num_retireMul(d, ts, a->neg, b->neg);
1690   d->neg = neg;
1691 
1692 err:
1693   bc_num_free(&temp);
1694   return s;
1695 }
1696 
bc_num_rem(BcNum * a,BcNum * b,BcNum * c,size_t scale)1697 static BcStatus bc_num_rem(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1698 
1699   BcStatus s;
1700   BcNum c1;
1701   size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts);
1702 
1703   bc_num_init(&c1, len);
1704   s = bc_num_r(a, b, &c1, c, scale, ts);
1705   bc_num_free(&c1);
1706 
1707   return s;
1708 }
1709 
bc_num_p(BcNum * a,BcNum * b,BcNum * c,size_t scale)1710 static BcStatus bc_num_p(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
1711 
1712   BcStatus s = BC_STATUS_SUCCESS;
1713   BcNum copy;
1714   unsigned long pow = 0;
1715   size_t i, powrdx, resrdx;
1716   int neg, zero;
1717 
1718   if (b->rdx) return bc_vm_err(BC_ERROR_MATH_NON_INTEGER);
1719 
1720   if (!b->len) {
1721     bc_num_one(c);
1722     return BC_STATUS_SUCCESS;
1723   }
1724   if (!a->len) {
1725     if (b->neg) return bc_vm_err(BC_ERROR_MATH_DIVIDE_BY_ZERO);
1726     bc_num_setToZero(c, scale);
1727     return BC_STATUS_SUCCESS;
1728   }
1729   if (BC_NUM_ONE(b)) {
1730     if (!b->neg) bc_num_copy(c, a);
1731     else s = bc_num_inv(a, c, scale);
1732     return s;
1733   }
1734 
1735   neg = b->neg;
1736   b->neg = 0;
1737   s = bc_num_ulong(b, &pow);
1738   b->neg = neg;
1739   if (s) return s;
1740 
1741   bc_num_createCopy(&copy, a);
1742 
1743   if (!neg) scale = minof(a->rdx * pow, maxof(scale, a->rdx));
1744 
1745   for (powrdx = a->rdx; !TT.sig && !(pow & 1); pow >>= 1) {
1746     powrdx <<= 1;
1747     s = bc_num_mul(&copy, &copy, &copy, powrdx);
1748     if (s) goto err;
1749   }
1750 
1751   if (TT.sig) {
1752     s = BC_STATUS_SIGNAL;
1753     goto err;
1754   }
1755 
1756   bc_num_copy(c, &copy);
1757   resrdx = powrdx;
1758 
1759   while (!TT.sig && (pow >>= 1)) {
1760 
1761     powrdx <<= 1;
1762     s = bc_num_mul(&copy, &copy, &copy, powrdx);
1763     if (s) goto err;
1764 
1765     if (pow & 1) {
1766       resrdx += powrdx;
1767       s = bc_num_mul(c, &copy, c, resrdx);
1768       if (s) goto err;
1769     }
1770   }
1771 
1772   if (neg) {
1773     s = bc_num_inv(c, c, scale);
1774     if (s) goto err;
1775   }
1776 
1777   if (TT.sig) {
1778     s = BC_STATUS_SIGNAL;
1779     goto err;
1780   }
1781 
1782   if (c->rdx > scale) bc_num_truncate(c, c->rdx - scale);
1783 
1784   // We can't use bc_num_clean() here.
1785   for (zero = 1, i = 0; zero && i < c->len; ++i) zero = !c->num[i];
1786   if (zero) bc_num_setToZero(c, scale);
1787 
1788 err:
1789   bc_num_free(&copy);
1790   return s;
1791 }
1792 
bc_num_binary(BcNum * a,BcNum * b,BcNum * c,size_t scale,BcNumBinaryOp op,size_t req)1793 static BcStatus bc_num_binary(BcNum *a, BcNum *b, BcNum *c, size_t scale,
1794                               BcNumBinaryOp op, size_t req)
1795 {
1796   BcStatus s;
1797   BcNum num2, *ptr_a, *ptr_b;
1798   int init = 0;
1799 
1800   if (c == a) {
1801     ptr_a = &num2;
1802     memcpy(ptr_a, c, sizeof(BcNum));
1803     init = 1;
1804   }
1805   else ptr_a = a;
1806 
1807   if (c == b) {
1808     ptr_b = &num2;
1809     if (c != a) {
1810       memcpy(ptr_b, c, sizeof(BcNum));
1811       init = 1;
1812     }
1813   }
1814   else ptr_b = b;
1815 
1816   if (init) bc_num_init(c, req);
1817   else bc_num_expand(c, req);
1818 
1819   s = op(ptr_a, ptr_b, c, scale);
1820 
1821   if (init) bc_num_free(&num2);
1822 
1823   return s;
1824 }
1825 
bc_num_parseChar(char c,size_t base_t)1826 static unsigned long bc_num_parseChar(char c, size_t base_t) {
1827 
1828   if (isupper(c)) {
1829     c += 10 - 'A';
1830     if (c >= base_t) c = base_t - 1;
1831   } else c -= '0';
1832 
1833   return c;
1834 }
1835 
bc_num_parseBase(BcNum * n,char * val,BcNum * base,size_t base_t)1836 static BcStatus bc_num_parseBase(BcNum *n, char *val,
1837                                  BcNum *base, size_t base_t)
1838 {
1839   BcStatus s = BC_STATUS_SUCCESS;
1840   BcNum temp, mult, result;
1841   signed char c = 0;
1842   int zero = 1;
1843   unsigned long v;
1844   size_t i, digits, len = strlen(val);
1845 
1846   for (i = 0; zero && i < len; ++i) zero = (val[i] == '.' || val[i] == '0');
1847   if (zero) return BC_STATUS_SUCCESS;
1848 
1849   bc_num_init(&temp, BC_NUM_LONG_LOG10);
1850   bc_num_init(&mult, BC_NUM_LONG_LOG10);
1851 
1852   for (i = 0; i < len && (c = val[i]) && c != '.'; ++i) {
1853 
1854     v = bc_num_parseChar(c, base_t);
1855 
1856     s = bc_num_mul(n, base, &mult, 0);
1857     if (s) goto int_err;
1858     bc_num_ulong2num(&temp, v);
1859     s = bc_num_add(&mult, &temp, n, 0);
1860     if (s) goto int_err;
1861   }
1862 
1863   if (i == len && !(c = val[i])) goto int_err;
1864 
1865   bc_num_init(&result, base->len);
1866   bc_num_one(&mult);
1867 
1868   for (i += 1, digits = 0; i < len && (c = val[i]); ++i, ++digits) {
1869 
1870     v = bc_num_parseChar(c, base_t);
1871 
1872     s = bc_num_mul(&result, base, &result, 0);
1873     if (s) goto err;
1874     bc_num_ulong2num(&temp, v);
1875     s = bc_num_add(&result, &temp, &result, 0);
1876     if (s) goto err;
1877     s = bc_num_mul(&mult, base, &mult, 0);
1878     if (s) goto err;
1879   }
1880 
1881   s = bc_num_div(&result, &mult, &result, digits);
1882   if (s) goto err;
1883   s = bc_num_add(n, &result, n, digits);
1884   if (s) goto err;
1885 
1886   if (n->len) {
1887     if (n->rdx < digits) bc_num_extend(n, digits - n->rdx);
1888   }
1889   else bc_num_setToZero(n, 0);
1890 
1891 
1892 err:
1893   bc_num_free(&result);
1894 int_err:
1895   bc_num_free(&mult);
1896   bc_num_free(&temp);
1897   return s;
1898 }
1899 
bc_num_printNewline()1900 static void bc_num_printNewline() {
1901   if (TT.nchars >= TT.line_len - 1) {
1902     putchar('\\');
1903     putchar('\n');
1904     TT.nchars = 0;
1905   }
1906 }
1907 
bc_num_printDigits(size_t n,size_t len,int rdx)1908 static void bc_num_printDigits(size_t n, size_t len, int rdx) {
1909 
1910   size_t exp, pow;
1911 
1912   bc_num_printNewline();
1913   putchar(rdx ? '.' : ' ');
1914   ++TT.nchars;
1915 
1916   bc_num_printNewline();
1917   for (exp = 0, pow = 1; exp < len - 1; ++exp, pow *= 10);
1918 
1919   for (exp = 0; exp < len; pow /= 10, ++TT.nchars, ++exp) {
1920     size_t dig;
1921     bc_num_printNewline();
1922     dig = n / pow;
1923     n -= dig * pow;
1924     putchar(((uchar) dig) + '0');
1925   }
1926 }
1927 
bc_num_printHex(size_t n,size_t len,int rdx)1928 static void bc_num_printHex(size_t n, size_t len, int rdx) {
1929 
1930   if (rdx) {
1931     bc_num_printNewline();
1932     putchar('.');
1933     TT.nchars += 1;
1934   }
1935 
1936   bc_num_printNewline();
1937   putchar(bc_num_hex_digits[n]);
1938   TT.nchars += len;
1939 }
1940 
bc_num_printDecimal(BcNum * n)1941 static void bc_num_printDecimal(BcNum *n) {
1942 
1943   size_t i, rdx = n->rdx - 1;
1944 
1945   if (n->neg) putchar('-');
1946   TT.nchars += n->neg;
1947 
1948   for (i = n->len - 1; i < n->len; --i)
1949     bc_num_printHex((size_t) n->num[i], 1, i == rdx);
1950 }
1951 
bc_num_printNum(BcNum * n,BcNum * base,size_t len,BcNumDigitOp print)1952 static BcStatus bc_num_printNum(BcNum *n, BcNum *base,
1953                                 size_t len, BcNumDigitOp print)
1954 {
1955   BcStatus s;
1956   BcVec stack;
1957   BcNum intp, fracp, digit, frac_len;
1958   unsigned long dig, *ptr;
1959   size_t i;
1960   int radix;
1961 
1962   if (!n->len) {
1963     print(0, len, 0);
1964     return BC_STATUS_SUCCESS;
1965   }
1966 
1967   bc_vec_init(&stack, sizeof(unsigned long), NULL);
1968   bc_num_init(&fracp, n->rdx);
1969   bc_num_init(&digit, len);
1970   bc_num_init(&frac_len, BC_NUM_INT(n));
1971   bc_num_one(&frac_len);
1972   bc_num_createCopy(&intp, n);
1973 
1974   bc_num_truncate(&intp, intp.rdx);
1975   s = bc_num_sub(n, &intp, &fracp, 0);
1976   if (s) goto err;
1977 
1978   while (intp.len) {
1979     s = bc_num_divmod(&intp, base, &intp, &digit, 0);
1980     if (s) goto err;
1981     s = bc_num_ulong(&digit, &dig);
1982     if (s) goto err;
1983     bc_vec_push(&stack, &dig);
1984   }
1985 
1986   for (i = 0; i < stack.len; ++i) {
1987     ptr = bc_vec_item_rev(&stack, i);
1988     print(*ptr, len, 0);
1989   }
1990 
1991   if (!n->rdx) goto err;
1992 
1993   for (radix = 1; frac_len.len <= n->rdx; radix = 0) {
1994     s = bc_num_mul(&fracp, base, &fracp, n->rdx);
1995     if (s) goto err;
1996     s = bc_num_ulong(&fracp, &dig);
1997     if (s) goto err;
1998     bc_num_ulong2num(&intp, dig);
1999     s = bc_num_sub(&fracp, &intp, &fracp, 0);
2000     if (s) goto err;
2001     print(dig, len, radix);
2002     s = bc_num_mul(&frac_len, base, &frac_len, 0);
2003     if (s) goto err;
2004   }
2005 
2006 err:
2007   bc_num_free(&frac_len);
2008   bc_num_free(&digit);
2009   bc_num_free(&fracp);
2010   bc_num_free(&intp);
2011   bc_vec_free(&stack);
2012   return s;
2013 }
2014 
bc_num_printBase(BcNum * n,BcNum * base,size_t base_t)2015 static BcStatus bc_num_printBase(BcNum *n, BcNum *base, size_t base_t) {
2016 
2017   BcStatus s;
2018   size_t width;
2019   BcNumDigitOp print;
2020   int neg = n->neg;
2021 
2022   if (neg) putchar('-');
2023   TT.nchars += neg;
2024 
2025   n->neg = 0;
2026 
2027   if (base_t <= 16) {
2028     width = 1;
2029     print = bc_num_printHex;
2030   } else {
2031     width = bc_num_log10(base_t - 1) - 1;
2032     print = bc_num_printDigits;
2033   }
2034 
2035   s = bc_num_printNum(n, base, width, print);
2036   n->neg = neg;
2037 
2038   return s;
2039 }
2040 
bc_num_setup(BcNum * n,signed char * num,size_t cap)2041 void bc_num_setup(BcNum *n, signed char *num, size_t cap) {
2042   n->num = num;
2043   n->cap = cap;
2044   n->rdx = n->len = 0;
2045   n->neg = 0;
2046 }
2047 
bc_num_init(BcNum * n,size_t req)2048 void bc_num_init(BcNum *n, size_t req) {
2049   req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2050   bc_num_setup(n, xmalloc(req), req);
2051 }
2052 
bc_num_expand(BcNum * n,size_t req)2053 void bc_num_expand(BcNum *n, size_t req) {
2054   req = req >= BC_NUM_DEF_SIZE ? req : BC_NUM_DEF_SIZE;
2055   if (req > n->cap) {
2056     n->num = xrealloc(n->num, req);
2057     n->cap = req;
2058   }
2059 }
2060 
bc_num_free(void * num)2061 void bc_num_free(void *num) {
2062   free(((BcNum*) num)->num);
2063 }
2064 
bc_num_copy(BcNum * d,BcNum * s)2065 void bc_num_copy(BcNum *d, BcNum *s) {
2066   if (d == s) return;
2067   bc_num_expand(d, s->len);
2068   d->len = s->len;
2069   d->neg = s->neg;
2070   d->rdx = s->rdx;
2071   memcpy(d->num, s->num, d->len);
2072 }
2073 
bc_num_createCopy(BcNum * d,BcNum * s)2074 void bc_num_createCopy(BcNum *d, BcNum *s) {
2075   bc_num_init(d, s->len);
2076   bc_num_copy(d, s);
2077 }
2078 
bc_num_createFromUlong(BcNum * n,unsigned long val)2079 void bc_num_createFromUlong(BcNum *n, unsigned long val) {
2080   bc_num_init(n, BC_NUM_LONG_LOG10);
2081   bc_num_ulong2num(n, val);
2082 }
2083 
bc_num_parse(BcNum * n,char * val,BcNum * base,size_t base_t,int letter)2084 BcStatus bc_num_parse(BcNum *n, char *val,
2085                       BcNum *base, size_t base_t, int letter)
2086 {
2087   BcStatus s = BC_STATUS_SUCCESS;
2088 
2089   if (letter) bc_num_ulong2num(n, bc_num_parseChar(val[0], 'Z'+11));
2090   else if (base_t == 10) {
2091     size_t len, i;
2092     char *ptr;
2093     int zero = 1;
2094 
2095     while (*val == '0') val++;
2096 
2097     len = strlen(val);
2098     if (len) {
2099       for (i = 0; zero && i < len; ++i) zero = (val[i] == '0') || val[i] == '.';
2100       bc_num_expand(n, len);
2101     }
2102     ptr = strchr(val, '.');
2103     n->rdx = ptr ? (val + len) - (ptr + 1) : 0;
2104 
2105     if (!zero) {
2106       for (i = len - 1; i < len; ++n->len, --i) {
2107 
2108         char c = val[i];
2109 
2110         if (c == '.') n->len -= 1;
2111         else {
2112           if (isupper(c)) c = '9';
2113           n->num[n->len] = c - '0';
2114         }
2115       }
2116     }
2117   } else s = bc_num_parseBase(n, val, base, base_t);
2118 
2119   return s;
2120 }
2121 
bc_num_ulong(BcNum * n,unsigned long * result)2122 BcStatus bc_num_ulong(BcNum *n, unsigned long *result) {
2123 
2124   size_t i;
2125   unsigned long r;
2126 
2127   *result = 0;
2128 
2129   if (n->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2130 
2131   for (r = 0, i = n->len; i > n->rdx;) {
2132 
2133     unsigned long prev = r * 10;
2134 
2135     if (prev == SIZE_MAX || prev / 10 != r)
2136       return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
2137 
2138     r = prev + ((uchar) n->num[--i]);
2139 
2140     if (r == SIZE_MAX || r < prev) return bc_vm_err(BC_ERROR_MATH_OVERFLOW);
2141   }
2142 
2143   *result = r;
2144 
2145   return BC_STATUS_SUCCESS;
2146 }
2147 
bc_num_ulong2num(BcNum * n,unsigned long val)2148 void bc_num_ulong2num(BcNum *n, unsigned long val) {
2149 
2150   size_t len;
2151   signed char *ptr;
2152   unsigned long i;
2153 
2154   bc_num_setToZero(n, 0);
2155 
2156   if (!val) return;
2157 
2158   len = bc_num_log10(ULONG_MAX);
2159   bc_num_expand(n, len);
2160   for (ptr = n->num, i = 0; val; ++i, ++n->len, val /= 10) ptr[i] = val % 10;
2161 }
2162 
bc_num_addReq(BcNum * a,BcNum * b,size_t scale)2163 size_t bc_num_addReq(BcNum *a, BcNum *b, size_t scale) {
2164   return maxof(a->rdx, b->rdx) + maxof(BC_NUM_INT(a), BC_NUM_INT(b)) + 1;
2165 }
2166 
bc_num_mulReq(BcNum * a,BcNum * b,size_t scale)2167 size_t bc_num_mulReq(BcNum *a, BcNum *b, size_t scale) {
2168   return BC_NUM_INT(a) + BC_NUM_INT(b) + maxof(scale, a->rdx + b->rdx) + 1;
2169 }
2170 
bc_num_powReq(BcNum * a,BcNum * b,size_t scale)2171 size_t bc_num_powReq(BcNum *a, BcNum *b, size_t scale) {
2172   return a->len + b->len + 1;
2173 }
2174 
bc_num_add(BcNum * a,BcNum * b,BcNum * c,size_t scale)2175 BcStatus bc_num_add(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2176   BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_a : bc_num_s;
2177   return bc_num_binary(a, b, c, 0, op, bc_num_addReq(a, b, scale));
2178 }
2179 
bc_num_sub(BcNum * a,BcNum * b,BcNum * c,size_t scale)2180 BcStatus bc_num_sub(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2181   BcNumBinaryOp op = (!a->neg == !b->neg) ? bc_num_s : bc_num_a;
2182   return bc_num_binary(a, b, c, 1, op, bc_num_addReq(a, b, scale));
2183 }
2184 
bc_num_mul(BcNum * a,BcNum * b,BcNum * c,size_t scale)2185 BcStatus bc_num_mul(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2186   return bc_num_binary(a, b, c, scale, bc_num_m, bc_num_mulReq(a, b, scale));
2187 }
2188 
bc_num_div(BcNum * a,BcNum * b,BcNum * c,size_t scale)2189 BcStatus bc_num_div(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2190   return bc_num_binary(a, b, c, scale, bc_num_d, bc_num_mulReq(a, b, scale));
2191 }
2192 
bc_num_mod(BcNum * a,BcNum * b,BcNum * c,size_t scale)2193 BcStatus bc_num_mod(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2194   return bc_num_binary(a, b, c, scale, bc_num_rem, bc_num_mulReq(a, b, scale));
2195 }
2196 
bc_num_pow(BcNum * a,BcNum * b,BcNum * c,size_t scale)2197 BcStatus bc_num_pow(BcNum *a, BcNum *b, BcNum *c, size_t scale) {
2198   return bc_num_binary(a, b, c, scale, bc_num_p, a->len + b->len + 1);
2199 }
2200 
bc_num_sqrt(BcNum * a,BcNum * b,size_t scale)2201 BcStatus bc_num_sqrt(BcNum *a, BcNum *b, size_t scale) {
2202 
2203   BcStatus s = BC_STATUS_SUCCESS;
2204   BcNum num1, num2, half, f, fprime, *x0, *x1, *temp;
2205   size_t pow, len, digs, digs1, resrdx, times = 0;
2206   ssize_t cmp = 1, cmp1 = SSIZE_MAX, cmp2 = SSIZE_MAX;
2207   signed char half_digs[2];
2208 
2209   bc_num_init(b, maxof(scale, a->rdx) + ((BC_NUM_INT(a) + 1) >> 1) + 1);
2210 
2211   if (!a->len) {
2212     bc_num_setToZero(b, scale);
2213     return BC_STATUS_SUCCESS;
2214   }
2215   if (a->neg) return bc_vm_err(BC_ERROR_MATH_NEGATIVE);
2216   if (BC_NUM_ONE(a)) {
2217     bc_num_one(b);
2218     bc_num_extend(b, scale);
2219     return BC_STATUS_SUCCESS;
2220   }
2221 
2222   scale = maxof(scale, a->rdx) + 1;
2223   len = a->len + scale;
2224 
2225   bc_num_init(&num1, len);
2226   bc_num_init(&num2, len);
2227   bc_num_setup(&half, half_digs, sizeof(half_digs));
2228 
2229   bc_num_one(&half);
2230   half.num[0] = 5;
2231   half.rdx = 1;
2232 
2233   bc_num_init(&f, len);
2234   bc_num_init(&fprime, len);
2235 
2236   x0 = &num1;
2237   x1 = &num2;
2238 
2239   bc_num_one(x0);
2240   pow = BC_NUM_INT(a);
2241 
2242   if (pow) {
2243 
2244     if (pow & 1) x0->num[0] = 2;
2245     else x0->num[0] = 6;
2246 
2247     pow -= 2 - (pow & 1);
2248 
2249     bc_num_extend(x0, pow);
2250 
2251     // Make sure to move the radix back.
2252     x0->rdx -= pow;
2253   }
2254 
2255   x0->rdx = digs = digs1 = 0;
2256   resrdx = scale + 2;
2257   len = BC_NUM_INT(x0) + resrdx - 1;
2258 
2259   while (!TT.sig && (cmp || digs < len)) {
2260 
2261     s = bc_num_div(a, x0, &f, resrdx);
2262     if (s) goto err;
2263     s = bc_num_add(x0, &f, &fprime, resrdx);
2264     if (s) goto err;
2265     s = bc_num_mul(&fprime, &half, x1, resrdx);
2266     if (s) goto err;
2267 
2268     cmp = bc_num_cmp(x1, x0);
2269     digs = x1->len - (unsigned long long) llabs(cmp);
2270 
2271     if (cmp == cmp2 && digs == digs1) times += 1;
2272     else times = 0;
2273 
2274     resrdx += times > 4;
2275 
2276     cmp2 = cmp1;
2277     cmp1 = cmp;
2278     digs1 = digs;
2279 
2280     temp = x0;
2281     x0 = x1;
2282     x1 = temp;
2283   }
2284 
2285   if (TT.sig) {
2286     s = BC_STATUS_SIGNAL;
2287     goto err;
2288   }
2289 
2290   bc_num_copy(b, x0);
2291   scale -= 1;
2292   if (b->rdx > scale) bc_num_truncate(b, b->rdx - scale);
2293 
2294 err:
2295   bc_num_free(&fprime);
2296   bc_num_free(&f);
2297   bc_num_free(&num2);
2298   bc_num_free(&num1);
2299   return s;
2300 }
2301 
bc_num_divmod(BcNum * a,BcNum * b,BcNum * c,BcNum * d,size_t scale)2302 BcStatus bc_num_divmod(BcNum *a, BcNum *b, BcNum *c, BcNum *d, size_t scale) {
2303 
2304   BcStatus s;
2305   BcNum num2, *ptr_a;
2306   int init = 0;
2307   size_t ts = maxof(scale + b->rdx, a->rdx), len = bc_num_mulReq(a, b, ts);
2308 
2309   if (c == a) {
2310     memcpy(&num2, c, sizeof(BcNum));
2311     ptr_a = &num2;
2312     bc_num_init(c, len);
2313     init = 1;
2314   }
2315   else {
2316     ptr_a = a;
2317     bc_num_expand(c, len);
2318   }
2319 
2320   s = bc_num_r(ptr_a, b, c, d, scale, ts);
2321 
2322   if (init) bc_num_free(&num2);
2323 
2324   return s;
2325 }
2326 
bc_id_cmp(struct str_len * e1,struct str_len * e2)2327 int bc_id_cmp(struct str_len *e1, struct str_len *e2) {
2328   return strcmp(e1->str, e2->str);
2329 }
2330 
bc_id_free(void * id)2331 void bc_id_free(void *id) {
2332   free(((struct str_len *)id)->str);
2333 }
2334 
bc_string_free(void * string)2335 void bc_string_free(void *string) {
2336   free(*((char**) string));
2337 }
2338 
bc_func_insert(BcFunc * f,char * name,BcType type,size_t line)2339 BcStatus bc_func_insert(BcFunc *f, char *name, BcType type, size_t line) {
2340 
2341   struct str_len a;
2342   size_t i;
2343 
2344   for (i = 0; i < f->autos.len; ++i) {
2345     struct str_len *id = bc_vec_item(&f->autos, i);
2346     if (!strcmp(name, id->str) && type == (BcType) id->len)
2347       return bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name);
2348   }
2349 
2350   a.len = type;
2351   a.str = name;
2352 
2353   bc_vec_push(&f->autos, &a);
2354 
2355   return BC_STATUS_SUCCESS;
2356 }
2357 
bc_func_init(BcFunc * f,char * name)2358 void bc_func_init(BcFunc *f, char *name) {
2359   bc_vec_init(&f->code, sizeof(uchar), NULL);
2360   bc_vec_init(&f->strs, sizeof(char*), bc_string_free);
2361   bc_vec_init(&f->consts, sizeof(char*), bc_string_free);
2362   bc_vec_init(&f->autos, sizeof(struct str_len), bc_id_free);
2363   bc_vec_init(&f->labels, sizeof(size_t), NULL);
2364   f->nparams = 0;
2365   f->voidfn = 0;
2366   f->name = name;
2367 }
2368 
bc_func_reset(BcFunc * f)2369 void bc_func_reset(BcFunc *f) {
2370   bc_vec_npop(&f->code, f->code.len);
2371   bc_vec_npop(&f->strs, f->strs.len);
2372   bc_vec_npop(&f->consts, f->consts.len);
2373   bc_vec_npop(&f->autos, f->autos.len);
2374   bc_vec_npop(&f->labels, f->labels.len);
2375   f->nparams = 0;
2376   f->voidfn = 0;
2377 }
2378 
bc_func_free(void * func)2379 void bc_func_free(void *func) {
2380   BcFunc *f = (BcFunc*) func;
2381   bc_vec_free(&f->code);
2382   bc_vec_free(&f->strs);
2383   bc_vec_free(&f->consts);
2384   bc_vec_free(&f->autos);
2385   bc_vec_free(&f->labels);
2386 }
2387 
bc_array_init(BcVec * a,int nums)2388 void bc_array_init(BcVec *a, int nums) {
2389   if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free);
2390   else bc_vec_init(a, sizeof(BcVec), bc_vec_free);
2391   bc_array_expand(a, 1);
2392 }
2393 
bc_array_copy(BcVec * d,BcVec * s)2394 void bc_array_copy(BcVec *d, BcVec *s) {
2395 
2396   size_t i;
2397 
2398   bc_vec_npop(d, d->len);
2399   bc_vec_expand(d, s->cap);
2400   d->len = s->len;
2401 
2402   for (i = 0; i < s->len; ++i) {
2403     BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
2404     bc_num_createCopy(dnum, snum);
2405   }
2406 }
2407 
bc_array_expand(BcVec * a,size_t len)2408 void bc_array_expand(BcVec *a, size_t len) {
2409 
2410   if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
2411     BcNum n;
2412     while (len > a->len) {
2413       bc_num_init(&n, BC_NUM_DEF_SIZE);
2414       bc_vec_push(a, &n);
2415     }
2416   }
2417   else {
2418     BcVec v;
2419     while (len > a->len) {
2420       bc_array_init(&v, 1);
2421       bc_vec_push(a, &v);
2422     }
2423   }
2424 }
2425 
bc_result_free(void * result)2426 void bc_result_free(void *result) {
2427 
2428   BcResult *r = (BcResult*) result;
2429 
2430   switch (r->t) {
2431 
2432     case BC_RESULT_TEMP:
2433     case BC_RESULT_IBASE:
2434     case BC_RESULT_SCALE:
2435     case BC_RESULT_OBASE:
2436     {
2437       bc_num_free(&r->d.n);
2438       break;
2439     }
2440 
2441     case BC_RESULT_VAR:
2442     case BC_RESULT_ARRAY:
2443     case BC_RESULT_ARRAY_ELEM:
2444     {
2445       free(r->d.id.str);
2446       break;
2447     }
2448 
2449     case BC_RESULT_STR:
2450     case BC_RESULT_CONSTANT:
2451     case BC_RESULT_VOID:
2452     case BC_RESULT_ONE:
2453     case BC_RESULT_LAST:
2454     {
2455       // Do nothing.
2456       break;
2457     }
2458   }
2459 }
2460 
bc_lex_invalidChar(BcLex * l,char c)2461 BcStatus bc_lex_invalidChar(BcLex *l, char c) {
2462   l->t = BC_LEX_INVALID;
2463   return bc_lex_verr(l, BC_ERROR_PARSE_CHAR, c);
2464 }
2465 
bc_lex_lineComment(BcLex * l)2466 void bc_lex_lineComment(BcLex *l) {
2467   l->t = BC_LEX_WHITESPACE;
2468   while (l->i < l->len && l->buf[l->i] != '\n') ++l->i;
2469 }
2470 
bc_lex_comment(BcLex * l)2471 BcStatus bc_lex_comment(BcLex *l) {
2472 
2473   size_t i, nlines = 0;
2474   char *buf = l->buf;
2475   int end = 0;
2476   char c;
2477 
2478   l->t = BC_LEX_WHITESPACE;
2479 
2480   for (i = ++l->i; !end; i += !end) {
2481 
2482     for (; (c = buf[i]) && c != '*'; ++i) nlines += (c == '\n');
2483 
2484     if (!c || buf[i + 1] == '\0') {
2485       l->i = i;
2486       return bc_lex_err(l, BC_ERROR_PARSE_COMMENT);
2487     }
2488 
2489     end = buf[i + 1] == '/';
2490   }
2491 
2492   l->i = i + 2;
2493   l->line += nlines;
2494 
2495   return BC_STATUS_SUCCESS;
2496 }
2497 
bc_lex_whitespace(BcLex * l)2498 void bc_lex_whitespace(BcLex *l) {
2499   char c;
2500   l->t = BC_LEX_WHITESPACE;
2501   for (c = l->buf[l->i]; c != '\n' && isspace(c); c = l->buf[++l->i]);
2502 }
2503 
bc_lex_number(BcLex * l,char start)2504 BcStatus bc_lex_number(BcLex *l, char start) {
2505 
2506   char *buf = l->buf + l->i;
2507   size_t i;
2508   char last_valid, c;
2509   int last_pt, pt = (start == '.');
2510 
2511   l->t = BC_LEX_NUMBER;
2512   last_valid = 'Z';
2513 
2514   bc_vec_npop(&l->str, l->str.len);
2515   bc_vec_push(&l->str, &start);
2516 
2517   for (i = 0; (c = buf[i]) && (BC_LEX_NUM_CHAR(c, last_valid, pt) ||
2518                                (c == '\\' && buf[i + 1] == '\n')); ++i)
2519   {
2520     if (c == '\\') {
2521 
2522       if (buf[i + 1] == '\n') {
2523 
2524         i += 2;
2525 
2526         // Make sure to eat whitespace at the beginning of the line.
2527         while(isspace(buf[i]) && buf[i] != '\n') ++i;
2528 
2529         c = buf[i];
2530 
2531         if (!BC_LEX_NUM_CHAR(c, last_valid, pt)) break;
2532       }
2533       else break;
2534     }
2535 
2536     last_pt = (c == '.');
2537     if (pt && last_pt) break;
2538     pt = pt || last_pt;
2539 
2540     bc_vec_push(&l->str, &c);
2541   }
2542 
2543   if (l->str.len - pt > BC_MAX_NUM)
2544     return bc_lex_verr(l, BC_ERROR_EXEC_NUM_LEN, BC_MAX_NUM);
2545 
2546   bc_vec_pushByte(&l->str, '\0');
2547   l->i += i;
2548 
2549   return BC_STATUS_SUCCESS;
2550 }
2551 
bc_lex_name(BcLex * l)2552 BcStatus bc_lex_name(BcLex *l) {
2553 
2554   size_t i = 0;
2555   char *buf = l->buf + l->i - 1;
2556   char c = buf[i];
2557 
2558   l->t = BC_LEX_NAME;
2559 
2560   while ((c >= 'a' && c <= 'z') || isdigit(c) || c == '_') c = buf[++i];
2561 
2562   if (i > BC_MAX_NAME)
2563     return bc_lex_verr(l, BC_ERROR_EXEC_NAME_LEN, BC_MAX_NAME);
2564 
2565   bc_vec_string(&l->str, i, buf);
2566 
2567   // Increment the index. We minus 1 because it has already been incremented.
2568   l->i += i - 1;
2569 
2570   return BC_STATUS_SUCCESS;
2571 }
2572 
bc_lex_init(BcLex * l)2573 void bc_lex_init(BcLex *l) {
2574   bc_vec_init(&l->str, sizeof(char), NULL);
2575 }
2576 
bc_lex_file(BcLex * l,char * file)2577 void bc_lex_file(BcLex *l, char *file) {
2578   l->line = 1;
2579   TT.file = file;
2580 }
2581 
bc_lex_next(BcLex * l)2582 BcStatus bc_lex_next(BcLex *l) {
2583 
2584   BcStatus s;
2585 
2586   l->last = l->t;
2587   l->line += (l->i != 0 && l->buf[l->i - 1] == '\n');
2588 
2589   if (l->last == BC_LEX_EOF) return bc_lex_err(l, BC_ERROR_PARSE_EOF);
2590 
2591   l->t = BC_LEX_EOF;
2592 
2593   if (l->i == l->len) return BC_STATUS_SUCCESS;
2594 
2595   // Loop until failure or we don't have whitespace. This
2596   // is so the parser doesn't get inundated with whitespace.
2597   do {
2598     s = bc_lex_token(l);
2599   } while (!s && l->t == BC_LEX_WHITESPACE);
2600 
2601   return s;
2602 }
2603 
bc_lex_text(BcLex * l,char * text)2604 BcStatus bc_lex_text(BcLex *l, char *text) {
2605   l->buf = text;
2606   l->i = 0;
2607   l->len = strlen(text);
2608   l->t = l->last = BC_LEX_INVALID;
2609   return bc_lex_next(l);
2610 }
2611 
bc_lex_identifier(BcLex * l)2612 static BcStatus bc_lex_identifier(BcLex *l) {
2613 
2614   BcStatus s;
2615   size_t i;
2616   char *buf = l->buf + l->i - 1;
2617 
2618   for (i = 0; i < bc_lex_kws_len; ++i) {
2619 
2620     BcLexKeyword *kw = bc_lex_kws + i;
2621     size_t len = BC_LEX_KW_LEN(kw);
2622 
2623     if (!strncmp(buf, kw->name, len) && !isalnum(buf[len]) && buf[len] != '_')
2624     {
2625       l->t = BC_LEX_KEY_AUTO + (BcLexType) i;
2626 
2627       if (!BC_LEX_KW_POSIX(kw)) {
2628         s = bc_lex_vposixErr(l, BC_ERROR_POSIX_KW, kw->name);
2629         if (s) return s;
2630       }
2631 
2632       // We minus 1 because the index has already been incremented.
2633       l->i += len - 1;
2634       return BC_STATUS_SUCCESS;
2635     }
2636   }
2637 
2638   s = bc_lex_name(l);
2639   if (s) return s;
2640 
2641   if (l->str.len - 1 > 1) s = bc_lex_vposixErr(l, BC_ERROR_POSIX_NAME_LEN, buf);
2642 
2643   return s;
2644 }
2645 
bc_lex_string(BcLex * l)2646 static BcStatus bc_lex_string(BcLex *l) {
2647 
2648   size_t len, nlines = 0, i = l->i;
2649   char *buf = l->buf;
2650   char c;
2651 
2652   l->t = BC_LEX_STR;
2653 
2654   for (; (c = buf[i]) && c != '"'; ++i) nlines += c == '\n';
2655 
2656   if (c == '\0') {
2657     l->i = i;
2658     return bc_lex_err(l, BC_ERROR_PARSE_STRING);
2659   }
2660 
2661   len = i - l->i;
2662 
2663   if (len > BC_MAX_STRING)
2664     return bc_lex_verr(l, BC_ERROR_EXEC_STRING_LEN, BC_MAX_STRING);
2665 
2666   bc_vec_string(&l->str, len, l->buf + l->i);
2667 
2668   l->i = i + 1;
2669   l->line += nlines;
2670 
2671   return BC_STATUS_SUCCESS;
2672 }
2673 
bc_lex_assign(BcLex * l,BcLexType with,BcLexType without)2674 static void bc_lex_assign(BcLex *l, BcLexType with, BcLexType without) {
2675   if (l->buf[l->i] == '=') {
2676     ++l->i;
2677     l->t = with;
2678   }
2679   else l->t = without;
2680 }
2681 
bc_lex_token(BcLex * l)2682 BcStatus bc_lex_token(BcLex *l) {
2683 
2684   BcStatus s = BC_STATUS_SUCCESS;
2685   char c = l->buf[l->i++], c2;
2686 
2687   // This is the workhorse of the lexer.
2688   switch (c) {
2689 
2690     case '\0':
2691     case '\n':
2692     {
2693       l->t = !c ? BC_LEX_EOF : BC_LEX_NLINE;
2694       break;
2695     }
2696 
2697     case '\t':
2698     case '\v':
2699     case '\f':
2700     case '\r':
2701     case ' ':
2702     {
2703       bc_lex_whitespace(l);
2704       break;
2705     }
2706 
2707     case '!':
2708     {
2709       bc_lex_assign(l, BC_LEX_OP_REL_NE, BC_LEX_OP_BOOL_NOT);
2710 
2711       if (l->t == BC_LEX_OP_BOOL_NOT) {
2712         s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "!");
2713         if (s) return s;
2714       }
2715 
2716       break;
2717     }
2718 
2719     case '"':
2720     {
2721       s = bc_lex_string(l);
2722       break;
2723     }
2724 
2725     case '#':
2726     {
2727       s = bc_lex_posixErr(l, BC_ERROR_POSIX_COMMENT);
2728       if (s) return s;
2729 
2730       bc_lex_lineComment(l);
2731 
2732       break;
2733     }
2734 
2735     case '%':
2736     {
2737       bc_lex_assign(l, BC_LEX_OP_ASSIGN_MODULUS, BC_LEX_OP_MODULUS);
2738       break;
2739     }
2740 
2741     case '&':
2742     {
2743       c2 = l->buf[l->i];
2744       if (c2 == '&') {
2745 
2746         s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "&&");
2747         if (s) return s;
2748 
2749         ++l->i;
2750         l->t = BC_LEX_OP_BOOL_AND;
2751       }
2752       else s = bc_lex_invalidChar(l, c);
2753 
2754       break;
2755     }
2756     case '(':
2757     case ')':
2758     {
2759       l->t = (BcLexType) (c - '(' + BC_LEX_LPAREN);
2760       break;
2761     }
2762 
2763     case '*':
2764     {
2765       bc_lex_assign(l, BC_LEX_OP_ASSIGN_MULTIPLY, BC_LEX_OP_MULTIPLY);
2766       break;
2767     }
2768 
2769     case '+':
2770     {
2771       c2 = l->buf[l->i];
2772       if (c2 == '+') {
2773         ++l->i;
2774         l->t = BC_LEX_OP_INC;
2775       }
2776       else bc_lex_assign(l, BC_LEX_OP_ASSIGN_PLUS, BC_LEX_OP_PLUS);
2777       break;
2778     }
2779 
2780     case ',':
2781     {
2782       l->t = BC_LEX_COMMA;
2783       break;
2784     }
2785 
2786     case '-':
2787     {
2788       c2 = l->buf[l->i];
2789       if (c2 == '-') {
2790         ++l->i;
2791         l->t = BC_LEX_OP_DEC;
2792       }
2793       else bc_lex_assign(l, BC_LEX_OP_ASSIGN_MINUS, BC_LEX_OP_MINUS);
2794       break;
2795     }
2796 
2797     case '.':
2798     {
2799       c2 = l->buf[l->i];
2800       if (BC_LEX_NUM_CHAR(c2, 'Z', 1)) s = bc_lex_number(l, c);
2801       else {
2802         l->t = BC_LEX_KEY_LAST;
2803         s = bc_lex_posixErr(l, BC_ERROR_POSIX_DOT);
2804       }
2805       break;
2806     }
2807 
2808     case '/':
2809     {
2810       c2 = l->buf[l->i];
2811       if (c2 =='*') s = bc_lex_comment(l);
2812       else bc_lex_assign(l, BC_LEX_OP_ASSIGN_DIVIDE, BC_LEX_OP_DIVIDE);
2813       break;
2814     }
2815 
2816     case '0':
2817     case '1':
2818     case '2':
2819     case '3':
2820     case '4':
2821     case '5':
2822     case '6':
2823     case '7':
2824     case '8':
2825     case '9':
2826     case 'A':
2827     case 'B':
2828     case 'C':
2829     case 'D':
2830     case 'E':
2831     case 'F':
2832     // Apparently, GNU bc (and maybe others) allows any uppercase letter as a
2833     // number. When single digits, they act like the ones above. When multi-
2834     // digit, any letter above the input base is automatically set to the
2835     // biggest allowable digit in the input base.
2836     case 'G':
2837     case 'H':
2838     case 'I':
2839     case 'J':
2840     case 'K':
2841     case 'L':
2842     case 'M':
2843     case 'N':
2844     case 'O':
2845     case 'P':
2846     case 'Q':
2847     case 'R':
2848     case 'S':
2849     case 'T':
2850     case 'U':
2851     case 'V':
2852     case 'W':
2853     case 'X':
2854     case 'Y':
2855     case 'Z':
2856     {
2857       s = bc_lex_number(l, c);
2858       break;
2859     }
2860 
2861     case ';':
2862     {
2863       l->t = BC_LEX_SCOLON;
2864       break;
2865     }
2866 
2867     case '<':
2868     {
2869       bc_lex_assign(l, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_LT);
2870       break;
2871     }
2872 
2873     case '=':
2874     {
2875       bc_lex_assign(l, BC_LEX_OP_REL_EQ, BC_LEX_OP_ASSIGN);
2876       break;
2877     }
2878 
2879     case '>':
2880     {
2881       bc_lex_assign(l, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_GT);
2882       break;
2883     }
2884 
2885     case '[':
2886     case ']':
2887     {
2888       l->t = (BcLexType) (c - '[' + BC_LEX_LBRACKET);
2889       break;
2890     }
2891 
2892     case '\\':
2893     {
2894       if (l->buf[l->i] == '\n') {
2895         l->t = BC_LEX_WHITESPACE;
2896         ++l->i;
2897       }
2898       else s = bc_lex_invalidChar(l, c);
2899       break;
2900     }
2901 
2902     case '^':
2903     {
2904       bc_lex_assign(l, BC_LEX_OP_ASSIGN_POWER, BC_LEX_OP_POWER);
2905       break;
2906     }
2907 
2908     case 'a':
2909     case 'b':
2910     case 'c':
2911     case 'd':
2912     case 'e':
2913     case 'f':
2914     case 'g':
2915     case 'h':
2916     case 'i':
2917     case 'j':
2918     case 'k':
2919     case 'l':
2920     case 'm':
2921     case 'n':
2922     case 'o':
2923     case 'p':
2924     case 'q':
2925     case 'r':
2926     case 's':
2927     case 't':
2928     case 'u':
2929     case 'v':
2930     case 'w':
2931     case 'x':
2932     case 'y':
2933     case 'z':
2934     {
2935       s = bc_lex_identifier(l);
2936       break;
2937     }
2938 
2939     case '{':
2940     case '}':
2941     {
2942       l->t = (BcLexType) (c - '{' + BC_LEX_LBRACE);
2943       break;
2944     }
2945 
2946     case '|':
2947     {
2948       c2 = l->buf[l->i];
2949 
2950       if (c2 == '|') {
2951 
2952         s = bc_lex_vposixErr(l, BC_ERROR_POSIX_BOOL, "||");
2953         if (s) return s;
2954 
2955         ++l->i;
2956         l->t = BC_LEX_OP_BOOL_OR;
2957       }
2958       else s = bc_lex_invalidChar(l, c);
2959 
2960       break;
2961     }
2962 
2963     default:
2964     {
2965       s = bc_lex_invalidChar(l, c);
2966       break;
2967     }
2968   }
2969 
2970   return s;
2971 }
2972 
bc_parse_updateFunc(BcParse * p,size_t fidx)2973 void bc_parse_updateFunc(BcParse *p, size_t fidx) {
2974   p->fidx = fidx;
2975   p->func = bc_vec_item(&p->prog->fns, fidx);
2976 }
2977 
bc_parse_pushName(BcParse * p,char * name)2978 void bc_parse_pushName(BcParse *p, char *name) {
2979   bc_vec_npush(&p->func->code, strlen(name), name);
2980   bc_parse_push(p, UCHAR_MAX);
2981 }
2982 
bc_parse_pushIndex(BcParse * p,size_t idx)2983 void bc_parse_pushIndex(BcParse *p, size_t idx) {
2984   bc_vec_pushIndex(&p->func->code, idx);
2985 }
2986 
bc_parse_addId(BcParse * p,uchar inst)2987 void bc_parse_addId(BcParse *p, uchar inst) {
2988 
2989   BcFunc *f = p->func;
2990   BcVec *v = inst == BC_INST_NUM ? &f->consts : &f->strs;
2991   size_t idx = v->len;
2992   char *str = xstrdup(p->l.str.v);
2993 
2994   bc_vec_push(v, &str);
2995   bc_parse_updateFunc(p, p->fidx);
2996   bc_parse_push(p, inst);
2997   bc_parse_pushIndex(p, idx);
2998 }
2999 
bc_parse_text(BcParse * p,char * text)3000 BcStatus bc_parse_text(BcParse *p, char *text) {
3001   // Make sure the pointer isn't invalidated.
3002   p->func = bc_vec_item(&p->prog->fns, p->fidx);
3003   return bc_lex_text(&p->l, text);
3004 }
3005 
bc_parse_reset(BcParse * p,BcStatus s)3006 BcStatus bc_parse_reset(BcParse *p, BcStatus s) {
3007 
3008   if (p->fidx != BC_PROG_MAIN) {
3009     bc_func_reset(p->func);
3010     bc_parse_updateFunc(p, BC_PROG_MAIN);
3011   }
3012 
3013   p->l.i = p->l.len;
3014   p->l.t = BC_LEX_EOF;
3015   p->auto_part = 0;
3016 
3017   bc_vec_npop(&p->flags, p->flags.len - 1);
3018   bc_vec_npop(&p->exits, p->exits.len);
3019   bc_vec_npop(&p->conds, p->conds.len);
3020   bc_vec_npop(&p->ops, p->ops.len);
3021 
3022   return bc_program_reset(p->prog, s);
3023 }
3024 
bc_parse_free(BcParse * p)3025 void bc_parse_free(BcParse *p) {
3026   bc_vec_free(&p->flags);
3027   bc_vec_free(&p->exits);
3028   bc_vec_free(&p->conds);
3029   bc_vec_free(&p->ops);
3030   bc_vec_free(&p->l.str);
3031 }
3032 
bc_parse_init(BcParse * p,BcProgram * prog,size_t func)3033 void bc_parse_init(BcParse *p, BcProgram *prog, size_t func)
3034 {
3035   uint16_t flag = 0;
3036   bc_vec_init(&p->flags, sizeof(uint16_t), NULL);
3037   bc_vec_push(&p->flags, &flag);
3038   bc_vec_init(&p->exits, sizeof(BcInstPtr), NULL);
3039   bc_vec_init(&p->conds, sizeof(size_t), NULL);
3040   bc_vec_init(&p->ops, sizeof(BcLexType), NULL);
3041 
3042   bc_lex_init(&p->l);
3043 
3044   p->prog = prog;
3045   p->auto_part = 0;
3046   bc_parse_updateFunc(p, func);
3047 }
3048 
3049 static BcStatus bc_parse_else(BcParse *p);
3050 static BcStatus bc_parse_stmt(BcParse *p);
3051 static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next);
3052 
bc_parse_inst_isLeaf(BcInst t)3053 static int bc_parse_inst_isLeaf(BcInst t) {
3054   return (t >= BC_INST_NUM && t <= BC_INST_ABS) ||
3055           t == BC_INST_INC_POST || t == BC_INST_DEC_POST;
3056 }
3057 
bc_parse_isDelimiter(BcParse * p)3058 static int bc_parse_isDelimiter(BcParse *p) {
3059 
3060   BcLexType t = p->l.t;
3061   int good = 0;
3062 
3063   if (BC_PARSE_DELIMITER(t)) return 1;
3064 
3065   if (t == BC_LEX_KEY_ELSE) {
3066 
3067     size_t i;
3068     uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
3069 
3070     for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) {
3071       fptr = bc_vec_item_rev(&p->flags, i);
3072       flags = *fptr;
3073       if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
3074         return 0;
3075     }
3076 
3077     good = ((flags & BC_PARSE_FLAG_IF) != 0);
3078   }
3079   else if (t == BC_LEX_RBRACE) {
3080 
3081     size_t i;
3082 
3083     for (i = 0; !good && i < p->flags.len; ++i) {
3084       uint16_t *fptr = bc_vec_item_rev(&p->flags, i);
3085       good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
3086     }
3087   }
3088 
3089   return good;
3090 }
3091 
bc_parse_setLabel(BcParse * p)3092 static void bc_parse_setLabel(BcParse *p) {
3093 
3094   BcFunc *func = p->func;
3095   BcInstPtr *ip = bc_vec_top(&p->exits);
3096   size_t *label;
3097 
3098   label = bc_vec_item(&func->labels, ip->idx);
3099   *label = func->code.len;
3100 
3101   bc_vec_pop(&p->exits);
3102 }
3103 
bc_parse_createLabel(BcParse * p,size_t idx)3104 static void bc_parse_createLabel(BcParse *p, size_t idx) {
3105   bc_vec_push(&p->func->labels, &idx);
3106 }
3107 
bc_parse_createCondLabel(BcParse * p,size_t idx)3108 static void bc_parse_createCondLabel(BcParse *p, size_t idx) {
3109   bc_parse_createLabel(p, p->func->code.len);
3110   bc_vec_push(&p->conds, &idx);
3111 }
3112 
bc_parse_createExitLabel(BcParse * p,size_t idx,int loop)3113 static void bc_parse_createExitLabel(BcParse *p, size_t idx, int loop) {
3114 
3115   BcInstPtr ip;
3116 
3117   ip.func = loop;
3118   ip.idx = idx;
3119   ip.len = 0;
3120 
3121   bc_vec_push(&p->exits, &ip);
3122   bc_parse_createLabel(p, SIZE_MAX);
3123 }
3124 
bc_parse_addFunc(BcParse * p,char * name)3125 static size_t bc_parse_addFunc(BcParse *p, char *name) {
3126 
3127   size_t idx = bc_program_insertFunc(p->prog, name);
3128 
3129   // Make sure that this pointer was not invalidated.
3130   p->func = bc_vec_item(&p->prog->fns, p->fidx);
3131 
3132   return idx;
3133 }
3134 
bc_parse_operator(BcParse * p,BcLexType type,size_t start,size_t * nexprs)3135 static void bc_parse_operator(BcParse *p, BcLexType type,
3136                               size_t start, size_t *nexprs)
3137 {
3138   BcLexType t;
3139   uchar l, r = BC_PARSE_OP_PREC(type);
3140   uchar left = BC_PARSE_OP_LEFT(type);
3141 
3142   while (p->ops.len > start) {
3143 
3144     t = BC_PARSE_TOP_OP(p);
3145     if (t == BC_LEX_LPAREN) break;
3146 
3147     l = BC_PARSE_OP_PREC(t);
3148     if (l >= r && (l != r || !left)) break;
3149 
3150     bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
3151     bc_vec_pop(&p->ops);
3152     *nexprs -= !BC_PARSE_OP_PREFIX(t);
3153   }
3154 
3155   bc_vec_push(&p->ops, &type);
3156 }
3157 
bc_parse_rightParen(BcParse * p,size_t ops_bgn,size_t * nexs)3158 static BcStatus bc_parse_rightParen(BcParse *p, size_t ops_bgn, size_t *nexs) {
3159 
3160   BcLexType top;
3161 
3162   if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3163 
3164   while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) {
3165 
3166     bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
3167 
3168     bc_vec_pop(&p->ops);
3169     *nexs -= !BC_PARSE_OP_PREFIX(top);
3170 
3171     if (p->ops.len <= ops_bgn) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3172   }
3173 
3174   bc_vec_pop(&p->ops);
3175 
3176   return bc_lex_next(&p->l);
3177 }
3178 
bc_parse_params(BcParse * p,uint8_t flags)3179 static BcStatus bc_parse_params(BcParse *p, uint8_t flags) {
3180 
3181   BcStatus s;
3182   int comma = 0;
3183   size_t nparams;
3184 
3185   s = bc_lex_next(&p->l);
3186   if (s) return s;
3187 
3188   for (nparams = 0; p->l.t != BC_LEX_RPAREN; ++nparams) {
3189 
3190     flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | BC_PARSE_ARRAY;
3191     s = bc_parse_expr_status(p, flags, bc_parse_next_param);
3192     if (s) return s;
3193 
3194     comma = p->l.t == BC_LEX_COMMA;
3195     if (comma) {
3196       s = bc_lex_next(&p->l);
3197       if (s) return s;
3198     }
3199   }
3200 
3201   if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3202   bc_parse_push(p, BC_INST_CALL);
3203   bc_parse_pushIndex(p, nparams);
3204 
3205   return BC_STATUS_SUCCESS;
3206 }
3207 
bc_parse_call(BcParse * p,char * name,uint8_t flags)3208 static BcStatus bc_parse_call(BcParse *p, char *name, uint8_t flags) {
3209 
3210   BcStatus s;
3211   struct str_len id;
3212   size_t idx;
3213 
3214   id.str = name;
3215 
3216   s = bc_parse_params(p, flags);
3217   if (s) goto err;
3218 
3219   if (p->l.t != BC_LEX_RPAREN) {
3220     s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3221     goto err;
3222   }
3223 
3224   idx = bc_map_index(&p->prog->fn_map, &id);
3225 
3226   if (idx == SIZE_MAX) {
3227     bc_parse_addFunc(p, name);
3228     idx = bc_map_index(&p->prog->fn_map, &id);
3229   } else free(name);
3230 
3231   bc_parse_pushIndex(p,
3232     ((struct str_len *)bc_vec_item(&p->prog->fn_map, idx))->len);
3233 
3234   return bc_lex_next(&p->l);
3235 
3236 err:
3237   free(name);
3238   return s;
3239 }
3240 
bc_parse_name(BcParse * p,BcInst * type,uint8_t flags)3241 static BcStatus bc_parse_name(BcParse *p, BcInst *type, uint8_t flags) {
3242 
3243   BcStatus s;
3244   char *name;
3245 
3246   name = xstrdup(p->l.str.v);
3247   s = bc_lex_next(&p->l);
3248   if (s) goto err;
3249 
3250   if (p->l.t == BC_LEX_LBRACKET) {
3251 
3252     s = bc_lex_next(&p->l);
3253     if (s) goto err;
3254 
3255     if (p->l.t == BC_LEX_RBRACKET) {
3256 
3257       if (!(flags & BC_PARSE_ARRAY)) {
3258         s = bc_parse_err(p, BC_ERROR_PARSE_EXPR);
3259         goto err;
3260       }
3261 
3262       *type = BC_INST_ARRAY;
3263     }
3264     else {
3265 
3266       *type = BC_INST_ARRAY_ELEM;
3267 
3268       flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3269       s = bc_parse_expr_status(p, flags, bc_parse_next_elem);
3270       if (s) goto err;
3271 
3272       if (p->l.t != BC_LEX_RBRACKET) {
3273         s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3274         goto err;
3275       }
3276     }
3277 
3278     s = bc_lex_next(&p->l);
3279     if (s) goto err;
3280 
3281     bc_parse_push(p, *type);
3282     bc_parse_pushName(p, name);
3283   }
3284   else if (p->l.t == BC_LEX_LPAREN) {
3285 
3286     if (flags & BC_PARSE_NOCALL) {
3287       s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3288       goto err;
3289     }
3290 
3291     *type = BC_INST_CALL;
3292 
3293     // Return early because bc_parse_call() frees the name.
3294     return bc_parse_call(p, name, flags);
3295   }
3296   else {
3297     *type = BC_INST_VAR;
3298     bc_parse_push(p, BC_INST_VAR);
3299     bc_parse_pushName(p, name);
3300   }
3301 
3302 err:
3303   free(name);
3304   return s;
3305 }
3306 
bc_parse_read(BcParse * p)3307 static BcStatus bc_parse_read(BcParse *p) {
3308 
3309   BcStatus s;
3310 
3311   s = bc_lex_next(&p->l);
3312   if (s) return s;
3313   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3314 
3315   s = bc_lex_next(&p->l);
3316   if (s) return s;
3317   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3318 
3319   bc_parse_push(p, BC_INST_READ);
3320 
3321   return bc_lex_next(&p->l);
3322 }
3323 
bc_parse_builtin(BcParse * p,BcLexType type,uint8_t flags,BcInst * prev)3324 static BcStatus bc_parse_builtin(BcParse *p, BcLexType type,
3325                                  uint8_t flags, BcInst *prev)
3326 {
3327   BcStatus s;
3328 
3329   s = bc_lex_next(&p->l);
3330   if (s) return s;
3331   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3332 
3333   s = bc_lex_next(&p->l);
3334   if (s) return s;
3335 
3336   flags = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL));
3337   if (type == BC_LEX_KEY_LENGTH) flags |= BC_PARSE_ARRAY;
3338 
3339   s = bc_parse_expr_status(p, flags, bc_parse_next_rel);
3340   if (s) return s;
3341 
3342   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3343 
3344   *prev = type - BC_LEX_KEY_LENGTH + BC_INST_LENGTH;
3345   bc_parse_push(p, *prev);
3346 
3347   return bc_lex_next(&p->l);
3348 }
3349 
bc_parse_scale(BcParse * p,BcInst * type,uint8_t flags)3350 static BcStatus bc_parse_scale(BcParse *p, BcInst *type, uint8_t flags) {
3351 
3352   BcStatus s;
3353 
3354   s = bc_lex_next(&p->l);
3355   if (s) return s;
3356 
3357   if (p->l.t != BC_LEX_LPAREN) {
3358     *type = BC_INST_SCALE;
3359     bc_parse_push(p, BC_INST_SCALE);
3360     return BC_STATUS_SUCCESS;
3361   }
3362 
3363   *type = BC_INST_SCALE_FUNC;
3364   flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
3365 
3366   s = bc_lex_next(&p->l);
3367   if (s) return s;
3368 
3369   s = bc_parse_expr_status(p, flags, bc_parse_next_rel);
3370   if (s) return s;
3371   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3372 
3373   bc_parse_push(p, BC_INST_SCALE_FUNC);
3374 
3375   return bc_lex_next(&p->l);
3376 }
3377 
bc_parse_incdec(BcParse * p,BcInst * prev,size_t * nexs,uint8_t flags)3378 static BcStatus bc_parse_incdec(BcParse *p, BcInst *prev,
3379                                 size_t *nexs, uint8_t flags)
3380 {
3381   BcStatus s;
3382   BcLexType type;
3383   uchar inst;
3384   BcInst etype = *prev;
3385   BcLexType last = p->l.last;
3386 
3387   if (last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC || last == BC_LEX_RPAREN)
3388     return s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
3389 
3390   if (BC_PARSE_INST_VAR(etype)) {
3391     *prev = inst = BC_INST_INC_POST + (p->l.t != BC_LEX_OP_INC);
3392     bc_parse_push(p, inst);
3393     s = bc_lex_next(&p->l);
3394   }
3395   else {
3396 
3397     *prev = inst = BC_INST_INC_PRE + (p->l.t != BC_LEX_OP_INC);
3398 
3399     s = bc_lex_next(&p->l);
3400     if (s) return s;
3401     type = p->l.t;
3402 
3403     // Because we parse the next part of the expression
3404     // right here, we need to increment this.
3405     *nexs = *nexs + 1;
3406 
3407     if (type == BC_LEX_NAME)
3408       s = bc_parse_name(p, prev, flags | BC_PARSE_NOCALL);
3409     else if (type >= BC_LEX_KEY_LAST && type <= BC_LEX_KEY_OBASE) {
3410       bc_parse_push(p, type - BC_LEX_KEY_LAST + BC_INST_LAST);
3411       s = bc_lex_next(&p->l);
3412     }
3413     else if (type == BC_LEX_KEY_SCALE) {
3414       s = bc_lex_next(&p->l);
3415       if (s) return s;
3416       if (p->l.t == BC_LEX_LPAREN) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3417       else bc_parse_push(p, BC_INST_SCALE);
3418     }
3419     else s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3420 
3421     if (!s) bc_parse_push(p, inst);
3422   }
3423 
3424   return s;
3425 }
3426 
bc_parse_minus(BcParse * p,BcInst * prev,size_t ops_bgn,int rparen,int bin_last,size_t * nexprs)3427 static BcStatus bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
3428                                int rparen, int bin_last, size_t *nexprs)
3429 {
3430   BcStatus s;
3431   BcLexType type;
3432 
3433   s = bc_lex_next(&p->l);
3434   if (s) return s;
3435 
3436   type = BC_PARSE_LEAF(*prev, bin_last, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
3437   *prev = BC_PARSE_TOKEN_INST(type);
3438 
3439   // We can just push onto the op stack because this is the largest
3440   // precedence operator that gets pushed. Inc/dec does not.
3441   if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
3442   else bc_parse_operator(p, type, ops_bgn, nexprs);
3443 
3444   return s;
3445 }
3446 
bc_parse_str(BcParse * p,char inst)3447 static BcStatus bc_parse_str(BcParse *p, char inst) {
3448   bc_parse_string(p);
3449   bc_parse_push(p, inst);
3450   return bc_lex_next(&p->l);
3451 }
3452 
bc_parse_print(BcParse * p)3453 static BcStatus bc_parse_print(BcParse *p) {
3454 
3455   BcStatus s;
3456   BcLexType t;
3457   int comma = 0;
3458 
3459   s = bc_lex_next(&p->l);
3460   if (s) return s;
3461 
3462   t = p->l.t;
3463 
3464   if (bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_PRINT);
3465 
3466   do {
3467     if (t == BC_LEX_STR) s = bc_parse_str(p, BC_INST_PRINT_POP);
3468     else {
3469       s = bc_parse_expr_status(p, 0, bc_parse_next_print);
3470       if (!s) bc_parse_push(p, BC_INST_PRINT_POP);
3471     }
3472 
3473     if (s) return s;
3474 
3475     comma = (p->l.t == BC_LEX_COMMA);
3476 
3477     if (comma) s = bc_lex_next(&p->l);
3478     else {
3479       if (!bc_parse_isDelimiter(p))
3480         return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3481       else break;
3482     }
3483 
3484     t = p->l.t;
3485   } while (!s);
3486 
3487   if (s) return s;
3488   if (comma) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3489 
3490   return s;
3491 }
3492 
bc_parse_return(BcParse * p)3493 static BcStatus bc_parse_return(BcParse *p) {
3494 
3495   BcStatus s;
3496   BcLexType t;
3497   int paren;
3498   uchar inst = BC_INST_RET0;
3499 
3500   if (!BC_PARSE_FUNC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3501 
3502   if (p->func->voidfn) inst = BC_INST_RET_VOID;
3503 
3504   s = bc_lex_next(&p->l);
3505   if (s) return s;
3506 
3507   t = p->l.t;
3508   paren = t == BC_LEX_LPAREN;
3509 
3510   if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
3511   else {
3512 
3513     s = bc_parse_expr_err(p, 0, bc_parse_next_expr);
3514     if (s && s != BC_STATUS_EMPTY_EXPR) return s;
3515     else if (s == BC_STATUS_EMPTY_EXPR) {
3516       bc_parse_push(p, inst);
3517       s = bc_lex_next(&p->l);
3518       if (s) return s;
3519     }
3520 
3521     if (!paren || p->l.last != BC_LEX_RPAREN) {
3522       s = bc_parse_posixErr(p, BC_ERROR_POSIX_RET);
3523       if (s) return s;
3524     }
3525     else if (p->func->voidfn)
3526       return bc_parse_verr(p, BC_ERROR_PARSE_RET_VOID, p->func->name);
3527 
3528     bc_parse_push(p, BC_INST_RET);
3529   }
3530 
3531   return s;
3532 }
3533 
bc_parse_endBody(BcParse * p,int brace)3534 static BcStatus bc_parse_endBody(BcParse *p, int brace) {
3535 
3536   BcStatus s = BC_STATUS_SUCCESS;
3537   int has_brace, new_else = 0;
3538 
3539   if (p->flags.len <= 1) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3540 
3541   if (brace) {
3542     if (p->l.t == BC_LEX_RBRACE) {
3543       s = bc_lex_next(&p->l);
3544       if (s) return s;
3545       if (!bc_parse_isDelimiter(p))
3546         return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3547     }
3548     else return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3549   }
3550 
3551   has_brace = (BC_PARSE_BRACE(p) != 0);
3552 
3553   do {
3554     size_t len = p->flags.len;
3555     int loop;
3556 
3557     if (has_brace && !brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3558 
3559     loop = BC_PARSE_LOOP_INNER(p) != 0;
3560 
3561     if (loop || BC_PARSE_ELSE(p)) {
3562 
3563       if (loop) {
3564 
3565         size_t *label = bc_vec_top(&p->conds);
3566 
3567         bc_parse_push(p, BC_INST_JUMP);
3568         bc_parse_pushIndex(p, *label);
3569 
3570         bc_vec_pop(&p->conds);
3571       }
3572 
3573       bc_parse_setLabel(p);
3574       bc_vec_pop(&p->flags);
3575     }
3576     else if (BC_PARSE_FUNC_INNER(p)) {
3577       BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
3578       bc_parse_push(p, inst);
3579       bc_parse_updateFunc(p, BC_PROG_MAIN);
3580       bc_vec_pop(&p->flags);
3581     }
3582     else if (BC_PARSE_BRACE(p) && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
3583 
3584     // This needs to be last to parse nested if's properly.
3585     if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) {
3586 
3587       while (p->l.t == BC_LEX_NLINE) {
3588         s = bc_lex_next(&p->l);
3589         if (s) return s;
3590       }
3591 
3592       bc_vec_pop(&p->flags);
3593       *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
3594 
3595       new_else = (p->l.t == BC_LEX_KEY_ELSE);
3596       if (new_else) s = bc_parse_else(p);
3597       else if (!has_brace && (!BC_PARSE_IF_END(p) || brace))
3598         bc_parse_noElse(p);
3599     }
3600 
3601     if (brace && has_brace) brace = 0;
3602 
3603   } while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
3604            !(has_brace = (BC_PARSE_BRACE(p) != 0)));
3605 
3606   if (!s && p->flags.len == 1 && brace)
3607     s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3608   else if (brace && BC_PARSE_BRACE(p)) {
3609     uint16_t flags = BC_PARSE_TOP_FLAG(p);
3610     if (!(flags & (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_LOOP_INNER)) &&
3611         !(flags & (BC_PARSE_FLAG_IF | BC_PARSE_FLAG_ELSE)) &&
3612         !(flags & (BC_PARSE_FLAG_IF_END)))
3613     {
3614       bc_vec_pop(&p->flags);
3615     }
3616   }
3617 
3618   return s;
3619 }
3620 
bc_parse_startBody(BcParse * p,uint16_t flags)3621 static void bc_parse_startBody(BcParse *p, uint16_t flags) {
3622   flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
3623   flags |= BC_PARSE_FLAG_BODY;
3624   bc_vec_push(&p->flags, &flags);
3625 }
3626 
bc_parse_noElse(BcParse * p)3627 void bc_parse_noElse(BcParse *p) {
3628   uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
3629   *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
3630   bc_parse_setLabel(p);
3631 }
3632 
bc_parse_if(BcParse * p)3633 static BcStatus bc_parse_if(BcParse *p) {
3634 
3635   BcStatus s;
3636   size_t idx;
3637 
3638   s = bc_lex_next(&p->l);
3639   if (s) return s;
3640   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3641 
3642   s = bc_lex_next(&p->l);
3643   if (s) return s;
3644   s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_rel);
3645   if (s) return s;
3646   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3647 
3648   s = bc_lex_next(&p->l);
3649   if (s) return s;
3650   bc_parse_push(p, BC_INST_JUMP_ZERO);
3651 
3652   idx = p->func->labels.len;
3653 
3654   bc_parse_pushIndex(p, idx);
3655   bc_parse_createExitLabel(p, idx, 0);
3656   bc_parse_startBody(p, BC_PARSE_FLAG_IF);
3657 
3658   return BC_STATUS_SUCCESS;
3659 }
3660 
bc_parse_else(BcParse * p)3661 static BcStatus bc_parse_else(BcParse *p) {
3662 
3663   size_t idx = p->func->labels.len;
3664 
3665   if (!BC_PARSE_IF_END(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3666 
3667   bc_parse_push(p, BC_INST_JUMP);
3668   bc_parse_pushIndex(p, idx);
3669 
3670   bc_parse_noElse(p);
3671 
3672   bc_parse_createExitLabel(p, idx, 0);
3673   bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
3674 
3675   return bc_lex_next(&p->l);
3676 }
3677 
bc_parse_while(BcParse * p)3678 static BcStatus bc_parse_while(BcParse *p) {
3679 
3680   BcStatus s;
3681   size_t idx;
3682 
3683   s = bc_lex_next(&p->l);
3684   if (s) return s;
3685   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3686   s = bc_lex_next(&p->l);
3687   if (s) return s;
3688 
3689   bc_parse_createCondLabel(p, p->func->labels.len);
3690 
3691   idx = p->func->labels.len;
3692 
3693   bc_parse_createExitLabel(p, idx, 1);
3694 
3695   s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_rel);
3696   if (s) return s;
3697   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3698   s = bc_lex_next(&p->l);
3699   if (s) return s;
3700 
3701   bc_parse_push(p, BC_INST_JUMP_ZERO);
3702   bc_parse_pushIndex(p, idx);
3703   bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
3704 
3705   return BC_STATUS_SUCCESS;
3706 }
3707 
bc_parse_for(BcParse * p)3708 static BcStatus bc_parse_for(BcParse *p) {
3709 
3710   BcStatus s;
3711   size_t cond_idx, exit_idx, body_idx, update_idx;
3712 
3713   s = bc_lex_next(&p->l);
3714   if (s) return s;
3715   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3716   s = bc_lex_next(&p->l);
3717   if (s) return s;
3718 
3719   if (p->l.t != BC_LEX_SCOLON) {
3720     s = bc_parse_expr_status(p, 0, bc_parse_next_for);
3721     if (!s) bc_parse_push(p, BC_INST_POP);
3722   }
3723   else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR1);
3724 
3725   if (s) return s;
3726   if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3727   s = bc_lex_next(&p->l);
3728   if (s) return s;
3729 
3730   cond_idx = p->func->labels.len;
3731   update_idx = cond_idx + 1;
3732   body_idx = update_idx + 1;
3733   exit_idx = body_idx + 1;
3734 
3735   bc_parse_createLabel(p, p->func->code.len);
3736 
3737   if (p->l.t != BC_LEX_SCOLON)
3738     s = bc_parse_expr_status(p, BC_PARSE_REL, bc_parse_next_for);
3739   else {
3740 
3741     // Set this for the next call to bc_parse_number.
3742     // This is safe to set because the current token
3743     // is a semicolon, which has no string requirement.
3744     bc_vec_string(&p->l.str, strlen(bc_parse_const1), bc_parse_const1);
3745     bc_parse_number(p);
3746 
3747     s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR2);
3748   }
3749 
3750   if (s) return s;
3751   if (p->l.t != BC_LEX_SCOLON) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3752 
3753   s = bc_lex_next(&p->l);
3754   if (s) return s;
3755 
3756   bc_parse_push(p, BC_INST_JUMP_ZERO);
3757   bc_parse_pushIndex(p, exit_idx);
3758   bc_parse_push(p, BC_INST_JUMP);
3759   bc_parse_pushIndex(p, body_idx);
3760 
3761   bc_parse_createCondLabel(p, update_idx);
3762 
3763   if (p->l.t != BC_LEX_RPAREN) {
3764     s = bc_parse_expr_status(p, 0, bc_parse_next_rel);
3765     if (!s) bc_parse_push(p, BC_INST_POP);
3766   }
3767   else s = bc_parse_posixErr(p, BC_ERROR_POSIX_FOR3);
3768 
3769   if (s) return s;
3770 
3771   if (p->l.t != BC_LEX_RPAREN) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3772   bc_parse_push(p, BC_INST_JUMP);
3773   bc_parse_pushIndex(p, cond_idx);
3774   bc_parse_createLabel(p, p->func->code.len);
3775 
3776   bc_parse_createExitLabel(p, exit_idx, 1);
3777   s = bc_lex_next(&p->l);
3778   if (!s) bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
3779 
3780   return s;
3781 }
3782 
bc_parse_loopExit(BcParse * p,BcLexType type)3783 static BcStatus bc_parse_loopExit(BcParse *p, BcLexType type) {
3784 
3785   size_t i;
3786   BcInstPtr *ip;
3787 
3788   if (!BC_PARSE_LOOP(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3789 
3790   if (type == BC_LEX_KEY_BREAK) {
3791 
3792     if (!p->exits.len) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3793 
3794     i = p->exits.len - 1;
3795     ip = bc_vec_item(&p->exits, i);
3796 
3797     while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
3798     if (i >= p->exits.len && !ip->func)
3799       return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3800 
3801     i = ip->idx;
3802   }
3803   else i = *((size_t*) bc_vec_top(&p->conds));
3804 
3805   bc_parse_push(p, BC_INST_JUMP);
3806   bc_parse_pushIndex(p, i);
3807 
3808   return bc_lex_next(&p->l);
3809 }
3810 
bc_parse_func(BcParse * p)3811 static BcStatus bc_parse_func(BcParse *p) {
3812 
3813   BcStatus s;
3814   int comma = 0, voidfn;
3815   uint16_t flags;
3816   char *name;
3817   size_t idx;
3818 
3819   s = bc_lex_next(&p->l);
3820   if (s) return s;
3821 
3822   if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3823 
3824   voidfn = (!FLAG(s) && !FLAG(w) && p->l.t == BC_LEX_NAME &&
3825             !strcmp(p->l.str.v, "void"));
3826 
3827   s = bc_lex_next(&p->l);
3828   if (s) return s;
3829 
3830   voidfn = (voidfn && p->l.t == BC_LEX_NAME);
3831 
3832   if (voidfn) {
3833     s = bc_lex_next(&p->l);
3834     if (s) return s;
3835   }
3836 
3837   if (p->l.t != BC_LEX_LPAREN) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3838 
3839   name = xstrdup(p->l.str.v);
3840   idx = bc_program_insertFunc(p->prog, name);
3841   bc_parse_updateFunc(p, idx);
3842   p->func->voidfn = voidfn;
3843 
3844   s = bc_lex_next(&p->l);
3845   if (s) return s;
3846 
3847   while (p->l.t != BC_LEX_RPAREN) {
3848 
3849     BcType t = BC_TYPE_VAR;
3850 
3851     if (p->l.t != BC_LEX_NAME) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3852 
3853     ++p->func->nparams;
3854 
3855     name = xstrdup(p->l.str.v);
3856     s = bc_lex_next(&p->l);
3857     if (s) goto err;
3858 
3859     if (p->l.t == BC_LEX_LBRACKET) {
3860 
3861       if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
3862 
3863       s = bc_lex_next(&p->l);
3864       if (s) goto err;
3865 
3866       if (p->l.t != BC_LEX_RBRACKET) {
3867         s = bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3868         goto err;
3869       }
3870 
3871       s = bc_lex_next(&p->l);
3872       if (s) goto err;
3873     }
3874 
3875     comma = p->l.t == BC_LEX_COMMA;
3876     if (comma) {
3877       s = bc_lex_next(&p->l);
3878       if (s) goto err;
3879     }
3880 
3881     s = bc_func_insert(p->func, name, t, p->l.line);
3882     if (s) goto err;
3883   }
3884 
3885   if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3886 
3887   flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_BODY;
3888   bc_parse_startBody(p, flags);
3889 
3890   s = bc_lex_next(&p->l);
3891   if (s) return s;
3892 
3893   if (p->l.t != BC_LEX_LBRACE) s = bc_parse_posixErr(p, BC_ERROR_POSIX_BRACE);
3894 
3895   return s;
3896 
3897 err:
3898   free(name);
3899   return s;
3900 }
3901 
bc_parse_auto(BcParse * p)3902 static BcStatus bc_parse_auto(BcParse *p) {
3903 
3904   BcStatus s;
3905   int comma, one;
3906   char *name;
3907 
3908   if (!p->auto_part) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3909   s = bc_lex_next(&p->l);
3910   if (s) return s;
3911 
3912   p->auto_part = comma = 0;
3913   one = p->l.t == BC_LEX_NAME;
3914 
3915   while (p->l.t == BC_LEX_NAME) {
3916 
3917     BcType t;
3918 
3919     name = xstrdup(p->l.str.v);
3920     s = bc_lex_next(&p->l);
3921     if (s) goto err;
3922 
3923     if (p->l.t == BC_LEX_LBRACKET) {
3924 
3925       t = BC_TYPE_ARRAY;
3926 
3927       s = bc_lex_next(&p->l);
3928       if (s) goto err;
3929 
3930       if (p->l.t != BC_LEX_RBRACKET) {
3931         s = bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3932         goto err;
3933       }
3934 
3935       s = bc_lex_next(&p->l);
3936       if (s) goto err;
3937     }
3938     else t = BC_TYPE_VAR;
3939 
3940     comma = p->l.t == BC_LEX_COMMA;
3941     if (comma) {
3942       s = bc_lex_next(&p->l);
3943       if (s) goto err;
3944     }
3945 
3946     s = bc_func_insert(p->func, name, t, p->l.line);
3947     if (s) goto err;
3948   }
3949 
3950   if (comma) return bc_parse_err(p, BC_ERROR_PARSE_FUNC);
3951   if (!one) return bc_parse_err(p, BC_ERROR_PARSE_NO_AUTO);
3952   if (!bc_parse_isDelimiter(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3953 
3954   return s;
3955 
3956 err:
3957   free(name);
3958   return s;
3959 }
3960 
bc_parse_body(BcParse * p,int brace)3961 static BcStatus bc_parse_body(BcParse *p, int brace) {
3962 
3963   BcStatus s = BC_STATUS_SUCCESS;
3964   uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
3965 
3966   *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
3967 
3968   if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
3969 
3970     if (!brace) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
3971 
3972     p->auto_part = p->l.t != BC_LEX_KEY_AUTO;
3973 
3974     if (!p->auto_part) {
3975 
3976       // Make sure this is 1 to not get a parse error.
3977       p->auto_part = 1;
3978 
3979       s = bc_parse_auto(p);
3980       if (s) return s;
3981     }
3982 
3983     if (p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
3984   }
3985   else {
3986     size_t len = p->flags.len;
3987     s = bc_parse_stmt(p);
3988     if (!s && !brace && !BC_PARSE_BODY(p) && len <= p->flags.len)
3989       s = bc_parse_endBody(p, 0);
3990   }
3991 
3992   return s;
3993 }
3994 
bc_parse_stmt(BcParse * p)3995 static BcStatus bc_parse_stmt(BcParse *p) {
3996 
3997   BcStatus s = BC_STATUS_SUCCESS;
3998   size_t len;
3999   uint16_t flags;
4000   BcLexType type = p->l.t;
4001 
4002   if (type == BC_LEX_NLINE) return bc_lex_next(&p->l);
4003   if (type == BC_LEX_KEY_AUTO) return bc_parse_auto(p);
4004 
4005   p->auto_part = 0;
4006 
4007   if (type != BC_LEX_KEY_ELSE) {
4008 
4009     if (BC_PARSE_IF_END(p)) {
4010       bc_parse_noElse(p);
4011       if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
4012         s = bc_parse_endBody(p, 0);
4013       return s;
4014     }
4015     else if (type == BC_LEX_LBRACE) {
4016 
4017       if (!BC_PARSE_BODY(p)) {
4018         bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
4019         s = bc_lex_next(&p->l);
4020       }
4021       else {
4022         *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
4023         s = bc_lex_next(&p->l);
4024         if (!s) s = bc_parse_body(p, 1);
4025       }
4026 
4027       return s;
4028     }
4029     else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p))
4030       return bc_parse_body(p, 0);
4031   }
4032 
4033   len = p->flags.len;
4034   flags = BC_PARSE_TOP_FLAG(p);
4035 
4036   switch (type) {
4037 
4038     case BC_LEX_OP_INC:
4039     case BC_LEX_OP_DEC:
4040     case BC_LEX_OP_MINUS:
4041     case BC_LEX_OP_BOOL_NOT:
4042     case BC_LEX_LPAREN:
4043     case BC_LEX_NAME:
4044     case BC_LEX_NUMBER:
4045     case BC_LEX_KEY_IBASE:
4046     case BC_LEX_KEY_LAST:
4047     case BC_LEX_KEY_LENGTH:
4048     case BC_LEX_KEY_OBASE:
4049     case BC_LEX_KEY_READ:
4050     case BC_LEX_KEY_SCALE:
4051     case BC_LEX_KEY_SQRT:
4052     case BC_LEX_KEY_ABS:
4053     {
4054       s = bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
4055       break;
4056     }
4057 
4058     case BC_LEX_KEY_ELSE:
4059     {
4060       s = bc_parse_else(p);
4061       break;
4062     }
4063 
4064     case BC_LEX_SCOLON:
4065     {
4066       // Do nothing.
4067       break;
4068     }
4069 
4070     case BC_LEX_RBRACE:
4071     {
4072       s = bc_parse_endBody(p, 1);
4073       break;
4074     }
4075 
4076     case BC_LEX_STR:
4077     {
4078       s = bc_parse_str(p, BC_INST_PRINT_STR);
4079       break;
4080     }
4081 
4082     case BC_LEX_KEY_BREAK:
4083     case BC_LEX_KEY_CONTINUE:
4084     {
4085       s = bc_parse_loopExit(p, p->l.t);
4086       break;
4087     }
4088 
4089     case BC_LEX_KEY_FOR:
4090     {
4091       s = bc_parse_for(p);
4092       break;
4093     }
4094 
4095     case BC_LEX_KEY_HALT:
4096     {
4097       bc_parse_push(p, BC_INST_HALT);
4098       s = bc_lex_next(&p->l);
4099       break;
4100     }
4101 
4102     case BC_LEX_KEY_IF:
4103     {
4104       s = bc_parse_if(p);
4105       break;
4106     }
4107 
4108     case BC_LEX_KEY_LIMITS:
4109     {
4110       printf("BC_BASE_MAX     = %lu\n", BC_MAX_OBASE);
4111       printf("BC_DIM_MAX      = %lu\n", BC_MAX_DIM);
4112       printf("BC_SCALE_MAX    = %lu\n", BC_MAX_SCALE);
4113       printf("BC_STRING_MAX   = %lu\n", BC_MAX_STRING);
4114       printf("BC_NAME_MAX     = %lu\n", BC_MAX_NAME);
4115       printf("BC_NUM_MAX      = %lu\n", BC_MAX_NUM);
4116       printf("MAX Exponent    = %lu\n", BC_MAX_EXP);
4117       printf("Number of vars  = %lu\n", BC_MAX_VARS);
4118 
4119       s = bc_lex_next(&p->l);
4120 
4121       break;
4122     }
4123 
4124     case BC_LEX_KEY_PRINT:
4125     {
4126       s = bc_parse_print(p);
4127       break;
4128     }
4129 
4130     case BC_LEX_KEY_QUIT:
4131     {
4132       // Quit is a compile-time command. We don't exit directly,
4133       // so the vm can clean up. Limits do the same thing.
4134       s = BC_STATUS_QUIT;
4135       break;
4136     }
4137 
4138     case BC_LEX_KEY_RETURN:
4139     {
4140       s = bc_parse_return(p);
4141       break;
4142     }
4143 
4144     case BC_LEX_KEY_WHILE:
4145     {
4146       s = bc_parse_while(p);
4147       break;
4148     }
4149 
4150     default:
4151     {
4152       s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4153       break;
4154     }
4155   }
4156 
4157   if (!s && len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) {
4158     if (!bc_parse_isDelimiter(p)) s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4159   }
4160 
4161   // Make sure semicolons are eaten.
4162   while (!s && p->l.t == BC_LEX_SCOLON) s = bc_lex_next(&p->l);
4163 
4164   return s;
4165 }
4166 
bc_parse_parse(BcParse * p)4167 BcStatus bc_parse_parse(BcParse *p) {
4168 
4169   BcStatus s;
4170 
4171   if (p->l.t == BC_LEX_EOF) s = bc_parse_err(p, BC_ERROR_PARSE_EOF);
4172   else if (p->l.t == BC_LEX_KEY_DEFINE) {
4173     if (BC_PARSE_NO_EXEC(p)) return bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4174     s = bc_parse_func(p);
4175   }
4176   else s = bc_parse_stmt(p);
4177 
4178   if ((s && s != BC_STATUS_QUIT) || TT.sig) s = bc_parse_reset(p, s);
4179 
4180   return s;
4181 }
4182 
bc_parse_expr_err(BcParse * p,uint8_t flags,BcParseNext next)4183 static BcStatus bc_parse_expr_err(BcParse *p, uint8_t flags, BcParseNext next) {
4184   BcStatus s = BC_STATUS_SUCCESS;
4185   BcInst prev = BC_INST_PRINT;
4186   BcLexType top, t = p->l.t;
4187   size_t nexprs = 0, ops_bgn = p->ops.len;
4188   uint32_t i, nparens, nrelops;
4189   int pfirst, rprn, done, get_token, assign, bin_last, incdec;
4190   char valid[] = {0xfc, 0xff, 0xff, 0x67, 0xc0, 0x00, 0x7c, 0x0b};
4191 
4192   pfirst = p->l.t == BC_LEX_LPAREN;
4193   nparens = nrelops = 0;
4194   rprn = done = get_token = assign = incdec = 0;
4195   bin_last = 1;
4196 
4197   // We want to eat newlines if newlines are not a valid ending token.
4198   // This is for spacing in things like for loop headers.
4199   while (!s && (t = p->l.t) == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4200 
4201   // Loop checking if token is valid in this expression
4202   for (; !TT.sig && !s && !done && (valid[t>>3] & (1<<(t&7))); t = p->l.t) {
4203 
4204     switch (t) {
4205 
4206       case BC_LEX_OP_INC:
4207       case BC_LEX_OP_DEC:
4208       {
4209         if (incdec) return bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
4210         s = bc_parse_incdec(p, &prev, &nexprs, flags);
4211         rprn = get_token = bin_last = 0;
4212         incdec = 1;
4213         break;
4214       }
4215 
4216       case BC_LEX_OP_MINUS:
4217       {
4218         s = bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
4219         rprn = get_token = 0;
4220         bin_last = (prev == BC_INST_MINUS);
4221         if (bin_last) incdec = 0;
4222         break;
4223       }
4224 
4225       case BC_LEX_OP_ASSIGN_POWER:
4226       case BC_LEX_OP_ASSIGN_MULTIPLY:
4227       case BC_LEX_OP_ASSIGN_DIVIDE:
4228       case BC_LEX_OP_ASSIGN_MODULUS:
4229       case BC_LEX_OP_ASSIGN_PLUS:
4230       case BC_LEX_OP_ASSIGN_MINUS:
4231       case BC_LEX_OP_ASSIGN:
4232       {
4233         if (!BC_PARSE_INST_VAR(prev)) {
4234           s = bc_parse_err(p, BC_ERROR_PARSE_ASSIGN);
4235           break;
4236         }
4237       }
4238       // Fallthrough.
4239       case BC_LEX_OP_POWER:
4240       case BC_LEX_OP_MULTIPLY:
4241       case BC_LEX_OP_DIVIDE:
4242       case BC_LEX_OP_MODULUS:
4243       case BC_LEX_OP_PLUS:
4244       case BC_LEX_OP_REL_EQ:
4245       case BC_LEX_OP_REL_LE:
4246       case BC_LEX_OP_REL_GE:
4247       case BC_LEX_OP_REL_NE:
4248       case BC_LEX_OP_REL_LT:
4249       case BC_LEX_OP_REL_GT:
4250       case BC_LEX_OP_BOOL_NOT:
4251       case BC_LEX_OP_BOOL_OR:
4252       case BC_LEX_OP_BOOL_AND:
4253       {
4254         if (BC_PARSE_OP_PREFIX(t)) {
4255           if (!bin_last && !BC_PARSE_OP_PREFIX(p->l.last))
4256             return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4257         }
4258         else if (BC_PARSE_PREV_PREFIX(prev) || bin_last)
4259           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4260 
4261         nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
4262         prev = BC_PARSE_TOKEN_INST(t);
4263         bc_parse_operator(p, t, ops_bgn, &nexprs);
4264         rprn = incdec = 0;
4265         get_token = 1;
4266         bin_last = !BC_PARSE_OP_PREFIX(t);
4267 
4268         break;
4269       }
4270 
4271       case BC_LEX_LPAREN:
4272       {
4273         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4274           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4275 
4276         ++nparens;
4277         rprn = incdec = 0;
4278         get_token = 1;
4279         bc_vec_push(&p->ops, &t);
4280 
4281         break;
4282       }
4283 
4284       case BC_LEX_RPAREN:
4285       {
4286         // This needs to be a status. The error
4287         // is handled in bc_parse_expr_status().
4288         if (p->l.last == BC_LEX_LPAREN) return BC_STATUS_EMPTY_EXPR;
4289 
4290         if (bin_last || BC_PARSE_PREV_PREFIX(prev))
4291           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4292 
4293         if (!nparens) {
4294           s = BC_STATUS_SUCCESS;
4295           done = 1;
4296           get_token = 0;
4297           break;
4298         }
4299 
4300         --nparens;
4301         rprn = 1;
4302         get_token = bin_last = incdec = 0;
4303 
4304         s = bc_parse_rightParen(p, ops_bgn, &nexprs);
4305 
4306         break;
4307       }
4308 
4309       case BC_LEX_NAME:
4310       {
4311         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4312           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4313 
4314         get_token = bin_last = 0;
4315         s = bc_parse_name(p, &prev, flags & ~BC_PARSE_NOCALL);
4316         rprn = (prev == BC_INST_CALL);
4317         ++nexprs;
4318 
4319         break;
4320       }
4321 
4322       case BC_LEX_NUMBER:
4323       {
4324         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4325           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4326 
4327         bc_parse_number(p);
4328         nexprs += 1;
4329         prev = BC_INST_NUM;
4330         get_token = 1;
4331         rprn = bin_last = 0;
4332 
4333         break;
4334       }
4335 
4336       case BC_LEX_KEY_IBASE:
4337       case BC_LEX_KEY_LAST:
4338       case BC_LEX_KEY_OBASE:
4339       {
4340         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4341           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4342 
4343         prev = (uchar) (t - BC_LEX_KEY_LAST + BC_INST_LAST);
4344         bc_parse_push(p, (uchar) prev);
4345 
4346         get_token = 1;
4347         rprn = bin_last = 0;
4348         ++nexprs;
4349 
4350         break;
4351       }
4352 
4353       case BC_LEX_KEY_LENGTH:
4354       case BC_LEX_KEY_SQRT:
4355       case BC_LEX_KEY_ABS:
4356       {
4357         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4358           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4359 
4360         s = bc_parse_builtin(p, t, flags, &prev);
4361         rprn = get_token = bin_last = incdec = 0;
4362         ++nexprs;
4363 
4364         break;
4365       }
4366 
4367       case BC_LEX_KEY_READ:
4368       {
4369         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4370           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4371         else if (flags & BC_PARSE_NOREAD)
4372           s = bc_parse_err(p, BC_ERROR_EXEC_REC_READ);
4373         else s = bc_parse_read(p);
4374 
4375         rprn = get_token = bin_last = incdec = 0;
4376         ++nexprs;
4377         prev = BC_INST_READ;
4378 
4379         break;
4380       }
4381 
4382       case BC_LEX_KEY_SCALE:
4383       {
4384         if (BC_PARSE_LEAF(prev, bin_last, rprn))
4385           return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4386 
4387         s = bc_parse_scale(p, &prev, flags);
4388         rprn = get_token = bin_last = 0;
4389         ++nexprs;
4390 
4391         break;
4392       }
4393 
4394       default:
4395       {
4396         s = bc_parse_err(p, BC_ERROR_PARSE_TOKEN);
4397         break;
4398       }
4399     }
4400 
4401     if (!s && get_token) s = bc_lex_next(&p->l);
4402   }
4403 
4404   if (s) return s;
4405   if (TT.sig) return BC_STATUS_SIGNAL;
4406 
4407   while (p->ops.len > ops_bgn) {
4408 
4409     top = BC_PARSE_TOP_OP(p);
4410     assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
4411 
4412     if (top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)
4413       return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4414 
4415     bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
4416 
4417     nexprs -= !BC_PARSE_OP_PREFIX(top);
4418     bc_vec_pop(&p->ops);
4419   }
4420 
4421   if (nexprs != 1) return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4422 
4423   for (i = 0; i < next.len && t != next.tokens[i]; ++i);
4424   if (i == next.len && !bc_parse_isDelimiter(p))
4425     return bc_parse_err(p, BC_ERROR_PARSE_EXPR);
4426 
4427   if (!(flags & BC_PARSE_REL) && nrelops) {
4428     s = bc_parse_posixErr(p, BC_ERROR_POSIX_REL_POS);
4429     if (s) return s;
4430   }
4431   else if ((flags & BC_PARSE_REL) && nrelops > 1) {
4432     s = bc_parse_posixErr(p, BC_ERROR_POSIX_MULTIREL);
4433     if (s) return s;
4434   }
4435 
4436   if (flags & BC_PARSE_PRINT) {
4437     if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
4438     bc_parse_push(p, BC_INST_POP);
4439   }
4440 
4441   // We want to eat newlines if newlines are not a valid ending token.
4442   // This is for spacing in things like for loop headers.
4443   for (incdec = 1, i = 0; i < next.len && incdec; ++i)
4444     incdec = (next.tokens[i] != BC_LEX_NLINE);
4445   if (incdec) {
4446     while (!s && p->l.t == BC_LEX_NLINE) s = bc_lex_next(&p->l);
4447   }
4448 
4449   return s;
4450 }
4451 
bc_parse_expr_status(BcParse * p,uint8_t flags,BcParseNext next)4452 BcStatus bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) {
4453 
4454   BcStatus s = bc_parse_expr_err(p, flags, next);
4455 
4456   if (s == BC_STATUS_EMPTY_EXPR) s = bc_parse_err(p, BC_ERROR_PARSE_EMPTY_EXPR);
4457 
4458   return s;
4459 }
4460 
bc_program_type_num(BcResult * r,BcNum * n)4461 static BcStatus bc_program_type_num(BcResult *r, BcNum *n) {
4462   if (!BC_PROG_NUM(r, n)) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4463   return BC_STATUS_SUCCESS;
4464 }
4465 
bc_program_type_match(BcResult * r,BcType t)4466 static BcStatus bc_program_type_match(BcResult *r, BcType t) {
4467   if ((r->t != BC_RESULT_ARRAY) != (!t)) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4468   return BC_STATUS_SUCCESS;
4469 }
4470 
bc_program_str(BcProgram * p,size_t idx,int str)4471 static char *bc_program_str(BcProgram *p, size_t idx, int str) {
4472 
4473   BcFunc *f;
4474   BcVec *v;
4475   size_t i;
4476 
4477   BcInstPtr *ip = bc_vec_item_rev(&p->stack, 0);
4478   i = ip->func;
4479 
4480   f = bc_vec_item(&p->fns, i);
4481   v = str ? &f->strs : &f->consts;
4482 
4483   return *((char**) bc_vec_item(v, idx));
4484 }
4485 
bc_program_index(char * code,size_t * bgn)4486 static size_t bc_program_index(char *code, size_t *bgn) {
4487 
4488   uchar amt = (uchar) code[(*bgn)++], i = 0;
4489   size_t res = 0;
4490 
4491   for (; i < amt; ++i, ++(*bgn)) {
4492     size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
4493     res |= (temp << (i * CHAR_BIT));
4494   }
4495 
4496   return res;
4497 }
4498 
bc_program_name(char * code,size_t * bgn)4499 static char *bc_program_name(char *code, size_t *bgn) {
4500 
4501   size_t i;
4502   uchar c;
4503   char *s;
4504   char *str = code + *bgn, *ptr = strchr(str, UCHAR_MAX);
4505 
4506   s = xmalloc(((unsigned long) ptr) - ((unsigned long) str) + 1);
4507 
4508   for (i = 0; (c = (uchar) code[(*bgn)++]) && c != UCHAR_MAX; ++i)
4509     s[i] = (char) c;
4510 
4511   s[i] = '\0';
4512 
4513   return s;
4514 }
4515 
bc_program_search(BcProgram * p,char * id,BcType type)4516 static BcVec* bc_program_search(BcProgram *p, char *id, BcType type) {
4517 
4518   struct str_len e, *ptr;
4519   BcVec *v, *map;
4520   size_t i;
4521   BcResultData data;
4522   int new, var = (type == BC_TYPE_VAR);
4523 
4524   v = var ? &p->vars : &p->arrs;
4525   map = var ? &p->var_map : &p->arr_map;
4526 
4527   e.str = id;
4528   e.len = v->len;
4529   new = bc_map_insert(map, &e, &i);
4530 
4531   if (new) {
4532     bc_array_init(&data.v, var);
4533     bc_vec_push(v, &data.v);
4534   }
4535 
4536   ptr = bc_vec_item(map, i);
4537   if (new) ptr->str = xstrdup(e.str);
4538 
4539   return bc_vec_item(v, ptr->len);
4540 }
4541 
bc_program_num(BcProgram * p,BcResult * r,BcNum ** num)4542 static BcStatus bc_program_num(BcProgram *p, BcResult *r, BcNum **num) {
4543 
4544   BcStatus s = BC_STATUS_SUCCESS;
4545   BcNum *n = &r->d.n;
4546 
4547   switch (r->t) {
4548 
4549     case BC_RESULT_CONSTANT:
4550     {
4551       char *str = bc_program_str(p, r->d.id.len, 0);
4552       size_t len = strlen(str);
4553 
4554       bc_num_init(n, len);
4555 
4556       s = bc_num_parse(n, str, &p->ib, p->ib_t, len == 1);
4557 
4558       if (s) {
4559         bc_num_free(n);
4560         return s;
4561       }
4562 
4563       r->t = BC_RESULT_TEMP;
4564     }
4565     // Fallthrough.
4566     case BC_RESULT_STR:
4567     case BC_RESULT_TEMP:
4568     case BC_RESULT_IBASE:
4569     case BC_RESULT_SCALE:
4570     case BC_RESULT_OBASE:
4571     {
4572       *num = n;
4573       break;
4574     }
4575 
4576     case BC_RESULT_VAR:
4577     case BC_RESULT_ARRAY:
4578     case BC_RESULT_ARRAY_ELEM:
4579     {
4580       BcVec *v;
4581       BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
4582 
4583       v = bc_program_search(p, r->d.id.str, type);
4584 
4585       if (r->t == BC_RESULT_ARRAY_ELEM) {
4586 
4587         size_t idx = r->d.id.len;
4588 
4589         v = bc_vec_top(v);
4590 
4591         if (v->len <= idx) bc_array_expand(v, idx + 1);
4592         *num = bc_vec_item(v, idx);
4593       }
4594       else *num = bc_vec_top(v);
4595 
4596       break;
4597     }
4598 
4599     case BC_RESULT_LAST:
4600     {
4601       *num = &p->last;
4602       break;
4603     }
4604 
4605     case BC_RESULT_ONE:
4606     {
4607       *num = &p->one;
4608       break;
4609     }
4610 
4611     case BC_RESULT_VOID:
4612     {
4613       s = bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
4614       break;
4615     }
4616   }
4617 
4618   return s;
4619 }
4620 
bc_program_operand(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)4621 static BcStatus bc_program_operand(BcProgram *p, BcResult **r,
4622                                    BcNum **n, size_t idx)
4623 {
4624 
4625   *r = bc_vec_item_rev(&p->results, idx);
4626 
4627   return bc_program_num(p, *r, n);
4628 }
4629 
bc_program_binPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)4630 static BcStatus bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
4631                                    BcResult **r, BcNum **rn)
4632 {
4633   BcStatus s;
4634   BcResultType lt;
4635 
4636   s = bc_program_operand(p, l, ln, 1);
4637   if (s) return s;
4638   s = bc_program_operand(p, r, rn, 0);
4639   if (s) return s;
4640 
4641   lt = (*l)->t;
4642 
4643   // We run this again under these conditions in case any vector has been
4644   // reallocated out from under the BcNums or arrays we had.
4645   if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
4646     s = bc_program_num(p, *l, ln);
4647 
4648   if (lt == BC_RESULT_STR) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4649 
4650   return s;
4651 }
4652 
bc_program_binOpPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)4653 static BcStatus bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
4654                                      BcResult **r, BcNum **rn)
4655 {
4656   BcStatus s;
4657 
4658   s = bc_program_binPrep(p, l, ln, r, rn);
4659   if (s) return s;
4660 
4661   s = bc_program_type_num(*l, *ln);
4662   if (s) return s;
4663 
4664   return bc_program_type_num(*r, *rn);
4665 }
4666 
bc_program_assignPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)4667 static BcStatus bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
4668                                       BcResult **r, BcNum **rn)
4669 {
4670   BcStatus s;
4671   int good = 0;
4672   BcResultType lt;
4673 
4674   s = bc_program_binPrep(p, l, ln, r, rn);
4675   if (s) return s;
4676 
4677   lt = (*l)->t;
4678 
4679   if (lt == BC_RESULT_CONSTANT || lt == BC_RESULT_TEMP ||lt == BC_RESULT_ARRAY)
4680     return bc_vm_err(BC_ERROR_EXEC_TYPE);
4681 
4682   if (lt == BC_RESULT_ONE) return bc_vm_err(BC_ERROR_EXEC_TYPE);
4683 
4684   if (!good) s = bc_program_type_num(*r, *rn);
4685 
4686   return s;
4687 }
4688 
bc_program_binOpRetire(BcProgram * p,BcResult * r)4689 static void bc_program_binOpRetire(BcProgram *p, BcResult *r) {
4690   r->t = BC_RESULT_TEMP;
4691   bc_vec_pop(&p->results);
4692   bc_vec_pop(&p->results);
4693   bc_vec_push(&p->results, r);
4694 }
4695 
bc_program_prep(BcProgram * p,BcResult ** r,BcNum ** n)4696 static BcStatus bc_program_prep(BcProgram *p, BcResult **r, BcNum **n) {
4697 
4698   BcStatus s;
4699 
4700   s = bc_program_operand(p, r, n, 0);
4701   if (s) return s;
4702 
4703   return bc_program_type_num(*r, *n);
4704 }
4705 
bc_program_retire(BcProgram * p,BcResult * r,BcResultType t)4706 static void bc_program_retire(BcProgram *p, BcResult *r, BcResultType t) {
4707   r->t = t;
4708   bc_vec_pop(&p->results);
4709   bc_vec_push(&p->results, r);
4710 }
4711 
bc_program_op(BcProgram * p,uchar inst)4712 static BcStatus bc_program_op(BcProgram *p, uchar inst) {
4713 
4714   BcStatus s;
4715   BcResult *opd1, *opd2, res;
4716   BcNum *n1 = NULL, *n2 = NULL;
4717   size_t idx = inst - BC_INST_POWER;
4718 
4719   s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2);
4720   if (s) return s;
4721   bc_num_init(&res.d.n, bc_program_opReqs[idx](n1, n2, p->scale));
4722 
4723   s = bc_program_ops[idx](n1, n2, &res.d.n, p->scale);
4724   if (s) goto err;
4725   bc_program_binOpRetire(p, &res);
4726 
4727   return s;
4728 
4729 err:
4730   bc_num_free(&res.d.n);
4731   return s;
4732 }
4733 
bc_program_read(BcProgram * p)4734 static BcStatus bc_program_read(BcProgram *p) {
4735 
4736   BcStatus s;
4737   BcParse parse;
4738   BcVec buf;
4739   BcInstPtr ip;
4740   size_t i;
4741   char *file;
4742   BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
4743 
4744   for (i = 0; i < p->stack.len; ++i) {
4745     BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
4746     if (ip_ptr->func == BC_PROG_READ)
4747       return bc_vm_err(BC_ERROR_EXEC_REC_READ);
4748   }
4749 
4750   file = TT.file;
4751   bc_lex_file(&parse.l, bc_program_stdin_name);
4752   bc_vec_npop(&f->code, f->code.len);
4753   bc_vec_init(&buf, sizeof(char), NULL);
4754 
4755   s = bc_read_line(&buf, "read> ");
4756   if (s) {
4757     if (s == BC_STATUS_EOF) s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
4758     goto io_err;
4759   }
4760 
4761   bc_parse_init(&parse, p, BC_PROG_READ);
4762 
4763   s = bc_parse_text(&parse, buf.v);
4764   if (s) goto exec_err;
4765   s = bc_parse_expr_status(&parse, BC_PARSE_NOREAD, bc_parse_next_read);
4766   if (s) goto exec_err;
4767 
4768   if (parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF) {
4769     s = bc_vm_err(BC_ERROR_EXEC_READ_EXPR);
4770     goto exec_err;
4771   }
4772 
4773   ip.func = BC_PROG_READ;
4774   ip.idx = 0;
4775   ip.len = p->results.len;
4776 
4777   // Update this pointer, just in case.
4778   f = bc_vec_item(&p->fns, BC_PROG_READ);
4779 
4780   bc_vec_pushByte(&f->code, BC_INST_RET);
4781   bc_vec_push(&p->stack, &ip);
4782 
4783 exec_err:
4784   bc_parse_free(&parse);
4785 io_err:
4786   bc_vec_free(&buf);
4787   TT.file = file;
4788   return s;
4789 }
4790 
bc_program_printChars(char * str)4791 static void bc_program_printChars(char *str) {
4792   char *nl;
4793   TT.nchars += printf("%s", str);
4794   nl = strrchr(str, '\n');
4795   if (nl) TT.nchars = strlen(nl + 1);
4796 }
4797 
4798 // Output, substituting escape sequences, see also unescape() in lib/
bc_program_printString(char * str)4799 static void bc_program_printString(char *str)
4800 {
4801   int i, c, idx;
4802 
4803   for (i = 0; str[i]; ++i, ++TT.nchars) {
4804     if ((c = str[i]) == '\\' && str[i+1]) {
4805       if ((idx = stridx("ab\\efnqrt", c = str[i+1])) >= 0) {
4806         if (c == 'n') TT.nchars = SIZE_MAX;
4807         c = "\a\b\\\\\f\n\"\r\t"[idx];
4808       }
4809       else putchar('\\');
4810       i++;
4811     }
4812 
4813     putchar(c);
4814   }
4815 }
4816 
bc_program_print(BcProgram * p,uchar inst,size_t idx)4817 static BcStatus bc_program_print(BcProgram *p, uchar inst, size_t idx) {
4818 
4819   BcStatus s = BC_STATUS_SUCCESS;
4820   BcResult *r;
4821   char *str;
4822   BcNum *n = NULL;
4823   int pop = inst != BC_INST_PRINT;
4824 
4825   r = bc_vec_item_rev(&p->results, idx);
4826 
4827   if (r->t == BC_RESULT_VOID) {
4828     if (pop) return bc_vm_err(BC_ERROR_EXEC_VOID_VAL);
4829     return s;
4830   }
4831 
4832   s = bc_program_num(p, r, &n);
4833   if (s) return s;
4834 
4835   if (BC_PROG_NUM(r, n)) {
4836     bc_num_printNewline();
4837 
4838     if (!n->len) bc_num_printHex(0, 1, 0);
4839     else if (p->ob_t == 10) bc_num_printDecimal(n);
4840     else s = bc_num_printBase(n, &p->ob, p->ob_t);
4841 
4842     if (!s && !pop) {
4843       putchar('\n');
4844       TT.nchars = 0;
4845     }
4846     if (!s) bc_num_copy(&p->last, n);
4847   } else {
4848 
4849     size_t i = (r->t == BC_RESULT_STR) ? r->d.id.len : n->rdx;
4850 
4851     str = bc_program_str(p, i, 1);
4852 
4853     if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
4854     else {
4855       bc_program_printString(str);
4856       if (inst == BC_INST_PRINT) {
4857         putchar('\n');
4858         TT.nchars = 0;
4859       }
4860     }
4861   }
4862 
4863   if (!s && pop) bc_vec_pop(&p->results);
4864 
4865   return s;
4866 }
4867 
bc_program_negate(BcResult * r,BcNum * n)4868 void bc_program_negate(BcResult *r, BcNum *n) {
4869   BcNum *rn = &r->d.n;
4870   bc_num_copy(rn, n);
4871   if (rn->len) rn->neg = !rn->neg;
4872 }
4873 
bc_program_not(BcResult * r,BcNum * n)4874 void bc_program_not(BcResult *r, BcNum *n) {
4875   if (!BC_NUM_CMP_ZERO(n)) bc_num_one(&r->d.n);
4876 }
4877 
bc_program_unary(BcProgram * p,uchar inst)4878 static BcStatus bc_program_unary(BcProgram *p, uchar inst) {
4879 
4880   BcStatus s;
4881   BcResult res, *ptr;
4882   BcNum *num = NULL;
4883 
4884   s = bc_program_prep(p, &ptr, &num);
4885   if (s) return s;
4886 
4887   bc_num_init(&res.d.n, num->len);
4888   bc_program_unarys[inst - BC_INST_NEG](&res, num);
4889   bc_program_retire(p, &res, BC_RESULT_TEMP);
4890 
4891   return s;
4892 }
4893 
bc_program_logical(BcProgram * p,uchar inst)4894 static BcStatus bc_program_logical(BcProgram *p, uchar inst) {
4895 
4896   BcStatus s;
4897   BcResult *opd1, *opd2, res;
4898   BcNum *n1 = NULL, *n2 = NULL;
4899   int cond = 0;
4900   ssize_t cmp;
4901 
4902   s = bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2);
4903   if (s) return s;
4904   bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
4905 
4906   if (inst == BC_INST_BOOL_AND)
4907     cond = BC_NUM_CMP_ZERO(n1) && BC_NUM_CMP_ZERO(n2);
4908   else if (inst == BC_INST_BOOL_OR)
4909     cond = BC_NUM_CMP_ZERO(n1) || BC_NUM_CMP_ZERO(n2);
4910   else {
4911 
4912     cmp = bc_num_cmp(n1, n2);
4913 
4914     switch (inst) {
4915 
4916       case BC_INST_REL_EQ:
4917       {
4918         cond = cmp == 0;
4919         break;
4920       }
4921 
4922       case BC_INST_REL_LE:
4923       {
4924         cond = cmp <= 0;
4925         break;
4926       }
4927 
4928       case BC_INST_REL_GE:
4929       {
4930         cond = cmp >= 0;
4931         break;
4932       }
4933 
4934       case BC_INST_REL_NE:
4935       {
4936         cond = cmp != 0;
4937         break;
4938       }
4939 
4940       case BC_INST_REL_LT:
4941       {
4942         cond = cmp < 0;
4943         break;
4944       }
4945 
4946       case BC_INST_REL_GT:
4947       {
4948         cond = cmp > 0;
4949         break;
4950       }
4951     }
4952   }
4953 
4954   if (cond) bc_num_one(&res.d.n);
4955 
4956   bc_program_binOpRetire(p, &res);
4957 
4958   return s;
4959 }
4960 
bc_program_copyToVar(BcProgram * p,char * name,BcType t,int last)4961 static BcStatus bc_program_copyToVar(BcProgram *p, char *name,
4962                                      BcType t, int last)
4963 {
4964   BcStatus s = BC_STATUS_SUCCESS;
4965   BcResult *ptr, r;
4966   BcVec *vec;
4967   BcNum *n = NULL;
4968   int var = (t == BC_TYPE_VAR);
4969 
4970   if (!last) {
4971 
4972     ptr = bc_vec_top(&p->results);
4973 
4974     if (ptr->t == BC_RESULT_VAR || ptr->t == BC_RESULT_ARRAY) {
4975       BcVec *v = bc_program_search(p, ptr->d.id.str, t);
4976       n = bc_vec_item_rev(v, 1);
4977     }
4978     else s = bc_program_num(p, ptr, &n);
4979   }
4980   else s = bc_program_operand(p, &ptr, &n, 0);
4981 
4982   if (s) return s;
4983 
4984   s = bc_program_type_match(ptr, t);
4985   if (s) return s;
4986 
4987   vec = bc_program_search(p, name, t);
4988 
4989   // Do this once more to make sure that pointers were not invalidated.
4990   vec = bc_program_search(p, name, t);
4991 
4992   if (var) bc_num_createCopy(&r.d.n, n);
4993   else {
4994     bc_array_init(&r.d.v, 1);
4995     bc_array_copy(&r.d.v, (BcVec *)n);
4996   }
4997 
4998   bc_vec_push(vec, &r.d);
4999   bc_vec_pop(&p->results);
5000 
5001   return s;
5002 }
5003 
bc_program_assign(BcProgram * p,uchar inst)5004 static BcStatus bc_program_assign(BcProgram *p, uchar inst) {
5005 
5006   BcStatus s;
5007   BcResult *left, *right, res;
5008   BcNum *l = NULL, *r = NULL;
5009   int ib, sc;
5010 
5011   s = bc_program_assignPrep(p, &left, &l, &right, &r);
5012   if (s) return s;
5013 
5014   ib = (left->t == BC_RESULT_IBASE);
5015   sc = (left->t == BC_RESULT_SCALE);
5016 
5017   if (inst == BC_INST_ASSIGN) bc_num_copy(l, r);
5018   else {
5019     s = bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, p->scale);
5020     if (s) return s;
5021   }
5022 
5023   if (ib || sc || left->t == BC_RESULT_OBASE) {
5024 
5025     size_t *ptr;
5026     unsigned long val, max, min;
5027     BcError e;
5028 
5029     s = bc_num_ulong(l, &val);
5030     if (s) return s;
5031     e = left->t - BC_RESULT_IBASE + BC_ERROR_EXEC_IBASE;
5032 
5033     if (sc) {
5034       max = BC_MAX_SCALE;
5035       min = 0;
5036       ptr = &p->scale;
5037     }
5038     else {
5039       max = ib ? TT.max_ibase : BC_MAX_OBASE;
5040       min = 2;
5041       ptr = ib ? &p->ib_t : &p->ob_t;
5042     }
5043 
5044     if (val > max || val < min) return bc_vm_verr(e, min, max);
5045     if (!sc) bc_num_ulong2num(ib ? &p->ib : &p->ob, (unsigned long) val);
5046 
5047     *ptr = (size_t) val;
5048     s = BC_STATUS_SUCCESS;
5049   }
5050 
5051   bc_num_createCopy(&res.d.n, l);
5052   bc_program_binOpRetire(p, &res);
5053 
5054   return s;
5055 }
5056 
bc_program_pushVar(BcProgram * p,char * code,size_t * bgn)5057 static BcStatus bc_program_pushVar(BcProgram *p, char *code, size_t *bgn) {
5058 
5059   BcStatus s = BC_STATUS_SUCCESS;
5060   BcResult r;
5061   char *name = bc_program_name(code, bgn);
5062 
5063   r.t = BC_RESULT_VAR;
5064   r.d.id.str = name;
5065 
5066   bc_vec_push(&p->results, &r);
5067 
5068   return s;
5069 }
5070 
bc_program_pushArray(BcProgram * p,char * code,size_t * bgn,uchar inst)5071 static BcStatus bc_program_pushArray(BcProgram *p, char *code,
5072                                      size_t *bgn, uchar inst)
5073 {
5074   BcStatus s = BC_STATUS_SUCCESS;
5075   BcResult r;
5076   BcNum *num = NULL;
5077 
5078   r.d.id.str = bc_program_name(code, bgn);
5079 
5080   if (inst == BC_INST_ARRAY) {
5081     r.t = BC_RESULT_ARRAY;
5082     bc_vec_push(&p->results, &r);
5083   }
5084   else {
5085 
5086     BcResult *operand;
5087     unsigned long temp;
5088 
5089     s = bc_program_prep(p, &operand, &num);
5090     if (s) goto err;
5091     s = bc_num_ulong(num, &temp);
5092     if (s) goto err;
5093 
5094     if (temp > BC_MAX_DIM) {
5095       s = bc_vm_verr(BC_ERROR_EXEC_ARRAY_LEN, BC_MAX_DIM);
5096       goto err;
5097     }
5098 
5099     r.d.id.len = temp;
5100     bc_program_retire(p, &r, BC_RESULT_ARRAY_ELEM);
5101   }
5102 
5103 err:
5104   if (s) free(r.d.id.str);
5105   return s;
5106 }
5107 
bc_program_incdec(BcProgram * p,uchar inst)5108 static BcStatus bc_program_incdec(BcProgram *p, uchar inst) {
5109 
5110   BcStatus s;
5111   BcResult *ptr, res, copy;
5112   BcNum *num = NULL;
5113   uchar inst2;
5114 
5115   s = bc_program_prep(p, &ptr, &num);
5116   if (s) return s;
5117 
5118   if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5119     copy.t = BC_RESULT_TEMP;
5120     bc_num_createCopy(&copy.d.n, num);
5121   }
5122 
5123   res.t = BC_RESULT_ONE;
5124   inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
5125 
5126   bc_vec_push(&p->results, &res);
5127   bc_program_assign(p, inst2);
5128 
5129   if (inst == BC_INST_INC_POST || inst == BC_INST_DEC_POST) {
5130     bc_vec_pop(&p->results);
5131     bc_vec_push(&p->results, &copy);
5132   }
5133 
5134   return s;
5135 }
5136 
bc_program_call(BcProgram * p,char * code,size_t * idx)5137 static BcStatus bc_program_call(BcProgram *p, char *code,
5138                                 size_t *idx)
5139 {
5140   BcStatus s = BC_STATUS_SUCCESS;
5141   BcInstPtr ip;
5142   size_t i, nparams = bc_program_index(code, idx);
5143   BcFunc *f;
5144   BcVec *v;
5145   struct str_len *a;
5146   BcResultData param;
5147   BcResult *arg;
5148 
5149   ip.idx = 0;
5150   ip.func = bc_program_index(code, idx);
5151   f = bc_vec_item(&p->fns, ip.func);
5152 
5153   if (!f->code.len) return bc_vm_verr(BC_ERROR_EXEC_UNDEF_FUNC, f->name);
5154   if (nparams != f->nparams)
5155     return bc_vm_verr(BC_ERROR_EXEC_PARAMS, f->nparams, nparams);
5156   ip.len = p->results.len - nparams;
5157 
5158   for (i = 0; i < nparams; ++i) {
5159 
5160     size_t j;
5161     int last = 1;
5162 
5163     a = bc_vec_item(&f->autos, nparams - 1 - i);
5164     arg = bc_vec_top(&p->results);
5165 
5166     // If I have already pushed to a var, I need to make sure I
5167     // get the previous version, not the already pushed one.
5168     if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
5169       for (j = 0; j < i && last; ++j) {
5170         struct str_len *id = bc_vec_item(&f->autos, nparams - 1 - j);
5171         last = strcmp(arg->d.id.str, id->str) ||
5172                (!id->len) != (arg->t == BC_RESULT_VAR);
5173       }
5174     }
5175 
5176     s = bc_program_copyToVar(p, a->str, a->len, last);
5177     if (s) return s;
5178   }
5179 
5180   for (; i < f->autos.len; ++i) {
5181 
5182     a = bc_vec_item(&f->autos, i);
5183     v = bc_program_search(p, a->str, a->len);
5184 
5185     if (a->len == BC_TYPE_VAR) {
5186       bc_num_init(&param.n, BC_NUM_DEF_SIZE);
5187       bc_vec_push(v, &param.n);
5188     }
5189     else {
5190       bc_array_init(&param.v, 1);
5191       bc_vec_push(v, &param.v);
5192     }
5193   }
5194 
5195   bc_vec_push(&p->stack, &ip);
5196 
5197   return BC_STATUS_SUCCESS;
5198 }
5199 
bc_program_return(BcProgram * p,uchar inst)5200 static BcStatus bc_program_return(BcProgram *p, uchar inst) {
5201 
5202   BcStatus s;
5203   BcResult res;
5204   BcFunc *f;
5205   size_t i;
5206   BcInstPtr *ip = bc_vec_top(&p->stack);
5207 
5208   f = bc_vec_item(&p->fns, ip->func);
5209   res.t = BC_RESULT_TEMP;
5210 
5211   if (inst == BC_INST_RET) {
5212 
5213     BcNum *num = NULL;
5214     BcResult *operand;
5215 
5216     s = bc_program_operand(p, &operand, &num, 0);
5217     if (s) return s;
5218 
5219     bc_num_createCopy(&res.d.n, num);
5220   }
5221   else if (inst == BC_INST_RET_VOID) res.t = BC_RESULT_VOID;
5222   else bc_num_init(&res.d.n, BC_NUM_DEF_SIZE);
5223 
5224   // We need to pop arguments as well, so this takes that into account.
5225   for (i = 0; i < f->autos.len; ++i) {
5226 
5227     BcVec *v;
5228     struct str_len *a = bc_vec_item(&f->autos, i);
5229 
5230     v = bc_program_search(p, a->str, a->len);
5231     bc_vec_pop(v);
5232   }
5233 
5234   bc_vec_npop(&p->results, p->results.len - ip->len);
5235   bc_vec_push(&p->results, &res);
5236   bc_vec_pop(&p->stack);
5237 
5238   return BC_STATUS_SUCCESS;
5239 }
5240 
bc_program_scale(BcNum * n)5241 unsigned long bc_program_scale(BcNum *n) {
5242   return (unsigned long) n->rdx;
5243 }
5244 
bc_program_len(BcNum * n)5245 unsigned long bc_program_len(BcNum *n) {
5246 
5247   unsigned long len = n->len;
5248   size_t i;
5249 
5250   if (n->rdx != n->len) return len;
5251   for (i = n->len - 1; i < n->len && !n->num[i]; --len, --i);
5252 
5253   return len;
5254 }
5255 
bc_program_builtin(BcProgram * p,uchar inst)5256 static BcStatus bc_program_builtin(BcProgram *p, uchar inst) {
5257 
5258   BcStatus s;
5259   BcResult *opnd;
5260   BcResult res;
5261   BcNum *num = NULL, *resn = &res.d.n;
5262   int len = (inst == BC_INST_LENGTH);
5263 
5264   s = bc_program_operand(p, &opnd, &num, 0);
5265   if (s) return s;
5266 
5267   if (inst == BC_INST_SQRT) s = bc_num_sqrt(num, resn, p->scale);
5268   else if (inst == BC_INST_ABS) {
5269     bc_num_createCopy(resn, num);
5270     resn->neg = 0;
5271   }
5272   else {
5273 
5274     unsigned long val = 0;
5275 
5276     if (len) {
5277       if (opnd->t == BC_RESULT_ARRAY)
5278         val = (unsigned long) ((BcVec*) num)->len;
5279       else val = bc_program_len(num);
5280     }
5281     else val = bc_program_scale(num);
5282 
5283     bc_num_createFromUlong(resn, val);
5284   }
5285 
5286   bc_program_retire(p, &res, BC_RESULT_TEMP);
5287 
5288   return s;
5289 }
5290 
bc_program_pushGlobal(BcProgram * p,uchar inst)5291 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
5292 
5293   BcResult res;
5294   unsigned long val;
5295 
5296   res.t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
5297   if (inst == BC_INST_IBASE) val = (unsigned long) p->ib_t;
5298   else if (inst == BC_INST_SCALE) val = (unsigned long) p->scale;
5299   else val = (unsigned long) p->ob_t;
5300 
5301   bc_num_createFromUlong(&res.d.n, val);
5302   bc_vec_push(&p->results, &res);
5303 }
5304 
bc_program_free(BcProgram * p)5305 void bc_program_free(BcProgram *p) {
5306   bc_vec_free(&p->fns);
5307   bc_vec_free(&p->fn_map);
5308   bc_vec_free(&p->vars);
5309   bc_vec_free(&p->var_map);
5310   bc_vec_free(&p->arrs);
5311   bc_vec_free(&p->arr_map);
5312   bc_vec_free(&p->results);
5313   bc_vec_free(&p->stack);
5314   bc_num_free(&p->last);
5315 }
5316 
bc_program_init(BcProgram * p)5317 void bc_program_init(BcProgram *p) {
5318 
5319   BcInstPtr ip;
5320 
5321   memset(p, 0, sizeof(BcProgram));
5322   memset(&ip, 0, sizeof(BcInstPtr));
5323 
5324   bc_num_setup(&p->ib, p->ib_num, BC_NUM_LONG_LOG10);
5325   bc_num_ten(&p->ib);
5326   p->ib_t = 10;
5327 
5328   bc_num_setup(&p->ob, p->ob_num, BC_NUM_LONG_LOG10);
5329   bc_num_ten(&p->ob);
5330   p->ob_t = 10;
5331 
5332   bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
5333   bc_num_one(&p->one);
5334   bc_num_init(&p->last, BC_NUM_DEF_SIZE);
5335 
5336   bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
5337   bc_vec_init(&p->fn_map, sizeof(struct str_len), bc_id_free);
5338   bc_program_insertFunc(p, xstrdup(bc_func_main));
5339   bc_program_insertFunc(p, xstrdup(bc_func_read));
5340 
5341   bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
5342   bc_vec_init(&p->var_map, sizeof(struct str_len), bc_id_free);
5343 
5344   bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
5345   bc_vec_init(&p->arr_map, sizeof(struct str_len), bc_id_free);
5346 
5347   bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
5348   bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
5349   bc_vec_push(&p->stack, &ip);
5350 }
5351 
bc_program_addFunc(BcProgram * p,BcFunc * f,char * name)5352 void bc_program_addFunc(BcProgram *p, BcFunc *f, char *name) {
5353   bc_func_init(f, name);
5354   bc_vec_push(&p->fns, f);
5355 }
5356 
bc_program_insertFunc(BcProgram * p,char * name)5357 size_t bc_program_insertFunc(BcProgram *p, char *name) {
5358 
5359   struct str_len id;
5360   BcFunc f;
5361   int new;
5362   size_t idx;
5363 
5364   id.str = name;
5365   id.len = p->fns.len;
5366 
5367   new = bc_map_insert(&p->fn_map, &id, &idx);
5368   idx = ((struct ptr_len *)bc_vec_item(&p->fn_map, idx))->len;
5369 
5370   if (!new) {
5371     BcFunc *func = bc_vec_item(&p->fns, idx);
5372     bc_func_reset(func);
5373     free(name);
5374   } else bc_program_addFunc(p, &f, name);
5375 
5376   return idx;
5377 }
5378 
bc_program_reset(BcProgram * p,BcStatus s)5379 BcStatus bc_program_reset(BcProgram *p, BcStatus s) {
5380 
5381   BcFunc *f;
5382   BcInstPtr *ip;
5383 
5384   bc_vec_npop(&p->stack, p->stack.len - 1);
5385   bc_vec_npop(&p->results, p->results.len);
5386 
5387   f = bc_vec_item(&p->fns, 0);
5388   ip = bc_vec_top(&p->stack);
5389   ip->idx = f->code.len;
5390 
5391   if (TT.sig == SIGTERM || TT.sig == SIGQUIT ||
5392       (!s && TT.sig == SIGINT && FLAG(i))) return BC_STATUS_QUIT;
5393   TT.sig = 0;
5394 
5395   if (!s || s == BC_STATUS_SIGNAL) {
5396     if (BC_TTYIN) {
5397       fputs(bc_program_ready_msg, stderr);
5398       fflush(stderr);
5399       s = BC_STATUS_SUCCESS;
5400     }
5401     else s = BC_STATUS_QUIT;
5402   }
5403 
5404   return s;
5405 }
5406 
bc_program_exec(BcProgram * p)5407 BcStatus bc_program_exec(BcProgram *p) {
5408 
5409   BcStatus s = BC_STATUS_SUCCESS;
5410   size_t idx;
5411   BcResult r, *ptr;
5412   BcInstPtr *ip = bc_vec_top(&p->stack);
5413   BcFunc *func = bc_vec_item(&p->fns, ip->func);
5414   char *code = func->code.v;
5415   int cond = 0;
5416   BcNum *num;
5417 
5418   while (!s && ip->idx < func->code.len) {
5419 
5420     uchar inst = (uchar) code[(ip->idx)++];
5421 
5422     switch (inst) {
5423 
5424       case BC_INST_JUMP_ZERO:
5425       {
5426         s = bc_program_prep(p, &ptr, &num);
5427         if (s) return s;
5428         cond = !BC_NUM_CMP_ZERO(num);
5429         bc_vec_pop(&p->results);
5430       }
5431       // Fallthrough.
5432       case BC_INST_JUMP:
5433       {
5434         size_t *addr;
5435         idx = bc_program_index(code, &ip->idx);
5436         addr = bc_vec_item(&func->labels, idx);
5437         if (inst == BC_INST_JUMP || cond) ip->idx = *addr;
5438         break;
5439       }
5440 
5441       case BC_INST_CALL:
5442       {
5443         s = bc_program_call(p, code, &ip->idx);
5444         break;
5445       }
5446 
5447       case BC_INST_INC_PRE:
5448       case BC_INST_DEC_PRE:
5449       case BC_INST_INC_POST:
5450       case BC_INST_DEC_POST:
5451       {
5452         s = bc_program_incdec(p, inst);
5453         break;
5454       }
5455 
5456       case BC_INST_HALT:
5457       {
5458         s = BC_STATUS_QUIT;
5459         break;
5460       }
5461 
5462       case BC_INST_RET:
5463       case BC_INST_RET0:
5464       case BC_INST_RET_VOID:
5465       {
5466         s = bc_program_return(p, inst);
5467         break;
5468       }
5469 
5470       case BC_INST_LAST:
5471       {
5472         r.t = BC_RESULT_LAST;
5473         bc_vec_push(&p->results, &r);
5474         break;
5475       }
5476 
5477       case BC_INST_BOOL_OR:
5478       case BC_INST_BOOL_AND:
5479       case BC_INST_REL_EQ:
5480       case BC_INST_REL_LE:
5481       case BC_INST_REL_GE:
5482       case BC_INST_REL_NE:
5483       case BC_INST_REL_LT:
5484       case BC_INST_REL_GT:
5485       {
5486         s = bc_program_logical(p, inst);
5487         break;
5488       }
5489 
5490       case BC_INST_READ:
5491       {
5492         s = bc_program_read(p);
5493         break;
5494       }
5495 
5496       case BC_INST_VAR:
5497       {
5498         s = bc_program_pushVar(p, code, &ip->idx);
5499         break;
5500       }
5501 
5502       case BC_INST_ARRAY_ELEM:
5503       case BC_INST_ARRAY:
5504       {
5505         s = bc_program_pushArray(p, code, &ip->idx, inst);
5506         break;
5507       }
5508 
5509       case BC_INST_IBASE:
5510       case BC_INST_SCALE:
5511       case BC_INST_OBASE:
5512       {
5513         bc_program_pushGlobal(p, inst);
5514         break;
5515       }
5516 
5517       case BC_INST_LENGTH:
5518       case BC_INST_SCALE_FUNC:
5519       case BC_INST_SQRT:
5520       case BC_INST_ABS:
5521       {
5522         s = bc_program_builtin(p, inst);
5523         break;
5524       }
5525 
5526       case BC_INST_NUM:
5527       {
5528         r.t = BC_RESULT_CONSTANT;
5529         r.d.id.len = bc_program_index(code, &ip->idx);
5530         bc_vec_push(&p->results, &r);
5531         break;
5532       }
5533 
5534       case BC_INST_POP:
5535       {
5536         bc_vec_pop(&p->results);
5537         break;
5538       }
5539 
5540       case BC_INST_PRINT:
5541       case BC_INST_PRINT_POP:
5542       case BC_INST_PRINT_STR:
5543       {
5544         s = bc_program_print(p, inst, 0);
5545         break;
5546       }
5547 
5548       case BC_INST_STR:
5549       {
5550         r.t = BC_RESULT_STR;
5551         r.d.id.len = bc_program_index(code, &ip->idx);
5552         bc_vec_push(&p->results, &r);
5553         break;
5554       }
5555 
5556       case BC_INST_POWER:
5557       case BC_INST_MULTIPLY:
5558       case BC_INST_DIVIDE:
5559       case BC_INST_MODULUS:
5560       case BC_INST_PLUS:
5561       case BC_INST_MINUS:
5562       {
5563         s = bc_program_op(p, inst);
5564         break;
5565       }
5566 
5567       case BC_INST_NEG:
5568       case BC_INST_BOOL_NOT:
5569       {
5570         s = bc_program_unary(p, inst);
5571         break;
5572       }
5573 
5574       case BC_INST_ASSIGN_POWER:
5575       case BC_INST_ASSIGN_MULTIPLY:
5576       case BC_INST_ASSIGN_DIVIDE:
5577       case BC_INST_ASSIGN_MODULUS:
5578       case BC_INST_ASSIGN_PLUS:
5579       case BC_INST_ASSIGN_MINUS:
5580       case BC_INST_ASSIGN:
5581       {
5582         s = bc_program_assign(p, inst);
5583         break;
5584       }
5585     }
5586 
5587     if ((s && s != BC_STATUS_QUIT) || TT.sig) s = bc_program_reset(p, s);
5588 
5589     // If the stack has changed, pointers may be invalid.
5590     ip = bc_vec_top(&p->stack);
5591     func = bc_vec_item(&p->fns, ip->func);
5592     code = func->code.v;
5593   }
5594 
5595   return s;
5596 }
5597 
bc_vm_sig(int sig)5598 static void bc_vm_sig(int sig) {
5599   int err = errno;
5600 
5601   // If you run bc 2>/dev/full ctrl-C is ignored. Why? No idea.
5602   if (sig == SIGINT) {
5603     size_t len = strlen(bc_sig_msg);
5604     if (write(2, bc_sig_msg, len) != len) sig = 0;
5605   }
5606   TT.sig = sig;
5607   errno = err;
5608 }
5609 
bc_vm_info(void)5610 void bc_vm_info(void) {
5611   printf("%s %s\n", toys.which->name, "1.1.0");
5612   fputs(bc_copyright, stdout);
5613 }
5614 
bc_vm_printError(BcError e,char * fmt,size_t line,va_list args)5615 static void bc_vm_printError(BcError e, char *fmt,
5616                              size_t line, va_list args)
5617 {
5618   // Make sure all of stdout is written first.
5619   fflush(stdout);
5620 
5621   fprintf(stderr, fmt, bc_errs[(size_t) bc_err_ids[e]]);
5622   vfprintf(stderr, bc_err_msgs[e], args);
5623 
5624   // This is the condition for parsing vs runtime.
5625   // If line is not 0, it is parsing.
5626   if (line) {
5627     fprintf(stderr, "\n    %s", TT.file);
5628     fprintf(stderr, bc_err_line, line);
5629   }
5630   else {
5631     BcInstPtr *ip = bc_vec_item_rev(&BC_VM->prog.stack, 0);
5632     BcFunc *f = bc_vec_item(&BC_VM->prog.fns, ip->func);
5633     fprintf(stderr, "\n    Function: %s", f->name);
5634   }
5635 
5636   fputs("\n\n", stderr);
5637   fflush(stderr);
5638 }
5639 
bc_vm_error(BcError e,size_t line,...)5640 BcStatus bc_vm_error(BcError e, size_t line, ...) {
5641 
5642   va_list args;
5643 
5644   va_start(args, line);
5645   bc_vm_printError(e, bc_err_fmt, line, args);
5646   va_end(args);
5647 
5648   return BC_STATUS_ERROR;
5649 }
5650 
bc_vm_posixError(BcError e,size_t line,...)5651 BcStatus bc_vm_posixError(BcError e, size_t line, ...) {
5652 
5653   va_list args;
5654 
5655   if (!(FLAG(s) || FLAG(w))) return BC_STATUS_SUCCESS;
5656 
5657   va_start(args, line);
5658   bc_vm_printError(e, FLAG(s) ? bc_err_fmt : bc_warn_fmt, line, args);
5659   va_end(args);
5660 
5661   return FLAG(s) ? BC_STATUS_ERROR : BC_STATUS_SUCCESS;
5662 }
5663 
bc_vm_clean()5664 static void bc_vm_clean()
5665 {
5666   BcProgram *prog = &BC_VM->prog;
5667   BcFunc *f = bc_vec_item(&prog->fns, BC_PROG_MAIN);
5668   BcInstPtr *ip = bc_vec_item(&prog->stack, 0);
5669 
5670   // If this condition is 1, we can get rid of strings,
5671   // constants, and code. This is an idea from busybox.
5672   if (!BC_PARSE_NO_EXEC(&BC_VM->prs) && prog->stack.len == 1 &&
5673       !prog->results.len && ip->idx == f->code.len)
5674   {
5675     bc_vec_npop(&f->labels, f->labels.len);
5676     bc_vec_npop(&f->strs, f->strs.len);
5677     bc_vec_npop(&f->consts, f->consts.len);
5678     bc_vec_npop(&f->code, f->code.len);
5679     ip->idx = 0;
5680   }
5681 }
5682 
bc_vm_process(char * text,int is_stdin)5683 static BcStatus bc_vm_process(char *text, int is_stdin) {
5684 
5685   BcStatus s;
5686   uint16_t *flags;
5687 
5688   s = bc_parse_text(&BC_VM->prs, text);
5689   if (s) goto err;
5690 
5691   while (BC_VM->prs.l.t != BC_LEX_EOF) {
5692     s = bc_parse_parse(&BC_VM->prs);
5693     if (s) goto err;
5694   }
5695 
5696   flags = BC_PARSE_TOP_FLAG_PTR(&BC_VM->prs);
5697 
5698   if (!is_stdin && BC_VM->prs.flags.len == 1 && *flags == BC_PARSE_FLAG_IF_END)
5699     bc_parse_noElse(&BC_VM->prs);
5700 
5701   if (BC_PARSE_NO_EXEC(&BC_VM->prs)) goto err;
5702 
5703   s = bc_program_exec(&BC_VM->prog);
5704   if (FLAG(i)) fflush(stdout);
5705 
5706 err:
5707   if (s || TT.sig) s = bc_program_reset(&BC_VM->prog, s);
5708   bc_vm_clean();
5709   return s == BC_STATUS_QUIT || !FLAG(i) || !is_stdin ? s : BC_STATUS_SUCCESS;
5710 }
5711 
bc_vm_file(char * file)5712 static BcStatus bc_vm_file(char *file) {
5713 
5714   BcStatus s;
5715   char *data;
5716 
5717   bc_lex_file(&BC_VM->prs.l, file);
5718   s = bc_read_file(file, &data);
5719   if (s) return s;
5720 
5721   s = bc_vm_process(data, 0);
5722   if (s) goto err;
5723 
5724   if (BC_PARSE_NO_EXEC(&BC_VM->prs))
5725     s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK);
5726 
5727 err:
5728   free(data);
5729   return s;
5730 }
5731 
bc_vm_stdin(void)5732 static BcStatus bc_vm_stdin(void) {
5733 
5734   BcStatus s = BC_STATUS_SUCCESS;
5735   BcVec buf, buffer;
5736   size_t string = 0;
5737   int comment = 0, done = 0;
5738 
5739   bc_lex_file(&BC_VM->prs.l, bc_program_stdin_name);
5740 
5741   bc_vec_init(&buffer, sizeof(uchar), NULL);
5742   bc_vec_init(&buf, sizeof(uchar), NULL);
5743   bc_vec_pushByte(&buffer, '\0');
5744 
5745   // This loop is complex because the vm tries not to send any lines that end
5746   // with a backslash to the parser, which
5747   // treats a backslash+newline combo as whitespace per the bc spec. In that
5748   // case, and for strings and comments, the parser will expect more stuff.
5749   while (!done && (s = bc_read_line(&buf, ">>> ")) != BC_STATUS_ERROR &&
5750          buf.len > 1 && !TT.sig && s != BC_STATUS_SIGNAL)
5751   {
5752     char c2, *str = buf.v;
5753     size_t i, len = buf.len - 1;
5754 
5755     done = (s == BC_STATUS_EOF);
5756 
5757     if (len >= 2 && str[len - 1] == '\n' && str[len - 2] == '\\') {
5758       bc_vec_concat(&buffer, buf.v);
5759       continue;
5760     }
5761 
5762     for (i = 0; i < len; ++i) {
5763 
5764       int notend = len > i + 1;
5765       uchar c = (uchar) str[i];
5766 
5767       if (!comment && (i - 1 > len || str[i - 1] != '\\')) string ^= c == '"';
5768 
5769       if (!string && notend) {
5770 
5771         c2 = str[i + 1];
5772 
5773         if (c == '/' && !comment && c2 == '*') {
5774           comment = 1;
5775           ++i;
5776         }
5777         else if (c == '*' && comment && c2 == '/') {
5778           comment = 0;
5779           ++i;
5780         }
5781       }
5782     }
5783 
5784     bc_vec_concat(&buffer, buf.v);
5785 
5786     if (string || comment) continue;
5787     if (len >= 2 && str[len - 2] == '\\' && str[len - 1] == '\n') continue;
5788 
5789     s = bc_vm_process(buffer.v, 1);
5790     if (s) goto err;
5791 
5792     bc_vec_empty(&buffer);
5793   }
5794 
5795   if (s && s != BC_STATUS_EOF) goto err;
5796   else if (TT.sig && !s) s = BC_STATUS_SIGNAL;
5797   else if (s != BC_STATUS_ERROR) {
5798     if (comment) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_COMMENT);
5799     else if (string) s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_STRING);
5800     else if (BC_PARSE_NO_EXEC(&BC_VM->prs))
5801       s = bc_parse_err(&BC_VM->prs, BC_ERROR_PARSE_BLOCK);
5802   }
5803 
5804 err:
5805   bc_vec_free(&buf);
5806   bc_vec_free(&buffer);
5807   return s;
5808 }
5809 
bc_main(void)5810 void bc_main(void)
5811 {
5812   BcStatus s = 0;
5813   char *ss;
5814 
5815   struct sigaction sa;
5816 
5817   sigemptyset(&sa.sa_mask);
5818   sa.sa_handler = bc_vm_sig;
5819   sa.sa_flags = 0;
5820   sigaction(SIGINT, &sa, NULL);
5821   sigaction(SIGTERM, &sa, NULL);
5822   sigaction(SIGQUIT, &sa, NULL);
5823 
5824   TT.line_len = 69;
5825   ss = getenv("BC_LINE_LENGTH");
5826   if (ss) {
5827     int len = atoi(ss);
5828     if (len>=2 && len <= UINT16_MAX) TT.line_len = len;
5829   }
5830 
5831   TT.vm = xzalloc(sizeof(BcVm));
5832   bc_program_init(&BC_VM->prog);
5833   bc_parse_init(&BC_VM->prs, &BC_VM->prog, BC_PROG_MAIN);
5834 
5835   if (getenv("POSIXLY_CORRECT")) toys.optflags |= FLAG_s;
5836   toys.optflags |= isatty(0) ? BC_FLAG_TTYIN : 0;
5837   toys.optflags |= BC_TTYIN && isatty(1) ? FLAG_i : 0;
5838 
5839   TT.max_ibase = !FLAG(s) && !FLAG(w) ? 16 : 36;
5840 
5841   if (FLAG(i) && !(toys.optflags & FLAG_q)) bc_vm_info();
5842 
5843   // load -l library (if any)
5844   if (FLAG(l)) {
5845     bc_lex_file(&BC_VM->prs.l, bc_lib_name);
5846     s = bc_parse_text(&BC_VM->prs, bc_lib);
5847 
5848     while (!s && BC_VM->prs.l.t != BC_LEX_EOF) s = bc_parse_parse(&BC_VM->prs);
5849   }
5850 
5851   // parse command line argument files, then stdin
5852   if (!s) {
5853     int i;
5854 
5855     for (i = 0; !s && i < toys.optc; ++i) s = bc_vm_file(toys.optargs[i]);
5856     if (!s) s = bc_vm_stdin();
5857   }
5858 
5859   if (CFG_TOYBOX_FREE) {
5860     bc_program_free(&BC_VM->prog);
5861     bc_parse_free(&BC_VM->prs);
5862     free(TT.vm);
5863   }
5864 
5865   toys.exitval = s == BC_STATUS_ERROR;
5866 }
5867