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