/*1* *****************************************************************************2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2018-2025 Gavin D. Howard and contributors.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions are met:9*10* * Redistributions of source code must retain the above copyright notice, this11* list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright notice,14* this list of conditions and the following disclaimer in the documentation15* and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"18* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE21* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGE.28*29* *****************************************************************************30*31* Code to manipulate data structures in programs.32*33*/3435#include <assert.h>36#include <stdlib.h>37#include <string.h>3839#include <lang.h>40#include <program.h>41#include <vm.h>4243void44bc_const_free(void* constant)45{46BcConst* c = constant;4748BC_SIG_ASSERT_LOCKED;4950assert(c->val != NULL);5152bc_num_free(&c->num);53}5455#if BC_ENABLED56void57bc_func_insert(BcFunc* f, BcProgram* p, char* name, BcType type, size_t line)58{59BcAuto a;60size_t i, idx;6162// The function must *always* be valid.63assert(f != NULL);6465// Get the index of the variable.66idx = bc_program_search(p, name, type == BC_TYPE_VAR);6768// Search through all of the other autos/parameters.69for (i = 0; i < f->autos.len; ++i)70{71// Get the auto.72BcAuto* aptr = bc_vec_item(&f->autos, i);7374// If they match, barf.75if (BC_ERR(idx == aptr->idx &&76BC_IS_ARRAY(type) == BC_IS_ARRAY(aptr->type)))77{78const char* array = BC_IS_ARRAY(type) ? "[]" : "";7980bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);81}82}8384// Set the auto.85a.idx = idx;86a.type = type;8788// Push it.89bc_vec_push(&f->autos, &a);90}91#endif // BC_ENABLED9293void94bc_func_init(BcFunc* f, const char* name)95{96BC_SIG_ASSERT_LOCKED;9798assert(f != NULL && name != NULL);99100bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);101102#if BC_ENABLED103104// Only bc needs these things.105if (BC_IS_BC)106{107bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);108bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);109110f->nparams = 0;111f->voidfn = false;112}113114#endif // BC_ENABLED115116f->name = name;117}118119void120bc_func_reset(BcFunc* f)121{122BC_SIG_ASSERT_LOCKED;123assert(f != NULL);124125bc_vec_popAll(&f->code);126127#if BC_ENABLED128if (BC_IS_BC)129{130bc_vec_popAll(&f->autos);131bc_vec_popAll(&f->labels);132133f->nparams = 0;134f->voidfn = false;135}136#endif // BC_ENABLED137}138139#if BC_DEBUG || BC_ENABLE_MEMCHECK140void141bc_func_free(void* func)142{143BcFunc* f = (BcFunc*) func;144145BC_SIG_ASSERT_LOCKED;146assert(f != NULL);147148bc_vec_free(&f->code);149150#if BC_ENABLED151if (BC_IS_BC)152{153bc_vec_free(&f->autos);154bc_vec_free(&f->labels);155}156#endif // BC_ENABLED157}158#endif // BC_DEBUG || BC_ENABLE_MEMCHECK159160void161bc_array_init(BcVec* a, bool nums)162{163BC_SIG_ASSERT_LOCKED;164165// Set the proper vector.166if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);167else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);168169// We always want at least one item in the array.170bc_array_expand(a, 1);171}172173void174bc_array_copy(BcVec* d, const BcVec* s)175{176size_t i;177178BC_SIG_ASSERT_LOCKED;179180assert(d != NULL && s != NULL);181assert(d != s && d->size == s->size && d->dtor == s->dtor);182183// Make sure to destroy everything currently in d. This will put a lot of184// temps on the reuse list, so allocating later is not going to be as185// expensive as it seems. Also, it makes it easier to copy numbers that are186// strings.187bc_vec_popAll(d);188189// Preexpand.190bc_vec_expand(d, s->cap);191d->len = s->len;192193for (i = 0; i < s->len; ++i)194{195BcNum* dnum;196BcNum* snum;197198dnum = bc_vec_item(d, i);199snum = bc_vec_item(s, i);200201// We have to create a copy of the number as well.202if (BC_PROG_STR(snum))203{204// NOLINTNEXTLINE205memcpy(dnum, snum, sizeof(BcNum));206}207else bc_num_createCopy(dnum, snum);208}209}210211void212bc_array_expand(BcVec* a, size_t len)213{214assert(a != NULL);215216BC_SIG_ASSERT_LOCKED;217218bc_vec_expand(a, len);219220// If this is true, then we have a num array.221if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM)222{223// Initialize numbers until we reach the target.224while (len > a->len)225{226BcNum* n = bc_vec_pushEmpty(a);227bc_num_init(n, BC_NUM_DEF_SIZE);228}229}230else231{232assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);233234// Recursively initialize arrays until we reach the target. Having the235// second argument of bc_array_init() be true will activate the base236// case, so we're safe.237while (len > a->len)238{239BcVec* v = bc_vec_pushEmpty(a);240bc_array_init(v, true);241}242}243}244245void246bc_result_clear(BcResult* r)247{248r->t = BC_RESULT_TEMP;249bc_num_clear(&r->d.n);250}251252#if DC_ENABLED253void254bc_result_copy(BcResult* d, BcResult* src)255{256assert(d != NULL && src != NULL);257258BC_SIG_ASSERT_LOCKED;259260// d is assumed to not be valid yet.261d->t = src->t;262263// Yes, it depends on what type.264switch (d->t)265{266case BC_RESULT_TEMP:267case BC_RESULT_IBASE:268case BC_RESULT_SCALE:269case BC_RESULT_OBASE:270#if BC_ENABLE_EXTRA_MATH271case BC_RESULT_SEED:272#endif // BC_ENABLE_EXTRA_MATH273{274bc_num_createCopy(&d->d.n, &src->d.n);275break;276}277278case BC_RESULT_VAR:279case BC_RESULT_ARRAY:280case BC_RESULT_ARRAY_ELEM:281{282// NOLINTNEXTLINE283memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));284break;285}286287case BC_RESULT_STR:288{289// NOLINTNEXTLINE290memcpy(&d->d.n, &src->d.n, sizeof(BcNum));291break;292}293294case BC_RESULT_ZERO:295case BC_RESULT_ONE:296{297// Do nothing.298break;299}300301#if BC_ENABLED302case BC_RESULT_VOID:303case BC_RESULT_LAST:304{305#if BC_DEBUG306// We should *never* try copying either of these.307abort();308#endif // BC_DEBUG309}310#endif // BC_ENABLED311}312}313#endif // DC_ENABLED314315void316bc_result_free(void* result)317{318BcResult* r = (BcResult*) result;319320BC_SIG_ASSERT_LOCKED;321322assert(r != NULL);323324switch (r->t)325{326case BC_RESULT_TEMP:327case BC_RESULT_IBASE:328case BC_RESULT_SCALE:329case BC_RESULT_OBASE:330#if BC_ENABLE_EXTRA_MATH331case BC_RESULT_SEED:332#endif // BC_ENABLE_EXTRA_MATH333{334bc_num_free(&r->d.n);335break;336}337338case BC_RESULT_VAR:339case BC_RESULT_ARRAY:340case BC_RESULT_ARRAY_ELEM:341case BC_RESULT_STR:342case BC_RESULT_ZERO:343case BC_RESULT_ONE:344#if BC_ENABLED345case BC_RESULT_VOID:346case BC_RESULT_LAST:347#endif // BC_ENABLED348{349// Do nothing.350break;351}352}353}354355356