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 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 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 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 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 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 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 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 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 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 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 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