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