aboutsummaryrefslogtreecommitdiff
path: root/contrib/bc/src/program.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bc/src/program.c')
-rw-r--r--contrib/bc/src/program.c1799
1 files changed, 1168 insertions, 631 deletions
diff --git a/contrib/bc/src/program.c b/contrib/bc/src/program.c
index 1ff9c24f323b..c9d268dfde82 100644
--- a/contrib/bc/src/program.c
+++ b/contrib/bc/src/program.c
@@ -3,7 +3,7 @@
*
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
+ * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -49,23 +49,13 @@
#include <vm.h>
/**
- * Quickly sets the const and strs vector pointers in the program. This is a
- * convenience function.
- * @param p The program.
- * @param f The new function.
- */
-static inline void bc_program_setVecs(BcProgram *p, BcFunc *f) {
- p->consts = &f->consts;
- p->strs = &f->strs;
-}
-
-/**
* Does a type check for something that expects a number.
* @param r The result that will be checked.
* @param n The result's number.
*/
-static inline void bc_program_type_num(BcResult *r, BcNum *n) {
-
+static inline void
+bc_program_type_num(BcResult* r, BcNum* n)
+{
#if BC_ENABLED
// This should have already been taken care of.
@@ -83,7 +73,9 @@ static inline void bc_program_type_num(BcResult *r, BcNum *n) {
* @param r The result to check.
* @param t The type that the result should be.
*/
-static void bc_program_type_match(BcResult *r, BcType t) {
+static void
+bc_program_type_match(BcResult* r, BcType t)
+{
if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE);
}
#endif // BC_ENABLED
@@ -97,12 +89,14 @@ static void bc_program_type_match(BcResult *r, BcType t) {
* updated.
* @return The index at @a bgn in the bytecode vector.
*/
-static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
+static size_t
+bc_program_index(const char* restrict code, size_t* restrict bgn)
{
uchar amt = (uchar) code[(*bgn)++], i = 0;
size_t res = 0;
- for (; i < amt; ++i, ++(*bgn)) {
+ for (; i < amt; ++i, ++(*bgn))
+ {
size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
res |= (temp << (i * CHAR_BIT));
}
@@ -116,9 +110,10 @@ static size_t bc_program_index(const char *restrict code, size_t *restrict bgn)
* @param n The number tied to the result.
* @return The string corresponding to the result and number.
*/
-static char* bc_program_string(BcProgram *p, const BcNum *n) {
- BcFunc *f = bc_vec_item(&p->fns, n->rdx);
- return *((char**) bc_vec_item(&f->strs, n->scale));
+static inline char*
+bc_program_string(BcProgram* p, const BcNum* n)
+{
+ return *((char**) bc_vec_item(&p->strs, n->scale));
}
#if BC_ENABLED
@@ -129,12 +124,15 @@ static char* bc_program_string(BcProgram *p, const BcNum *n) {
* their respective stacks.
* @param p The program.
*/
-static void bc_program_prepGlobals(BcProgram *p) {
-
+static void
+bc_program_prepGlobals(BcProgram* p)
+{
size_t i;
for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
+ {
bc_vec_push(p->globals_v + i, p->globals + i);
+ }
#if BC_ENABLE_EXTRA_MATH
bc_rand_push(&p->rng);
@@ -148,12 +146,16 @@ static void bc_program_prepGlobals(BcProgram *p) {
* @param reset True if all but one item on each stack should be popped, false
* otherwise.
*/
-static void bc_program_popGlobals(BcProgram *p, bool reset) {
-
+static void
+bc_program_popGlobals(BcProgram* p, bool reset)
+{
size_t i;
- for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
- BcVec *v = p->globals_v + i;
+ BC_SIG_ASSERT_LOCKED;
+
+ for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
+ {
+ BcVec* v = p->globals_v + i;
bc_vec_npop(v, reset ? v->len - 1 : 1);
p->globals[i] = BC_PROG_GLOBAL(v);
}
@@ -169,9 +171,10 @@ static void bc_program_popGlobals(BcProgram *p, bool reset) {
* @param vec The reference vector.
* @return A pointer to the desired array.
*/
-static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
-
- BcVec *v;
+static BcVec*
+bc_program_dereference(const BcProgram* p, BcVec* vec)
+{
+ BcVec* v;
size_t vidx, nidx, i = 0;
// We want to be sure we have a reference vector.
@@ -189,6 +192,7 @@ static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
return v;
}
+
#endif // BC_ENABLED
/**
@@ -198,7 +202,8 @@ static BcVec* bc_program_dereference(const BcProgram *p, BcVec *vec) {
* @param dig The BcBigDig to push onto the results stack.
* @param type The type that the pushed result should be.
*/
-static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
+static void
+bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
{
BcResult res;
@@ -212,49 +217,60 @@ static void bc_program_pushBigdig(BcProgram *p, BcBigDig dig, BcResultType type)
BC_SIG_UNLOCK;
}
-size_t bc_program_addString(BcProgram *p, const char *str, size_t fidx) {
-
- BcFunc *f;
- char **str_ptr;
- BcVec *slabs;
+size_t
+bc_program_addString(BcProgram* p, const char* str)
+{
+ size_t idx;
BC_SIG_ASSERT_LOCKED;
- // Push an empty string on the proper vector.
- f = bc_vec_item(&p->fns, fidx);
- str_ptr = bc_vec_pushEmpty(&f->strs);
+ if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
+ {
+ char** str_ptr;
+ BcId* id = bc_vec_item(&p->str_map, idx);
- // Figure out which slab vector to use.
- slabs = fidx == BC_PROG_MAIN || fidx == BC_PROG_READ ?
- &vm.main_slabs : &vm.other_slabs;
+ // Get the index.
+ idx = id->idx;
- *str_ptr = bc_slabvec_strdup(slabs, str);
+ // Push an empty string on the proper vector.
+ str_ptr = bc_vec_pushEmpty(&p->strs);
- return f->strs.len - 1;
-}
+ // We reuse the string in the ID (allocated by bc_map_insert()), because
+ // why not?
+ *str_ptr = id->name;
+ }
+ else
+ {
+ BcId* id = bc_vec_item(&p->str_map, idx);
+ idx = id->idx;
+ }
-size_t bc_program_search(BcProgram *p, const char *id, bool var) {
+ return idx;
+}
- BcVec *v, *map;
+size_t
+bc_program_search(BcProgram* p, const char* name, bool var)
+{
+ BcVec* v;
+ BcVec* map;
size_t i;
+ BC_SIG_ASSERT_LOCKED;
+
// Grab the right vector and map.
v = var ? &p->vars : &p->arrs;
map = var ? &p->var_map : &p->arr_map;
- BC_SIG_LOCK;
-
// We do an insert because the variable might not exist yet. This is because
// the parser calls this function. If the insert succeeds, we create a stack
// for the variable/array. But regardless, bc_map_insert() gives us the
// index of the item in i.
- if (bc_map_insert(map, id, v->len, &i)) {
- BcVec *temp = bc_vec_pushEmpty(v);
+ if (bc_map_insert(map, name, v->len, &i))
+ {
+ BcVec* temp = bc_vec_pushEmpty(v);
bc_array_init(temp, var);
}
- BC_SIG_UNLOCK;
-
return ((BcId*) bc_vec_item(map, i))->idx;
}
@@ -266,9 +282,10 @@ size_t bc_program_search(BcProgram *p, const char *id, bool var) {
* @param type The type of vector to return.
* @return A pointer to the variable or array stack.
*/
-static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
+static inline BcVec*
+bc_program_vec(const BcProgram* p, size_t idx, BcType type)
{
- const BcVec *v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
+ const BcVec* v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
return bc_vec_item(v, idx);
}
@@ -283,9 +300,10 @@ static inline BcVec* bc_program_vec(const BcProgram *p, size_t idx, BcType type)
* @param r The result whose number will be returned.
* @return The BcNum corresponding to the result.
*/
-static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
-
- BcNum *n;
+static BcNum*
+bc_program_num(BcProgram* p, BcResult* r)
+{
+ BcNum* n;
#ifdef _WIN32
// Windows made it an error to not initialize this, so shut it up.
@@ -295,8 +313,8 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
n = NULL;
#endif // _WIN32
- switch (r->t) {
-
+ switch (r->t)
+ {
case BC_RESULT_STR:
case BC_RESULT_TEMP:
case BC_RESULT_IBASE:
@@ -314,7 +332,7 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
case BC_RESULT_ARRAY:
case BC_RESULT_ARRAY_ELEM:
{
- BcVec *v;
+ BcVec* v;
BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
// Get the correct variable or array vector.
@@ -324,11 +342,11 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
// it's returning an array element. This is because we have to dig
// deeper to get *to* the element. That's what the code inside this
// if statement does.
- if (r->t == BC_RESULT_ARRAY_ELEM) {
-
+ if (r->t == BC_RESULT_ARRAY_ELEM)
+ {
size_t idx = r->d.loc.idx;
- v = bc_vec_top(v);
+ v = bc_vec_item(v, r->d.loc.stack_idx);
#if BC_ENABLED
// If this is true, we have a reference vector, so dereference
@@ -348,7 +366,8 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
// an element *way* out there, we have to preinitialize all
// elements between the current last element and the actual
// accessed element.
- if (v->len <= idx) {
+ if (v->len <= idx)
+ {
BC_SIG_LOCK;
bc_array_expand(v, bc_vm_growSize(idx, 1));
BC_SIG_UNLOCK;
@@ -357,21 +376,34 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
n = bc_vec_item(v, idx);
}
// This is either a number (for a var) or an array (for an array).
- // Because bc_vec_top() returns a void*, we don't need to cast.
- else n = bc_vec_top(v);
+ // Because bc_vec_top() and bc_vec_item() return a void*, we don't
+ // need to cast.
+ else
+ {
+#if BC_ENABLED
+ if (BC_IS_BC)
+ {
+ n = bc_vec_item(v, r->d.loc.stack_idx);
+ }
+ else
+#endif // BC_ENABLED
+ {
+ n = bc_vec_top(v);
+ }
+ }
break;
}
case BC_RESULT_ZERO:
{
- n = &vm.zero;
+ n = &vm->zero;
break;
}
case BC_RESULT_ONE:
{
- n = &vm.one;
+ n = &vm->one;
break;
}
@@ -379,18 +411,26 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
// We should never get here; this is taken care of earlier because a
// result is expected.
case BC_RESULT_VOID:
-#ifndef NDEBUG
+#if BC_DEBUG
{
abort();
+ // Fallthrough
}
-#endif // NDEBUG
- // Fallthrough
+#endif // BC_DEBUG
case BC_RESULT_LAST:
{
n = &p->last;
break;
}
#endif // BC_ENABLED
+
+#if BC_GCC
+ // This is here in GCC to quiet the "maybe-uninitialized" warning.
+ default:
+ {
+ abort();
+ }
+#endif // BC_GCC
}
return n;
@@ -405,8 +445,8 @@ static BcNum* bc_program_num(BcProgram *p, BcResult *r) {
* we care about.
* @param idx The index of the result from the top of the results stack.
*/
-static void bc_program_operand(BcProgram *p, BcResult **r,
- BcNum **n, size_t idx)
+static void
+bc_program_operand(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
{
*r = bc_vec_item_rev(&p->results, idx);
@@ -431,8 +471,9 @@ static void bc_program_operand(BcProgram *p, BcResult **r,
* @param idx The starting index where the operands are in the results stack,
* starting from the top.
*/
-static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
- BcResult **r, BcNum **rn, size_t idx)
+static void
+bc_program_binPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
+ BcNum** rn, size_t idx)
{
BcResultType lt;
@@ -440,9 +481,12 @@ static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
#ifndef BC_PROG_NO_STACK_CHECK
// Check the stack for dc.
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
}
#endif // BC_PROG_NO_STACK_CHECK
@@ -463,7 +507,9 @@ static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
// reallocated out from under the BcNums or arrays we had. In other words,
// this is to fix pointer invalidation.
if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
+ {
*ln = bc_program_num(p, *l);
+ }
if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE);
}
@@ -484,8 +530,9 @@ static void bc_program_binPrep(BcProgram *p, BcResult **l, BcNum **ln,
* @param idx The starting index where the operands are in the results stack,
* starting from the top.
*/
-static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
- BcResult **r, BcNum **rn, size_t idx)
+static void
+bc_program_binOpPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
+ BcNum** rn, size_t idx)
{
bc_program_binPrep(p, l, ln, r, rn, idx);
bc_program_type_num(*l, *ln);
@@ -504,10 +551,12 @@ static void bc_program_binOpPrep(BcProgram *p, BcResult **l, BcNum **ln,
* @param rn An out parameter; this is set to the pointer to the number for the
* right operand.
*/
-static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
- BcResult **r, BcNum **rn)
+static void
+bc_program_assignPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
+ BcNum** rn)
{
BcResultType lt, min;
+ bool good;
// This is the min non-allowable result type. dc allows strings.
min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
@@ -522,7 +571,7 @@ static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
// Strings can be assigned to variables. We are already good if we are
// assigning a string.
- bool good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
+ good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR);
@@ -540,15 +589,19 @@ static void bc_program_assignPrep(BcProgram *p, BcResult **l, BcNum **ln,
* we care about.
* @param idx The index of the result from the top of the results stack.
*/
-static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
-
+static void
+bc_program_prep(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
+{
assert(p != NULL && r != NULL && n != NULL);
#ifndef BC_PROG_NO_STACK_CHECK
// Check the stack for dc.
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
}
#endif // BC_PROG_NO_STACK_CHECK
@@ -565,9 +618,10 @@ static void bc_program_prep(BcProgram *p, BcResult **r, BcNum **n, size_t idx) {
* @param p The program.
* @return A clean result.
*/
-static BcResult* bc_program_prepResult(BcProgram *p) {
-
- BcResult *res = bc_vec_pushEmpty(&p->results);
+static BcResult*
+bc_program_prepResult(BcProgram* p)
+{
+ BcResult* res = bc_vec_pushEmpty(&p->results);
bc_result_clear(res);
@@ -583,23 +637,30 @@ static BcResult* bc_program_prepResult(BcProgram *p) {
* @param bgn An in/out parameter; marks the start of the index in the
* bytecode vector and will be updated to point to after the index.
*/
-static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
-
+static void
+bc_program_const(BcProgram* p, const char* code, size_t* bgn)
+{
// I lied. I actually push the result first. I can do this because the
// result will be popped on error. I also get the constant itself.
- BcResult *r = bc_program_prepResult(p);
- BcConst *c = bc_vec_item(p->consts, bc_program_index(code, bgn));
+ BcResult* r = bc_program_prepResult(p);
+ BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
BcBigDig base = BC_PROG_IBASE(p);
// Only reparse if the base changed.
- if (c->base != base) {
-
+ if (c->base != base)
+ {
// Allocate if we haven't yet.
- if (c->num.num == NULL) {
+ if (c->num.num == NULL)
+ {
+ // The plus 1 is in case of overflow with lack of clamping.
+ size_t len = strlen(c->val) + (BC_DIGIT_CLAMP == 0);
+
BC_SIG_LOCK;
- bc_num_init(&c->num, BC_NUM_RDX(strlen(c->val)));
+ bc_num_init(&c->num, BC_NUM_RDX(len));
BC_SIG_UNLOCK;
}
+ // We need to zero an already existing number.
+ else bc_num_zero(&c->num);
// bc_num_parse() should only do operations that cannot fail.
bc_num_parse(&c->num, c->val, base);
@@ -619,10 +680,14 @@ static void bc_program_const(BcProgram *p, const char *code, size_t *bgn) {
* @param p The program.
* @param inst The instruction corresponding to the binary operator to execute.
*/
-static void bc_program_op(BcProgram *p, uchar inst) {
-
- BcResult *opd1, *opd2, *res;
- BcNum *n1, *n2;
+static void
+bc_program_op(BcProgram* p, uchar inst)
+{
+ BcResult* opd1;
+ BcResult* opd2;
+ BcResult* res;
+ BcNum* n1;
+ BcNum* n2;
size_t idx = inst - BC_INST_POWER;
res = bc_program_prepResult(p);
@@ -651,72 +716,83 @@ static void bc_program_op(BcProgram *p, uchar inst) {
* Executes a read() or ? command.
* @param p The program.
*/
-static void bc_program_read(BcProgram *p) {
-
+static void
+bc_program_read(BcProgram* p)
+{
BcStatus s;
BcInstPtr ip;
size_t i;
const char* file;
- bool is_stdin;
- BcFunc *f = bc_vec_item(&p->fns, BC_PROG_READ);
+ BcMode mode;
+ BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
// If we are already executing a read, that is an error. So look for a read
// and barf.
- for (i = 0; i < p->stack.len; ++i) {
- BcInstPtr *ip_ptr = bc_vec_item(&p->stack, i);
+ for (i = 0; i < p->stack.len; ++i)
+ {
+ BcInstPtr* ip_ptr = bc_vec_item(&p->stack, i);
if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ);
}
BC_SIG_LOCK;
// Save the filename because we are going to overwrite it.
- file = vm.file;
- is_stdin = vm.is_stdin;
+ file = vm->file;
+ mode = vm->mode;
// It is a parse error if there needs to be more than one line, so we unset
// this to tell the lexer to not request more. We set it back later.
- vm.is_stdin = false;
-
- if (!BC_PARSE_IS_INITED(&vm.read_prs, p)) {
+ vm->mode = BC_MODE_FILE;
+ if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
+ {
// We need to parse, but we don't want to use the existing parser
// because it has state it needs to keep. (It could have a partial parse
// state.) So we create a new parser. This parser is in the BcVm struct
// so that it is not local, which means that a longjmp() could change
// it.
- bc_parse_init(&vm.read_prs, p, BC_PROG_READ);
+ bc_parse_init(&vm->read_prs, p, BC_PROG_READ);
// We need a separate input buffer; that's why it is also in the BcVm
// struct.
- bc_vec_init(&vm.read_buf, sizeof(char), BC_DTOR_NONE);
+ bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
+ }
+ else
+ {
+ // This needs to be updated because the parser could have been used
+ // somewhere else.
+ bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
+
+ // The read buffer also needs to be emptied or else it will still
+ // contain previous read expressions.
+ bc_vec_empty(&vm->read_buf);
}
- // This needs to be updated because the parser could have been used
- // somewhere else
- else bc_parse_updateFunc(&vm.read_prs, BC_PROG_READ);
- BC_SETJMP_LOCKED(exec_err);
+ BC_SETJMP_LOCKED(vm, exec_err);
BC_SIG_UNLOCK;
// Set up the lexer and the read function.
- bc_lex_file(&vm.read_prs.l, bc_program_stdin_name);
+ bc_lex_file(&vm->read_prs.l, bc_program_stdin_name);
bc_vec_popAll(&f->code);
// Read a line.
- if (!BC_R) s = bc_read_line(&vm.read_buf, "");
- else s = bc_read_line(&vm.read_buf, BC_IS_BC ? "read> " : "?> ");
+ if (!BC_R) s = bc_read_line(&vm->read_buf, "");
+ else s = bc_read_line(&vm->read_buf, BC_VM_READ_PROMPT);
// We should *not* have run into EOF.
if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
- // Parse *one* expression.
- bc_parse_text(&vm.read_prs, vm.read_buf.v, false);
- vm.expr(&vm.read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
+ // Parse *one* expression, so mode should not be stdin.
+ bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
+ BC_SIG_LOCK;
+ vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
+ BC_SIG_UNLOCK;
// We *must* have a valid expression. A semicolon cannot end an expression,
// although EOF can.
- if (BC_ERR(vm.read_prs.l.t != BC_LEX_NLINE &&
- vm.read_prs.l.t != BC_LEX_EOF))
+ if (BC_ERR(vm->read_prs.l.t != BC_LEX_NLINE &&
+ vm->read_prs.l.t != BC_LEX_EOF))
{
bc_err(BC_ERR_EXEC_READ_EXPR);
}
@@ -735,12 +811,16 @@ static void bc_program_read(BcProgram *p) {
f = bc_vec_item(&p->fns, BC_PROG_READ);
// We want a return instruction to simplify things.
- bc_vec_pushByte(&f->code, vm.read_ret);
+ bc_vec_pushByte(&f->code, vm->read_ret);
+
+ // This lock is here to make sure dc's tail calls are the same length.
+ BC_SIG_LOCK;
bc_vec_push(&p->stack, &ip);
#if DC_ENABLED
// We need a new tail call entry for dc.
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
size_t temp = 0;
bc_vec_push(&p->tail_calls, &temp);
}
@@ -748,9 +828,9 @@ static void bc_program_read(BcProgram *p) {
exec_err:
BC_SIG_MAYLOCK;
- vm.is_stdin = is_stdin;
- vm.file = file;
- BC_LONGJMP_CONT;
+ vm->mode = (uchar) mode;
+ vm->file = file;
+ BC_LONGJMP_CONT(vm);
}
#if BC_ENABLE_EXTRA_MATH
@@ -759,20 +839,21 @@ exec_err:
* Execute a rand().
* @param p The program.
*/
-static void bc_program_rand(BcProgram *p) {
-
+static void
+bc_program_rand(BcProgram* p)
+{
BcRand rand = bc_rand_int(&p->rng);
bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
-#ifndef NDEBUG
+#if BC_DEBUG
// This is just to ensure that the generated number is correct. I also use
// braces because I declare every local at the top of the scope.
{
- BcResult *r = bc_vec_top(&p->results);
+ BcResult* r = bc_vec_top(&p->results);
assert(BC_NUM_RDX_VALID_NP(r->d.n));
}
-#endif // NDEBUG
+#endif // BC_DEBUG
}
#endif // BC_ENABLE_EXTRA_MATH
@@ -780,12 +861,16 @@ static void bc_program_rand(BcProgram *p) {
* Prints a series of characters, without escapes.
* @param str The string (series of characters).
*/
-static void bc_program_printChars(const char *str) {
+static void
+bc_program_printChars(const char* str)
+{
+ const char* nl;
+ size_t len = vm->nchars + strlen(str);
+ sig_atomic_t lock;
- const char *nl;
- size_t len = vm.nchars + strlen(str);
+ BC_SIG_TRYLOCK(lock);
- bc_file_puts(&vm.fout, bc_flush_save, str);
+ bc_file_puts(&vm->fout, bc_flush_save, str);
// We need to update the number of characters, so we find the last newline
// and set the characters accordingly.
@@ -793,49 +878,59 @@ static void bc_program_printChars(const char *str) {
if (nl != NULL) len = strlen(nl + 1);
- vm.nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
+ vm->nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
+
+ BC_SIG_TRYUNLOCK(lock);
}
/**
* Prints a string with escapes.
* @param str The string.
*/
-static void bc_program_printString(const char *restrict str) {
-
+static void
+bc_program_printString(const char* restrict str)
+{
size_t i, len = strlen(str);
#if DC_ENABLED
// This is to ensure a nul byte is printed for dc's stream operation.
- if (!len && BC_IS_DC) {
+ if (!len && BC_IS_DC)
+ {
bc_vm_putchar('\0', bc_flush_save);
return;
}
#endif // DC_ENABLED
// Loop over the characters, processing escapes and printing the rest.
- for (i = 0; i < len; ++i) {
-
+ for (i = 0; i < len; ++i)
+ {
int c = str[i];
// If we have an escape...
- if (c == '\\' && i != len - 1) {
-
- const char *ptr;
+ if (c == '\\' && i != len - 1)
+ {
+ const char* ptr;
// Get the escape character and its companion.
c = str[++i];
ptr = strchr(bc_program_esc_chars, c);
// If we have a companion character...
- if (ptr != NULL) {
-
+ if (ptr != NULL)
+ {
// We need to specially handle a newline.
- if (c == 'n') vm.nchars = UINT16_MAX;
+ if (c == 'n')
+ {
+ BC_SIG_LOCK;
+ vm->nchars = UINT16_MAX;
+ BC_SIG_UNLOCK;
+ }
// Grab the actual character.
c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
}
- else {
+ else
+ {
// Just print the backslash if there is no companion character.
// The following character will be printed later after the outer
// if statement.
@@ -853,19 +948,23 @@ static void bc_program_printString(const char *restrict str) {
* @param inst The instruction for the type of print we are doing.
* @param idx The index of the result that we are printing.
*/
-static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
-
- BcResult *r;
- char *str;
- BcNum *n;
+static void
+bc_program_print(BcProgram* p, uchar inst, size_t idx)
+{
+ BcResult* r;
+ char* str;
+ BcNum* n;
bool pop = (inst != BC_INST_PRINT);
assert(p != NULL);
#ifndef BC_PROG_NO_STACK_CHECK
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
}
#endif // BC_PROG_NO_STACK_CHECK
@@ -878,7 +977,8 @@ static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
// true because that means that we are executing a print statement, but
// attempting to do a print on a lone void value is allowed because that's
// exactly how we want void values used.
- if (r->t == BC_RESULT_VOID) {
+ if (r->t == BC_RESULT_VOID)
+ {
if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL);
bc_vec_pop(&p->results);
return;
@@ -888,8 +988,8 @@ static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
n = bc_program_num(p, r);
// If we have a number...
- if (BC_PROG_NUM(r, n)) {
-
+ if (BC_PROG_NUM(r, n))
+ {
#if BC_ENABLED
assert(inst != BC_INST_PRINT_STR);
#endif // BC_ENABLED
@@ -902,10 +1002,10 @@ static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
if (BC_IS_BC) bc_num_copy(&p->last, n);
#endif // BC_ENABLED
}
- else {
-
+ else
+ {
// We want to flush any stuff in the stdout buffer first.
- bc_file_flush(&vm.fout, bc_flush_save);
+ bc_file_flush(&vm->fout, bc_flush_save);
str = bc_program_string(p, n);
#if BC_ENABLED
@@ -916,26 +1016,31 @@ static void bc_program_print(BcProgram *p, uchar inst, size_t idx) {
bc_program_printString(str);
// Need to print a newline only in this case.
- if (inst == BC_INST_PRINT)
- bc_vm_putchar('\n', bc_flush_err);
+ if (inst == BC_INST_PRINT) bc_vm_putchar('\n', bc_flush_err);
}
}
- // bc always pops.
- if (BC_IS_BC || pop) bc_vec_pop(&p->results);
+ // bc always pops. This macro makes sure that happens.
+ if (BC_PROGRAM_POP(pop)) bc_vec_pop(&p->results);
}
-void bc_program_negate(BcResult *r, BcNum *n) {
+void
+bc_program_negate(BcResult* r, BcNum* n)
+{
bc_num_copy(&r->d.n, n);
if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
}
-void bc_program_not(BcResult *r, BcNum *n) {
+void
+bc_program_not(BcResult* r, BcNum* n)
+{
if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
}
#if BC_ENABLE_EXTRA_MATH
-void bc_program_trunc(BcResult *r, BcNum *n) {
+void
+bc_program_trunc(BcResult* r, BcNum* n)
+{
bc_num_copy(&r->d.n, n);
bc_num_truncate(&r->d.n, n->scale);
}
@@ -946,10 +1051,12 @@ void bc_program_trunc(BcResult *r, BcNum *n) {
* @param p The program.
* @param inst The unary operation.
*/
-static void bc_program_unary(BcProgram *p, uchar inst) {
-
- BcResult *res, *ptr;
- BcNum *num;
+static void
+bc_program_unary(BcProgram* p, uchar inst)
+{
+ BcResult* res;
+ BcResult* ptr;
+ BcNum* num;
res = bc_program_prepResult(p);
@@ -971,10 +1078,14 @@ static void bc_program_unary(BcProgram *p, uchar inst) {
* @param p The program.
* @param inst The operator.
*/
-static void bc_program_logical(BcProgram *p, uchar inst) {
-
- BcResult *opd1, *opd2, *res;
- BcNum *n1, *n2;
+static void
+bc_program_logical(BcProgram* p, uchar inst)
+{
+ BcResult* opd1;
+ BcResult* opd2;
+ BcResult* res;
+ BcNum* n1;
+ BcNum* n2;
bool cond = 0;
ssize_t cmp;
@@ -987,16 +1098,20 @@ static void bc_program_logical(BcProgram *p, uchar inst) {
// Boolean and and or are not short circuiting. This is why; they can be
// implemented much easier this way.
if (inst == BC_INST_BOOL_AND)
+ {
cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
+ }
else if (inst == BC_INST_BOOL_OR)
+ {
cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
- else {
-
+ }
+ else
+ {
// We have a relational operator, so do a comparison.
cmp = bc_num_cmp(n1, n2);
- switch (inst) {
-
+ switch (inst)
+ {
case BC_INST_REL_EQ:
{
cond = (cmp == 0);
@@ -1032,13 +1147,13 @@ static void bc_program_logical(BcProgram *p, uchar inst) {
cond = (cmp > 0);
break;
}
-#ifndef NDEBUG
+#if BC_DEBUG
default:
{
// There is a bug if we get here.
abort();
}
-#endif // NDEBUG
+#endif // BC_DEBUG
}
}
@@ -1062,9 +1177,10 @@ static void bc_program_logical(BcProgram *p, uchar inst) {
* string from the results stack and push it onto the variable
* stack.
*/
-static void bc_program_assignStr(BcProgram *p, BcNum *num, BcVec *v, bool push)
+static void
+bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
{
- BcNum *n;
+ BcNum* n;
assert(BC_PROG_STACK(&p->results, 1 + !push));
assert(num != NULL && num->num == NULL && num->cap == 0);
@@ -1078,32 +1194,29 @@ static void bc_program_assignStr(BcProgram *p, BcNum *num, BcVec *v, bool push)
n = bc_vec_pushEmpty(v);
// We can just copy because the num should not have allocated anything.
+ // NOLINTNEXTLINE
memcpy(n, num, sizeof(BcNum));
}
/**
* Copies a value to a variable. This is used for storing in dc as well as to
* set function parameters to arguments in bc.
- * @param p The program.
- * @param idx The index of the variable or array to copy to.
- * @param t The type to copy to. This could be a variable or an array.
- * @param last Whether to grab the last item on the variable stack or not (for
- * bc function parameters). This is important because if a new
- * value has been pushed to the variable already, we need to grab
- * the value pushed before. This happens when you have a parameter
- * named something like "x", and a variable "x" is passed to
- * another parameter.
+ * @param p The program.
+ * @param idx The index of the variable or array to copy to.
+ * @param t The type to copy to. This could be a variable or an array.
*/
-static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
+static void
+bc_program_copyToVar(BcProgram* p, size_t idx, BcType t)
{
BcResult *ptr = NULL, r;
- BcVec *vec;
- BcNum *n = NULL;
+ BcVec* vec;
+ BcNum* n = NULL;
bool var = (t == BC_TYPE_VAR);
#if DC_ENABLED
// Check the stack for dc.
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
}
#endif
@@ -1118,11 +1231,6 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
{
// Type match the result.
bc_program_type_match(ptr, t);
-
- // Get the variable or array, taking care to get the real item. We take
- // care of last with arrays later.
- if (!last && var)
- n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1);
}
#endif // BC_ENABLED
@@ -1130,8 +1238,8 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
// We can shortcut in dc if it's assigning a string by using
// bc_program_assignStr().
- if (ptr->t == BC_RESULT_STR) {
-
+ if (ptr->t == BC_RESULT_STR)
+ {
assert(BC_PROG_STR(n));
if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE);
@@ -1144,33 +1252,28 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
BC_SIG_LOCK;
// Just create and copy for a normal variable.
- if (var) {
- if (BC_PROG_STR(n)) memcpy(&r.d.n, n, sizeof(BcNum));
+ if (var)
+ {
+ if (BC_PROG_STR(n))
+ {
+ // NOLINTNEXTLINE
+ memcpy(&r.d.n, n, sizeof(BcNum));
+ }
else bc_num_createCopy(&r.d.n, n);
}
- else {
-
+ else
+ {
// If we get here, we are handling an array. This is one place we need
// to cast the number from bc_program_num() to a vector.
- BcVec *v = (BcVec*) n, *rv = &r.d.v;
+ BcVec* v = (BcVec*) n;
+ BcVec* rv = &r.d.v;
#if BC_ENABLED
- if (BC_IS_BC) {
-
- BcVec *parent;
+ if (BC_IS_BC)
+ {
bool ref, ref_size;
- // We need to figure out if the parameter is a reference or not and
- // construct the reference vector, if necessary. So this gets the
- // parent stack for the array.
- parent = bc_program_vec(p, ptr->d.loc.loc, t);
- assert(parent != NULL);
-
- // This takes care of last for arrays. Mostly.
- if (!last) v = bc_vec_item_rev(parent, !last);
- assert(v != NULL);
-
// True if we are using a reference.
ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
@@ -1182,16 +1285,14 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
ref_size = (v->size == sizeof(uchar));
// If we *should* have a reference.
- if (ref || (ref_size && t == BC_TYPE_REF)) {
-
+ if (ref || (ref_size && t == BC_TYPE_REF))
+ {
// Create a new reference vector.
bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE);
// If this is true, then we need to construct a reference.
- if (ref) {
-
- assert(parent->len >= (size_t) (!last + 1));
-
+ if (ref)
+ {
// Make sure the pointer was not invalidated.
vec = bc_program_vec(p, idx, t);
@@ -1199,7 +1300,7 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
// care of last; it ensures the reference goes to the right
// place.
bc_vec_pushIndex(rv, ptr->d.loc.loc);
- bc_vec_pushIndex(rv, parent->len - !last - 1);
+ bc_vec_pushIndex(rv, ptr->d.loc.stack_idx);
}
// If we get here, we are copying a ref to a ref. Just push a
// copy of all of the bytes.
@@ -1218,7 +1319,9 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
// If we get here, we have a reference, but we need an array, so
// dereference the array.
else if (ref_size && t != BC_TYPE_REF)
+ {
v = bc_program_dereference(p, v);
+ }
}
#endif // BC_ENABLED
@@ -1235,16 +1338,97 @@ static void bc_program_copyToVar(BcProgram *p, size_t idx, BcType t, bool last)
BC_SIG_UNLOCK;
}
+void
+bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val)
+{
+ BcBigDig* ptr_t;
+ BcBigDig max, min;
+#if BC_ENABLED
+ BcVec* v;
+ BcBigDig* ptr;
+#endif // BC_ENABLED
+
+ assert(!scale || !obase);
+
+ // Scale needs handling separate from ibase and obase.
+ if (scale)
+ {
+ // Set the min and max.
+ min = 0;
+ max = vm->maxes[BC_PROG_GLOBALS_SCALE];
+
+#if BC_ENABLED
+ // Get a pointer to the stack.
+ v = p->globals_v + BC_PROG_GLOBALS_SCALE;
+#endif // BC_ENABLED
+
+ // Get a pointer to the current value.
+ ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
+ }
+ else
+ {
+ // Set the min and max.
+ min = BC_NUM_MIN_BASE;
+ if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX))
+ {
+ min = 0;
+ }
+ max = vm->maxes[obase + BC_PROG_GLOBALS_IBASE];
+
+#if BC_ENABLED
+ // Get a pointer to the stack.
+ v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase;
+#endif // BC_ENABLED
+
+ // Get a pointer to the current value.
+ ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase;
+ }
+
+ // Check for error.
+ if (BC_ERR(val > max || val < min))
+ {
+ BcErr e;
+
+ // This grabs the right error.
+ if (scale) e = BC_ERR_EXEC_SCALE;
+ else if (obase) e = BC_ERR_EXEC_OBASE;
+ else e = BC_ERR_EXEC_IBASE;
+
+ bc_verr(e, min, max);
+ }
+
+#if BC_ENABLED
+ // Set the top of the stack.
+ ptr = bc_vec_top(v);
+ *ptr = val;
+#endif // BC_ENABLED
+
+ // Set the actual global variable.
+ *ptr_t = val;
+}
+
+#if BC_ENABLE_EXTRA_MATH
+void
+bc_program_assignSeed(BcProgram* p, BcNum* val)
+{
+ bc_num_rng(val, &p->rng);
+}
+#endif // BC_ENABLE_EXTRA_MATH
+
/**
* Executes an assignment operator.
* @param p The program.
* @param inst The assignment operator to execute.
*/
-static void bc_program_assign(BcProgram *p, uchar inst) {
-
+static void
+bc_program_assign(BcProgram* p, uchar inst)
+{
// The local use_val is true when the assigned value needs to be copied.
- BcResult *left, *right, res;
- BcNum *l, *r;
+ BcResult* left;
+ BcResult* right;
+ BcResult res;
+ BcNum* l;
+ BcNum* r;
bool ob, sc, use_val = BC_INST_USE_VAL(inst);
bc_program_assignPrep(p, &left, &l, &right, &r);
@@ -1253,23 +1437,26 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
assert(left->t != BC_RESULT_STR);
// If we are assigning a string...
- if (right->t == BC_RESULT_STR) {
-
+ if (right->t == BC_RESULT_STR)
+ {
assert(BC_PROG_STR(r));
#if BC_ENABLED
if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL)
+ {
bc_err(BC_ERR_EXEC_TYPE);
+ }
#endif // BC_ENABLED
// If we are assigning to an array element...
- if (left->t == BC_RESULT_ARRAY_ELEM) {
-
+ if (left->t == BC_RESULT_ARRAY_ELEM)
+ {
BC_SIG_LOCK;
// We need to free the number and clear it.
bc_num_free(l);
+ // NOLINTNEXTLINE
memcpy(l, r, sizeof(BcNum));
// Now we can pop the results.
@@ -1277,11 +1464,11 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
BC_SIG_UNLOCK;
}
- else {
-
+ else
+ {
// If we get here, we are assigning to a variable, which we can use
// bc_program_assignStr() for.
- BcVec *v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
+ BcVec* v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
bc_program_assignStr(p, r, v, false);
}
@@ -1289,8 +1476,10 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
// If this is true, the value is going to be used again, so we want to
// push a temporary with the string.
- if (inst == BC_INST_ASSIGN) {
+ if (inst == BC_INST_ASSIGN)
+ {
res.t = BC_RESULT_STR;
+ // NOLINTNEXTLINE
memcpy(&res.d.n, r, sizeof(BcNum));
bc_vec_push(&p->results, &res);
}
@@ -1302,8 +1491,8 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
}
// If we have a normal assignment operator, not a math one...
- if (BC_INST_IS_ASSIGN(inst)) {
-
+ if (BC_INST_IS_ASSIGN(inst))
+ {
// Assigning to a variable that has a string here is fine because there
// is no math done on it.
@@ -1313,11 +1502,12 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
// type of right to BC_RESULT_ZERO in order to prevent it from being
// freed. We also don't have to worry about BC_RESULT_STR because it's
// take care of above.
- if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE) {
-
+ if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE)
+ {
BC_SIG_LOCK;
bc_num_free(l);
+ // NOLINTNEXTLINE
memcpy(l, r, sizeof(BcNum));
right->t = BC_RESULT_ZERO;
@@ -1327,8 +1517,8 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
else bc_num_copy(l, r);
}
#if BC_ENABLED
- else {
-
+ else
+ {
// If we get here, we are doing a math assignment (+=, -=, etc.). So
// we need to prepare for a binary operator.
BcBigDig scale = BC_PROG_SCALE(p);
@@ -1341,7 +1531,9 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
// Get the right type of assignment operator, whether val is used or
// NO_VAL for performance.
if (!use_val)
+ {
inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
+ }
assert(BC_NUM_RDX_VALID(l));
assert(BC_NUM_RDX_VALID(r));
@@ -1357,62 +1549,24 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
// The globals need special handling, especially the non-seed ones. The
// first part of the if statement handles them.
- if (ob || sc || left->t == BC_RESULT_IBASE) {
-
- BcVec *v;
- BcBigDig *ptr, *ptr_t, val, max, min;
-
+ if (ob || sc || left->t == BC_RESULT_IBASE)
+ {
// Get the actual value.
- val = bc_num_bigdig(l);
-
- // Scale needs handling separate from ibase and obase.
- if (sc) {
-
- // Set the min and max.
- min = 0;
- max = vm.maxes[BC_PROG_GLOBALS_SCALE];
-
- // Get a pointer to the stack and to the current value.
- v = p->globals_v + BC_PROG_GLOBALS_SCALE;
- ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
- }
- else {
-
- // Set the min and max.
- min = BC_NUM_MIN_BASE;
- if (BC_ENABLE_EXTRA_MATH && ob && (BC_IS_DC || !BC_IS_POSIX))
- min = 0;
- max = vm.maxes[ob + BC_PROG_GLOBALS_IBASE];
+ BcBigDig val = bc_num_bigdig(l);
- // Get a pointer to the stack and to the current value.
- v = p->globals_v + BC_PROG_GLOBALS_IBASE + ob;
- ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + ob;
- }
-
- // Check for error.
- if (BC_ERR(val > max || val < min)) {
-
- // This grabs the right error.
- BcErr e = left->t - BC_RESULT_IBASE + BC_ERR_EXEC_IBASE;
-
- bc_verr(e, min, max);
- }
-
- // Set the top of the stack and the actual global value.
- ptr = bc_vec_top(v);
- *ptr = val;
- *ptr_t = val;
+ bc_program_assignBuiltin(p, sc, ob, val);
}
#if BC_ENABLE_EXTRA_MATH
// To assign to steed, let bc_num_rng() do its magic.
- else if (left->t == BC_RESULT_SEED) bc_num_rng(l, &p->rng);
+ else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l);
#endif // BC_ENABLE_EXTRA_MATH
BC_SIG_LOCK;
// If we needed to use the value, then we need to copy it. Otherwise, we can
// pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP.
- if (use_val) {
+ if (use_val)
+ {
bc_num_createCopy(&res.d.n, l);
res.t = BC_RESULT_TEMP;
bc_vec_npop(&p->results, 2);
@@ -1434,36 +1588,42 @@ static void bc_program_assign(BcProgram *p, uchar inst) {
* @param copy True if the variable's value should be copied to the results
* stack. This is only used in dc.
*/
-static void bc_program_pushVar(BcProgram *p, const char *restrict code,
- size_t *restrict bgn, bool pop, bool copy)
+static void
+bc_program_pushVar(BcProgram* p, const char* restrict code,
+ size_t* restrict bgn, bool pop, bool copy)
{
BcResult r;
size_t idx = bc_program_index(code, bgn);
+ BcVec* v;
// Set the result appropriately.
r.t = BC_RESULT_VAR;
r.d.loc.loc = idx;
+ // Get the stack for the variable. This is used in both bc and dc.
+ v = bc_program_vec(p, idx, BC_TYPE_VAR);
+ r.d.loc.stack_idx = v->len - 1;
+
#if DC_ENABLED
// If this condition is true, then we have the hard case, where we have to
// adjust dc registers.
- if (BC_IS_DC && (pop || copy)) {
-
- // Get the stack for the variable and the number at the top.
- BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
- BcNum *num = bc_vec_top(v);
+ if (BC_IS_DC && (pop || copy))
+ {
+ // Get the number at the top at the top of the stack.
+ BcNum* num = bc_vec_top(v);
// Ensure there are enough elements on the stack.
- if (BC_ERR(!BC_PROG_STACK(v, 2 - copy))) {
- const char *name = bc_map_name(&p->var_map, idx);
+ if (BC_ERR(!BC_PROG_STACK(v, 2 - copy)))
+ {
+ const char* name = bc_map_name(&p->var_map, idx);
bc_verr(BC_ERR_EXEC_STACK_REGISTER, name);
}
assert(BC_PROG_STACK(v, 2 - copy));
// If the top of the stack is actually a number...
- if (!BC_PROG_STR(num)) {
-
+ if (!BC_PROG_STR(num))
+ {
BC_SIG_LOCK;
// Create a copy to go onto the results stack as appropriate.
@@ -1479,9 +1639,11 @@ static void bc_program_pushVar(BcProgram *p, const char *restrict code,
return;
}
- else {
+ else
+ {
// Set the string result. We can just memcpy because all of the
// fields in the num should be cleared.
+ // NOLINTNEXTLINE
memcpy(&r.d.n, num, sizeof(BcNum));
r.t = BC_RESULT_STR;
}
@@ -1502,18 +1664,28 @@ static void bc_program_pushVar(BcProgram *p, const char *restrict code,
* vector, and will be updated to point after the index on return.
* @param inst The instruction; whether to push an array or an array element.
*/
-static void bc_program_pushArray(BcProgram *p, const char *restrict code,
- size_t *restrict bgn, uchar inst)
+static void
+bc_program_pushArray(BcProgram* p, const char* restrict code,
+ size_t* restrict bgn, uchar inst)
{
- BcResult r, *operand;
- BcNum *num;
+ BcResult r;
+ BcResult* operand;
+ BcNum* num;
BcBigDig temp;
+ BcVec* v;
// Get the index of the array.
r.d.loc.loc = bc_program_index(code, bgn);
+ // We need the array to get its length.
+ v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY);
+ assert(v != NULL);
+
+ r.d.loc.stack_idx = v->len - 1;
+
// Doing an array is easy; just set the result type and finish.
- if (inst == BC_INST_ARRAY) {
+ if (inst == BC_INST_ARRAY)
+ {
r.t = BC_RESULT_ARRAY;
bc_vec_push(&p->results, &r);
return;
@@ -1545,10 +1717,11 @@ static void bc_program_pushArray(BcProgram *p, const char *restrict code,
* @param p The program.
* @param inst The instruction; whether to do an increment or decrement.
*/
-static void bc_program_incdec(BcProgram *p, uchar inst) {
-
+static void
+bc_program_incdec(BcProgram* p, uchar inst)
+{
BcResult *ptr, res, copy;
- BcNum *num;
+ BcNum* num;
uchar inst2;
bc_program_prep(p, &ptr, &num, 0);
@@ -1559,7 +1732,7 @@ static void bc_program_incdec(BcProgram *p, uchar inst) {
copy.t = BC_RESULT_TEMP;
bc_num_createCopy(&copy.d.n, num);
- BC_SETJMP_LOCKED(exit);
+ BC_SETJMP_LOCKED(vm, exit);
BC_SIG_UNLOCK;
@@ -1574,7 +1747,7 @@ static void bc_program_incdec(BcProgram *p, uchar inst) {
bc_vec_push(&p->results, &copy);
- BC_UNSETJMP;
+ BC_UNSETJMP(vm);
BC_SIG_UNLOCK;
@@ -1584,7 +1757,7 @@ static void bc_program_incdec(BcProgram *p, uchar inst) {
exit:
BC_SIG_MAYLOCK;
bc_num_free(&copy.d.n);
- BC_LONGJMP_CONT;
+ BC_LONGJMP_CONT(vm);
}
/**
@@ -1596,15 +1769,15 @@ exit:
* vector, and will be updated to point after the indices on
* return.
*/
-static void bc_program_call(BcProgram *p, const char *restrict code,
- size_t *restrict bgn)
+static void
+bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn)
{
BcInstPtr ip;
size_t i, nargs;
- BcFunc *f;
- BcVec *v;
- BcAuto *a;
- BcResult *arg;
+ BcFunc* f;
+ BcVec* v;
+ BcAuto* a;
+ BcResult* arg;
// Pull the number of arguments out of the bytecode vector.
nargs = bc_program_index(code, bgn);
@@ -1617,7 +1790,9 @@ static void bc_program_call(BcProgram *p, const char *restrict code,
// Error checking.
if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
if (BC_ERR(nargs != f->nparams))
+ {
bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs);
+ }
// Set the length of the results stack. We discount the argument, of course.
ip.len = p->results.len - nargs;
@@ -1628,56 +1803,36 @@ static void bc_program_call(BcProgram *p, const char *restrict code,
if (BC_G) bc_program_prepGlobals(p);
// Push the arguments onto the stacks of their respective parameters.
- for (i = 0; i < nargs; ++i) {
-
- size_t j;
- bool last = true;
-
+ for (i = 0; i < nargs; ++i)
+ {
arg = bc_vec_top(&p->results);
if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
// Get the corresponding parameter.
a = bc_vec_item(&f->autos, nargs - 1 - i);
- // If I have already pushed to a var, I need to make sure I
- // get the previous version, not the already pushed one. This condition
- // must be true for that to even be possible.
- if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) {
-
- // Loop through all of the previous parameters.
- for (j = 0; j < i && last; ++j) {
-
- BcAuto *aptr = bc_vec_item(&f->autos, nargs - 1 - j);
-
- // This condition is true if there is a previous parameter with
- // the same name *and* type because variables and arrays do not
- // interfere with each other.
- last = (arg->d.loc.loc != aptr->idx ||
- (!aptr->type) != (arg->t == BC_RESULT_VAR));
- }
- }
-
// Actually push the value onto the parameter's stack.
- bc_program_copyToVar(p, a->idx, a->type, last);
+ bc_program_copyToVar(p, a->idx, a->type);
}
BC_SIG_LOCK;
// Push zeroes onto the stacks of the auto variables.
- for (; i < f->autos.len; ++i) {
-
+ for (; i < f->autos.len; ++i)
+ {
// Get the auto and its stack.
a = bc_vec_item(&f->autos, i);
v = bc_program_vec(p, a->idx, a->type);
// If a variable, just push a 0; otherwise, push an array.
- if (a->type == BC_TYPE_VAR) {
- BcNum *n = bc_vec_pushEmpty(v);
+ if (a->type == BC_TYPE_VAR)
+ {
+ BcNum* n = bc_vec_pushEmpty(v);
bc_num_init(n, BC_NUM_DEF_SIZE);
}
- else {
-
- BcVec *v2;
+ else
+ {
+ BcVec* v2;
assert(a->type == BC_TYPE_ARRAY);
@@ -1698,11 +1853,12 @@ static void bc_program_call(BcProgram *p, const char *restrict code,
* @param inst The return instruction. bc can return void, and we need to know
* if it is.
*/
-static void bc_program_return(BcProgram *p, uchar inst) {
-
- BcResult *res;
- BcFunc *f;
- BcInstPtr *ip;
+static void
+bc_program_return(BcProgram* p, uchar inst)
+{
+ BcResult* res;
+ BcFunc* f;
+ BcInstPtr* ip;
size_t i, nresults;
// Get the instruction pointer.
@@ -1725,25 +1881,26 @@ static void bc_program_return(BcProgram *p, uchar inst) {
res = bc_program_prepResult(p);
// If we are returning normally...
- if (inst == BC_INST_RET) {
-
- BcNum *num;
- BcResult *operand;
+ if (inst == BC_INST_RET)
+ {
+ BcNum* num;
+ BcResult* operand;
// Prepare and copy the return value.
bc_program_operand(p, &operand, &num, 1);
- if (BC_PROG_STR(num)) {
-
+ if (BC_PROG_STR(num))
+ {
// We need to set this because otherwise, it will be a
// BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make
// it easier to do type checking.
res->t = BC_RESULT_STR;
+ // NOLINTNEXTLINE
memcpy(&res->d.n, num, sizeof(BcNum));
}
- else {
-
+ else
+ {
BC_SIG_LOCK;
bc_num_createCopy(&res->d.n, num);
@@ -1751,8 +1908,8 @@ static void bc_program_return(BcProgram *p, uchar inst) {
}
// Void is easy; set the result.
else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
- else {
-
+ else
+ {
BC_SIG_LOCK;
// If we get here, the instruction is for returning a zero, so do that.
@@ -1762,14 +1919,16 @@ static void bc_program_return(BcProgram *p, uchar inst) {
BC_SIG_MAYUNLOCK;
// We need to pop items off of the stacks of arguments and autos as well.
- for (i = 0; i < f->autos.len; ++i) {
-
- BcAuto *a = bc_vec_item(&f->autos, i);
- BcVec *v = bc_program_vec(p, a->idx, a->type);
+ for (i = 0; i < f->autos.len; ++i)
+ {
+ BcAuto* a = bc_vec_item(&f->autos, i);
+ BcVec* v = bc_program_vec(p, a->idx, a->type);
bc_vec_pop(v);
}
+ BC_SIG_LOCK;
+
// When we retire, pop all of the unused results.
bc_program_retire(p, 1, nresults);
@@ -1778,6 +1937,8 @@ static void bc_program_return(BcProgram *p, uchar inst) {
// Pop the stack. This is what causes the function to actually "return."
bc_vec_pop(&p->stack);
+
+ BC_SIG_UNLOCK;
}
#endif // BC_ENABLED
@@ -1786,23 +1947,27 @@ static void bc_program_return(BcProgram *p, uchar inst) {
* @param p The program.
* @param inst The builtin to execute.
*/
-static void bc_program_builtin(BcProgram *p, uchar inst) {
-
- BcResult *opd, *res;
- BcNum *num;
+static void
+bc_program_builtin(BcProgram* p, uchar inst)
+{
+ BcResult* opd;
+ BcResult* res;
+ BcNum* num;
bool len = (inst == BC_INST_LENGTH);
// Ensure we have a valid builtin.
#if BC_ENABLE_EXTRA_MATH
assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
#else // BC_ENABLE_EXTRA_MATH
- assert(inst >= BC_INST_LENGTH && inst <= BC_INST_ABS);
+ assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
#endif // BC_ENABLE_EXTRA_MATH
#ifndef BC_PROG_NO_STACK_CHECK
// Check stack for dc.
if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
#endif // BC_PROG_NO_STACK_CHECK
assert(BC_PROG_STACK(&p->results, 1));
@@ -1815,15 +1980,18 @@ static void bc_program_builtin(BcProgram *p, uchar inst) {
// We need to ensure that strings and arrays aren't passed to most builtins.
// The scale function can take strings in dc.
- if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC))
+ if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
+ inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
+ {
bc_program_type_num(opd, num);
+ }
// Square root is easy.
if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
// Absolute value is easy.
- else if (inst == BC_INST_ABS) {
-
+ else if (inst == BC_INST_ABS)
+ {
BC_SIG_LOCK;
bc_num_createCopy(&res->d.n, num);
@@ -1832,10 +2000,34 @@ static void bc_program_builtin(BcProgram *p, uchar inst) {
BC_NUM_NEG_CLR_NP(res->d.n);
}
+
+ // Testing for number or string is easy.
+ else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
+ {
+ bool cond;
+ bool is_str;
+
+ BC_SIG_LOCK;
+
+ bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
+
+ BC_SIG_UNLOCK;
+
+ // Test if the number is a string.
+ is_str = BC_PROG_STR(num);
+
+ // This confusing condition simply means that the instruction must be
+ // true if is_str is, or it must be false if is_str is. Otherwise, the
+ // returned value is false (0).
+ cond = ((inst == BC_INST_IS_STRING) == is_str);
+ if (cond) bc_num_one(&res->d.n);
+ }
+
#if BC_ENABLE_EXTRA_MATH
- // irand() is easy.
- else if (inst == BC_INST_IRAND) {
+ // irand() is easy.
+ else if (inst == BC_INST_IRAND)
+ {
BC_SIG_LOCK;
bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num));
@@ -1844,39 +2036,45 @@ static void bc_program_builtin(BcProgram *p, uchar inst) {
bc_num_irand(num, &res->d.n, &p->rng);
}
+
#endif // BC_ENABLE_EXTRA_MATH
// Everything else is...not easy.
- else {
-
+ else
+ {
BcBigDig val = 0;
// Well, scale() is easy, but length() is not.
- if (len) {
-
+ if (len)
+ {
// If we are bc and we have an array...
- if (opd->t == BC_RESULT_ARRAY) {
-
+ if (opd->t == BC_RESULT_ARRAY)
+ {
// Yes, this is one place where we need to cast the number from
// bc_program_num() to a vector.
- BcVec *v = (BcVec*) num;
+ BcVec* v = (BcVec*) num;
+
+ // XXX: If this is changed, you should also change the similar
+ // code in bc_program_asciify().
#if BC_ENABLED
// Dereference the array, if necessary.
if (BC_IS_BC && v->size == sizeof(uchar))
+ {
v = bc_program_dereference(p, v);
+ }
#endif // BC_ENABLED
assert(v->size == sizeof(BcNum));
val = (BcBigDig) v->len;
}
- else {
-
+ else
+ {
// If the item is a string...
- if (!BC_PROG_NUM(opd, num)) {
-
- char *str;
+ if (!BC_PROG_NUM(opd, num))
+ {
+ char* str;
// Get the string, then get the length.
str = bc_program_string(p, num);
@@ -1892,7 +2090,9 @@ static void bc_program_builtin(BcProgram *p, uchar inst) {
// Like I said; scale() is actually easy. It just also needs the integer
// conversion that length() does.
else if (BC_IS_BC || BC_PROG_NUM(opd, num))
+ {
val = (BcBigDig) bc_num_scale(num);
+ }
BC_SIG_LOCK;
@@ -1909,10 +2109,15 @@ static void bc_program_builtin(BcProgram *p, uchar inst) {
* Executes a divmod.
* @param p The program.
*/
-static void bc_program_divmod(BcProgram *p) {
-
- BcResult *opd1, *opd2, *res, *res2;
- BcNum *n1, *n2;
+static void
+bc_program_divmod(BcProgram* p)
+{
+ BcResult* opd1;
+ BcResult* opd2;
+ BcResult* res;
+ BcResult* res2;
+ BcNum* n1;
+ BcNum* n2;
size_t req;
// We grow first to avoid pointer invalidation.
@@ -1946,16 +2151,24 @@ static void bc_program_divmod(BcProgram *p) {
* Executes modular exponentiation.
* @param p The program.
*/
-static void bc_program_modexp(BcProgram *p) {
-
- BcResult *r1, *r2, *r3, *res;
- BcNum *n1, *n2, *n3;
+static void
+bc_program_modexp(BcProgram* p)
+{
+ BcResult* r1;
+ BcResult* r2;
+ BcResult* r3;
+ BcResult* res;
+ BcNum* n1;
+ BcNum* n2;
+ BcNum* n3;
#if DC_ENABLED
// Check the stack.
if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
#endif // DC_ENABLED
@@ -1973,7 +2186,9 @@ static void bc_program_modexp(BcProgram *p) {
// Make sure that the values have their pointers updated, if necessary.
// Only array elements are possible because this is dc.
if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
+ {
n1 = bc_program_num(p, r1);
+ }
BC_SIG_LOCK;
@@ -1991,58 +2206,40 @@ static void bc_program_modexp(BcProgram *p) {
* @param p The program.
* @param n The number to asciify.
*/
-static uchar bc_program_asciifyNum(BcProgram *p, BcNum *n) {
-
- BcNum num;
- BcBigDig val;
-
-#ifndef NDEBUG
- // This is entirely to satisfy a useless scan-build error.
- val = 0;
-#endif // NDEBUG
-
- bc_num_clear(&num);
-
- BC_SETJMP(num_err);
-
- BC_SIG_LOCK;
-
- bc_num_createCopy(&num, n);
-
- BC_SIG_UNLOCK;
+static uchar
+bc_program_asciifyNum(BcProgram* p, BcNum* n)
+{
+ bc_num_copy(&p->asciify, n);
// We want to clear the scale and sign for easy mod later.
- bc_num_truncate(&num, num.scale);
- BC_NUM_NEG_CLR_NP(num);
+ bc_num_truncate(&p->asciify, p->asciify.scale);
+ BC_NUM_NEG_CLR(&p->asciify);
// This is guaranteed to not have a divide by 0
// because strmb is equal to 256.
- bc_num_mod(&num, &p->strmb, &num, 0);
+ bc_num_mod(&p->asciify, &p->strmb, &p->asciify, 0);
// This is also guaranteed to not error because num is in the range
// [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
// it is not negative.
- val = bc_num_bigdig2(&num);
-
-num_err:
- BC_SIG_MAYLOCK;
- bc_num_free(&num);
- BC_LONGJMP_CONT;
- return (uchar) val;
+ return (uchar) bc_num_bigdig2(&p->asciify);
}
/**
- * Executes the "asciify" command in dc.
- * @param p The program.
- * @param fidx The index of the current function.
+ * Executes the "asciify" command in bc and dc.
+ * @param p The program.
*/
-static void bc_program_asciify(BcProgram *p, size_t fidx) {
-
+static void
+bc_program_asciify(BcProgram* p)
+{
BcResult *r, res;
- BcNum *n;
- char str[2], *str2;
+ BcNum* n;
uchar c;
size_t idx;
+#if BC_ENABLED
+ // This is in the outer scope because it has to be freed after a jump.
+ char* temp_str;
+#endif // BC_ENABLED
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
@@ -2053,44 +2250,109 @@ static void bc_program_asciify(BcProgram *p, size_t fidx) {
bc_program_operand(p, &r, &n, 0);
assert(n != NULL);
+ assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
- // Asciify.
- if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
- else {
+#if BC_ENABLED
+ // Handle arrays in bc specially.
+ if (r->t == BC_RESULT_ARRAY)
+ {
+ // Yes, this is one place where we need to cast the number from
+ // bc_program_num() to a vector.
+ BcVec* v = (BcVec*) n;
+ size_t i;
- // Get the string itself, then the first character.
- str2 = bc_program_string(p, n);
- c = (uchar) str2[0];
+ // XXX: If this is changed, you should also change the similar code in
+ // bc_program_builtin().
+
+ // Dereference the array, if necessary.
+ if (v->size == sizeof(uchar))
+ {
+ v = bc_program_dereference(p, v);
+ }
+
+ assert(v->size == sizeof(BcNum));
+
+ // Allocate the string and set the jump for it.
+ BC_SIG_LOCK;
+ temp_str = bc_vm_malloc(v->len + 1);
+ BC_SETJMP_LOCKED(vm, exit);
+ BC_SIG_UNLOCK;
+
+ // Convert the array.
+ for (i = 0; i < v->len; ++i)
+ {
+ BcNum* num = (BcNum*) bc_vec_item(v, i);
+
+ if (BC_PROG_STR(num))
+ {
+ temp_str[i] = (bc_program_string(p, num))[0];
+ }
+ else
+ {
+ temp_str[i] = (char) bc_program_asciifyNum(p, num);
+ }
+ }
+
+ temp_str[v->len] = '\0';
+
+ // Store the string in the slab and map, and free the temp string.
+ BC_SIG_LOCK;
+ idx = bc_program_addString(p, temp_str);
+ free(temp_str);
+ BC_UNSETJMP(vm);
+ BC_SIG_UNLOCK;
}
+ else
+#endif // BC_ENABLED
+ {
+ char str[2];
+ char* str2;
- // Fill the resulting string.
- str[0] = (char) c;
- str[1] = '\0';
+ // Asciify.
+ if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
+ else
+ {
+ // Get the string itself, then the first character.
+ str2 = bc_program_string(p, n);
+ c = (uchar) str2[0];
+ }
- // Add the string to the data structures.
- BC_SIG_LOCK;
- idx = bc_program_addString(p, str, fidx);
- BC_SIG_UNLOCK;
+ // Fill the resulting string.
+ str[0] = (char) c;
+ str[1] = '\0';
+
+ // Add the string to the data structures.
+ BC_SIG_LOCK;
+ idx = bc_program_addString(p, str);
+ BC_SIG_UNLOCK;
+ }
// Set the result
res.t = BC_RESULT_STR;
bc_num_clear(&res.d.n);
- res.d.n.rdx = fidx;
res.d.n.scale = idx;
// Pop and push.
bc_vec_pop(&p->results);
bc_vec_push(&p->results, &res);
+
+ return;
+
+#if BC_ENABLED
+exit:
+ free(temp_str);
+#endif // BC_ENABLED
}
/**
* Streams a number or a string to stdout.
* @param p The program.
*/
-static void bc_program_printStream(BcProgram *p) {
-
- BcResult *r;
- BcNum *n;
+static void
+bc_program_printStream(BcProgram* p)
+{
+ BcResult* r;
+ BcNum* n;
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
@@ -2119,11 +2381,12 @@ static void bc_program_printStream(BcProgram *p) {
* @param bgn An in/out parameter; the start of the index in the bytecode
* vector, and will be updated to point after the index on return.
*/
-static void bc_program_regStackLen(BcProgram *p, const char *restrict code,
- size_t *restrict bgn)
+static void
+bc_program_regStackLen(BcProgram* p, const char* restrict code,
+ size_t* restrict bgn)
{
size_t idx = bc_program_index(code, bgn);
- BcVec *v = bc_program_vec(p, idx, BC_TYPE_VAR);
+ BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR);
bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP);
}
@@ -2132,7 +2395,9 @@ static void bc_program_regStackLen(BcProgram *p, const char *restrict code,
* Pushes the length of the results stack onto the results stack.
* @param p The program.
*/
-static void bc_program_stackLen(BcProgram *p) {
+static void
+bc_program_stackLen(BcProgram* p)
+{
bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
}
@@ -2143,10 +2408,11 @@ static void bc_program_stackLen(BcProgram *p) {
* 2, and one to pop the amount equal to the number at the top of
* the results stack.
*/
-static void bc_program_nquit(BcProgram *p, uchar inst) {
-
- BcResult *opnd;
- BcNum *num;
+static void
+bc_program_nquit(BcProgram* p, uchar inst)
+{
+ BcResult* opnd;
+ BcNum* num;
BcBigDig val;
size_t i;
@@ -2155,8 +2421,8 @@ static void bc_program_nquit(BcProgram *p, uchar inst) {
// Get the number of executions to pop.
if (inst == BC_INST_QUIT) val = 2;
- else {
-
+ else
+ {
bc_program_prep(p, &opnd, &num, 0);
val = bc_num_bigdig(num);
@@ -2164,8 +2430,8 @@ static void bc_program_nquit(BcProgram *p, uchar inst) {
}
// Loop over the tail call stack and adjust the quit value appropriately.
- for (i = 0; val && i < p->tail_calls.len; ++i) {
-
+ for (i = 0; val && i < p->tail_calls.len; ++i)
+ {
// Get the number of tail calls for this one.
size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
@@ -2175,17 +2441,21 @@ static void bc_program_nquit(BcProgram *p, uchar inst) {
}
// If we don't have enough executions, just quit.
- if (i == p->stack.len) {
- vm.status = BC_STATUS_QUIT;
+ if (i == p->stack.len)
+ {
+ vm->status = BC_STATUS_QUIT;
BC_JMP;
}
- else {
+ else
+ {
// We can always pop the last item we reached on the tail call stack
// because these are for tail calls. That means that any executions that
// we would not have quit in that position on the stack would have quit
// anyway.
+ BC_SIG_LOCK;
bc_vec_npop(&p->stack, i);
bc_vec_npop(&p->tail_calls, i);
+ BC_SIG_UNLOCK;
}
}
@@ -2193,14 +2463,17 @@ static void bc_program_nquit(BcProgram *p, uchar inst) {
* Pushes the depth of the execution stack onto the stack.
* @param p The program.
*/
-static void bc_program_execStackLen(BcProgram *p) {
-
+static void
+bc_program_execStackLen(BcProgram* p)
+{
size_t i, amt, len = p->tail_calls.len;
amt = len;
for (i = 0; i < len; ++i)
+ {
amt += *((size_t*) bc_vec_item(&p->tail_calls, i));
+ }
bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP);
}
@@ -2214,15 +2487,16 @@ static void bc_program_execStackLen(BcProgram *p) {
* @param cond True if the execution is conditional, false otherwise.
* @param len The number of bytes in the bytecode vector.
*/
-static void bc_program_execStr(BcProgram *p, const char *restrict code,
- size_t *restrict bgn, bool cond, size_t len)
+static void
+bc_program_execStr(BcProgram* p, const char* restrict code,
+ size_t* restrict bgn, bool cond, size_t len)
{
- BcResult *r;
- char *str;
- BcFunc *f;
+ BcResult* r;
+ char* str;
+ BcFunc* f;
BcInstPtr ip;
size_t fidx;
- BcNum *n;
+ BcNum* n;
assert(p->stack.len == p->tail_calls.len);
@@ -2235,10 +2509,14 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code,
bc_program_operand(p, &r, &n, 0);
// If execution is conditional...
- if (cond) {
-
+ if (cond)
+ {
bool exec;
- size_t idx, then_idx, else_idx;
+ size_t then_idx;
+ // These are volatile to quiet warnings on GCC about clobbering with
+ // longjmp().
+ volatile size_t else_idx;
+ volatile size_t idx;
// Get the index of the "then" var and "else" var.
then_idx = bc_program_index(code, bgn);
@@ -2250,23 +2528,25 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code,
idx = exec ? then_idx : else_idx;
BC_SIG_LOCK;
- BC_SETJMP_LOCKED(exit);
+ BC_SETJMP_LOCKED(vm, exit);
// If we are supposed to execute, execute. If else_idx == SIZE_MAX, that
// means there was no else clause, so if execute is false and else does
// not exist, we don't execute. The goto skips all of the setup for the
// execution.
if (exec || (else_idx != SIZE_MAX))
+ {
n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
+ }
else goto exit;
if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE);
- BC_UNSETJMP;
+ BC_UNSETJMP(vm);
BC_SIG_UNLOCK;
}
- else {
-
+ else
+ {
// In non-conditional situations, only the top of stack can be executed,
// and in those cases, variables are not allowed to be "on the stack";
// they are only put on the stack to be assigned to.
@@ -2287,39 +2567,39 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code,
f = bc_vec_item(&p->fns, fidx);
// If the function has not been parsed yet...
- if (!f->code.len) {
-
+ if (!f->code.len)
+ {
BC_SIG_LOCK;
- if (!BC_PARSE_IS_INITED(&vm.read_prs, p)) {
-
- bc_parse_init(&vm.read_prs, p, fidx);
+ if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
+ {
+ bc_parse_init(&vm->read_prs, p, fidx);
// Initialize this too because bc_vm_shutdown() expects them to be
// initialized togther.
- bc_vec_init(&vm.read_buf, sizeof(char), BC_DTOR_NONE);
+ bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
}
// This needs to be updated because the parser could have been used
// somewhere else
- else bc_parse_updateFunc(&vm.read_prs, fidx);
+ else bc_parse_updateFunc(&vm->read_prs, fidx);
- bc_lex_file(&vm.read_prs.l, vm.file);
+ bc_lex_file(&vm->read_prs.l, vm->file);
- BC_SETJMP_LOCKED(err);
+ BC_SETJMP_LOCKED(vm, err);
BC_SIG_UNLOCK;
- // Parse.
- bc_parse_text(&vm.read_prs, str, false);
- vm.expr(&vm.read_prs, BC_PARSE_NOCALL);
+ // Parse. Only one expression is needed, so stdin isn't used.
+ bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
BC_SIG_LOCK;
+ vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
- BC_UNSETJMP;
+ BC_UNSETJMP(vm);
// We can just assert this here because
// dc should parse everything until EOF.
- assert(vm.read_prs.l.t == BC_LEX_EOF);
+ assert(vm->read_prs.l.t == BC_LEX_EOF);
BC_SIG_UNLOCK;
}
@@ -2329,15 +2609,17 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code,
ip.len = p->results.len;
ip.func = fidx;
+ BC_SIG_LOCK;
+
// Pop the operand.
bc_vec_pop(&p->results);
// Tail call processing. This condition means that there is more on the
// execution stack, and we are at the end of the bytecode vector, and the
// last instruction is just a BC_INST_POP_EXEC, which would return.
- if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC) {
-
- size_t *call_ptr = bc_vec_top(&p->tail_calls);
+ if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC)
+ {
+ size_t* call_ptr = bc_vec_top(&p->tail_calls);
// Add one to the tail call.
*call_ptr += 1;
@@ -2352,6 +2634,8 @@ static void bc_program_execStr(BcProgram *p, const char *restrict code,
// Push the new function onto the execution stack and return.
bc_vec_push(&p->stack, &ip);
+ BC_SIG_UNLOCK;
+
return;
err:
@@ -2364,19 +2648,22 @@ err:
exit:
bc_vec_pop(&p->results);
- BC_LONGJMP_CONT;
+ BC_LONGJMP_CONT(vm);
}
/**
* Prints every item on the results stack, one per line.
* @param p The program.
*/
-static void bc_program_printStack(BcProgram *p) {
-
+static void
+bc_program_printStack(BcProgram* p)
+{
size_t idx;
for (idx = 0; idx < p->results.len; ++idx)
+ {
bc_program_print(p, BC_INST_PRINT, idx);
+ }
}
#endif // DC_ENABLED
@@ -2385,8 +2672,9 @@ static void bc_program_printStack(BcProgram *p) {
* @param p The program.
* @param inst Which global to push, as an instruction.
*/
-static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
-
+static void
+bc_program_pushGlobal(BcProgram* p, uchar inst)
+{
BcResultType t;
// Make sure the instruction is valid.
@@ -2402,17 +2690,35 @@ static void bc_program_pushGlobal(BcProgram *p, uchar inst) {
* @param p The program.
* @param inst Which global setting to push, as an instruction.
*/
-static void bc_program_globalSetting(BcProgram *p, uchar inst) {
-
+static void
+bc_program_globalSetting(BcProgram* p, uchar inst)
+{
BcBigDig val;
// Make sure the instruction is valid.
+#if DC_ENABLED
+ assert((inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO) ||
+ (BC_IS_DC && inst == BC_INST_EXTENDED_REGISTERS));
+#else // DC_ENABLED
assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO);
+#endif // DC_ENABLED
- if (inst == BC_INST_LINE_LENGTH) val = (BcBigDig) vm.line_len;
+ if (inst == BC_INST_LINE_LENGTH)
+ {
+ val = (BcBigDig) vm->line_len;
+ }
#if BC_ENABLED
- else if (inst == BC_INST_GLOBAL_STACKS) val = (BC_G != 0);
+ else if (inst == BC_INST_GLOBAL_STACKS)
+ {
+ val = (BC_G != 0);
+ }
#endif // BC_ENABLED
+#if DC_ENABLED
+ else if (inst == BC_INST_EXTENDED_REGISTERS)
+ {
+ val = (DC_X != 0);
+ }
+#endif // DC_ENABLED
else val = (BC_Z != 0);
// Push the global.
@@ -2425,9 +2731,10 @@ static void bc_program_globalSetting(BcProgram *p, uchar inst) {
* Pushes the value of seed on the stack.
* @param p The program.
*/
-static void bc_program_pushSeed(BcProgram *p) {
-
- BcResult *res;
+static void
+bc_program_pushSeed(BcProgram* p)
+{
+ BcResult* res;
res = bc_program_prepResult(p);
res->t = BC_RESULT_SEED;
@@ -2450,27 +2757,22 @@ static void bc_program_pushSeed(BcProgram *p) {
* @param p The program.
* @param id_ptr The ID of the function as inserted into the map.
*/
-static void bc_program_addFunc(BcProgram *p, BcId *id_ptr) {
-
- BcInstPtr *ip;
- BcFunc *f;
+static void
+bc_program_addFunc(BcProgram* p, BcId* id_ptr)
+{
+ BcFunc* f;
BC_SIG_ASSERT_LOCKED;
// Push and init.
f = bc_vec_pushEmpty(&p->fns);
bc_func_init(f, id_ptr->name);
-
- // This is to make sure pointers are updated if the array was moved.
- if (p->stack.len) {
- ip = bc_vec_top(&p->stack);
- bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, ip->func));
- }
}
-size_t bc_program_insertFunc(BcProgram *p, const char *name) {
-
- BcId *id_ptr;
+size_t
+bc_program_insertFunc(BcProgram* p, const char* name)
+{
+ BcId* id_ptr;
bool new;
size_t idx;
@@ -2484,15 +2786,16 @@ size_t bc_program_insertFunc(BcProgram *p, const char *name) {
idx = id_ptr->idx;
// If the function is new...
- if (new) {
-
+ if (new)
+ {
// Add the function to the fns array.
bc_program_addFunc(p, id_ptr);
}
#if BC_ENABLED
// bc has to reset the function because it's about to be redefined.
- else if (BC_IS_BC) {
- BcFunc *func = bc_vec_item(&p->fns, idx);
+ else if (BC_IS_BC)
+ {
+ BcFunc* func = bc_vec_item(&p->fns, idx);
bc_func_reset(func);
}
#endif // BC_ENABLED
@@ -2500,17 +2803,25 @@ size_t bc_program_insertFunc(BcProgram *p, const char *name) {
return idx;
}
-#ifndef NDEBUG
-void bc_program_free(BcProgram *p) {
-
+#if BC_DEBUG
+void
+bc_program_free(BcProgram* p)
+{
+#if BC_ENABLED
size_t i;
+#endif // BC_ENABLED
BC_SIG_ASSERT_LOCKED;
assert(p != NULL);
+#if BC_ENABLED
// Free the globals stacks.
- for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) bc_vec_free(p->globals_v + i);
+ for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
+ {
+ bc_vec_free(p->globals_v + i);
+ }
+#endif // BC_ENABLED
bc_vec_free(&p->fns);
bc_vec_free(&p->fn_map);
@@ -2520,6 +2831,12 @@ void bc_program_free(BcProgram *p) {
bc_vec_free(&p->arr_map);
bc_vec_free(&p->results);
bc_vec_free(&p->stack);
+ bc_vec_free(&p->consts);
+ bc_vec_free(&p->const_map);
+ bc_vec_free(&p->strs);
+ bc_vec_free(&p->str_map);
+
+ bc_num_free(&p->asciify);
#if BC_ENABLED
if (BC_IS_BC) bc_num_free(&p->last);
@@ -2533,10 +2850,11 @@ void bc_program_free(BcProgram *p) {
if (BC_IS_DC) bc_vec_free(&p->tail_calls);
#endif // DC_ENABLED
}
-#endif // NDEBUG
-
-void bc_program_init(BcProgram *p) {
+#endif // BC_DEBUG
+void
+bc_program_init(BcProgram* p)
+{
BcInstPtr ip;
size_t i;
@@ -2545,23 +2863,26 @@ void bc_program_init(BcProgram *p) {
assert(p != NULL);
// We want this clear.
+ // NOLINTNEXTLINE
memset(&ip, 0, sizeof(BcInstPtr));
// Setup the globals stacks and the current values.
- for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i) {
-
+ for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
+ {
BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
+#if BC_ENABLED
bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE);
bc_vec_push(p->globals_v + i, &val);
+#endif // BC_ENABLED
p->globals[i] = val;
}
#if DC_ENABLED
// dc-only setup.
- if (BC_IS_DC) {
-
+ if (BC_IS_DC)
+ {
bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE);
// We want an item for the main function on the tail call stack.
@@ -2573,6 +2894,8 @@ void bc_program_init(BcProgram *p) {
bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE);
+ bc_num_init(&p->asciify, BC_NUM_DEF_SIZE);
+
#if BC_ENABLE_EXTRA_MATH
// We need to initialize srand() just in case /dev/urandom and /dev/random
// are not available.
@@ -2584,11 +2907,11 @@ void bc_program_init(BcProgram *p) {
if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
#endif // BC_ENABLED
-#ifndef NDEBUG
+#if BC_DEBUG
bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC);
-#else // NDEBUG
+#else // BC_DEBUG
bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE);
-#endif // NDEBUG
+#endif // BC_DEBUG
bc_map_init(&p->fn_map);
bc_program_insertFunc(p, bc_func_main);
bc_program_insertFunc(p, bc_func_read);
@@ -2605,16 +2928,52 @@ void bc_program_init(BcProgram *p) {
bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
bc_vec_push(&p->stack, &ip);
- // Make sure the pointers are properly set up.
- bc_program_setVecs(p, (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN));
-
- assert(p->consts != NULL && p->strs != NULL);
+ bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
+ bc_map_init(&p->const_map);
+ bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
+ bc_map_init(&p->str_map);
}
-void bc_program_reset(BcProgram *p) {
+void
+bc_program_printStackTrace(BcProgram* p)
+{
+ size_t i, max_digits;
+
+ max_digits = bc_vm_numDigits(p->stack.len - 1);
+
+ for (i = 0; i < p->stack.len; ++i)
+ {
+ BcInstPtr* ip = bc_vec_item_rev(&p->stack, i);
+ BcFunc* f = bc_vec_item(&p->fns, ip->func);
+ size_t j, digits;
- BcFunc *f;
- BcInstPtr *ip;
+ digits = bc_vm_numDigits(i);
+
+ bc_file_puts(&vm->ferr, bc_flush_none, " ");
+
+ for (j = 0; j < max_digits - digits; ++j)
+ {
+ bc_file_putchar(&vm->ferr, bc_flush_none, ' ');
+ }
+
+ bc_file_printf(&vm->ferr, "%zu: %s", i, f->name);
+
+#if BC_ENABLED
+ if (BC_IS_BC && ip->func != BC_PROG_MAIN && ip->func != BC_PROG_READ)
+ {
+ bc_file_puts(&vm->ferr, bc_flush_none, "()");
+ }
+#endif // BC_ENABLED
+
+ bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
+ }
+}
+
+void
+bc_program_reset(BcProgram* p)
+{
+ BcFunc* f;
+ BcInstPtr* ip;
BC_SIG_ASSERT_LOCKED;
@@ -2622,6 +2981,11 @@ void bc_program_reset(BcProgram *p) {
bc_vec_npop(&p->stack, p->stack.len - 1);
bc_vec_popAll(&p->results);
+#if DC_ENABLED
+ // We need to pop tail calls too.
+ if (BC_IS_DC) bc_vec_npop(&p->tail_calls, p->tail_calls.len - 1);
+#endif // DC_ENABLED
+
#if BC_ENABLED
// Clear the globals' stacks.
if (BC_G) bc_program_popGlobals(p, true);
@@ -2633,69 +2997,96 @@ void bc_program_reset(BcProgram *p) {
// Reset the instruction pointer.
ip = bc_vec_top(&p->stack);
- bc_program_setVecs(p, f);
+ // NOLINTNEXTLINE
memset(ip, 0, sizeof(BcInstPtr));
- // Write the ready message for a signal, and clear the signal.
- if (vm.sig) {
- bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
- bc_program_ready_msg_len);
- bc_file_flush(&vm.fout, bc_flush_err);
- vm.sig = 0;
+ if (BC_SIG_INTERRUPT(vm))
+ {
+ // Write the ready message for a signal.
+ bc_file_printf(&vm->fout, "%s", bc_program_ready_msg);
+ bc_file_flush(&vm->fout, bc_flush_err);
}
-}
-void bc_program_exec(BcProgram *p) {
+ // Clear the signal.
+ vm->sig = 0;
+}
+void
+bc_program_exec(BcProgram* p)
+{
size_t idx;
- BcResult r, *ptr;
- BcInstPtr *ip;
- BcFunc *func;
- char *code;
+ BcResult r;
+ BcResult* ptr;
+ BcInstPtr* ip;
+ BcFunc* func;
+ char* code;
bool cond = false;
uchar inst;
#if BC_ENABLED
- BcNum *num;
+ BcNum* num;
#endif // BC_ENABLED
#if !BC_HAS_COMPUTED_GOTO
-#ifndef NDEBUG
+#if BC_DEBUG
size_t jmp_bufs_len;
-#endif // NDEBUG
+#endif // BC_DEBUG
#endif // !BC_HAS_COMPUTED_GOTO
#if BC_HAS_COMPUTED_GOTO
+
+#if BC_GCC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif // BC_GCC
+
+#if BC_CLANG
+#pragma clang diagnostic ignored "-Wgnu-label-as-value"
+#endif // BC_CLANG
+
BC_PROG_LBLS;
BC_PROG_LBLS_ASSERT;
+#if BC_CLANG
+#pragma clang diagnostic warning "-Wgnu-label-as-value"
+#endif // BC_CLANG
+
+#if BC_GCC
+#pragma GCC diagnostic warning "-Wpedantic"
+#endif // BC_GCC
+
// BC_INST_INVALID is a marker for the end so that we don't have to have an
// execution loop.
func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN);
bc_vec_pushByte(&func->code, BC_INST_INVALID);
#endif // BC_HAS_COMPUTED_GOTO
+ BC_SETJMP(vm, end);
+
ip = bc_vec_top(&p->stack);
func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- // Ensure the pointers are correct.
- bc_program_setVecs(p, func);
-
#if !BC_HAS_COMPUTED_GOTO
-#ifndef NDEBUG
- jmp_bufs_len = vm.jmp_bufs.len;
-#endif // NDEBUG
+#if BC_DEBUG
+ jmp_bufs_len = vm->jmp_bufs.len;
+#endif // BC_DEBUG
// This loop is the heart of the execution engine. It *is* the engine. For
// computed goto, it is ignored.
while (ip->idx < func->code.len)
#endif // !BC_HAS_COMPUTED_GOTO
{
-
BC_SIG_ASSERT_NOT_LOCKED;
#if BC_HAS_COMPUTED_GOTO
+#if BC_GCC
+#pragma GCC diagnostic ignored "-Wpedantic"
+#endif // BC_GCC
+
+#if BC_CLANG
+#pragma clang diagnostic ignored "-Wgnu-label-as-value"
+#endif // BC_CLANG
+
BC_PROG_JUMP(inst, code, ip);
#else // BC_HAS_COMPUTED_GOTO
@@ -2706,19 +3097,20 @@ void bc_program_exec(BcProgram *p) {
#endif // BC_HAS_COMPUTED_GOTO
#if BC_DEBUG_CODE
- bc_file_printf(&vm.ferr, "inst: %s\n", bc_inst_names[inst]);
- bc_file_flush(&vm.ferr, bc_flush_none);
+ bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]);
+ bc_file_flush(&vm->ferr, bc_flush_none);
#endif // BC_DEBUG_CODE
#if !BC_HAS_COMPUTED_GOTO
switch (inst)
#endif // !BC_HAS_COMPUTED_GOTO
{
-
#if BC_ENABLED
// This just sets up the condition for the unconditional jump below,
// which checks the condition, if necessary.
+ // clang-format off
BC_PROG_LBL(BC_INST_JUMP_ZERO):
+ // clang-format on
{
bc_program_prep(p, &ptr, &num, 0);
@@ -2730,15 +3122,17 @@ void bc_program_exec(BcProgram *p) {
// Fallthrough.
BC_PROG_FALLTHROUGH
+ // clang-format off
BC_PROG_LBL(BC_INST_JUMP):
+ // clang-format on
{
idx = bc_program_index(code, &ip->idx);
// If a jump is required...
- if (inst == BC_INST_JUMP || cond) {
-
+ if (inst == BC_INST_JUMP || cond)
+ {
// Get the address to jump to.
- size_t *addr = bc_vec_item(&func->labels, idx);
+ size_t* addr = bc_vec_item(&func->labels, idx);
// If this fails, then the parser failed to set up the
// labels correctly.
@@ -2751,7 +3145,9 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_CALL):
+ // clang-format on
{
assert(BC_IS_BC);
@@ -2759,24 +3155,29 @@ void bc_program_exec(BcProgram *p) {
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_INC):
BC_PROG_LBL(BC_INST_DEC):
+ // clang-format on
{
bc_program_incdec(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_HALT):
+ // clang-format on
{
- vm.status = BC_STATUS_QUIT;
+ vm->status = BC_STATUS_QUIT;
// Just jump out. The jump series will take care of everything.
BC_JMP;
@@ -2784,23 +3185,27 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_RET):
BC_PROG_LBL(BC_INST_RET0):
BC_PROG_LBL(BC_INST_RET_VOID):
+ // clang-format on
{
bc_program_return(p, inst);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
#endif // BC_ENABLED
+ // clang-format off
BC_PROG_LBL(BC_INST_BOOL_OR):
BC_PROG_LBL(BC_INST_BOOL_AND):
BC_PROG_LBL(BC_INST_REL_EQ):
@@ -2809,157 +3214,193 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_LBL(BC_INST_REL_NE):
BC_PROG_LBL(BC_INST_REL_LT):
BC_PROG_LBL(BC_INST_REL_GT):
+ // clang-format on
{
bc_program_logical(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_READ):
+ // clang-format on
{
// We want to flush output before
// this in case there is a prompt.
- bc_file_flush(&vm.fout, bc_flush_save);
+ bc_file_flush(&vm->fout, bc_flush_save);
bc_program_read(p);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
#if BC_ENABLE_EXTRA_MATH
+ // clang-format off
BC_PROG_LBL(BC_INST_RAND):
+ // clang-format on
{
bc_program_rand(p);
BC_PROG_JUMP(inst, code, ip);
}
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format off
BC_PROG_LBL(BC_INST_MAXIBASE):
BC_PROG_LBL(BC_INST_MAXOBASE):
BC_PROG_LBL(BC_INST_MAXSCALE):
#if BC_ENABLE_EXTRA_MATH
BC_PROG_LBL(BC_INST_MAXRAND):
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format on
{
- BcBigDig dig = vm.maxes[inst - BC_INST_MAXIBASE];
+ BcBigDig dig = vm->maxes[inst - BC_INST_MAXIBASE];
bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_LINE_LENGTH):
#if BC_ENABLED
BC_PROG_LBL(BC_INST_GLOBAL_STACKS):
#endif // BC_ENABLED
+#if DC_ENABLED
+ BC_PROG_LBL(BC_INST_EXTENDED_REGISTERS):
+#endif // DC_ENABLE
BC_PROG_LBL(BC_INST_LEADING_ZERO):
+ // clang-format on
{
bc_program_globalSetting(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_VAR):
+ // clang-format on
{
bc_program_pushVar(p, code, &ip->idx, false, false);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_ARRAY_ELEM):
BC_PROG_LBL(BC_INST_ARRAY):
+ // clang-format on
{
bc_program_pushArray(p, code, &ip->idx, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_IBASE):
BC_PROG_LBL(BC_INST_SCALE):
BC_PROG_LBL(BC_INST_OBASE):
+ // clang-format on
{
bc_program_pushGlobal(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
#if BC_ENABLE_EXTRA_MATH
+ // clang-format off
BC_PROG_LBL(BC_INST_SEED):
+ // clang-format on
{
bc_program_pushSeed(p);
BC_PROG_JUMP(inst, code, ip);
}
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format off
BC_PROG_LBL(BC_INST_LENGTH):
BC_PROG_LBL(BC_INST_SCALE_FUNC):
BC_PROG_LBL(BC_INST_SQRT):
BC_PROG_LBL(BC_INST_ABS):
+ BC_PROG_LBL(BC_INST_IS_NUMBER):
+ BC_PROG_LBL(BC_INST_IS_STRING):
#if BC_ENABLE_EXTRA_MATH
BC_PROG_LBL(BC_INST_IRAND):
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format on
{
bc_program_builtin(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_ASCIIFY):
+ // clang-format on
{
- bc_program_asciify(p, ip->func);
+ bc_program_asciify(p);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_NUM):
+ // clang-format on
{
bc_program_const(p, code, &ip->idx);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_ZERO):
BC_PROG_LBL(BC_INST_ONE):
#if BC_ENABLED
BC_PROG_LBL(BC_INST_LAST):
#endif // BC_ENABLED
+ // clang-format on
{
r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
bc_vec_push(&p->results, &r);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_PRINT):
BC_PROG_LBL(BC_INST_PRINT_POP):
#if BC_ENABLED
BC_PROG_LBL(BC_INST_PRINT_STR):
#endif // BC_ENABLED
+ // clang-format on
{
bc_program_print(p, inst, 0);
// We want to flush right away to save the output for history,
// if history must preserve it when taking input.
- bc_file_flush(&vm.fout, bc_flush_save);
+ bc_file_flush(&vm->fout, bc_flush_save);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_STR):
+ // clang-format on
{
// Set up the result and push.
r.t = BC_RESULT_STR;
bc_num_clear(&r.d.n);
- r.d.n.rdx = bc_program_index(code, &ip->idx);
r.d.n.scale = bc_program_index(code, &ip->idx);
bc_vec_push(&p->results, &r);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_POWER):
BC_PROG_LBL(BC_INST_MULTIPLY):
BC_PROG_LBL(BC_INST_DIVIDE):
@@ -2971,21 +3412,25 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_LBL(BC_INST_LSHIFT):
BC_PROG_LBL(BC_INST_RSHIFT):
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format on
{
bc_program_op(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_NEG):
BC_PROG_LBL(BC_INST_BOOL_NOT):
#if BC_ENABLE_EXTRA_MATH
BC_PROG_LBL(BC_INST_TRUNC):
#endif // BC_ENABLE_EXTRA_MATH
+ // clang-format on
{
bc_program_unary(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
#if BC_ENABLED
BC_PROG_LBL(BC_INST_ASSIGN_POWER):
BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY):
@@ -3012,18 +3457,24 @@ void bc_program_exec(BcProgram *p) {
#endif // BC_ENABLE_EXTRA_MATH
#endif // BC_ENABLED
BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL):
+ // clang-format on
{
bc_program_assign(p, inst);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_POP):
+ // clang-format on
{
#ifndef BC_PROG_NO_STACK_CHECK
// dc must do a stack check, but bc does not.
- if (BC_IS_DC) {
+ if (BC_IS_DC)
+ {
if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
}
#endif // BC_PROG_NO_STACK_CHECK
@@ -3034,13 +3485,17 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_SWAP):
+ // clang-format on
{
- BcResult *ptr2;
+ BcResult* ptr2;
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
assert(BC_PROG_STACK(&p->results, 2));
@@ -3049,33 +3504,44 @@ void bc_program_exec(BcProgram *p) {
ptr2 = bc_vec_item_rev(&p->results, 1);
// Swap. It's just easiest to do it this way.
+ // NOLINTNEXTLINE
memcpy(&r, ptr, sizeof(BcResult));
+ // NOLINTNEXTLINE
memcpy(ptr, ptr2, sizeof(BcResult));
+ // NOLINTNEXTLINE
memcpy(ptr2, &r, sizeof(BcResult));
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_MODEXP):
+ // clang-format on
{
bc_program_modexp(p);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_DIVMOD):
+ // clang-format on
{
bc_program_divmod(p);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_PRINT_STREAM):
+ // clang-format on
{
bc_program_printStream(p);
BC_PROG_JUMP(inst, code, ip);
}
#if DC_ENABLED
+ // clang-format off
BC_PROG_LBL(BC_INST_POP_EXEC):
+ // clang-format on
{
// If this fails, the dc parser got something wrong.
assert(BC_PROG_STACK(&p->stack, 2));
@@ -3086,16 +3552,19 @@ void bc_program_exec(BcProgram *p) {
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_EXECUTE):
BC_PROG_LBL(BC_INST_EXEC_COND):
+ // clang-format on
{
cond = (inst == BC_INST_EXEC_COND);
@@ -3103,43 +3572,56 @@ void bc_program_exec(BcProgram *p) {
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_PRINT_STACK):
+ // clang-format on
{
bc_program_printStack(p);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_CLEAR_STACK):
+ // clang-format on
{
bc_vec_popAll(&p->results);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_REG_STACK_LEN):
+ // clang-format on
{
bc_program_regStackLen(p, code, &ip->idx);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_STACK_LEN):
+ // clang-format on
{
bc_program_stackLen(p);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_DUPLICATE):
+ // clang-format on
{
// Check the stack.
if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
+ {
bc_err(BC_ERR_EXEC_STACK);
+ }
assert(BC_PROG_STACK(&p->results, 1));
@@ -3157,37 +3639,46 @@ void bc_program_exec(BcProgram *p) {
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_LOAD):
BC_PROG_LBL(BC_INST_PUSH_VAR):
+ // clang-format on
{
bool copy = (inst == BC_INST_LOAD);
bc_program_pushVar(p, code, &ip->idx, true, copy);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_PUSH_TO_VAR):
+ // clang-format on
{
idx = bc_program_index(code, &ip->idx);
- bc_program_copyToVar(p, idx, BC_TYPE_VAR, true);
+ bc_program_copyToVar(p, idx, BC_TYPE_VAR);
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_QUIT):
BC_PROG_LBL(BC_INST_NQUIT):
+ // clang-format on
{
bc_program_nquit(p, inst);
// Because we changed the execution stack and where we are
// executing, we have to update all of this.
+ BC_SIG_LOCK;
ip = bc_vec_top(&p->stack);
func = bc_vec_item(&p->fns, ip->func);
code = func->code.v;
- bc_program_setVecs(p, func);
+ BC_SIG_UNLOCK;
BC_PROG_JUMP(inst, code, ip);
}
+ // clang-format off
BC_PROG_LBL(BC_INST_EXEC_STACK_LEN):
+ // clang-format on
{
bc_program_execStackLen(p);
BC_PROG_JUMP(inst, code, ip);
@@ -3195,47 +3686,86 @@ void bc_program_exec(BcProgram *p) {
#endif // DC_ENABLED
#if BC_HAS_COMPUTED_GOTO
+ // clang-format off
BC_PROG_LBL(BC_INST_INVALID):
+ // clang-format on
{
- return;
+ goto end;
}
#else // BC_HAS_COMPUTED_GOTO
default:
{
BC_UNREACHABLE
-#ifndef NDEBUG
+#if BC_DEBUG && !BC_CLANG
abort();
-#endif // NDEBUG
+#endif // BC_DEBUG && !BC_CLANG
}
#endif // BC_HAS_COMPUTED_GOTO
}
-#if !BC_HAS_COMPUTED_GOTO
-#ifndef NDEBUG
+#if BC_HAS_COMPUTED_GOTO
+
+#if BC_CLANG
+#pragma clang diagnostic warning "-Wgnu-label-as-value"
+#endif // BC_CLANG
+
+#if BC_GCC
+#pragma GCC diagnostic warning "-Wpedantic"
+#endif // BC_GCC
+
+#else // BC_HAS_COMPUTED_GOTO
+
+#if BC_DEBUG
// This is to allow me to use a debugger to see the last instruction,
// which will point to which function was the problem. But it's also a
// good smoke test for error handling changes.
- assert(jmp_bufs_len == vm.jmp_bufs.len);
-#endif // NDEBUG
-#endif // !BC_HAS_COMPUTED_GOTO
+ assert(jmp_bufs_len == vm->jmp_bufs.len);
+#endif // BC_DEBUG
+
+#endif // BC_HAS_COMPUTED_GOTO
}
+
+end:
+ BC_SIG_MAYLOCK;
+
+ // This is here just to print a stack trace on interrupts. This is for
+ // finding infinite loops.
+ if (BC_SIG_INTERRUPT(vm))
+ {
+ BcStatus s;
+
+ bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
+
+ bc_program_printStackTrace(p);
+
+ s = bc_file_flushErr(&vm->ferr, bc_flush_err);
+ if (BC_ERR(s != BC_STATUS_SUCCESS && vm->status == BC_STATUS_SUCCESS))
+ {
+ vm->status = (sig_atomic_t) s;
+ }
+ }
+
+ BC_LONGJMP_CONT(vm);
}
#if BC_DEBUG_CODE
#if BC_ENABLED && DC_ENABLED
-void bc_program_printStackDebug(BcProgram *p) {
- bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack ----------\n");
+void
+bc_program_printStackDebug(BcProgram* p)
+{
+ bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack ----------\n");
bc_program_printStack(p);
- bc_file_puts(&vm.fout, bc_flush_err, "-------------- Stack End ------\n");
+ bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack End ------\n");
}
-static void bc_program_printIndex(const char *restrict code,
- size_t *restrict bgn)
+static void
+bc_program_printIndex(const char* restrict code, size_t* restrict bgn)
{
uchar byte, i, bytes = (uchar) code[(*bgn)++];
ulong val = 0;
- for (byte = 1, i = 0; byte && i < bytes; ++i) {
+ for (byte = 1, i = 0; byte && i < bytes; ++i)
+ {
byte = (uchar) code[(*bgn)++];
if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
}
@@ -3243,24 +3773,26 @@ static void bc_program_printIndex(const char *restrict code,
bc_vm_printf(" (%lu) ", val);
}
-static void bc_program_printStr(const BcProgram *p, const char *restrict code,
- size_t *restrict bgn)
+static void
+bc_program_printStr(const BcProgram* p, const char* restrict code,
+ size_t* restrict bgn)
{
size_t idx = bc_program_index(code, bgn);
- char *s;
+ char* s;
- s = *((char**) bc_vec_item(p->strs, idx));
+ s = *((char**) bc_vec_item(&p->strs, idx));
bc_vm_printf(" (\"%s\") ", s);
}
-void bc_program_printInst(const BcProgram *p, const char *restrict code,
- size_t *restrict bgn)
+void
+bc_program_printInst(const BcProgram* p, const char* restrict code,
+ size_t* restrict bgn)
{
uchar inst = (uchar) code[(*bgn)++];
- bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1,
- bc_inst_names[inst], (unsigned long) inst);
+ bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, bc_inst_names[inst],
+ (unsigned long) inst);
if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
inst == BC_INST_ARRAY)
@@ -3268,9 +3800,10 @@ void bc_program_printInst(const BcProgram *p, const char *restrict code,
bc_program_printIndex(code, bgn);
}
else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
- else if (inst == BC_INST_NUM) {
+ else if (inst == BC_INST_NUM)
+ {
size_t idx = bc_program_index(code, bgn);
- BcConst *c = bc_vec_item(p->consts, idx);
+ BcConst* c = bc_vec_item(&p->consts, idx);
bc_vm_printf("(%s)", c->val);
}
else if (inst == BC_INST_CALL ||
@@ -3283,15 +3816,16 @@ void bc_program_printInst(const BcProgram *p, const char *restrict code,
bc_vm_putchar('\n', bc_flush_err);
}
-void bc_program_code(const BcProgram* p) {
-
- BcFunc *f;
- char *code;
+void
+bc_program_code(const BcProgram* p)
+{
+ BcFunc* f;
+ char* code;
BcInstPtr ip;
size_t i;
- for (i = 0; i < p->fns.len; ++i) {
-
+ for (i = 0; i < p->fns.len; ++i)
+ {
ip.idx = ip.len = 0;
ip.func = i;
@@ -3299,8 +3833,11 @@ void bc_program_code(const BcProgram* p) {
code = f->code.v;
bc_vm_printf("func[%zu]:\n", ip.func);
- while (ip.idx < f->code.len) bc_program_printInst(p, code, &ip.idx);
- bc_file_puts(&vm.fout, bc_flush_err, "\n\n");
+ while (ip.idx < f->code.len)
+ {
+ bc_program_printInst(p, code, &ip.idx);
+ }
+ bc_file_puts(&vm->fout, bc_flush_err, "\n\n");
}
}
#endif // BC_ENABLED && DC_ENABLED