xref: /freebsd/contrib/bc/src/lang.c (revision 103d7cdf)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6d101cdd6SStefan Eßer  * Copyright (c) 2018-2023 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 
4478bc019dSStefan Eßer void
bc_const_free(void * constant)4578bc019dSStefan Eßer bc_const_free(void* constant)
4678bc019dSStefan 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
5778bc019dSStefan Eßer void
bc_func_insert(BcFunc * f,BcProgram * p,char * name,BcType type,size_t line)5878bc019dSStefan 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.
7078bc019dSStefan Eßer 	for (i = 0; i < f->autos.len; ++i)
7178bc019dSStefan 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.
7678bc019dSStefan Eßer 		if (BC_ERR(idx == aptr->idx && type == aptr->type))
7778bc019dSStefan 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 
9378bc019dSStefan Eßer void
bc_func_init(BcFunc * f,const char * name)9478bc019dSStefan Eßer bc_func_init(BcFunc* f, const char* name)
9578bc019dSStefan 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 
102252884aeSStefan Eßer #if BC_ENABLED
10344d4804dSStefan Eßer 
10444d4804dSStefan Eßer 	// Only bc needs these things.
10578bc019dSStefan Eßer 	if (BC_IS_BC)
10678bc019dSStefan Eßer 	{
10744d4804dSStefan Eßer 		bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
10844d4804dSStefan Eßer 		bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
1093aa99676SStefan Eßer 
110252884aeSStefan Eßer 		f->nparams = 0;
111252884aeSStefan Eßer 		f->voidfn = false;
112252884aeSStefan Eßer 	}
11344d4804dSStefan Eßer 
114252884aeSStefan Eßer #endif // BC_ENABLED
1153aa99676SStefan Eßer 
116252884aeSStefan Eßer 	f->name = name;
117252884aeSStefan Eßer }
118252884aeSStefan Eßer 
11978bc019dSStefan Eßer void
bc_func_reset(BcFunc * f)12078bc019dSStefan Eßer bc_func_reset(BcFunc* f)
12178bc019dSStefan Eßer {
122252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
123252884aeSStefan Eßer 	assert(f != NULL);
1243aa99676SStefan Eßer 
12510328f8bSStefan Eßer 	bc_vec_popAll(&f->code);
1263aa99676SStefan Eßer 
127252884aeSStefan Eßer #if BC_ENABLED
12878bc019dSStefan Eßer 	if (BC_IS_BC)
12978bc019dSStefan Eßer 	{
13010328f8bSStefan Eßer 		bc_vec_popAll(&f->autos);
13110328f8bSStefan Eßer 		bc_vec_popAll(&f->labels);
1323aa99676SStefan Eßer 
133252884aeSStefan Eßer 		f->nparams = 0;
134252884aeSStefan Eßer 		f->voidfn = false;
135252884aeSStefan Eßer 	}
136252884aeSStefan Eßer #endif // BC_ENABLED
137252884aeSStefan Eßer }
138252884aeSStefan Eßer 
139103d7cdfSStefan Eßer #if BC_DEBUG
14078bc019dSStefan Eßer void
bc_func_free(void * func)14178bc019dSStefan Eßer bc_func_free(void* func)
14278bc019dSStefan Eßer {
143252884aeSStefan Eßer 	BcFunc* f = (BcFunc*) func;
1443aa99676SStefan Eßer 
145252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
146252884aeSStefan Eßer 	assert(f != NULL);
1473aa99676SStefan Eßer 
148252884aeSStefan Eßer 	bc_vec_free(&f->code);
1493aa99676SStefan Eßer 
15044d4804dSStefan Eßer #if BC_ENABLED
15178bc019dSStefan Eßer 	if (BC_IS_BC)
15278bc019dSStefan Eßer 	{
153252884aeSStefan Eßer 		bc_vec_free(&f->autos);
154252884aeSStefan Eßer 		bc_vec_free(&f->labels);
155252884aeSStefan Eßer 	}
156252884aeSStefan Eßer #endif // BC_ENABLED
157252884aeSStefan Eßer }
158103d7cdfSStefan Eßer #endif // BC_DEBUG
159252884aeSStefan Eßer 
16078bc019dSStefan Eßer void
bc_array_init(BcVec * a,bool nums)16178bc019dSStefan Eßer bc_array_init(BcVec* a, bool nums)
16278bc019dSStefan Eßer {
163252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
16444d4804dSStefan Eßer 
16544d4804dSStefan Eßer 	// Set the proper vector.
16644d4804dSStefan Eßer 	if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
16744d4804dSStefan Eßer 	else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
16844d4804dSStefan Eßer 
16944d4804dSStefan Eßer 	// We always want at least one item in the array.
170252884aeSStefan Eßer 	bc_array_expand(a, 1);
171252884aeSStefan Eßer }
172252884aeSStefan Eßer 
17378bc019dSStefan Eßer void
bc_array_copy(BcVec * d,const BcVec * s)17478bc019dSStefan Eßer bc_array_copy(BcVec* d, const BcVec* s)
17578bc019dSStefan Eßer {
176252884aeSStefan Eßer 	size_t i;
177252884aeSStefan Eßer 
178252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
179252884aeSStefan Eßer 
180252884aeSStefan Eßer 	assert(d != NULL && s != NULL);
181252884aeSStefan Eßer 	assert(d != s && d->size == s->size && d->dtor == s->dtor);
182252884aeSStefan Eßer 
18344d4804dSStefan Eßer 	// Make sure to destroy everything currently in d. This will put a lot of
18444d4804dSStefan Eßer 	// temps on the reuse list, so allocating later is not going to be as
18544d4804dSStefan Eßer 	// expensive as it seems. Also, it makes it easier to copy numbers that are
18644d4804dSStefan Eßer 	// strings.
18710328f8bSStefan Eßer 	bc_vec_popAll(d);
18844d4804dSStefan Eßer 
18944d4804dSStefan Eßer 	// Preexpand.
190252884aeSStefan Eßer 	bc_vec_expand(d, s->cap);
191252884aeSStefan Eßer 	d->len = s->len;
192252884aeSStefan Eßer 
19378bc019dSStefan Eßer 	for (i = 0; i < s->len; ++i)
19478bc019dSStefan Eßer 	{
19578bc019dSStefan Eßer 		BcNum* dnum;
19678bc019dSStefan Eßer 		BcNum* snum;
19744d4804dSStefan Eßer 
19844d4804dSStefan Eßer 		dnum = bc_vec_item(d, i);
19944d4804dSStefan Eßer 		snum = bc_vec_item(s, i);
20044d4804dSStefan Eßer 
20144d4804dSStefan Eßer 		// We have to create a copy of the number as well.
20278bc019dSStefan Eßer 		if (BC_PROG_STR(snum))
20378bc019dSStefan Eßer 		{
20478bc019dSStefan Eßer 			// NOLINTNEXTLINE
20578bc019dSStefan Eßer 			memcpy(dnum, snum, sizeof(BcNum));
20678bc019dSStefan Eßer 		}
20744d4804dSStefan Eßer 		else bc_num_createCopy(dnum, snum);
208252884aeSStefan Eßer 	}
209252884aeSStefan Eßer }
210252884aeSStefan Eßer 
21178bc019dSStefan Eßer void
bc_array_expand(BcVec * a,size_t len)21278bc019dSStefan Eßer bc_array_expand(BcVec* a, size_t len)
21378bc019dSStefan 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 
22044d4804dSStefan Eßer 	// If this is true, then we have a num array.
22178bc019dSStefan Eßer 	if (a->size == sizeof(BcNum) && a->dtor == BC_DTOR_NUM)
22278bc019dSStefan Eßer 	{
22344d4804dSStefan Eßer 		// Initialize numbers until we reach the target.
22478bc019dSStefan Eßer 		while (len > a->len)
22578bc019dSStefan Eßer 		{
22644d4804dSStefan Eßer 			BcNum* n = bc_vec_pushEmpty(a);
22744d4804dSStefan Eßer 			bc_num_init(n, BC_NUM_DEF_SIZE);
228252884aeSStefan Eßer 		}
229252884aeSStefan Eßer 	}
23078bc019dSStefan Eßer 	else
23178bc019dSStefan Eßer 	{
23244d4804dSStefan Eßer 		assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
23344d4804dSStefan Eßer 
23444d4804dSStefan Eßer 		// Recursively initialize arrays until we reach the target. Having the
23544d4804dSStefan Eßer 		// second argument of bc_array_init() be true will activate the base
23644d4804dSStefan Eßer 		// case, so we're safe.
23778bc019dSStefan Eßer 		while (len > a->len)
23878bc019dSStefan Eßer 		{
23944d4804dSStefan Eßer 			BcVec* v = bc_vec_pushEmpty(a);
24044d4804dSStefan Eßer 			bc_array_init(v, true);
241252884aeSStefan Eßer 		}
242252884aeSStefan Eßer 	}
243252884aeSStefan Eßer }
244252884aeSStefan Eßer 
24578bc019dSStefan Eßer void
bc_result_clear(BcResult * r)24678bc019dSStefan Eßer bc_result_clear(BcResult* r)
24778bc019dSStefan Eßer {
248252884aeSStefan Eßer 	r->t = BC_RESULT_TEMP;
249252884aeSStefan Eßer 	bc_num_clear(&r->d.n);
250252884aeSStefan Eßer }
251252884aeSStefan Eßer 
252252884aeSStefan Eßer #if DC_ENABLED
25378bc019dSStefan Eßer void
bc_result_copy(BcResult * d,BcResult * src)25478bc019dSStefan Eßer bc_result_copy(BcResult* d, BcResult* src)
25578bc019dSStefan Eßer {
256252884aeSStefan Eßer 	assert(d != NULL && src != NULL);
257252884aeSStefan Eßer 
258252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
259252884aeSStefan Eßer 
26044d4804dSStefan Eßer 	// d is assumed to not be valid yet.
261252884aeSStefan Eßer 	d->t = src->t;
262252884aeSStefan Eßer 
26344d4804dSStefan Eßer 	// Yes, it depends on what type.
26478bc019dSStefan Eßer 	switch (d->t)
26578bc019dSStefan Eßer 	{
266252884aeSStefan Eßer 		case BC_RESULT_TEMP:
267252884aeSStefan Eßer 		case BC_RESULT_IBASE:
268252884aeSStefan Eßer 		case BC_RESULT_SCALE:
269252884aeSStefan Eßer 		case BC_RESULT_OBASE:
270252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
271252884aeSStefan Eßer 		case BC_RESULT_SEED:
272252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
273252884aeSStefan Eßer 		{
274252884aeSStefan Eßer 			bc_num_createCopy(&d->d.n, &src->d.n);
275252884aeSStefan Eßer 			break;
276252884aeSStefan Eßer 		}
277252884aeSStefan Eßer 
278252884aeSStefan Eßer 		case BC_RESULT_VAR:
279252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
280252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
281252884aeSStefan Eßer 		{
28278bc019dSStefan Eßer 			// NOLINTNEXTLINE
283252884aeSStefan Eßer 			memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
284252884aeSStefan Eßer 			break;
285252884aeSStefan Eßer 		}
286252884aeSStefan Eßer 
287252884aeSStefan Eßer 		case BC_RESULT_STR:
288252884aeSStefan Eßer 		{
28978bc019dSStefan Eßer 			// NOLINTNEXTLINE
290252884aeSStefan Eßer 			memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
291252884aeSStefan Eßer 			break;
292252884aeSStefan Eßer 		}
293252884aeSStefan Eßer 
2943aa99676SStefan Eßer 		case BC_RESULT_ZERO:
295252884aeSStefan Eßer 		case BC_RESULT_ONE:
296252884aeSStefan Eßer 		{
297252884aeSStefan Eßer 			// Do nothing.
298252884aeSStefan Eßer 			break;
299252884aeSStefan Eßer 		}
300252884aeSStefan Eßer 
301252884aeSStefan Eßer #if BC_ENABLED
302252884aeSStefan Eßer 		case BC_RESULT_VOID:
303252884aeSStefan Eßer 		case BC_RESULT_LAST:
304252884aeSStefan Eßer 		{
305103d7cdfSStefan Eßer #if BC_DEBUG
30644d4804dSStefan Eßer 			// We should *never* try copying either of these.
307252884aeSStefan Eßer 			abort();
308103d7cdfSStefan Eßer #endif // BC_DEBUG
309252884aeSStefan Eßer 		}
310252884aeSStefan Eßer #endif // BC_ENABLED
311252884aeSStefan Eßer 	}
312252884aeSStefan Eßer }
313252884aeSStefan Eßer #endif // DC_ENABLED
314252884aeSStefan Eßer 
31578bc019dSStefan Eßer void
bc_result_free(void * result)31678bc019dSStefan Eßer bc_result_free(void* result)
31778bc019dSStefan Eßer {
318252884aeSStefan Eßer 	BcResult* r = (BcResult*) result;
319252884aeSStefan Eßer 
320252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
321252884aeSStefan Eßer 
322252884aeSStefan Eßer 	assert(r != NULL);
323252884aeSStefan Eßer 
32478bc019dSStefan Eßer 	switch (r->t)
32578bc019dSStefan Eßer 	{
326252884aeSStefan Eßer 		case BC_RESULT_TEMP:
327252884aeSStefan Eßer 		case BC_RESULT_IBASE:
328252884aeSStefan Eßer 		case BC_RESULT_SCALE:
329252884aeSStefan Eßer 		case BC_RESULT_OBASE:
330252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
331252884aeSStefan Eßer 		case BC_RESULT_SEED:
332252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
333252884aeSStefan Eßer 		{
334252884aeSStefan Eßer 			bc_num_free(&r->d.n);
335252884aeSStefan Eßer 			break;
336252884aeSStefan Eßer 		}
337252884aeSStefan Eßer 
338252884aeSStefan Eßer 		case BC_RESULT_VAR:
339252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
340252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
341252884aeSStefan Eßer 		case BC_RESULT_STR:
3423aa99676SStefan Eßer 		case BC_RESULT_ZERO:
343252884aeSStefan Eßer 		case BC_RESULT_ONE:
344252884aeSStefan Eßer #if BC_ENABLED
345252884aeSStefan Eßer 		case BC_RESULT_VOID:
346252884aeSStefan Eßer 		case BC_RESULT_LAST:
347252884aeSStefan Eßer #endif // BC_ENABLED
348252884aeSStefan Eßer 		{
349252884aeSStefan Eßer 			// Do nothing.
350252884aeSStefan Eßer 			break;
351252884aeSStefan Eßer 		}
352252884aeSStefan Eßer 	}
353252884aeSStefan Eßer }
354