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