xref: /freebsd/contrib/bc/src/lang.c (revision 1f1e2261e341e6ca6862f82261066ef1705f0a7a)
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 
44 void
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
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
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 	bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
103 
104 	bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
105 
106 #if BC_ENABLED
107 
108 	// Only bc needs these things.
109 	if (BC_IS_BC)
110 	{
111 		bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
112 		bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
113 
114 		f->nparams = 0;
115 		f->voidfn = false;
116 	}
117 
118 #endif // BC_ENABLED
119 
120 	f->name = name;
121 }
122 
123 void
124 bc_func_reset(BcFunc* f)
125 {
126 	BC_SIG_ASSERT_LOCKED;
127 	assert(f != NULL);
128 
129 	bc_vec_popAll(&f->code);
130 
131 	bc_vec_popAll(&f->consts);
132 
133 	bc_vec_popAll(&f->strs);
134 
135 #if BC_ENABLED
136 	if (BC_IS_BC)
137 	{
138 		bc_vec_popAll(&f->autos);
139 		bc_vec_popAll(&f->labels);
140 
141 		f->nparams = 0;
142 		f->voidfn = false;
143 	}
144 #endif // BC_ENABLED
145 }
146 
147 #ifndef NDEBUG
148 void
149 bc_func_free(void* func)
150 {
151 	BcFunc* f = (BcFunc*) func;
152 
153 	BC_SIG_ASSERT_LOCKED;
154 	assert(f != NULL);
155 
156 	bc_vec_free(&f->code);
157 
158 	bc_vec_free(&f->consts);
159 
160 	bc_vec_free(&f->strs);
161 
162 #if BC_ENABLED
163 	if (BC_IS_BC)
164 	{
165 		bc_vec_free(&f->autos);
166 		bc_vec_free(&f->labels);
167 	}
168 #endif // BC_ENABLED
169 }
170 #endif // NDEBUG
171 
172 void
173 bc_array_init(BcVec* a, bool nums)
174 {
175 	BC_SIG_ASSERT_LOCKED;
176 
177 	// Set the proper vector.
178 	if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
179 	else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
180 
181 	// We always want at least one item in the array.
182 	bc_array_expand(a, 1);
183 }
184 
185 void
186 bc_array_copy(BcVec* d, const BcVec* s)
187 {
188 	size_t i;
189 
190 	BC_SIG_ASSERT_LOCKED;
191 
192 	assert(d != NULL && s != NULL);
193 	assert(d != s && d->size == s->size && d->dtor == s->dtor);
194 
195 	// Make sure to destroy everything currently in d. This will put a lot of
196 	// temps on the reuse list, so allocating later is not going to be as
197 	// expensive as it seems. Also, it makes it easier to copy numbers that are
198 	// strings.
199 	bc_vec_popAll(d);
200 
201 	// Preexpand.
202 	bc_vec_expand(d, s->cap);
203 	d->len = s->len;
204 
205 	for (i = 0; i < s->len; ++i)
206 	{
207 		BcNum* dnum;
208 		BcNum* snum;
209 
210 		dnum = bc_vec_item(d, i);
211 		snum = bc_vec_item(s, i);
212 
213 		// We have to create a copy of the number as well.
214 		if (BC_PROG_STR(snum))
215 		{
216 			// NOLINTNEXTLINE
217 			memcpy(dnum, snum, sizeof(BcNum));
218 		}
219 		else bc_num_createCopy(dnum, snum);
220 	}
221 }
222 
223 void
224 bc_array_expand(BcVec* a, size_t len)
225 {
226 	assert(a != NULL);
227 
228 	BC_SIG_ASSERT_LOCKED;
229 
230 	bc_vec_expand(a, len);
231 
232 	// If this is true, then we have a num array.
233 	if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM)
234 	{
235 		// Initialize numbers until we reach the target.
236 		while (len > a->len)
237 		{
238 			BcNum* n = bc_vec_pushEmpty(a);
239 			bc_num_init(n, BC_NUM_DEF_SIZE);
240 		}
241 	}
242 	else
243 	{
244 		assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
245 
246 		// Recursively initialize arrays until we reach the target. Having the
247 		// second argument of bc_array_init() be true will activate the base
248 		// case, so we're safe.
249 		while (len > a->len)
250 		{
251 			BcVec* v = bc_vec_pushEmpty(a);
252 			bc_array_init(v, true);
253 		}
254 	}
255 }
256 
257 void
258 bc_result_clear(BcResult* r)
259 {
260 	r->t = BC_RESULT_TEMP;
261 	bc_num_clear(&r->d.n);
262 }
263 
264 #if DC_ENABLED
265 void
266 bc_result_copy(BcResult* d, BcResult* src)
267 {
268 	assert(d != NULL && src != NULL);
269 
270 	BC_SIG_ASSERT_LOCKED;
271 
272 	// d is assumed to not be valid yet.
273 	d->t = src->t;
274 
275 	// Yes, it depends on what type.
276 	switch (d->t)
277 	{
278 		case BC_RESULT_TEMP:
279 		case BC_RESULT_IBASE:
280 		case BC_RESULT_SCALE:
281 		case BC_RESULT_OBASE:
282 #if BC_ENABLE_EXTRA_MATH
283 		case BC_RESULT_SEED:
284 #endif // BC_ENABLE_EXTRA_MATH
285 		{
286 			bc_num_createCopy(&d->d.n, &src->d.n);
287 			break;
288 		}
289 
290 		case BC_RESULT_VAR:
291 		case BC_RESULT_ARRAY:
292 		case BC_RESULT_ARRAY_ELEM:
293 		{
294 			// NOLINTNEXTLINE
295 			memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
296 			break;
297 		}
298 
299 		case BC_RESULT_STR:
300 		{
301 			// NOLINTNEXTLINE
302 			memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
303 			break;
304 		}
305 
306 		case BC_RESULT_ZERO:
307 		case BC_RESULT_ONE:
308 		{
309 			// Do nothing.
310 			break;
311 		}
312 
313 #if BC_ENABLED
314 		case BC_RESULT_VOID:
315 		case BC_RESULT_LAST:
316 		{
317 #ifndef NDEBUG
318 			// We should *never* try copying either of these.
319 			abort();
320 #endif // NDEBUG
321 		}
322 #endif // BC_ENABLED
323 	}
324 }
325 #endif // DC_ENABLED
326 
327 void
328 bc_result_free(void* result)
329 {
330 	BcResult* r = (BcResult*) result;
331 
332 	BC_SIG_ASSERT_LOCKED;
333 
334 	assert(r != NULL);
335 
336 	switch (r->t)
337 	{
338 		case BC_RESULT_TEMP:
339 		case BC_RESULT_IBASE:
340 		case BC_RESULT_SCALE:
341 		case BC_RESULT_OBASE:
342 #if BC_ENABLE_EXTRA_MATH
343 		case BC_RESULT_SEED:
344 #endif // BC_ENABLE_EXTRA_MATH
345 		{
346 			bc_num_free(&r->d.n);
347 			break;
348 		}
349 
350 		case BC_RESULT_VAR:
351 		case BC_RESULT_ARRAY:
352 		case BC_RESULT_ARRAY_ELEM:
353 		case BC_RESULT_STR:
354 		case BC_RESULT_ZERO:
355 		case BC_RESULT_ONE:
356 #if BC_ENABLED
357 		case BC_RESULT_VOID:
358 		case BC_RESULT_LAST:
359 #endif // BC_ENABLED
360 		{
361 			// Do nothing.
362 			break;
363 		}
364 	}
365 }
366