xref: /freebsd/contrib/bc/src/lang.c (revision 3aa99676b43a74a61fae17e19fd554e1937fa746)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
4*3aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6*3aa99676SStefan Eßer  * Copyright (c) 2018-2020 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>
41252884aeSStefan Eßer #include <vm.h>
42252884aeSStefan Eßer 
43252884aeSStefan Eßer #ifndef NDEBUG
44252884aeSStefan Eßer void bc_id_free(void *id) {
45252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
46252884aeSStefan Eßer 	assert(id != NULL);
47252884aeSStefan Eßer 	free(((BcId*) id)->name);
48252884aeSStefan Eßer }
49252884aeSStefan Eßer #endif // NDEBUG
50252884aeSStefan Eßer 
51252884aeSStefan Eßer void bc_string_free(void *string) {
52252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
53252884aeSStefan Eßer 	assert(string != NULL && (*((char**) string)) != NULL);
54252884aeSStefan Eßer 	if (BC_IS_BC) free(*((char**) string));
55252884aeSStefan Eßer }
56252884aeSStefan Eßer 
57252884aeSStefan Eßer void bc_const_free(void *constant) {
58252884aeSStefan Eßer 	BcConst *c = constant;
59252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
60252884aeSStefan Eßer 	assert(c->val != NULL);
61252884aeSStefan Eßer 	free(c->val);
62252884aeSStefan Eßer 	bc_num_free(&c->num);
63252884aeSStefan Eßer }
64252884aeSStefan Eßer 
65252884aeSStefan Eßer #if BC_ENABLED
66252884aeSStefan Eßer void bc_func_insert(BcFunc *f, BcProgram *p, char *name,
67252884aeSStefan Eßer                     BcType type, size_t line)
68252884aeSStefan Eßer {
69252884aeSStefan Eßer 	BcLoc a;
70252884aeSStefan Eßer 	size_t i, idx;
71252884aeSStefan Eßer 
72252884aeSStefan Eßer 	assert(f != NULL);
73252884aeSStefan Eßer 
74252884aeSStefan Eßer 	idx = bc_program_search(p, name, type == BC_TYPE_VAR);
75252884aeSStefan Eßer 
76252884aeSStefan Eßer 	for (i = 0; i < f->autos.len; ++i) {
77252884aeSStefan Eßer 		BcLoc *id = bc_vec_item(&f->autos, i);
78252884aeSStefan Eßer 		if (BC_ERR(idx == id->loc && type == (BcType) id->idx)) {
79252884aeSStefan Eßer 			const char *array = type == BC_TYPE_ARRAY ? "[]" : "";
80252884aeSStefan Eßer 			bc_vm_error(BC_ERROR_PARSE_DUP_LOCAL, line, name, array);
81252884aeSStefan Eßer 		}
82252884aeSStefan Eßer 	}
83252884aeSStefan Eßer 
84252884aeSStefan Eßer 	a.loc = idx;
85252884aeSStefan Eßer 	a.idx = type;
86252884aeSStefan Eßer 
87252884aeSStefan Eßer 	bc_vec_push(&f->autos, &a);
88252884aeSStefan Eßer }
89252884aeSStefan Eßer #endif // BC_ENABLED
90252884aeSStefan Eßer 
91252884aeSStefan Eßer void bc_func_init(BcFunc *f, const char *name) {
92252884aeSStefan Eßer 
93252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
94252884aeSStefan Eßer 
95252884aeSStefan Eßer 	assert(f != NULL && name != NULL);
96252884aeSStefan Eßer 
97252884aeSStefan Eßer 	bc_vec_init(&f->code, sizeof(uchar), NULL);
98252884aeSStefan Eßer 
99252884aeSStefan Eßer 	bc_vec_init(&f->consts, sizeof(BcConst), bc_const_free);
100*3aa99676SStefan Eßer 
101252884aeSStefan Eßer #if BC_ENABLED
102252884aeSStefan Eßer 	if (BC_IS_BC) {
103*3aa99676SStefan Eßer 
104*3aa99676SStefan Eßer 		bc_vec_init(&f->strs, sizeof(char*), bc_string_free);
105*3aa99676SStefan Eßer 
106252884aeSStefan Eßer 		bc_vec_init(&f->autos, sizeof(BcLoc), NULL);
107252884aeSStefan Eßer 		bc_vec_init(&f->labels, sizeof(size_t), NULL);
108*3aa99676SStefan Eßer 
109252884aeSStefan Eßer 		f->nparams = 0;
110252884aeSStefan Eßer 		f->voidfn = false;
111252884aeSStefan Eßer 	}
112252884aeSStefan Eßer #endif // BC_ENABLED
113*3aa99676SStefan Eßer 
114252884aeSStefan Eßer 	f->name = name;
115252884aeSStefan Eßer }
116252884aeSStefan Eßer 
117252884aeSStefan Eßer void bc_func_reset(BcFunc *f) {
118*3aa99676SStefan Eßer 
119252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
120252884aeSStefan Eßer 	assert(f != NULL);
121*3aa99676SStefan Eßer 
122252884aeSStefan Eßer 	bc_vec_npop(&f->code, f->code.len);
123*3aa99676SStefan Eßer 
124252884aeSStefan Eßer 	bc_vec_npop(&f->consts, f->consts.len);
125*3aa99676SStefan Eßer 
126252884aeSStefan Eßer #if BC_ENABLED
127252884aeSStefan Eßer 	if (BC_IS_BC) {
128*3aa99676SStefan Eßer 
129*3aa99676SStefan Eßer 		bc_vec_npop(&f->strs, f->strs.len);
130*3aa99676SStefan Eßer 
131252884aeSStefan Eßer 		bc_vec_npop(&f->autos, f->autos.len);
132252884aeSStefan Eßer 		bc_vec_npop(&f->labels, f->labels.len);
133*3aa99676SStefan Eßer 
134252884aeSStefan Eßer 		f->nparams = 0;
135252884aeSStefan Eßer 		f->voidfn = false;
136252884aeSStefan Eßer 	}
137252884aeSStefan Eßer #endif // BC_ENABLED
138252884aeSStefan Eßer }
139252884aeSStefan Eßer 
140252884aeSStefan Eßer void bc_func_free(void *func) {
141*3aa99676SStefan Eßer 
142252884aeSStefan Eßer #if BC_ENABLE_FUNC_FREE
143252884aeSStefan Eßer 
144252884aeSStefan Eßer 	BcFunc *f = (BcFunc*) func;
145*3aa99676SStefan Eßer 
146252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
147252884aeSStefan Eßer 	assert(f != NULL);
148*3aa99676SStefan Eßer 
149252884aeSStefan Eßer 	bc_vec_free(&f->code);
150*3aa99676SStefan Eßer 
151252884aeSStefan Eßer 	bc_vec_free(&f->consts);
152*3aa99676SStefan Eßer 
153252884aeSStefan Eßer #if BC_ENABLED
154252884aeSStefan Eßer #ifndef NDEBUG
155252884aeSStefan Eßer 	if (BC_IS_BC) {
156*3aa99676SStefan Eßer 
157*3aa99676SStefan Eßer 		bc_vec_free(&f->strs);
158*3aa99676SStefan Eßer 
159252884aeSStefan Eßer 		bc_vec_free(&f->autos);
160252884aeSStefan Eßer 		bc_vec_free(&f->labels);
161252884aeSStefan Eßer 	}
162252884aeSStefan Eßer #endif // NDEBUG
163252884aeSStefan Eßer #endif // BC_ENABLED
164252884aeSStefan Eßer 
165252884aeSStefan Eßer #else // BC_ENABLE_FUNC_FREE
166252884aeSStefan Eßer 	BC_UNUSED(func);
167252884aeSStefan Eßer #endif // BC_ENABLE_FUNC_FREE
168252884aeSStefan Eßer }
169252884aeSStefan Eßer 
170252884aeSStefan Eßer void bc_array_init(BcVec *a, bool nums) {
171252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
172252884aeSStefan Eßer 	if (nums) bc_vec_init(a, sizeof(BcNum), bc_num_free);
173252884aeSStefan Eßer 	else bc_vec_init(a, sizeof(BcVec), bc_vec_free);
174252884aeSStefan Eßer 	bc_array_expand(a, 1);
175252884aeSStefan Eßer }
176252884aeSStefan Eßer 
177252884aeSStefan Eßer void bc_array_copy(BcVec *d, const BcVec *s) {
178252884aeSStefan Eßer 
179252884aeSStefan Eßer 	size_t i;
180252884aeSStefan Eßer 
181252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
182252884aeSStefan Eßer 
183252884aeSStefan Eßer 	assert(d != NULL && s != NULL);
184252884aeSStefan Eßer 	assert(d != s && d->size == s->size && d->dtor == s->dtor);
185252884aeSStefan Eßer 
186252884aeSStefan Eßer 	bc_vec_npop(d, d->len);
187252884aeSStefan Eßer 	bc_vec_expand(d, s->cap);
188252884aeSStefan Eßer 	d->len = s->len;
189252884aeSStefan Eßer 
190252884aeSStefan Eßer 	for (i = 0; i < s->len; ++i) {
191252884aeSStefan Eßer 		BcNum *dnum = bc_vec_item(d, i), *snum = bc_vec_item(s, i);
192252884aeSStefan Eßer 		bc_num_createCopy(dnum, snum);
193252884aeSStefan Eßer 	}
194252884aeSStefan Eßer }
195252884aeSStefan Eßer 
196252884aeSStefan Eßer void bc_array_expand(BcVec *a, size_t len) {
197252884aeSStefan Eßer 
198252884aeSStefan Eßer 	assert(a != NULL);
199252884aeSStefan Eßer 
200252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
201252884aeSStefan Eßer 
202252884aeSStefan Eßer 	bc_vec_expand(a, len);
203252884aeSStefan Eßer 
204252884aeSStefan Eßer 	if (a->size == sizeof(BcNum) && a->dtor == bc_num_free) {
205252884aeSStefan Eßer 		BcNum n;
206252884aeSStefan Eßer 		while (len > a->len) {
207252884aeSStefan Eßer 			bc_num_init(&n, BC_NUM_DEF_SIZE);
208252884aeSStefan Eßer 			bc_vec_push(a, &n);
209252884aeSStefan Eßer 		}
210252884aeSStefan Eßer 	}
211252884aeSStefan Eßer 	else {
212252884aeSStefan Eßer 		BcVec v;
213252884aeSStefan Eßer 		assert(a->size == sizeof(BcVec) && a->dtor == bc_vec_free);
214252884aeSStefan Eßer 		while (len > a->len) {
215252884aeSStefan Eßer 			bc_array_init(&v, true);
216252884aeSStefan Eßer 			bc_vec_push(a, &v);
217252884aeSStefan Eßer 		}
218252884aeSStefan Eßer 	}
219252884aeSStefan Eßer }
220252884aeSStefan Eßer 
221252884aeSStefan Eßer void bc_result_clear(BcResult *r) {
222252884aeSStefan Eßer 	r->t = BC_RESULT_TEMP;
223252884aeSStefan Eßer 	bc_num_clear(&r->d.n);
224252884aeSStefan Eßer }
225252884aeSStefan Eßer 
226252884aeSStefan Eßer #if DC_ENABLED
227252884aeSStefan Eßer void bc_result_copy(BcResult *d, BcResult *src) {
228252884aeSStefan Eßer 
229252884aeSStefan Eßer 	assert(d != NULL && src != NULL);
230252884aeSStefan Eßer 
231252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
232252884aeSStefan Eßer 
233252884aeSStefan Eßer 	d->t = src->t;
234252884aeSStefan Eßer 
235252884aeSStefan Eßer 	switch (d->t) {
236252884aeSStefan Eßer 
237252884aeSStefan Eßer 		case BC_RESULT_TEMP:
238252884aeSStefan Eßer 		case BC_RESULT_IBASE:
239252884aeSStefan Eßer 		case BC_RESULT_SCALE:
240252884aeSStefan Eßer 		case BC_RESULT_OBASE:
241252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
242252884aeSStefan Eßer 		case BC_RESULT_SEED:
243252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
244252884aeSStefan Eßer 		{
245252884aeSStefan Eßer 			bc_num_createCopy(&d->d.n, &src->d.n);
246252884aeSStefan Eßer 			break;
247252884aeSStefan Eßer 		}
248252884aeSStefan Eßer 
249252884aeSStefan Eßer 		case BC_RESULT_VAR:
250252884aeSStefan Eßer #if BC_ENABLED
251252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
252252884aeSStefan Eßer #endif // BC_ENABLED
253252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
254252884aeSStefan Eßer 		{
255252884aeSStefan Eßer 			memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
256252884aeSStefan Eßer 			break;
257252884aeSStefan Eßer 		}
258252884aeSStefan Eßer 
259252884aeSStefan Eßer 		case BC_RESULT_STR:
260252884aeSStefan Eßer 		{
261252884aeSStefan Eßer 			memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
262252884aeSStefan Eßer 			break;
263252884aeSStefan Eßer 		}
264252884aeSStefan Eßer 
265*3aa99676SStefan Eßer 		case BC_RESULT_ZERO:
266252884aeSStefan Eßer 		case BC_RESULT_ONE:
267252884aeSStefan Eßer 		{
268252884aeSStefan Eßer 			// Do nothing.
269252884aeSStefan Eßer 			break;
270252884aeSStefan Eßer 		}
271252884aeSStefan Eßer 
272252884aeSStefan Eßer #if BC_ENABLED
273252884aeSStefan Eßer 		case BC_RESULT_VOID:
274252884aeSStefan Eßer 		case BC_RESULT_LAST:
275252884aeSStefan Eßer 		{
276252884aeSStefan Eßer #ifndef NDEBUG
277252884aeSStefan Eßer 			abort();
278252884aeSStefan Eßer #endif // NDEBUG
279252884aeSStefan Eßer 		}
280252884aeSStefan Eßer #endif // BC_ENABLED
281252884aeSStefan Eßer 	}
282252884aeSStefan Eßer }
283252884aeSStefan Eßer #endif // DC_ENABLED
284252884aeSStefan Eßer 
285252884aeSStefan Eßer void bc_result_free(void *result) {
286252884aeSStefan Eßer 
287252884aeSStefan Eßer 	BcResult *r = (BcResult*) result;
288252884aeSStefan Eßer 
289252884aeSStefan Eßer 	BC_SIG_ASSERT_LOCKED;
290252884aeSStefan Eßer 
291252884aeSStefan Eßer 	assert(r != NULL);
292252884aeSStefan Eßer 
293252884aeSStefan Eßer 	switch (r->t) {
294252884aeSStefan Eßer 
295252884aeSStefan Eßer 		case BC_RESULT_TEMP:
296252884aeSStefan Eßer 		case BC_RESULT_IBASE:
297252884aeSStefan Eßer 		case BC_RESULT_SCALE:
298252884aeSStefan Eßer 		case BC_RESULT_OBASE:
299252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
300252884aeSStefan Eßer 		case BC_RESULT_SEED:
301252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
302252884aeSStefan Eßer 		{
303252884aeSStefan Eßer 			bc_num_free(&r->d.n);
304252884aeSStefan Eßer 			break;
305252884aeSStefan Eßer 		}
306252884aeSStefan Eßer 
307252884aeSStefan Eßer 		case BC_RESULT_VAR:
308252884aeSStefan Eßer #if BC_ENABLED
309252884aeSStefan Eßer 		case BC_RESULT_ARRAY:
310252884aeSStefan Eßer #endif // BC_ENABLED
311252884aeSStefan Eßer 		case BC_RESULT_ARRAY_ELEM:
312252884aeSStefan Eßer 		case BC_RESULT_STR:
313*3aa99676SStefan Eßer 		case BC_RESULT_ZERO:
314252884aeSStefan Eßer 		case BC_RESULT_ONE:
315252884aeSStefan Eßer #if BC_ENABLED
316252884aeSStefan Eßer 		case BC_RESULT_VOID:
317252884aeSStefan Eßer 		case BC_RESULT_LAST:
318252884aeSStefan Eßer #endif // BC_ENABLED
319252884aeSStefan Eßer 		{
320252884aeSStefan Eßer 			// Do nothing.
321252884aeSStefan Eßer 			break;
322252884aeSStefan Eßer 		}
323252884aeSStefan Eßer 	}
324252884aeSStefan Eßer }
325