1 /* 2 * ***************************************************************************** 3 * 4 * Copyright (c) 2018-2020 Gavin D. Howard and contributors. 5 * 6 * All rights reserved. 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 // This is necessary for not allocating memory where it isn't used. 100 // dc does not use strings except in the main function. The else part 101 // is necessary to stop uninitiazed data errors in valgrind. 102 if (BC_IS_BC || !strcmp(name, bc_func_main)) 103 bc_vec_init(&f->strs, sizeof(char*), bc_string_free); 104 #if BC_ENABLE_FUNC_FREE 105 else bc_vec_clear(&f->strs); 106 #endif // BC_ENABLE_FUNC_FREE 107 108 bc_vec_init(&f->consts, sizeof(BcConst), bc_const_free); 109 #if BC_ENABLED 110 if (BC_IS_BC) { 111 bc_vec_init(&f->autos, sizeof(BcLoc), NULL); 112 bc_vec_init(&f->labels, sizeof(size_t), NULL); 113 f->nparams = 0; 114 f->voidfn = false; 115 } 116 #endif // BC_ENABLED 117 f->name = name; 118 } 119 120 void bc_func_reset(BcFunc *f) { 121 BC_SIG_ASSERT_LOCKED; 122 assert(f != NULL); 123 bc_vec_npop(&f->code, f->code.len); 124 bc_vec_npop(&f->strs, f->strs.len); 125 bc_vec_npop(&f->consts, f->consts.len); 126 #if BC_ENABLED 127 if (BC_IS_BC) { 128 bc_vec_npop(&f->autos, f->autos.len); 129 bc_vec_npop(&f->labels, f->labels.len); 130 f->nparams = 0; 131 f->voidfn = false; 132 } 133 #endif // BC_ENABLED 134 } 135 136 void bc_func_free(void *func) { 137 #if BC_ENABLE_FUNC_FREE 138 139 BcFunc *f = (BcFunc*) func; 140 BC_SIG_ASSERT_LOCKED; 141 assert(f != NULL); 142 bc_vec_free(&f->code); 143 bc_vec_free(&f->strs); 144 bc_vec_free(&f->consts); 145 #if BC_ENABLED 146 #ifndef NDEBUG 147 if (BC_IS_BC) { 148 bc_vec_free(&f->autos); 149 bc_vec_free(&f->labels); 150 } 151 #endif // NDEBUG 152 #endif // BC_ENABLED 153 154 #else // BC_ENABLE_FUNC_FREE 155 BC_UNUSED(func); 156 #endif // BC_ENABLE_FUNC_FREE 157 } 158 159 void bc_array_init(BcVec *a, bool nums) { 160 BC_SIG_ASSERT_LOCKED; 161 if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free); 162 else bc_vec_init(a, sizeof(BcVec), bc_vec_free); 163 bc_array_expand(a, 1); 164 } 165 166 void bc_array_copy(BcVec *d, const BcVec *s) { 167 168 size_t i; 169 170 BC_SIG_ASSERT_LOCKED; 171 172 assert(d != NULL && s != NULL); 173 assert(d != s && d->size == s->size && d->dtor == s->dtor); 174 175 bc_vec_npop(d, d->len); 176 bc_vec_expand(d, s->cap); 177 d->len = s->len; 178 179 for (i = 0; i < s->len; ++i) { 180 BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i); 181 bc_num_createCopy(dnum, snum); 182 } 183 } 184 185 void bc_array_expand(BcVec *a, size_t len) { 186 187 assert(a != NULL); 188 189 BC_SIG_ASSERT_LOCKED; 190 191 bc_vec_expand(a, len); 192 193 if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) { 194 BcNum n; 195 while (len > a->len) { 196 bc_num_init(&n, BC_NUM_DEF_SIZE); 197 bc_vec_push(a, &n); 198 } 199 } 200 else { 201 BcVec v; 202 assert(a->size == sizeof(BcVec) && a->dtor == bc_vec_free); 203 while (len > a->len) { 204 bc_array_init(&v, true); 205 bc_vec_push(a, &v); 206 } 207 } 208 } 209 210 void bc_result_clear(BcResult *r) { 211 r->t = BC_RESULT_TEMP; 212 bc_num_clear(&r->d.n); 213 } 214 215 #if DC_ENABLED 216 void bc_result_copy(BcResult *d, BcResult *src) { 217 218 assert(d != NULL && src != NULL); 219 220 BC_SIG_ASSERT_LOCKED; 221 222 d->t = src->t; 223 224 switch (d->t) { 225 226 case BC_RESULT_TEMP: 227 case BC_RESULT_IBASE: 228 case BC_RESULT_SCALE: 229 case BC_RESULT_OBASE: 230 #if BC_ENABLE_EXTRA_MATH 231 case BC_RESULT_SEED: 232 #endif // BC_ENABLE_EXTRA_MATH 233 { 234 bc_num_createCopy(&d->d.n, &src->d.n); 235 break; 236 } 237 238 case BC_RESULT_VAR: 239 #if BC_ENABLED 240 case BC_RESULT_ARRAY: 241 #endif // BC_ENABLED 242 case BC_RESULT_ARRAY_ELEM: 243 { 244 memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc)); 245 break; 246 } 247 248 case BC_RESULT_CONSTANT: 249 case BC_RESULT_STR: 250 { 251 memcpy(&d->d.n, &src->d.n, sizeof(BcNum)); 252 break; 253 } 254 255 case BC_RESULT_ONE: 256 { 257 // Do nothing. 258 break; 259 } 260 261 #if BC_ENABLED 262 case BC_RESULT_VOID: 263 case BC_RESULT_LAST: 264 { 265 #ifndef NDEBUG 266 abort(); 267 #endif // NDEBUG 268 } 269 #endif // BC_ENABLED 270 } 271 } 272 #endif // DC_ENABLED 273 274 void bc_result_free(void *result) { 275 276 BcResult *r = (BcResult*) result; 277 278 BC_SIG_ASSERT_LOCKED; 279 280 assert(r != NULL); 281 282 switch (r->t) { 283 284 case BC_RESULT_TEMP: 285 case BC_RESULT_IBASE: 286 case BC_RESULT_SCALE: 287 case BC_RESULT_OBASE: 288 #if BC_ENABLE_EXTRA_MATH 289 case BC_RESULT_SEED: 290 #endif // BC_ENABLE_EXTRA_MATH 291 { 292 bc_num_free(&r->d.n); 293 break; 294 } 295 296 case BC_RESULT_VAR: 297 #if BC_ENABLED 298 case BC_RESULT_ARRAY: 299 #endif // BC_ENABLED 300 case BC_RESULT_ARRAY_ELEM: 301 case BC_RESULT_STR: 302 case BC_RESULT_CONSTANT: 303 case BC_RESULT_ONE: 304 #if BC_ENABLED 305 case BC_RESULT_VOID: 306 case BC_RESULT_LAST: 307 #endif // BC_ENABLED 308 { 309 // Do nothing. 310 break; 311 } 312 } 313 } 314