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