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