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