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:
parent
3c2ba19f6b
commit
1a63323d17
9
NEWS.md
9
NEWS.md
@ -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.
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
@ -1184,15 +1197,9 @@ bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
|
||||
* @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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ add.bc
|
||||
print.bc
|
||||
parse.bc
|
||||
array.bc
|
||||
array2.bc
|
||||
atan.bc
|
||||
bessel.bc
|
||||
functions.bc
|
||||
|
20
tests/bc/scripts/array2.bc
Normal file
20
tests/bc/scripts/array2.bc
Normal 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
|
2
tests/bc/scripts/array2.txt
Normal file
2
tests/bc/scripts/array2.txt
Normal file
@ -0,0 +1,2 @@
|
||||
12
|
||||
14
|
Loading…
Reference in New Issue
Block a user