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