xref: /freebsd/contrib/bc/src/lang.c (revision 44d4804d1945435745518cd09eb8ae6ab22ecef4)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
610328f8bSStefan Eßer  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7252884aeSStefan Eßer  *
8252884aeSStefan Eßer  * Redistribution and use in source and binary forms, with or without
9252884aeSStefan Eßer  * modification, are permitted provided that the following conditions are met:
10252884aeSStefan Eßer  *
11252884aeSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
12252884aeSStefan Eßer  *   list of conditions and the following disclaimer.
13252884aeSStefan Eßer  *
14252884aeSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
15252884aeSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
16252884aeSStefan Eßer  *   and/or other materials provided with the distribution.
17252884aeSStefan Eßer  *
18252884aeSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19252884aeSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20252884aeSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21252884aeSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22252884aeSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23252884aeSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24252884aeSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25252884aeSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26252884aeSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27252884aeSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28252884aeSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
29252884aeSStefan Eßer  *
30252884aeSStefan Eßer  * *****************************************************************************
31252884aeSStefan Eßer  *
32252884aeSStefan Eßer  * Code to manipulate data structures in programs.
33252884aeSStefan Eßer  *
34252884aeSStefan Eßer  */
35252884aeSStefan Eßer 
36252884aeSStefan Eßer #include <assert.h>
37252884aeSStefan Eßer #include <stdlib.h>
38252884aeSStefan Eßer #include <string.h>
39252884aeSStefan Eßer 
40252884aeSStefan Eßer #include <lang.h>
41*44d4804dSStefan Eßer #include <program.h>
42252884aeSStefan Eßer #include <vm.h>
43252884aeSStefan Eßer 
44252884aeSStefan Eßer void bc_const_free(void *constant) {
45*44d4804dSStefan Eßer 
46252884aeSStefan Eßer 	BcConst *c = constant;
47*44d4804dSStefan Eßer 
48252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
49*44d4804dSStefan Eßer 
50252884aeSStefan Eßer 	assert(c->val != NULL);
51*44d4804dSStefan Eßer 
52252884aeSStefan Eßer 	bc_num_free(&c->num);
53252884aeSStefan Eßer }
54252884aeSStefan Eßer 
55252884aeSStefan Eßer #if BC_ENABLED
56252884aeSStefan Eßer void bc_func_insert(BcFunc *f, BcProgram *p, char *name,
57252884aeSStefan Eßer                     BcType type, size_t line)
58252884aeSStefan Eßer {
59*44d4804dSStefan Eßer 	BcAuto a;
60252884aeSStefan Eßer 	size_t i, idx;
61252884aeSStefan Eßer 
62*44d4804dSStefan Eßer 	// The function must *always* be valid.
63252884aeSStefan Eßer 	assert(f != NULL);
64252884aeSStefan Eßer 
65*44d4804dSStefan Eßer 	// Get the index of the variable.
66252884aeSStefan Eßer 	idx = bc_program_search(p, name, type == BC_TYPE_VAR);
67252884aeSStefan Eßer 
68*44d4804dSStefan Eßer 	// Search through all of the other autos/parameters.
69252884aeSStefan Eßer 	for (i = 0; i < f->autos.len; ++i) {
70*44d4804dSStefan Eßer 
71*44d4804dSStefan Eßer 		// Get the auto.
72*44d4804dSStefan Eßer 		BcAuto *aptr = bc_vec_item(&f->autos, i);
73*44d4804dSStefan Eßer 
74*44d4804dSStefan Eßer 		// If they match, barf.
75*44d4804dSStefan Eßer 		if (BC_ERR(idx == aptr->idx && type == aptr->type)) {
76*44d4804dSStefan Eßer 
77252884aeSStefan Eßer 			const char *array = type == BC_TYPE_ARRAY ? "[]" : "";
78*44d4804dSStefan Eßer 
79*44d4804dSStefan Eßer 			bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);
80252884aeSStefan Eßer 		}
81252884aeSStefan Eßer 	}
82252884aeSStefan Eßer 
83*44d4804dSStefan Eßer 	// Set the auto.
84*44d4804dSStefan Eßer 	a.idx = idx;
85*44d4804dSStefan Eßer 	a.type = type;
86252884aeSStefan Eßer 
87*44d4804dSStefan Eßer 	// Push it.
88252884aeSStefan Eßer 	bc_vec_push(&f->autos, &a);
89252884aeSStefan Eßer }
90252884aeSStefan Eßer #endif // BC_ENABLED
91252884aeSStefan Eßer 
92252884aeSStefan Eßer void bc_func_init(BcFunc *f, const char *name) {
93252884aeSStefan Eßer 
94252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
95252884aeSStefan Eßer 
96252884aeSStefan Eßer 	assert(f != NULL && name != NULL);
97252884aeSStefan Eßer 
98*44d4804dSStefan Eßer 	bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
99252884aeSStefan Eßer 
100*44d4804dSStefan Eßer 	bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
101*44d4804dSStefan Eßer 
102*44d4804dSStefan Eßer 	bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
1033aa99676SStefan Eßer 
104252884aeSStefan Eßer #if BC_ENABLED
105*44d4804dSStefan Eßer 
106*44d4804dSStefan Eßer 	// Only bc needs these things.
107252884aeSStefan Eßer 	if (BC_IS_BC) {
1083aa99676SStefan Eßer 
109*44d4804dSStefan Eßer 		bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
110*44d4804dSStefan Eßer 		bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
1113aa99676SStefan Eßer 
112252884aeSStefan Eßer 		f->nparams = 0;
113252884aeSStefan Eßer 		f->voidfn = false;
114252884aeSStefan Eßer 	}
115*44d4804dSStefan Eßer 
116252884aeSStefan Eßer #endif // BC_ENABLED
1173aa99676SStefan Eßer 
118252884aeSStefan Eßer 	f->name = name;
119252884aeSStefan Eßer }
120252884aeSStefan Eßer 
121252884aeSStefan Eßer void bc_func_reset(BcFunc *f) {
1223aa99676SStefan Eßer 
123252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
124252884aeSStefan Eßer 	assert(f != NULL);
1253aa99676SStefan Eßer 
12610328f8bSStefan Eßer 	bc_vec_popAll(&f->code);
1273aa99676SStefan Eßer 
12810328f8bSStefan Eßer 	bc_vec_popAll(&f->consts);
1293aa99676SStefan Eßer 
130*44d4804dSStefan Eßer 	bc_vec_popAll(&f->strs);
131*44d4804dSStefan Eßer 
132252884aeSStefan Eßer #if BC_ENABLED
133252884aeSStefan Eßer 	if (BC_IS_BC) {
1343aa99676SStefan Eßer 
13510328f8bSStefan Eßer 		bc_vec_popAll(&f->autos);
13610328f8bSStefan Eßer 		bc_vec_popAll(&f->labels);
1373aa99676SStefan Eßer 
138252884aeSStefan Eßer 		f->nparams = 0;
139252884aeSStefan Eßer 		f->voidfn = false;
140252884aeSStefan Eßer 	}
141252884aeSStefan Eßer #endif // BC_ENABLED
142252884aeSStefan Eßer }
143252884aeSStefan Eßer 
144*44d4804dSStefan Eßer #ifndef NDEBUG
145252884aeSStefan Eßer void bc_func_free(void *func) {
1463aa99676SStefan Eßer 
147252884aeSStefan Eßer 	BcFunc *f = (BcFunc*) func;
1483aa99676SStefan Eßer 
149252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
150252884aeSStefan Eßer 	assert(f != NULL);
1513aa99676SStefan Eßer 
152252884aeSStefan Eßer 	bc_vec_free(&f->code);
1533aa99676SStefan Eßer 
154252884aeSStefan Eßer 	bc_vec_free(&f->consts);
1553aa99676SStefan Eßer 
1563aa99676SStefan Eßer 	bc_vec_free(&f->strs);
1573aa99676SStefan Eßer 
158*44d4804dSStefan Eßer #if BC_ENABLED
159*44d4804dSStefan Eßer 	if (BC_IS_BC) {
160*44d4804dSStefan Eßer 
161252884aeSStefan Eßer 		bc_vec_free(&f->autos);
162252884aeSStefan Eßer 		bc_vec_free(&f->labels);
163252884aeSStefan Eßer 	}
164252884aeSStefan Eßer #endif // BC_ENABLED
165252884aeSStefan Eßer }
166*44d4804dSStefan Eßer #endif // NDEBUG
167252884aeSStefan Eßer 
168252884aeSStefan Eßer void bc_array_init(BcVec *a, bool nums) {
169*44d4804dSStefan Eßer 
170252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
171*44d4804dSStefan Eßer 
172*44d4804dSStefan Eßer 	// Set the proper vector.
173*44d4804dSStefan Eßer 	if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
174*44d4804dSStefan Eßer 	else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
175*44d4804dSStefan Eßer 
176*44d4804dSStefan Eßer 	// We always want at least one item in the array.
177252884aeSStefan Eßer 	bc_array_expand(a, 1);
178252884aeSStefan Eßer }
179252884aeSStefan Eßer 
180252884aeSStefan Eßer void bc_array_copy(BcVec *d, const BcVec *s) {
181252884aeSStefan Eßer 
182252884aeSStefan Eßer 	size_t i;
183252884aeSStefan Eßer 
184252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
185252884aeSStefan Eßer 
186252884aeSStefan Eßer 	assert(d != NULL && s != NULL);
187252884aeSStefan Eßer 	assert(d != s && d->size == s->size && d->dtor == s->dtor);
188252884aeSStefan Eßer 
189*44d4804dSStefan Eßer 	// Make sure to destroy everything currently in d. This will put a lot of
190*44d4804dSStefan Eßer 	// temps on the reuse list, so allocating later is not going to be as
191*44d4804dSStefan Eßer 	// expensive as it seems. Also, it makes it easier to copy numbers that are
192*44d4804dSStefan Eßer 	// strings.
19310328f8bSStefan Eßer 	bc_vec_popAll(d);
194*44d4804dSStefan Eßer 
195*44d4804dSStefan Eßer 	// Preexpand.
196252884aeSStefan Eßer 	bc_vec_expand(d, s->cap);
197252884aeSStefan Eßer 	d->len = s->len;
198252884aeSStefan Eßer 
199252884aeSStefan Eßer 	for (i = 0; i < s->len; ++i) {
200*44d4804dSStefan Eßer 
201*44d4804dSStefan Eßer 		BcNum *dnum, *snum;
202*44d4804dSStefan Eßer 
203*44d4804dSStefan Eßer 		dnum = bc_vec_item(d, i);
204*44d4804dSStefan Eßer 		snum = bc_vec_item(s, i);
205*44d4804dSStefan Eßer 
206*44d4804dSStefan Eßer 		// We have to create a copy of the number as well.
207*44d4804dSStefan Eßer 		if (BC_PROG_STR(snum)) memcpy(dnum, snum, sizeof(BcNum));
208*44d4804dSStefan Eßer 		else bc_num_createCopy(dnum, snum);
209252884aeSStefan Eßer 	}
210252884aeSStefan Eßer }
211252884aeSStefan Eßer 
212252884aeSStefan Eßer void bc_array_expand(BcVec *a, size_t len) {
213252884aeSStefan Eßer 
214252884aeSStefan Eßer 	assert(a != NULL);
215252884aeSStefan Eßer 
216252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
217252884aeSStefan Eßer 
218252884aeSStefan Eßer 	bc_vec_expand(a, len);
219252884aeSStefan Eßer 
220*44d4804dSStefan Eßer 	// If this is true, then we have a num array.
221*44d4804dSStefan Eßer 	if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM) {
222*44d4804dSStefan Eßer 
223*44d4804dSStefan Eßer 		// Initialize numbers until we reach the target.
224252884aeSStefan Eßer 		while (len > a->len) {
225*44d4804dSStefan Eßer 			BcNum *n = bc_vec_pushEmpty(a);
226*44d4804dSStefan Eßer 			bc_num_init(n, BC_NUM_DEF_SIZE);
227252884aeSStefan Eßer 		}
228252884aeSStefan Eßer 	}
229252884aeSStefan Eßer 	else {
230*44d4804dSStefan Eßer 
231*44d4804dSStefan Eßer 		assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
232*44d4804dSStefan Eßer 
233*44d4804dSStefan Eßer 		// Recursively initialize arrays until we reach the target. Having the
234*44d4804dSStefan Eßer 		// second argument of bc_array_init() be true will activate the base
235*44d4804dSStefan Eßer 		// case, so we're safe.
236252884aeSStefan Eßer 		while (len > a->len) {
237*44d4804dSStefan Eßer 			BcVec *v = bc_vec_pushEmpty(a);
238*44d4804dSStefan Eßer 			bc_array_init(v, true);
239252884aeSStefan Eßer 		}
240252884aeSStefan Eßer 	}
241252884aeSStefan Eßer }
242252884aeSStefan Eßer 
243252884aeSStefan Eßer void bc_result_clear(BcResult *r) {
244252884aeSStefan Eßer 	r->t = BC_RESULT_TEMP;
245252884aeSStefan Eßer 	bc_num_clear(&r->d.n);
246252884aeSStefan Eßer }
247252884aeSStefan Eßer 
248252884aeSStefan Eßer #if DC_ENABLED
249252884aeSStefan Eßer void bc_result_copy(BcResult *d, BcResult *src) {
250252884aeSStefan Eßer 
251252884aeSStefan Eßer 	assert(d != NULL && src != NULL);
252252884aeSStefan Eßer 
253252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
254252884aeSStefan Eßer 
255*44d4804dSStefan Eßer 	// d is assumed to not be valid yet.
256252884aeSStefan Eßer 	d->t = src->t;
257252884aeSStefan Eßer 
258*44d4804dSStefan Eßer 	// Yes, it depends on what type.
259252884aeSStefan Eßer 	switch (d->t) {
260252884aeSStefan Eßer 
261252884aeSStefan Eßer 		case BC_RESULT_TEMP:
262252884aeSStefan Eßer 		case BC_RESULT_IBASE:
263252884aeSStefan Eßer 		case BC_RESULT_SCALE:
264252884aeSStefan Eßer 		case BC_RESULT_OBASE:
265252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
266252884aeSStefan Eßer 		case BC_RESULT_SEED:
267252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
268252884aeSStefan Eßer 		{
269252884aeSStefan Eßer 			bc_num_createCopy(&d->d.n, &src->d.n);
270252884aeSStefan Eßer 			break;
271252884aeSStefan Eßer 		}
272252884aeSStefan Eßer 
273252884aeSStefan Eßer 		case BC_RESULT_VAR:
274252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
275252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
276252884aeSStefan Eßer 		{
277252884aeSStefan Eßer 			memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
278252884aeSStefan Eßer 			break;
279252884aeSStefan Eßer 		}
280252884aeSStefan Eßer 
281252884aeSStefan Eßer 		case BC_RESULT_STR:
282252884aeSStefan Eßer 		{
283252884aeSStefan Eßer 			memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
284252884aeSStefan Eßer 			break;
285252884aeSStefan Eßer 		}
286252884aeSStefan Eßer 
2873aa99676SStefan Eßer 		case BC_RESULT_ZERO:
288252884aeSStefan Eßer 		case BC_RESULT_ONE:
289252884aeSStefan Eßer 		{
290252884aeSStefan Eßer 			// Do nothing.
291252884aeSStefan Eßer 			break;
292252884aeSStefan Eßer 		}
293252884aeSStefan Eßer 
294252884aeSStefan Eßer #if BC_ENABLED
295252884aeSStefan Eßer 		case BC_RESULT_VOID:
296252884aeSStefan Eßer 		case BC_RESULT_LAST:
297252884aeSStefan Eßer 		{
298252884aeSStefan Eßer #ifndef NDEBUG
299*44d4804dSStefan Eßer 			// We should *never* try copying either of these.
300252884aeSStefan Eßer 			abort();
301252884aeSStefan Eßer #endif // NDEBUG
302252884aeSStefan Eßer 		}
303252884aeSStefan Eßer #endif // BC_ENABLED
304252884aeSStefan Eßer 	}
305252884aeSStefan Eßer }
306252884aeSStefan Eßer #endif // DC_ENABLED
307252884aeSStefan Eßer 
308252884aeSStefan Eßer void bc_result_free(void *result) {
309252884aeSStefan Eßer 
310252884aeSStefan Eßer 	BcResult *r = (BcResult*) result;
311252884aeSStefan Eßer 
312252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
313252884aeSStefan Eßer 
314252884aeSStefan Eßer 	assert(r != NULL);
315252884aeSStefan Eßer 
316252884aeSStefan Eßer 	switch (r->t) {
317252884aeSStefan Eßer 
318252884aeSStefan Eßer 		case BC_RESULT_TEMP:
319252884aeSStefan Eßer 		case BC_RESULT_IBASE:
320252884aeSStefan Eßer 		case BC_RESULT_SCALE:
321252884aeSStefan Eßer 		case BC_RESULT_OBASE:
322252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
323252884aeSStefan Eßer 		case BC_RESULT_SEED:
324252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
325252884aeSStefan Eßer 		{
326252884aeSStefan Eßer 			bc_num_free(&r->d.n);
327252884aeSStefan Eßer 			break;
328252884aeSStefan Eßer 		}
329252884aeSStefan Eßer 
330252884aeSStefan Eßer 		case BC_RESULT_VAR:
331252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
332252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
333252884aeSStefan Eßer 		case BC_RESULT_STR:
3343aa99676SStefan Eßer 		case BC_RESULT_ZERO:
335252884aeSStefan Eßer 		case BC_RESULT_ONE:
336252884aeSStefan Eßer #if BC_ENABLED
337252884aeSStefan Eßer 		case BC_RESULT_VOID:
338252884aeSStefan Eßer 		case BC_RESULT_LAST:
339252884aeSStefan Eßer #endif // BC_ENABLED
340252884aeSStefan Eßer 		{
341252884aeSStefan Eßer 			// Do nothing.
342252884aeSStefan Eßer 			break;
343252884aeSStefan Eßer 		}
344252884aeSStefan Eßer 	}
345252884aeSStefan Eßer }
346