1 /*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 *
30 * *****************************************************************************
31 *
32 * Code to execute bc programs.
33 *
34 */
35
36 #include <assert.h>
37 #include <stdbool.h>
38 #include <string.h>
39
40 #include <setjmp.h>
41
42 #include <signal.h>
43
44 #include <time.h>
45
46 #include <read.h>
47 #include <parse.h>
48 #include <program.h>
49 #include <vm.h>
50
51 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr);
52
bc_program_setVecs(BcProgram * p,BcFunc * f)53 static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
54 p->consts = &f->consts;
55 if (BC_IS_BC) p->strs = &f->strs;
56 }
57
bc_program_type_num(BcResult * r,BcNum * n)58 static inline void bc_program_type_num(BcResult *r, BcNum *n) {
59
60 #if BC_ENABLED
61 assert(r->t != BC_RESULT_VOID);
62 #endif // BC_ENABLED
63
64 if (BC_ERR(!BC_PROG_NUM(r, n))) bc_vm_err(BC_ERR_EXEC_TYPE);
65 }
66
67 #if BC_ENABLED
bc_program_type_match(BcResult * r,BcType t)68 static void bc_program_type_match(BcResult *r, BcType t) {
69
70 #if DC_ENABLED
71 assert(BC_IS_DC || BC_NO_ERR(r->t != BC_RESULT_STR));
72 #endif // DC_ENABLED
73
74 if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t)))
75 bc_vm_err(BC_ERR_EXEC_TYPE);
76 }
77 #endif // BC_ENABLED
78
bc_program_index(const char * restrict code,size_t * restrict bgn)79 static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
80 {
81 uchar amt = (uchar) code[(*bgn)++], i = 0;
82 size_t res = 0;
83
84 for (; i < amt; ++i, ++(*bgn)) {
85 size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
86 res |= (temp << (i * CHAR_BIT));
87 }
88
89 return res;
90 }
91
92 #if BC_ENABLED
bc_program_prepGlobals(BcProgram * p)93 static void bc_program_prepGlobals(BcProgram *p) {
94
95 size_t i;
96
97 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
98 bc_vec_push(p->globals_v + i, p->globals + i);
99
100 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
101 bc_rand_push(&p->rng);
102 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
103 }
104
bc_program_popGlobals(BcProgram * p,bool reset)105 static void bc_program_popGlobals(BcProgram *p, bool reset) {
106
107 size_t i;
108
109 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
110 BcVec *v = p->globals_v + i;
111 bc_vec_npop(v, reset ? v->len - 1 : 1);
112 p->globals[i] = BC_PROG_GLOBAL(v);
113 }
114
115 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
116 bc_rand_pop(&p->rng, reset);
117 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
118 }
119 #endif // BC_ENABLED
120
bc_program_pushBigdig(BcProgram * p,BcBigDig dig,BcResultType type)121 static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
122 {
123 BcResult res;
124
125 res.t = type;
126
127 BC_SIG_LOCK;
128
129 bc_num_createFromBigdig(&res.d.n, dig);
130 bc_vec_push(&p->results, &res);
131
132 BC_SIG_UNLOCK;
133 }
134
135 #if BC_ENABLED
bc_program_dereference(const BcProgram * p,BcVec * vec)136 static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
137
138 BcVec *v;
139 size_t vidx, nidx, i = 0;
140
141 assert(vec->size == sizeof(uchar));
142
143 vidx = bc_program_index(vec->v, &i);
144 nidx = bc_program_index(vec->v, &i);
145
146 v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
147
148 assert(v->size != sizeof(uchar));
149
150 return v;
151 }
152 #endif // BC_ENABLED
153
bc_program_search(BcProgram * p,const char * id,bool var)154 size_t bc_program_search(BcProgram *p, const char *id, bool var) {
155
156 BcVec *v, *map;
157 size_t i;
158 BcResultData data;
159
160 v = var ? &p->vars : &p->arrs;
161 map = var ? &p->var_map : &p->arr_map;
162
163 BC_SIG_LOCK;
164
165 if (bc_map_insert(map, id, v->len, &i)) {
166 bc_array_init(&data.v, var);
167 bc_vec_push(v, &data.v);
168 }
169
170 BC_SIG_UNLOCK;
171
172 return ((BcId*) bc_vec_item(map, i))->idx;
173 }
174
bc_program_vec(const BcProgram * p,size_t idx,BcType type)175 static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
176 {
177 const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
178 return bc_vec_item(v, idx);
179 }
180
bc_program_num(BcProgram * p,BcResult * r)181 static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
182
183 BcNum *n;
184
185 switch (r->t) {
186
187 case BC_RESULT_STR:
188 case BC_RESULT_TEMP:
189 case BC_RESULT_IBASE:
190 case BC_RESULT_SCALE:
191 case BC_RESULT_OBASE:
192 #if BC_ENABLE_EXTRA_MATH
193 case BC_RESULT_SEED:
194 #endif // BC_ENABLE_EXTRA_MATH
195 {
196 n = &r->d.n;
197 break;
198 }
199
200 case BC_RESULT_VAR:
201 #if BC_ENABLED
202 case BC_RESULT_ARRAY:
203 #endif // BC_ENABLED
204 case BC_RESULT_ARRAY_ELEM:
205 {
206 BcVec *v;
207 BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
208
209 v = bc_program_vec(p, r->d.loc.loc, type);
210
211 if (r->t == BC_RESULT_ARRAY_ELEM) {
212
213 size_t idx = r->d.loc.idx;
214
215 v = bc_vec_top(v);
216
217 #if BC_ENABLED
218 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
219 #endif // BC_ENABLED
220
221 assert(v->size == sizeof(BcNum));
222
223 if (v->len <= idx) {
224 BC_SIG_LOCK;
225 bc_array_expand(v, bc_vm_growSize(idx, 1));
226 BC_SIG_UNLOCK;
227 }
228
229 n = bc_vec_item(v, idx);
230 }
231 else n = bc_vec_top(v);
232
233 break;
234 }
235
236 case BC_RESULT_ZERO:
237 {
238 n = &p->zero;
239 break;
240 }
241
242 case BC_RESULT_ONE:
243 {
244 n = &p->one;
245 break;
246 }
247
248 #if BC_ENABLED
249 case BC_RESULT_VOID:
250 #ifndef NDEBUG
251 {
252 abort();
253 }
254 #endif // NDEBUG
255 // Fallthrough
256 case BC_RESULT_LAST:
257 {
258 n = &p->last;
259 break;
260 }
261 #endif // BC_ENABLED
262 }
263
264 return n;
265 }
266
bc_program_operand(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)267 static void bc_program_operand(BcProgram *p, BcResult **r,
268 BcNum **n, size_t idx)
269 {
270 *r = bc_vec_item_rev(&p->results, idx);
271
272 #if BC_ENABLED
273 if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
274 #endif // BC_ENABLED
275
276 *n = bc_program_num(p, *r);
277 }
278
bc_program_binPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)279 static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
280 BcResult **r, BcNum **rn, size_t idx)
281 {
282 BcResultType lt;
283
284 assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
285
286 #ifndef BC_PROG_NO_STACK_CHECK
287 if (BC_IS_DC) {
288 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
289 bc_vm_err(BC_ERR_EXEC_STACK);
290 }
291 #endif // BC_PROG_NO_STACK_CHECK
292
293 assert(BC_PROG_STACK(&p->results, idx + 2));
294
295 bc_program_operand(p, l, ln, idx + 1);
296 bc_program_operand(p, r, rn, idx);
297
298 lt = (*l)->t;
299
300 #if BC_ENABLED
301 assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
302 #endif // BC_ENABLED
303
304 // We run this again under these conditions in case any vector has been
305 // reallocated out from under the BcNums or arrays we had.
306 if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
307 *ln = bc_program_num(p, *l);
308
309 if (BC_ERR(lt == BC_RESULT_STR)) bc_vm_err(BC_ERR_EXEC_TYPE);
310 }
311
bc_program_binOpPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)312 static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
313 BcResult **r, BcNum **rn, size_t idx)
314 {
315 bc_program_binPrep(p, l, ln, r, rn, idx);
316 bc_program_type_num(*l, *ln);
317 bc_program_type_num(*r, *rn);
318 }
319
bc_program_assignPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)320 static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
321 BcResult **r, BcNum **rn)
322 {
323 BcResultType lt, min;
324
325 min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
326
327 bc_program_binPrep(p, l, ln, r, rn, 0);
328
329 lt = (*l)->t;
330
331 if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE))
332 bc_vm_err(BC_ERR_EXEC_TYPE);
333
334 #if DC_ENABLED
335 if(BC_IS_DC) {
336
337 bool good = (((*r)->t == BC_RESULT_STR || BC_PROG_STR(*rn)) &&
338 lt <= BC_RESULT_ARRAY_ELEM);
339
340 if (!good) bc_program_type_num(*r, *rn);
341 }
342 #else
343 assert((*r)->t != BC_RESULT_STR);
344 #endif // DC_ENABLED
345 }
346
bc_program_prep(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)347 static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
348
349 assert(p != NULL && r != NULL && n != NULL);
350
351 #ifndef BC_PROG_NO_STACK_CHECK
352 if (BC_IS_DC) {
353 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
354 bc_vm_err(BC_ERR_EXEC_STACK);
355 }
356 #endif // BC_PROG_NO_STACK_CHECK
357
358 assert(BC_PROG_STACK(&p->results, idx + 1));
359
360 bc_program_operand(p, r, n, idx);
361
362 #if DC_ENABLED
363 assert((*r)->t != BC_RESULT_VAR || !BC_PROG_STR(*n));
364 #endif // DC_ENABLED
365
366 bc_program_type_num(*r, *n);
367 }
368
bc_program_prepResult(BcProgram * p)369 static BcResult* bc_program_prepResult(BcProgram *p) {
370
371 BcResult res;
372
373 bc_result_clear(&res);
374 bc_vec_push(&p->results, &res);
375
376 return bc_vec_top(&p->results);
377 }
378
bc_program_const(BcProgram * p,const char * code,size_t * bgn)379 static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
380
381 BcResult *r = bc_program_prepResult(p);
382 BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
383 BcBigDig base = BC_PROG_IBASE(p);
384
385 if (c->base != base) {
386
387 if (c->num.num == NULL) {
388 BC_SIG_LOCK;
389 bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
390 BC_SIG_UNLOCK;
391 }
392
393 // bc_num_parse() should only do operations that cannot fail.
394 bc_num_parse(&c->num, c->val, base);
395
396 c->base = base;
397 }
398
399 BC_SIG_LOCK;
400
401 bc_num_createCopy(&r->d.n, &c->num);
402
403 BC_SIG_UNLOCK;
404 }
405
bc_program_op(BcProgram * p,uchar inst)406 static void bc_program_op(BcProgram *p, uchar inst) {
407
408 BcResult *opd1, *opd2, *res;
409 BcNum *n1, *n2;
410 size_t idx = inst - BC_INST_POWER;
411
412 res = bc_program_prepResult(p);
413
414 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
415
416 BC_SIG_LOCK;
417
418 bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
419
420 BC_SIG_UNLOCK;
421
422 assert(BC_NUM_RDX_VALID(n1));
423 assert(BC_NUM_RDX_VALID(n2));
424
425 bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
426
427 bc_program_retire(p, 1, 2);
428 }
429
bc_program_read(BcProgram * p)430 static void bc_program_read(BcProgram *p) {
431
432 BcStatus s;
433 BcParse parse;
434 BcVec buf;
435 BcInstPtr ip;
436 size_t i;
437 const char* file;
438 BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
439
440 for (i = 0; i < p->stack.len; ++i) {
441 BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
442 if (ip_ptr->func == BC_PROG_READ)
443 bc_vm_err(BC_ERR_EXEC_REC_READ);
444 }
445
446 BC_SIG_LOCK;
447
448 file = vm.file;
449 bc_parse_init(&parse, p, BC_PROG_READ);
450 bc_vec_init(&buf, sizeof(char), NULL);
451
452 BC_SETJMP_LOCKED(exec_err);
453
454 BC_SIG_UNLOCK;
455
456 bc_lex_file(&parse.l, bc_program_stdin_name);
457 bc_vec_popAll(&f->code);
458
459 if (BC_R) s = bc_read_line(&buf, "");
460 else s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> ");
461
462 if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR);
463
464 bc_parse_text(&parse, buf.v);
465 vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
466
467 if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF))
468 bc_vm_err(BC_ERR_EXEC_READ_EXPR);
469
470 #if BC_ENABLED
471 if (BC_G) bc_program_prepGlobals(p);
472 #endif // BC_ENABLED
473
474 ip.func = BC_PROG_READ;
475 ip.idx = 0;
476 ip.len = p->results.len;
477
478 // Update this pointer, just in case.
479 f = bc_vec_item(&p->fns, BC_PROG_READ);
480
481 bc_vec_pushByte(&f->code, vm.read_ret);
482 bc_vec_push(&p->stack, &ip);
483
484 #if DC_ENABLED
485 if (BC_IS_DC) {
486 size_t temp = 0;
487 bc_vec_push(&p->tail_calls, &temp);
488 }
489 #endif // DC_ENABLED
490
491 exec_err:
492 BC_SIG_MAYLOCK;
493 bc_parse_free(&parse);
494 bc_vec_free(&buf);
495 vm.file = file;
496 BC_LONGJMP_CONT;
497 }
498
499 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
bc_program_rand(BcProgram * p)500 static void bc_program_rand(BcProgram *p) {
501 BcRand rand = bc_rand_int(&p->rng);
502 bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
503 #ifndef NDEBUG
504 {
505 BcResult *r = bc_vec_top(&p->results);
506 assert(BC_NUM_RDX_VALID_NP(r->d.n));
507 }
508 #endif // NDEBUG
509 }
510 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
511
bc_program_printChars(const char * str)512 static void bc_program_printChars(const char *str) {
513
514 const char *nl;
515 size_t len = vm.nchars + strlen(str);
516
517 bc_file_puts(&vm.fout, bc_flush_save, str);
518 nl = strrchr(str, '\n');
519
520 if (nl != NULL) len = strlen(nl + 1);
521
522 vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
523 }
524
bc_program_printString(const char * restrict str)525 static void bc_program_printString(const char *restrict str) {
526
527 size_t i, len = strlen(str);
528
529 #if DC_ENABLED
530 if (!len && BC_IS_DC) {
531 bc_vm_putchar('\0', bc_flush_save);
532 return;
533 }
534 #endif // DC_ENABLED
535
536 for (i = 0; i < len; ++i) {
537
538 int c = str[i];
539
540 if (c == '\\' && i != len - 1) {
541
542 const char *ptr;
543
544 c = str[++i];
545 ptr = strchr(bc_program_esc_chars, c);
546
547 if (ptr != NULL) {
548 if (c == 'n') vm.nchars = UINT16_MAX;
549 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
550 }
551 else {
552 // Just print the backslash. The following
553 // character will be printed later.
554 bc_vm_putchar('\\', bc_flush_save);
555 }
556 }
557
558 bc_vm_putchar(c, bc_flush_save);
559 }
560 }
561
bc_program_print(BcProgram * p,uchar inst,size_t idx)562 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
563
564 BcResult *r;
565 char *str;
566 BcNum *n;
567 bool pop = (inst != BC_INST_PRINT);
568
569 assert(p != NULL);
570
571 #ifndef BC_PROG_NO_STACK_CHECK
572 if (BC_IS_DC) {
573 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
574 bc_vm_err(BC_ERR_EXEC_STACK);
575 }
576 #endif // BC_PROG_NO_STACK_CHECK
577
578 assert(BC_PROG_STACK(&p->results, idx + 1));
579
580 r = bc_vec_item_rev(&p->results, idx);
581
582 #if BC_ENABLED
583 if (r->t == BC_RESULT_VOID) {
584 if (BC_ERR(pop)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
585 bc_vec_pop(&p->results);
586 return;
587 }
588 #endif // BC_ENABLED
589
590 n = bc_program_num(p, r);
591
592 if (BC_PROG_NUM(r, n)) {
593 assert(inst != BC_INST_PRINT_STR);
594 bc_num_print(n, BC_PROG_OBASE(p), !pop);
595 #if BC_ENABLED
596 if (BC_IS_BC) bc_num_copy(&p->last, n);
597 #endif // BC_ENABLED
598 }
599 else {
600
601 size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
602
603 bc_file_flush(&vm.fout, bc_flush_save);
604 str = *((char**) bc_vec_item(p->strs, i));
605
606 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
607 else {
608 bc_program_printString(str);
609 if (inst == BC_INST_PRINT)
610 bc_vm_putchar('\n', bc_flush_err);
611 }
612 }
613
614 if (BC_IS_BC || pop) bc_vec_pop(&p->results);
615 }
616
bc_program_negate(BcResult * r,BcNum * n)617 void bc_program_negate(BcResult *r, BcNum *n) {
618 bc_num_copy(&r->d.n, n);
619 if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
620 }
621
bc_program_not(BcResult * r,BcNum * n)622 void bc_program_not(BcResult *r, BcNum *n) {
623 if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
624 }
625
626 #if BC_ENABLE_EXTRA_MATH
bc_program_trunc(BcResult * r,BcNum * n)627 void bc_program_trunc(BcResult *r, BcNum *n) {
628 bc_num_copy(&r->d.n, n);
629 bc_num_truncate(&r->d.n, n->scale);
630 }
631 #endif // BC_ENABLE_EXTRA_MATH
632
bc_program_unary(BcProgram * p,uchar inst)633 static void bc_program_unary(BcProgram *p, uchar inst) {
634
635 BcResult *res, *ptr;
636 BcNum *num;
637
638 res = bc_program_prepResult(p);
639
640 bc_program_prep(p, &ptr, &num, 1);
641
642 BC_SIG_LOCK;
643
644 bc_num_init(&res->d.n, num->len);
645
646 BC_SIG_UNLOCK;
647
648 bc_program_unarys[inst - BC_INST_NEG](res, num);
649 bc_program_retire(p, 1, 1);
650 }
651
bc_program_logical(BcProgram * p,uchar inst)652 static void bc_program_logical(BcProgram *p, uchar inst) {
653
654 BcResult *opd1, *opd2, *res;
655 BcNum *n1, *n2;
656 bool cond = 0;
657 ssize_t cmp;
658
659 res = bc_program_prepResult(p);
660
661 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
662
663 if (inst == BC_INST_BOOL_AND)
664 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
665 else if (inst == BC_INST_BOOL_OR)
666 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
667 else {
668
669 cmp = bc_num_cmp(n1, n2);
670
671 switch (inst) {
672
673 case BC_INST_REL_EQ:
674 {
675 cond = (cmp == 0);
676 break;
677 }
678
679 case BC_INST_REL_LE:
680 {
681 cond = (cmp <= 0);
682 break;
683 }
684
685 case BC_INST_REL_GE:
686 {
687 cond = (cmp >= 0);
688 break;
689 }
690
691 case BC_INST_REL_NE:
692 {
693 cond = (cmp != 0);
694 break;
695 }
696
697 case BC_INST_REL_LT:
698 {
699 cond = (cmp < 0);
700 break;
701 }
702
703 case BC_INST_REL_GT:
704 {
705 cond = (cmp > 0);
706 break;
707 }
708 #ifndef NDEBUG
709 default:
710 {
711 abort();
712 }
713 #endif // NDEBUG
714 }
715 }
716
717 BC_SIG_LOCK;
718
719 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
720
721 BC_SIG_UNLOCK;
722
723 if (cond) bc_num_one(&res->d.n);
724
725 bc_program_retire(p, 1, 2);
726 }
727
728 #if DC_ENABLED
bc_program_assignStr(BcProgram * p,size_t idx,BcVec * v,bool push)729 static void bc_program_assignStr(BcProgram *p, size_t idx,
730 BcVec *v, bool push)
731 {
732 BcNum n2;
733
734 bc_num_clear(&n2);
735 n2.scale = idx;
736
737 assert(BC_PROG_STACK(&p->results, 1 + !push));
738
739 if (!push) bc_vec_pop(v);
740
741 bc_vec_npop(&p->results, 1 + !push);
742 bc_vec_push(v, &n2);
743 }
744 #endif // DC_ENABLED
745
bc_program_copyToVar(BcProgram * p,size_t idx,BcType t,bool last)746 static void bc_program_copyToVar(BcProgram *p, size_t idx,
747 BcType t, bool last)
748 {
749 BcResult *ptr = NULL, r;
750 BcVec *vec;
751 BcNum *n = NULL;
752 bool var = (t == BC_TYPE_VAR);
753
754 #if DC_ENABLED
755 if (BC_IS_DC) {
756
757 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
758 bc_vm_err(BC_ERR_EXEC_STACK);
759
760 assert(BC_PROG_STACK(&p->results, 1));
761
762 bc_program_operand(p, &ptr, &n, 0);
763 }
764 #endif
765
766 #if BC_ENABLED
767 if (BC_IS_BC)
768 {
769 ptr = bc_vec_top(&p->results);
770
771 bc_program_type_match(ptr, t);
772
773 if (last) n = bc_program_num(p, ptr);
774 else if (var)
775 n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
776 }
777 #endif // BC_ENABLED
778
779 vec = bc_program_vec(p, idx, t);
780
781 #if DC_ENABLED
782 if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) {
783
784 size_t str_idx = ptr->t == BC_RESULT_STR ? ptr->d.loc.loc : n->scale;
785
786 if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE);
787
788 bc_program_assignStr(p, str_idx, vec, true);
789
790 return;
791 }
792 #endif // DC_ENABLED
793
794 BC_SIG_LOCK;
795
796 if (var) bc_num_createCopy(&r.d.n, n);
797 else {
798
799 BcVec *v = (BcVec*) n, *rv = &r.d.v;
800 #if BC_ENABLED
801 BcVec *parent;
802 bool ref, ref_size;
803
804 parent = bc_program_vec(p, ptr->d.loc.loc, t);
805 assert(parent != NULL);
806
807 if (!last) v = bc_vec_item_rev(parent, !last);
808 assert(v != NULL);
809
810 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
811 ref_size = (v->size == sizeof(uchar));
812
813 if (ref || (ref_size && t == BC_TYPE_REF)) {
814
815 bc_vec_init(rv, sizeof(uchar), NULL);
816
817 if (ref) {
818
819 assert(parent->len >= (size_t) (!last + 1));
820
821 // Make sure the pointer was not invalidated.
822 vec = bc_program_vec(p, idx, t);
823
824 bc_vec_pushIndex(rv, ptr->d.loc.loc);
825 bc_vec_pushIndex(rv, parent->len - !last - 1);
826 }
827 // If we get here, we are copying a ref to a ref.
828 else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
829
830 // We need to return early.
831 bc_vec_push(vec, &r.d);
832 bc_vec_pop(&p->results);
833
834 BC_SIG_UNLOCK;
835 return;
836 }
837 else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v);
838 #endif // BC_ENABLED
839
840 bc_array_init(rv, true);
841 bc_array_copy(rv, v);
842 }
843
844 bc_vec_push(vec, &r.d);
845 bc_vec_pop(&p->results);
846
847 BC_SIG_UNLOCK;
848 }
849
bc_program_assign(BcProgram * p,uchar inst)850 static void bc_program_assign(BcProgram *p, uchar inst) {
851
852 BcResult *left, *right, res;
853 BcNum *l, *r;
854 bool ob, sc, use_val = BC_INST_USE_VAL(inst);
855
856 bc_program_assignPrep(p, &left, &l, &right, &r);
857
858 #if DC_ENABLED
859 assert(left->t != BC_RESULT_STR);
860
861 if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) {
862
863 size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale;
864
865 if (left->t == BC_RESULT_ARRAY_ELEM) {
866 BC_SIG_LOCK;
867 bc_num_free(l);
868 bc_num_clear(l);
869 l->scale = idx;
870 bc_vec_npop(&p->results, 2);
871 BC_SIG_UNLOCK;
872 }
873 else {
874 BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
875 bc_program_assignStr(p, idx, v, false);
876 }
877
878 return;
879 }
880 #endif // DC_ENABLED
881
882 if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r);
883 #if BC_ENABLED
884 else {
885
886 BcBigDig scale = BC_PROG_SCALE(p);
887
888 if (!use_val)
889 inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
890
891 assert(BC_NUM_RDX_VALID(l));
892 assert(BC_NUM_RDX_VALID(r));
893
894 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
895 }
896 #endif // BC_ENABLED
897
898 ob = (left->t == BC_RESULT_OBASE);
899 sc = (left->t == BC_RESULT_SCALE);
900
901 if (ob || sc || left->t == BC_RESULT_IBASE) {
902
903 BcVec *v;
904 BcBigDig *ptr, *ptr_t, val, max, min;
905 BcErr e;
906
907 bc_num_bigdig(l, &val);
908 e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
909
910 if (sc) {
911 min = 0;
912 max = vm.maxes[BC_PROG_GLOBALS_SCALE];
913 v = p->globals_v + BC_PROG_GLOBALS_SCALE;
914 ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
915 }
916 else {
917 min = BC_NUM_MIN_BASE;
918 if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
919 min = 0;
920 max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
921 v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
922 ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
923 }
924
925 if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max);
926
927 ptr = bc_vec_top(v);
928 *ptr = val;
929 *ptr_t = val;
930 }
931 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
932 else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
933 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
934
935 BC_SIG_LOCK;
936
937 if (use_val) {
938 bc_num_createCopy(&res.d.n, l);
939 res.t = BC_RESULT_TEMP;
940 bc_vec_npop(&p->results, 2);
941 bc_vec_push(&p->results, &res);
942 }
943 else bc_vec_npop(&p->results, 2);
944
945 BC_SIG_UNLOCK;
946 }
947
bc_program_pushVar(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool pop,bool copy)948 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
949 size_t *restrict bgn, bool pop, bool copy)
950 {
951 BcResult r;
952 size_t idx = bc_program_index(code, bgn);
953
954 r.t = BC_RESULT_VAR;
955 r.d.loc.loc = idx;
956
957 #if DC_ENABLED
958 if (BC_IS_DC && (pop || copy)) {
959
960 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
961 BcNum *num = bc_vec_top(v);
962
963 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK);
964
965 assert(BC_PROG_STACK(v, 2 - copy));
966
967 if (!BC_PROG_STR(num)) {
968
969 BC_SIG_LOCK;
970
971 r.t = BC_RESULT_TEMP;
972 bc_num_createCopy(&r.d.n, num);
973
974 if (!copy) bc_vec_pop(v);
975
976 bc_vec_push(&p->results, &r);
977
978 BC_SIG_UNLOCK;
979
980 return;
981 }
982 else {
983 r.d.loc.loc = num->scale;
984 r.t = BC_RESULT_STR;
985 }
986
987 if (!copy) bc_vec_pop(v);
988 }
989 #endif // DC_ENABLED
990
991 bc_vec_push(&p->results, &r);
992 }
993
bc_program_pushArray(BcProgram * p,const char * restrict code,size_t * restrict bgn,uchar inst)994 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
995 size_t *restrict bgn, uchar inst)
996 {
997 BcResult r, *operand;
998 BcNum *num;
999 BcBigDig temp;
1000
1001 r.d.loc.loc = bc_program_index(code, bgn);
1002
1003 #if BC_ENABLED
1004 if (inst == BC_INST_ARRAY) {
1005 r.t = BC_RESULT_ARRAY;
1006 bc_vec_push(&p->results, &r);
1007 return;
1008 }
1009 #endif // BC_ENABLED
1010
1011 bc_program_prep(p, &operand, &num, 0);
1012 bc_num_bigdig(num, &temp);
1013
1014 r.t = BC_RESULT_ARRAY_ELEM;
1015 r.d.loc.idx = (size_t) temp;
1016
1017 BC_SIG_LOCK;
1018
1019 bc_vec_pop(&p->results);
1020 bc_vec_push(&p->results, &r);
1021
1022 BC_SIG_UNLOCK;
1023 }
1024
1025 #if BC_ENABLED
bc_program_incdec(BcProgram * p,uchar inst)1026 static void bc_program_incdec(BcProgram *p, uchar inst) {
1027
1028 BcResult *ptr, res, copy;
1029 BcNum *num;
1030 uchar inst2;
1031
1032 bc_program_prep(p, &ptr, &num, 0);
1033
1034 BC_SIG_LOCK;
1035
1036 copy.t = BC_RESULT_TEMP;
1037 bc_num_createCopy(©.d.n, num);
1038
1039 BC_SETJMP_LOCKED(exit);
1040
1041 BC_SIG_UNLOCK;
1042
1043 res.t = BC_RESULT_ONE;
1044 inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
1045
1046 bc_vec_push(&p->results, &res);
1047 bc_program_assign(p, inst2);
1048
1049 BC_SIG_LOCK;
1050
1051 bc_vec_pop(&p->results);
1052 bc_vec_push(&p->results, ©);
1053
1054 BC_UNSETJMP;
1055
1056 BC_SIG_UNLOCK;
1057
1058 return;
1059
1060 exit:
1061 BC_SIG_MAYLOCK;
1062 bc_num_free(©.d.n);
1063 BC_LONGJMP_CONT;
1064 }
1065
bc_program_call(BcProgram * p,const char * restrict code,size_t * restrict idx)1066 static void bc_program_call(BcProgram *p, const char *restrict code,
1067 size_t *restrict idx)
1068 {
1069 BcInstPtr ip;
1070 size_t i, nparams = bc_program_index(code, idx);
1071 BcFunc *f;
1072 BcVec *v;
1073 BcLoc *a;
1074 BcResultData param;
1075 BcResult *arg;
1076
1077 ip.idx = 0;
1078 ip.func = bc_program_index(code, idx);
1079 f = bc_vec_item(&p->fns, ip.func);
1080
1081 if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1082 if (BC_ERR(nparams != f->nparams))
1083 bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams);
1084 ip.len = p->results.len - nparams;
1085
1086 assert(BC_PROG_STACK(&p->results, nparams));
1087
1088 if (BC_G) bc_program_prepGlobals(p);
1089
1090 for (i = 0; i < nparams; ++i) {
1091
1092 size_t j;
1093 bool last = true;
1094
1095 arg = bc_vec_top(&p->results);
1096 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
1097
1098 a = bc_vec_item(&f->autos, nparams - 1 - i);
1099
1100 // If I have already pushed to a var, I need to make sure I
1101 // get the previous version, not the already pushed one.
1102 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1103 for (j = 0; j < i && last; ++j) {
1104 BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j);
1105 last = (arg->d.loc.loc != loc->loc ||
1106 (!loc->idx) != (arg->t == BC_RESULT_VAR));
1107 }
1108 }
1109
1110 bc_program_copyToVar(p, a->loc, (BcType) a->idx, last);
1111 }
1112
1113 BC_SIG_LOCK;
1114
1115 for (; i < f->autos.len; ++i) {
1116
1117 a = bc_vec_item(&f->autos, i);
1118 v = bc_program_vec(p, a->loc, (BcType) a->idx);
1119
1120 if (a->idx == BC_TYPE_VAR) {
1121 bc_num_init(¶m.n, BC_NUM_DEF_SIZE);
1122 bc_vec_push(v, ¶m.n);
1123 }
1124 else {
1125 assert(a->idx == BC_TYPE_ARRAY);
1126 bc_array_init(¶m.v, true);
1127 bc_vec_push(v, ¶m.v);
1128 }
1129 }
1130
1131 bc_vec_push(&p->stack, &ip);
1132
1133 BC_SIG_UNLOCK;
1134 }
1135
bc_program_return(BcProgram * p,uchar inst)1136 static void bc_program_return(BcProgram *p, uchar inst) {
1137
1138 BcResult *res;
1139 BcFunc *f;
1140 BcInstPtr *ip = bc_vec_top(&p->stack);
1141 size_t i, nops = p->results.len - ip->len;
1142
1143 assert(BC_PROG_STACK(&p->stack, 2));
1144 assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1145
1146 f = bc_vec_item(&p->fns, ip->func);
1147 res = bc_program_prepResult(p);
1148
1149 if (inst == BC_INST_RET) {
1150
1151 BcNum *num;
1152 BcResult *operand;
1153
1154 bc_program_operand(p, &operand, &num, 1);
1155
1156 BC_SIG_LOCK;
1157
1158 bc_num_createCopy(&res->d.n, num);
1159 }
1160 else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1161 else {
1162 BC_SIG_LOCK;
1163 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1164 }
1165
1166 BC_SIG_MAYUNLOCK;
1167
1168 // We need to pop arguments as well, so this takes that into account.
1169 for (i = 0; i < f->autos.len; ++i) {
1170
1171 BcLoc *a = bc_vec_item(&f->autos, i);
1172 BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx);
1173
1174 bc_vec_pop(v);
1175 }
1176
1177 bc_program_retire(p, 1, nops);
1178
1179 if (BC_G) bc_program_popGlobals(p, false);
1180
1181 bc_vec_pop(&p->stack);
1182 }
1183 #endif // BC_ENABLED
1184
bc_program_builtin(BcProgram * p,uchar inst)1185 static void bc_program_builtin(BcProgram *p, uchar inst) {
1186
1187 BcResult *opd, *res;
1188 BcNum *num;
1189 bool len = (inst == BC_INST_LENGTH);
1190
1191 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1192 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1193 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1194 assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1195 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1196
1197 #ifndef BC_PROG_NO_STACK_CHECK
1198 if (BC_IS_DC) {
1199 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1200 bc_vm_err(BC_ERR_EXEC_STACK);
1201 }
1202 #endif // BC_PROG_NO_STACK_CHECK
1203
1204 assert(BC_PROG_STACK(&p->results, 1));
1205
1206 res = bc_program_prepResult(p);
1207
1208 bc_program_operand(p, &opd, &num, 1);
1209
1210 assert(num != NULL);
1211
1212 #if DC_ENABLED
1213 if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num);
1214 #endif // DC_ENABLED
1215
1216 if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1217 else if (inst == BC_INST_ABS) {
1218
1219 BC_SIG_LOCK;
1220
1221 bc_num_createCopy(&res->d.n, num);
1222
1223 BC_SIG_UNLOCK;
1224
1225 BC_NUM_NEG_CLR_NP(res->d.n);
1226 }
1227 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1228 else if (inst == BC_INST_IRAND) {
1229
1230 BC_SIG_LOCK;
1231
1232 bc_num_init(&res->d.n, num->len - num->rdx);
1233
1234 BC_SIG_UNLOCK;
1235
1236 bc_num_irand(num, &res->d.n, &p->rng);
1237 }
1238 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1239 else {
1240
1241 BcBigDig val = 0;
1242
1243 if (len) {
1244 #if BC_ENABLED
1245 if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) {
1246
1247 BcVec *v = (BcVec*) num;
1248
1249 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
1250
1251 assert(v->size == sizeof(BcNum));
1252
1253 val = (BcBigDig) v->len;
1254 }
1255 else
1256 #endif // BC_ENABLED
1257 {
1258 #if DC_ENABLED
1259 if (!BC_PROG_NUM(opd, num)) {
1260
1261 size_t idx;
1262 char *str;
1263
1264 idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale;
1265 str = *((char**) bc_vec_item(p->strs, idx));
1266 val = (BcBigDig) strlen(str);
1267 }
1268 else
1269 #endif // DC_ENABLED
1270 {
1271 val = (BcBigDig) bc_num_len(num);
1272 }
1273 }
1274 }
1275 else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1276 val = (BcBigDig) bc_num_scale(num);
1277
1278 BC_SIG_LOCK;
1279
1280 bc_num_createFromBigdig(&res->d.n, val);
1281
1282 BC_SIG_UNLOCK;
1283 }
1284
1285 bc_program_retire(p, 1, 1);
1286 }
1287
1288 #if DC_ENABLED
bc_program_divmod(BcProgram * p)1289 static void bc_program_divmod(BcProgram *p) {
1290
1291 BcResult *opd1, *opd2, *res, *res2;
1292 BcNum *n1, *n2;
1293 size_t req;
1294
1295 bc_vec_grow(&p->results, 2);
1296
1297 // We don't need to update the pointer because
1298 // the capacity is enough due to the line above.
1299 res2 = bc_program_prepResult(p);
1300 res = bc_program_prepResult(p);
1301
1302 bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1303
1304 req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1305
1306 BC_SIG_LOCK;
1307
1308 bc_num_init(&res->d.n, req);
1309 bc_num_init(&res2->d.n, req);
1310
1311 BC_SIG_UNLOCK;
1312
1313 bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1314
1315 bc_program_retire(p, 2, 2);
1316 }
1317
bc_program_modexp(BcProgram * p)1318 static void bc_program_modexp(BcProgram *p) {
1319
1320 BcResult *r1, *r2, *r3, *res;
1321 BcNum *n1, *n2, *n3;
1322
1323 if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK);
1324
1325 assert(BC_PROG_STACK(&p->results, 3));
1326
1327 res = bc_program_prepResult(p);
1328
1329 bc_program_operand(p, &r1, &n1, 3);
1330 bc_program_type_num(r1, n1);
1331
1332 bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1333
1334 // Make sure that the values have their pointers updated, if necessary.
1335 // Only array elements are possible.
1336 if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1337 n1 = bc_program_num(p, r1);
1338
1339 BC_SIG_LOCK;
1340
1341 bc_num_init(&res->d.n, n3->len);
1342
1343 BC_SIG_UNLOCK;
1344
1345 bc_num_modexp(n1, n2, n3, &res->d.n);
1346
1347 bc_program_retire(p, 1, 3);
1348 }
1349
bc_program_stackLen(BcProgram * p)1350 static void bc_program_stackLen(BcProgram *p) {
1351 bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1352 }
1353
bc_program_asciifyNum(BcProgram * p,BcNum * n)1354 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
1355
1356 BcNum num;
1357 BcBigDig val = 0;
1358
1359 bc_num_clear(&num);
1360
1361 BC_SETJMP(num_err);
1362
1363 BC_SIG_LOCK;
1364
1365 bc_num_createCopy(&num, n);
1366
1367 BC_SIG_UNLOCK;
1368
1369 bc_num_truncate(&num, num.scale);
1370 BC_NUM_NEG_CLR_NP(num);
1371
1372 // This is guaranteed to not have a divide by 0
1373 // because strmb is equal to UCHAR_MAX + 1.
1374 bc_num_mod(&num, &p->strmb, &num, 0);
1375
1376 // This is also guaranteed to not error because num is in the range
1377 // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
1378 // it is not negative.
1379 bc_num_bigdig2(&num, &val);
1380
1381 num_err:
1382 BC_SIG_MAYLOCK;
1383 bc_num_free(&num);
1384 BC_LONGJMP_CONT;
1385 return (uchar) val;
1386 }
1387
bc_program_asciify(BcProgram * p)1388 static void bc_program_asciify(BcProgram *p) {
1389
1390 BcResult *r, res;
1391 BcNum *n;
1392 char str[2], *str2;
1393 uchar c;
1394 size_t idx;
1395
1396 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1397
1398 assert(BC_PROG_STACK(&p->results, 1));
1399
1400 bc_program_operand(p, &r, &n, 0);
1401
1402 assert(n != NULL);
1403
1404 assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len);
1405
1406 if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
1407 else {
1408 size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale;
1409 str2 = *((char**) bc_vec_item(p->strs, index));
1410 c = (uchar) str2[0];
1411 }
1412
1413 str[0] = (char) c;
1414 str[1] = '\0';
1415
1416 BC_SIG_LOCK;
1417
1418 idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS;
1419
1420 BC_SIG_UNLOCK;
1421
1422 res.t = BC_RESULT_STR;
1423 res.d.loc.loc = idx;
1424 bc_vec_pop(&p->results);
1425 bc_vec_push(&p->results, &res);
1426 }
1427
bc_program_printStream(BcProgram * p)1428 static void bc_program_printStream(BcProgram *p) {
1429
1430 BcResult *r;
1431 BcNum *n;
1432
1433 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1434
1435 assert(BC_PROG_STACK(&p->results, 1));
1436
1437 bc_program_operand(p, &r, &n, 0);
1438
1439 assert(n != NULL);
1440
1441 if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm);
1442 else {
1443 size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
1444 bc_program_printChars(*((char**) bc_vec_item(p->strs, idx)));
1445 }
1446
1447 bc_vec_pop(&p->results);
1448 }
1449
bc_program_nquit(BcProgram * p,uchar inst)1450 static void bc_program_nquit(BcProgram *p, uchar inst) {
1451
1452 BcResult *opnd;
1453 BcNum *num;
1454 BcBigDig val;
1455 size_t i;
1456
1457 assert(p->stack.len == p->tail_calls.len);
1458
1459 if (inst == BC_INST_QUIT) val = 2;
1460 else {
1461
1462 bc_program_prep(p, &opnd, &num, 0);
1463 bc_num_bigdig(num, &val);
1464
1465 bc_vec_pop(&p->results);
1466 }
1467
1468 for (i = 0; val && i < p->tail_calls.len; ++i) {
1469 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
1470 if (calls >= val) val = 0;
1471 else val -= (BcBigDig) calls;
1472 }
1473
1474 if (i == p->stack.len) {
1475 vm.status = BC_STATUS_QUIT;
1476 BC_VM_JMP;
1477 }
1478 else {
1479 bc_vec_npop(&p->stack, i);
1480 bc_vec_npop(&p->tail_calls, i);
1481 }
1482 }
1483
bc_program_execStr(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool cond,size_t len)1484 static void bc_program_execStr(BcProgram *p, const char *restrict code,
1485 size_t *restrict bgn, bool cond, size_t len)
1486 {
1487 BcResult *r;
1488 char *str;
1489 BcFunc *f;
1490 BcParse prs;
1491 BcInstPtr ip;
1492 size_t fidx, sidx;
1493 BcNum *n;
1494
1495 assert(p->stack.len == p->tail_calls.len);
1496
1497 if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1498
1499 assert(BC_PROG_STACK(&p->results, 1));
1500
1501 bc_program_operand(p, &r, &n, 0);
1502
1503 if (cond) {
1504
1505 bool exec;
1506 size_t idx, then_idx, else_idx;
1507
1508 then_idx = bc_program_index(code, bgn);
1509 else_idx = bc_program_index(code, bgn);
1510
1511 exec = (r->d.n.len != 0);
1512
1513 idx = exec ? then_idx : else_idx;
1514
1515 BC_SIG_LOCK;
1516 BC_SETJMP_LOCKED(exit);
1517
1518 if (exec || (else_idx != SIZE_MAX))
1519 n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
1520 else goto exit;
1521
1522 if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE);
1523
1524 BC_UNSETJMP;
1525 BC_SIG_UNLOCK;
1526
1527 sidx = n->scale;
1528 }
1529 else {
1530
1531 // In non-conditional situations, only the top of stack can be executed,
1532 // and in those cases, variables are not allowed to be "on the stack";
1533 // they are only put on the stack to be assigned to.
1534 assert(r->t != BC_RESULT_VAR);
1535
1536 if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc;
1537 else return;
1538 }
1539
1540 fidx = sidx + BC_PROG_REQ_FUNCS;
1541 str = *((char**) bc_vec_item(p->strs, sidx));
1542 f = bc_vec_item(&p->fns, fidx);
1543
1544 if (!f->code.len) {
1545
1546 BC_SIG_LOCK;
1547
1548 bc_parse_init(&prs, p, fidx);
1549 bc_lex_file(&prs.l, vm.file);
1550
1551 BC_SETJMP_LOCKED(err);
1552
1553 BC_SIG_UNLOCK;
1554
1555 bc_parse_text(&prs, str);
1556 vm.expr(&prs, BC_PARSE_NOCALL);
1557
1558 BC_SIG_LOCK;
1559
1560 BC_UNSETJMP;
1561
1562 // We can just assert this here because
1563 // dc should parse everything until EOF.
1564 assert(prs.l.t == BC_LEX_EOF);
1565
1566 bc_parse_free(&prs);
1567
1568 BC_SIG_UNLOCK;
1569 }
1570
1571 ip.idx = 0;
1572 ip.len = p->results.len;
1573 ip.func = fidx;
1574
1575 bc_vec_pop(&p->results);
1576
1577 // Tail call.
1578 if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
1579 size_t *call_ptr = bc_vec_top(&p->tail_calls);
1580 *call_ptr += 1;
1581 bc_vec_pop(&p->stack);
1582 }
1583 else bc_vec_push(&p->tail_calls, &ip.idx);
1584
1585 bc_vec_push(&p->stack, &ip);
1586
1587 return;
1588
1589 err:
1590 BC_SIG_MAYLOCK;
1591 bc_parse_free(&prs);
1592 f = bc_vec_item(&p->fns, fidx);
1593 bc_vec_popAll(&f->code);
1594 exit:
1595 bc_vec_pop(&p->results);
1596 BC_LONGJMP_CONT;
1597 }
1598
bc_program_printStack(BcProgram * p)1599 static void bc_program_printStack(BcProgram *p) {
1600
1601 size_t idx;
1602
1603 for (idx = 0; idx < p->results.len; ++idx)
1604 bc_program_print(p, BC_INST_PRINT, idx);
1605 }
1606 #endif // DC_ENABLED
1607
bc_program_pushGlobal(BcProgram * p,uchar inst)1608 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
1609
1610 BcResultType t;
1611
1612 assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
1613
1614 t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
1615 bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
1616 }
1617
1618 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
bc_program_pushSeed(BcProgram * p)1619 static void bc_program_pushSeed(BcProgram *p) {
1620
1621 BcResult *res;
1622
1623 res = bc_program_prepResult(p);
1624 res->t = BC_RESULT_SEED;
1625
1626 BC_SIG_LOCK;
1627
1628 bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
1629
1630 BC_SIG_UNLOCK;
1631
1632 bc_num_createFromRNG(&res->d.n, &p->rng);
1633 }
1634 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1635
bc_program_addFunc(BcProgram * p,BcFunc * f,BcId * id_ptr)1636 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) {
1637
1638 BcInstPtr *ip;
1639
1640 BC_SIG_ASSERT_LOCKED;
1641
1642 bc_func_init(f, id_ptr->name);
1643 bc_vec_push(&p->fns, f);
1644
1645 // This is to make sure pointers are updated if the array was moved.
1646 if (p->stack.len) {
1647 ip = bc_vec_top(&p->stack);
1648 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
1649 }
1650 }
1651
bc_program_insertFunc(BcProgram * p,const char * name)1652 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
1653
1654 BcId *id_ptr;
1655 BcFunc f;
1656 bool new;
1657 size_t idx;
1658
1659 BC_SIG_ASSERT_LOCKED;
1660
1661 assert(p != NULL && name != NULL);
1662
1663 new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
1664 id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
1665 idx = id_ptr->idx;
1666
1667 if (!new) {
1668 if (BC_IS_BC) {
1669 BcFunc *func = bc_vec_item(&p->fns, idx);
1670 bc_func_reset(func);
1671 }
1672 }
1673 else {
1674
1675 bc_program_addFunc(p, &f, id_ptr);
1676
1677 #if DC_ENABLED
1678 if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) {
1679 bc_vec_push(p->strs, &id_ptr->name);
1680 assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS);
1681 }
1682 #endif // DC_ENABLED
1683 }
1684
1685 return idx;
1686 }
1687
1688 #ifndef NDEBUG
bc_program_free(BcProgram * p)1689 void bc_program_free(BcProgram *p) {
1690
1691 size_t i;
1692
1693 BC_SIG_ASSERT_LOCKED;
1694
1695 assert(p != NULL);
1696
1697 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
1698
1699 bc_vec_free(&p->fns);
1700 bc_vec_free(&p->fn_map);
1701 bc_vec_free(&p->vars);
1702 bc_vec_free(&p->var_map);
1703 bc_vec_free(&p->arrs);
1704 bc_vec_free(&p->arr_map);
1705 bc_vec_free(&p->results);
1706 bc_vec_free(&p->stack);
1707
1708 #if BC_ENABLED
1709 if (BC_IS_BC) bc_num_free(&p->last);
1710 #endif // BC_ENABLED
1711
1712 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1713 bc_rand_free(&p->rng);
1714 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1715
1716 #if DC_ENABLED
1717 if (BC_IS_DC) {
1718 bc_vec_free(&p->tail_calls);
1719 bc_vec_free(&p->strs_v);
1720 }
1721 #endif // DC_ENABLED
1722 }
1723 #endif // NDEBUG
1724
bc_program_init(BcProgram * p)1725 void bc_program_init(BcProgram *p) {
1726
1727 BcInstPtr ip;
1728 size_t i;
1729
1730 BC_SIG_ASSERT_LOCKED;
1731
1732 assert(p != NULL);
1733
1734 memset(p, 0, sizeof(BcProgram));
1735 memset(&ip, 0, sizeof(BcInstPtr));
1736
1737 for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
1738 BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
1739 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL);
1740 bc_vec_push(p->globals_v + i, &val);
1741 p->globals[i] = val;
1742 }
1743
1744 #if DC_ENABLED
1745 if (BC_IS_DC) {
1746
1747 bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free);
1748 p->strs = &p->strs_v;
1749
1750 bc_vec_init(&p->tail_calls, sizeof(size_t), NULL);
1751 i = 0;
1752 bc_vec_push(&p->tail_calls, &i);
1753
1754 p->strm = UCHAR_MAX + 1;
1755 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
1756 bc_num_bigdig2num(&p->strmb, p->strm);
1757 }
1758 #endif // DC_ENABLED
1759
1760 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1761 srand((unsigned int) time(NULL));
1762 bc_rand_init(&p->rng);
1763 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1764
1765 bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP);
1766
1767 bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
1768 bc_num_one(&p->one);
1769
1770 #if BC_ENABLED
1771 if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
1772 #endif // BC_ENABLED
1773
1774 bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
1775 bc_map_init(&p->fn_map);
1776 bc_program_insertFunc(p, bc_func_main);
1777 bc_program_insertFunc(p, bc_func_read);
1778
1779 bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
1780 bc_map_init(&p->var_map);
1781
1782 bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
1783 bc_map_init(&p->arr_map);
1784
1785 bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1786 bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
1787 bc_vec_push(&p->stack, &ip);
1788
1789 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
1790
1791 assert(p->consts != NULL && p->strs != NULL);
1792 }
1793
bc_program_reset(BcProgram * p)1794 void bc_program_reset(BcProgram *p) {
1795
1796 BcFunc *f;
1797 BcInstPtr *ip;
1798
1799 BC_SIG_ASSERT_LOCKED;
1800
1801 bc_vec_npop(&p->stack, p->stack.len - 1);
1802 bc_vec_popAll(&p->results);
1803
1804 #if BC_ENABLED
1805 if (BC_G) bc_program_popGlobals(p, true);
1806 #endif // BC_ENABLED
1807
1808 f = bc_vec_item(&p->fns, BC_PROG_MAIN);
1809 bc_vec_npop(&f->code, f->code.len);
1810 ip = bc_vec_top(&p->stack);
1811 bc_program_setVecs(p, f);
1812 memset(ip, 0, sizeof(BcInstPtr));
1813
1814 if (vm.sig) {
1815 bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
1816 bc_program_ready_msg_len);
1817 bc_file_flush(&vm.fout, bc_flush_err);
1818 vm.sig = 0;
1819 }
1820 }
1821
bc_program_exec(BcProgram * p)1822 void bc_program_exec(BcProgram *p) {
1823
1824 size_t idx;
1825 BcResult r, *ptr;
1826 BcInstPtr *ip = bc_vec_top(&p->stack);
1827 BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
1828 char *code = func->code.v;
1829 bool cond = false;
1830 #if BC_ENABLED
1831 BcNum *num;
1832 #endif // BC_ENABLED
1833 #ifndef NDEBUG
1834 size_t jmp_bufs_len;
1835 #endif // NDEBUG
1836
1837 #ifndef NDEBUG
1838 jmp_bufs_len = vm.jmp_bufs.len;
1839 #endif // NDEBUG
1840
1841 bc_program_setVecs(p, func);
1842
1843 while (ip->idx < func->code.len) {
1844
1845 BC_SIG_ASSERT_NOT_LOCKED;
1846
1847 uchar inst = (uchar) code[(ip->idx)++];
1848
1849 switch (inst) {
1850
1851 #if BC_ENABLED
1852 case BC_INST_JUMP_ZERO:
1853 {
1854 bc_program_prep(p, &ptr, &num, 0);
1855 cond = !bc_num_cmpZero(num);
1856 bc_vec_pop(&p->results);
1857 }
1858 // Fallthrough.
1859 BC_FALLTHROUGH
1860
1861 case BC_INST_JUMP:
1862 {
1863 idx = bc_program_index(code, &ip->idx);
1864
1865 if (inst == BC_INST_JUMP || cond) {
1866
1867 size_t *addr = bc_vec_item(&func->labels, idx);
1868
1869 assert(*addr != SIZE_MAX);
1870
1871 ip->idx = *addr;
1872 }
1873
1874 break;
1875 }
1876
1877 case BC_INST_CALL:
1878 {
1879 assert(BC_IS_BC);
1880
1881 bc_program_call(p, code, &ip->idx);
1882
1883 ip = bc_vec_top(&p->stack);
1884 func = bc_vec_item(&p->fns, ip->func);
1885 code = func->code.v;
1886
1887 bc_program_setVecs(p, func);
1888
1889 break;
1890 }
1891
1892 case BC_INST_INC:
1893 case BC_INST_DEC:
1894 {
1895 bc_program_incdec(p, inst);
1896 break;
1897 }
1898
1899 case BC_INST_HALT:
1900 {
1901 vm.status = BC_STATUS_QUIT;
1902 BC_VM_JMP;
1903 break;
1904 }
1905
1906 case BC_INST_RET:
1907 case BC_INST_RET0:
1908 case BC_INST_RET_VOID:
1909 {
1910 bc_program_return(p, inst);
1911
1912 ip = bc_vec_top(&p->stack);
1913 func = bc_vec_item(&p->fns, ip->func);
1914 code = func->code.v;
1915
1916 bc_program_setVecs(p, func);
1917
1918 break;
1919 }
1920 #endif // BC_ENABLED
1921
1922 case BC_INST_BOOL_OR:
1923 case BC_INST_BOOL_AND:
1924 case BC_INST_REL_EQ:
1925 case BC_INST_REL_LE:
1926 case BC_INST_REL_GE:
1927 case BC_INST_REL_NE:
1928 case BC_INST_REL_LT:
1929 case BC_INST_REL_GT:
1930 {
1931 bc_program_logical(p, inst);
1932 break;
1933 }
1934
1935 case BC_INST_READ:
1936 {
1937 // We want to flush output before
1938 // this in case there is a prompt.
1939 bc_file_flush(&vm.fout, bc_flush_save);
1940
1941 bc_program_read(p);
1942
1943 ip = bc_vec_top(&p->stack);
1944 func = bc_vec_item(&p->fns, ip->func);
1945 code = func->code.v;
1946
1947 bc_program_setVecs(p, func);
1948
1949 break;
1950 }
1951
1952 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1953 case BC_INST_RAND:
1954 {
1955 bc_program_rand(p);
1956 break;
1957 }
1958 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1959
1960 case BC_INST_MAXIBASE:
1961 case BC_INST_MAXOBASE:
1962 case BC_INST_MAXSCALE:
1963 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1964 case BC_INST_MAXRAND:
1965 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1966 {
1967 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
1968 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
1969 break;
1970 }
1971
1972 case BC_INST_VAR:
1973 {
1974 bc_program_pushVar(p, code, &ip->idx, false, false);
1975 break;
1976 }
1977
1978 case BC_INST_ARRAY_ELEM:
1979 #if BC_ENABLED
1980 case BC_INST_ARRAY:
1981 #endif // BC_ENABLED
1982 {
1983 bc_program_pushArray(p, code, &ip->idx, inst);
1984 break;
1985 }
1986
1987 case BC_INST_IBASE:
1988 case BC_INST_SCALE:
1989 case BC_INST_OBASE:
1990 {
1991 bc_program_pushGlobal(p, inst);
1992 break;
1993 }
1994
1995 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1996 case BC_INST_SEED:
1997 {
1998 bc_program_pushSeed(p);
1999 break;
2000 }
2001 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
2002
2003 case BC_INST_LENGTH:
2004 case BC_INST_SCALE_FUNC:
2005 case BC_INST_SQRT:
2006 case BC_INST_ABS:
2007 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
2008 case BC_INST_IRAND:
2009 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
2010 {
2011 bc_program_builtin(p, inst);
2012 break;
2013 }
2014
2015 case BC_INST_NUM:
2016 {
2017 bc_program_const(p, code, &ip->idx);
2018 break;
2019 }
2020
2021 case BC_INST_ZERO:
2022 case BC_INST_ONE:
2023 #if BC_ENABLED
2024 case BC_INST_LAST:
2025 #endif // BC_ENABLED
2026 {
2027 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
2028 bc_vec_push(&p->results, &r);
2029 break;
2030 }
2031
2032 case BC_INST_PRINT:
2033 case BC_INST_PRINT_POP:
2034 case BC_INST_PRINT_STR:
2035 {
2036 bc_program_print(p, inst, 0);
2037 bc_file_flush(&vm.fout, bc_flush_save);
2038 break;
2039 }
2040
2041 case BC_INST_STR:
2042 {
2043 r.t = BC_RESULT_STR;
2044 r.d.loc.loc = bc_program_index(code, &ip->idx);
2045 bc_vec_push(&p->results, &r);
2046 break;
2047 }
2048
2049 case BC_INST_POWER:
2050 case BC_INST_MULTIPLY:
2051 case BC_INST_DIVIDE:
2052 case BC_INST_MODULUS:
2053 case BC_INST_PLUS:
2054 case BC_INST_MINUS:
2055 #if BC_ENABLE_EXTRA_MATH
2056 case BC_INST_PLACES:
2057 case BC_INST_LSHIFT:
2058 case BC_INST_RSHIFT:
2059 #endif // BC_ENABLE_EXTRA_MATH
2060 {
2061 bc_program_op(p, inst);
2062 break;
2063 }
2064
2065 case BC_INST_NEG:
2066 case BC_INST_BOOL_NOT:
2067 #if BC_ENABLE_EXTRA_MATH
2068 case BC_INST_TRUNC:
2069 #endif // BC_ENABLE_EXTRA_MATH
2070 {
2071 bc_program_unary(p, inst);
2072 break;
2073 }
2074
2075 #if BC_ENABLED
2076 case BC_INST_ASSIGN_POWER:
2077 case BC_INST_ASSIGN_MULTIPLY:
2078 case BC_INST_ASSIGN_DIVIDE:
2079 case BC_INST_ASSIGN_MODULUS:
2080 case BC_INST_ASSIGN_PLUS:
2081 case BC_INST_ASSIGN_MINUS:
2082 #if BC_ENABLE_EXTRA_MATH
2083 case BC_INST_ASSIGN_PLACES:
2084 case BC_INST_ASSIGN_LSHIFT:
2085 case BC_INST_ASSIGN_RSHIFT:
2086 #endif // BC_ENABLE_EXTRA_MATH
2087 case BC_INST_ASSIGN:
2088 case BC_INST_ASSIGN_POWER_NO_VAL:
2089 case BC_INST_ASSIGN_MULTIPLY_NO_VAL:
2090 case BC_INST_ASSIGN_DIVIDE_NO_VAL:
2091 case BC_INST_ASSIGN_MODULUS_NO_VAL:
2092 case BC_INST_ASSIGN_PLUS_NO_VAL:
2093 case BC_INST_ASSIGN_MINUS_NO_VAL:
2094 #if BC_ENABLE_EXTRA_MATH
2095 case BC_INST_ASSIGN_PLACES_NO_VAL:
2096 case BC_INST_ASSIGN_LSHIFT_NO_VAL:
2097 case BC_INST_ASSIGN_RSHIFT_NO_VAL:
2098 #endif // BC_ENABLE_EXTRA_MATH
2099 #endif // BC_ENABLED
2100 case BC_INST_ASSIGN_NO_VAL:
2101 {
2102 bc_program_assign(p, inst);
2103 break;
2104 }
2105
2106 case BC_INST_POP:
2107 {
2108 #ifndef BC_PROG_NO_STACK_CHECK
2109 if (!BC_IS_BC) {
2110 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2111 bc_vm_err(BC_ERR_EXEC_STACK);
2112 }
2113 #endif // BC_PROG_NO_STACK_CHECK
2114
2115 assert(BC_PROG_STACK(&p->results, 1));
2116
2117 bc_vec_pop(&p->results);
2118 break;
2119 }
2120
2121 #if DC_ENABLED
2122 case BC_INST_POP_EXEC:
2123 {
2124 assert(BC_PROG_STACK(&p->stack, 2));
2125 bc_vec_pop(&p->stack);
2126 bc_vec_pop(&p->tail_calls);
2127 ip = bc_vec_top(&p->stack);
2128 func = bc_vec_item(&p->fns, ip->func);
2129 code = func->code.v;
2130 bc_program_setVecs(p, func);
2131 break;
2132 }
2133
2134 case BC_INST_MODEXP:
2135 {
2136 bc_program_modexp(p);
2137 break;
2138 }
2139
2140 case BC_INST_DIVMOD:
2141 {
2142 bc_program_divmod(p);
2143 break;
2144 }
2145
2146 case BC_INST_EXECUTE:
2147 case BC_INST_EXEC_COND:
2148 {
2149 cond = (inst == BC_INST_EXEC_COND);
2150 bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
2151 ip = bc_vec_top(&p->stack);
2152 func = bc_vec_item(&p->fns, ip->func);
2153 code = func->code.v;
2154 bc_program_setVecs(p, func);
2155 break;
2156 }
2157
2158 case BC_INST_PRINT_STACK:
2159 {
2160 bc_program_printStack(p);
2161 break;
2162 }
2163
2164 case BC_INST_CLEAR_STACK:
2165 {
2166 bc_vec_popAll(&p->results);
2167 break;
2168 }
2169
2170 case BC_INST_STACK_LEN:
2171 {
2172 bc_program_stackLen(p);
2173 break;
2174 }
2175
2176 case BC_INST_DUPLICATE:
2177 {
2178 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2179 bc_vm_err(BC_ERR_EXEC_STACK);
2180
2181 assert(BC_PROG_STACK(&p->results, 1));
2182
2183 ptr = bc_vec_top(&p->results);
2184
2185 BC_SIG_LOCK;
2186
2187 bc_result_copy(&r, ptr);
2188 bc_vec_push(&p->results, &r);
2189
2190 BC_SIG_UNLOCK;
2191
2192 break;
2193 }
2194
2195 case BC_INST_SWAP:
2196 {
2197 BcResult *ptr2;
2198
2199 if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
2200 bc_vm_err(BC_ERR_EXEC_STACK);
2201
2202 assert(BC_PROG_STACK(&p->results, 2));
2203
2204 ptr = bc_vec_item_rev(&p->results, 0);
2205 ptr2 = bc_vec_item_rev(&p->results, 1);
2206 memcpy(&r, ptr, sizeof(BcResult));
2207 memcpy(ptr, ptr2, sizeof(BcResult));
2208 memcpy(ptr2, &r, sizeof(BcResult));
2209
2210 break;
2211 }
2212
2213 case BC_INST_ASCIIFY:
2214 {
2215 bc_program_asciify(p);
2216 ip = bc_vec_top(&p->stack);
2217 func = bc_vec_item(&p->fns, ip->func);
2218 code = func->code.v;
2219 bc_program_setVecs(p, func);
2220 break;
2221 }
2222
2223 case BC_INST_PRINT_STREAM:
2224 {
2225 bc_program_printStream(p);
2226 break;
2227 }
2228
2229 case BC_INST_LOAD:
2230 case BC_INST_PUSH_VAR:
2231 {
2232 bool copy = (inst == BC_INST_LOAD);
2233 bc_program_pushVar(p, code, &ip->idx, true, copy);
2234 break;
2235 }
2236
2237 case BC_INST_PUSH_TO_VAR:
2238 {
2239 idx = bc_program_index(code, &ip->idx);
2240 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
2241 break;
2242 }
2243
2244 case BC_INST_QUIT:
2245 case BC_INST_NQUIT:
2246 {
2247 bc_program_nquit(p, inst);
2248 ip = bc_vec_top(&p->stack);
2249 func = bc_vec_item(&p->fns, ip->func);
2250 code = func->code.v;
2251 bc_program_setVecs(p, func);
2252 break;
2253 }
2254 #endif // DC_ENABLED
2255 #ifndef NDEBUG
2256 default:
2257 {
2258 abort();
2259 }
2260 #endif // NDEBUG
2261 }
2262
2263 #ifndef NDEBUG
2264 // This is to allow me to use a debugger to see the last instruction,
2265 // which will point to which function was the problem.
2266 assert(jmp_bufs_len == vm.jmp_bufs.len);
2267 #endif // NDEBUG
2268 }
2269 }
2270
2271 #if BC_DEBUG_CODE
2272 #if BC_ENABLED && DC_ENABLED
bc_program_printStackDebug(BcProgram * p)2273 void bc_program_printStackDebug(BcProgram *p) {
2274 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack ----------\n");
2275 bc_program_printStack(p);
2276 bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack End ------\n");
2277 }
2278
bc_program_printIndex(const char * restrict code,size_t * restrict bgn)2279 static void bc_program_printIndex(const char *restrict code,
2280 size_t *restrict bgn)
2281 {
2282 uchar byte, i, bytes = (uchar) code[(*bgn)++];
2283 ulong val = 0;
2284
2285 for (byte = 1, i = 0; byte && i < bytes; ++i) {
2286 byte = (uchar) code[(*bgn)++];
2287 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
2288 }
2289
2290 bc_vm_printf(" (%lu) ", val);
2291 }
2292
bc_program_printStr(const BcProgram * p,const char * restrict code,size_t * restrict bgn)2293 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
2294 size_t *restrict bgn)
2295 {
2296 size_t idx = bc_program_index(code, bgn);
2297 char *s;
2298
2299 s = *((char**) bc_vec_item(p->strs, idx));
2300
2301 bc_vm_printf(" (\"%s\") ", s);
2302 }
2303
bc_program_printInst(const BcProgram * p,const char * restrict code,size_t * restrict bgn)2304 void bc_program_printInst(const BcProgram *p, const char *restrict code,
2305 size_t *restrict bgn)
2306 {
2307 uchar inst = (uchar) code[(*bgn)++];
2308
2309 bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
2310 bc_inst_names[inst], (unsigned long) inst);
2311
2312 if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
2313 inst == BC_INST_ARRAY)
2314 {
2315 bc_program_printIndex(code, bgn);
2316 }
2317 else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
2318 else if (inst == BC_INST_NUM) {
2319 size_t idx = bc_program_index(code, bgn);
2320 BcConst *c = bc_vec_item(p->consts, idx);
2321 bc_vm_printf("(%s)", c->val);
2322 }
2323 else if (inst == BC_INST_CALL ||
2324 (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
2325 {
2326 bc_program_printIndex(code, bgn);
2327 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
2328 }
2329
2330 bc_vm_putchar('\n', bc_flush_err);
2331 }
2332
bc_program_code(const BcProgram * p)2333 void bc_program_code(const BcProgram* p) {
2334
2335 BcFunc *f;
2336 char *code;
2337 BcInstPtr ip;
2338 size_t i;
2339
2340 for (i = 0; i < p->fns.len; ++i) {
2341
2342 ip.idx = ip.len = 0;
2343 ip.func = i;
2344
2345 f = bc_vec_item(&p->fns, ip.func);
2346 code = f->code.v;
2347
2348 bc_vm_printf("func[%zu]:\n", ip.func);
2349 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
2350 bc_file_puts(&vm.fout, bc_flush_err, "\n\n");
2351 }
2352 }
2353 #endif // BC_ENABLED && DC_ENABLED
2354 #endif // BC_DEBUG_CODE
2355