1 /*
2 * *****************************************************************************
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 *
6 * Copyright (c) 2018-2023 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 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
bc_func_insert(BcFunc * f,BcProgram * p,char * name,BcType type,size_t line)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
bc_func_init(BcFunc * f,const char * name)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
bc_func_reset(BcFunc * f)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
140 void
bc_func_free(void * func)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
159
160 void
bc_array_init(BcVec * a,bool nums)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
bc_array_copy(BcVec * d,const BcVec * s)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
bc_array_expand(BcVec * a,size_t len)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
bc_result_clear(BcResult * r)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
bc_result_copy(BcResult * d,BcResult * src)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
bc_result_free(void * result)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