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
bc_const_free(void * constant)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
bc_func_insert(BcFunc * f,BcProgram * p,char * name,BcType type,size_t line)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
bc_func_init(BcFunc * f,const char * name)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
bc_func_reset(BcFunc * f)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
bc_func_free(void * func)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
bc_array_init(BcVec * a,bool nums)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
bc_array_copy(BcVec * d,const BcVec * s)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
bc_array_expand(BcVec * a,size_t len)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
bc_result_clear(BcResult * r)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
bc_result_copy(BcResult * d,BcResult * src)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
bc_result_free(void * result)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