1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 610328f8bSStefan Eßer * Copyright (c) 2018-2021 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 44*78bc019dSStefan Eßer void 45*78bc019dSStefan Eßer bc_const_free(void* constant) 46*78bc019dSStefan 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 57*78bc019dSStefan Eßer void 58*78bc019dSStefan 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. 70*78bc019dSStefan Eßer for (i = 0; i < f->autos.len; ++i) 71*78bc019dSStefan 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. 76*78bc019dSStefan Eßer if (BC_ERR(idx == aptr->idx && type == aptr->type)) 77*78bc019dSStefan 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 93*78bc019dSStefan Eßer void 94*78bc019dSStefan Eßer bc_func_init(BcFunc* f, const char* name) 95*78bc019dSStefan 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 10244d4804dSStefan Eßer bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST); 10344d4804dSStefan Eßer 10444d4804dSStefan Eßer bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE); 1053aa99676SStefan Eßer 106252884aeSStefan Eßer #if BC_ENABLED 10744d4804dSStefan Eßer 10844d4804dSStefan Eßer // Only bc needs these things. 109*78bc019dSStefan Eßer if (BC_IS_BC) 110*78bc019dSStefan Eßer { 11144d4804dSStefan Eßer bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE); 11244d4804dSStefan Eßer bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE); 1133aa99676SStefan Eßer 114252884aeSStefan Eßer f->nparams = 0; 115252884aeSStefan Eßer f->voidfn = false; 116252884aeSStefan Eßer } 11744d4804dSStefan Eßer 118252884aeSStefan Eßer #endif // BC_ENABLED 1193aa99676SStefan Eßer 120252884aeSStefan Eßer f->name = name; 121252884aeSStefan Eßer } 122252884aeSStefan Eßer 123*78bc019dSStefan Eßer void 124*78bc019dSStefan Eßer bc_func_reset(BcFunc* f) 125*78bc019dSStefan Eßer { 126252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 127252884aeSStefan Eßer assert(f != NULL); 1283aa99676SStefan Eßer 12910328f8bSStefan Eßer bc_vec_popAll(&f->code); 1303aa99676SStefan Eßer 13110328f8bSStefan Eßer bc_vec_popAll(&f->consts); 1323aa99676SStefan Eßer 13344d4804dSStefan Eßer bc_vec_popAll(&f->strs); 13444d4804dSStefan Eßer 135252884aeSStefan Eßer #if BC_ENABLED 136*78bc019dSStefan Eßer if (BC_IS_BC) 137*78bc019dSStefan Eßer { 13810328f8bSStefan Eßer bc_vec_popAll(&f->autos); 13910328f8bSStefan Eßer bc_vec_popAll(&f->labels); 1403aa99676SStefan Eßer 141252884aeSStefan Eßer f->nparams = 0; 142252884aeSStefan Eßer f->voidfn = false; 143252884aeSStefan Eßer } 144252884aeSStefan Eßer #endif // BC_ENABLED 145252884aeSStefan Eßer } 146252884aeSStefan Eßer 14744d4804dSStefan Eßer #ifndef NDEBUG 148*78bc019dSStefan Eßer void 149*78bc019dSStefan Eßer bc_func_free(void* func) 150*78bc019dSStefan Eßer { 151252884aeSStefan Eßer BcFunc* f = (BcFunc*) func; 1523aa99676SStefan Eßer 153252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 154252884aeSStefan Eßer assert(f != NULL); 1553aa99676SStefan Eßer 156252884aeSStefan Eßer bc_vec_free(&f->code); 1573aa99676SStefan Eßer 158252884aeSStefan Eßer bc_vec_free(&f->consts); 1593aa99676SStefan Eßer 1603aa99676SStefan Eßer bc_vec_free(&f->strs); 1613aa99676SStefan Eßer 16244d4804dSStefan Eßer #if BC_ENABLED 163*78bc019dSStefan Eßer if (BC_IS_BC) 164*78bc019dSStefan Eßer { 165252884aeSStefan Eßer bc_vec_free(&f->autos); 166252884aeSStefan Eßer bc_vec_free(&f->labels); 167252884aeSStefan Eßer } 168252884aeSStefan Eßer #endif // BC_ENABLED 169252884aeSStefan Eßer } 17044d4804dSStefan Eßer #endif // NDEBUG 171252884aeSStefan Eßer 172*78bc019dSStefan Eßer void 173*78bc019dSStefan Eßer bc_array_init(BcVec* a, bool nums) 174*78bc019dSStefan Eßer { 175252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 17644d4804dSStefan Eßer 17744d4804dSStefan Eßer // Set the proper vector. 17844d4804dSStefan Eßer if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM); 17944d4804dSStefan Eßer else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC); 18044d4804dSStefan Eßer 18144d4804dSStefan Eßer // We always want at least one item in the array. 182252884aeSStefan Eßer bc_array_expand(a, 1); 183252884aeSStefan Eßer } 184252884aeSStefan Eßer 185*78bc019dSStefan Eßer void 186*78bc019dSStefan Eßer bc_array_copy(BcVec* d, const BcVec* s) 187*78bc019dSStefan Eßer { 188252884aeSStefan Eßer size_t i; 189252884aeSStefan Eßer 190252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 191252884aeSStefan Eßer 192252884aeSStefan Eßer assert(d != NULL && s != NULL); 193252884aeSStefan Eßer assert(d != s && d->size == s->size && d->dtor == s->dtor); 194252884aeSStefan Eßer 19544d4804dSStefan Eßer // Make sure to destroy everything currently in d. This will put a lot of 19644d4804dSStefan Eßer // temps on the reuse list, so allocating later is not going to be as 19744d4804dSStefan Eßer // expensive as it seems. Also, it makes it easier to copy numbers that are 19844d4804dSStefan Eßer // strings. 19910328f8bSStefan Eßer bc_vec_popAll(d); 20044d4804dSStefan Eßer 20144d4804dSStefan Eßer // Preexpand. 202252884aeSStefan Eßer bc_vec_expand(d, s->cap); 203252884aeSStefan Eßer d->len = s->len; 204252884aeSStefan Eßer 205*78bc019dSStefan Eßer for (i = 0; i < s->len; ++i) 206*78bc019dSStefan Eßer { 207*78bc019dSStefan Eßer BcNum* dnum; 208*78bc019dSStefan Eßer BcNum* snum; 20944d4804dSStefan Eßer 21044d4804dSStefan Eßer dnum = bc_vec_item(d, i); 21144d4804dSStefan Eßer snum = bc_vec_item(s, i); 21244d4804dSStefan Eßer 21344d4804dSStefan Eßer // We have to create a copy of the number as well. 214*78bc019dSStefan Eßer if (BC_PROG_STR(snum)) 215*78bc019dSStefan Eßer { 216*78bc019dSStefan Eßer // NOLINTNEXTLINE 217*78bc019dSStefan Eßer memcpy(dnum, snum, sizeof(BcNum)); 218*78bc019dSStefan Eßer } 21944d4804dSStefan Eßer else bc_num_createCopy(dnum, snum); 220252884aeSStefan Eßer } 221252884aeSStefan Eßer } 222252884aeSStefan Eßer 223*78bc019dSStefan Eßer void 224*78bc019dSStefan Eßer bc_array_expand(BcVec* a, size_t len) 225*78bc019dSStefan Eßer { 226252884aeSStefan Eßer assert(a != NULL); 227252884aeSStefan Eßer 228252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 229252884aeSStefan Eßer 230252884aeSStefan Eßer bc_vec_expand(a, len); 231252884aeSStefan Eßer 23244d4804dSStefan Eßer // If this is true, then we have a num array. 233*78bc019dSStefan Eßer if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM) 234*78bc019dSStefan Eßer { 23544d4804dSStefan Eßer // Initialize numbers until we reach the target. 236*78bc019dSStefan Eßer while (len > a->len) 237*78bc019dSStefan Eßer { 23844d4804dSStefan Eßer BcNum* n = bc_vec_pushEmpty(a); 23944d4804dSStefan Eßer bc_num_init(n, BC_NUM_DEF_SIZE); 240252884aeSStefan Eßer } 241252884aeSStefan Eßer } 242*78bc019dSStefan Eßer else 243*78bc019dSStefan Eßer { 24444d4804dSStefan Eßer assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC); 24544d4804dSStefan Eßer 24644d4804dSStefan Eßer // Recursively initialize arrays until we reach the target. Having the 24744d4804dSStefan Eßer // second argument of bc_array_init() be true will activate the base 24844d4804dSStefan Eßer // case, so we're safe. 249*78bc019dSStefan Eßer while (len > a->len) 250*78bc019dSStefan Eßer { 25144d4804dSStefan Eßer BcVec* v = bc_vec_pushEmpty(a); 25244d4804dSStefan Eßer bc_array_init(v, true); 253252884aeSStefan Eßer } 254252884aeSStefan Eßer } 255252884aeSStefan Eßer } 256252884aeSStefan Eßer 257*78bc019dSStefan Eßer void 258*78bc019dSStefan Eßer bc_result_clear(BcResult* r) 259*78bc019dSStefan Eßer { 260252884aeSStefan Eßer r->t = BC_RESULT_TEMP; 261252884aeSStefan Eßer bc_num_clear(&r->d.n); 262252884aeSStefan Eßer } 263252884aeSStefan Eßer 264252884aeSStefan Eßer #if DC_ENABLED 265*78bc019dSStefan Eßer void 266*78bc019dSStefan Eßer bc_result_copy(BcResult* d, BcResult* src) 267*78bc019dSStefan Eßer { 268252884aeSStefan Eßer assert(d != NULL && src != NULL); 269252884aeSStefan Eßer 270252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 271252884aeSStefan Eßer 27244d4804dSStefan Eßer // d is assumed to not be valid yet. 273252884aeSStefan Eßer d->t = src->t; 274252884aeSStefan Eßer 27544d4804dSStefan Eßer // Yes, it depends on what type. 276*78bc019dSStefan Eßer switch (d->t) 277*78bc019dSStefan Eßer { 278252884aeSStefan Eßer case BC_RESULT_TEMP: 279252884aeSStefan Eßer case BC_RESULT_IBASE: 280252884aeSStefan Eßer case BC_RESULT_SCALE: 281252884aeSStefan Eßer case BC_RESULT_OBASE: 282252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 283252884aeSStefan Eßer case BC_RESULT_SEED: 284252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 285252884aeSStefan Eßer { 286252884aeSStefan Eßer bc_num_createCopy(&d->d.n, &src->d.n); 287252884aeSStefan Eßer break; 288252884aeSStefan Eßer } 289252884aeSStefan Eßer 290252884aeSStefan Eßer case BC_RESULT_VAR: 291252884aeSStefan Eßer case BC_RESULT_ARRAY: 292252884aeSStefan Eßer case BC_RESULT_ARRAY_ELEM: 293252884aeSStefan Eßer { 294*78bc019dSStefan Eßer // NOLINTNEXTLINE 295252884aeSStefan Eßer memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc)); 296252884aeSStefan Eßer break; 297252884aeSStefan Eßer } 298252884aeSStefan Eßer 299252884aeSStefan Eßer case BC_RESULT_STR: 300252884aeSStefan Eßer { 301*78bc019dSStefan Eßer // NOLINTNEXTLINE 302252884aeSStefan Eßer memcpy(&d->d.n, &src->d.n, sizeof(BcNum)); 303252884aeSStefan Eßer break; 304252884aeSStefan Eßer } 305252884aeSStefan Eßer 3063aa99676SStefan Eßer case BC_RESULT_ZERO: 307252884aeSStefan Eßer case BC_RESULT_ONE: 308252884aeSStefan Eßer { 309252884aeSStefan Eßer // Do nothing. 310252884aeSStefan Eßer break; 311252884aeSStefan Eßer } 312252884aeSStefan Eßer 313252884aeSStefan Eßer #if BC_ENABLED 314252884aeSStefan Eßer case BC_RESULT_VOID: 315252884aeSStefan Eßer case BC_RESULT_LAST: 316252884aeSStefan Eßer { 317252884aeSStefan Eßer #ifndef NDEBUG 31844d4804dSStefan Eßer // We should *never* try copying either of these. 319252884aeSStefan Eßer abort(); 320252884aeSStefan Eßer #endif // NDEBUG 321252884aeSStefan Eßer } 322252884aeSStefan Eßer #endif // BC_ENABLED 323252884aeSStefan Eßer } 324252884aeSStefan Eßer } 325252884aeSStefan Eßer #endif // DC_ENABLED 326252884aeSStefan Eßer 327*78bc019dSStefan Eßer void 328*78bc019dSStefan Eßer bc_result_free(void* result) 329*78bc019dSStefan Eßer { 330252884aeSStefan Eßer BcResult* r = (BcResult*) result; 331252884aeSStefan Eßer 332252884aeSStefan Eßer BC_SIG_ASSERT_LOCKED; 333252884aeSStefan Eßer 334252884aeSStefan Eßer assert(r != NULL); 335252884aeSStefan Eßer 336*78bc019dSStefan Eßer switch (r->t) 337*78bc019dSStefan Eßer { 338252884aeSStefan Eßer case BC_RESULT_TEMP: 339252884aeSStefan Eßer case BC_RESULT_IBASE: 340252884aeSStefan Eßer case BC_RESULT_SCALE: 341252884aeSStefan Eßer case BC_RESULT_OBASE: 342252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 343252884aeSStefan Eßer case BC_RESULT_SEED: 344252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 345252884aeSStefan Eßer { 346252884aeSStefan Eßer bc_num_free(&r->d.n); 347252884aeSStefan Eßer break; 348252884aeSStefan Eßer } 349252884aeSStefan Eßer 350252884aeSStefan Eßer case BC_RESULT_VAR: 351252884aeSStefan Eßer case BC_RESULT_ARRAY: 352252884aeSStefan Eßer case BC_RESULT_ARRAY_ELEM: 353252884aeSStefan Eßer case BC_RESULT_STR: 3543aa99676SStefan Eßer case BC_RESULT_ZERO: 355252884aeSStefan Eßer case BC_RESULT_ONE: 356252884aeSStefan Eßer #if BC_ENABLED 357252884aeSStefan Eßer case BC_RESULT_VOID: 358252884aeSStefan Eßer case BC_RESULT_LAST: 359252884aeSStefan Eßer #endif // BC_ENABLED 360252884aeSStefan Eßer { 361252884aeSStefan Eßer // Do nothing. 362252884aeSStefan Eßer break; 363252884aeSStefan Eßer } 364252884aeSStefan Eßer } 365252884aeSStefan Eßer } 366