1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2025 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * Code to manipulate data structures in programs. 33 * 34 */ 35 36 #include <assert.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 #include <lang.h> 41 #include <program.h> 42 #include <vm.h> 43 44 void 45 bc_const_free(void* constant) 46 { 47 BcConst* c = constant; 48 49 BC_SIG_ASSERT_LOCKED; 50 51 assert(c->val != NULL); 52 53 bc_num_free(&c->num); 54 } 55 56 #if BC_ENABLED 57 void 58 bc_func_insert(BcFunc* f, BcProgram* p, char* name, BcType type, size_t line) 59 { 60 BcAuto a; 61 size_t i, idx; 62 63 // The function must *always* be valid. 64 assert(f != NULL); 65 66 // Get the index of the variable. 67 idx = bc_program_search(p, name, type == BC_TYPE_VAR); 68 69 // Search through all of the other autos/parameters. 70 for (i = 0; i < f->autos.len; ++i) 71 { 72 // Get the auto. 73 BcAuto* aptr = bc_vec_item(&f->autos, i); 74 75 // If they match, barf. 76 if (BC_ERR(idx == aptr->idx && 77 BC_IS_ARRAY(type) == BC_IS_ARRAY(aptr->type))) 78 { 79 const char* array = BC_IS_ARRAY(type) ? "[]" : ""; 80 81 bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array); 82 } 83 } 84 85 // Set the auto. 86 a.idx = idx; 87 a.type = type; 88 89 // Push it. 90 bc_vec_push(&f->autos, &a); 91 } 92 #endif // BC_ENABLED 93 94 void 95 bc_func_init(BcFunc* f, const char* name) 96 { 97 BC_SIG_ASSERT_LOCKED; 98 99 assert(f != NULL && name != NULL); 100 101 bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE); 102 103 #if BC_ENABLED 104 105 // Only bc needs these things. 106 if (BC_IS_BC) 107 { 108 bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE); 109 bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE); 110 111 f->nparams = 0; 112 f->voidfn = false; 113 } 114 115 #endif // BC_ENABLED 116 117 f->name = name; 118 } 119 120 void 121 bc_func_reset(BcFunc* f) 122 { 123 BC_SIG_ASSERT_LOCKED; 124 assert(f != NULL); 125 126 bc_vec_popAll(&f->code); 127 128 #if BC_ENABLED 129 if (BC_IS_BC) 130 { 131 bc_vec_popAll(&f->autos); 132 bc_vec_popAll(&f->labels); 133 134 f->nparams = 0; 135 f->voidfn = false; 136 } 137 #endif // BC_ENABLED 138 } 139 140 #if BC_DEBUG || BC_ENABLE_MEMCHECK 141 void 142 bc_func_free(void* func) 143 { 144 BcFunc* f = (BcFunc*) func; 145 146 BC_SIG_ASSERT_LOCKED; 147 assert(f != NULL); 148 149 bc_vec_free(&f->code); 150 151 #if BC_ENABLED 152 if (BC_IS_BC) 153 { 154 bc_vec_free(&f->autos); 155 bc_vec_free(&f->labels); 156 } 157 #endif // BC_ENABLED 158 } 159 #endif // BC_DEBUG || BC_ENABLE_MEMCHECK 160 161 void 162 bc_array_init(BcVec* a, bool nums) 163 { 164 BC_SIG_ASSERT_LOCKED; 165 166 // Set the proper vector. 167 if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM); 168 else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC); 169 170 // We always want at least one item in the array. 171 bc_array_expand(a, 1); 172 } 173 174 void 175 bc_array_copy(BcVec* d, const BcVec* s) 176 { 177 size_t i; 178 179 BC_SIG_ASSERT_LOCKED; 180 181 assert(d != NULL && s != NULL); 182 assert(d != s && d->size == s->size && d->dtor == s->dtor); 183 184 // Make sure to destroy everything currently in d. This will put a lot of 185 // temps on the reuse list, so allocating later is not going to be as 186 // expensive as it seems. Also, it makes it easier to copy numbers that are 187 // strings. 188 bc_vec_popAll(d); 189 190 // Preexpand. 191 bc_vec_expand(d, s->cap); 192 d->len = s->len; 193 194 for (i = 0; i < s->len; ++i) 195 { 196 BcNum* dnum; 197 BcNum* snum; 198 199 dnum = bc_vec_item(d, i); 200 snum = bc_vec_item(s, i); 201 202 // We have to create a copy of the number as well. 203 if (BC_PROG_STR(snum)) 204 { 205 // NOLINTNEXTLINE 206 memcpy(dnum, snum, sizeof(BcNum)); 207 } 208 else bc_num_createCopy(dnum, snum); 209 } 210 } 211 212 void 213 bc_array_expand(BcVec* a, size_t len) 214 { 215 assert(a != NULL); 216 217 BC_SIG_ASSERT_LOCKED; 218 219 bc_vec_expand(a, len); 220 221 // If this is true, then we have a num array. 222 if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM) 223 { 224 // Initialize numbers until we reach the target. 225 while (len > a->len) 226 { 227 BcNum* n = bc_vec_pushEmpty(a); 228 bc_num_init(n, BC_NUM_DEF_SIZE); 229 } 230 } 231 else 232 { 233 assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC); 234 235 // Recursively initialize arrays until we reach the target. Having the 236 // second argument of bc_array_init() be true will activate the base 237 // case, so we're safe. 238 while (len > a->len) 239 { 240 BcVec* v = bc_vec_pushEmpty(a); 241 bc_array_init(v, true); 242 } 243 } 244 } 245 246 void 247 bc_result_clear(BcResult* r) 248 { 249 r->t = BC_RESULT_TEMP; 250 bc_num_clear(&r->d.n); 251 } 252 253 #if DC_ENABLED 254 void 255 bc_result_copy(BcResult* d, BcResult* src) 256 { 257 assert(d != NULL && src != NULL); 258 259 BC_SIG_ASSERT_LOCKED; 260 261 // d is assumed to not be valid yet. 262 d->t = src->t; 263 264 // Yes, it depends on what type. 265 switch (d->t) 266 { 267 case BC_RESULT_TEMP: 268 case BC_RESULT_IBASE: 269 case BC_RESULT_SCALE: 270 case BC_RESULT_OBASE: 271 #if BC_ENABLE_EXTRA_MATH 272 case BC_RESULT_SEED: 273 #endif // BC_ENABLE_EXTRA_MATH 274 { 275 bc_num_createCopy(&d->d.n, &src->d.n); 276 break; 277 } 278 279 case BC_RESULT_VAR: 280 case BC_RESULT_ARRAY: 281 case BC_RESULT_ARRAY_ELEM: 282 { 283 // NOLINTNEXTLINE 284 memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc)); 285 break; 286 } 287 288 case BC_RESULT_STR: 289 { 290 // NOLINTNEXTLINE 291 memcpy(&d->d.n, &src->d.n, sizeof(BcNum)); 292 break; 293 } 294 295 case BC_RESULT_ZERO: 296 case BC_RESULT_ONE: 297 { 298 // Do nothing. 299 break; 300 } 301 302 #if BC_ENABLED 303 case BC_RESULT_VOID: 304 case BC_RESULT_LAST: 305 { 306 #if BC_DEBUG 307 // We should *never* try copying either of these. 308 abort(); 309 #endif // BC_DEBUG 310 } 311 #endif // BC_ENABLED 312 } 313 } 314 #endif // DC_ENABLED 315 316 void 317 bc_result_free(void* result) 318 { 319 BcResult* r = (BcResult*) result; 320 321 BC_SIG_ASSERT_LOCKED; 322 323 assert(r != NULL); 324 325 switch (r->t) 326 { 327 case BC_RESULT_TEMP: 328 case BC_RESULT_IBASE: 329 case BC_RESULT_SCALE: 330 case BC_RESULT_OBASE: 331 #if BC_ENABLE_EXTRA_MATH 332 case BC_RESULT_SEED: 333 #endif // BC_ENABLE_EXTRA_MATH 334 { 335 bc_num_free(&r->d.n); 336 break; 337 } 338 339 case BC_RESULT_VAR: 340 case BC_RESULT_ARRAY: 341 case BC_RESULT_ARRAY_ELEM: 342 case BC_RESULT_STR: 343 case BC_RESULT_ZERO: 344 case BC_RESULT_ONE: 345 #if BC_ENABLED 346 case BC_RESULT_VOID: 347 case BC_RESULT_LAST: 348 #endif // BC_ENABLED 349 { 350 // Do nothing. 351 break; 352 } 353 } 354 } 355