]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/src/program.c
Update to version 3.2.0
[FreeBSD/FreeBSD.git] / contrib / bc / src / program.c
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2020 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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_npop(&f->code, f->code.len);
458
459         s = bc_read_line(&buf, BC_IS_BC ? "read> " : "?> ");
460         if (s == BC_STATUS_EOF) bc_vm_err(BC_ERR_EXEC_READ_EXPR);
461
462         bc_parse_text(&parse, buf.v);
463         vm.expr(&parse, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
464
465         if (BC_ERR(parse.l.t != BC_LEX_NLINE && parse.l.t != BC_LEX_EOF))
466                 bc_vm_err(BC_ERR_EXEC_READ_EXPR);
467
468 #if BC_ENABLED
469         if (BC_G) bc_program_prepGlobals(p);
470 #endif // BC_ENABLED
471
472         ip.func = BC_PROG_READ;
473         ip.idx = 0;
474         ip.len = p->results.len;
475
476         // Update this pointer, just in case.
477         f = bc_vec_item(&p->fns, BC_PROG_READ);
478
479         bc_vec_pushByte(&f->code, vm.read_ret);
480         bc_vec_push(&p->stack, &ip);
481
482 #if DC_ENABLED
483         if (BC_IS_DC) {
484                 size_t temp = 0;
485                 bc_vec_push(&p->tail_calls, &temp);
486         }
487 #endif // DC_ENABLED
488
489 exec_err:
490         BC_SIG_MAYLOCK;
491         bc_parse_free(&parse);
492         bc_vec_free(&buf);
493         vm.file = file;
494         BC_LONGJMP_CONT;
495 }
496
497 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
498 static void bc_program_rand(BcProgram *p) {
499         BcRand rand = bc_rand_int(&p->rng);
500         bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
501 #ifndef NDEBUG
502         {
503                 BcResult *r = bc_vec_top(&p->results);
504                 assert(BC_NUM_RDX_VALID_NP(r->d.n));
505         }
506 #endif // NDEBUG
507 }
508 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
509
510 static void bc_program_printChars(const char *str) {
511
512         const char *nl;
513         size_t len = vm.nchars + strlen(str);
514
515         bc_file_puts(&vm.fout, str);
516         nl = strrchr(str, '\n');
517
518         if (nl != NULL) len = strlen(nl + 1);
519
520         vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
521 }
522
523 static void bc_program_printString(const char *restrict str) {
524
525         size_t i, len = strlen(str);
526
527 #if DC_ENABLED
528         if (!len && BC_IS_DC) {
529                 bc_vm_putchar('\0');
530                 return;
531         }
532 #endif // DC_ENABLED
533
534         for (i = 0; i < len; ++i) {
535
536                 int c = str[i];
537
538                 if (c == '\\' && i != len - 1) {
539
540                         const char *ptr;
541
542                         c = str[++i];
543                         ptr = strchr(bc_program_esc_chars, c);
544
545                         if (ptr != NULL) {
546                                 if (c == 'n') vm.nchars = UINT16_MAX;
547                                 c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
548                         }
549                         else {
550                                 // Just print the backslash. The following
551                                 // character will be printed later.
552                                 bc_vm_putchar('\\');
553                         }
554                 }
555
556                 bc_vm_putchar(c);
557         }
558 }
559
560 static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
561
562         BcResult *r;
563         char *str;
564         BcNum *n;
565         bool pop = (inst != BC_INST_PRINT);
566
567         assert(p != NULL);
568
569 #ifndef BC_PROG_NO_STACK_CHECK
570         if (BC_IS_DC) {
571                 if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
572                         bc_vm_err(BC_ERR_EXEC_STACK);
573         }
574 #endif // BC_PROG_NO_STACK_CHECK
575
576         assert(BC_PROG_STACK(&p->results, idx + 1));
577
578         r = bc_vec_item_rev(&p->results, idx);
579
580 #if BC_ENABLED
581         if (r->t == BC_RESULT_VOID) {
582                 if (BC_ERR(pop)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
583                 bc_vec_pop(&p->results);
584                 return;
585         }
586 #endif // BC_ENABLED
587
588         n = bc_program_num(p, r);
589
590         if (BC_PROG_NUM(r, n)) {
591                 assert(inst != BC_INST_PRINT_STR);
592                 bc_num_print(n, BC_PROG_OBASE(p), !pop);
593 #if BC_ENABLED
594                 if (BC_IS_BC) bc_num_copy(&p->last, n);
595 #endif // BC_ENABLED
596         }
597         else {
598
599                 size_t i = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
600
601                 bc_file_flush(&vm.fout);
602                 str = *((char**) bc_vec_item(p->strs, i));
603
604                 if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
605                 else {
606                         bc_program_printString(str);
607                         if (inst == BC_INST_PRINT) bc_vm_putchar('\n');
608                 }
609         }
610
611         if (BC_IS_BC || pop) bc_vec_pop(&p->results);
612 }
613
614 void bc_program_negate(BcResult *r, BcNum *n) {
615         bc_num_copy(&r->d.n, n);
616         if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
617 }
618
619 void bc_program_not(BcResult *r, BcNum *n) {
620         if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
621 }
622
623 #if BC_ENABLE_EXTRA_MATH
624 void bc_program_trunc(BcResult *r, BcNum *n) {
625         bc_num_copy(&r->d.n, n);
626         bc_num_truncate(&r->d.n, n->scale);
627 }
628 #endif // BC_ENABLE_EXTRA_MATH
629
630 static void bc_program_unary(BcProgram *p, uchar inst) {
631
632         BcResult *res, *ptr;
633         BcNum *num;
634
635         res = bc_program_prepResult(p);
636
637         bc_program_prep(p, &ptr, &num, 1);
638
639         BC_SIG_LOCK;
640
641         bc_num_init(&res->d.n, num->len);
642
643         BC_SIG_UNLOCK;
644
645         bc_program_unarys[inst - BC_INST_NEG](res, num);
646         bc_program_retire(p, 1, 1);
647 }
648
649 static void bc_program_logical(BcProgram *p, uchar inst) {
650
651         BcResult *opd1, *opd2, *res;
652         BcNum *n1, *n2;
653         bool cond = 0;
654         ssize_t cmp;
655
656         res = bc_program_prepResult(p);
657
658         bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
659
660         if (inst == BC_INST_BOOL_AND)
661                 cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
662         else if (inst == BC_INST_BOOL_OR)
663                 cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
664         else {
665
666                 cmp = bc_num_cmp(n1, n2);
667
668                 switch (inst) {
669
670                         case BC_INST_REL_EQ:
671                         {
672                                 cond = (cmp == 0);
673                                 break;
674                         }
675
676                         case BC_INST_REL_LE:
677                         {
678                                 cond = (cmp <= 0);
679                                 break;
680                         }
681
682                         case BC_INST_REL_GE:
683                         {
684                                 cond = (cmp >= 0);
685                                 break;
686                         }
687
688                         case BC_INST_REL_NE:
689                         {
690                                 cond = (cmp != 0);
691                                 break;
692                         }
693
694                         case BC_INST_REL_LT:
695                         {
696                                 cond = (cmp < 0);
697                                 break;
698                         }
699
700                         case BC_INST_REL_GT:
701                         {
702                                 cond = (cmp > 0);
703                                 break;
704                         }
705 #ifndef NDEBUG
706                         default:
707                         {
708                                 abort();
709                         }
710 #endif // NDEBUG
711                 }
712         }
713
714         BC_SIG_LOCK;
715
716         bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
717
718         BC_SIG_UNLOCK;
719
720         if (cond) bc_num_one(&res->d.n);
721
722         bc_program_retire(p, 1, 2);
723 }
724
725 #if DC_ENABLED
726 static void bc_program_assignStr(BcProgram *p, BcResult *r,
727                                  BcVec *v, bool push)
728 {
729         BcNum n2;
730
731         bc_num_clear(&n2);
732         n2.scale = r->d.loc.loc;
733
734         assert(BC_PROG_STACK(&p->results, 1 + !push));
735
736         if (!push) bc_vec_pop(v);
737
738         bc_vec_npop(&p->results, 1 + !push);
739         bc_vec_push(v, &n2);
740 }
741 #endif // DC_ENABLED
742
743 static void bc_program_copyToVar(BcProgram *p, size_t idx,
744                                  BcType t, bool last)
745 {
746         BcResult *ptr = NULL, r;
747         BcVec *vec;
748         BcNum *n = NULL;
749         bool var = (t == BC_TYPE_VAR);
750
751 #if DC_ENABLED
752         if (BC_IS_DC) {
753
754                 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
755                         bc_vm_err(BC_ERR_EXEC_STACK);
756
757                 assert(BC_PROG_STACK(&p->results, 1));
758
759                 bc_program_operand(p, &ptr, &n, 0);
760         }
761 #endif
762
763 #if BC_ENABLED
764         if (BC_IS_BC)
765         {
766                 ptr = bc_vec_top(&p->results);
767
768                 bc_program_type_match(ptr, t);
769
770                 if (last) n = bc_program_num(p, ptr);
771                 else if (var)
772                         n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
773         }
774 #endif // BC_ENABLED
775
776         vec = bc_program_vec(p, idx, t);
777
778 #if DC_ENABLED
779         if (BC_IS_DC && (ptr->t == BC_RESULT_STR || BC_PROG_STR(n))) {
780                 if (BC_ERR(!var)) bc_vm_err(BC_ERR_EXEC_TYPE);
781                 bc_program_assignStr(p, ptr, vec, true);
782                 return;
783         }
784 #endif // DC_ENABLED
785
786         BC_SIG_LOCK;
787
788         if (var) bc_num_createCopy(&r.d.n, n);
789         else {
790
791                 BcVec *v = (BcVec*) n, *rv = &r.d.v;
792 #if BC_ENABLED
793                 BcVec *parent;
794                 bool ref, ref_size;
795
796                 parent = bc_program_vec(p, ptr->d.loc.loc, t);
797                 assert(parent != NULL);
798
799                 if (!last) v = bc_vec_item_rev(parent, !last);
800                 assert(v != NULL);
801
802                 ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
803                 ref_size = (v->size == sizeof(uchar));
804
805                 if (ref || (ref_size && t == BC_TYPE_REF)) {
806
807                         bc_vec_init(rv, sizeof(uchar), NULL);
808
809                         if (ref) {
810
811                                 assert(parent->len >= (size_t) (!last + 1));
812
813                                 // Make sure the pointer was not invalidated.
814                                 vec = bc_program_vec(p, idx, t);
815
816                                 bc_vec_pushIndex(rv, ptr->d.loc.loc);
817                                 bc_vec_pushIndex(rv, parent->len - !last - 1);
818                         }
819                         // If we get here, we are copying a ref to a ref.
820                         else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
821
822                         // We need to return early.
823                         bc_vec_push(vec, &r.d);
824                         bc_vec_pop(&p->results);
825
826                         BC_SIG_UNLOCK;
827                         return;
828                 }
829                 else if (ref_size && t != BC_TYPE_REF) v = bc_program_dereference(p, v);
830 #endif // BC_ENABLED
831
832                 bc_array_init(rv, true);
833                 bc_array_copy(rv, v);
834         }
835
836         bc_vec_push(vec, &r.d);
837         bc_vec_pop(&p->results);
838
839         BC_SIG_UNLOCK;
840 }
841
842 static void bc_program_assign(BcProgram *p, uchar inst) {
843
844         BcResult *left, *right, res;
845         BcNum *l, *r;
846         bool ob, sc, use_val = BC_INST_USE_VAL(inst);
847
848         bc_program_assignPrep(p, &left, &l, &right, &r);
849
850 #if DC_ENABLED
851         assert(left->t != BC_RESULT_STR);
852
853         if (right->t == BC_RESULT_STR || BC_PROG_STR(r)) {
854
855                 size_t idx = right->t == BC_RESULT_STR ? right->d.loc.loc : r->scale;
856
857                 if (left->t == BC_RESULT_ARRAY_ELEM) {
858                         BC_SIG_LOCK;
859                         bc_num_free(l);
860                         bc_num_clear(l);
861                         l->scale = idx;
862                         bc_vec_npop(&p->results, 2);
863                         BC_SIG_UNLOCK;
864                 }
865                 else {
866                         BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
867                         bc_program_assignStr(p, right, v, false);
868                 }
869
870                 return;
871         }
872 #endif // DC_ENABLED
873
874         if (BC_INST_IS_ASSIGN(inst)) bc_num_copy(l, r);
875 #if BC_ENABLED
876         else {
877
878                 BcBigDig scale = BC_PROG_SCALE(p);
879
880                 if (!use_val)
881                         inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
882
883                 assert(BC_NUM_RDX_VALID(l));
884                 assert(BC_NUM_RDX_VALID(r));
885
886                 bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
887         }
888 #endif // BC_ENABLED
889
890         ob = (left->t == BC_RESULT_OBASE);
891         sc = (left->t == BC_RESULT_SCALE);
892
893         if (ob || sc || left->t == BC_RESULT_IBASE) {
894
895                 BcVec *v;
896                 BcBigDig *ptr, *ptr_t, val, max, min;
897                 BcErr e;
898
899                 bc_num_bigdig(l, &val);
900                 e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
901
902                 if (sc) {
903                         min = 0;
904                         max = vm.maxes[BC_PROG_GLOBALS_SCALE];
905                         v = p->globals_v + BC_PROG_GLOBALS_SCALE;
906                         ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
907                 }
908                 else {
909                         min = BC_NUM_MIN_BASE;
910                         if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
911                                 min = 0;
912                         max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
913                         v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
914                         ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
915                 }
916
917                 if (BC_ERR(val > max || val < min)) bc_vm_verr(e, min, max);
918
919                 ptr = bc_vec_top(v);
920                 *ptr = val;
921                 *ptr_t = val;
922         }
923 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
924         else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
925 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
926
927         BC_SIG_LOCK;
928
929         if (use_val) {
930                 bc_num_createCopy(&res.d.n, l);
931                 res.t = BC_RESULT_TEMP;
932                 bc_vec_npop(&p->results, 2);
933                 bc_vec_push(&p->results, &res);
934         }
935         else bc_vec_npop(&p->results, 2);
936
937         BC_SIG_UNLOCK;
938 }
939
940 static void bc_program_pushVar(BcProgram *p, const char *restrict code,
941                                size_t *restrict bgn, bool pop, bool copy)
942 {
943         BcResult r;
944         size_t idx = bc_program_index(code, bgn);
945
946         r.t = BC_RESULT_VAR;
947         r.d.loc.loc = idx;
948
949 #if DC_ENABLED
950         if (BC_IS_DC && (pop || copy)) {
951
952                 BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
953                 BcNum *num = bc_vec_top(v);
954
955                 if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) bc_vm_err(BC_ERR_EXEC_STACK);
956
957                 assert(BC_PROG_STACK(v, 2 - copy));
958
959                 if (!BC_PROG_STR(num)) {
960
961                         BC_SIG_LOCK;
962
963                         r.t = BC_RESULT_TEMP;
964                         bc_num_createCopy(&r.d.n, num);
965
966                         if (!copy) bc_vec_pop(v);
967
968                         bc_vec_push(&p->results, &r);
969
970                         BC_SIG_UNLOCK;
971
972                         return;
973                 }
974                 else {
975                         r.d.loc.loc = num->scale;
976                         r.t = BC_RESULT_STR;
977                 }
978
979                 if (!copy) bc_vec_pop(v);
980         }
981 #endif // DC_ENABLED
982
983         bc_vec_push(&p->results, &r);
984 }
985
986 static void bc_program_pushArray(BcProgram *p, const char *restrict code,
987                                  size_t *restrict bgn, uchar inst)
988 {
989         BcResult r, *operand;
990         BcNum *num;
991         BcBigDig temp;
992
993         r.d.loc.loc = bc_program_index(code, bgn);
994
995 #if BC_ENABLED
996         if (inst == BC_INST_ARRAY) {
997                 r.t = BC_RESULT_ARRAY;
998                 bc_vec_push(&p->results, &r);
999                 return;
1000         }
1001 #endif // BC_ENABLED
1002
1003         bc_program_prep(p, &operand, &num, 0);
1004         bc_num_bigdig(num, &temp);
1005
1006         r.t = BC_RESULT_ARRAY_ELEM;
1007         r.d.loc.idx = (size_t) temp;
1008
1009         BC_SIG_LOCK;
1010
1011         bc_vec_pop(&p->results);
1012         bc_vec_push(&p->results, &r);
1013
1014         BC_SIG_UNLOCK;
1015 }
1016
1017 #if BC_ENABLED
1018 static void bc_program_incdec(BcProgram *p, uchar inst) {
1019
1020         BcResult *ptr, res, copy;
1021         BcNum *num;
1022         uchar inst2;
1023
1024         bc_program_prep(p, &ptr, &num, 0);
1025
1026         BC_SIG_LOCK;
1027
1028         copy.t = BC_RESULT_TEMP;
1029         bc_num_createCopy(&copy.d.n, num);
1030
1031         BC_SETJMP_LOCKED(exit);
1032
1033         BC_SIG_UNLOCK;
1034
1035         res.t = BC_RESULT_ONE;
1036         inst2 = BC_INST_ASSIGN_PLUS + (inst & 0x01);
1037
1038         bc_vec_push(&p->results, &res);
1039         bc_program_assign(p, inst2);
1040
1041         BC_SIG_LOCK;
1042
1043         bc_vec_pop(&p->results);
1044         bc_vec_push(&p->results, &copy);
1045
1046         BC_UNSETJMP;
1047
1048         BC_SIG_UNLOCK;
1049
1050         return;
1051
1052 exit:
1053         BC_SIG_MAYLOCK;
1054         bc_num_free(&copy.d.n);
1055         BC_LONGJMP_CONT;
1056 }
1057
1058 static void bc_program_call(BcProgram *p, const char *restrict code,
1059                             size_t *restrict idx)
1060 {
1061         BcInstPtr ip;
1062         size_t i, nparams = bc_program_index(code, idx);
1063         BcFunc *f;
1064         BcVec *v;
1065         BcLoc *a;
1066         BcResultData param;
1067         BcResult *arg;
1068
1069         ip.idx = 0;
1070         ip.func = bc_program_index(code, idx);
1071         f = bc_vec_item(&p->fns, ip.func);
1072
1073         if (BC_ERR(!f->code.len)) bc_vm_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1074         if (BC_ERR(nparams != f->nparams))
1075                 bc_vm_verr(BC_ERR_EXEC_PARAMS, f->nparams, nparams);
1076         ip.len = p->results.len - nparams;
1077
1078         assert(BC_PROG_STACK(&p->results, nparams));
1079
1080         if (BC_G) bc_program_prepGlobals(p);
1081
1082         for (i = 0; i < nparams; ++i) {
1083
1084                 size_t j;
1085                 bool last = true;
1086
1087                 arg = bc_vec_top(&p->results);
1088                 if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_vm_err(BC_ERR_EXEC_VOID_VAL);
1089
1090                 a = bc_vec_item(&f->autos, nparams - 1 - i);
1091
1092                 // If I have already pushed to a var, I need to make sure I
1093                 // get the previous version, not the already pushed one.
1094                 if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
1095                         for (j = 0; j < i && last; ++j) {
1096                                 BcLoc *loc = bc_vec_item(&f->autos, nparams - 1 - j);
1097                                 last = (arg->d.loc.loc != loc->loc ||
1098                                         (!loc->idx) != (arg->t == BC_RESULT_VAR));
1099                         }
1100                 }
1101
1102                 bc_program_copyToVar(p, a->loc, (BcType) a->idx, last);
1103         }
1104
1105         BC_SIG_LOCK;
1106
1107         for (; i < f->autos.len; ++i) {
1108
1109                 a = bc_vec_item(&f->autos, i);
1110                 v = bc_program_vec(p, a->loc, (BcType) a->idx);
1111
1112                 if (a->idx == BC_TYPE_VAR) {
1113                         bc_num_init(&param.n, BC_NUM_DEF_SIZE);
1114                         bc_vec_push(v, &param.n);
1115                 }
1116                 else {
1117                         assert(a->idx == BC_TYPE_ARRAY);
1118                         bc_array_init(&param.v, true);
1119                         bc_vec_push(v, &param.v);
1120                 }
1121         }
1122
1123         bc_vec_push(&p->stack, &ip);
1124
1125         BC_SIG_UNLOCK;
1126 }
1127
1128 static void bc_program_return(BcProgram *p, uchar inst) {
1129
1130         BcResult *res;
1131         BcFunc *f;
1132         BcInstPtr *ip = bc_vec_top(&p->stack);
1133         size_t i, nops = p->results.len - ip->len;
1134
1135         assert(BC_PROG_STACK(&p->stack, 2));
1136         assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1137
1138         f = bc_vec_item(&p->fns, ip->func);
1139         res = bc_program_prepResult(p);
1140
1141         if (inst == BC_INST_RET) {
1142
1143                 BcNum *num;
1144                 BcResult *operand;
1145
1146                 bc_program_operand(p, &operand, &num, 1);
1147
1148                 BC_SIG_LOCK;
1149
1150                 bc_num_createCopy(&res->d.n, num);
1151         }
1152         else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1153         else {
1154                 BC_SIG_LOCK;
1155                 bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1156         }
1157
1158         BC_SIG_MAYUNLOCK;
1159
1160         // We need to pop arguments as well, so this takes that into account.
1161         for (i = 0; i < f->autos.len; ++i) {
1162
1163                 BcLoc *a = bc_vec_item(&f->autos, i);
1164                 BcVec *v = bc_program_vec(p, a->loc, (BcType) a->idx);
1165
1166                 bc_vec_pop(v);
1167         }
1168
1169         bc_program_retire(p, 1, nops);
1170
1171         if (BC_G) bc_program_popGlobals(p, false);
1172
1173         bc_vec_pop(&p->stack);
1174 }
1175 #endif // BC_ENABLED
1176
1177 static void bc_program_builtin(BcProgram *p, uchar inst) {
1178
1179         BcResult *opd, *res;
1180         BcNum *num;
1181         bool len = (inst == BC_INST_LENGTH);
1182
1183 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1184         assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1185 #else // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1186         assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
1187 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1188
1189 #ifndef BC_PROG_NO_STACK_CHECK
1190         if (BC_IS_DC) {
1191                 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1192                         bc_vm_err(BC_ERR_EXEC_STACK);
1193         }
1194 #endif // BC_PROG_NO_STACK_CHECK
1195
1196         assert(BC_PROG_STACK(&p->results, 1));
1197
1198         res = bc_program_prepResult(p);
1199
1200         bc_program_operand(p, &opd, &num, 1);
1201
1202         assert(num != NULL);
1203
1204 #if DC_ENABLED
1205         if (!len && inst != BC_INST_SCALE_FUNC) bc_program_type_num(opd, num);
1206 #endif // DC_ENABLED
1207
1208         if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1209         else if (inst == BC_INST_ABS) {
1210
1211                 BC_SIG_LOCK;
1212
1213                 bc_num_createCopy(&res->d.n, num);
1214
1215                 BC_SIG_UNLOCK;
1216
1217                 BC_NUM_NEG_CLR_NP(res->d.n);
1218         }
1219 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1220         else if (inst == BC_INST_IRAND) {
1221
1222                 BC_SIG_LOCK;
1223
1224                 bc_num_init(&res->d.n, num->len - num->rdx);
1225
1226                 BC_SIG_UNLOCK;
1227
1228                 bc_num_irand(num, &res->d.n, &p->rng);
1229         }
1230 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1231         else {
1232
1233                 BcBigDig val = 0;
1234
1235                 if (len) {
1236 #if BC_ENABLED
1237                         if (BC_IS_BC && opd->t == BC_RESULT_ARRAY) {
1238
1239                                 BcVec *v = (BcVec*) num;
1240
1241                                 if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
1242
1243                                 assert(v->size == sizeof(BcNum));
1244
1245                                 val = (BcBigDig) v->len;
1246                         }
1247                         else
1248 #endif // BC_ENABLED
1249                         {
1250 #if DC_ENABLED
1251                                 if (!BC_PROG_NUM(opd, num)) {
1252                                         size_t idx;
1253                                         char *str;
1254                                         idx = opd->t == BC_RESULT_STR ? opd->d.loc.loc : num->scale;
1255                                         str = *((char**) bc_vec_item(p->strs, idx));
1256                                         val = (BcBigDig) strlen(str);
1257                                 }
1258                                 else
1259 #endif // DC_ENABLED
1260                                 {
1261                                         val = (BcBigDig) bc_num_len(num);
1262                                 }
1263                         }
1264                 }
1265                 else if (BC_IS_BC || BC_PROG_NUM(opd, num))
1266                         val = (BcBigDig) bc_num_scale(num);
1267
1268                 BC_SIG_LOCK;
1269
1270                 bc_num_createFromBigdig(&res->d.n, val);
1271
1272                 BC_SIG_UNLOCK;
1273         }
1274
1275         bc_program_retire(p, 1, 1);
1276 }
1277
1278 #if DC_ENABLED
1279 static void bc_program_divmod(BcProgram *p) {
1280
1281         BcResult *opd1, *opd2, *res, *res2;
1282         BcNum *n1, *n2;
1283         size_t req;
1284
1285         bc_vec_grow(&p->results, 2);
1286
1287         // We don't need to update the pointer because
1288         // the capacity is enough due to the line above.
1289         res2 = bc_program_prepResult(p);
1290         res = bc_program_prepResult(p);
1291
1292         bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
1293
1294         req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
1295
1296         BC_SIG_LOCK;
1297
1298         bc_num_init(&res->d.n, req);
1299         bc_num_init(&res2->d.n, req);
1300
1301         BC_SIG_UNLOCK;
1302
1303         bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
1304
1305         bc_program_retire(p, 2, 2);
1306 }
1307
1308 static void bc_program_modexp(BcProgram *p) {
1309
1310         BcResult *r1, *r2, *r3, *res;
1311         BcNum *n1, *n2, *n3;
1312
1313         if (BC_ERR(!BC_PROG_STACK(&p->results, 3))) bc_vm_err(BC_ERR_EXEC_STACK);
1314
1315         assert(BC_PROG_STACK(&p->results, 3));
1316
1317         res = bc_program_prepResult(p);
1318
1319         bc_program_operand(p, &r1, &n1, 3);
1320         bc_program_type_num(r1, n1);
1321
1322         bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
1323
1324         // Make sure that the values have their pointers updated, if necessary.
1325         // Only array elements are possible.
1326         if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
1327                 n1 = bc_program_num(p, r1);
1328
1329         BC_SIG_LOCK;
1330
1331         bc_num_init(&res->d.n, n3->len);
1332
1333         BC_SIG_UNLOCK;
1334
1335         bc_num_modexp(n1, n2, n3, &res->d.n);
1336
1337         bc_program_retire(p, 1, 3);
1338 }
1339
1340 static void bc_program_stackLen(BcProgram *p) {
1341         bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
1342 }
1343
1344 static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
1345
1346         BcNum num;
1347         BcBigDig val = 0;
1348
1349         bc_num_clear(&num);
1350
1351         BC_SETJMP(num_err);
1352
1353         BC_SIG_LOCK;
1354
1355         bc_num_createCopy(&num, n);
1356
1357         BC_SIG_UNLOCK;
1358
1359         bc_num_truncate(&num, num.scale);
1360         BC_NUM_NEG_CLR_NP(num);
1361
1362         // This is guaranteed to not have a divide by 0
1363         // because strmb is equal to UCHAR_MAX + 1.
1364         bc_num_mod(&num, &p->strmb, &num, 0);
1365
1366         // This is also guaranteed to not error because num is in the range
1367         // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
1368         // it is not negative.
1369         bc_num_bigdig2(&num, &val);
1370
1371 num_err:
1372         BC_SIG_MAYLOCK;
1373         bc_num_free(&num);
1374         BC_LONGJMP_CONT;
1375         return (uchar) val;
1376 }
1377
1378 static void bc_program_asciify(BcProgram *p) {
1379
1380         BcResult *r, res;
1381         BcNum *n;
1382         char str[2], *str2;
1383         uchar c;
1384         size_t idx;
1385
1386         if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1387
1388         assert(BC_PROG_STACK(&p->results, 1));
1389
1390         bc_program_operand(p, &r, &n, 0);
1391
1392         assert(n != NULL);
1393
1394         assert(p->strs->len + BC_PROG_REQ_FUNCS == p->fns.len);
1395
1396         if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
1397         else {
1398                 size_t index = r->t == BC_RESULT_STR ? r->d.loc.loc : n->scale;
1399                 str2 = *((char**) bc_vec_item(p->strs, index));
1400                 c = (uchar) str2[0];
1401         }
1402
1403         str[0] = (char) c;
1404         str[1] = '\0';
1405
1406         BC_SIG_LOCK;
1407
1408         idx = bc_program_insertFunc(p, str) - BC_PROG_REQ_FUNCS;
1409
1410         BC_SIG_UNLOCK;
1411
1412         res.t = BC_RESULT_STR;
1413         res.d.loc.loc = idx;
1414         bc_vec_pop(&p->results);
1415         bc_vec_push(&p->results, &res);
1416 }
1417
1418 static void bc_program_printStream(BcProgram *p) {
1419
1420         BcResult *r;
1421         BcNum *n;
1422
1423         if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1424
1425         assert(BC_PROG_STACK(&p->results, 1));
1426
1427         bc_program_operand(p, &r, &n, 0);
1428
1429         assert(n != NULL);
1430
1431         if (BC_PROG_NUM(r, n)) bc_num_stream(n, p->strm);
1432         else {
1433                 size_t idx = (r->t == BC_RESULT_STR) ? r->d.loc.loc : n->scale;
1434                 bc_program_printChars(*((char**) bc_vec_item(p->strs, idx)));
1435         }
1436 }
1437
1438 static void bc_program_nquit(BcProgram *p, uchar inst) {
1439
1440         BcResult *opnd;
1441         BcNum *num;
1442         BcBigDig val;
1443         size_t i;
1444
1445         assert(p->stack.len == p->tail_calls.len);
1446
1447         if (inst == BC_INST_QUIT) val = 2;
1448         else {
1449
1450                 bc_program_prep(p, &opnd, &num, 0);
1451                 bc_num_bigdig(num, &val);
1452
1453                 bc_vec_pop(&p->results);
1454         }
1455
1456         for (i = 0; val && i < p->tail_calls.len; ++i) {
1457                 size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
1458                 if (calls >= val) val = 0;
1459                 else val -= calls;
1460         }
1461
1462         if (i == p->stack.len) {
1463                 vm.status = BC_STATUS_QUIT;
1464                 BC_VM_JMP;
1465         }
1466         else {
1467                 bc_vec_npop(&p->stack, i);
1468                 bc_vec_npop(&p->tail_calls, i);
1469         }
1470 }
1471
1472 static void bc_program_execStr(BcProgram *p, const char *restrict code,
1473                                    size_t *restrict bgn, bool cond, size_t len)
1474 {
1475         BcResult *r;
1476         char *str;
1477         BcFunc *f;
1478         BcParse prs;
1479         BcInstPtr ip;
1480         size_t fidx, sidx;
1481         BcNum *n;
1482
1483         assert(p->stack.len == p->tail_calls.len);
1484
1485         if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_vm_err(BC_ERR_EXEC_STACK);
1486
1487         assert(BC_PROG_STACK(&p->results, 1));
1488
1489         bc_program_operand(p, &r, &n, 0);
1490
1491         if (cond) {
1492
1493                 bool exec;
1494                 size_t idx, then_idx, else_idx;
1495
1496                 then_idx = bc_program_index(code, bgn);
1497                 else_idx = bc_program_index(code, bgn);
1498
1499                 exec = (r->d.n.len != 0);
1500
1501                 idx = exec ? then_idx : else_idx;
1502
1503                 BC_SIG_LOCK;
1504                 BC_SETJMP_LOCKED(exit);
1505
1506                 if (exec || (else_idx != SIZE_MAX))
1507                         n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
1508                 else goto exit;
1509
1510                 if (BC_ERR(!BC_PROG_STR(n))) bc_vm_err(BC_ERR_EXEC_TYPE);
1511
1512                 BC_UNSETJMP;
1513                 BC_SIG_UNLOCK;
1514
1515                 sidx = n->scale;
1516         }
1517         else {
1518
1519                 // In non-conditional situations, only the top of stack can be executed,
1520                 // and in those cases, variables are not allowed to be "on the stack";
1521                 // they are only put on the stack to be assigned to.
1522                 assert(r->t != BC_RESULT_VAR);
1523
1524                 if (r->t == BC_RESULT_STR) sidx = r->d.loc.loc;
1525                 else return;
1526         }
1527
1528         fidx = sidx + BC_PROG_REQ_FUNCS;
1529         str = *((char**) bc_vec_item(p->strs, sidx));
1530         f = bc_vec_item(&p->fns, fidx);
1531
1532         if (!f->code.len) {
1533
1534                 BC_SIG_LOCK;
1535
1536                 bc_parse_init(&prs, p, fidx);
1537                 bc_lex_file(&prs.l, vm.file);
1538
1539                 BC_SETJMP_LOCKED(err);
1540
1541                 BC_SIG_UNLOCK;
1542
1543                 bc_parse_text(&prs, str);
1544                 vm.expr(&prs, BC_PARSE_NOCALL);
1545
1546                 BC_SIG_LOCK;
1547
1548                 BC_UNSETJMP;
1549
1550                 // We can just assert this here because
1551                 // dc should parse everything until EOF.
1552                 assert(prs.l.t == BC_LEX_EOF);
1553
1554                 bc_parse_free(&prs);
1555
1556                 BC_SIG_UNLOCK;
1557         }
1558
1559         ip.idx = 0;
1560         ip.len = p->results.len;
1561         ip.func = fidx;
1562
1563         bc_vec_pop(&p->results);
1564
1565         // Tail call.
1566         if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
1567                 size_t *call_ptr = bc_vec_top(&p->tail_calls);
1568                 *call_ptr += 1;
1569                 bc_vec_pop(&p->stack);
1570         }
1571         else bc_vec_push(&p->tail_calls, &ip.idx);
1572
1573         bc_vec_push(&p->stack, &ip);
1574
1575         return;
1576
1577 err:
1578         BC_SIG_MAYLOCK;
1579         bc_parse_free(&prs);
1580         f = bc_vec_item(&p->fns, fidx);
1581         bc_vec_npop(&f->code, f->code.len);
1582 exit:
1583         bc_vec_pop(&p->results);
1584         BC_LONGJMP_CONT;
1585 }
1586
1587 static void bc_program_printStack(BcProgram *p) {
1588
1589         size_t idx;
1590
1591         for (idx = 0; idx < p->results.len; ++idx)
1592                 bc_program_print(p, BC_INST_PRINT, idx);
1593 }
1594 #endif // DC_ENABLED
1595
1596 static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
1597
1598         BcResultType t;
1599
1600         assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
1601
1602         t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
1603         bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
1604 }
1605
1606 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1607 static void bc_program_pushSeed(BcProgram *p) {
1608
1609         BcResult *res;
1610
1611         res = bc_program_prepResult(p);
1612         res->t = BC_RESULT_SEED;
1613
1614         BC_SIG_LOCK;
1615
1616         bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
1617
1618         BC_SIG_UNLOCK;
1619
1620         bc_num_createFromRNG(&res->d.n, &p->rng);
1621 }
1622 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1623
1624 static void bc_program_addFunc(BcProgram *p, BcFunc *f, BcId *id_ptr) {
1625
1626         BcInstPtr *ip;
1627
1628         BC_SIG_ASSERT_LOCKED;
1629
1630         bc_func_init(f, id_ptr->name);
1631         bc_vec_push(&p->fns, f);
1632
1633         // This is to make sure pointers are updated if the array was moved.
1634         if (p->stack.len) {
1635                 ip = bc_vec_top(&p->stack);
1636                 bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
1637         }
1638 }
1639
1640 size_t bc_program_insertFunc(BcProgram *p, const char *name) {
1641
1642         BcId *id_ptr;
1643         BcFunc f;
1644         bool new;
1645         size_t idx;
1646
1647         BC_SIG_ASSERT_LOCKED;
1648
1649         assert(p != NULL && name != NULL);
1650
1651         new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
1652         id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
1653         idx = id_ptr->idx;
1654
1655         if (!new) {
1656                 if (BC_IS_BC) {
1657                         BcFunc *func = bc_vec_item(&p->fns, idx);
1658                         bc_func_reset(func);
1659                 }
1660         }
1661         else {
1662
1663                 bc_program_addFunc(p, &f, id_ptr);
1664
1665 #if DC_ENABLED
1666                 if (BC_IS_DC && idx >= BC_PROG_REQ_FUNCS) {
1667                         bc_vec_push(p->strs, &id_ptr->name);
1668                         assert(p->strs->len == p->fns.len - BC_PROG_REQ_FUNCS);
1669                 }
1670 #endif // DC_ENABLED
1671         }
1672
1673         return idx;
1674 }
1675
1676 #ifndef NDEBUG
1677 void bc_program_free(BcProgram *p) {
1678
1679         size_t i;
1680
1681         BC_SIG_ASSERT_LOCKED;
1682
1683         assert(p != NULL);
1684
1685         for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
1686
1687         bc_vec_free(&p->fns);
1688         bc_vec_free(&p->fn_map);
1689         bc_vec_free(&p->vars);
1690         bc_vec_free(&p->var_map);
1691         bc_vec_free(&p->arrs);
1692         bc_vec_free(&p->arr_map);
1693         bc_vec_free(&p->results);
1694         bc_vec_free(&p->stack);
1695
1696 #if BC_ENABLED
1697         if (BC_IS_BC) bc_num_free(&p->last);
1698 #endif // BC_ENABLED
1699
1700 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1701         bc_rand_free(&p->rng);
1702 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1703
1704 #if DC_ENABLED
1705         if (BC_IS_DC) {
1706                 bc_vec_free(&p->tail_calls);
1707                 bc_vec_free(&p->strs_v);
1708         }
1709 #endif // DC_ENABLED
1710 }
1711 #endif // NDEBUG
1712
1713 void bc_program_init(BcProgram *p) {
1714
1715         BcInstPtr ip;
1716         size_t i;
1717         BcBigDig val = BC_BASE;
1718
1719         BC_SIG_ASSERT_LOCKED;
1720
1721         assert(p != NULL);
1722
1723         memset(p, 0, sizeof(BcProgram));
1724         memset(&ip, 0, sizeof(BcInstPtr));
1725
1726         for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
1727                 bc_vec_init(p->globals_v + i, sizeof(BcBigDig), NULL);
1728                 val = i == BC_PROG_GLOBALS_SCALE ? 0 : val;
1729                 bc_vec_push(p->globals_v + i, &val);
1730                 p->globals[i] = val;
1731         }
1732
1733 #if DC_ENABLED
1734         if (BC_IS_DC) {
1735
1736                 bc_vec_init(&p->strs_v, sizeof(char*), bc_string_free);
1737                 p->strs = &p->strs_v;
1738
1739                 bc_vec_init(&p->tail_calls, sizeof(size_t), NULL);
1740                 i = 0;
1741                 bc_vec_push(&p->tail_calls, &i);
1742
1743                 p->strm = UCHAR_MAX + 1;
1744                 bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
1745                 bc_num_bigdig2num(&p->strmb, p->strm);
1746         }
1747 #endif // DC_ENABLED
1748
1749 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1750         srand((unsigned int) time(NULL));
1751         bc_rand_init(&p->rng);
1752 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1753
1754         bc_num_setup(&p->zero, p->zero_num, BC_PROG_ONE_CAP);
1755
1756         bc_num_setup(&p->one, p->one_num, BC_PROG_ONE_CAP);
1757         bc_num_one(&p->one);
1758
1759 #if BC_ENABLED
1760         if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
1761 #endif // BC_ENABLED
1762
1763         bc_vec_init(&p->fns, sizeof(BcFunc), bc_func_free);
1764         bc_map_init(&p->fn_map);
1765         bc_program_insertFunc(p, bc_func_main);
1766         bc_program_insertFunc(p, bc_func_read);
1767
1768         bc_vec_init(&p->vars, sizeof(BcVec), bc_vec_free);
1769         bc_map_init(&p->var_map);
1770
1771         bc_vec_init(&p->arrs, sizeof(BcVec), bc_vec_free);
1772         bc_map_init(&p->arr_map);
1773
1774         bc_vec_init(&p->results, sizeof(BcResult), bc_result_free);
1775         bc_vec_init(&p->stack, sizeof(BcInstPtr), NULL);
1776         bc_vec_push(&p->stack, &ip);
1777
1778         bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
1779
1780         assert(p->consts != NULL && p->strs != NULL);
1781 }
1782
1783 void bc_program_reset(BcProgram *p) {
1784
1785         BcFunc *f;
1786         BcInstPtr *ip;
1787
1788         BC_SIG_ASSERT_LOCKED;
1789
1790         bc_vec_npop(&p->stack, p->stack.len - 1);
1791         bc_vec_npop(&p->results, p->results.len);
1792
1793 #if BC_ENABLED
1794         if (BC_G) bc_program_popGlobals(p, true);
1795 #endif // BC_ENABLED
1796
1797         f = bc_vec_item(&p->fns, BC_PROG_MAIN);
1798         ip = bc_vec_top(&p->stack);
1799         bc_program_setVecs(p, f);
1800         ip->idx = f->code.len;
1801
1802         if (vm.sig) {
1803                 bc_file_write(&vm.fout, bc_program_ready_msg, bc_program_ready_msg_len);
1804                 bc_file_flush(&vm.fout);
1805                 vm.sig = 0;
1806         }
1807 }
1808
1809 void bc_program_exec(BcProgram *p) {
1810
1811         size_t idx;
1812         BcResult r, *ptr;
1813         BcInstPtr *ip = bc_vec_top(&p->stack);
1814         BcFunc *func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
1815         char *code = func->code.v;
1816         bool cond = false;
1817 #if BC_ENABLED
1818         BcNum *num;
1819 #endif // BC_ENABLED
1820 #ifndef NDEBUG
1821         size_t jmp_bufs_len;
1822 #endif // NDEBUG
1823
1824 #ifndef NDEBUG
1825         jmp_bufs_len = vm.jmp_bufs.len;
1826 #endif // NDEBUG
1827
1828         bc_program_setVecs(p, func);
1829
1830         while (ip->idx < func->code.len) {
1831
1832                 BC_SIG_ASSERT_NOT_LOCKED;
1833
1834                 uchar inst = (uchar) code[(ip->idx)++];
1835
1836                 switch (inst) {
1837
1838 #if BC_ENABLED
1839                         case BC_INST_JUMP_ZERO:
1840                         {
1841                                 bc_program_prep(p, &ptr, &num, 0);
1842                                 cond = !bc_num_cmpZero(num);
1843                                 bc_vec_pop(&p->results);
1844                         }
1845                         // Fallthrough.
1846                         BC_FALLTHROUGH
1847
1848                         case BC_INST_JUMP:
1849                         {
1850                                 idx = bc_program_index(code, &ip->idx);
1851
1852                                 if (inst == BC_INST_JUMP || cond) {
1853
1854                                         size_t *addr = bc_vec_item(&func->labels, idx);
1855
1856                                         assert(*addr != SIZE_MAX);
1857
1858                                         ip->idx = *addr;
1859                                 }
1860
1861                                 break;
1862                         }
1863
1864                         case BC_INST_CALL:
1865                         {
1866                                 assert(BC_IS_BC);
1867
1868                                 bc_program_call(p, code, &ip->idx);
1869
1870                                 ip = bc_vec_top(&p->stack);
1871                                 func = bc_vec_item(&p->fns, ip->func);
1872                                 code = func->code.v;
1873
1874                                 bc_program_setVecs(p, func);
1875
1876                                 break;
1877                         }
1878
1879                         case BC_INST_INC:
1880                         case BC_INST_DEC:
1881                         {
1882                                 bc_program_incdec(p, inst);
1883                                 break;
1884                         }
1885
1886                         case BC_INST_HALT:
1887                         {
1888                                 vm.status = BC_STATUS_QUIT;
1889                                 BC_VM_JMP;
1890                                 break;
1891                         }
1892
1893                         case BC_INST_RET:
1894                         case BC_INST_RET0:
1895                         case BC_INST_RET_VOID:
1896                         {
1897                                 bc_program_return(p, inst);
1898
1899                                 ip = bc_vec_top(&p->stack);
1900                                 func = bc_vec_item(&p->fns, ip->func);
1901                                 code = func->code.v;
1902
1903                                 bc_program_setVecs(p, func);
1904
1905                                 break;
1906                         }
1907 #endif // BC_ENABLED
1908
1909                         case BC_INST_BOOL_OR:
1910                         case BC_INST_BOOL_AND:
1911                         case BC_INST_REL_EQ:
1912                         case BC_INST_REL_LE:
1913                         case BC_INST_REL_GE:
1914                         case BC_INST_REL_NE:
1915                         case BC_INST_REL_LT:
1916                         case BC_INST_REL_GT:
1917                         {
1918                                 bc_program_logical(p, inst);
1919                                 break;
1920                         }
1921
1922                         case BC_INST_READ:
1923                         {
1924                                 bc_program_read(p);
1925
1926                                 ip = bc_vec_top(&p->stack);
1927                                 func = bc_vec_item(&p->fns, ip->func);
1928                                 code = func->code.v;
1929
1930                                 bc_program_setVecs(p, func);
1931
1932                                 break;
1933                         }
1934
1935 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1936                         case BC_INST_RAND:
1937                         {
1938                                 bc_program_rand(p);
1939                                 break;
1940                         }
1941 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1942
1943                         case BC_INST_MAXIBASE:
1944                         case BC_INST_MAXOBASE:
1945                         case BC_INST_MAXSCALE:
1946 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1947                         case BC_INST_MAXRAND:
1948 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1949                         {
1950                                 BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
1951                                 bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
1952                                 break;
1953                         }
1954
1955                         case BC_INST_VAR:
1956                         {
1957                                 bc_program_pushVar(p, code, &ip->idx, false, false);
1958                                 break;
1959                         }
1960
1961                         case BC_INST_ARRAY_ELEM:
1962 #if BC_ENABLED
1963                         case BC_INST_ARRAY:
1964 #endif // BC_ENABLED
1965                         {
1966                                 bc_program_pushArray(p, code, &ip->idx, inst);
1967                                 break;
1968                         }
1969
1970                         case BC_INST_IBASE:
1971                         case BC_INST_SCALE:
1972                         case BC_INST_OBASE:
1973                         {
1974                                 bc_program_pushGlobal(p, inst);
1975                                 break;
1976                         }
1977
1978 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1979                         case BC_INST_SEED:
1980                         {
1981                                 bc_program_pushSeed(p);
1982                                 break;
1983                         }
1984 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1985
1986                         case BC_INST_LENGTH:
1987                         case BC_INST_SCALE_FUNC:
1988                         case BC_INST_SQRT:
1989                         case BC_INST_ABS:
1990 #if BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1991                         case BC_INST_IRAND:
1992 #endif // BC_ENABLE_EXTRA_MATH && BC_ENABLE_RAND
1993                         {
1994                                 bc_program_builtin(p, inst);
1995                                 break;
1996                         }
1997
1998                         case BC_INST_NUM:
1999                         {
2000                                 bc_program_const(p, code, &ip->idx);
2001                                 break;
2002                         }
2003
2004                         case BC_INST_ZERO:
2005                         case BC_INST_ONE:
2006 #if BC_ENABLED
2007                         case BC_INST_LAST:
2008 #endif // BC_ENABLED
2009                         {
2010                                 r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
2011                                 bc_vec_push(&p->results, &r);
2012                                 break;
2013                         }
2014
2015                         case BC_INST_PRINT:
2016                         case BC_INST_PRINT_POP:
2017                         case BC_INST_PRINT_STR:
2018                         {
2019                                 bc_program_print(p, inst, 0);
2020                                 break;
2021                         }
2022
2023                         case BC_INST_STR:
2024                         {
2025                                 r.t = BC_RESULT_STR;
2026                                 r.d.loc.loc = bc_program_index(code, &ip->idx);
2027                                 bc_vec_push(&p->results, &r);
2028                                 break;
2029                         }
2030
2031                         case BC_INST_POWER:
2032                         case BC_INST_MULTIPLY:
2033                         case BC_INST_DIVIDE:
2034                         case BC_INST_MODULUS:
2035                         case BC_INST_PLUS:
2036                         case BC_INST_MINUS:
2037 #if BC_ENABLE_EXTRA_MATH
2038                         case BC_INST_PLACES:
2039                         case BC_INST_LSHIFT:
2040                         case BC_INST_RSHIFT:
2041 #endif // BC_ENABLE_EXTRA_MATH
2042                         {
2043                                 bc_program_op(p, inst);
2044                                 break;
2045                         }
2046
2047                         case BC_INST_NEG:
2048                         case BC_INST_BOOL_NOT:
2049 #if BC_ENABLE_EXTRA_MATH
2050                         case BC_INST_TRUNC:
2051 #endif // BC_ENABLE_EXTRA_MATH
2052                         {
2053                                 bc_program_unary(p, inst);
2054                                 break;
2055                         }
2056
2057 #if BC_ENABLED
2058                         case BC_INST_ASSIGN_POWER:
2059                         case BC_INST_ASSIGN_MULTIPLY:
2060                         case BC_INST_ASSIGN_DIVIDE:
2061                         case BC_INST_ASSIGN_MODULUS:
2062                         case BC_INST_ASSIGN_PLUS:
2063                         case BC_INST_ASSIGN_MINUS:
2064 #if BC_ENABLE_EXTRA_MATH
2065                         case BC_INST_ASSIGN_PLACES:
2066                         case BC_INST_ASSIGN_LSHIFT:
2067                         case BC_INST_ASSIGN_RSHIFT:
2068 #endif // BC_ENABLE_EXTRA_MATH
2069                         case BC_INST_ASSIGN:
2070                         case BC_INST_ASSIGN_POWER_NO_VAL:
2071                         case BC_INST_ASSIGN_MULTIPLY_NO_VAL:
2072                         case BC_INST_ASSIGN_DIVIDE_NO_VAL:
2073                         case BC_INST_ASSIGN_MODULUS_NO_VAL:
2074                         case BC_INST_ASSIGN_PLUS_NO_VAL:
2075                         case BC_INST_ASSIGN_MINUS_NO_VAL:
2076 #if BC_ENABLE_EXTRA_MATH
2077                         case BC_INST_ASSIGN_PLACES_NO_VAL:
2078                         case BC_INST_ASSIGN_LSHIFT_NO_VAL:
2079                         case BC_INST_ASSIGN_RSHIFT_NO_VAL:
2080 #endif // BC_ENABLE_EXTRA_MATH
2081 #endif // BC_ENABLED
2082                         case BC_INST_ASSIGN_NO_VAL:
2083                         {
2084                                 bc_program_assign(p, inst);
2085                                 break;
2086                         }
2087
2088                         case BC_INST_POP:
2089                         {
2090 #ifndef BC_PROG_NO_STACK_CHECK
2091                                 if (!BC_IS_BC) {
2092                                         if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2093                                                 bc_vm_err(BC_ERR_EXEC_STACK);
2094                                 }
2095 #endif // BC_PROG_NO_STACK_CHECK
2096
2097                                 assert(BC_PROG_STACK(&p->results, 1));
2098
2099                                 bc_vec_pop(&p->results);
2100                                 break;
2101                         }
2102
2103 #if DC_ENABLED
2104                         case BC_INST_POP_EXEC:
2105                         {
2106                                 assert(BC_PROG_STACK(&p->stack, 2));
2107                                 bc_vec_pop(&p->stack);
2108                                 bc_vec_pop(&p->tail_calls);
2109                                 ip = bc_vec_top(&p->stack);
2110                                 func = bc_vec_item(&p->fns, ip->func);
2111                                 code = func->code.v;
2112                                 bc_program_setVecs(p, func);
2113                                 break;
2114                         }
2115
2116                         case BC_INST_MODEXP:
2117                         {
2118                                 bc_program_modexp(p);
2119                                 break;
2120                         }
2121
2122                         case BC_INST_DIVMOD:
2123                         {
2124                                 bc_program_divmod(p);
2125                                 break;
2126                         }
2127
2128                         case BC_INST_EXECUTE:
2129                         case BC_INST_EXEC_COND:
2130                         {
2131                                 cond = (inst == BC_INST_EXEC_COND);
2132                                 bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
2133                                 ip = bc_vec_top(&p->stack);
2134                                 func = bc_vec_item(&p->fns, ip->func);
2135                                 code = func->code.v;
2136                                 bc_program_setVecs(p, func);
2137                                 break;
2138                         }
2139
2140                         case BC_INST_PRINT_STACK:
2141                         {
2142                                 bc_program_printStack(p);
2143                                 break;
2144                         }
2145
2146                         case BC_INST_CLEAR_STACK:
2147                         {
2148                                 bc_vec_npop(&p->results, p->results.len);
2149                                 break;
2150                         }
2151
2152                         case BC_INST_STACK_LEN:
2153                         {
2154                                 bc_program_stackLen(p);
2155                                 break;
2156                         }
2157
2158                         case BC_INST_DUPLICATE:
2159                         {
2160                                 if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
2161                                         bc_vm_err(BC_ERR_EXEC_STACK);
2162
2163                                 assert(BC_PROG_STACK(&p->results, 1));
2164
2165                                 ptr = bc_vec_top(&p->results);
2166
2167                                 BC_SIG_LOCK;
2168
2169                                 bc_result_copy(&r, ptr);
2170                                 bc_vec_push(&p->results, &r);
2171
2172                                 BC_SIG_UNLOCK;
2173
2174                                 break;
2175                         }
2176
2177                         case BC_INST_SWAP:
2178                         {
2179                                 BcResult *ptr2;
2180
2181                                 if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
2182                                         bc_vm_err(BC_ERR_EXEC_STACK);
2183
2184                                 assert(BC_PROG_STACK(&p->results, 2));
2185
2186                                 ptr = bc_vec_item_rev(&p->results, 0);
2187                                 ptr2 = bc_vec_item_rev(&p->results, 1);
2188                                 memcpy(&r, ptr, sizeof(BcResult));
2189                                 memcpy(ptr, ptr2, sizeof(BcResult));
2190                                 memcpy(ptr2, &r, sizeof(BcResult));
2191
2192                                 break;
2193                         }
2194
2195                         case BC_INST_ASCIIFY:
2196                         {
2197                                 bc_program_asciify(p);
2198                                 ip = bc_vec_top(&p->stack);
2199                                 func = bc_vec_item(&p->fns, ip->func);
2200                                 code = func->code.v;
2201                                 bc_program_setVecs(p, func);
2202                                 break;
2203                         }
2204
2205                         case BC_INST_PRINT_STREAM:
2206                         {
2207                                 bc_program_printStream(p);
2208                                 break;
2209                         }
2210
2211                         case BC_INST_LOAD:
2212                         case BC_INST_PUSH_VAR:
2213                         {
2214                                 bool copy = (inst == BC_INST_LOAD);
2215                                 bc_program_pushVar(p, code, &ip->idx, true, copy);
2216                                 break;
2217                         }
2218
2219                         case BC_INST_PUSH_TO_VAR:
2220                         {
2221                                 idx = bc_program_index(code, &ip->idx);
2222                                 bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
2223                                 break;
2224                         }
2225
2226                         case BC_INST_QUIT:
2227                         case BC_INST_NQUIT:
2228                         {
2229                                 bc_program_nquit(p, inst);
2230                                 ip = bc_vec_top(&p->stack);
2231                                 func = bc_vec_item(&p->fns, ip->func);
2232                                 code = func->code.v;
2233                                 bc_program_setVecs(p, func);
2234                                 break;
2235                         }
2236 #endif // DC_ENABLED
2237 #ifndef NDEBUG
2238                         default:
2239                         {
2240                                 abort();
2241                         }
2242 #endif // NDEBUG
2243                 }
2244
2245 #ifndef NDEBUG
2246                 // This is to allow me to use a debugger to see the last instruction,
2247                 // which will point to which function was the problem.
2248                 assert(jmp_bufs_len == vm.jmp_bufs.len);
2249 #endif // NDEBUG
2250         }
2251 }
2252
2253 #if BC_DEBUG_CODE
2254 #if BC_ENABLED && DC_ENABLED
2255 void bc_program_printStackDebug(BcProgram *p) {
2256         bc_file_puts(&vm.fout, "-------------- Stack ----------\n");
2257         bc_program_printStack(p);
2258         bc_file_puts(&vm.fout, "-------------- Stack End ------\n");
2259 }
2260
2261 static void bc_program_printIndex(const char *restrict code,
2262                                   size_t *restrict bgn)
2263 {
2264         uchar byte, i, bytes = (uchar) code[(*bgn)++];
2265         ulong val = 0;
2266
2267         for (byte = 1, i = 0; byte && i < bytes; ++i) {
2268                 byte = (uchar) code[(*bgn)++];
2269                 if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
2270         }
2271
2272         bc_vm_printf(" (%lu) ", val);
2273 }
2274
2275 static void bc_program_printStr(const BcProgram *p, const char *restrict code,
2276                          size_t *restrict bgn)
2277 {
2278         size_t idx = bc_program_index(code, bgn);
2279         char *s;
2280
2281         s = *((char**) bc_vec_item(p->strs, idx));
2282
2283         bc_vm_printf(" (\"%s\") ", s);
2284 }
2285
2286 void bc_program_printInst(const BcProgram *p, const char *restrict code,
2287                           size_t *restrict bgn)
2288 {
2289         uchar inst = (uchar) code[(*bgn)++];
2290
2291         bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
2292                      bc_inst_names[inst], (unsigned long) inst);
2293
2294         if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
2295             inst == BC_INST_ARRAY)
2296         {
2297                 bc_program_printIndex(code, bgn);
2298         }
2299         else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
2300         else if (inst == BC_INST_NUM) {
2301                 size_t idx = bc_program_index(code, bgn);
2302                 BcConst *c = bc_vec_item(p->consts, idx);
2303                 bc_vm_printf("(%s)", c->val);
2304         }
2305         else if (inst == BC_INST_CALL ||
2306                  (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
2307         {
2308                 bc_program_printIndex(code, bgn);
2309                 if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
2310         }
2311
2312         bc_vm_putchar('\n');
2313 }
2314
2315 void bc_program_code(const BcProgram* p) {
2316
2317         BcFunc *f;
2318         char *code;
2319         BcInstPtr ip;
2320         size_t i;
2321
2322         for (i = 0; i < p->fns.len; ++i) {
2323
2324                 ip.idx = ip.len = 0;
2325                 ip.func = i;
2326
2327                 f = bc_vec_item(&p->fns, ip.func);
2328                 code = f->code.v;
2329
2330                 bc_vm_printf("func[%zu]:\n", ip.func);
2331                 while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
2332                 bc_file_puts(&vm.fout, "\n\n");
2333         }
2334 }
2335 #endif // BC_ENABLED && DC_ENABLED
2336 #endif // BC_DEBUG_CODE