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