xref: /freebsd/contrib/bc/src/lang.c (revision 8036e7876d23145ca4bce797608e2ffb3c06a870)
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