1252884aeSStefan Eßer /*
2252884aeSStefan Eßer * *****************************************************************************
3252884aeSStefan Eßer *
43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer *
6a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7252884aeSStefan Eßer *
8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without
9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met:
10252884aeSStefan Eßer *
11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this
12252884aeSStefan Eßer * list of conditions and the following disclaimer.
13252884aeSStefan Eßer *
14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice,
15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation
16252884aeSStefan Eßer * and/or other materials provided with the distribution.
17252884aeSStefan Eßer *
18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE.
29252884aeSStefan Eßer *
30252884aeSStefan Eßer * *****************************************************************************
31252884aeSStefan Eßer *
32252884aeSStefan Eßer * Code to manipulate data structures in programs.
33252884aeSStefan Eßer *
34252884aeSStefan Eßer */
35252884aeSStefan Eßer
36252884aeSStefan Eßer #include <assert.h>
37252884aeSStefan Eßer #include <stdlib.h>
38252884aeSStefan Eßer #include <string.h>
39252884aeSStefan Eßer
40252884aeSStefan Eßer #include <lang.h>
4144d4804dSStefan Eßer #include <program.h>
42252884aeSStefan Eßer #include <vm.h>
43252884aeSStefan Eßer
4478bc019dSStefan Eßer void
bc_const_free(void * constant)4578bc019dSStefan Eßer bc_const_free(void* constant)
4678bc019dSStefan Eßer {
47252884aeSStefan Eßer BcConst* c = constant;
4844d4804dSStefan Eßer
49252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
5044d4804dSStefan Eßer
51252884aeSStefan Eßer assert(c->val != NULL);
5244d4804dSStefan Eßer
53252884aeSStefan Eßer bc_num_free(&c->num);
54252884aeSStefan Eßer }
55252884aeSStefan Eßer
56252884aeSStefan Eßer #if BC_ENABLED
5778bc019dSStefan Eßer void
bc_func_insert(BcFunc * f,BcProgram * p,char * name,BcType type,size_t line)5878bc019dSStefan Eßer bc_func_insert(BcFunc* f, BcProgram* p, char* name, BcType type, size_t line)
59252884aeSStefan Eßer {
6044d4804dSStefan Eßer BcAuto a;
61252884aeSStefan Eßer size_t i, idx;
62252884aeSStefan Eßer
6344d4804dSStefan Eßer // The function must *always* be valid.
64252884aeSStefan Eßer assert(f != NULL);
65252884aeSStefan Eßer
6644d4804dSStefan Eßer // Get the index of the variable.
67252884aeSStefan Eßer idx = bc_program_search(p, name, type == BC_TYPE_VAR);
68252884aeSStefan Eßer
6944d4804dSStefan Eßer // Search through all of the other autos/parameters.
7078bc019dSStefan Eßer for (i = 0; i < f->autos.len; ++i)
7178bc019dSStefan Eßer {
7244d4804dSStefan Eßer // Get the auto.
7344d4804dSStefan Eßer BcAuto* aptr = bc_vec_item(&f->autos, i);
7444d4804dSStefan Eßer
7544d4804dSStefan Eßer // If they match, barf.
7678bc019dSStefan Eßer if (BC_ERR(idx == aptr->idx && type == aptr->type))
7778bc019dSStefan Eßer {
78252884aeSStefan Eßer const char* array = type == BC_TYPE_ARRAY ? "[]" : "";
7944d4804dSStefan Eßer
8044d4804dSStefan Eßer bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);
81252884aeSStefan Eßer }
82252884aeSStefan Eßer }
83252884aeSStefan Eßer
8444d4804dSStefan Eßer // Set the auto.
8544d4804dSStefan Eßer a.idx = idx;
8644d4804dSStefan Eßer a.type = type;
87252884aeSStefan Eßer
8844d4804dSStefan Eßer // Push it.
89252884aeSStefan Eßer bc_vec_push(&f->autos, &a);
90252884aeSStefan Eßer }
91252884aeSStefan Eßer #endif // BC_ENABLED
92252884aeSStefan Eßer
9378bc019dSStefan Eßer void
bc_func_init(BcFunc * f,const char * name)9478bc019dSStefan Eßer bc_func_init(BcFunc* f, const char* name)
9578bc019dSStefan Eßer {
96252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
97252884aeSStefan Eßer
98252884aeSStefan Eßer assert(f != NULL && name != NULL);
99252884aeSStefan Eßer
10044d4804dSStefan Eßer bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
101252884aeSStefan Eßer
102252884aeSStefan Eßer #if BC_ENABLED
10344d4804dSStefan Eßer
10444d4804dSStefan Eßer // Only bc needs these things.
10578bc019dSStefan Eßer if (BC_IS_BC)
10678bc019dSStefan Eßer {
10744d4804dSStefan Eßer bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
10844d4804dSStefan Eßer bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
1093aa99676SStefan Eßer
110252884aeSStefan Eßer f->nparams = 0;
111252884aeSStefan Eßer f->voidfn = false;
112252884aeSStefan Eßer }
11344d4804dSStefan Eßer
114252884aeSStefan Eßer #endif // BC_ENABLED
1153aa99676SStefan Eßer
116252884aeSStefan Eßer f->name = name;
117252884aeSStefan Eßer }
118252884aeSStefan Eßer
11978bc019dSStefan Eßer void
bc_func_reset(BcFunc * f)12078bc019dSStefan Eßer bc_func_reset(BcFunc* f)
12178bc019dSStefan Eßer {
122252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
123252884aeSStefan Eßer assert(f != NULL);
1243aa99676SStefan Eßer
12510328f8bSStefan Eßer bc_vec_popAll(&f->code);
1263aa99676SStefan Eßer
127252884aeSStefan Eßer #if BC_ENABLED
12878bc019dSStefan Eßer if (BC_IS_BC)
12978bc019dSStefan Eßer {
13010328f8bSStefan Eßer bc_vec_popAll(&f->autos);
13110328f8bSStefan Eßer bc_vec_popAll(&f->labels);
1323aa99676SStefan Eßer
133252884aeSStefan Eßer f->nparams = 0;
134252884aeSStefan Eßer f->voidfn = false;
135252884aeSStefan Eßer }
136252884aeSStefan Eßer #endif // BC_ENABLED
137252884aeSStefan Eßer }
138252884aeSStefan Eßer
139*12e0d316SStefan Eßer #if BC_DEBUG || BC_ENABLE_MEMCHECK
14078bc019dSStefan Eßer void
bc_func_free(void * func)14178bc019dSStefan Eßer bc_func_free(void* func)
14278bc019dSStefan Eßer {
143252884aeSStefan Eßer BcFunc* f = (BcFunc*) func;
1443aa99676SStefan Eßer
145252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
146252884aeSStefan Eßer assert(f != NULL);
1473aa99676SStefan Eßer
148252884aeSStefan Eßer bc_vec_free(&f->code);
1493aa99676SStefan Eßer
15044d4804dSStefan Eßer #if BC_ENABLED
15178bc019dSStefan Eßer if (BC_IS_BC)
15278bc019dSStefan Eßer {
153252884aeSStefan Eßer bc_vec_free(&f->autos);
154252884aeSStefan Eßer bc_vec_free(&f->labels);
155252884aeSStefan Eßer }
156252884aeSStefan Eßer #endif // BC_ENABLED
157252884aeSStefan Eßer }
158*12e0d316SStefan Eßer #endif // BC_DEBUG || BC_ENABLE_MEMCHECK
159252884aeSStefan Eßer
16078bc019dSStefan Eßer void
bc_array_init(BcVec * a,bool nums)16178bc019dSStefan Eßer bc_array_init(BcVec* a, bool nums)
16278bc019dSStefan Eßer {
163252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
16444d4804dSStefan Eßer
16544d4804dSStefan Eßer // Set the proper vector.
16644d4804dSStefan Eßer if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
16744d4804dSStefan Eßer else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
16844d4804dSStefan Eßer
16944d4804dSStefan Eßer // We always want at least one item in the array.
170252884aeSStefan Eßer bc_array_expand(a, 1);
171252884aeSStefan Eßer }
172252884aeSStefan Eßer
17378bc019dSStefan Eßer void
bc_array_copy(BcVec * d,const BcVec * s)17478bc019dSStefan Eßer bc_array_copy(BcVec* d, const BcVec* s)
17578bc019dSStefan Eßer {
176252884aeSStefan Eßer size_t i;
177252884aeSStefan Eßer
178252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
179252884aeSStefan Eßer
180252884aeSStefan Eßer assert(d != NULL && s != NULL);
181252884aeSStefan Eßer assert(d != s && d->size == s->size && d->dtor == s->dtor);
182252884aeSStefan Eßer
18344d4804dSStefan Eßer // Make sure to destroy everything currently in d. This will put a lot of
18444d4804dSStefan Eßer // temps on the reuse list, so allocating later is not going to be as
18544d4804dSStefan Eßer // expensive as it seems. Also, it makes it easier to copy numbers that are
18644d4804dSStefan Eßer // strings.
18710328f8bSStefan Eßer bc_vec_popAll(d);
18844d4804dSStefan Eßer
18944d4804dSStefan Eßer // Preexpand.
190252884aeSStefan Eßer bc_vec_expand(d, s->cap);
191252884aeSStefan Eßer d->len = s->len;
192252884aeSStefan Eßer
19378bc019dSStefan Eßer for (i = 0; i < s->len; ++i)
19478bc019dSStefan Eßer {
19578bc019dSStefan Eßer BcNum* dnum;
19678bc019dSStefan Eßer BcNum* snum;
19744d4804dSStefan Eßer
19844d4804dSStefan Eßer dnum = bc_vec_item(d, i);
19944d4804dSStefan Eßer snum = bc_vec_item(s, i);
20044d4804dSStefan Eßer
20144d4804dSStefan Eßer // We have to create a copy of the number as well.
20278bc019dSStefan Eßer if (BC_PROG_STR(snum))
20378bc019dSStefan Eßer {
20478bc019dSStefan Eßer // NOLINTNEXTLINE
20578bc019dSStefan Eßer memcpy(dnum, snum, sizeof(BcNum));
20678bc019dSStefan Eßer }
20744d4804dSStefan Eßer else bc_num_createCopy(dnum, snum);
208252884aeSStefan Eßer }
209252884aeSStefan Eßer }
210252884aeSStefan Eßer
21178bc019dSStefan Eßer void
bc_array_expand(BcVec * a,size_t len)21278bc019dSStefan Eßer bc_array_expand(BcVec* a, size_t len)
21378bc019dSStefan Eßer {
214252884aeSStefan Eßer assert(a != NULL);
215252884aeSStefan Eßer
216252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
217252884aeSStefan Eßer
218252884aeSStefan Eßer bc_vec_expand(a, len);
219252884aeSStefan Eßer
22044d4804dSStefan Eßer // If this is true, then we have a num array.
22178bc019dSStefan Eßer if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM)
22278bc019dSStefan Eßer {
22344d4804dSStefan Eßer // Initialize numbers until we reach the target.
22478bc019dSStefan Eßer while (len > a->len)
22578bc019dSStefan Eßer {
22644d4804dSStefan Eßer BcNum* n = bc_vec_pushEmpty(a);
22744d4804dSStefan Eßer bc_num_init(n, BC_NUM_DEF_SIZE);
228252884aeSStefan Eßer }
229252884aeSStefan Eßer }
23078bc019dSStefan Eßer else
23178bc019dSStefan Eßer {
23244d4804dSStefan Eßer assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
23344d4804dSStefan Eßer
23444d4804dSStefan Eßer // Recursively initialize arrays until we reach the target. Having the
23544d4804dSStefan Eßer // second argument of bc_array_init() be true will activate the base
23644d4804dSStefan Eßer // case, so we're safe.
23778bc019dSStefan Eßer while (len > a->len)
23878bc019dSStefan Eßer {
23944d4804dSStefan Eßer BcVec* v = bc_vec_pushEmpty(a);
24044d4804dSStefan Eßer bc_array_init(v, true);
241252884aeSStefan Eßer }
242252884aeSStefan Eßer }
243252884aeSStefan Eßer }
244252884aeSStefan Eßer
24578bc019dSStefan Eßer void
bc_result_clear(BcResult * r)24678bc019dSStefan Eßer bc_result_clear(BcResult* r)
24778bc019dSStefan Eßer {
248252884aeSStefan Eßer r->t = BC_RESULT_TEMP;
249252884aeSStefan Eßer bc_num_clear(&r->d.n);
250252884aeSStefan Eßer }
251252884aeSStefan Eßer
252252884aeSStefan Eßer #if DC_ENABLED
25378bc019dSStefan Eßer void
bc_result_copy(BcResult * d,BcResult * src)25478bc019dSStefan Eßer bc_result_copy(BcResult* d, BcResult* src)
25578bc019dSStefan Eßer {
256252884aeSStefan Eßer assert(d != NULL && src != NULL);
257252884aeSStefan Eßer
258252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
259252884aeSStefan Eßer
26044d4804dSStefan Eßer // d is assumed to not be valid yet.
261252884aeSStefan Eßer d->t = src->t;
262252884aeSStefan Eßer
26344d4804dSStefan Eßer // Yes, it depends on what type.
26478bc019dSStefan Eßer switch (d->t)
26578bc019dSStefan Eßer {
266252884aeSStefan Eßer case BC_RESULT_TEMP:
267252884aeSStefan Eßer case BC_RESULT_IBASE:
268252884aeSStefan Eßer case BC_RESULT_SCALE:
269252884aeSStefan Eßer case BC_RESULT_OBASE:
270252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
271252884aeSStefan Eßer case BC_RESULT_SEED:
272252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
273252884aeSStefan Eßer {
274252884aeSStefan Eßer bc_num_createCopy(&d->d.n, &src->d.n);
275252884aeSStefan Eßer break;
276252884aeSStefan Eßer }
277252884aeSStefan Eßer
278252884aeSStefan Eßer case BC_RESULT_VAR:
279252884aeSStefan Eßer case BC_RESULT_ARRAY:
280252884aeSStefan Eßer case BC_RESULT_ARRAY_ELEM:
281252884aeSStefan Eßer {
28278bc019dSStefan Eßer // NOLINTNEXTLINE
283252884aeSStefan Eßer memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
284252884aeSStefan Eßer break;
285252884aeSStefan Eßer }
286252884aeSStefan Eßer
287252884aeSStefan Eßer case BC_RESULT_STR:
288252884aeSStefan Eßer {
28978bc019dSStefan Eßer // NOLINTNEXTLINE
290252884aeSStefan Eßer memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
291252884aeSStefan Eßer break;
292252884aeSStefan Eßer }
293252884aeSStefan Eßer
2943aa99676SStefan Eßer case BC_RESULT_ZERO:
295252884aeSStefan Eßer case BC_RESULT_ONE:
296252884aeSStefan Eßer {
297252884aeSStefan Eßer // Do nothing.
298252884aeSStefan Eßer break;
299252884aeSStefan Eßer }
300252884aeSStefan Eßer
301252884aeSStefan Eßer #if BC_ENABLED
302252884aeSStefan Eßer case BC_RESULT_VOID:
303252884aeSStefan Eßer case BC_RESULT_LAST:
304252884aeSStefan Eßer {
305103d7cdfSStefan Eßer #if BC_DEBUG
30644d4804dSStefan Eßer // We should *never* try copying either of these.
307252884aeSStefan Eßer abort();
308103d7cdfSStefan Eßer #endif // BC_DEBUG
309252884aeSStefan Eßer }
310252884aeSStefan Eßer #endif // BC_ENABLED
311252884aeSStefan Eßer }
312252884aeSStefan Eßer }
313252884aeSStefan Eßer #endif // DC_ENABLED
314252884aeSStefan Eßer
31578bc019dSStefan Eßer void
bc_result_free(void * result)31678bc019dSStefan Eßer bc_result_free(void* result)
31778bc019dSStefan Eßer {
318252884aeSStefan Eßer BcResult* r = (BcResult*) result;
319252884aeSStefan Eßer
320252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED;
321252884aeSStefan Eßer
322252884aeSStefan Eßer assert(r != NULL);
323252884aeSStefan Eßer
32478bc019dSStefan Eßer switch (r->t)
32578bc019dSStefan Eßer {
326252884aeSStefan Eßer case BC_RESULT_TEMP:
327252884aeSStefan Eßer case BC_RESULT_IBASE:
328252884aeSStefan Eßer case BC_RESULT_SCALE:
329252884aeSStefan Eßer case BC_RESULT_OBASE:
330252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
331252884aeSStefan Eßer case BC_RESULT_SEED:
332252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
333252884aeSStefan Eßer {
334252884aeSStefan Eßer bc_num_free(&r->d.n);
335252884aeSStefan Eßer break;
336252884aeSStefan Eßer }
337252884aeSStefan Eßer
338252884aeSStefan Eßer case BC_RESULT_VAR:
339252884aeSStefan Eßer case BC_RESULT_ARRAY:
340252884aeSStefan Eßer case BC_RESULT_ARRAY_ELEM:
341252884aeSStefan Eßer case BC_RESULT_STR:
3423aa99676SStefan Eßer case BC_RESULT_ZERO:
343252884aeSStefan Eßer case BC_RESULT_ONE:
344252884aeSStefan Eßer #if BC_ENABLED
345252884aeSStefan Eßer case BC_RESULT_VOID:
346252884aeSStefan Eßer case BC_RESULT_LAST:
347252884aeSStefan Eßer #endif // BC_ENABLED
348252884aeSStefan Eßer {
349252884aeSStefan Eßer // Do nothing.
350252884aeSStefan Eßer break;
351252884aeSStefan Eßer }
352252884aeSStefan Eßer }
353252884aeSStefan Eßer }
354