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