1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2024 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 && type == aptr->type)) 77 { 78 const char* array = type == BC_TYPE_ARRAY ? "[]" : ""; 79 80 bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array); 81 } 82 } 83 84 // Set the auto. 85 a.idx = idx; 86 a.type = type; 87 88 // Push it. 89 bc_vec_push(&f->autos, &a); 90 } 91 #endif // BC_ENABLED 92 93 void 94 bc_func_init(BcFunc* f, const char* name) 95 { 96 BC_SIG_ASSERT_LOCKED; 97 98 assert(f != NULL && name != NULL); 99 100 bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE); 101 102 #if BC_ENABLED 103 104 // Only bc needs these things. 105 if (BC_IS_BC) 106 { 107 bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE); 108 bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE); 109 110 f->nparams = 0; 111 f->voidfn = false; 112 } 113 114 #endif // BC_ENABLED 115 116 f->name = name; 117 } 118 119 void 120 bc_func_reset(BcFunc* f) 121 { 122 BC_SIG_ASSERT_LOCKED; 123 assert(f != NULL); 124 125 bc_vec_popAll(&f->code); 126 127 #if BC_ENABLED 128 if (BC_IS_BC) 129 { 130 bc_vec_popAll(&f->autos); 131 bc_vec_popAll(&f->labels); 132 133 f->nparams = 0; 134 f->voidfn = false; 135 } 136 #endif // BC_ENABLED 137 } 138 139 #if BC_DEBUG || BC_ENABLE_MEMCHECK 140 void 141 bc_func_free(void* func) 142 { 143 BcFunc* f = (BcFunc*) func; 144 145 BC_SIG_ASSERT_LOCKED; 146 assert(f != NULL); 147 148 bc_vec_free(&f->code); 149 150 #if BC_ENABLED 151 if (BC_IS_BC) 152 { 153 bc_vec_free(&f->autos); 154 bc_vec_free(&f->labels); 155 } 156 #endif // BC_ENABLED 157 } 158 #endif // BC_DEBUG || BC_ENABLE_MEMCHECK 159 160 void 161 bc_array_init(BcVec* a, bool nums) 162 { 163 BC_SIG_ASSERT_LOCKED; 164 165 // Set the proper vector. 166 if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM); 167 else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC); 168 169 // We always want at least one item in the array. 170 bc_array_expand(a, 1); 171 } 172 173 void 174 bc_array_copy(BcVec* d, const BcVec* s) 175 { 176 size_t i; 177 178 BC_SIG_ASSERT_LOCKED; 179 180 assert(d != NULL && s != NULL); 181 assert(d != s && d->size == s->size && d->dtor == s->dtor); 182 183 // Make sure to destroy everything currently in d. This will put a lot of 184 // temps on the reuse list, so allocating later is not going to be as 185 // expensive as it seems. Also, it makes it easier to copy numbers that are 186 // strings. 187 bc_vec_popAll(d); 188 189 // Preexpand. 190 bc_vec_expand(d, s->cap); 191 d->len = s->len; 192 193 for (i = 0; i < s->len; ++i) 194 { 195 BcNum* dnum; 196 BcNum* snum; 197 198 dnum = bc_vec_item(d, i); 199 snum = bc_vec_item(s, i); 200 201 // We have to create a copy of the number as well. 202 if (BC_PROG_STR(snum)) 203 { 204 // NOLINTNEXTLINE 205 memcpy(dnum, snum, sizeof(BcNum)); 206 } 207 else bc_num_createCopy(dnum, snum); 208 } 209 } 210 211 void 212 bc_array_expand(BcVec* a, size_t len) 213 { 214 assert(a != NULL); 215 216 BC_SIG_ASSERT_LOCKED; 217 218 bc_vec_expand(a, len); 219 220 // If this is true, then we have a num array. 221 if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM) 222 { 223 // Initialize numbers until we reach the target. 224 while (len > a->len) 225 { 226 BcNum* n = bc_vec_pushEmpty(a); 227 bc_num_init(n, BC_NUM_DEF_SIZE); 228 } 229 } 230 else 231 { 232 assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC); 233 234 // Recursively initialize arrays until we reach the target. Having the 235 // second argument of bc_array_init() be true will activate the base 236 // case, so we're safe. 237 while (len > a->len) 238 { 239 BcVec* v = bc_vec_pushEmpty(a); 240 bc_array_init(v, true); 241 } 242 } 243 } 244 245 void 246 bc_result_clear(BcResult* r) 247 { 248 r->t = BC_RESULT_TEMP; 249 bc_num_clear(&r->d.n); 250 } 251 252 #if DC_ENABLED 253 void 254 bc_result_copy(BcResult* d, BcResult* src) 255 { 256 assert(d != NULL && src != NULL); 257 258 BC_SIG_ASSERT_LOCKED; 259 260 // d is assumed to not be valid yet. 261 d->t = src->t; 262 263 // Yes, it depends on what type. 264 switch (d->t) 265 { 266 case BC_RESULT_TEMP: 267 case BC_RESULT_IBASE: 268 case BC_RESULT_SCALE: 269 case BC_RESULT_OBASE: 270 #if BC_ENABLE_EXTRA_MATH 271 case BC_RESULT_SEED: 272 #endif // BC_ENABLE_EXTRA_MATH 273 { 274 bc_num_createCopy(&d->d.n, &src->d.n); 275 break; 276 } 277 278 case BC_RESULT_VAR: 279 case BC_RESULT_ARRAY: 280 case BC_RESULT_ARRAY_ELEM: 281 { 282 // NOLINTNEXTLINE 283 memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc)); 284 break; 285 } 286 287 case BC_RESULT_STR: 288 { 289 // NOLINTNEXTLINE 290 memcpy(&d->d.n, &src->d.n, sizeof(BcNum)); 291 break; 292 } 293 294 case BC_RESULT_ZERO: 295 case BC_RESULT_ONE: 296 { 297 // Do nothing. 298 break; 299 } 300 301 #if BC_ENABLED 302 case BC_RESULT_VOID: 303 case BC_RESULT_LAST: 304 { 305 #if BC_DEBUG 306 // We should *never* try copying either of these. 307 abort(); 308 #endif // BC_DEBUG 309 } 310 #endif // BC_ENABLED 311 } 312 } 313 #endif // DC_ENABLED 314 315 void 316 bc_result_free(void* result) 317 { 318 BcResult* r = (BcResult*) result; 319 320 BC_SIG_ASSERT_LOCKED; 321 322 assert(r != NULL); 323 324 switch (r->t) 325 { 326 case BC_RESULT_TEMP: 327 case BC_RESULT_IBASE: 328 case BC_RESULT_SCALE: 329 case BC_RESULT_OBASE: 330 #if BC_ENABLE_EXTRA_MATH 331 case BC_RESULT_SEED: 332 #endif // BC_ENABLE_EXTRA_MATH 333 { 334 bc_num_free(&r->d.n); 335 break; 336 } 337 338 case BC_RESULT_VAR: 339 case BC_RESULT_ARRAY: 340 case BC_RESULT_ARRAY_ELEM: 341 case BC_RESULT_STR: 342 case BC_RESULT_ZERO: 343 case BC_RESULT_ONE: 344 #if BC_ENABLED 345 case BC_RESULT_VOID: 346 case BC_RESULT_LAST: 347 #endif // BC_ENABLED 348 { 349 // Do nothing. 350 break; 351 } 352 } 353 } 354