Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bc/src/program.c
39535 views
1
/*
2
* *****************************************************************************
3
*
4
* SPDX-License-Identifier: BSD-2-Clause
5
*
6
* Copyright (c) 2018-2025 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
/**
52
* Does a type check for something that expects a number.
53
* @param r The result that will be checked.
54
* @param n The result's number.
55
*/
56
static inline void
57
bc_program_type_num(BcResult* r, BcNum* n)
58
{
59
#if BC_ENABLED
60
61
// This should have already been taken care of.
62
assert(r->t != BC_RESULT_VOID);
63
64
#endif // BC_ENABLED
65
66
if (BC_ERR(!BC_PROG_NUM(r, n))) bc_err(BC_ERR_EXEC_TYPE);
67
}
68
69
#if BC_ENABLED
70
71
/**
72
* Does a type check.
73
* @param r The result to check.
74
* @param t The type that the result should be.
75
*/
76
static void
77
bc_program_type_match(BcResult* r, BcType t)
78
{
79
if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE);
80
}
81
#endif // BC_ENABLED
82
83
/**
84
* Pulls an index out of a bytecode vector and updates the index into the vector
85
* to point to the spot after the index. For more details on bytecode indices,
86
* see the development manual (manuals/development.md#bytecode-indices).
87
* @param code The bytecode vector.
88
* @param bgn An in/out parameter; the index into the vector that will be
89
* updated.
90
* @return The index at @a bgn in the bytecode vector.
91
*/
92
static size_t
93
bc_program_index(const char* restrict code, size_t* restrict bgn)
94
{
95
uchar amt = (uchar) code[(*bgn)++], i = 0;
96
size_t res = 0;
97
98
for (; i < amt; ++i, ++(*bgn))
99
{
100
size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
101
res |= (temp << (i * CHAR_BIT));
102
}
103
104
return res;
105
}
106
107
/**
108
* Returns a string from a result and its number.
109
* @param p The program.
110
* @param n The number tied to the result.
111
* @return The string corresponding to the result and number.
112
*/
113
static inline char*
114
bc_program_string(BcProgram* p, const BcNum* n)
115
{
116
return *((char**) bc_vec_item(&p->strs, n->scale));
117
}
118
119
#if BC_ENABLED
120
121
/**
122
* Prepares the globals for a function call. This is only called when global
123
* stacks are on because it pushes a copy of the current globals onto each of
124
* their respective stacks.
125
* @param p The program.
126
*/
127
static void
128
bc_program_prepGlobals(BcProgram* p)
129
{
130
size_t i;
131
132
for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
133
{
134
bc_vec_push(p->globals_v + i, p->globals + i);
135
}
136
137
#if BC_ENABLE_EXTRA_MATH
138
bc_rand_push(&p->rng);
139
#endif // BC_ENABLE_EXTRA_MATH
140
}
141
142
/**
143
* Pops globals stacks on returning from a function, or in the case of reset,
144
* pops all but one item on each global stack.
145
* @param p The program.
146
* @param reset True if all but one item on each stack should be popped, false
147
* otherwise.
148
*/
149
static void
150
bc_program_popGlobals(BcProgram* p, bool reset)
151
{
152
size_t i;
153
154
BC_SIG_ASSERT_LOCKED;
155
156
for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
157
{
158
BcVec* v = p->globals_v + i;
159
bc_vec_npop(v, reset ? v->len - 1 : 1);
160
p->globals[i] = BC_PROG_GLOBAL(v);
161
}
162
163
#if BC_ENABLE_EXTRA_MATH
164
bc_rand_pop(&p->rng, reset);
165
#endif // BC_ENABLE_EXTRA_MATH
166
}
167
168
/**
169
* Derefeneces an array reference and returns a pointer to the real array.
170
* @param p The program.
171
* @param vec The reference vector.
172
* @return A pointer to the desired array.
173
*/
174
static BcVec*
175
bc_program_dereference(const BcProgram* p, BcVec* vec)
176
{
177
BcVec* v;
178
size_t vidx, nidx, i = 0;
179
180
// We want to be sure we have a reference vector.
181
assert(vec->size == sizeof(uchar));
182
183
// Get the index of the vector in arrs, then the index of the original
184
// referenced vector.
185
vidx = bc_program_index(vec->v, &i);
186
nidx = bc_program_index(vec->v, &i);
187
188
v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
189
190
// We want to be sure we do *not* have a reference vector.
191
assert(v->size != sizeof(uchar));
192
193
return v;
194
}
195
196
#endif // BC_ENABLED
197
198
/**
199
* Creates a BcNum from a BcBigDig and pushes onto the results stack. This is a
200
* convenience function.
201
* @param p The program.
202
* @param dig The BcBigDig to push onto the results stack.
203
* @param type The type that the pushed result should be.
204
*/
205
static void
206
bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
207
{
208
BcResult res;
209
210
res.t = type;
211
212
BC_SIG_LOCK;
213
214
bc_num_createFromBigdig(&res.d.n, dig);
215
bc_vec_push(&p->results, &res);
216
217
BC_SIG_UNLOCK;
218
}
219
220
size_t
221
bc_program_addString(BcProgram* p, const char* str)
222
{
223
size_t idx;
224
225
BC_SIG_ASSERT_LOCKED;
226
227
if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
228
{
229
char** str_ptr;
230
BcId* id = bc_vec_item(&p->str_map, idx);
231
232
// Get the index.
233
idx = id->idx;
234
235
// Push an empty string on the proper vector.
236
str_ptr = bc_vec_pushEmpty(&p->strs);
237
238
// We reuse the string in the ID (allocated by bc_map_insert()), because
239
// why not?
240
*str_ptr = id->name;
241
}
242
else
243
{
244
BcId* id = bc_vec_item(&p->str_map, idx);
245
idx = id->idx;
246
}
247
248
return idx;
249
}
250
251
size_t
252
bc_program_search(BcProgram* p, const char* name, bool var)
253
{
254
BcVec* v;
255
BcVec* map;
256
size_t i;
257
258
BC_SIG_ASSERT_LOCKED;
259
260
// Grab the right vector and map.
261
v = var ? &p->vars : &p->arrs;
262
map = var ? &p->var_map : &p->arr_map;
263
264
// We do an insert because the variable might not exist yet. This is because
265
// the parser calls this function. If the insert succeeds, we create a stack
266
// for the variable/array. But regardless, bc_map_insert() gives us the
267
// index of the item in i.
268
if (bc_map_insert(map, name, v->len, &i))
269
{
270
BcVec* temp = bc_vec_pushEmpty(v);
271
bc_array_init(temp, var);
272
}
273
274
return ((BcId*) bc_vec_item(map, i))->idx;
275
}
276
277
/**
278
* Returns the correct variable or array stack for the type.
279
* @param p The program.
280
* @param idx The index of the variable or array in the variable or array
281
* vector.
282
* @param type The type of vector to return.
283
* @return A pointer to the variable or array stack.
284
*/
285
static inline BcVec*
286
bc_program_vec(const BcProgram* p, size_t idx, BcType type)
287
{
288
const BcVec* v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
289
return bc_vec_item(v, idx);
290
}
291
292
/**
293
* Returns a pointer to the BcNum corresponding to the result. There is one
294
* case, however, where this returns a pointer to a BcVec: if the type of the
295
* result is array. In that case, the pointer is casted to a pointer to BcNum,
296
* but is never used. The function that calls this expecting an array casts the
297
* pointer back. This function is called a lot and needs to be as fast as
298
* possible.
299
* @param p The program.
300
* @param r The result whose number will be returned.
301
* @return The BcNum corresponding to the result.
302
*/
303
static BcNum*
304
bc_program_num(BcProgram* p, BcResult* r)
305
{
306
BcNum* n;
307
308
#ifdef _WIN32
309
// Windows made it an error to not initialize this, so shut it up.
310
// I don't want to do this on other platforms because this procedure
311
// is one of the most heavily-used, and eliminating the initialization
312
// is a performance win.
313
n = NULL;
314
#endif // _WIN32
315
316
switch (r->t)
317
{
318
case BC_RESULT_STR:
319
case BC_RESULT_TEMP:
320
case BC_RESULT_IBASE:
321
case BC_RESULT_SCALE:
322
case BC_RESULT_OBASE:
323
#if BC_ENABLE_EXTRA_MATH
324
case BC_RESULT_SEED:
325
#endif // BC_ENABLE_EXTRA_MATH
326
{
327
n = &r->d.n;
328
break;
329
}
330
331
case BC_RESULT_VAR:
332
case BC_RESULT_ARRAY:
333
case BC_RESULT_ARRAY_ELEM:
334
{
335
BcVec* v;
336
BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
337
338
// Get the correct variable or array vector.
339
v = bc_program_vec(p, r->d.loc.loc, type);
340
341
// Surprisingly enough, the hard case is *not* returning an array;
342
// it's returning an array element. This is because we have to dig
343
// deeper to get *to* the element. That's what the code inside this
344
// if statement does.
345
if (r->t == BC_RESULT_ARRAY_ELEM)
346
{
347
size_t idx = r->d.loc.idx;
348
349
v = bc_vec_item(v, r->d.loc.stack_idx);
350
351
#if BC_ENABLED
352
// If this is true, we have a reference vector, so dereference
353
// it. The reason we don't need to worry about it for returning
354
// a straight array is because we only care about references
355
// when we access elements of an array that is a reference. That
356
// is this code, so in essence, this line takes care of arrays
357
// as well.
358
if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
359
#endif // BC_ENABLED
360
361
// We want to be sure we got a valid array of numbers.
362
assert(v->size == sizeof(BcNum));
363
364
// The bc spec says that if an element is accessed that does not
365
// exist, it should be preinitialized to 0. Well, if we access
366
// an element *way* out there, we have to preinitialize all
367
// elements between the current last element and the actual
368
// accessed element.
369
if (v->len <= idx)
370
{
371
BC_SIG_LOCK;
372
bc_array_expand(v, bc_vm_growSize(idx, 1));
373
BC_SIG_UNLOCK;
374
}
375
376
n = bc_vec_item(v, idx);
377
}
378
// This is either a number (for a var) or an array (for an array).
379
// Because bc_vec_top() and bc_vec_item() return a void*, we don't
380
// need to cast.
381
else
382
{
383
#if BC_ENABLED
384
if (BC_IS_BC)
385
{
386
n = bc_vec_item(v, r->d.loc.stack_idx);
387
}
388
else
389
#endif // BC_ENABLED
390
{
391
n = bc_vec_top(v);
392
}
393
}
394
395
break;
396
}
397
398
case BC_RESULT_ZERO:
399
{
400
n = &vm->zero;
401
break;
402
}
403
404
case BC_RESULT_ONE:
405
{
406
n = &vm->one;
407
break;
408
}
409
410
#if BC_ENABLED
411
// We should never get here; this is taken care of earlier because a
412
// result is expected.
413
case BC_RESULT_VOID:
414
#if BC_DEBUG
415
{
416
abort();
417
// Fallthrough
418
}
419
#endif // BC_DEBUG
420
case BC_RESULT_LAST:
421
{
422
n = &p->last;
423
break;
424
}
425
#endif // BC_ENABLED
426
427
#if BC_GCC
428
// This is here in GCC to quiet the "maybe-uninitialized" warning.
429
default:
430
{
431
abort();
432
}
433
#endif // BC_GCC
434
}
435
436
return n;
437
}
438
439
/**
440
* Prepares an operand for use.
441
* @param p The program.
442
* @param r An out parameter; this is set to the pointer to the result that
443
* we care about.
444
* @param n An out parameter; this is set to the pointer to the number that
445
* we care about.
446
* @param idx The index of the result from the top of the results stack.
447
*/
448
static void
449
bc_program_operand(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
450
{
451
*r = bc_vec_item_rev(&p->results, idx);
452
453
#if BC_ENABLED
454
if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
455
#endif // BC_ENABLED
456
457
*n = bc_program_num(p, *r);
458
}
459
460
/**
461
* Prepares the operands of a binary operator.
462
* @param p The program.
463
* @param l An out parameter; this is set to the pointer to the result for
464
* the left operand.
465
* @param ln An out parameter; this is set to the pointer to the number for
466
* the left operand.
467
* @param r An out parameter; this is set to the pointer to the result for
468
* the right operand.
469
* @param rn An out parameter; this is set to the pointer to the number for
470
* the right operand.
471
* @param idx The starting index where the operands are in the results stack,
472
* starting from the top.
473
*/
474
static void
475
bc_program_binPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
476
BcNum** rn, size_t idx)
477
{
478
BcResultType lt;
479
480
assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
481
482
#ifndef BC_PROG_NO_STACK_CHECK
483
// Check the stack for dc.
484
if (BC_IS_DC)
485
{
486
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
487
{
488
bc_err(BC_ERR_EXEC_STACK);
489
}
490
}
491
#endif // BC_PROG_NO_STACK_CHECK
492
493
assert(BC_PROG_STACK(&p->results, idx + 2));
494
495
// Get the operands.
496
bc_program_operand(p, l, ln, idx + 1);
497
bc_program_operand(p, r, rn, idx);
498
499
lt = (*l)->t;
500
501
#if BC_ENABLED
502
// bc_program_operand() checked these for us.
503
assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
504
#endif // BC_ENABLED
505
506
// We run this again under these conditions in case any vector has been
507
// reallocated out from under the BcNums or arrays we had. In other words,
508
// this is to fix pointer invalidation.
509
if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
510
{
511
*ln = bc_program_num(p, *l);
512
}
513
514
if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE);
515
}
516
517
/**
518
* Prepares the operands of a binary operator and type checks them. This is
519
* separate from bc_program_binPrep() because some places want this, others want
520
* bc_program_binPrep().
521
* @param p The program.
522
* @param l An out parameter; this is set to the pointer to the result for
523
* the left operand.
524
* @param ln An out parameter; this is set to the pointer to the number for
525
* the left operand.
526
* @param r An out parameter; this is set to the pointer to the result for
527
* the right operand.
528
* @param rn An out parameter; this is set to the pointer to the number for
529
* the right operand.
530
* @param idx The starting index where the operands are in the results stack,
531
* starting from the top.
532
*/
533
static void
534
bc_program_binOpPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
535
BcNum** rn, size_t idx)
536
{
537
bc_program_binPrep(p, l, ln, r, rn, idx);
538
bc_program_type_num(*l, *ln);
539
bc_program_type_num(*r, *rn);
540
}
541
542
/**
543
* Prepares the operands of an assignment operator.
544
* @param p The program.
545
* @param l An out parameter; this is set to the pointer to the result for the
546
* left operand.
547
* @param ln An out parameter; this is set to the pointer to the number for the
548
* left operand.
549
* @param r An out parameter; this is set to the pointer to the result for the
550
* right operand.
551
* @param rn An out parameter; this is set to the pointer to the number for the
552
* right operand.
553
*/
554
static void
555
bc_program_assignPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
556
BcNum** rn)
557
{
558
BcResultType lt, min;
559
bool good;
560
561
// This is the min non-allowable result type. dc allows strings.
562
min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
563
564
// Prepare the operands.
565
bc_program_binPrep(p, l, ln, r, rn, 0);
566
567
lt = (*l)->t;
568
569
// Typecheck the left.
570
if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) bc_err(BC_ERR_EXEC_TYPE);
571
572
// Strings can be assigned to variables. We are already good if we are
573
// assigning a string.
574
good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
575
576
assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR);
577
578
// If not, type check for a number.
579
if (!good) bc_program_type_num(*r, *rn);
580
}
581
582
/**
583
* Prepares a single operand and type checks it. This is separate from
584
* bc_program_operand() because different places want one or the other.
585
* @param p The program.
586
* @param r An out parameter; this is set to the pointer to the result that
587
* we care about.
588
* @param n An out parameter; this is set to the pointer to the number that
589
* we care about.
590
* @param idx The index of the result from the top of the results stack.
591
*/
592
static void
593
bc_program_prep(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
594
{
595
assert(p != NULL && r != NULL && n != NULL);
596
597
#ifndef BC_PROG_NO_STACK_CHECK
598
// Check the stack for dc.
599
if (BC_IS_DC)
600
{
601
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
602
{
603
bc_err(BC_ERR_EXEC_STACK);
604
}
605
}
606
#endif // BC_PROG_NO_STACK_CHECK
607
608
assert(BC_PROG_STACK(&p->results, idx + 1));
609
610
bc_program_operand(p, r, n, idx);
611
612
// dc does not allow strings in this case.
613
bc_program_type_num(*r, *n);
614
}
615
616
/**
617
* Prepares and returns a clean result for the result of an operation.
618
* @param p The program.
619
* @return A clean result.
620
*/
621
static BcResult*
622
bc_program_prepResult(BcProgram* p)
623
{
624
BcResult* res = bc_vec_pushEmpty(&p->results);
625
626
// Mark a result as not retired.
627
p->nresults += 1;
628
629
bc_result_clear(res);
630
631
return res;
632
}
633
634
/**
635
* Prepares a constant for use. This parses the constant into a number and then
636
* pushes that number onto the results stack.
637
* @param p The program.
638
* @param code The bytecode vector that we will pull the index of the constant
639
* from.
640
* @param bgn An in/out parameter; marks the start of the index in the
641
* bytecode vector and will be updated to point to after the index.
642
*/
643
static void
644
bc_program_const(BcProgram* p, const char* code, size_t* bgn)
645
{
646
// I lied. I actually push the result first. I can do this because the
647
// result will be popped on error. I also get the constant itself.
648
BcResult* r = bc_program_prepResult(p);
649
BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
650
BcBigDig base = BC_PROG_IBASE(p);
651
652
assert(p->nresults == 1);
653
654
// Only reparse if the base changed.
655
if (c->base != base)
656
{
657
// Allocate if we haven't yet.
658
if (c->num.num == NULL)
659
{
660
// The plus 1 is in case of overflow with lack of clamping.
661
size_t len = strlen(c->val) + (BC_DIGIT_CLAMP == 0);
662
663
BC_SIG_LOCK;
664
bc_num_init(&c->num, BC_NUM_RDX(len));
665
BC_SIG_UNLOCK;
666
}
667
// We need to zero an already existing number.
668
else bc_num_zero(&c->num);
669
670
// bc_num_parse() should only do operations that cannot fail.
671
bc_num_parse(&c->num, c->val, base);
672
673
c->base = base;
674
}
675
676
BC_SIG_LOCK;
677
678
bc_num_createCopy(&r->d.n, &c->num);
679
680
BC_SIG_UNLOCK;
681
682
// XXX: Make sure to clear the number of results.
683
p->nresults -= 1;
684
}
685
686
/**
687
* Executes a binary operator operation.
688
* @param p The program.
689
* @param inst The instruction corresponding to the binary operator to execute.
690
*/
691
static void
692
bc_program_op(BcProgram* p, uchar inst)
693
{
694
BcResult* opd1;
695
BcResult* opd2;
696
BcResult* res;
697
BcNum* n1;
698
BcNum* n2;
699
size_t idx = inst - BC_INST_POWER;
700
701
res = bc_program_prepResult(p);
702
703
assert(p->nresults == 1);
704
705
bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
706
707
BC_SIG_LOCK;
708
709
// Initialize the number with enough space, using the correct
710
// BcNumBinaryOpReq function. This looks weird because it is executing an
711
// item of an array. Rest assured that item is a function.
712
bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
713
714
BC_SIG_UNLOCK;
715
716
assert(BC_NUM_RDX_VALID(n1));
717
assert(BC_NUM_RDX_VALID(n2));
718
719
// Run the operation. This also executes an item of an array.
720
bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
721
722
bc_program_retire(p, 2);
723
}
724
725
/**
726
* Executes a read() or ? command.
727
* @param p The program.
728
*/
729
static void
730
bc_program_read(BcProgram* p)
731
{
732
BcStatus s;
733
BcInstPtr ip;
734
size_t i;
735
const char* file;
736
BcMode mode;
737
BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
738
739
// If we are already executing a read, that is an error. So look for a read
740
// and barf.
741
for (i = 0; i < p->stack.len; ++i)
742
{
743
BcInstPtr* ip_ptr = bc_vec_item(&p->stack, i);
744
if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ);
745
}
746
747
BC_SIG_LOCK;
748
749
// Save the filename because we are going to overwrite it.
750
file = vm->file;
751
mode = vm->mode;
752
753
// It is a parse error if there needs to be more than one line, so we unset
754
// this to tell the lexer to not request more. We set it back later.
755
vm->mode = BC_MODE_FILE;
756
757
if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
758
{
759
// We need to parse, but we don't want to use the existing parser
760
// because it has state it needs to keep. (It could have a partial parse
761
// state.) So we create a new parser. This parser is in the BcVm struct
762
// so that it is not local, which means that a longjmp() could change
763
// it.
764
bc_parse_init(&vm->read_prs, p, BC_PROG_READ);
765
766
// We need a separate input buffer; that's why it is also in the BcVm
767
// struct.
768
bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
769
}
770
else
771
{
772
// This needs to be updated because the parser could have been used
773
// somewhere else.
774
bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
775
776
// The read buffer also needs to be emptied or else it will still
777
// contain previous read expressions.
778
bc_vec_empty(&vm->read_buf);
779
}
780
781
BC_SETJMP_LOCKED(vm, exec_err);
782
783
BC_SIG_UNLOCK;
784
785
// Set up the lexer and the read function.
786
bc_lex_file(&vm->read_prs.l, bc_program_stdin_name);
787
bc_vec_popAll(&f->code);
788
789
// Read a line.
790
if (!BC_R) s = bc_read_line(&vm->read_buf, "");
791
else s = bc_read_line(&vm->read_buf, BC_VM_READ_PROMPT);
792
793
// We should *not* have run into EOF.
794
if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
795
796
// Parse *one* expression, so mode should not be stdin.
797
bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
798
BC_SIG_LOCK;
799
vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
800
BC_SIG_UNLOCK;
801
802
// We *must* have a valid expression. A semicolon cannot end an expression,
803
// although EOF can.
804
if (BC_ERR(vm->read_prs.l.t != BC_LEX_NLINE &&
805
vm->read_prs.l.t != BC_LEX_EOF))
806
{
807
bc_err(BC_ERR_EXEC_READ_EXPR);
808
}
809
810
#if BC_ENABLED
811
// Push on the globals stack if necessary.
812
if (BC_G) bc_program_prepGlobals(p);
813
#endif // BC_ENABLED
814
815
// Set up a new BcInstPtr.
816
ip.func = BC_PROG_READ;
817
ip.idx = 0;
818
ip.len = p->results.len;
819
820
// Update this pointer, just in case.
821
f = bc_vec_item(&p->fns, BC_PROG_READ);
822
823
// We want a return instruction to simplify things.
824
bc_vec_pushByte(&f->code, vm->read_ret);
825
826
// This lock is here to make sure dc's tail calls are the same length.
827
BC_SIG_LOCK;
828
bc_vec_push(&p->stack, &ip);
829
830
#if DC_ENABLED
831
// We need a new tail call entry for dc.
832
if (BC_IS_DC)
833
{
834
size_t temp = 0;
835
bc_vec_push(&p->tail_calls, &temp);
836
}
837
#endif // DC_ENABLED
838
839
exec_err:
840
BC_SIG_MAYLOCK;
841
vm->mode = (uchar) mode;
842
vm->file = file;
843
BC_LONGJMP_CONT(vm);
844
}
845
846
#if BC_ENABLE_EXTRA_MATH
847
848
/**
849
* Execute a rand().
850
* @param p The program.
851
*/
852
static void
853
bc_program_rand(BcProgram* p)
854
{
855
BcRand rand = bc_rand_int(&p->rng);
856
857
bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
858
859
#if BC_DEBUG
860
// This is just to ensure that the generated number is correct. I also use
861
// braces because I declare every local at the top of the scope.
862
{
863
BcResult* r = bc_vec_top(&p->results);
864
assert(BC_NUM_RDX_VALID_NP(r->d.n));
865
}
866
#endif // BC_DEBUG
867
}
868
#endif // BC_ENABLE_EXTRA_MATH
869
870
/**
871
* Prints a series of characters, without escapes.
872
* @param str The string (series of characters).
873
*/
874
static void
875
bc_program_printChars(const char* str)
876
{
877
const char* nl;
878
size_t len = vm->nchars + strlen(str);
879
sig_atomic_t lock;
880
881
BC_SIG_TRYLOCK(lock);
882
883
bc_file_puts(&vm->fout, bc_flush_save, str);
884
885
// We need to update the number of characters, so we find the last newline
886
// and set the characters accordingly.
887
nl = strrchr(str, '\n');
888
889
if (nl != NULL) len = strlen(nl + 1);
890
891
vm->nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
892
893
BC_SIG_TRYUNLOCK(lock);
894
}
895
896
/**
897
* Prints a string with escapes.
898
* @param str The string.
899
*/
900
static void
901
bc_program_printString(const char* restrict str)
902
{
903
size_t i, len = strlen(str);
904
905
#if DC_ENABLED
906
// This is to ensure a nul byte is printed for dc's stream operation.
907
if (!len && BC_IS_DC)
908
{
909
bc_vm_putchar('\0', bc_flush_save);
910
return;
911
}
912
#endif // DC_ENABLED
913
914
// Loop over the characters, processing escapes and printing the rest.
915
for (i = 0; i < len; ++i)
916
{
917
int c = str[i];
918
919
// If we have an escape...
920
if (c == '\\' && i != len - 1)
921
{
922
const char* ptr;
923
924
// Get the escape character and its companion.
925
c = str[++i];
926
ptr = strchr(bc_program_esc_chars, c);
927
928
// If we have a companion character...
929
if (ptr != NULL)
930
{
931
// We need to specially handle a newline.
932
if (c == 'n')
933
{
934
BC_SIG_LOCK;
935
vm->nchars = UINT16_MAX;
936
BC_SIG_UNLOCK;
937
}
938
939
// Grab the actual character.
940
c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
941
}
942
else
943
{
944
// Just print the backslash if there is no companion character.
945
// The following character will be printed later after the outer
946
// if statement.
947
bc_vm_putchar('\\', bc_flush_save);
948
}
949
}
950
951
bc_vm_putchar(c, bc_flush_save);
952
}
953
}
954
955
/**
956
* Executes a print. This function handles all printing except streaming.
957
* @param p The program.
958
* @param inst The instruction for the type of print we are doing.
959
* @param idx The index of the result that we are printing.
960
*/
961
static void
962
bc_program_print(BcProgram* p, uchar inst, size_t idx)
963
{
964
BcResult* r;
965
char* str;
966
BcNum* n;
967
bool pop = (inst != BC_INST_PRINT);
968
969
assert(p != NULL);
970
971
#ifndef BC_PROG_NO_STACK_CHECK
972
if (BC_IS_DC)
973
{
974
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
975
{
976
bc_err(BC_ERR_EXEC_STACK);
977
}
978
}
979
#endif // BC_PROG_NO_STACK_CHECK
980
981
assert(BC_PROG_STACK(&p->results, idx + 1));
982
983
r = bc_vec_item_rev(&p->results, idx);
984
985
#if BC_ENABLED
986
// If we have a void value, that's not necessarily an error. It is if pop is
987
// true because that means that we are executing a print statement, but
988
// attempting to do a print on a lone void value is allowed because that's
989
// exactly how we want void values used.
990
if (r->t == BC_RESULT_VOID)
991
{
992
if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL);
993
bc_vec_pop(&p->results);
994
return;
995
}
996
#endif // BC_ENABLED
997
998
n = bc_program_num(p, r);
999
1000
// If we have a number...
1001
if (BC_PROG_NUM(r, n))
1002
{
1003
#if BC_ENABLED
1004
assert(inst != BC_INST_PRINT_STR);
1005
#endif // BC_ENABLED
1006
1007
// Print the number.
1008
bc_num_print(n, BC_PROG_OBASE(p), !pop);
1009
1010
#if BC_ENABLED
1011
// Need to store the number in last.
1012
if (BC_IS_BC) bc_num_copy(&p->last, n);
1013
#endif // BC_ENABLED
1014
}
1015
else
1016
{
1017
// We want to flush any stuff in the stdout buffer first.
1018
bc_file_flush(&vm->fout, bc_flush_save);
1019
str = bc_program_string(p, n);
1020
1021
#if BC_ENABLED
1022
if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
1023
else
1024
#endif // BC_ENABLED
1025
{
1026
bc_program_printString(str);
1027
1028
// Need to print a newline only in this case.
1029
if (inst == BC_INST_PRINT) bc_vm_putchar('\n', bc_flush_err);
1030
}
1031
}
1032
1033
// bc always pops. This macro makes sure that happens.
1034
if (BC_PROGRAM_POP(pop)) bc_vec_pop(&p->results);
1035
}
1036
1037
void
1038
bc_program_negate(BcResult* r, BcNum* n)
1039
{
1040
bc_num_copy(&r->d.n, n);
1041
if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
1042
}
1043
1044
void
1045
bc_program_not(BcResult* r, BcNum* n)
1046
{
1047
if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
1048
}
1049
1050
#if BC_ENABLE_EXTRA_MATH
1051
void
1052
bc_program_trunc(BcResult* r, BcNum* n)
1053
{
1054
bc_num_copy(&r->d.n, n);
1055
bc_num_truncate(&r->d.n, n->scale);
1056
}
1057
#endif // BC_ENABLE_EXTRA_MATH
1058
1059
/**
1060
* Runs a unary operation.
1061
* @param p The program.
1062
* @param inst The unary operation.
1063
*/
1064
static void
1065
bc_program_unary(BcProgram* p, uchar inst)
1066
{
1067
BcResult* res;
1068
BcResult* ptr;
1069
BcNum* num;
1070
1071
res = bc_program_prepResult(p);
1072
1073
assert(p->nresults == 1);
1074
1075
bc_program_prep(p, &ptr, &num, 1);
1076
1077
BC_SIG_LOCK;
1078
1079
bc_num_init(&res->d.n, num->len);
1080
1081
BC_SIG_UNLOCK;
1082
1083
// This calls a function that is in an array.
1084
bc_program_unarys[inst - BC_INST_NEG](res, num);
1085
bc_program_retire(p, 1);
1086
}
1087
1088
/**
1089
* Executes a logical operator.
1090
* @param p The program.
1091
* @param inst The operator.
1092
*/
1093
static void
1094
bc_program_logical(BcProgram* p, uchar inst)
1095
{
1096
BcResult* opd1;
1097
BcResult* opd2;
1098
BcResult* res;
1099
BcNum* n1;
1100
BcNum* n2;
1101
bool cond = 0;
1102
ssize_t cmp;
1103
1104
res = bc_program_prepResult(p);
1105
1106
assert(p->nresults == 1);
1107
1108
// All logical operators (except boolean not, which is taken care of by
1109
// bc_program_unary()), are binary operators.
1110
bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
1111
1112
// Boolean and and or are not short circuiting. This is why; they can be
1113
// implemented much easier this way.
1114
if (inst == BC_INST_BOOL_AND)
1115
{
1116
cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
1117
}
1118
else if (inst == BC_INST_BOOL_OR)
1119
{
1120
cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
1121
}
1122
else
1123
{
1124
// We have a relational operator, so do a comparison.
1125
cmp = bc_num_cmp(n1, n2);
1126
1127
switch (inst)
1128
{
1129
case BC_INST_REL_EQ:
1130
{
1131
cond = (cmp == 0);
1132
break;
1133
}
1134
1135
case BC_INST_REL_LE:
1136
{
1137
cond = (cmp <= 0);
1138
break;
1139
}
1140
1141
case BC_INST_REL_GE:
1142
{
1143
cond = (cmp >= 0);
1144
break;
1145
}
1146
1147
case BC_INST_REL_NE:
1148
{
1149
cond = (cmp != 0);
1150
break;
1151
}
1152
1153
case BC_INST_REL_LT:
1154
{
1155
cond = (cmp < 0);
1156
break;
1157
}
1158
1159
case BC_INST_REL_GT:
1160
{
1161
cond = (cmp > 0);
1162
break;
1163
}
1164
#if BC_DEBUG
1165
default:
1166
{
1167
// There is a bug if we get here.
1168
abort();
1169
}
1170
#endif // BC_DEBUG
1171
}
1172
}
1173
1174
BC_SIG_LOCK;
1175
1176
bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1177
1178
BC_SIG_UNLOCK;
1179
1180
if (cond) bc_num_one(&res->d.n);
1181
1182
bc_program_retire(p, 2);
1183
}
1184
1185
/**
1186
* Assigns a string to a variable.
1187
* @param p The program.
1188
* @param num The location of the string as a BcNum.
1189
* @param v The stack for the variable.
1190
* @param push Whether to push the string or not. To push means to move the
1191
* string from the results stack and push it onto the variable
1192
* stack.
1193
*/
1194
static void
1195
bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
1196
{
1197
BcNum* n;
1198
1199
assert(BC_PROG_STACK(&p->results, 1 + !push));
1200
assert(num != NULL && num->num == NULL && num->cap == 0);
1201
1202
// If we are not pushing onto the variable stack, we need to replace the
1203
// top of the variable stack.
1204
if (!push) bc_vec_pop(v);
1205
1206
bc_vec_npop(&p->results, 1 + !push);
1207
1208
n = bc_vec_pushEmpty(v);
1209
1210
// We can just copy because the num should not have allocated anything.
1211
// NOLINTNEXTLINE
1212
memcpy(n, num, sizeof(BcNum));
1213
}
1214
1215
/**
1216
* Copies a value to a variable. This is used for storing in dc as well as to
1217
* set function parameters to arguments in bc.
1218
* @param p The program.
1219
* @param idx The index of the variable or array to copy to.
1220
* @param t The type to copy to. This could be a variable or an array.
1221
*/
1222
static void
1223
bc_program_copyToVar(BcProgram* p, size_t idx, BcType t)
1224
{
1225
BcResult *ptr = NULL, r;
1226
BcVec* vec;
1227
BcNum* n = NULL;
1228
bool var = (t == BC_TYPE_VAR);
1229
1230
#if DC_ENABLED
1231
// Check the stack for dc.
1232
if (BC_IS_DC)
1233
{
1234
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
1235
}
1236
#endif
1237
1238
assert(BC_PROG_STACK(&p->results, 1));
1239
1240
bc_program_operand(p, &ptr, &n, 0);
1241
1242
#if BC_ENABLED
1243
// Get the variable for a bc function call.
1244
if (BC_IS_BC)
1245
{
1246
// Type match the result.
1247
bc_program_type_match(ptr, t);
1248
}
1249
#endif // BC_ENABLED
1250
1251
vec = bc_program_vec(p, idx, t);
1252
1253
// We can shortcut in dc if it's assigning a string by using
1254
// bc_program_assignStr().
1255
if (ptr->t == BC_RESULT_STR)
1256
{
1257
assert(BC_PROG_STR(n));
1258
1259
if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE);
1260
1261
bc_program_assignStr(p, n, vec, true);
1262
1263
return;
1264
}
1265
1266
BC_SIG_LOCK;
1267
1268
// Just create and copy for a normal variable.
1269
if (var)
1270
{
1271
if (BC_PROG_STR(n))
1272
{
1273
// NOLINTNEXTLINE
1274
memcpy(&r.d.n, n, sizeof(BcNum));
1275
}
1276
else bc_num_createCopy(&r.d.n, n);
1277
}
1278
else
1279
{
1280
// If we get here, we are handling an array. This is one place we need
1281
// to cast the number from bc_program_num() to a vector.
1282
BcVec* v = (BcVec*) n;
1283
BcVec* rv = &r.d.v;
1284
1285
#if BC_ENABLED
1286
1287
if (BC_IS_BC)
1288
{
1289
bool ref, ref_size;
1290
1291
// True if we are using a reference.
1292
ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
1293
1294
// True if we already have a reference vector. This is slightly
1295
// (okay, a lot; it just doesn't look that way) different from
1296
// above. The above means that we need to construct a reference
1297
// vector, whereas this means that we have one and we might have to
1298
// *dereference* it.
1299
ref_size = (v->size == sizeof(uchar));
1300
1301
// If we *should* have a reference.
1302
if (ref || (ref_size && t == BC_TYPE_REF))
1303
{
1304
// Create a new reference vector.
1305
bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE);
1306
1307
// If this is true, then we need to construct a reference.
1308
if (ref)
1309
{
1310
// Make sure the pointer was not invalidated.
1311
vec = bc_program_vec(p, idx, t);
1312
1313
// Push the indices onto the reference vector. This takes
1314
// care of last; it ensures the reference goes to the right
1315
// place.
1316
bc_vec_pushIndex(rv, ptr->d.loc.loc);
1317
bc_vec_pushIndex(rv, ptr->d.loc.stack_idx);
1318
}
1319
// If we get here, we are copying a ref to a ref. Just push a
1320
// copy of all of the bytes.
1321
else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
1322
1323
// Push the reference vector onto the array stack and pop the
1324
// source.
1325
bc_vec_push(vec, &r.d);
1326
bc_vec_pop(&p->results);
1327
1328
// We need to return early to avoid executing code that we must
1329
// not touch.
1330
BC_SIG_UNLOCK;
1331
return;
1332
}
1333
// If we get here, we have a reference, but we need an array, so
1334
// dereference the array.
1335
else if (ref_size && t != BC_TYPE_REF)
1336
{
1337
v = bc_program_dereference(p, v);
1338
}
1339
}
1340
#endif // BC_ENABLED
1341
1342
// If we get here, we need to copy the array because in bc, all
1343
// arguments are passed by value. Yes, this is expensive.
1344
bc_array_init(rv, true);
1345
bc_array_copy(rv, v);
1346
}
1347
1348
// Push the vector onto the array stack and pop the source.
1349
bc_vec_push(vec, &r.d);
1350
bc_vec_pop(&p->results);
1351
1352
BC_SIG_UNLOCK;
1353
}
1354
1355
void
1356
bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val)
1357
{
1358
BcBigDig* ptr_t;
1359
BcBigDig max, min;
1360
#if BC_ENABLED
1361
BcVec* v;
1362
BcBigDig* ptr;
1363
#endif // BC_ENABLED
1364
1365
assert(!scale || !obase);
1366
1367
// Scale needs handling separate from ibase and obase.
1368
if (scale)
1369
{
1370
// Set the min and max.
1371
min = 0;
1372
max = vm->maxes[BC_PROG_GLOBALS_SCALE];
1373
1374
#if BC_ENABLED
1375
// Get a pointer to the stack.
1376
v = p->globals_v + BC_PROG_GLOBALS_SCALE;
1377
#endif // BC_ENABLED
1378
1379
// Get a pointer to the current value.
1380
ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
1381
}
1382
else
1383
{
1384
// Set the min and max.
1385
min = BC_NUM_MIN_BASE;
1386
if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX))
1387
{
1388
min = 0;
1389
}
1390
max = vm->maxes[obase + BC_PROG_GLOBALS_IBASE];
1391
1392
#if BC_ENABLED
1393
// Get a pointer to the stack.
1394
v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase;
1395
#endif // BC_ENABLED
1396
1397
// Get a pointer to the current value.
1398
ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase;
1399
}
1400
1401
// Check for error.
1402
if (BC_ERR(val > max || val < min))
1403
{
1404
BcErr e;
1405
1406
// This grabs the right error.
1407
if (scale) e = BC_ERR_EXEC_SCALE;
1408
else if (obase) e = BC_ERR_EXEC_OBASE;
1409
else e = BC_ERR_EXEC_IBASE;
1410
1411
bc_verr(e, min, max);
1412
}
1413
1414
#if BC_ENABLED
1415
// Set the top of the stack.
1416
ptr = bc_vec_top(v);
1417
*ptr = val;
1418
#endif // BC_ENABLED
1419
1420
// Set the actual global variable.
1421
*ptr_t = val;
1422
}
1423
1424
#if BC_ENABLE_EXTRA_MATH
1425
void
1426
bc_program_assignSeed(BcProgram* p, BcNum* val)
1427
{
1428
bc_num_rng(val, &p->rng);
1429
}
1430
#endif // BC_ENABLE_EXTRA_MATH
1431
1432
/**
1433
* Executes an assignment operator.
1434
* @param p The program.
1435
* @param inst The assignment operator to execute.
1436
*/
1437
static void
1438
bc_program_assign(BcProgram* p, uchar inst)
1439
{
1440
// The local use_val is true when the assigned value needs to be copied.
1441
BcResult* left;
1442
BcResult* right;
1443
BcResult res;
1444
BcNum* l;
1445
BcNum* r;
1446
bool ob, sc, use_val = BC_INST_USE_VAL(inst);
1447
1448
bc_program_assignPrep(p, &left, &l, &right, &r);
1449
1450
// Assigning to a string should be impossible simply because of the parse.
1451
assert(left->t != BC_RESULT_STR);
1452
1453
// If we are assigning a string...
1454
if (right->t == BC_RESULT_STR)
1455
{
1456
assert(BC_PROG_STR(r));
1457
1458
#if BC_ENABLED
1459
if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL)
1460
{
1461
bc_err(BC_ERR_EXEC_TYPE);
1462
}
1463
#endif // BC_ENABLED
1464
1465
// If we are assigning to an array element...
1466
if (left->t == BC_RESULT_ARRAY_ELEM)
1467
{
1468
BC_SIG_LOCK;
1469
1470
// We need to free the number and clear it.
1471
bc_num_free(l);
1472
1473
// NOLINTNEXTLINE
1474
memcpy(l, r, sizeof(BcNum));
1475
1476
// Now we can pop the results.
1477
bc_vec_npop(&p->results, 2);
1478
1479
BC_SIG_UNLOCK;
1480
}
1481
else
1482
{
1483
// If we get here, we are assigning to a variable, which we can use
1484
// bc_program_assignStr() for.
1485
BcVec* v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
1486
bc_program_assignStr(p, r, v, false);
1487
}
1488
1489
#if BC_ENABLED
1490
1491
// If this is true, the value is going to be used again, so we want to
1492
// push a temporary with the string.
1493
if (inst == BC_INST_ASSIGN)
1494
{
1495
res.t = BC_RESULT_STR;
1496
// NOLINTNEXTLINE
1497
memcpy(&res.d.n, r, sizeof(BcNum));
1498
bc_vec_push(&p->results, &res);
1499
}
1500
1501
#endif // BC_ENABLED
1502
1503
// By using bc_program_assignStr(), we short-circuited this, so return.
1504
return;
1505
}
1506
1507
// If we have a normal assignment operator, not a math one...
1508
if (BC_INST_IS_ASSIGN(inst))
1509
{
1510
// Assigning to a variable that has a string here is fine because there
1511
// is no math done on it.
1512
1513
// BC_RESULT_TEMP, BC_RESULT_IBASE, BC_RESULT_OBASE, BC_RESULT_SCALE,
1514
// and BC_RESULT_SEED all have temporary copies. Because that's the
1515
// case, we can free the left and just move the value over. We set the
1516
// type of right to BC_RESULT_ZERO in order to prevent it from being
1517
// freed. We also don't have to worry about BC_RESULT_STR because it's
1518
// take care of above.
1519
if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE)
1520
{
1521
BC_SIG_LOCK;
1522
1523
bc_num_free(l);
1524
// NOLINTNEXTLINE
1525
memcpy(l, r, sizeof(BcNum));
1526
right->t = BC_RESULT_ZERO;
1527
1528
BC_SIG_UNLOCK;
1529
}
1530
// Copy over.
1531
else bc_num_copy(l, r);
1532
}
1533
#if BC_ENABLED
1534
else
1535
{
1536
// If we get here, we are doing a math assignment (+=, -=, etc.). So
1537
// we need to prepare for a binary operator.
1538
BcBigDig scale = BC_PROG_SCALE(p);
1539
1540
// At this point, the left side could still be a string because it could
1541
// be a variable that has the string. If that's the case, we have a type
1542
// error.
1543
if (BC_PROG_STR(l)) bc_err(BC_ERR_EXEC_TYPE);
1544
1545
// Get the right type of assignment operator, whether val is used or
1546
// NO_VAL for performance.
1547
if (!use_val)
1548
{
1549
inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
1550
}
1551
1552
assert(BC_NUM_RDX_VALID(l));
1553
assert(BC_NUM_RDX_VALID(r));
1554
1555
// Run the actual operation. We do not need worry about reallocating l
1556
// because bc_num_binary() does that behind the scenes for us.
1557
bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
1558
}
1559
#endif // BC_ENABLED
1560
1561
ob = (left->t == BC_RESULT_OBASE);
1562
sc = (left->t == BC_RESULT_SCALE);
1563
1564
// The globals need special handling, especially the non-seed ones. The
1565
// first part of the if statement handles them.
1566
if (ob || sc || left->t == BC_RESULT_IBASE)
1567
{
1568
// Get the actual value.
1569
BcBigDig val = bc_num_bigdig(l);
1570
1571
bc_program_assignBuiltin(p, sc, ob, val);
1572
}
1573
#if BC_ENABLE_EXTRA_MATH
1574
// To assign to steed, let bc_num_rng() do its magic.
1575
else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l);
1576
#endif // BC_ENABLE_EXTRA_MATH
1577
1578
BC_SIG_LOCK;
1579
1580
// If we needed to use the value, then we need to copy it. Otherwise, we can
1581
// pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP.
1582
if (use_val)
1583
{
1584
bc_num_createCopy(&res.d.n, l);
1585
res.t = BC_RESULT_TEMP;
1586
bc_vec_npop(&p->results, 2);
1587
bc_vec_push(&p->results, &res);
1588
}
1589
else bc_vec_npop(&p->results, 2);
1590
1591
BC_SIG_UNLOCK;
1592
}
1593
1594
/**
1595
* Pushes a variable's value onto the results stack.
1596
* @param p The program.
1597
* @param code The bytecode vector to pull the variable's index out of.
1598
* @param bgn An in/out parameter; the start of the index in the bytecode
1599
* vector, and will be updated to point after the index on return.
1600
* @param pop True if the variable's value should be popped off its stack.
1601
* This is only used in dc.
1602
* @param copy True if the variable's value should be copied to the results
1603
* stack. This is only used in dc.
1604
*/
1605
static void
1606
bc_program_pushVar(BcProgram* p, const char* restrict code,
1607
size_t* restrict bgn, bool pop, bool copy)
1608
{
1609
BcResult r;
1610
size_t idx = bc_program_index(code, bgn);
1611
BcVec* v;
1612
1613
// Set the result appropriately.
1614
r.t = BC_RESULT_VAR;
1615
r.d.loc.loc = idx;
1616
1617
// Get the stack for the variable. This is used in both bc and dc.
1618
v = bc_program_vec(p, idx, BC_TYPE_VAR);
1619
r.d.loc.stack_idx = v->len - 1;
1620
1621
#if DC_ENABLED
1622
// If this condition is true, then we have the hard case, where we have to
1623
// adjust dc registers.
1624
if (BC_IS_DC && (pop || copy))
1625
{
1626
// Get the number at the top at the top of the stack.
1627
BcNum* num = bc_vec_top(v);
1628
1629
// Ensure there are enough elements on the stack.
1630
if (BC_ERR(!BC_PROG_STACK(v, 2 - copy)))
1631
{
1632
const char* name = bc_map_name(&p->var_map, idx);
1633
bc_verr(BC_ERR_EXEC_STACK_REGISTER, name);
1634
}
1635
1636
assert(BC_PROG_STACK(v, 2 - copy));
1637
1638
// If the top of the stack is actually a number...
1639
if (!BC_PROG_STR(num))
1640
{
1641
BC_SIG_LOCK;
1642
1643
// Create a copy to go onto the results stack as appropriate.
1644
r.t = BC_RESULT_TEMP;
1645
bc_num_createCopy(&r.d.n, num);
1646
1647
// If we are not actually copying, we need to do a replace, so pop.
1648
if (!copy) bc_vec_pop(v);
1649
1650
bc_vec_push(&p->results, &r);
1651
1652
BC_SIG_UNLOCK;
1653
1654
return;
1655
}
1656
else
1657
{
1658
// Set the string result. We can just memcpy because all of the
1659
// fields in the num should be cleared.
1660
// NOLINTNEXTLINE
1661
memcpy(&r.d.n, num, sizeof(BcNum));
1662
r.t = BC_RESULT_STR;
1663
}
1664
1665
// If we are not actually copying, we need to do a replace, so pop.
1666
if (!copy) bc_vec_pop(v);
1667
}
1668
#endif // DC_ENABLED
1669
1670
bc_vec_push(&p->results, &r);
1671
}
1672
1673
/**
1674
* Pushes an array or an array element onto the results stack.
1675
* @param p The program.
1676
* @param code The bytecode vector to pull the variable's index out of.
1677
* @param bgn An in/out parameter; the start of the index in the bytecode
1678
* vector, and will be updated to point after the index on return.
1679
* @param inst The instruction; whether to push an array or an array element.
1680
*/
1681
static void
1682
bc_program_pushArray(BcProgram* p, const char* restrict code,
1683
size_t* restrict bgn, uchar inst)
1684
{
1685
BcResult r;
1686
BcResult* operand;
1687
BcNum* num;
1688
BcBigDig temp;
1689
BcVec* v;
1690
1691
// Get the index of the array.
1692
r.d.loc.loc = bc_program_index(code, bgn);
1693
1694
// We need the array to get its length.
1695
v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY);
1696
assert(v != NULL);
1697
1698
r.d.loc.stack_idx = v->len - 1;
1699
1700
// Doing an array is easy; just set the result type and finish.
1701
if (inst == BC_INST_ARRAY)
1702
{
1703
r.t = BC_RESULT_ARRAY;
1704
bc_vec_push(&p->results, &r);
1705
return;
1706
}
1707
1708
// Grab the top element of the results stack for the array index.
1709
bc_program_prep(p, &operand, &num, 0);
1710
temp = bc_num_bigdig(num);
1711
1712
// Set the result.
1713
r.t = BC_RESULT_ARRAY_ELEM;
1714
r.d.loc.idx = (size_t) temp;
1715
1716
BC_SIG_LOCK;
1717
1718
// Pop the index and push the element.
1719
bc_vec_pop(&p->results);
1720
bc_vec_push(&p->results, &r);
1721
1722
BC_SIG_UNLOCK;
1723
}
1724
1725
#if BC_ENABLED
1726
1727
/**
1728
* Executes an increment or decrement operator. This only handles postfix
1729
* inc/dec because the parser translates prefix inc/dec into an assignment where
1730
* the value is used.
1731
* @param p The program.
1732
* @param inst The instruction; whether to do an increment or decrement.
1733
*/
1734
static void
1735
bc_program_incdec(BcProgram* p, uchar inst)
1736
{
1737
BcResult *ptr, res, copy;
1738
BcNum* num;
1739
uchar inst2;
1740
1741
bc_program_prep(p, &ptr, &num, 0);
1742
1743
BC_SIG_LOCK;
1744
1745
// We need a copy from *before* the operation.
1746
copy.t = BC_RESULT_TEMP;
1747
bc_num_createCopy(&copy.d.n, num);
1748
1749
BC_SETJMP_LOCKED(vm, exit);
1750
1751
BC_SIG_UNLOCK;
1752
1753
// Create the proper assignment.
1754
res.t = BC_RESULT_ONE;
1755
inst2 = BC_INST_ASSIGN_PLUS_NO_VAL + (inst & 0x01);
1756
1757
bc_vec_push(&p->results, &res);
1758
bc_program_assign(p, inst2);
1759
1760
BC_SIG_LOCK;
1761
1762
bc_vec_push(&p->results, &copy);
1763
1764
BC_UNSETJMP(vm);
1765
1766
BC_SIG_UNLOCK;
1767
1768
// No need to free the copy here because we pushed it onto the stack.
1769
return;
1770
1771
exit:
1772
BC_SIG_MAYLOCK;
1773
bc_num_free(&copy.d.n);
1774
BC_LONGJMP_CONT(vm);
1775
}
1776
1777
/**
1778
* Executes a function call for bc.
1779
* @param p The program.
1780
* @param code The bytecode vector to pull the number of arguments and the
1781
* function index out of.
1782
* @param bgn An in/out parameter; the start of the indices in the bytecode
1783
* vector, and will be updated to point after the indices on
1784
* return.
1785
*/
1786
static void
1787
bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn)
1788
{
1789
BcInstPtr ip;
1790
size_t i, nargs;
1791
BcFunc* f;
1792
BcVec* v;
1793
BcAuto* a;
1794
BcResult* arg;
1795
1796
// Pull the number of arguments out of the bytecode vector.
1797
nargs = bc_program_index(code, bgn);
1798
1799
// Set up instruction pointer.
1800
ip.idx = 0;
1801
ip.func = bc_program_index(code, bgn);
1802
f = bc_vec_item(&p->fns, ip.func);
1803
1804
// Error checking.
1805
if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1806
if (BC_ERR(nargs != f->nparams))
1807
{
1808
bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs);
1809
}
1810
1811
// Set the length of the results stack. We discount the argument, of course.
1812
ip.len = p->results.len - nargs;
1813
1814
assert(BC_PROG_STACK(&p->results, nargs));
1815
1816
// Prepare the globals' stacks.
1817
if (BC_G) bc_program_prepGlobals(p);
1818
1819
// Push the arguments onto the stacks of their respective parameters.
1820
for (i = 0; i < nargs; ++i)
1821
{
1822
arg = bc_vec_top(&p->results);
1823
if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
1824
1825
// Get the corresponding parameter.
1826
a = bc_vec_item(&f->autos, nargs - 1 - i);
1827
1828
// Actually push the value onto the parameter's stack.
1829
bc_program_copyToVar(p, a->idx, a->type);
1830
}
1831
1832
BC_SIG_LOCK;
1833
1834
// Push zeroes onto the stacks of the auto variables.
1835
for (; i < f->autos.len; ++i)
1836
{
1837
// Get the auto and its stack.
1838
a = bc_vec_item(&f->autos, i);
1839
v = bc_program_vec(p, a->idx, a->type);
1840
1841
// If a variable, just push a 0; otherwise, push an array.
1842
if (a->type == BC_TYPE_VAR)
1843
{
1844
BcNum* n = bc_vec_pushEmpty(v);
1845
bc_num_init(n, BC_NUM_DEF_SIZE);
1846
}
1847
else
1848
{
1849
BcVec* v2;
1850
1851
assert(a->type == BC_TYPE_ARRAY);
1852
1853
v2 = bc_vec_pushEmpty(v);
1854
bc_array_init(v2, true);
1855
}
1856
}
1857
1858
// Push the instruction pointer onto the execution stack.
1859
bc_vec_push(&p->stack, &ip);
1860
1861
BC_SIG_UNLOCK;
1862
}
1863
1864
/**
1865
* Executes a return instruction.
1866
* @param p The program.
1867
* @param inst The return instruction. bc can return void, and we need to know
1868
* if it is.
1869
*/
1870
static void
1871
bc_program_return(BcProgram* p, uchar inst)
1872
{
1873
BcResult* res;
1874
BcFunc* f;
1875
BcInstPtr* ip;
1876
size_t i, nresults;
1877
1878
// Get the instruction pointer.
1879
ip = bc_vec_top(&p->stack);
1880
1881
// Get the difference between the actual number of results and the number of
1882
// results the caller expects.
1883
nresults = p->results.len - ip->len;
1884
1885
// If this isn't true, there was a missing call somewhere.
1886
assert(BC_PROG_STACK(&p->stack, 2));
1887
1888
// If this isn't true, the parser screwed by giving us no value when we
1889
// expected one, or giving us a value when we expected none.
1890
assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1891
1892
// Get the function we are returning from.
1893
f = bc_vec_item(&p->fns, ip->func);
1894
1895
res = bc_program_prepResult(p);
1896
1897
assert(p->nresults == 1);
1898
1899
// If we are returning normally...
1900
if (inst == BC_INST_RET)
1901
{
1902
BcNum* num;
1903
BcResult* operand;
1904
1905
// Prepare and copy the return value.
1906
bc_program_operand(p, &operand, &num, 1);
1907
1908
if (BC_PROG_STR(num))
1909
{
1910
// We need to set this because otherwise, it will be a
1911
// BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make
1912
// it easier to do type checking.
1913
res->t = BC_RESULT_STR;
1914
1915
// NOLINTNEXTLINE
1916
memcpy(&res->d.n, num, sizeof(BcNum));
1917
}
1918
else
1919
{
1920
BC_SIG_LOCK;
1921
1922
bc_num_createCopy(&res->d.n, num);
1923
}
1924
}
1925
// Void is easy; set the result.
1926
else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1927
else
1928
{
1929
BC_SIG_LOCK;
1930
1931
// If we get here, the instruction is for returning a zero, so do that.
1932
bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1933
}
1934
1935
BC_SIG_MAYUNLOCK;
1936
1937
// We need to pop items off of the stacks of arguments and autos as well.
1938
for (i = 0; i < f->autos.len; ++i)
1939
{
1940
BcAuto* a = bc_vec_item(&f->autos, i);
1941
BcVec* v = bc_program_vec(p, a->idx, a->type);
1942
1943
bc_vec_pop(v);
1944
}
1945
1946
BC_SIG_LOCK;
1947
1948
// When we retire, pop all of the unused results.
1949
bc_program_retire(p, nresults);
1950
1951
// Pop the globals, if necessary.
1952
if (BC_G) bc_program_popGlobals(p, false);
1953
1954
// Pop the stack. This is what causes the function to actually "return."
1955
bc_vec_pop(&p->stack);
1956
1957
BC_SIG_UNLOCK;
1958
}
1959
#endif // BC_ENABLED
1960
1961
/**
1962
* Executes a builtin function.
1963
* @param p The program.
1964
* @param inst The builtin to execute.
1965
*/
1966
static void
1967
bc_program_builtin(BcProgram* p, uchar inst)
1968
{
1969
BcResult* opd;
1970
BcResult* res;
1971
BcNum* num;
1972
bool len = (inst == BC_INST_LENGTH);
1973
1974
// Ensure we have a valid builtin.
1975
#if BC_ENABLE_EXTRA_MATH
1976
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1977
#else // BC_ENABLE_EXTRA_MATH
1978
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
1979
#endif // BC_ENABLE_EXTRA_MATH
1980
1981
#ifndef BC_PROG_NO_STACK_CHECK
1982
// Check stack for dc.
1983
if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1984
{
1985
bc_err(BC_ERR_EXEC_STACK);
1986
}
1987
#endif // BC_PROG_NO_STACK_CHECK
1988
1989
assert(BC_PROG_STACK(&p->results, 1));
1990
1991
res = bc_program_prepResult(p);
1992
1993
assert(p->nresults == 1);
1994
1995
bc_program_operand(p, &opd, &num, 1);
1996
1997
assert(num != NULL);
1998
1999
// We need to ensure that strings and arrays aren't passed to most builtins.
2000
// The scale function can take strings in dc.
2001
if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
2002
inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
2003
{
2004
bc_program_type_num(opd, num);
2005
}
2006
2007
// Square root is easy.
2008
if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
2009
2010
// Absolute value is easy.
2011
else if (inst == BC_INST_ABS)
2012
{
2013
BC_SIG_LOCK;
2014
2015
bc_num_createCopy(&res->d.n, num);
2016
2017
BC_SIG_UNLOCK;
2018
2019
BC_NUM_NEG_CLR_NP(res->d.n);
2020
}
2021
2022
// Testing for number or string is easy.
2023
else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
2024
{
2025
bool cond;
2026
bool is_str;
2027
2028
BC_SIG_LOCK;
2029
2030
bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
2031
2032
BC_SIG_UNLOCK;
2033
2034
// Test if the number is a string.
2035
is_str = BC_PROG_STR(num);
2036
2037
// This confusing condition simply means that the instruction must be
2038
// true if is_str is, or it must be false if is_str is. Otherwise, the
2039
// returned value is false (0).
2040
cond = ((inst == BC_INST_IS_STRING) == is_str);
2041
if (cond) bc_num_one(&res->d.n);
2042
}
2043
2044
#if BC_ENABLE_EXTRA_MATH
2045
2046
// irand() is easy.
2047
else if (inst == BC_INST_IRAND)
2048
{
2049
BC_SIG_LOCK;
2050
2051
bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num));
2052
2053
BC_SIG_UNLOCK;
2054
2055
bc_num_irand(num, &res->d.n, &p->rng);
2056
}
2057
2058
#endif // BC_ENABLE_EXTRA_MATH
2059
2060
// Everything else is...not easy.
2061
else
2062
{
2063
BcBigDig val = 0;
2064
2065
// Well, scale() is easy, but length() is not.
2066
if (len)
2067
{
2068
// If we are bc and we have an array...
2069
if (opd->t == BC_RESULT_ARRAY)
2070
{
2071
// Yes, this is one place where we need to cast the number from
2072
// bc_program_num() to a vector.
2073
BcVec* v = (BcVec*) num;
2074
2075
// XXX: If this is changed, you should also change the similar
2076
// code in bc_program_asciify().
2077
2078
#if BC_ENABLED
2079
// Dereference the array, if necessary.
2080
if (BC_IS_BC && v->size == sizeof(uchar))
2081
{
2082
v = bc_program_dereference(p, v);
2083
}
2084
#endif // BC_ENABLED
2085
2086
assert(v->size == sizeof(BcNum));
2087
2088
val = (BcBigDig) v->len;
2089
}
2090
else
2091
{
2092
// If the item is a string...
2093
if (!BC_PROG_NUM(opd, num))
2094
{
2095
char* str;
2096
2097
// Get the string, then get the length.
2098
str = bc_program_string(p, num);
2099
val = (BcBigDig) strlen(str);
2100
}
2101
else
2102
{
2103
// Calculate the length of the number.
2104
val = (BcBigDig) bc_num_len(num);
2105
}
2106
}
2107
}
2108
// Like I said; scale() is actually easy. It just also needs the integer
2109
// conversion that length() does.
2110
else if (BC_IS_BC || BC_PROG_NUM(opd, num))
2111
{
2112
val = (BcBigDig) bc_num_scale(num);
2113
}
2114
2115
BC_SIG_LOCK;
2116
2117
// Create the result.
2118
bc_num_createFromBigdig(&res->d.n, val);
2119
2120
BC_SIG_UNLOCK;
2121
}
2122
2123
bc_program_retire(p, 1);
2124
}
2125
2126
/**
2127
* Executes a divmod.
2128
* @param p The program.
2129
*/
2130
static void
2131
bc_program_divmod(BcProgram* p)
2132
{
2133
BcResult* opd1;
2134
BcResult* opd2;
2135
BcResult* res;
2136
BcResult* res2;
2137
BcNum* n1;
2138
BcNum* n2;
2139
size_t req;
2140
2141
// We grow first to avoid pointer invalidation.
2142
bc_vec_grow(&p->results, 2);
2143
2144
// We don't need to update the pointer because
2145
// the capacity is enough due to the line above.
2146
res2 = bc_program_prepResult(p);
2147
res = bc_program_prepResult(p);
2148
assert(p->nresults == 2);
2149
2150
// Prepare the operands.
2151
bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
2152
2153
req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
2154
2155
BC_SIG_LOCK;
2156
2157
// Initialize the results.
2158
bc_num_init(&res->d.n, req);
2159
bc_num_init(&res2->d.n, req);
2160
2161
BC_SIG_UNLOCK;
2162
2163
// Execute.
2164
bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
2165
2166
bc_program_retire(p, 2);
2167
}
2168
2169
/**
2170
* Executes modular exponentiation.
2171
* @param p The program.
2172
*/
2173
static void
2174
bc_program_modexp(BcProgram* p)
2175
{
2176
BcResult* r1;
2177
BcResult* r2;
2178
BcResult* r3;
2179
BcResult* res;
2180
BcNum* n1;
2181
BcNum* n2;
2182
BcNum* n3;
2183
2184
#if DC_ENABLED
2185
2186
// Check the stack.
2187
if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3)))
2188
{
2189
bc_err(BC_ERR_EXEC_STACK);
2190
}
2191
2192
#endif // DC_ENABLED
2193
2194
assert(BC_PROG_STACK(&p->results, 3));
2195
2196
res = bc_program_prepResult(p);
2197
2198
assert(p->nresults == 1);
2199
2200
// Get the first operand and typecheck.
2201
bc_program_operand(p, &r1, &n1, 3);
2202
bc_program_type_num(r1, n1);
2203
2204
// Get the last two operands.
2205
bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
2206
2207
// Make sure that the values have their pointers updated, if necessary.
2208
// Only array elements are possible because this is dc.
2209
if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
2210
{
2211
n1 = bc_program_num(p, r1);
2212
}
2213
2214
BC_SIG_LOCK;
2215
2216
bc_num_init(&res->d.n, n3->len);
2217
2218
BC_SIG_UNLOCK;
2219
2220
bc_num_modexp(n1, n2, n3, &res->d.n);
2221
2222
bc_program_retire(p, 3);
2223
}
2224
2225
/**
2226
* Asciifies a number for dc. This is a helper for bc_program_asciify().
2227
* @param p The program.
2228
* @param n The number to asciify.
2229
*/
2230
static uchar
2231
bc_program_asciifyNum(BcProgram* p, BcNum* n)
2232
{
2233
bc_num_copy(&p->asciify, n);
2234
2235
// We want to clear the scale and sign for easy mod later.
2236
bc_num_truncate(&p->asciify, p->asciify.scale);
2237
BC_NUM_NEG_CLR(&p->asciify);
2238
2239
// This is guaranteed to not have a divide by 0
2240
// because strmb is equal to 256.
2241
bc_num_mod(&p->asciify, &p->strmb, &p->asciify, 0);
2242
2243
// This is also guaranteed to not error because num is in the range
2244
// [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
2245
// it is not negative.
2246
return (uchar) bc_num_bigdig2(&p->asciify);
2247
}
2248
2249
/**
2250
* Executes the "asciify" command in bc and dc.
2251
* @param p The program.
2252
*/
2253
static void
2254
bc_program_asciify(BcProgram* p)
2255
{
2256
BcResult *r, res;
2257
BcNum* n;
2258
uchar c;
2259
size_t idx;
2260
#if BC_ENABLED
2261
// This is in the outer scope because it has to be freed after a jump.
2262
char* temp_str;
2263
#endif // BC_ENABLED
2264
2265
// Check the stack.
2266
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2267
2268
assert(BC_PROG_STACK(&p->results, 1));
2269
2270
// Get the top of the results stack.
2271
bc_program_operand(p, &r, &n, 0);
2272
2273
assert(n != NULL);
2274
assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
2275
2276
#if BC_ENABLED
2277
// Handle arrays in bc specially.
2278
if (r->t == BC_RESULT_ARRAY)
2279
{
2280
// Yes, this is one place where we need to cast the number from
2281
// bc_program_num() to a vector.
2282
BcVec* v = (BcVec*) n;
2283
size_t i;
2284
2285
// XXX: If this is changed, you should also change the similar code in
2286
// bc_program_builtin().
2287
2288
// Dereference the array, if necessary.
2289
if (v->size == sizeof(uchar))
2290
{
2291
v = bc_program_dereference(p, v);
2292
}
2293
2294
assert(v->size == sizeof(BcNum));
2295
2296
// Allocate the string and set the jump for it.
2297
BC_SIG_LOCK;
2298
temp_str = bc_vm_malloc(v->len + 1);
2299
BC_SETJMP_LOCKED(vm, exit);
2300
BC_SIG_UNLOCK;
2301
2302
// Convert the array.
2303
for (i = 0; i < v->len; ++i)
2304
{
2305
BcNum* num = (BcNum*) bc_vec_item(v, i);
2306
2307
if (BC_PROG_STR(num))
2308
{
2309
temp_str[i] = (bc_program_string(p, num))[0];
2310
}
2311
else
2312
{
2313
temp_str[i] = (char) bc_program_asciifyNum(p, num);
2314
}
2315
}
2316
2317
temp_str[v->len] = '\0';
2318
2319
// Store the string in the slab and map, and free the temp string.
2320
BC_SIG_LOCK;
2321
idx = bc_program_addString(p, temp_str);
2322
free(temp_str);
2323
BC_UNSETJMP(vm);
2324
BC_SIG_UNLOCK;
2325
}
2326
else
2327
#endif // BC_ENABLED
2328
{
2329
char str[2];
2330
char* str2;
2331
2332
// Asciify.
2333
if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
2334
else
2335
{
2336
// Get the string itself, then the first character.
2337
str2 = bc_program_string(p, n);
2338
c = (uchar) str2[0];
2339
}
2340
2341
// Fill the resulting string.
2342
str[0] = (char) c;
2343
str[1] = '\0';
2344
2345
// Add the string to the data structures.
2346
BC_SIG_LOCK;
2347
idx = bc_program_addString(p, str);
2348
BC_SIG_UNLOCK;
2349
}
2350
2351
// Set the result
2352
res.t = BC_RESULT_STR;
2353
bc_num_clear(&res.d.n);
2354
res.d.n.scale = idx;
2355
2356
// Pop and push.
2357
bc_vec_pop(&p->results);
2358
bc_vec_push(&p->results, &res);
2359
2360
return;
2361
2362
#if BC_ENABLED
2363
exit:
2364
free(temp_str);
2365
#endif // BC_ENABLED
2366
}
2367
2368
/**
2369
* Streams a number or a string to stdout.
2370
* @param p The program.
2371
*/
2372
static void
2373
bc_program_printStream(BcProgram* p)
2374
{
2375
BcResult* r;
2376
BcNum* n;
2377
2378
// Check the stack.
2379
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2380
2381
assert(BC_PROG_STACK(&p->results, 1));
2382
2383
// Get the top of the results stack.
2384
bc_program_operand(p, &r, &n, 0);
2385
2386
assert(n != NULL);
2387
2388
// Stream appropriately.
2389
if (BC_PROG_NUM(r, n)) bc_num_stream(n);
2390
else bc_program_printChars(bc_program_string(p, n));
2391
2392
// Pop the operand.
2393
bc_vec_pop(&p->results);
2394
}
2395
2396
#if DC_ENABLED
2397
2398
/**
2399
* Gets the length of a register in dc and pushes it onto the results stack.
2400
* @param p The program.
2401
* @param code The bytecode vector to pull the register's index out of.
2402
* @param bgn An in/out parameter; the start of the index in the bytecode
2403
* vector, and will be updated to point after the index on return.
2404
*/
2405
static void
2406
bc_program_regStackLen(BcProgram* p, const char* restrict code,
2407
size_t* restrict bgn)
2408
{
2409
size_t idx = bc_program_index(code, bgn);
2410
BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR);
2411
2412
bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP);
2413
}
2414
2415
/**
2416
* Pushes the length of the results stack onto the results stack.
2417
* @param p The program.
2418
*/
2419
static void
2420
bc_program_stackLen(BcProgram* p)
2421
{
2422
bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
2423
}
2424
2425
/**
2426
* Pops a certain number of elements off the execution stack.
2427
* @param p The program.
2428
* @param inst The instruction to tell us how many. There is one to pop up to
2429
* 2, and one to pop the amount equal to the number at the top of
2430
* the results stack.
2431
*/
2432
static void
2433
bc_program_nquit(BcProgram* p, uchar inst)
2434
{
2435
BcResult* opnd;
2436
BcNum* num;
2437
BcBigDig val;
2438
size_t i;
2439
2440
// Ensure that the tail calls stack is correct.
2441
assert(p->stack.len == p->tail_calls.len);
2442
2443
// Get the number of executions to pop.
2444
if (inst == BC_INST_QUIT) val = 2;
2445
else
2446
{
2447
bc_program_prep(p, &opnd, &num, 0);
2448
val = bc_num_bigdig(num);
2449
2450
bc_vec_pop(&p->results);
2451
}
2452
2453
// Loop over the tail call stack and adjust the quit value appropriately.
2454
for (i = 0; val && i < p->tail_calls.len; ++i)
2455
{
2456
// Get the number of tail calls for this one.
2457
size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
2458
2459
// Adjust the value.
2460
if (calls >= val) val = 0;
2461
else val -= (BcBigDig) calls;
2462
}
2463
2464
// If we don't have enough executions, just quit.
2465
if (i == p->stack.len)
2466
{
2467
vm->status = BC_STATUS_QUIT;
2468
BC_JMP;
2469
}
2470
else
2471
{
2472
// We can always pop the last item we reached on the tail call stack
2473
// because these are for tail calls. That means that any executions that
2474
// we would not have quit in that position on the stack would have quit
2475
// anyway.
2476
BC_SIG_LOCK;
2477
bc_vec_npop(&p->stack, i);
2478
bc_vec_npop(&p->tail_calls, i);
2479
BC_SIG_UNLOCK;
2480
}
2481
}
2482
2483
/**
2484
* Pushes the depth of the execution stack onto the stack.
2485
* @param p The program.
2486
*/
2487
static void
2488
bc_program_execStackLen(BcProgram* p)
2489
{
2490
size_t i, amt, len = p->tail_calls.len;
2491
2492
amt = len;
2493
2494
for (i = 0; i < len; ++i)
2495
{
2496
amt += *((size_t*) bc_vec_item(&p->tail_calls, i));
2497
}
2498
2499
bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP);
2500
}
2501
2502
/**
2503
*
2504
* @param p The program.
2505
* @param code The bytecode vector to pull the register's index out of.
2506
* @param bgn An in/out parameter; the start of the index in the bytecode
2507
* vector, and will be updated to point after the index on return.
2508
* @param cond True if the execution is conditional, false otherwise.
2509
* @param len The number of bytes in the bytecode vector.
2510
*/
2511
static void
2512
bc_program_execStr(BcProgram* p, const char* restrict code,
2513
size_t* restrict bgn, bool cond, size_t len)
2514
{
2515
BcResult* r;
2516
char* str;
2517
BcFunc* f;
2518
BcInstPtr ip;
2519
size_t fidx;
2520
BcNum* n;
2521
2522
assert(p->stack.len == p->tail_calls.len);
2523
2524
// Check the stack.
2525
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2526
2527
assert(BC_PROG_STACK(&p->results, 1));
2528
2529
// Get the operand.
2530
bc_program_operand(p, &r, &n, 0);
2531
2532
// If execution is conditional...
2533
if (cond)
2534
{
2535
bool exec;
2536
size_t then_idx;
2537
// These are volatile to quiet warnings on GCC about clobbering with
2538
// longjmp().
2539
volatile size_t else_idx;
2540
volatile size_t idx;
2541
2542
// Get the index of the "then" var and "else" var.
2543
then_idx = bc_program_index(code, bgn);
2544
else_idx = bc_program_index(code, bgn);
2545
2546
// Figure out if we should execute.
2547
exec = (r->d.n.len != 0);
2548
2549
idx = exec ? then_idx : else_idx;
2550
2551
BC_SIG_LOCK;
2552
BC_SETJMP_LOCKED(vm, exit);
2553
2554
// If we are supposed to execute, execute. If else_idx == SIZE_MAX, that
2555
// means there was no else clause, so if execute is false and else does
2556
// not exist, we don't execute. The goto skips all of the setup for the
2557
// execution.
2558
if (exec || (else_idx != SIZE_MAX))
2559
{
2560
n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
2561
}
2562
else goto exit;
2563
2564
if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE);
2565
2566
BC_UNSETJMP(vm);
2567
BC_SIG_UNLOCK;
2568
}
2569
else
2570
{
2571
// In non-conditional situations, only the top of stack can be executed,
2572
// and in those cases, variables are not allowed to be "on the stack";
2573
// they are only put on the stack to be assigned to.
2574
assert(r->t != BC_RESULT_VAR);
2575
2576
if (r->t != BC_RESULT_STR) return;
2577
}
2578
2579
assert(BC_PROG_STR(n));
2580
2581
// Get the string.
2582
str = bc_program_string(p, n);
2583
2584
// Get the function index and function.
2585
BC_SIG_LOCK;
2586
fidx = bc_program_insertFunc(p, str);
2587
BC_SIG_UNLOCK;
2588
f = bc_vec_item(&p->fns, fidx);
2589
2590
// If the function has not been parsed yet...
2591
if (!f->code.len)
2592
{
2593
BC_SIG_LOCK;
2594
2595
if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
2596
{
2597
bc_parse_init(&vm->read_prs, p, fidx);
2598
2599
// Initialize this too because bc_vm_shutdown() expects them to be
2600
// initialized togther.
2601
bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
2602
}
2603
// This needs to be updated because the parser could have been used
2604
// somewhere else
2605
else bc_parse_updateFunc(&vm->read_prs, fidx);
2606
2607
bc_lex_file(&vm->read_prs.l, vm->file);
2608
2609
BC_SETJMP_LOCKED(vm, err);
2610
2611
BC_SIG_UNLOCK;
2612
2613
// Parse. Only one expression is needed, so stdin isn't used.
2614
bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
2615
2616
BC_SIG_LOCK;
2617
vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
2618
2619
BC_UNSETJMP(vm);
2620
2621
// We can just assert this here because
2622
// dc should parse everything until EOF.
2623
assert(vm->read_prs.l.t == BC_LEX_EOF);
2624
2625
BC_SIG_UNLOCK;
2626
}
2627
2628
// Set the instruction pointer.
2629
ip.idx = 0;
2630
ip.len = p->results.len;
2631
ip.func = fidx;
2632
2633
BC_SIG_LOCK;
2634
2635
// Pop the operand.
2636
bc_vec_pop(&p->results);
2637
2638
// Tail call processing. This condition means that there is more on the
2639
// execution stack, and we are at the end of the bytecode vector, and the
2640
// last instruction is just a BC_INST_POP_EXEC, which would return.
2641
if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC)
2642
{
2643
size_t* call_ptr = bc_vec_top(&p->tail_calls);
2644
2645
// Add one to the tail call.
2646
*call_ptr += 1;
2647
2648
// Pop the execution stack before pushing the new instruction pointer
2649
// on.
2650
bc_vec_pop(&p->stack);
2651
}
2652
// If not a tail call, just push a new one.
2653
else bc_vec_push(&p->tail_calls, &ip.idx);
2654
2655
// Push the new function onto the execution stack and return.
2656
bc_vec_push(&p->stack, &ip);
2657
2658
BC_SIG_UNLOCK;
2659
2660
return;
2661
2662
err:
2663
BC_SIG_MAYLOCK;
2664
2665
f = bc_vec_item(&p->fns, fidx);
2666
2667
// Make sure to erase the bytecode vector so dc knows it is not parsed.
2668
bc_vec_popAll(&f->code);
2669
2670
exit:
2671
bc_vec_pop(&p->results);
2672
BC_LONGJMP_CONT(vm);
2673
}
2674
2675
/**
2676
* Prints every item on the results stack, one per line.
2677
* @param p The program.
2678
*/
2679
static void
2680
bc_program_printStack(BcProgram* p)
2681
{
2682
size_t idx;
2683
2684
for (idx = 0; idx < p->results.len; ++idx)
2685
{
2686
bc_program_print(p, BC_INST_PRINT, idx);
2687
}
2688
}
2689
#endif // DC_ENABLED
2690
2691
/**
2692
* Pushes the value of a global onto the results stack.
2693
* @param p The program.
2694
* @param inst Which global to push, as an instruction.
2695
*/
2696
static void
2697
bc_program_pushGlobal(BcProgram* p, uchar inst)
2698
{
2699
BcResultType t;
2700
2701
// Make sure the instruction is valid.
2702
assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
2703
2704
// Push the global.
2705
t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
2706
bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
2707
}
2708
2709
/**
2710
* Pushes the value of a global setting onto the stack.
2711
* @param p The program.
2712
* @param inst Which global setting to push, as an instruction.
2713
*/
2714
static void
2715
bc_program_globalSetting(BcProgram* p, uchar inst)
2716
{
2717
BcBigDig val;
2718
2719
// Make sure the instruction is valid.
2720
#if DC_ENABLED
2721
assert((inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO) ||
2722
(BC_IS_DC && inst == BC_INST_EXTENDED_REGISTERS));
2723
#else // DC_ENABLED
2724
assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO);
2725
#endif // DC_ENABLED
2726
2727
if (inst == BC_INST_LINE_LENGTH)
2728
{
2729
val = (BcBigDig) vm->line_len;
2730
}
2731
#if BC_ENABLED
2732
else if (inst == BC_INST_GLOBAL_STACKS)
2733
{
2734
val = (BC_G != 0);
2735
}
2736
#endif // BC_ENABLED
2737
#if DC_ENABLED
2738
else if (inst == BC_INST_EXTENDED_REGISTERS)
2739
{
2740
val = (DC_X != 0);
2741
}
2742
#endif // DC_ENABLED
2743
else val = (BC_Z != 0);
2744
2745
// Push the global.
2746
bc_program_pushBigdig(p, val, BC_RESULT_TEMP);
2747
}
2748
2749
#if BC_ENABLE_EXTRA_MATH
2750
2751
/**
2752
* Pushes the value of seed on the stack.
2753
* @param p The program.
2754
*/
2755
static void
2756
bc_program_pushSeed(BcProgram* p)
2757
{
2758
BcResult* res;
2759
2760
res = bc_program_prepResult(p);
2761
2762
assert(p->nresults == 1);
2763
2764
res->t = BC_RESULT_SEED;
2765
2766
BC_SIG_LOCK;
2767
2768
// We need 2*BC_RAND_NUM_SIZE because of the size of the state.
2769
bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
2770
2771
BC_SIG_UNLOCK;
2772
2773
bc_num_createFromRNG(&res->d.n, &p->rng);
2774
2775
// XXX: Clear the number of results.
2776
p->nresults = 0;
2777
}
2778
2779
#endif // BC_ENABLE_EXTRA_MATH
2780
2781
/**
2782
* Adds a function to the fns array. The function's ID must have already been
2783
* inserted into the map.
2784
* @param p The program.
2785
* @param id_ptr The ID of the function as inserted into the map.
2786
*/
2787
static void
2788
bc_program_addFunc(BcProgram* p, BcId* id_ptr)
2789
{
2790
BcFunc* f;
2791
2792
BC_SIG_ASSERT_LOCKED;
2793
2794
// Push and init.
2795
f = bc_vec_pushEmpty(&p->fns);
2796
bc_func_init(f, id_ptr->name);
2797
}
2798
2799
size_t
2800
bc_program_insertFunc(BcProgram* p, const char* name)
2801
{
2802
BcId* id_ptr;
2803
bool new;
2804
size_t idx;
2805
2806
BC_SIG_ASSERT_LOCKED;
2807
2808
assert(p != NULL && name != NULL);
2809
2810
// Insert into the map and get the resulting ID.
2811
new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
2812
id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
2813
idx = id_ptr->idx;
2814
2815
// If the function is new...
2816
if (new)
2817
{
2818
// Add the function to the fns array.
2819
bc_program_addFunc(p, id_ptr);
2820
}
2821
#if BC_ENABLED
2822
// bc has to reset the function because it's about to be redefined.
2823
else if (BC_IS_BC)
2824
{
2825
BcFunc* func = bc_vec_item(&p->fns, idx);
2826
bc_func_reset(func);
2827
}
2828
#endif // BC_ENABLED
2829
2830
return idx;
2831
}
2832
2833
#if BC_DEBUG || BC_ENABLE_MEMCHECK
2834
void
2835
bc_program_free(BcProgram* p)
2836
{
2837
#if BC_ENABLED
2838
size_t i;
2839
#endif // BC_ENABLED
2840
2841
BC_SIG_ASSERT_LOCKED;
2842
2843
assert(p != NULL);
2844
2845
#if BC_ENABLED
2846
// Free the globals stacks.
2847
for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2848
{
2849
bc_vec_free(p->globals_v + i);
2850
}
2851
#endif // BC_ENABLED
2852
2853
bc_vec_free(&p->fns);
2854
bc_vec_free(&p->fn_map);
2855
bc_vec_free(&p->vars);
2856
bc_vec_free(&p->var_map);
2857
bc_vec_free(&p->arrs);
2858
bc_vec_free(&p->arr_map);
2859
bc_vec_free(&p->results);
2860
bc_vec_free(&p->stack);
2861
bc_vec_free(&p->consts);
2862
bc_vec_free(&p->const_map);
2863
bc_vec_free(&p->strs);
2864
bc_vec_free(&p->str_map);
2865
2866
bc_num_free(&p->asciify);
2867
2868
#if BC_ENABLED
2869
if (BC_IS_BC) bc_num_free(&p->last);
2870
#endif // BC_ENABLED
2871
2872
#if BC_ENABLE_EXTRA_MATH
2873
bc_rand_free(&p->rng);
2874
#endif // BC_ENABLE_EXTRA_MATH
2875
2876
#if DC_ENABLED
2877
if (BC_IS_DC) bc_vec_free(&p->tail_calls);
2878
#endif // DC_ENABLED
2879
}
2880
#endif // BC_DEBUG || BC_ENABLE_MEMCHECK
2881
2882
void
2883
bc_program_init(BcProgram* p)
2884
{
2885
BcInstPtr ip;
2886
size_t i;
2887
2888
BC_SIG_ASSERT_LOCKED;
2889
2890
assert(p != NULL);
2891
2892
// We want this clear.
2893
// NOLINTNEXTLINE
2894
memset(&ip, 0, sizeof(BcInstPtr));
2895
2896
// Setup the globals stacks and the current values.
2897
for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2898
{
2899
BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
2900
2901
#if BC_ENABLED
2902
bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE);
2903
bc_vec_push(p->globals_v + i, &val);
2904
#endif // BC_ENABLED
2905
2906
p->globals[i] = val;
2907
}
2908
2909
#if DC_ENABLED
2910
// dc-only setup.
2911
if (BC_IS_DC)
2912
{
2913
bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE);
2914
2915
// We want an item for the main function on the tail call stack.
2916
i = 0;
2917
bc_vec_push(&p->tail_calls, &i);
2918
}
2919
#endif // DC_ENABLED
2920
2921
bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
2922
bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE);
2923
2924
bc_num_init(&p->asciify, BC_NUM_DEF_SIZE);
2925
2926
#if BC_ENABLE_EXTRA_MATH
2927
// We need to initialize srand() just in case /dev/urandom and /dev/random
2928
// are not available.
2929
srand((unsigned int) time(NULL));
2930
bc_rand_init(&p->rng);
2931
#endif // BC_ENABLE_EXTRA_MATH
2932
2933
#if BC_ENABLED
2934
if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
2935
#endif // BC_ENABLED
2936
2937
#if BC_DEBUG
2938
bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC);
2939
#else // BC_DEBUG
2940
bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE);
2941
#endif // BC_DEBUG
2942
bc_map_init(&p->fn_map);
2943
bc_program_insertFunc(p, bc_func_main);
2944
bc_program_insertFunc(p, bc_func_read);
2945
2946
bc_vec_init(&p->vars, sizeof(BcVec), BC_DTOR_VEC);
2947
bc_map_init(&p->var_map);
2948
2949
bc_vec_init(&p->arrs, sizeof(BcVec), BC_DTOR_VEC);
2950
bc_map_init(&p->arr_map);
2951
2952
bc_vec_init(&p->results, sizeof(BcResult), BC_DTOR_RESULT);
2953
2954
// Push the first instruction pointer onto the execution stack.
2955
bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
2956
bc_vec_push(&p->stack, &ip);
2957
2958
bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
2959
bc_map_init(&p->const_map);
2960
bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
2961
bc_map_init(&p->str_map);
2962
2963
// XXX: Clear the number of results.
2964
p->nresults = 0;
2965
}
2966
2967
void
2968
bc_program_printStackTrace(BcProgram* p)
2969
{
2970
size_t i, max_digits;
2971
2972
max_digits = bc_vm_numDigits(p->stack.len - 1);
2973
2974
for (i = 0; i < p->stack.len; ++i)
2975
{
2976
BcInstPtr* ip = bc_vec_item_rev(&p->stack, i);
2977
BcFunc* f = bc_vec_item(&p->fns, ip->func);
2978
size_t j, digits;
2979
2980
digits = bc_vm_numDigits(i);
2981
2982
bc_file_puts(&vm->ferr, bc_flush_none, " ");
2983
2984
for (j = 0; j < max_digits - digits; ++j)
2985
{
2986
bc_file_putchar(&vm->ferr, bc_flush_none, ' ');
2987
}
2988
2989
bc_file_printf(&vm->ferr, "%zu: %s", i, f->name);
2990
2991
#if BC_ENABLED
2992
if (BC_IS_BC && ip->func != BC_PROG_MAIN && ip->func != BC_PROG_READ)
2993
{
2994
bc_file_puts(&vm->ferr, bc_flush_none, "()");
2995
}
2996
#endif // BC_ENABLED
2997
2998
bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
2999
}
3000
}
3001
3002
void
3003
bc_program_reset(BcProgram* p)
3004
{
3005
BcFunc* f;
3006
BcInstPtr* ip;
3007
3008
BC_SIG_ASSERT_LOCKED;
3009
3010
// Pop all but the last execution.
3011
bc_vec_npop(&p->stack, p->stack.len - 1);
3012
3013
#if DC_ENABLED
3014
// We need to pop tail calls too.
3015
if (BC_IS_DC) bc_vec_npop(&p->tail_calls, p->tail_calls.len - 1);
3016
#endif // DC_ENABLED
3017
3018
// Clear the stack if we are in bc. We have to do this in bc because bc's
3019
// stack is implicit.
3020
//
3021
// XXX: We don't do this in dc because other dc implementations don't.
3022
// However, we *MUST* pop the items for results that are not retired yet.
3023
if (BC_IS_DC && BC_I) bc_vec_npop(&p->results, p->nresults);
3024
else bc_vec_popAll(&p->results);
3025
3026
// Now clear how many results there are.
3027
p->nresults = 0;
3028
3029
#if BC_ENABLED
3030
// Clear the globals' stacks.
3031
if (BC_G) bc_program_popGlobals(p, true);
3032
#endif // BC_ENABLED
3033
3034
// Clear the bytecode vector of the main function.
3035
f = bc_vec_item(&p->fns, BC_PROG_MAIN);
3036
bc_vec_npop(&f->code, f->code.len);
3037
3038
// Reset the instruction pointer.
3039
ip = bc_vec_top(&p->stack);
3040
// NOLINTNEXTLINE
3041
memset(ip, 0, sizeof(BcInstPtr));
3042
3043
if (BC_SIG_INTERRUPT(vm))
3044
{
3045
// Write the ready message for a signal.
3046
bc_file_printf(&vm->fout, "%s", bc_program_ready_msg);
3047
bc_file_flush(&vm->fout, bc_flush_err);
3048
}
3049
3050
// Clear the signal.
3051
vm->sig = 0;
3052
}
3053
3054
void
3055
bc_program_exec(BcProgram* p)
3056
{
3057
size_t idx;
3058
BcResult r;
3059
BcResult* ptr;
3060
BcInstPtr* ip;
3061
BcFunc* func;
3062
char* code;
3063
bool cond = false;
3064
uchar inst;
3065
#if BC_ENABLED
3066
BcNum* num;
3067
#endif // BC_ENABLED
3068
#if !BC_HAS_COMPUTED_GOTO
3069
#if BC_DEBUG
3070
size_t jmp_bufs_len;
3071
#endif // BC_DEBUG
3072
#endif // !BC_HAS_COMPUTED_GOTO
3073
3074
#if BC_HAS_COMPUTED_GOTO
3075
3076
#if BC_GCC
3077
#pragma GCC diagnostic push
3078
#pragma GCC diagnostic ignored "-Wpedantic"
3079
#endif // BC_GCC
3080
3081
#if BC_CLANG
3082
#pragma clang diagnostic push
3083
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
3084
#endif // BC_CLANG
3085
3086
BC_PROG_LBLS;
3087
BC_PROG_LBLS_ASSERT;
3088
3089
#if BC_CLANG
3090
#pragma clang diagnostic pop
3091
#endif // BC_CLANG
3092
3093
#if BC_GCC
3094
#pragma GCC diagnostic pop
3095
#endif // BC_GCC
3096
3097
// BC_INST_INVALID is a marker for the end so that we don't have to have an
3098
// execution loop.
3099
func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN);
3100
bc_vec_pushByte(&func->code, BC_INST_INVALID);
3101
#endif // BC_HAS_COMPUTED_GOTO
3102
3103
BC_SETJMP(vm, end);
3104
3105
ip = bc_vec_top(&p->stack);
3106
func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
3107
code = func->code.v;
3108
3109
#if !BC_HAS_COMPUTED_GOTO
3110
3111
#if BC_DEBUG
3112
jmp_bufs_len = vm->jmp_bufs.len;
3113
#endif // BC_DEBUG
3114
3115
// This loop is the heart of the execution engine. It *is* the engine. For
3116
// computed goto, it is ignored.
3117
while (ip->idx < func->code.len)
3118
#endif // !BC_HAS_COMPUTED_GOTO
3119
{
3120
BC_SIG_ASSERT_NOT_LOCKED;
3121
3122
#if BC_HAS_COMPUTED_GOTO
3123
3124
#if BC_GCC
3125
#pragma GCC diagnostic push
3126
#pragma GCC diagnostic ignored "-Wpedantic"
3127
#endif // BC_GCC
3128
3129
#if BC_CLANG
3130
#pragma clang diagnostic push
3131
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
3132
#endif // BC_CLANG
3133
3134
BC_PROG_JUMP(inst, code, ip);
3135
3136
#else // BC_HAS_COMPUTED_GOTO
3137
3138
// Get the next instruction and increment the index.
3139
inst = (uchar) code[(ip->idx)++];
3140
3141
#endif // BC_HAS_COMPUTED_GOTO
3142
3143
#if BC_DEBUG_CODE
3144
bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]);
3145
bc_file_flush(&vm->ferr, bc_flush_none);
3146
#endif // BC_DEBUG_CODE
3147
3148
#if !BC_HAS_COMPUTED_GOTO
3149
switch (inst)
3150
#endif // !BC_HAS_COMPUTED_GOTO
3151
{
3152
#if BC_ENABLED
3153
// This just sets up the condition for the unconditional jump below,
3154
// which checks the condition, if necessary.
3155
// clang-format off
3156
BC_PROG_LBL(BC_INST_JUMP_ZERO):
3157
// clang-format on
3158
{
3159
bc_program_prep(p, &ptr, &num, 0);
3160
3161
cond = !bc_num_cmpZero(num);
3162
bc_vec_pop(&p->results);
3163
3164
BC_PROG_DIRECT_JUMP(BC_INST_JUMP)
3165
}
3166
// Fallthrough.
3167
BC_PROG_FALLTHROUGH
3168
3169
// clang-format off
3170
BC_PROG_LBL(BC_INST_JUMP):
3171
// clang-format on
3172
{
3173
idx = bc_program_index(code, &ip->idx);
3174
3175
// If a jump is required...
3176
if (inst == BC_INST_JUMP || cond)
3177
{
3178
// Get the address to jump to.
3179
size_t* addr = bc_vec_item(&func->labels, idx);
3180
3181
// If this fails, then the parser failed to set up the
3182
// labels correctly.
3183
assert(*addr != SIZE_MAX);
3184
3185
// Set the new address.
3186
ip->idx = *addr;
3187
}
3188
3189
BC_PROG_JUMP(inst, code, ip);
3190
}
3191
3192
// clang-format off
3193
BC_PROG_LBL(BC_INST_CALL):
3194
// clang-format on
3195
{
3196
assert(BC_IS_BC);
3197
3198
bc_program_call(p, code, &ip->idx);
3199
3200
// Because we changed the execution stack and where we are
3201
// executing, we have to update all of this.
3202
BC_SIG_LOCK;
3203
ip = bc_vec_top(&p->stack);
3204
func = bc_vec_item(&p->fns, ip->func);
3205
code = func->code.v;
3206
BC_SIG_UNLOCK;
3207
3208
BC_PROG_JUMP(inst, code, ip);
3209
}
3210
3211
// clang-format off
3212
BC_PROG_LBL(BC_INST_INC):
3213
BC_PROG_LBL(BC_INST_DEC):
3214
// clang-format on
3215
{
3216
bc_program_incdec(p, inst);
3217
BC_PROG_JUMP(inst, code, ip);
3218
}
3219
3220
// clang-format off
3221
BC_PROG_LBL(BC_INST_HALT):
3222
// clang-format on
3223
{
3224
vm->status = BC_STATUS_QUIT;
3225
3226
// Just jump out. The jump series will take care of everything.
3227
BC_JMP;
3228
3229
BC_PROG_JUMP(inst, code, ip);
3230
}
3231
3232
// clang-format off
3233
BC_PROG_LBL(BC_INST_RET):
3234
BC_PROG_LBL(BC_INST_RET0):
3235
BC_PROG_LBL(BC_INST_RET_VOID):
3236
// clang-format on
3237
{
3238
bc_program_return(p, inst);
3239
3240
// Because we changed the execution stack and where we are
3241
// executing, we have to update all of this.
3242
BC_SIG_LOCK;
3243
ip = bc_vec_top(&p->stack);
3244
func = bc_vec_item(&p->fns, ip->func);
3245
code = func->code.v;
3246
BC_SIG_UNLOCK;
3247
3248
BC_PROG_JUMP(inst, code, ip);
3249
}
3250
#endif // BC_ENABLED
3251
3252
// clang-format off
3253
BC_PROG_LBL(BC_INST_BOOL_OR):
3254
BC_PROG_LBL(BC_INST_BOOL_AND):
3255
BC_PROG_LBL(BC_INST_REL_EQ):
3256
BC_PROG_LBL(BC_INST_REL_LE):
3257
BC_PROG_LBL(BC_INST_REL_GE):
3258
BC_PROG_LBL(BC_INST_REL_NE):
3259
BC_PROG_LBL(BC_INST_REL_LT):
3260
BC_PROG_LBL(BC_INST_REL_GT):
3261
// clang-format on
3262
{
3263
bc_program_logical(p, inst);
3264
BC_PROG_JUMP(inst, code, ip);
3265
}
3266
3267
// clang-format off
3268
BC_PROG_LBL(BC_INST_READ):
3269
// clang-format on
3270
{
3271
// We want to flush output before
3272
// this in case there is a prompt.
3273
bc_file_flush(&vm->fout, bc_flush_save);
3274
3275
bc_program_read(p);
3276
3277
// Because we changed the execution stack and where we are
3278
// executing, we have to update all of this.
3279
BC_SIG_LOCK;
3280
ip = bc_vec_top(&p->stack);
3281
func = bc_vec_item(&p->fns, ip->func);
3282
code = func->code.v;
3283
BC_SIG_UNLOCK;
3284
3285
BC_PROG_JUMP(inst, code, ip);
3286
}
3287
3288
#if BC_ENABLE_EXTRA_MATH
3289
// clang-format off
3290
BC_PROG_LBL(BC_INST_RAND):
3291
// clang-format on
3292
{
3293
bc_program_rand(p);
3294
BC_PROG_JUMP(inst, code, ip);
3295
}
3296
#endif // BC_ENABLE_EXTRA_MATH
3297
3298
// clang-format off
3299
BC_PROG_LBL(BC_INST_MAXIBASE):
3300
BC_PROG_LBL(BC_INST_MAXOBASE):
3301
BC_PROG_LBL(BC_INST_MAXSCALE):
3302
#if BC_ENABLE_EXTRA_MATH
3303
BC_PROG_LBL(BC_INST_MAXRAND):
3304
#endif // BC_ENABLE_EXTRA_MATH
3305
// clang-format on
3306
{
3307
BcBigDig dig = vm->maxes[inst - BC_INST_MAXIBASE];
3308
bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
3309
BC_PROG_JUMP(inst, code, ip);
3310
}
3311
3312
// clang-format off
3313
BC_PROG_LBL(BC_INST_LINE_LENGTH):
3314
#if BC_ENABLED
3315
BC_PROG_LBL(BC_INST_GLOBAL_STACKS):
3316
#endif // BC_ENABLED
3317
#if DC_ENABLED
3318
BC_PROG_LBL(BC_INST_EXTENDED_REGISTERS):
3319
#endif // DC_ENABLE
3320
BC_PROG_LBL(BC_INST_LEADING_ZERO):
3321
// clang-format on
3322
{
3323
bc_program_globalSetting(p, inst);
3324
BC_PROG_JUMP(inst, code, ip);
3325
}
3326
3327
// clang-format off
3328
BC_PROG_LBL(BC_INST_VAR):
3329
// clang-format on
3330
{
3331
bc_program_pushVar(p, code, &ip->idx, false, false);
3332
BC_PROG_JUMP(inst, code, ip);
3333
}
3334
3335
// clang-format off
3336
BC_PROG_LBL(BC_INST_ARRAY_ELEM):
3337
BC_PROG_LBL(BC_INST_ARRAY):
3338
// clang-format on
3339
{
3340
bc_program_pushArray(p, code, &ip->idx, inst);
3341
BC_PROG_JUMP(inst, code, ip);
3342
}
3343
3344
// clang-format off
3345
BC_PROG_LBL(BC_INST_IBASE):
3346
BC_PROG_LBL(BC_INST_SCALE):
3347
BC_PROG_LBL(BC_INST_OBASE):
3348
// clang-format on
3349
{
3350
bc_program_pushGlobal(p, inst);
3351
BC_PROG_JUMP(inst, code, ip);
3352
}
3353
3354
#if BC_ENABLE_EXTRA_MATH
3355
// clang-format off
3356
BC_PROG_LBL(BC_INST_SEED):
3357
// clang-format on
3358
{
3359
bc_program_pushSeed(p);
3360
BC_PROG_JUMP(inst, code, ip);
3361
}
3362
#endif // BC_ENABLE_EXTRA_MATH
3363
3364
// clang-format off
3365
BC_PROG_LBL(BC_INST_LENGTH):
3366
BC_PROG_LBL(BC_INST_SCALE_FUNC):
3367
BC_PROG_LBL(BC_INST_SQRT):
3368
BC_PROG_LBL(BC_INST_ABS):
3369
BC_PROG_LBL(BC_INST_IS_NUMBER):
3370
BC_PROG_LBL(BC_INST_IS_STRING):
3371
#if BC_ENABLE_EXTRA_MATH
3372
BC_PROG_LBL(BC_INST_IRAND):
3373
#endif // BC_ENABLE_EXTRA_MATH
3374
// clang-format on
3375
{
3376
bc_program_builtin(p, inst);
3377
BC_PROG_JUMP(inst, code, ip);
3378
}
3379
3380
// clang-format off
3381
BC_PROG_LBL(BC_INST_ASCIIFY):
3382
// clang-format on
3383
{
3384
bc_program_asciify(p);
3385
3386
// Because we changed the execution stack and where we are
3387
// executing, we have to update all of this.
3388
BC_SIG_LOCK;
3389
ip = bc_vec_top(&p->stack);
3390
func = bc_vec_item(&p->fns, ip->func);
3391
code = func->code.v;
3392
BC_SIG_UNLOCK;
3393
3394
BC_PROG_JUMP(inst, code, ip);
3395
}
3396
3397
// clang-format off
3398
BC_PROG_LBL(BC_INST_NUM):
3399
// clang-format on
3400
{
3401
bc_program_const(p, code, &ip->idx);
3402
BC_PROG_JUMP(inst, code, ip);
3403
}
3404
3405
// clang-format off
3406
BC_PROG_LBL(BC_INST_ZERO):
3407
BC_PROG_LBL(BC_INST_ONE):
3408
#if BC_ENABLED
3409
BC_PROG_LBL(BC_INST_LAST):
3410
#endif // BC_ENABLED
3411
// clang-format on
3412
{
3413
r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
3414
bc_vec_push(&p->results, &r);
3415
BC_PROG_JUMP(inst, code, ip);
3416
}
3417
3418
// clang-format off
3419
BC_PROG_LBL(BC_INST_PRINT):
3420
BC_PROG_LBL(BC_INST_PRINT_POP):
3421
#if BC_ENABLED
3422
BC_PROG_LBL(BC_INST_PRINT_STR):
3423
#endif // BC_ENABLED
3424
// clang-format on
3425
{
3426
bc_program_print(p, inst, 0);
3427
3428
// We want to flush right away to save the output for history,
3429
// if history must preserve it when taking input.
3430
bc_file_flush(&vm->fout, bc_flush_save);
3431
3432
BC_PROG_JUMP(inst, code, ip);
3433
}
3434
3435
// clang-format off
3436
BC_PROG_LBL(BC_INST_STR):
3437
// clang-format on
3438
{
3439
// Set up the result and push.
3440
r.t = BC_RESULT_STR;
3441
bc_num_clear(&r.d.n);
3442
r.d.n.scale = bc_program_index(code, &ip->idx);
3443
bc_vec_push(&p->results, &r);
3444
BC_PROG_JUMP(inst, code, ip);
3445
}
3446
3447
// clang-format off
3448
BC_PROG_LBL(BC_INST_POWER):
3449
BC_PROG_LBL(BC_INST_MULTIPLY):
3450
BC_PROG_LBL(BC_INST_DIVIDE):
3451
BC_PROG_LBL(BC_INST_MODULUS):
3452
BC_PROG_LBL(BC_INST_PLUS):
3453
BC_PROG_LBL(BC_INST_MINUS):
3454
#if BC_ENABLE_EXTRA_MATH
3455
BC_PROG_LBL(BC_INST_PLACES):
3456
BC_PROG_LBL(BC_INST_LSHIFT):
3457
BC_PROG_LBL(BC_INST_RSHIFT):
3458
#endif // BC_ENABLE_EXTRA_MATH
3459
// clang-format on
3460
{
3461
bc_program_op(p, inst);
3462
BC_PROG_JUMP(inst, code, ip);
3463
}
3464
3465
// clang-format off
3466
BC_PROG_LBL(BC_INST_NEG):
3467
BC_PROG_LBL(BC_INST_BOOL_NOT):
3468
#if BC_ENABLE_EXTRA_MATH
3469
BC_PROG_LBL(BC_INST_TRUNC):
3470
#endif // BC_ENABLE_EXTRA_MATH
3471
// clang-format on
3472
{
3473
bc_program_unary(p, inst);
3474
BC_PROG_JUMP(inst, code, ip);
3475
}
3476
3477
// clang-format off
3478
#if BC_ENABLED
3479
BC_PROG_LBL(BC_INST_ASSIGN_POWER):
3480
BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY):
3481
BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE):
3482
BC_PROG_LBL(BC_INST_ASSIGN_MODULUS):
3483
BC_PROG_LBL(BC_INST_ASSIGN_PLUS):
3484
BC_PROG_LBL(BC_INST_ASSIGN_MINUS):
3485
#if BC_ENABLE_EXTRA_MATH
3486
BC_PROG_LBL(BC_INST_ASSIGN_PLACES):
3487
BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT):
3488
BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT):
3489
#endif // BC_ENABLE_EXTRA_MATH
3490
BC_PROG_LBL(BC_INST_ASSIGN):
3491
BC_PROG_LBL(BC_INST_ASSIGN_POWER_NO_VAL):
3492
BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY_NO_VAL):
3493
BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE_NO_VAL):
3494
BC_PROG_LBL(BC_INST_ASSIGN_MODULUS_NO_VAL):
3495
BC_PROG_LBL(BC_INST_ASSIGN_PLUS_NO_VAL):
3496
BC_PROG_LBL(BC_INST_ASSIGN_MINUS_NO_VAL):
3497
#if BC_ENABLE_EXTRA_MATH
3498
BC_PROG_LBL(BC_INST_ASSIGN_PLACES_NO_VAL):
3499
BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT_NO_VAL):
3500
BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT_NO_VAL):
3501
#endif // BC_ENABLE_EXTRA_MATH
3502
#endif // BC_ENABLED
3503
BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL):
3504
// clang-format on
3505
{
3506
bc_program_assign(p, inst);
3507
BC_PROG_JUMP(inst, code, ip);
3508
}
3509
3510
// clang-format off
3511
BC_PROG_LBL(BC_INST_POP):
3512
// clang-format on
3513
{
3514
#ifndef BC_PROG_NO_STACK_CHECK
3515
// dc must do a stack check, but bc does not.
3516
if (BC_IS_DC)
3517
{
3518
if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3519
{
3520
bc_err(BC_ERR_EXEC_STACK);
3521
}
3522
}
3523
#endif // BC_PROG_NO_STACK_CHECK
3524
3525
assert(BC_PROG_STACK(&p->results, 1));
3526
3527
bc_vec_pop(&p->results);
3528
3529
BC_PROG_JUMP(inst, code, ip);
3530
}
3531
3532
// clang-format off
3533
BC_PROG_LBL(BC_INST_SWAP):
3534
// clang-format on
3535
{
3536
BcResult* ptr2;
3537
3538
// Check the stack.
3539
if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
3540
{
3541
bc_err(BC_ERR_EXEC_STACK);
3542
}
3543
3544
assert(BC_PROG_STACK(&p->results, 2));
3545
3546
// Get the two items.
3547
ptr = bc_vec_item_rev(&p->results, 0);
3548
ptr2 = bc_vec_item_rev(&p->results, 1);
3549
3550
// Swap. It's just easiest to do it this way.
3551
// NOLINTNEXTLINE
3552
memcpy(&r, ptr, sizeof(BcResult));
3553
// NOLINTNEXTLINE
3554
memcpy(ptr, ptr2, sizeof(BcResult));
3555
// NOLINTNEXTLINE
3556
memcpy(ptr2, &r, sizeof(BcResult));
3557
3558
BC_PROG_JUMP(inst, code, ip);
3559
}
3560
3561
// clang-format off
3562
BC_PROG_LBL(BC_INST_MODEXP):
3563
// clang-format on
3564
{
3565
bc_program_modexp(p);
3566
BC_PROG_JUMP(inst, code, ip);
3567
}
3568
3569
// clang-format off
3570
BC_PROG_LBL(BC_INST_DIVMOD):
3571
// clang-format on
3572
{
3573
bc_program_divmod(p);
3574
BC_PROG_JUMP(inst, code, ip);
3575
}
3576
3577
// clang-format off
3578
BC_PROG_LBL(BC_INST_PRINT_STREAM):
3579
// clang-format on
3580
{
3581
bc_program_printStream(p);
3582
BC_PROG_JUMP(inst, code, ip);
3583
}
3584
3585
#if DC_ENABLED
3586
// clang-format off
3587
BC_PROG_LBL(BC_INST_POP_EXEC):
3588
// clang-format on
3589
{
3590
// If this fails, the dc parser got something wrong.
3591
assert(BC_PROG_STACK(&p->stack, 2));
3592
3593
// Pop the execution stack and tail call stack.
3594
bc_vec_pop(&p->stack);
3595
bc_vec_pop(&p->tail_calls);
3596
3597
// Because we changed the execution stack and where we are
3598
// executing, we have to update all of this.
3599
BC_SIG_LOCK;
3600
ip = bc_vec_top(&p->stack);
3601
func = bc_vec_item(&p->fns, ip->func);
3602
code = func->code.v;
3603
BC_SIG_UNLOCK;
3604
3605
BC_PROG_JUMP(inst, code, ip);
3606
}
3607
3608
// clang-format off
3609
BC_PROG_LBL(BC_INST_EXECUTE):
3610
BC_PROG_LBL(BC_INST_EXEC_COND):
3611
// clang-format on
3612
{
3613
cond = (inst == BC_INST_EXEC_COND);
3614
3615
bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
3616
3617
// Because we changed the execution stack and where we are
3618
// executing, we have to update all of this.
3619
BC_SIG_LOCK;
3620
ip = bc_vec_top(&p->stack);
3621
func = bc_vec_item(&p->fns, ip->func);
3622
code = func->code.v;
3623
BC_SIG_UNLOCK;
3624
3625
BC_PROG_JUMP(inst, code, ip);
3626
}
3627
3628
// clang-format off
3629
BC_PROG_LBL(BC_INST_PRINT_STACK):
3630
// clang-format on
3631
{
3632
bc_program_printStack(p);
3633
BC_PROG_JUMP(inst, code, ip);
3634
}
3635
3636
// clang-format off
3637
BC_PROG_LBL(BC_INST_CLEAR_STACK):
3638
// clang-format on
3639
{
3640
bc_vec_popAll(&p->results);
3641
BC_PROG_JUMP(inst, code, ip);
3642
}
3643
3644
// clang-format off
3645
BC_PROG_LBL(BC_INST_REG_STACK_LEN):
3646
// clang-format on
3647
{
3648
bc_program_regStackLen(p, code, &ip->idx);
3649
BC_PROG_JUMP(inst, code, ip);
3650
}
3651
3652
// clang-format off
3653
BC_PROG_LBL(BC_INST_STACK_LEN):
3654
// clang-format on
3655
{
3656
bc_program_stackLen(p);
3657
BC_PROG_JUMP(inst, code, ip);
3658
}
3659
3660
// clang-format off
3661
BC_PROG_LBL(BC_INST_DUPLICATE):
3662
// clang-format on
3663
{
3664
// Check the stack.
3665
if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3666
{
3667
bc_err(BC_ERR_EXEC_STACK);
3668
}
3669
3670
assert(BC_PROG_STACK(&p->results, 1));
3671
3672
// Get the top of the stack.
3673
ptr = bc_vec_top(&p->results);
3674
3675
BC_SIG_LOCK;
3676
3677
// Copy and push.
3678
bc_result_copy(&r, ptr);
3679
bc_vec_push(&p->results, &r);
3680
3681
BC_SIG_UNLOCK;
3682
3683
BC_PROG_JUMP(inst, code, ip);
3684
}
3685
3686
// clang-format off
3687
BC_PROG_LBL(BC_INST_LOAD):
3688
BC_PROG_LBL(BC_INST_PUSH_VAR):
3689
// clang-format on
3690
{
3691
bool copy = (inst == BC_INST_LOAD);
3692
bc_program_pushVar(p, code, &ip->idx, true, copy);
3693
BC_PROG_JUMP(inst, code, ip);
3694
}
3695
3696
// clang-format off
3697
BC_PROG_LBL(BC_INST_PUSH_TO_VAR):
3698
// clang-format on
3699
{
3700
idx = bc_program_index(code, &ip->idx);
3701
bc_program_copyToVar(p, idx, BC_TYPE_VAR);
3702
BC_PROG_JUMP(inst, code, ip);
3703
}
3704
3705
// clang-format off
3706
BC_PROG_LBL(BC_INST_QUIT):
3707
BC_PROG_LBL(BC_INST_NQUIT):
3708
// clang-format on
3709
{
3710
bc_program_nquit(p, inst);
3711
3712
// Because we changed the execution stack and where we are
3713
// executing, we have to update all of this.
3714
BC_SIG_LOCK;
3715
ip = bc_vec_top(&p->stack);
3716
func = bc_vec_item(&p->fns, ip->func);
3717
code = func->code.v;
3718
BC_SIG_UNLOCK;
3719
3720
BC_PROG_JUMP(inst, code, ip);
3721
}
3722
3723
// clang-format off
3724
BC_PROG_LBL(BC_INST_EXEC_STACK_LEN):
3725
// clang-format on
3726
{
3727
bc_program_execStackLen(p);
3728
BC_PROG_JUMP(inst, code, ip);
3729
}
3730
#endif // DC_ENABLED
3731
3732
#if BC_HAS_COMPUTED_GOTO
3733
// clang-format off
3734
BC_PROG_LBL(BC_INST_INVALID):
3735
// clang-format on
3736
{
3737
goto end;
3738
}
3739
#else // BC_HAS_COMPUTED_GOTO
3740
default:
3741
{
3742
BC_UNREACHABLE
3743
#if BC_DEBUG && !BC_CLANG
3744
abort();
3745
#endif // BC_DEBUG && !BC_CLANG
3746
}
3747
#endif // BC_HAS_COMPUTED_GOTO
3748
}
3749
3750
#if BC_HAS_COMPUTED_GOTO
3751
3752
#if BC_CLANG
3753
#pragma clang diagnostic pop
3754
#endif // BC_CLANG
3755
3756
#if BC_GCC
3757
#pragma GCC diagnostic pop
3758
#endif // BC_GCC
3759
3760
#else // BC_HAS_COMPUTED_GOTO
3761
3762
#if BC_DEBUG
3763
// This is to allow me to use a debugger to see the last instruction,
3764
// which will point to which function was the problem. But it's also a
3765
// good smoke test for error handling changes.
3766
assert(jmp_bufs_len == vm->jmp_bufs.len);
3767
#endif // BC_DEBUG
3768
3769
#endif // BC_HAS_COMPUTED_GOTO
3770
}
3771
3772
end:
3773
BC_SIG_MAYLOCK;
3774
3775
// This is here just to print a stack trace on interrupts. This is for
3776
// finding infinite loops.
3777
if (BC_SIG_INTERRUPT(vm))
3778
{
3779
BcStatus s;
3780
3781
bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
3782
3783
bc_program_printStackTrace(p);
3784
3785
s = bc_file_flushErr(&vm->ferr, bc_flush_err);
3786
if (BC_ERR(s != BC_STATUS_SUCCESS && vm->status == BC_STATUS_SUCCESS))
3787
{
3788
vm->status = (sig_atomic_t) s;
3789
}
3790
}
3791
3792
BC_LONGJMP_CONT(vm);
3793
}
3794
3795
#if BC_DEBUG_CODE
3796
#if BC_ENABLED && DC_ENABLED
3797
void
3798
bc_program_printStackDebug(BcProgram* p)
3799
{
3800
bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack ----------\n");
3801
bc_program_printStack(p);
3802
bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack End ------\n");
3803
}
3804
3805
static void
3806
bc_program_printIndex(const char* restrict code, size_t* restrict bgn)
3807
{
3808
uchar byte, i, bytes = (uchar) code[(*bgn)++];
3809
ulong val = 0;
3810
3811
for (byte = 1, i = 0; byte && i < bytes; ++i)
3812
{
3813
byte = (uchar) code[(*bgn)++];
3814
if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
3815
}
3816
3817
bc_vm_printf(" (%lu) ", val);
3818
}
3819
3820
static void
3821
bc_program_printStr(const BcProgram* p, const char* restrict code,
3822
size_t* restrict bgn)
3823
{
3824
size_t idx = bc_program_index(code, bgn);
3825
char* s;
3826
3827
s = *((char**) bc_vec_item(&p->strs, idx));
3828
3829
bc_vm_printf(" (\"%s\") ", s);
3830
}
3831
3832
void
3833
bc_program_printInst(const BcProgram* p, const char* restrict code,
3834
size_t* restrict bgn)
3835
{
3836
uchar inst = (uchar) code[(*bgn)++];
3837
3838
bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, bc_inst_names[inst],
3839
(unsigned long) inst);
3840
3841
if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
3842
inst == BC_INST_ARRAY)
3843
{
3844
bc_program_printIndex(code, bgn);
3845
}
3846
else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
3847
else if (inst == BC_INST_NUM)
3848
{
3849
size_t idx = bc_program_index(code, bgn);
3850
BcConst* c = bc_vec_item(&p->consts, idx);
3851
bc_vm_printf("(%s)", c->val);
3852
}
3853
else if (inst == BC_INST_CALL ||
3854
(inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
3855
{
3856
bc_program_printIndex(code, bgn);
3857
if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
3858
}
3859
3860
bc_vm_putchar('\n', bc_flush_err);
3861
}
3862
3863
void
3864
bc_program_code(const BcProgram* p)
3865
{
3866
BcFunc* f;
3867
char* code;
3868
BcInstPtr ip;
3869
size_t i;
3870
3871
for (i = 0; i < p->fns.len; ++i)
3872
{
3873
ip.idx = ip.len = 0;
3874
ip.func = i;
3875
3876
f = bc_vec_item(&p->fns, ip.func);
3877
code = f->code.v;
3878
3879
bc_vm_printf("func[%zu]:\n", ip.func);
3880
while (ip.idx < f->code.len)
3881
{
3882
bc_program_printInst(p, code, &ip.idx);
3883
}
3884
bc_file_puts(&vm->fout, bc_flush_err, "\n\n");
3885
}
3886
}
3887
#endif // BC_ENABLED && DC_ENABLED
3888
#endif // BC_DEBUG_CODE
3889
3890