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 <vm.h>
42
43 #ifndef NDEBUG
bc_id_free(void * id)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
bc_string_free(void * string)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
bc_const_free(void * constant)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
bc_func_insert(BcFunc * f,BcProgram * p,char * name,BcType type,size_t line)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_ERR_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
bc_func_init(BcFunc * f,const char * name)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
bc_func_reset(BcFunc * f)117 void bc_func_reset(BcFunc *f) {
118
119 BC_SIG_ASSERT_LOCKED;
120 assert(f != NULL);
121
122 bc_vec_popAll(&f->code);
123
124 bc_vec_popAll(&f->consts);
125
126 #if BC_ENABLED
127 if (BC_IS_BC) {
128
129 bc_vec_popAll(&f->strs);
130
131 bc_vec_popAll(&f->autos);
132 bc_vec_popAll(&f->labels);
133
134 f->nparams = 0;
135 f->voidfn = false;
136 }
137 #endif // BC_ENABLED
138 }
139
bc_func_free(void * func)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
bc_array_init(BcVec * a,bool nums)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
bc_array_copy(BcVec * d,const BcVec * s)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_popAll(d);
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
bc_array_expand(BcVec * a,size_t len)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
bc_result_clear(BcResult * r)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
bc_result_copy(BcResult * d,BcResult * src)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
bc_result_free(void * result)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