vendor/bc: import version 6.2.2

This is a production release that fixes a bug.

The bug was that if an array element was used as a parameter, and then
a later parameter had the same name as the array whose element was
used, bc would grab the element from the new array parameter, not the
actual element from before the function call.
This commit is contained in:
Stefan Eßer 2023-01-28 21:08:43 +01:00
parent 3c2ba19f6b
commit 1a63323d17
8 changed files with 75 additions and 69 deletions

View File

@ -1,5 +1,14 @@
# News
## 6.2.2
This is a production release that fixes a bug.
The bug was that if an array element was used as a parameter, and then a later
parameter had the same name as the array whose element was used, `bc` would grab
the element from the new array parameter, not the actual element from before the
function call.
## 6.2.1
This is a production release with one bug fix for a memory bug in history.

View File

@ -352,6 +352,12 @@ typedef struct BcLoc
/// The index of the var or array.
size_t loc;
/// The index of the array or variable in the array stack. This is to
/// prevent a bug with getting the wrong array element or variable after a
/// function call. See the tests/bc/scripts/array.bc test for the array
/// case; the variable case is in various variable tests.
size_t stack_idx;
/// The index of the array element. Only used for array elements.
size_t idx;

View File

@ -220,20 +220,11 @@ typedef struct BcProgram
#if !BC_ENABLED
/// This define disappears the parameter last because for dc only, last is
/// always true.
#define bc_program_copyToVar(p, name, t, last) \
bc_program_copyToVar_impl(p, name, t)
/// Returns true if the calculator should pop after printing.
#define BC_PROGRAM_POP(pop) (pop)
#else // !BC_ENABLED
// This is here to quiet a compiler warning.
#define bc_program_copyToVar(p, name, t, last) \
bc_program_copyToVar_impl(p, name, t, last)
/// Returns true if the calculator should pop after printing.
#define BC_PROGRAM_POP(pop) (BC_IS_BC || (pop))

View File

@ -37,6 +37,6 @@
#define BC_VERSION_H
/// The current version.
#define VERSION 6.2.1
#define VERSION 6.2.2
#endif // BC_VERSION_H

View File

@ -346,7 +346,7 @@ bc_program_num(BcProgram* p, BcResult* r)
{
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
@ -376,8 +376,21 @@ 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;
}
@ -1181,18 +1194,12 @@ bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
/**
* 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)
bc_program_copyToVar(BcProgram* p, size_t idx, BcType t)
{
BcResult *ptr = NULL, r;
BcVec* vec;
@ -1217,13 +1224,6 @@ 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
@ -1265,19 +1265,8 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last)
if (BC_IS_BC)
{
BcVec* parent;
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);
@ -1297,8 +1286,6 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last)
// If this is true, then we need to construct a reference.
if (ref)
{
assert(parent->len >= (size_t) (!last + 1));
// Make sure the pointer was not invalidated.
vec = bc_program_vec(p, idx, t);
@ -1306,7 +1293,7 @@ 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.
@ -1600,18 +1587,22 @@ bc_program_pushVar(BcProgram* p, const char* restrict code,
{
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);
// 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.
@ -1674,10 +1665,17 @@ bc_program_pushArray(BcProgram* p, const char* restrict code,
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)
{
@ -1800,35 +1798,14 @@ bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn)
// Push the arguments onto the stacks of their respective parameters.
for (i = 0; i < nargs; ++i)
{
size_t j;
bool last = true;
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;
@ -3650,7 +3627,7 @@ bc_program_exec(BcProgram* p)
// 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);
}

View File

@ -5,6 +5,7 @@ add.bc
print.bc
parse.bc
array.bc
array2.bc
atan.bc
bessel.bc
functions.bc

View File

@ -0,0 +1,20 @@
#! /usr/bin/bc -q
define z(x, a[]) {
return x + a[1]
}
define y(x, *b[]) {
return x + b[1]
}
a[0] = 5
a[1] = 6
b[0] = 8
b[1] = 7
z(a[0], b[])
y(b[0], a[])
halt

View File

@ -0,0 +1,2 @@
12
14