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