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