]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/src/lang.c
usr.bin/gh-bc, contrib/bc: update to version 5.0.0
[FreeBSD/FreeBSD.git] / contrib / bc / src / lang.c
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 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
46         BcConst *c = constant;
47
48         BC_SIG_ASSERT_LOCKED;
49
50         assert(c->val != NULL);
51
52         bc_num_free(&c->num);
53 }
54
55 #if BC_ENABLED
56 void bc_func_insert(BcFunc *f, BcProgram *p, char *name,
57                     BcType type, size_t line)
58 {
59         BcAuto a;
60         size_t i, idx;
61
62         // The function must *always* be valid.
63         assert(f != NULL);
64
65         // Get the index of the variable.
66         idx = bc_program_search(p, name, type == BC_TYPE_VAR);
67
68         // Search through all of the other autos/parameters.
69         for (i = 0; i < f->autos.len; ++i) {
70
71                 // Get the auto.
72                 BcAuto *aptr = bc_vec_item(&f->autos, i);
73
74                 // If they match, barf.
75                 if (BC_ERR(idx == aptr->idx && type == aptr->type)) {
76
77                         const char *array = type == BC_TYPE_ARRAY ? "[]" : "";
78
79                         bc_error(BC_ERR_PARSE_DUP_LOCAL, line, name, array);
80                 }
81         }
82
83         // Set the auto.
84         a.idx = idx;
85         a.type = type;
86
87         // Push it.
88         bc_vec_push(&f->autos, &a);
89 }
90 #endif // BC_ENABLED
91
92 void bc_func_init(BcFunc *f, const char *name) {
93
94         BC_SIG_ASSERT_LOCKED;
95
96         assert(f != NULL && name != NULL);
97
98         bc_vec_init(&f->code, sizeof(uchar), BC_DTOR_NONE);
99
100         bc_vec_init(&f->consts, sizeof(BcConst), BC_DTOR_CONST);
101
102         bc_vec_init(&f->strs, sizeof(char*), BC_DTOR_NONE);
103
104 #if BC_ENABLED
105
106         // Only bc needs these things.
107         if (BC_IS_BC) {
108
109                 bc_vec_init(&f->autos, sizeof(BcAuto), BC_DTOR_NONE);
110                 bc_vec_init(&f->labels, sizeof(size_t), BC_DTOR_NONE);
111
112                 f->nparams = 0;
113                 f->voidfn = false;
114         }
115
116 #endif // BC_ENABLED
117
118         f->name = name;
119 }
120
121 void bc_func_reset(BcFunc *f) {
122
123         BC_SIG_ASSERT_LOCKED;
124         assert(f != NULL);
125
126         bc_vec_popAll(&f->code);
127
128         bc_vec_popAll(&f->consts);
129
130         bc_vec_popAll(&f->strs);
131
132 #if BC_ENABLED
133         if (BC_IS_BC) {
134
135                 bc_vec_popAll(&f->autos);
136                 bc_vec_popAll(&f->labels);
137
138                 f->nparams = 0;
139                 f->voidfn = false;
140         }
141 #endif // BC_ENABLED
142 }
143
144 #ifndef NDEBUG
145 void bc_func_free(void *func) {
146
147         BcFunc *f = (BcFunc*) func;
148
149         BC_SIG_ASSERT_LOCKED;
150         assert(f != NULL);
151
152         bc_vec_free(&f->code);
153
154         bc_vec_free(&f->consts);
155
156         bc_vec_free(&f->strs);
157
158 #if BC_ENABLED
159         if (BC_IS_BC) {
160
161                 bc_vec_free(&f->autos);
162                 bc_vec_free(&f->labels);
163         }
164 #endif // BC_ENABLED
165 }
166 #endif // NDEBUG
167
168 void bc_array_init(BcVec *a, bool nums) {
169
170         BC_SIG_ASSERT_LOCKED;
171
172         // Set the proper vector.
173         if (nums) bc_vec_init(a, sizeof(BcNum), BC_DTOR_NUM);
174         else bc_vec_init(a, sizeof(BcVec), BC_DTOR_VEC);
175
176         // We always want at least one item in the array.
177         bc_array_expand(a, 1);
178 }
179
180 void bc_array_copy(BcVec *d, const BcVec *s) {
181
182         size_t i;
183
184         BC_SIG_ASSERT_LOCKED;
185
186         assert(d != NULL && s != NULL);
187         assert(d != s && d->size == s->size && d->dtor == s->dtor);
188
189         // Make sure to destroy everything currently in d. This will put a lot of
190         // temps on the reuse list, so allocating later is not going to be as
191         // expensive as it seems. Also, it makes it easier to copy numbers that are
192         // strings.
193         bc_vec_popAll(d);
194
195         // Preexpand.
196         bc_vec_expand(d, s->cap);
197         d->len = s->len;
198
199         for (i = 0; i < s->len; ++i) {
200
201                 BcNum *dnum, *snum;
202
203                 dnum = bc_vec_item(d, i);
204                 snum = bc_vec_item(s, i);
205
206                 // We have to create a copy of the number as well.
207                 if (BC_PROG_STR(snum)) memcpy(dnum, snum, sizeof(BcNum));
208                 else bc_num_createCopy(dnum, snum);
209         }
210 }
211
212 void 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                         BcNum *n = bc_vec_pushEmpty(a);
226                         bc_num_init(n, BC_NUM_DEF_SIZE);
227                 }
228         }
229         else {
230
231                 assert(a->size == sizeof(BcVec) && a->dtor == BC_DTOR_VEC);
232
233                 // Recursively initialize arrays until we reach the target. Having the
234                 // second argument of bc_array_init() be true will activate the base
235                 // case, so we're safe.
236                 while (len > a->len) {
237                         BcVec *v = bc_vec_pushEmpty(a);
238                         bc_array_init(v, true);
239                 }
240         }
241 }
242
243 void bc_result_clear(BcResult *r) {
244         r->t = BC_RESULT_TEMP;
245         bc_num_clear(&r->d.n);
246 }
247
248 #if DC_ENABLED
249 void bc_result_copy(BcResult *d, BcResult *src) {
250
251         assert(d != NULL && src != NULL);
252
253         BC_SIG_ASSERT_LOCKED;
254
255         // d is assumed to not be valid yet.
256         d->t = src->t;
257
258         // Yes, it depends on what type.
259         switch (d->t) {
260
261                 case BC_RESULT_TEMP:
262                 case BC_RESULT_IBASE:
263                 case BC_RESULT_SCALE:
264                 case BC_RESULT_OBASE:
265 #if BC_ENABLE_EXTRA_MATH
266                 case BC_RESULT_SEED:
267 #endif // BC_ENABLE_EXTRA_MATH
268                 {
269                         bc_num_createCopy(&d->d.n, &src->d.n);
270                         break;
271                 }
272
273                 case BC_RESULT_VAR:
274                 case BC_RESULT_ARRAY:
275                 case BC_RESULT_ARRAY_ELEM:
276                 {
277                         memcpy(&d->d.loc, &src->d.loc, sizeof(BcLoc));
278                         break;
279                 }
280
281                 case BC_RESULT_STR:
282                 {
283                         memcpy(&d->d.n, &src->d.n, sizeof(BcNum));
284                         break;
285                 }
286
287                 case BC_RESULT_ZERO:
288                 case BC_RESULT_ONE:
289                 {
290                         // Do nothing.
291                         break;
292                 }
293
294 #if BC_ENABLED
295                 case BC_RESULT_VOID:
296                 case BC_RESULT_LAST:
297                 {
298 #ifndef NDEBUG
299                         // We should *never* try copying either of these.
300                         abort();
301 #endif // NDEBUG
302                 }
303 #endif // BC_ENABLED
304         }
305 }
306 #endif // DC_ENABLED
307
308 void bc_result_free(void *result) {
309
310         BcResult *r = (BcResult*) result;
311
312         BC_SIG_ASSERT_LOCKED;
313
314         assert(r != NULL);
315
316         switch (r->t) {
317
318                 case BC_RESULT_TEMP:
319                 case BC_RESULT_IBASE:
320                 case BC_RESULT_SCALE:
321                 case BC_RESULT_OBASE:
322 #if BC_ENABLE_EXTRA_MATH
323                 case BC_RESULT_SEED:
324 #endif // BC_ENABLE_EXTRA_MATH
325                 {
326                         bc_num_free(&r->d.n);
327                         break;
328                 }
329
330                 case BC_RESULT_VAR:
331                 case BC_RESULT_ARRAY:
332                 case BC_RESULT_ARRAY_ELEM:
333                 case BC_RESULT_STR:
334                 case BC_RESULT_ZERO:
335                 case BC_RESULT_ONE:
336 #if BC_ENABLED
337                 case BC_RESULT_VOID:
338                 case BC_RESULT_LAST:
339 #endif // BC_ENABLED
340                 {
341                         // Do nothing.
342                         break;
343                 }
344         }
345 }