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