1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2020 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 <vm.h> 42 43 #ifndef NDEBUG 44 void bc_id_free(void *id) { 45 BC_SIG_ASSERT_LOCKED; 46 assert(id != NULL); 47 free(((BcId*) id)->name); 48 } 49 #endif // NDEBUG 50 51 void bc_string_free(void *string) { 52 BC_SIG_ASSERT_LOCKED; 53 assert(string != NULL && (*((char**) string)) != NULL); 54 if (BC_IS_BC) free(*((char**) string)); 55 } 56 57 void bc_const_free(void *constant) { 58 BcConst *c = constant; 59 BC_SIG_ASSERT_LOCKED; 60 assert(c->val != NULL); 61 free(c->val); 62 bc_num_free(&c->num); 63 } 64 65 #if BC_ENABLED 66 void bc_func_insert(BcFunc *f, BcProgram *p, char *name, 67 BcType type, size_t line) 68 { 69 BcLoc a; 70 size_t i, idx; 71 72 assert(f != NULL); 73 74 idx = bc_program_search(p, name, type == BC_TYPE_VAR); 75 76 for (i = 0; i < f->autos.len; ++i) { 77 BcLoc *id = bc_vec_item(&f->autos, i); 78 if (BC_ERR(idx == id->loc && type == (BcType) id->idx)) { 79 const char *array = type == BC_TYPE_ARRAY ? "[]" : ""; 80 bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name, array); 81 } 82 } 83 84 a.loc = idx; 85 a.idx = type; 86 87 bc_vec_push(&f->autos, &a); 88 } 89 #endif // BC_ENABLED 90 91 void bc_func_init(BcFunc *f, const char *name) { 92 93 BC_SIG_ASSERT_LOCKED; 94 95 assert(f != NULL && name != NULL); 96 97 bc_vec_init(&f->code, sizeof(uchar), NULL); 98 99 bc_vec_init(&f->consts, sizeof(BcConst), bc_const_free); 100 101 #if BC_ENABLED 102 if (BC_IS_BC) { 103 104 bc_vec_init(&f->strs, sizeof(char*), bc_string_free); 105 106 bc_vec_init(&f->autos, sizeof(BcLoc), NULL); 107 bc_vec_init(&f->labels, sizeof(size_t), NULL); 108 109 f->nparams = 0; 110 f->voidfn = false; 111 } 112 #endif // BC_ENABLED 113 114 f->name = name; 115 } 116 117 void bc_func_reset(BcFunc *f) { 118 119 BC_SIG_ASSERT_LOCKED; 120 assert(f != NULL); 121 122 bc_vec_npop(&f->code, f->code.len); 123 124 bc_vec_npop(&f->consts, f->consts.len); 125 126 #if BC_ENABLED 127 if (BC_IS_BC) { 128 129 bc_vec_npop(&f->strs, f->strs.len); 130 131 bc_vec_npop(&f->autos, f->autos.len); 132 bc_vec_npop(&f->labels, f->labels.len); 133 134 f->nparams = 0; 135 f->voidfn = false; 136 } 137 #endif // BC_ENABLED 138 } 139 140 void bc_func_free(void *func) { 141 142 #if BC_ENABLE_FUNC_FREE 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 bc_vec_free(&f->consts); 152 153 #if BC_ENABLED 154 #ifndef NDEBUG 155 if (BC_IS_BC) { 156 157 bc_vec_free(&f->strs); 158 159 bc_vec_free(&f->autos); 160 bc_vec_free(&f->labels); 161 } 162 #endif // NDEBUG 163 #endif // BC_ENABLED 164 165 #else // BC_ENABLE_FUNC_FREE 166 BC_UNUSED(func); 167 #endif // BC_ENABLE_FUNC_FREE 168 } 169 170 void bc_array_init(BcVec *a, bool nums) { 171 BC_SIG_ASSERT_LOCKED; 172 if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free); 173 else bc_vec_init(a, sizeof(BcVec), bc_vec_free); 174 bc_array_expand(a, 1); 175 } 176 177 void bc_array_copy(BcVec *d, const BcVec *s) { 178 179 size_t i; 180 181 BC_SIG_ASSERT_LOCKED; 182 183 assert(d != NULL && s != NULL); 184 assert(d != s && d->size == s->size && d->dtor == s->dtor); 185 186 bc_vec_npop(d, d->len); 187 bc_vec_expand(d, s->cap); 188 d->len = s->len; 189 190 for (i = 0; i < s->len; ++i) { 191 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i); 192 bc_num_createCopy(dnum, snum); 193 } 194 } 195 196 void bc_array_expand(BcVec *a, size_t len) { 197 198 assert(a != NULL); 199 200 BC_SIG_ASSERT_LOCKED; 201 202 bc_vec_expand(a, len); 203 204 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) { 205 BcNum n; 206 while (len > a->len) { 207 bc_num_init(&n, BC_NUM_DEF_SIZE); 208 bc_vec_push(a, &n); 209 } 210 } 211 else { 212 BcVec v; 213 assert(a->size == sizeof(BcVec) && a->dtor == bc_vec_free); 214 while (len > a->len) { 215 bc_array_init(&v, true); 216 bc_vec_push(a, &v); 217 } 218 } 219 } 220 221 void bc_result_clear(BcResult *r) { 222 r->t = BC_RESULT_TEMP; 223 bc_num_clear(&r->d.n); 224 } 225 226 #if DC_ENABLED 227 void bc_result_copy(BcResult *d, BcResult *src) { 228 229 assert(d != NULL && src != NULL); 230 231 BC_SIG_ASSERT_LOCKED; 232 233 d->t = src->t; 234 235 switch (d->t) { 236 237 case BC_RESULT_TEMP: 238 case BC_RESULT_IBASE: 239 case BC_RESULT_SCALE: 240 case BC_RESULT_OBASE: 241 #if BC_ENABLE_EXTRA_MATH 242 case BC_RESULT_SEED: 243 #endif // BC_ENABLE_EXTRA_MATH 244 { 245 bc_num_createCopy(&d->d.n, &src->d.n); 246 break; 247 } 248 249 case BC_RESULT_VAR: 250 #if BC_ENABLED 251 case BC_RESULT_ARRAY: 252 #endif // BC_ENABLED 253 case BC_RESULT_ARRAY_ELEM: 254 { 255 memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc)); 256 break; 257 } 258 259 case BC_RESULT_STR: 260 { 261 memcpy(&d->d.n, &src->d.n, sizeof(BcNum)); 262 break; 263 } 264 265 case BC_RESULT_ZERO: 266 case BC_RESULT_ONE: 267 { 268 // Do nothing. 269 break; 270 } 271 272 #if BC_ENABLED 273 case BC_RESULT_VOID: 274 case BC_RESULT_LAST: 275 { 276 #ifndef NDEBUG 277 abort(); 278 #endif // NDEBUG 279 } 280 #endif // BC_ENABLED 281 } 282 } 283 #endif // DC_ENABLED 284 285 void bc_result_free(void *result) { 286 287 BcResult *r = (BcResult*) result; 288 289 BC_SIG_ASSERT_LOCKED; 290 291 assert(r != NULL); 292 293 switch (r->t) { 294 295 case BC_RESULT_TEMP: 296 case BC_RESULT_IBASE: 297 case BC_RESULT_SCALE: 298 case BC_RESULT_OBASE: 299 #if BC_ENABLE_EXTRA_MATH 300 case BC_RESULT_SEED: 301 #endif // BC_ENABLE_EXTRA_MATH 302 { 303 bc_num_free(&r->d.n); 304 break; 305 } 306 307 case BC_RESULT_VAR: 308 #if BC_ENABLED 309 case BC_RESULT_ARRAY: 310 #endif // BC_ENABLED 311 case BC_RESULT_ARRAY_ELEM: 312 case BC_RESULT_STR: 313 case BC_RESULT_ZERO: 314 case BC_RESULT_ONE: 315 #if BC_ENABLED 316 case BC_RESULT_VOID: 317 case BC_RESULT_LAST: 318 #endif // BC_ENABLED 319 { 320 // Do nothing. 321 break; 322 } 323 } 324 } 325