xref: /freebsd/contrib/bc/src/lang.c (revision 78bc019d220e05abb5b12f678f9b4a847019bbcc)
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>
4144d4804dSStefan Eßer #include <program.h>
42252884aeSStefan Eßer #include <vm.h>
43252884aeSStefan Eßer 
44*78bc019dSStefan Eßer void
45*78bc019dSStefan Eßer bc_const_free(void* constant)
46*78bc019dSStefan Eßer {
47252884aeSStefan Eßer 	BcConst* c = constant;
4844d4804dSStefan Eßer 
49252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
5044d4804dSStefan Eßer 
51252884aeSStefan Eßer 	assert(c->val != NULL);
5244d4804dSStefan Eßer 
53252884aeSStefan Eßer 	bc_num_free(&c->num);
54252884aeSStefan Eßer }
55252884aeSStefan Eßer 
56252884aeSStefan Eßer #if BC_ENABLED
57*78bc019dSStefan Eßer void
58*78bc019dSStefan Eßer bc_func_insert(BcFunc* f, BcProgram* p, char* name, BcType type, size_t line)
59252884aeSStefan Eßer {
6044d4804dSStefan Eßer 	BcAuto a;
61252884aeSStefan Eßer 	size_t i, idx;
62252884aeSStefan Eßer 
6344d4804dSStefan Eßer 	// The function must *always* be valid.
64252884aeSStefan Eßer 	assert(f != NULL);
65252884aeSStefan Eßer 
6644d4804dSStefan Eßer 	// Get the index of the variable.
67252884aeSStefan Eßer 	idx = bc_program_search(p, name, type == BC_TYPE_VAR);
68252884aeSStefan Eßer 
6944d4804dSStefan Eßer 	// Search through all of the other autos/parameters.
70*78bc019dSStefan Eßer 	for (i = 0; i < f->autos.len; ++i)
71*78bc019dSStefan Eßer 	{
7244d4804dSStefan Eßer 		// Get the auto.
7344d4804dSStefan Eßer 		BcAuto* aptr = bc_vec_item(&f->autos, i);
7444d4804dSStefan Eßer 
7544d4804dSStefan Eßer 		// If they match, barf.
76*78bc019dSStefan Eßer 		if (BC_ERR(idx == aptr->idx && type == aptr->type))
77*78bc019dSStefan Eßer 		{
78252884aeSStefan Eßer 			const char* array = type == BC_TYPE_ARRAY ? "[]" : "";
7944d4804dSStefan Eßer 
8044d4804dSStefan Eßer 			bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);
81252884aeSStefan Eßer 		}
82252884aeSStefan Eßer 	}
83252884aeSStefan Eßer 
8444d4804dSStefan Eßer 	// Set the auto.
8544d4804dSStefan Eßer 	a.idx = idx;
8644d4804dSStefan Eßer 	a.type = type;
87252884aeSStefan Eßer 
8844d4804dSStefan Eßer 	// Push it.
89252884aeSStefan Eßer 	bc_vec_push(&f->autos, &a);
90252884aeSStefan Eßer }
91252884aeSStefan Eßer #endif // BC_ENABLED
92252884aeSStefan Eßer 
93*78bc019dSStefan Eßer void
94*78bc019dSStefan Eßer bc_func_init(BcFunc* f, const char* name)
95*78bc019dSStefan Eßer {
96252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
97252884aeSStefan Eßer 
98252884aeSStefan Eßer 	assert(f != NULL && name != NULL);
99252884aeSStefan Eßer 
10044d4804dSStefan Eßer 	bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
101252884aeSStefan Eßer 
10244d4804dSStefan Eßer 	bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
10344d4804dSStefan Eßer 
10444d4804dSStefan Eßer 	bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
1053aa99676SStefan Eßer 
106252884aeSStefan Eßer #if BC_ENABLED
10744d4804dSStefan Eßer 
10844d4804dSStefan Eßer 	// Only bc needs these things.
109*78bc019dSStefan Eßer 	if (BC_IS_BC)
110*78bc019dSStefan Eßer 	{
11144d4804dSStefan Eßer 		bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
11244d4804dSStefan Eßer 		bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
1133aa99676SStefan Eßer 
114252884aeSStefan Eßer 		f->nparams = 0;
115252884aeSStefan Eßer 		f->voidfn = false;
116252884aeSStefan Eßer 	}
11744d4804dSStefan Eßer 
118252884aeSStefan Eßer #endif // BC_ENABLED
1193aa99676SStefan Eßer 
120252884aeSStefan Eßer 	f->name = name;
121252884aeSStefan Eßer }
122252884aeSStefan Eßer 
123*78bc019dSStefan Eßer void
124*78bc019dSStefan Eßer bc_func_reset(BcFunc* f)
125*78bc019dSStefan Eßer {
126252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
127252884aeSStefan Eßer 	assert(f != NULL);
1283aa99676SStefan Eßer 
12910328f8bSStefan Eßer 	bc_vec_popAll(&f->code);
1303aa99676SStefan Eßer 
13110328f8bSStefan Eßer 	bc_vec_popAll(&f->consts);
1323aa99676SStefan Eßer 
13344d4804dSStefan Eßer 	bc_vec_popAll(&f->strs);
13444d4804dSStefan Eßer 
135252884aeSStefan Eßer #if BC_ENABLED
136*78bc019dSStefan Eßer 	if (BC_IS_BC)
137*78bc019dSStefan Eßer 	{
13810328f8bSStefan Eßer 		bc_vec_popAll(&f->autos);
13910328f8bSStefan Eßer 		bc_vec_popAll(&f->labels);
1403aa99676SStefan Eßer 
141252884aeSStefan Eßer 		f->nparams = 0;
142252884aeSStefan Eßer 		f->voidfn = false;
143252884aeSStefan Eßer 	}
144252884aeSStefan Eßer #endif // BC_ENABLED
145252884aeSStefan Eßer }
146252884aeSStefan Eßer 
14744d4804dSStefan Eßer #ifndef NDEBUG
148*78bc019dSStefan Eßer void
149*78bc019dSStefan Eßer bc_func_free(void* func)
150*78bc019dSStefan Eßer {
151252884aeSStefan Eßer 	BcFunc* f = (BcFunc*) func;
1523aa99676SStefan Eßer 
153252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
154252884aeSStefan Eßer 	assert(f != NULL);
1553aa99676SStefan Eßer 
156252884aeSStefan Eßer 	bc_vec_free(&f->code);
1573aa99676SStefan Eßer 
158252884aeSStefan Eßer 	bc_vec_free(&f->consts);
1593aa99676SStefan Eßer 
1603aa99676SStefan Eßer 	bc_vec_free(&f->strs);
1613aa99676SStefan Eßer 
16244d4804dSStefan Eßer #if BC_ENABLED
163*78bc019dSStefan Eßer 	if (BC_IS_BC)
164*78bc019dSStefan Eßer 	{
165252884aeSStefan Eßer 		bc_vec_free(&f->autos);
166252884aeSStefan Eßer 		bc_vec_free(&f->labels);
167252884aeSStefan Eßer 	}
168252884aeSStefan Eßer #endif // BC_ENABLED
169252884aeSStefan Eßer }
17044d4804dSStefan Eßer #endif // NDEBUG
171252884aeSStefan Eßer 
172*78bc019dSStefan Eßer void
173*78bc019dSStefan Eßer bc_array_init(BcVec* a, bool nums)
174*78bc019dSStefan Eßer {
175252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
17644d4804dSStefan Eßer 
17744d4804dSStefan Eßer 	// Set the proper vector.
17844d4804dSStefan Eßer 	if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
17944d4804dSStefan Eßer 	else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
18044d4804dSStefan Eßer 
18144d4804dSStefan Eßer 	// We always want at least one item in the array.
182252884aeSStefan Eßer 	bc_array_expand(a, 1);
183252884aeSStefan Eßer }
184252884aeSStefan Eßer 
185*78bc019dSStefan Eßer void
186*78bc019dSStefan Eßer bc_array_copy(BcVec* d, const BcVec* s)
187*78bc019dSStefan Eßer {
188252884aeSStefan Eßer 	size_t i;
189252884aeSStefan Eßer 
190252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
191252884aeSStefan Eßer 
192252884aeSStefan Eßer 	assert(d != NULL && s != NULL);
193252884aeSStefan Eßer 	assert(d != s && d->size == s->size && d->dtor == s->dtor);
194252884aeSStefan Eßer 
19544d4804dSStefan Eßer 	// Make sure to destroy everything currently in d. This will put a lot of
19644d4804dSStefan Eßer 	// temps on the reuse list, so allocating later is not going to be as
19744d4804dSStefan Eßer 	// expensive as it seems. Also, it makes it easier to copy numbers that are
19844d4804dSStefan Eßer 	// strings.
19910328f8bSStefan Eßer 	bc_vec_popAll(d);
20044d4804dSStefan Eßer 
20144d4804dSStefan Eßer 	// Preexpand.
202252884aeSStefan Eßer 	bc_vec_expand(d, s->cap);
203252884aeSStefan Eßer 	d->len = s->len;
204252884aeSStefan Eßer 
205*78bc019dSStefan Eßer 	for (i = 0; i < s->len; ++i)
206*78bc019dSStefan Eßer 	{
207*78bc019dSStefan Eßer 		BcNum* dnum;
208*78bc019dSStefan Eßer 		BcNum* snum;
20944d4804dSStefan Eßer 
21044d4804dSStefan Eßer 		dnum = bc_vec_item(d, i);
21144d4804dSStefan Eßer 		snum = bc_vec_item(s, i);
21244d4804dSStefan Eßer 
21344d4804dSStefan Eßer 		// We have to create a copy of the number as well.
214*78bc019dSStefan Eßer 		if (BC_PROG_STR(snum))
215*78bc019dSStefan Eßer 		{
216*78bc019dSStefan Eßer 			// NOLINTNEXTLINE
217*78bc019dSStefan Eßer 			memcpy(dnum, snum, sizeof(BcNum));
218*78bc019dSStefan Eßer 		}
21944d4804dSStefan Eßer 		else bc_num_createCopy(dnum, snum);
220252884aeSStefan Eßer 	}
221252884aeSStefan Eßer }
222252884aeSStefan Eßer 
223*78bc019dSStefan Eßer void
224*78bc019dSStefan Eßer bc_array_expand(BcVec* a, size_t len)
225*78bc019dSStefan Eßer {
226252884aeSStefan Eßer 	assert(a != NULL);
227252884aeSStefan Eßer 
228252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
229252884aeSStefan Eßer 
230252884aeSStefan Eßer 	bc_vec_expand(a, len);
231252884aeSStefan Eßer 
23244d4804dSStefan Eßer 	// If this is true, then we have a num array.
233*78bc019dSStefan Eßer 	if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM)
234*78bc019dSStefan Eßer 	{
23544d4804dSStefan Eßer 		// Initialize numbers until we reach the target.
236*78bc019dSStefan Eßer 		while (len > a->len)
237*78bc019dSStefan Eßer 		{
23844d4804dSStefan Eßer 			BcNum* n = bc_vec_pushEmpty(a);
23944d4804dSStefan Eßer 			bc_num_init(n, BC_NUM_DEF_SIZE);
240252884aeSStefan Eßer 		}
241252884aeSStefan Eßer 	}
242*78bc019dSStefan Eßer 	else
243*78bc019dSStefan Eßer 	{
24444d4804dSStefan Eßer 		assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
24544d4804dSStefan Eßer 
24644d4804dSStefan Eßer 		// Recursively initialize arrays until we reach the target. Having the
24744d4804dSStefan Eßer 		// second argument of bc_array_init() be true will activate the base
24844d4804dSStefan Eßer 		// case, so we're safe.
249*78bc019dSStefan Eßer 		while (len > a->len)
250*78bc019dSStefan Eßer 		{
25144d4804dSStefan Eßer 			BcVec* v = bc_vec_pushEmpty(a);
25244d4804dSStefan Eßer 			bc_array_init(v, true);
253252884aeSStefan Eßer 		}
254252884aeSStefan Eßer 	}
255252884aeSStefan Eßer }
256252884aeSStefan Eßer 
257*78bc019dSStefan Eßer void
258*78bc019dSStefan Eßer bc_result_clear(BcResult* r)
259*78bc019dSStefan Eßer {
260252884aeSStefan Eßer 	r->t = BC_RESULT_TEMP;
261252884aeSStefan Eßer 	bc_num_clear(&r->d.n);
262252884aeSStefan Eßer }
263252884aeSStefan Eßer 
264252884aeSStefan Eßer #if DC_ENABLED
265*78bc019dSStefan Eßer void
266*78bc019dSStefan Eßer bc_result_copy(BcResult* d, BcResult* src)
267*78bc019dSStefan Eßer {
268252884aeSStefan Eßer 	assert(d != NULL && src != NULL);
269252884aeSStefan Eßer 
270252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
271252884aeSStefan Eßer 
27244d4804dSStefan Eßer 	// d is assumed to not be valid yet.
273252884aeSStefan Eßer 	d->t = src->t;
274252884aeSStefan Eßer 
27544d4804dSStefan Eßer 	// Yes, it depends on what type.
276*78bc019dSStefan Eßer 	switch (d->t)
277*78bc019dSStefan Eßer 	{
278252884aeSStefan Eßer 		case BC_RESULT_TEMP:
279252884aeSStefan Eßer 		case BC_RESULT_IBASE:
280252884aeSStefan Eßer 		case BC_RESULT_SCALE:
281252884aeSStefan Eßer 		case BC_RESULT_OBASE:
282252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
283252884aeSStefan Eßer 		case BC_RESULT_SEED:
284252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
285252884aeSStefan Eßer 		{
286252884aeSStefan Eßer 			bc_num_createCopy(&d->d.n, &src->d.n);
287252884aeSStefan Eßer 			break;
288252884aeSStefan Eßer 		}
289252884aeSStefan Eßer 
290252884aeSStefan Eßer 		case BC_RESULT_VAR:
291252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
292252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
293252884aeSStefan Eßer 		{
294*78bc019dSStefan Eßer 			// NOLINTNEXTLINE
295252884aeSStefan Eßer 			memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
296252884aeSStefan Eßer 			break;
297252884aeSStefan Eßer 		}
298252884aeSStefan Eßer 
299252884aeSStefan Eßer 		case BC_RESULT_STR:
300252884aeSStefan Eßer 		{
301*78bc019dSStefan Eßer 			// NOLINTNEXTLINE
302252884aeSStefan Eßer 			memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
303252884aeSStefan Eßer 			break;
304252884aeSStefan Eßer 		}
305252884aeSStefan Eßer 
3063aa99676SStefan Eßer 		case BC_RESULT_ZERO:
307252884aeSStefan Eßer 		case BC_RESULT_ONE:
308252884aeSStefan Eßer 		{
309252884aeSStefan Eßer 			// Do nothing.
310252884aeSStefan Eßer 			break;
311252884aeSStefan Eßer 		}
312252884aeSStefan Eßer 
313252884aeSStefan Eßer #if BC_ENABLED
314252884aeSStefan Eßer 		case BC_RESULT_VOID:
315252884aeSStefan Eßer 		case BC_RESULT_LAST:
316252884aeSStefan Eßer 		{
317252884aeSStefan Eßer #ifndef NDEBUG
31844d4804dSStefan Eßer 			// We should *never* try copying either of these.
319252884aeSStefan Eßer 			abort();
320252884aeSStefan Eßer #endif // NDEBUG
321252884aeSStefan Eßer 		}
322252884aeSStefan Eßer #endif // BC_ENABLED
323252884aeSStefan Eßer 	}
324252884aeSStefan Eßer }
325252884aeSStefan Eßer #endif // DC_ENABLED
326252884aeSStefan Eßer 
327*78bc019dSStefan Eßer void
328*78bc019dSStefan Eßer bc_result_free(void* result)
329*78bc019dSStefan Eßer {
330252884aeSStefan Eßer 	BcResult* r = (BcResult*) result;
331252884aeSStefan Eßer 
332252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
333252884aeSStefan Eßer 
334252884aeSStefan Eßer 	assert(r != NULL);
335252884aeSStefan Eßer 
336*78bc019dSStefan Eßer 	switch (r->t)
337*78bc019dSStefan Eßer 	{
338252884aeSStefan Eßer 		case BC_RESULT_TEMP:
339252884aeSStefan Eßer 		case BC_RESULT_IBASE:
340252884aeSStefan Eßer 		case BC_RESULT_SCALE:
341252884aeSStefan Eßer 		case BC_RESULT_OBASE:
342252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
343252884aeSStefan Eßer 		case BC_RESULT_SEED:
344252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
345252884aeSStefan Eßer 		{
346252884aeSStefan Eßer 			bc_num_free(&r->d.n);
347252884aeSStefan Eßer 			break;
348252884aeSStefan Eßer 		}
349252884aeSStefan Eßer 
350252884aeSStefan Eßer 		case BC_RESULT_VAR:
351252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
352252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
353252884aeSStefan Eßer 		case BC_RESULT_STR:
3543aa99676SStefan Eßer 		case BC_RESULT_ZERO:
355252884aeSStefan Eßer 		case BC_RESULT_ONE:
356252884aeSStefan Eßer #if BC_ENABLED
357252884aeSStefan Eßer 		case BC_RESULT_VOID:
358252884aeSStefan Eßer 		case BC_RESULT_LAST:
359252884aeSStefan Eßer #endif // BC_ENABLED
360252884aeSStefan Eßer 		{
361252884aeSStefan Eßer 			// Do nothing.
362252884aeSStefan Eßer 			break;
363252884aeSStefan Eßer 		}
364252884aeSStefan Eßer 	}
365252884aeSStefan Eßer }
366