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