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