1*5a6e8488SAndroid Build Coastguard Worker /*
2*5a6e8488SAndroid Build Coastguard Worker * *****************************************************************************
3*5a6e8488SAndroid Build Coastguard Worker *
4*5a6e8488SAndroid Build Coastguard Worker * SPDX-License-Identifier: BSD-2-Clause
5*5a6e8488SAndroid Build Coastguard Worker *
6*5a6e8488SAndroid Build Coastguard Worker * Copyright (c) 2018-2024 Gavin D. Howard and contributors.
7*5a6e8488SAndroid Build Coastguard Worker *
8*5a6e8488SAndroid Build Coastguard Worker * Redistribution and use in source and binary forms, with or without
9*5a6e8488SAndroid Build Coastguard Worker * modification, are permitted provided that the following conditions are met:
10*5a6e8488SAndroid Build Coastguard Worker *
11*5a6e8488SAndroid Build Coastguard Worker * * Redistributions of source code must retain the above copyright notice, this
12*5a6e8488SAndroid Build Coastguard Worker * list of conditions and the following disclaimer.
13*5a6e8488SAndroid Build Coastguard Worker *
14*5a6e8488SAndroid Build Coastguard Worker * * Redistributions in binary form must reproduce the above copyright notice,
15*5a6e8488SAndroid Build Coastguard Worker * this list of conditions and the following disclaimer in the documentation
16*5a6e8488SAndroid Build Coastguard Worker * and/or other materials provided with the distribution.
17*5a6e8488SAndroid Build Coastguard Worker *
18*5a6e8488SAndroid Build Coastguard Worker * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19*5a6e8488SAndroid Build Coastguard Worker * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5a6e8488SAndroid Build Coastguard Worker * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5a6e8488SAndroid Build Coastguard Worker * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22*5a6e8488SAndroid Build Coastguard Worker * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*5a6e8488SAndroid Build Coastguard Worker * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*5a6e8488SAndroid Build Coastguard Worker * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*5a6e8488SAndroid Build Coastguard Worker * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*5a6e8488SAndroid Build Coastguard Worker * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*5a6e8488SAndroid Build Coastguard Worker * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*5a6e8488SAndroid Build Coastguard Worker * POSSIBILITY OF SUCH DAMAGE.
29*5a6e8488SAndroid Build Coastguard Worker *
30*5a6e8488SAndroid Build Coastguard Worker * *****************************************************************************
31*5a6e8488SAndroid Build Coastguard Worker *
32*5a6e8488SAndroid Build Coastguard Worker * Code to execute bc programs.
33*5a6e8488SAndroid Build Coastguard Worker *
34*5a6e8488SAndroid Build Coastguard Worker */
35*5a6e8488SAndroid Build Coastguard Worker
36*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
37*5a6e8488SAndroid Build Coastguard Worker #include <stdbool.h>
38*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
39*5a6e8488SAndroid Build Coastguard Worker
40*5a6e8488SAndroid Build Coastguard Worker #include <setjmp.h>
41*5a6e8488SAndroid Build Coastguard Worker
42*5a6e8488SAndroid Build Coastguard Worker #include <signal.h>
43*5a6e8488SAndroid Build Coastguard Worker
44*5a6e8488SAndroid Build Coastguard Worker #include <time.h>
45*5a6e8488SAndroid Build Coastguard Worker
46*5a6e8488SAndroid Build Coastguard Worker #include <read.h>
47*5a6e8488SAndroid Build Coastguard Worker #include <parse.h>
48*5a6e8488SAndroid Build Coastguard Worker #include <program.h>
49*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
50*5a6e8488SAndroid Build Coastguard Worker
51*5a6e8488SAndroid Build Coastguard Worker /**
52*5a6e8488SAndroid Build Coastguard Worker * Does a type check for something that expects a number.
53*5a6e8488SAndroid Build Coastguard Worker * @param r The result that will be checked.
54*5a6e8488SAndroid Build Coastguard Worker * @param n The result's number.
55*5a6e8488SAndroid Build Coastguard Worker */
56*5a6e8488SAndroid Build Coastguard Worker static inline void
bc_program_type_num(BcResult * r,BcNum * n)57*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(BcResult* r, BcNum* n)
58*5a6e8488SAndroid Build Coastguard Worker {
59*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
60*5a6e8488SAndroid Build Coastguard Worker
61*5a6e8488SAndroid Build Coastguard Worker // This should have already been taken care of.
62*5a6e8488SAndroid Build Coastguard Worker assert(r->t != BC_RESULT_VOID);
63*5a6e8488SAndroid Build Coastguard Worker
64*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
65*5a6e8488SAndroid Build Coastguard Worker
66*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_NUM(r, n))) bc_err(BC_ERR_EXEC_TYPE);
67*5a6e8488SAndroid Build Coastguard Worker }
68*5a6e8488SAndroid Build Coastguard Worker
69*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
70*5a6e8488SAndroid Build Coastguard Worker
71*5a6e8488SAndroid Build Coastguard Worker /**
72*5a6e8488SAndroid Build Coastguard Worker * Does a type check.
73*5a6e8488SAndroid Build Coastguard Worker * @param r The result to check.
74*5a6e8488SAndroid Build Coastguard Worker * @param t The type that the result should be.
75*5a6e8488SAndroid Build Coastguard Worker */
76*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_type_match(BcResult * r,BcType t)77*5a6e8488SAndroid Build Coastguard Worker bc_program_type_match(BcResult* r, BcType t)
78*5a6e8488SAndroid Build Coastguard Worker {
79*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR((r->t != BC_RESULT_ARRAY) != (!t))) bc_err(BC_ERR_EXEC_TYPE);
80*5a6e8488SAndroid Build Coastguard Worker }
81*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
82*5a6e8488SAndroid Build Coastguard Worker
83*5a6e8488SAndroid Build Coastguard Worker /**
84*5a6e8488SAndroid Build Coastguard Worker * Pulls an index out of a bytecode vector and updates the index into the vector
85*5a6e8488SAndroid Build Coastguard Worker * to point to the spot after the index. For more details on bytecode indices,
86*5a6e8488SAndroid Build Coastguard Worker * see the development manual (manuals/development.md#bytecode-indices).
87*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector.
88*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the index into the vector that will be
89*5a6e8488SAndroid Build Coastguard Worker * updated.
90*5a6e8488SAndroid Build Coastguard Worker * @return The index at @a bgn in the bytecode vector.
91*5a6e8488SAndroid Build Coastguard Worker */
92*5a6e8488SAndroid Build Coastguard Worker static size_t
bc_program_index(const char * restrict code,size_t * restrict bgn)93*5a6e8488SAndroid Build Coastguard Worker bc_program_index(const char* restrict code, size_t* restrict bgn)
94*5a6e8488SAndroid Build Coastguard Worker {
95*5a6e8488SAndroid Build Coastguard Worker uchar amt = (uchar) code[(*bgn)++], i = 0;
96*5a6e8488SAndroid Build Coastguard Worker size_t res = 0;
97*5a6e8488SAndroid Build Coastguard Worker
98*5a6e8488SAndroid Build Coastguard Worker for (; i < amt; ++i, ++(*bgn))
99*5a6e8488SAndroid Build Coastguard Worker {
100*5a6e8488SAndroid Build Coastguard Worker size_t temp = ((size_t) ((int) (uchar) code[*bgn]) & UCHAR_MAX);
101*5a6e8488SAndroid Build Coastguard Worker res |= (temp << (i * CHAR_BIT));
102*5a6e8488SAndroid Build Coastguard Worker }
103*5a6e8488SAndroid Build Coastguard Worker
104*5a6e8488SAndroid Build Coastguard Worker return res;
105*5a6e8488SAndroid Build Coastguard Worker }
106*5a6e8488SAndroid Build Coastguard Worker
107*5a6e8488SAndroid Build Coastguard Worker /**
108*5a6e8488SAndroid Build Coastguard Worker * Returns a string from a result and its number.
109*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
110*5a6e8488SAndroid Build Coastguard Worker * @param n The number tied to the result.
111*5a6e8488SAndroid Build Coastguard Worker * @return The string corresponding to the result and number.
112*5a6e8488SAndroid Build Coastguard Worker */
113*5a6e8488SAndroid Build Coastguard Worker static inline char*
bc_program_string(BcProgram * p,const BcNum * n)114*5a6e8488SAndroid Build Coastguard Worker bc_program_string(BcProgram* p, const BcNum* n)
115*5a6e8488SAndroid Build Coastguard Worker {
116*5a6e8488SAndroid Build Coastguard Worker return *((char**) bc_vec_item(&p->strs, n->scale));
117*5a6e8488SAndroid Build Coastguard Worker }
118*5a6e8488SAndroid Build Coastguard Worker
119*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
120*5a6e8488SAndroid Build Coastguard Worker
121*5a6e8488SAndroid Build Coastguard Worker /**
122*5a6e8488SAndroid Build Coastguard Worker * Prepares the globals for a function call. This is only called when global
123*5a6e8488SAndroid Build Coastguard Worker * stacks are on because it pushes a copy of the current globals onto each of
124*5a6e8488SAndroid Build Coastguard Worker * their respective stacks.
125*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
126*5a6e8488SAndroid Build Coastguard Worker */
127*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_prepGlobals(BcProgram * p)128*5a6e8488SAndroid Build Coastguard Worker bc_program_prepGlobals(BcProgram* p)
129*5a6e8488SAndroid Build Coastguard Worker {
130*5a6e8488SAndroid Build Coastguard Worker size_t i;
131*5a6e8488SAndroid Build Coastguard Worker
132*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
133*5a6e8488SAndroid Build Coastguard Worker {
134*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(p->globals_v + i, p->globals + i);
135*5a6e8488SAndroid Build Coastguard Worker }
136*5a6e8488SAndroid Build Coastguard Worker
137*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
138*5a6e8488SAndroid Build Coastguard Worker bc_rand_push(&p->rng);
139*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
140*5a6e8488SAndroid Build Coastguard Worker }
141*5a6e8488SAndroid Build Coastguard Worker
142*5a6e8488SAndroid Build Coastguard Worker /**
143*5a6e8488SAndroid Build Coastguard Worker * Pops globals stacks on returning from a function, or in the case of reset,
144*5a6e8488SAndroid Build Coastguard Worker * pops all but one item on each global stack.
145*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
146*5a6e8488SAndroid Build Coastguard Worker * @param reset True if all but one item on each stack should be popped, false
147*5a6e8488SAndroid Build Coastguard Worker * otherwise.
148*5a6e8488SAndroid Build Coastguard Worker */
149*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_popGlobals(BcProgram * p,bool reset)150*5a6e8488SAndroid Build Coastguard Worker bc_program_popGlobals(BcProgram* p, bool reset)
151*5a6e8488SAndroid Build Coastguard Worker {
152*5a6e8488SAndroid Build Coastguard Worker size_t i;
153*5a6e8488SAndroid Build Coastguard Worker
154*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
155*5a6e8488SAndroid Build Coastguard Worker
156*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
157*5a6e8488SAndroid Build Coastguard Worker {
158*5a6e8488SAndroid Build Coastguard Worker BcVec* v = p->globals_v + i;
159*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(v, reset ? v->len - 1 : 1);
160*5a6e8488SAndroid Build Coastguard Worker p->globals[i] = BC_PROG_GLOBAL(v);
161*5a6e8488SAndroid Build Coastguard Worker }
162*5a6e8488SAndroid Build Coastguard Worker
163*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
164*5a6e8488SAndroid Build Coastguard Worker bc_rand_pop(&p->rng, reset);
165*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
166*5a6e8488SAndroid Build Coastguard Worker }
167*5a6e8488SAndroid Build Coastguard Worker
168*5a6e8488SAndroid Build Coastguard Worker /**
169*5a6e8488SAndroid Build Coastguard Worker * Derefeneces an array reference and returns a pointer to the real array.
170*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
171*5a6e8488SAndroid Build Coastguard Worker * @param vec The reference vector.
172*5a6e8488SAndroid Build Coastguard Worker * @return A pointer to the desired array.
173*5a6e8488SAndroid Build Coastguard Worker */
174*5a6e8488SAndroid Build Coastguard Worker static BcVec*
bc_program_dereference(const BcProgram * p,BcVec * vec)175*5a6e8488SAndroid Build Coastguard Worker bc_program_dereference(const BcProgram* p, BcVec* vec)
176*5a6e8488SAndroid Build Coastguard Worker {
177*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
178*5a6e8488SAndroid Build Coastguard Worker size_t vidx, nidx, i = 0;
179*5a6e8488SAndroid Build Coastguard Worker
180*5a6e8488SAndroid Build Coastguard Worker // We want to be sure we have a reference vector.
181*5a6e8488SAndroid Build Coastguard Worker assert(vec->size == sizeof(uchar));
182*5a6e8488SAndroid Build Coastguard Worker
183*5a6e8488SAndroid Build Coastguard Worker // Get the index of the vector in arrs, then the index of the original
184*5a6e8488SAndroid Build Coastguard Worker // referenced vector.
185*5a6e8488SAndroid Build Coastguard Worker vidx = bc_program_index(vec->v, &i);
186*5a6e8488SAndroid Build Coastguard Worker nidx = bc_program_index(vec->v, &i);
187*5a6e8488SAndroid Build Coastguard Worker
188*5a6e8488SAndroid Build Coastguard Worker v = bc_vec_item(bc_vec_item(&p->arrs, vidx), nidx);
189*5a6e8488SAndroid Build Coastguard Worker
190*5a6e8488SAndroid Build Coastguard Worker // We want to be sure we do *not* have a reference vector.
191*5a6e8488SAndroid Build Coastguard Worker assert(v->size != sizeof(uchar));
192*5a6e8488SAndroid Build Coastguard Worker
193*5a6e8488SAndroid Build Coastguard Worker return v;
194*5a6e8488SAndroid Build Coastguard Worker }
195*5a6e8488SAndroid Build Coastguard Worker
196*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
197*5a6e8488SAndroid Build Coastguard Worker
198*5a6e8488SAndroid Build Coastguard Worker /**
199*5a6e8488SAndroid Build Coastguard Worker * Creates a BcNum from a BcBigDig and pushes onto the results stack. This is a
200*5a6e8488SAndroid Build Coastguard Worker * convenience function.
201*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
202*5a6e8488SAndroid Build Coastguard Worker * @param dig The BcBigDig to push onto the results stack.
203*5a6e8488SAndroid Build Coastguard Worker * @param type The type that the pushed result should be.
204*5a6e8488SAndroid Build Coastguard Worker */
205*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_pushBigdig(BcProgram * p,BcBigDig dig,BcResultType type)206*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(BcProgram* p, BcBigDig dig, BcResultType type)
207*5a6e8488SAndroid Build Coastguard Worker {
208*5a6e8488SAndroid Build Coastguard Worker BcResult res;
209*5a6e8488SAndroid Build Coastguard Worker
210*5a6e8488SAndroid Build Coastguard Worker res.t = type;
211*5a6e8488SAndroid Build Coastguard Worker
212*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
213*5a6e8488SAndroid Build Coastguard Worker
214*5a6e8488SAndroid Build Coastguard Worker bc_num_createFromBigdig(&res.d.n, dig);
215*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &res);
216*5a6e8488SAndroid Build Coastguard Worker
217*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
218*5a6e8488SAndroid Build Coastguard Worker }
219*5a6e8488SAndroid Build Coastguard Worker
220*5a6e8488SAndroid Build Coastguard Worker size_t
bc_program_addString(BcProgram * p,const char * str)221*5a6e8488SAndroid Build Coastguard Worker bc_program_addString(BcProgram* p, const char* str)
222*5a6e8488SAndroid Build Coastguard Worker {
223*5a6e8488SAndroid Build Coastguard Worker size_t idx;
224*5a6e8488SAndroid Build Coastguard Worker
225*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
226*5a6e8488SAndroid Build Coastguard Worker
227*5a6e8488SAndroid Build Coastguard Worker if (bc_map_insert(&p->str_map, str, p->strs.len, &idx))
228*5a6e8488SAndroid Build Coastguard Worker {
229*5a6e8488SAndroid Build Coastguard Worker char** str_ptr;
230*5a6e8488SAndroid Build Coastguard Worker BcId* id = bc_vec_item(&p->str_map, idx);
231*5a6e8488SAndroid Build Coastguard Worker
232*5a6e8488SAndroid Build Coastguard Worker // Get the index.
233*5a6e8488SAndroid Build Coastguard Worker idx = id->idx;
234*5a6e8488SAndroid Build Coastguard Worker
235*5a6e8488SAndroid Build Coastguard Worker // Push an empty string on the proper vector.
236*5a6e8488SAndroid Build Coastguard Worker str_ptr = bc_vec_pushEmpty(&p->strs);
237*5a6e8488SAndroid Build Coastguard Worker
238*5a6e8488SAndroid Build Coastguard Worker // We reuse the string in the ID (allocated by bc_map_insert()), because
239*5a6e8488SAndroid Build Coastguard Worker // why not?
240*5a6e8488SAndroid Build Coastguard Worker *str_ptr = id->name;
241*5a6e8488SAndroid Build Coastguard Worker }
242*5a6e8488SAndroid Build Coastguard Worker else
243*5a6e8488SAndroid Build Coastguard Worker {
244*5a6e8488SAndroid Build Coastguard Worker BcId* id = bc_vec_item(&p->str_map, idx);
245*5a6e8488SAndroid Build Coastguard Worker idx = id->idx;
246*5a6e8488SAndroid Build Coastguard Worker }
247*5a6e8488SAndroid Build Coastguard Worker
248*5a6e8488SAndroid Build Coastguard Worker return idx;
249*5a6e8488SAndroid Build Coastguard Worker }
250*5a6e8488SAndroid Build Coastguard Worker
251*5a6e8488SAndroid Build Coastguard Worker size_t
bc_program_search(BcProgram * p,const char * name,bool var)252*5a6e8488SAndroid Build Coastguard Worker bc_program_search(BcProgram* p, const char* name, bool var)
253*5a6e8488SAndroid Build Coastguard Worker {
254*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
255*5a6e8488SAndroid Build Coastguard Worker BcVec* map;
256*5a6e8488SAndroid Build Coastguard Worker size_t i;
257*5a6e8488SAndroid Build Coastguard Worker
258*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
259*5a6e8488SAndroid Build Coastguard Worker
260*5a6e8488SAndroid Build Coastguard Worker // Grab the right vector and map.
261*5a6e8488SAndroid Build Coastguard Worker v = var ? &p->vars : &p->arrs;
262*5a6e8488SAndroid Build Coastguard Worker map = var ? &p->var_map : &p->arr_map;
263*5a6e8488SAndroid Build Coastguard Worker
264*5a6e8488SAndroid Build Coastguard Worker // We do an insert because the variable might not exist yet. This is because
265*5a6e8488SAndroid Build Coastguard Worker // the parser calls this function. If the insert succeeds, we create a stack
266*5a6e8488SAndroid Build Coastguard Worker // for the variable/array. But regardless, bc_map_insert() gives us the
267*5a6e8488SAndroid Build Coastguard Worker // index of the item in i.
268*5a6e8488SAndroid Build Coastguard Worker if (bc_map_insert(map, name, v->len, &i))
269*5a6e8488SAndroid Build Coastguard Worker {
270*5a6e8488SAndroid Build Coastguard Worker BcVec* temp = bc_vec_pushEmpty(v);
271*5a6e8488SAndroid Build Coastguard Worker bc_array_init(temp, var);
272*5a6e8488SAndroid Build Coastguard Worker }
273*5a6e8488SAndroid Build Coastguard Worker
274*5a6e8488SAndroid Build Coastguard Worker return ((BcId*) bc_vec_item(map, i))->idx;
275*5a6e8488SAndroid Build Coastguard Worker }
276*5a6e8488SAndroid Build Coastguard Worker
277*5a6e8488SAndroid Build Coastguard Worker /**
278*5a6e8488SAndroid Build Coastguard Worker * Returns the correct variable or array stack for the type.
279*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
280*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the variable or array in the variable or array
281*5a6e8488SAndroid Build Coastguard Worker * vector.
282*5a6e8488SAndroid Build Coastguard Worker * @param type The type of vector to return.
283*5a6e8488SAndroid Build Coastguard Worker * @return A pointer to the variable or array stack.
284*5a6e8488SAndroid Build Coastguard Worker */
285*5a6e8488SAndroid Build Coastguard Worker static inline BcVec*
bc_program_vec(const BcProgram * p,size_t idx,BcType type)286*5a6e8488SAndroid Build Coastguard Worker bc_program_vec(const BcProgram* p, size_t idx, BcType type)
287*5a6e8488SAndroid Build Coastguard Worker {
288*5a6e8488SAndroid Build Coastguard Worker const BcVec* v = (type == BC_TYPE_VAR) ? &p->vars : &p->arrs;
289*5a6e8488SAndroid Build Coastguard Worker return bc_vec_item(v, idx);
290*5a6e8488SAndroid Build Coastguard Worker }
291*5a6e8488SAndroid Build Coastguard Worker
292*5a6e8488SAndroid Build Coastguard Worker /**
293*5a6e8488SAndroid Build Coastguard Worker * Returns a pointer to the BcNum corresponding to the result. There is one
294*5a6e8488SAndroid Build Coastguard Worker * case, however, where this returns a pointer to a BcVec: if the type of the
295*5a6e8488SAndroid Build Coastguard Worker * result is array. In that case, the pointer is casted to a pointer to BcNum,
296*5a6e8488SAndroid Build Coastguard Worker * but is never used. The function that calls this expecting an array casts the
297*5a6e8488SAndroid Build Coastguard Worker * pointer back. This function is called a lot and needs to be as fast as
298*5a6e8488SAndroid Build Coastguard Worker * possible.
299*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
300*5a6e8488SAndroid Build Coastguard Worker * @param r The result whose number will be returned.
301*5a6e8488SAndroid Build Coastguard Worker * @return The BcNum corresponding to the result.
302*5a6e8488SAndroid Build Coastguard Worker */
303*5a6e8488SAndroid Build Coastguard Worker static BcNum*
bc_program_num(BcProgram * p,BcResult * r)304*5a6e8488SAndroid Build Coastguard Worker bc_program_num(BcProgram* p, BcResult* r)
305*5a6e8488SAndroid Build Coastguard Worker {
306*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
307*5a6e8488SAndroid Build Coastguard Worker
308*5a6e8488SAndroid Build Coastguard Worker #ifdef _WIN32
309*5a6e8488SAndroid Build Coastguard Worker // Windows made it an error to not initialize this, so shut it up.
310*5a6e8488SAndroid Build Coastguard Worker // I don't want to do this on other platforms because this procedure
311*5a6e8488SAndroid Build Coastguard Worker // is one of the most heavily-used, and eliminating the initialization
312*5a6e8488SAndroid Build Coastguard Worker // is a performance win.
313*5a6e8488SAndroid Build Coastguard Worker n = NULL;
314*5a6e8488SAndroid Build Coastguard Worker #endif // _WIN32
315*5a6e8488SAndroid Build Coastguard Worker
316*5a6e8488SAndroid Build Coastguard Worker switch (r->t)
317*5a6e8488SAndroid Build Coastguard Worker {
318*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_STR:
319*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_TEMP:
320*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_IBASE:
321*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_SCALE:
322*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_OBASE:
323*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
324*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_SEED:
325*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
326*5a6e8488SAndroid Build Coastguard Worker {
327*5a6e8488SAndroid Build Coastguard Worker n = &r->d.n;
328*5a6e8488SAndroid Build Coastguard Worker break;
329*5a6e8488SAndroid Build Coastguard Worker }
330*5a6e8488SAndroid Build Coastguard Worker
331*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_VAR:
332*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_ARRAY:
333*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_ARRAY_ELEM:
334*5a6e8488SAndroid Build Coastguard Worker {
335*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
336*5a6e8488SAndroid Build Coastguard Worker BcType type = (r->t == BC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY;
337*5a6e8488SAndroid Build Coastguard Worker
338*5a6e8488SAndroid Build Coastguard Worker // Get the correct variable or array vector.
339*5a6e8488SAndroid Build Coastguard Worker v = bc_program_vec(p, r->d.loc.loc, type);
340*5a6e8488SAndroid Build Coastguard Worker
341*5a6e8488SAndroid Build Coastguard Worker // Surprisingly enough, the hard case is *not* returning an array;
342*5a6e8488SAndroid Build Coastguard Worker // it's returning an array element. This is because we have to dig
343*5a6e8488SAndroid Build Coastguard Worker // deeper to get *to* the element. That's what the code inside this
344*5a6e8488SAndroid Build Coastguard Worker // if statement does.
345*5a6e8488SAndroid Build Coastguard Worker if (r->t == BC_RESULT_ARRAY_ELEM)
346*5a6e8488SAndroid Build Coastguard Worker {
347*5a6e8488SAndroid Build Coastguard Worker size_t idx = r->d.loc.idx;
348*5a6e8488SAndroid Build Coastguard Worker
349*5a6e8488SAndroid Build Coastguard Worker v = bc_vec_item(v, r->d.loc.stack_idx);
350*5a6e8488SAndroid Build Coastguard Worker
351*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
352*5a6e8488SAndroid Build Coastguard Worker // If this is true, we have a reference vector, so dereference
353*5a6e8488SAndroid Build Coastguard Worker // it. The reason we don't need to worry about it for returning
354*5a6e8488SAndroid Build Coastguard Worker // a straight array is because we only care about references
355*5a6e8488SAndroid Build Coastguard Worker // when we access elements of an array that is a reference. That
356*5a6e8488SAndroid Build Coastguard Worker // is this code, so in essence, this line takes care of arrays
357*5a6e8488SAndroid Build Coastguard Worker // as well.
358*5a6e8488SAndroid Build Coastguard Worker if (v->size == sizeof(uchar)) v = bc_program_dereference(p, v);
359*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
360*5a6e8488SAndroid Build Coastguard Worker
361*5a6e8488SAndroid Build Coastguard Worker // We want to be sure we got a valid array of numbers.
362*5a6e8488SAndroid Build Coastguard Worker assert(v->size == sizeof(BcNum));
363*5a6e8488SAndroid Build Coastguard Worker
364*5a6e8488SAndroid Build Coastguard Worker // The bc spec says that if an element is accessed that does not
365*5a6e8488SAndroid Build Coastguard Worker // exist, it should be preinitialized to 0. Well, if we access
366*5a6e8488SAndroid Build Coastguard Worker // an element *way* out there, we have to preinitialize all
367*5a6e8488SAndroid Build Coastguard Worker // elements between the current last element and the actual
368*5a6e8488SAndroid Build Coastguard Worker // accessed element.
369*5a6e8488SAndroid Build Coastguard Worker if (v->len <= idx)
370*5a6e8488SAndroid Build Coastguard Worker {
371*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
372*5a6e8488SAndroid Build Coastguard Worker bc_array_expand(v, bc_vm_growSize(idx, 1));
373*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
374*5a6e8488SAndroid Build Coastguard Worker }
375*5a6e8488SAndroid Build Coastguard Worker
376*5a6e8488SAndroid Build Coastguard Worker n = bc_vec_item(v, idx);
377*5a6e8488SAndroid Build Coastguard Worker }
378*5a6e8488SAndroid Build Coastguard Worker // This is either a number (for a var) or an array (for an array).
379*5a6e8488SAndroid Build Coastguard Worker // Because bc_vec_top() and bc_vec_item() return a void*, we don't
380*5a6e8488SAndroid Build Coastguard Worker // need to cast.
381*5a6e8488SAndroid Build Coastguard Worker else
382*5a6e8488SAndroid Build Coastguard Worker {
383*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
384*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC)
385*5a6e8488SAndroid Build Coastguard Worker {
386*5a6e8488SAndroid Build Coastguard Worker n = bc_vec_item(v, r->d.loc.stack_idx);
387*5a6e8488SAndroid Build Coastguard Worker }
388*5a6e8488SAndroid Build Coastguard Worker else
389*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
390*5a6e8488SAndroid Build Coastguard Worker {
391*5a6e8488SAndroid Build Coastguard Worker n = bc_vec_top(v);
392*5a6e8488SAndroid Build Coastguard Worker }
393*5a6e8488SAndroid Build Coastguard Worker }
394*5a6e8488SAndroid Build Coastguard Worker
395*5a6e8488SAndroid Build Coastguard Worker break;
396*5a6e8488SAndroid Build Coastguard Worker }
397*5a6e8488SAndroid Build Coastguard Worker
398*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_ZERO:
399*5a6e8488SAndroid Build Coastguard Worker {
400*5a6e8488SAndroid Build Coastguard Worker n = &vm->zero;
401*5a6e8488SAndroid Build Coastguard Worker break;
402*5a6e8488SAndroid Build Coastguard Worker }
403*5a6e8488SAndroid Build Coastguard Worker
404*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_ONE:
405*5a6e8488SAndroid Build Coastguard Worker {
406*5a6e8488SAndroid Build Coastguard Worker n = &vm->one;
407*5a6e8488SAndroid Build Coastguard Worker break;
408*5a6e8488SAndroid Build Coastguard Worker }
409*5a6e8488SAndroid Build Coastguard Worker
410*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
411*5a6e8488SAndroid Build Coastguard Worker // We should never get here; this is taken care of earlier because a
412*5a6e8488SAndroid Build Coastguard Worker // result is expected.
413*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_VOID:
414*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
415*5a6e8488SAndroid Build Coastguard Worker {
416*5a6e8488SAndroid Build Coastguard Worker abort();
417*5a6e8488SAndroid Build Coastguard Worker // Fallthrough
418*5a6e8488SAndroid Build Coastguard Worker }
419*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
420*5a6e8488SAndroid Build Coastguard Worker case BC_RESULT_LAST:
421*5a6e8488SAndroid Build Coastguard Worker {
422*5a6e8488SAndroid Build Coastguard Worker n = &p->last;
423*5a6e8488SAndroid Build Coastguard Worker break;
424*5a6e8488SAndroid Build Coastguard Worker }
425*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
426*5a6e8488SAndroid Build Coastguard Worker
427*5a6e8488SAndroid Build Coastguard Worker #if BC_GCC
428*5a6e8488SAndroid Build Coastguard Worker // This is here in GCC to quiet the "maybe-uninitialized" warning.
429*5a6e8488SAndroid Build Coastguard Worker default:
430*5a6e8488SAndroid Build Coastguard Worker {
431*5a6e8488SAndroid Build Coastguard Worker abort();
432*5a6e8488SAndroid Build Coastguard Worker }
433*5a6e8488SAndroid Build Coastguard Worker #endif // BC_GCC
434*5a6e8488SAndroid Build Coastguard Worker }
435*5a6e8488SAndroid Build Coastguard Worker
436*5a6e8488SAndroid Build Coastguard Worker return n;
437*5a6e8488SAndroid Build Coastguard Worker }
438*5a6e8488SAndroid Build Coastguard Worker
439*5a6e8488SAndroid Build Coastguard Worker /**
440*5a6e8488SAndroid Build Coastguard Worker * Prepares an operand for use.
441*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
442*5a6e8488SAndroid Build Coastguard Worker * @param r An out parameter; this is set to the pointer to the result that
443*5a6e8488SAndroid Build Coastguard Worker * we care about.
444*5a6e8488SAndroid Build Coastguard Worker * @param n An out parameter; this is set to the pointer to the number that
445*5a6e8488SAndroid Build Coastguard Worker * we care about.
446*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the result from the top of the results stack.
447*5a6e8488SAndroid Build Coastguard Worker */
448*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_operand(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)449*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
450*5a6e8488SAndroid Build Coastguard Worker {
451*5a6e8488SAndroid Build Coastguard Worker *r = bc_vec_item_rev(&p->results, idx);
452*5a6e8488SAndroid Build Coastguard Worker
453*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
454*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR((*r)->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
455*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
456*5a6e8488SAndroid Build Coastguard Worker
457*5a6e8488SAndroid Build Coastguard Worker *n = bc_program_num(p, *r);
458*5a6e8488SAndroid Build Coastguard Worker }
459*5a6e8488SAndroid Build Coastguard Worker
460*5a6e8488SAndroid Build Coastguard Worker /**
461*5a6e8488SAndroid Build Coastguard Worker * Prepares the operands of a binary operator.
462*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
463*5a6e8488SAndroid Build Coastguard Worker * @param l An out parameter; this is set to the pointer to the result for
464*5a6e8488SAndroid Build Coastguard Worker * the left operand.
465*5a6e8488SAndroid Build Coastguard Worker * @param ln An out parameter; this is set to the pointer to the number for
466*5a6e8488SAndroid Build Coastguard Worker * the left operand.
467*5a6e8488SAndroid Build Coastguard Worker * @param r An out parameter; this is set to the pointer to the result for
468*5a6e8488SAndroid Build Coastguard Worker * the right operand.
469*5a6e8488SAndroid Build Coastguard Worker * @param rn An out parameter; this is set to the pointer to the number for
470*5a6e8488SAndroid Build Coastguard Worker * the right operand.
471*5a6e8488SAndroid Build Coastguard Worker * @param idx The starting index where the operands are in the results stack,
472*5a6e8488SAndroid Build Coastguard Worker * starting from the top.
473*5a6e8488SAndroid Build Coastguard Worker */
474*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_binPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)475*5a6e8488SAndroid Build Coastguard Worker bc_program_binPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
476*5a6e8488SAndroid Build Coastguard Worker BcNum** rn, size_t idx)
477*5a6e8488SAndroid Build Coastguard Worker {
478*5a6e8488SAndroid Build Coastguard Worker BcResultType lt;
479*5a6e8488SAndroid Build Coastguard Worker
480*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL && l != NULL && ln != NULL && r != NULL && rn != NULL);
481*5a6e8488SAndroid Build Coastguard Worker
482*5a6e8488SAndroid Build Coastguard Worker #ifndef BC_PROG_NO_STACK_CHECK
483*5a6e8488SAndroid Build Coastguard Worker // Check the stack for dc.
484*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
485*5a6e8488SAndroid Build Coastguard Worker {
486*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 2)))
487*5a6e8488SAndroid Build Coastguard Worker {
488*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
489*5a6e8488SAndroid Build Coastguard Worker }
490*5a6e8488SAndroid Build Coastguard Worker }
491*5a6e8488SAndroid Build Coastguard Worker #endif // BC_PROG_NO_STACK_CHECK
492*5a6e8488SAndroid Build Coastguard Worker
493*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, idx + 2));
494*5a6e8488SAndroid Build Coastguard Worker
495*5a6e8488SAndroid Build Coastguard Worker // Get the operands.
496*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, l, ln, idx + 1);
497*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, r, rn, idx);
498*5a6e8488SAndroid Build Coastguard Worker
499*5a6e8488SAndroid Build Coastguard Worker lt = (*l)->t;
500*5a6e8488SAndroid Build Coastguard Worker
501*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
502*5a6e8488SAndroid Build Coastguard Worker // bc_program_operand() checked these for us.
503*5a6e8488SAndroid Build Coastguard Worker assert(lt != BC_RESULT_VOID && (*r)->t != BC_RESULT_VOID);
504*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
505*5a6e8488SAndroid Build Coastguard Worker
506*5a6e8488SAndroid Build Coastguard Worker // We run this again under these conditions in case any vector has been
507*5a6e8488SAndroid Build Coastguard Worker // reallocated out from under the BcNums or arrays we had. In other words,
508*5a6e8488SAndroid Build Coastguard Worker // this is to fix pointer invalidation.
509*5a6e8488SAndroid Build Coastguard Worker if (lt == (*r)->t && (lt == BC_RESULT_VAR || lt == BC_RESULT_ARRAY_ELEM))
510*5a6e8488SAndroid Build Coastguard Worker {
511*5a6e8488SAndroid Build Coastguard Worker *ln = bc_program_num(p, *l);
512*5a6e8488SAndroid Build Coastguard Worker }
513*5a6e8488SAndroid Build Coastguard Worker
514*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(lt == BC_RESULT_STR)) bc_err(BC_ERR_EXEC_TYPE);
515*5a6e8488SAndroid Build Coastguard Worker }
516*5a6e8488SAndroid Build Coastguard Worker
517*5a6e8488SAndroid Build Coastguard Worker /**
518*5a6e8488SAndroid Build Coastguard Worker * Prepares the operands of a binary operator and type checks them. This is
519*5a6e8488SAndroid Build Coastguard Worker * separate from bc_program_binPrep() because some places want this, others want
520*5a6e8488SAndroid Build Coastguard Worker * bc_program_binPrep().
521*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
522*5a6e8488SAndroid Build Coastguard Worker * @param l An out parameter; this is set to the pointer to the result for
523*5a6e8488SAndroid Build Coastguard Worker * the left operand.
524*5a6e8488SAndroid Build Coastguard Worker * @param ln An out parameter; this is set to the pointer to the number for
525*5a6e8488SAndroid Build Coastguard Worker * the left operand.
526*5a6e8488SAndroid Build Coastguard Worker * @param r An out parameter; this is set to the pointer to the result for
527*5a6e8488SAndroid Build Coastguard Worker * the right operand.
528*5a6e8488SAndroid Build Coastguard Worker * @param rn An out parameter; this is set to the pointer to the number for
529*5a6e8488SAndroid Build Coastguard Worker * the right operand.
530*5a6e8488SAndroid Build Coastguard Worker * @param idx The starting index where the operands are in the results stack,
531*5a6e8488SAndroid Build Coastguard Worker * starting from the top.
532*5a6e8488SAndroid Build Coastguard Worker */
533*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_binOpPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn,size_t idx)534*5a6e8488SAndroid Build Coastguard Worker bc_program_binOpPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
535*5a6e8488SAndroid Build Coastguard Worker BcNum** rn, size_t idx)
536*5a6e8488SAndroid Build Coastguard Worker {
537*5a6e8488SAndroid Build Coastguard Worker bc_program_binPrep(p, l, ln, r, rn, idx);
538*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(*l, *ln);
539*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(*r, *rn);
540*5a6e8488SAndroid Build Coastguard Worker }
541*5a6e8488SAndroid Build Coastguard Worker
542*5a6e8488SAndroid Build Coastguard Worker /**
543*5a6e8488SAndroid Build Coastguard Worker * Prepares the operands of an assignment operator.
544*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
545*5a6e8488SAndroid Build Coastguard Worker * @param l An out parameter; this is set to the pointer to the result for the
546*5a6e8488SAndroid Build Coastguard Worker * left operand.
547*5a6e8488SAndroid Build Coastguard Worker * @param ln An out parameter; this is set to the pointer to the number for the
548*5a6e8488SAndroid Build Coastguard Worker * left operand.
549*5a6e8488SAndroid Build Coastguard Worker * @param r An out parameter; this is set to the pointer to the result for the
550*5a6e8488SAndroid Build Coastguard Worker * right operand.
551*5a6e8488SAndroid Build Coastguard Worker * @param rn An out parameter; this is set to the pointer to the number for the
552*5a6e8488SAndroid Build Coastguard Worker * right operand.
553*5a6e8488SAndroid Build Coastguard Worker */
554*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_assignPrep(BcProgram * p,BcResult ** l,BcNum ** ln,BcResult ** r,BcNum ** rn)555*5a6e8488SAndroid Build Coastguard Worker bc_program_assignPrep(BcProgram* p, BcResult** l, BcNum** ln, BcResult** r,
556*5a6e8488SAndroid Build Coastguard Worker BcNum** rn)
557*5a6e8488SAndroid Build Coastguard Worker {
558*5a6e8488SAndroid Build Coastguard Worker BcResultType lt, min;
559*5a6e8488SAndroid Build Coastguard Worker bool good;
560*5a6e8488SAndroid Build Coastguard Worker
561*5a6e8488SAndroid Build Coastguard Worker // This is the min non-allowable result type. dc allows strings.
562*5a6e8488SAndroid Build Coastguard Worker min = BC_RESULT_TEMP - ((unsigned int) (BC_IS_BC));
563*5a6e8488SAndroid Build Coastguard Worker
564*5a6e8488SAndroid Build Coastguard Worker // Prepare the operands.
565*5a6e8488SAndroid Build Coastguard Worker bc_program_binPrep(p, l, ln, r, rn, 0);
566*5a6e8488SAndroid Build Coastguard Worker
567*5a6e8488SAndroid Build Coastguard Worker lt = (*l)->t;
568*5a6e8488SAndroid Build Coastguard Worker
569*5a6e8488SAndroid Build Coastguard Worker // Typecheck the left.
570*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(lt >= min && lt <= BC_RESULT_ONE)) bc_err(BC_ERR_EXEC_TYPE);
571*5a6e8488SAndroid Build Coastguard Worker
572*5a6e8488SAndroid Build Coastguard Worker // Strings can be assigned to variables. We are already good if we are
573*5a6e8488SAndroid Build Coastguard Worker // assigning a string.
574*5a6e8488SAndroid Build Coastguard Worker good = ((*r)->t == BC_RESULT_STR && lt <= BC_RESULT_ARRAY_ELEM);
575*5a6e8488SAndroid Build Coastguard Worker
576*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STR(*rn) || (*r)->t != BC_RESULT_STR);
577*5a6e8488SAndroid Build Coastguard Worker
578*5a6e8488SAndroid Build Coastguard Worker // If not, type check for a number.
579*5a6e8488SAndroid Build Coastguard Worker if (!good) bc_program_type_num(*r, *rn);
580*5a6e8488SAndroid Build Coastguard Worker }
581*5a6e8488SAndroid Build Coastguard Worker
582*5a6e8488SAndroid Build Coastguard Worker /**
583*5a6e8488SAndroid Build Coastguard Worker * Prepares a single operand and type checks it. This is separate from
584*5a6e8488SAndroid Build Coastguard Worker * bc_program_operand() because different places want one or the other.
585*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
586*5a6e8488SAndroid Build Coastguard Worker * @param r An out parameter; this is set to the pointer to the result that
587*5a6e8488SAndroid Build Coastguard Worker * we care about.
588*5a6e8488SAndroid Build Coastguard Worker * @param n An out parameter; this is set to the pointer to the number that
589*5a6e8488SAndroid Build Coastguard Worker * we care about.
590*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the result from the top of the results stack.
591*5a6e8488SAndroid Build Coastguard Worker */
592*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_prep(BcProgram * p,BcResult ** r,BcNum ** n,size_t idx)593*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(BcProgram* p, BcResult** r, BcNum** n, size_t idx)
594*5a6e8488SAndroid Build Coastguard Worker {
595*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL && r != NULL && n != NULL);
596*5a6e8488SAndroid Build Coastguard Worker
597*5a6e8488SAndroid Build Coastguard Worker #ifndef BC_PROG_NO_STACK_CHECK
598*5a6e8488SAndroid Build Coastguard Worker // Check the stack for dc.
599*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
600*5a6e8488SAndroid Build Coastguard Worker {
601*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
602*5a6e8488SAndroid Build Coastguard Worker {
603*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
604*5a6e8488SAndroid Build Coastguard Worker }
605*5a6e8488SAndroid Build Coastguard Worker }
606*5a6e8488SAndroid Build Coastguard Worker #endif // BC_PROG_NO_STACK_CHECK
607*5a6e8488SAndroid Build Coastguard Worker
608*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, idx + 1));
609*5a6e8488SAndroid Build Coastguard Worker
610*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, r, n, idx);
611*5a6e8488SAndroid Build Coastguard Worker
612*5a6e8488SAndroid Build Coastguard Worker // dc does not allow strings in this case.
613*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(*r, *n);
614*5a6e8488SAndroid Build Coastguard Worker }
615*5a6e8488SAndroid Build Coastguard Worker
616*5a6e8488SAndroid Build Coastguard Worker /**
617*5a6e8488SAndroid Build Coastguard Worker * Prepares and returns a clean result for the result of an operation.
618*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
619*5a6e8488SAndroid Build Coastguard Worker * @return A clean result.
620*5a6e8488SAndroid Build Coastguard Worker */
621*5a6e8488SAndroid Build Coastguard Worker static BcResult*
bc_program_prepResult(BcProgram * p)622*5a6e8488SAndroid Build Coastguard Worker bc_program_prepResult(BcProgram* p)
623*5a6e8488SAndroid Build Coastguard Worker {
624*5a6e8488SAndroid Build Coastguard Worker BcResult* res = bc_vec_pushEmpty(&p->results);
625*5a6e8488SAndroid Build Coastguard Worker
626*5a6e8488SAndroid Build Coastguard Worker bc_result_clear(res);
627*5a6e8488SAndroid Build Coastguard Worker
628*5a6e8488SAndroid Build Coastguard Worker return res;
629*5a6e8488SAndroid Build Coastguard Worker }
630*5a6e8488SAndroid Build Coastguard Worker
631*5a6e8488SAndroid Build Coastguard Worker /**
632*5a6e8488SAndroid Build Coastguard Worker * Prepares a constant for use. This parses the constant into a number and then
633*5a6e8488SAndroid Build Coastguard Worker * pushes that number onto the results stack.
634*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
635*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector that we will pull the index of the constant
636*5a6e8488SAndroid Build Coastguard Worker * from.
637*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; marks the start of the index in the
638*5a6e8488SAndroid Build Coastguard Worker * bytecode vector and will be updated to point to after the index.
639*5a6e8488SAndroid Build Coastguard Worker */
640*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_const(BcProgram * p,const char * code,size_t * bgn)641*5a6e8488SAndroid Build Coastguard Worker bc_program_const(BcProgram* p, const char* code, size_t* bgn)
642*5a6e8488SAndroid Build Coastguard Worker {
643*5a6e8488SAndroid Build Coastguard Worker // I lied. I actually push the result first. I can do this because the
644*5a6e8488SAndroid Build Coastguard Worker // result will be popped on error. I also get the constant itself.
645*5a6e8488SAndroid Build Coastguard Worker BcResult* r = bc_program_prepResult(p);
646*5a6e8488SAndroid Build Coastguard Worker BcConst* c = bc_vec_item(&p->consts, bc_program_index(code, bgn));
647*5a6e8488SAndroid Build Coastguard Worker BcBigDig base = BC_PROG_IBASE(p);
648*5a6e8488SAndroid Build Coastguard Worker
649*5a6e8488SAndroid Build Coastguard Worker // Only reparse if the base changed.
650*5a6e8488SAndroid Build Coastguard Worker if (c->base != base)
651*5a6e8488SAndroid Build Coastguard Worker {
652*5a6e8488SAndroid Build Coastguard Worker // Allocate if we haven't yet.
653*5a6e8488SAndroid Build Coastguard Worker if (c->num.num == NULL)
654*5a6e8488SAndroid Build Coastguard Worker {
655*5a6e8488SAndroid Build Coastguard Worker // The plus 1 is in case of overflow with lack of clamping.
656*5a6e8488SAndroid Build Coastguard Worker size_t len = strlen(c->val) + (BC_DIGIT_CLAMP == 0);
657*5a6e8488SAndroid Build Coastguard Worker
658*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
659*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&c->num, BC_NUM_RDX(len));
660*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
661*5a6e8488SAndroid Build Coastguard Worker }
662*5a6e8488SAndroid Build Coastguard Worker // We need to zero an already existing number.
663*5a6e8488SAndroid Build Coastguard Worker else bc_num_zero(&c->num);
664*5a6e8488SAndroid Build Coastguard Worker
665*5a6e8488SAndroid Build Coastguard Worker // bc_num_parse() should only do operations that cannot fail.
666*5a6e8488SAndroid Build Coastguard Worker bc_num_parse(&c->num, c->val, base);
667*5a6e8488SAndroid Build Coastguard Worker
668*5a6e8488SAndroid Build Coastguard Worker c->base = base;
669*5a6e8488SAndroid Build Coastguard Worker }
670*5a6e8488SAndroid Build Coastguard Worker
671*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
672*5a6e8488SAndroid Build Coastguard Worker
673*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(&r->d.n, &c->num);
674*5a6e8488SAndroid Build Coastguard Worker
675*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
676*5a6e8488SAndroid Build Coastguard Worker }
677*5a6e8488SAndroid Build Coastguard Worker
678*5a6e8488SAndroid Build Coastguard Worker /**
679*5a6e8488SAndroid Build Coastguard Worker * Executes a binary operator operation.
680*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
681*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction corresponding to the binary operator to execute.
682*5a6e8488SAndroid Build Coastguard Worker */
683*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_op(BcProgram * p,uchar inst)684*5a6e8488SAndroid Build Coastguard Worker bc_program_op(BcProgram* p, uchar inst)
685*5a6e8488SAndroid Build Coastguard Worker {
686*5a6e8488SAndroid Build Coastguard Worker BcResult* opd1;
687*5a6e8488SAndroid Build Coastguard Worker BcResult* opd2;
688*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
689*5a6e8488SAndroid Build Coastguard Worker BcNum* n1;
690*5a6e8488SAndroid Build Coastguard Worker BcNum* n2;
691*5a6e8488SAndroid Build Coastguard Worker size_t idx = inst - BC_INST_POWER;
692*5a6e8488SAndroid Build Coastguard Worker
693*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
694*5a6e8488SAndroid Build Coastguard Worker
695*5a6e8488SAndroid Build Coastguard Worker bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
696*5a6e8488SAndroid Build Coastguard Worker
697*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
698*5a6e8488SAndroid Build Coastguard Worker
699*5a6e8488SAndroid Build Coastguard Worker // Initialize the number with enough space, using the correct
700*5a6e8488SAndroid Build Coastguard Worker // BcNumBinaryOpReq function. This looks weird because it is executing an
701*5a6e8488SAndroid Build Coastguard Worker // item of an array. Rest assured that item is a function.
702*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, bc_program_opReqs[idx](n1, n2, BC_PROG_SCALE(p)));
703*5a6e8488SAndroid Build Coastguard Worker
704*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
705*5a6e8488SAndroid Build Coastguard Worker
706*5a6e8488SAndroid Build Coastguard Worker assert(BC_NUM_RDX_VALID(n1));
707*5a6e8488SAndroid Build Coastguard Worker assert(BC_NUM_RDX_VALID(n2));
708*5a6e8488SAndroid Build Coastguard Worker
709*5a6e8488SAndroid Build Coastguard Worker // Run the operation. This also executes an item of an array.
710*5a6e8488SAndroid Build Coastguard Worker bc_program_ops[idx](n1, n2, &res->d.n, BC_PROG_SCALE(p));
711*5a6e8488SAndroid Build Coastguard Worker
712*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, 2);
713*5a6e8488SAndroid Build Coastguard Worker }
714*5a6e8488SAndroid Build Coastguard Worker
715*5a6e8488SAndroid Build Coastguard Worker /**
716*5a6e8488SAndroid Build Coastguard Worker * Executes a read() or ? command.
717*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
718*5a6e8488SAndroid Build Coastguard Worker */
719*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_read(BcProgram * p)720*5a6e8488SAndroid Build Coastguard Worker bc_program_read(BcProgram* p)
721*5a6e8488SAndroid Build Coastguard Worker {
722*5a6e8488SAndroid Build Coastguard Worker BcStatus s;
723*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
724*5a6e8488SAndroid Build Coastguard Worker size_t i;
725*5a6e8488SAndroid Build Coastguard Worker const char* file;
726*5a6e8488SAndroid Build Coastguard Worker BcMode mode;
727*5a6e8488SAndroid Build Coastguard Worker BcFunc* f = bc_vec_item(&p->fns, BC_PROG_READ);
728*5a6e8488SAndroid Build Coastguard Worker
729*5a6e8488SAndroid Build Coastguard Worker // If we are already executing a read, that is an error. So look for a read
730*5a6e8488SAndroid Build Coastguard Worker // and barf.
731*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < p->stack.len; ++i)
732*5a6e8488SAndroid Build Coastguard Worker {
733*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip_ptr = bc_vec_item(&p->stack, i);
734*5a6e8488SAndroid Build Coastguard Worker if (ip_ptr->func == BC_PROG_READ) bc_err(BC_ERR_EXEC_REC_READ);
735*5a6e8488SAndroid Build Coastguard Worker }
736*5a6e8488SAndroid Build Coastguard Worker
737*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
738*5a6e8488SAndroid Build Coastguard Worker
739*5a6e8488SAndroid Build Coastguard Worker // Save the filename because we are going to overwrite it.
740*5a6e8488SAndroid Build Coastguard Worker file = vm->file;
741*5a6e8488SAndroid Build Coastguard Worker mode = vm->mode;
742*5a6e8488SAndroid Build Coastguard Worker
743*5a6e8488SAndroid Build Coastguard Worker // It is a parse error if there needs to be more than one line, so we unset
744*5a6e8488SAndroid Build Coastguard Worker // this to tell the lexer to not request more. We set it back later.
745*5a6e8488SAndroid Build Coastguard Worker vm->mode = BC_MODE_FILE;
746*5a6e8488SAndroid Build Coastguard Worker
747*5a6e8488SAndroid Build Coastguard Worker if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
748*5a6e8488SAndroid Build Coastguard Worker {
749*5a6e8488SAndroid Build Coastguard Worker // We need to parse, but we don't want to use the existing parser
750*5a6e8488SAndroid Build Coastguard Worker // because it has state it needs to keep. (It could have a partial parse
751*5a6e8488SAndroid Build Coastguard Worker // state.) So we create a new parser. This parser is in the BcVm struct
752*5a6e8488SAndroid Build Coastguard Worker // so that it is not local, which means that a longjmp() could change
753*5a6e8488SAndroid Build Coastguard Worker // it.
754*5a6e8488SAndroid Build Coastguard Worker bc_parse_init(&vm->read_prs, p, BC_PROG_READ);
755*5a6e8488SAndroid Build Coastguard Worker
756*5a6e8488SAndroid Build Coastguard Worker // We need a separate input buffer; that's why it is also in the BcVm
757*5a6e8488SAndroid Build Coastguard Worker // struct.
758*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
759*5a6e8488SAndroid Build Coastguard Worker }
760*5a6e8488SAndroid Build Coastguard Worker else
761*5a6e8488SAndroid Build Coastguard Worker {
762*5a6e8488SAndroid Build Coastguard Worker // This needs to be updated because the parser could have been used
763*5a6e8488SAndroid Build Coastguard Worker // somewhere else.
764*5a6e8488SAndroid Build Coastguard Worker bc_parse_updateFunc(&vm->read_prs, BC_PROG_READ);
765*5a6e8488SAndroid Build Coastguard Worker
766*5a6e8488SAndroid Build Coastguard Worker // The read buffer also needs to be emptied or else it will still
767*5a6e8488SAndroid Build Coastguard Worker // contain previous read expressions.
768*5a6e8488SAndroid Build Coastguard Worker bc_vec_empty(&vm->read_buf);
769*5a6e8488SAndroid Build Coastguard Worker }
770*5a6e8488SAndroid Build Coastguard Worker
771*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exec_err);
772*5a6e8488SAndroid Build Coastguard Worker
773*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
774*5a6e8488SAndroid Build Coastguard Worker
775*5a6e8488SAndroid Build Coastguard Worker // Set up the lexer and the read function.
776*5a6e8488SAndroid Build Coastguard Worker bc_lex_file(&vm->read_prs.l, bc_program_stdin_name);
777*5a6e8488SAndroid Build Coastguard Worker bc_vec_popAll(&f->code);
778*5a6e8488SAndroid Build Coastguard Worker
779*5a6e8488SAndroid Build Coastguard Worker // Read a line.
780*5a6e8488SAndroid Build Coastguard Worker if (!BC_R) s = bc_read_line(&vm->read_buf, "");
781*5a6e8488SAndroid Build Coastguard Worker else s = bc_read_line(&vm->read_buf, BC_VM_READ_PROMPT);
782*5a6e8488SAndroid Build Coastguard Worker
783*5a6e8488SAndroid Build Coastguard Worker // We should *not* have run into EOF.
784*5a6e8488SAndroid Build Coastguard Worker if (s == BC_STATUS_EOF) bc_err(BC_ERR_EXEC_READ_EXPR);
785*5a6e8488SAndroid Build Coastguard Worker
786*5a6e8488SAndroid Build Coastguard Worker // Parse *one* expression, so mode should not be stdin.
787*5a6e8488SAndroid Build Coastguard Worker bc_parse_text(&vm->read_prs, vm->read_buf.v, BC_MODE_FILE);
788*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
789*5a6e8488SAndroid Build Coastguard Worker vm->expr(&vm->read_prs, BC_PARSE_NOREAD | BC_PARSE_NEEDVAL);
790*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
791*5a6e8488SAndroid Build Coastguard Worker
792*5a6e8488SAndroid Build Coastguard Worker // We *must* have a valid expression. A semicolon cannot end an expression,
793*5a6e8488SAndroid Build Coastguard Worker // although EOF can.
794*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(vm->read_prs.l.t != BC_LEX_NLINE &&
795*5a6e8488SAndroid Build Coastguard Worker vm->read_prs.l.t != BC_LEX_EOF))
796*5a6e8488SAndroid Build Coastguard Worker {
797*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_READ_EXPR);
798*5a6e8488SAndroid Build Coastguard Worker }
799*5a6e8488SAndroid Build Coastguard Worker
800*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
801*5a6e8488SAndroid Build Coastguard Worker // Push on the globals stack if necessary.
802*5a6e8488SAndroid Build Coastguard Worker if (BC_G) bc_program_prepGlobals(p);
803*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
804*5a6e8488SAndroid Build Coastguard Worker
805*5a6e8488SAndroid Build Coastguard Worker // Set up a new BcInstPtr.
806*5a6e8488SAndroid Build Coastguard Worker ip.func = BC_PROG_READ;
807*5a6e8488SAndroid Build Coastguard Worker ip.idx = 0;
808*5a6e8488SAndroid Build Coastguard Worker ip.len = p->results.len;
809*5a6e8488SAndroid Build Coastguard Worker
810*5a6e8488SAndroid Build Coastguard Worker // Update this pointer, just in case.
811*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, BC_PROG_READ);
812*5a6e8488SAndroid Build Coastguard Worker
813*5a6e8488SAndroid Build Coastguard Worker // We want a return instruction to simplify things.
814*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushByte(&f->code, vm->read_ret);
815*5a6e8488SAndroid Build Coastguard Worker
816*5a6e8488SAndroid Build Coastguard Worker // This lock is here to make sure dc's tail calls are the same length.
817*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
818*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->stack, &ip);
819*5a6e8488SAndroid Build Coastguard Worker
820*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
821*5a6e8488SAndroid Build Coastguard Worker // We need a new tail call entry for dc.
822*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
823*5a6e8488SAndroid Build Coastguard Worker {
824*5a6e8488SAndroid Build Coastguard Worker size_t temp = 0;
825*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->tail_calls, &temp);
826*5a6e8488SAndroid Build Coastguard Worker }
827*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
828*5a6e8488SAndroid Build Coastguard Worker
829*5a6e8488SAndroid Build Coastguard Worker exec_err:
830*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
831*5a6e8488SAndroid Build Coastguard Worker vm->mode = (uchar) mode;
832*5a6e8488SAndroid Build Coastguard Worker vm->file = file;
833*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
834*5a6e8488SAndroid Build Coastguard Worker }
835*5a6e8488SAndroid Build Coastguard Worker
836*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
837*5a6e8488SAndroid Build Coastguard Worker
838*5a6e8488SAndroid Build Coastguard Worker /**
839*5a6e8488SAndroid Build Coastguard Worker * Execute a rand().
840*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
841*5a6e8488SAndroid Build Coastguard Worker */
842*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_rand(BcProgram * p)843*5a6e8488SAndroid Build Coastguard Worker bc_program_rand(BcProgram* p)
844*5a6e8488SAndroid Build Coastguard Worker {
845*5a6e8488SAndroid Build Coastguard Worker BcRand rand = bc_rand_int(&p->rng);
846*5a6e8488SAndroid Build Coastguard Worker
847*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, (BcBigDig) rand, BC_RESULT_TEMP);
848*5a6e8488SAndroid Build Coastguard Worker
849*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
850*5a6e8488SAndroid Build Coastguard Worker // This is just to ensure that the generated number is correct. I also use
851*5a6e8488SAndroid Build Coastguard Worker // braces because I declare every local at the top of the scope.
852*5a6e8488SAndroid Build Coastguard Worker {
853*5a6e8488SAndroid Build Coastguard Worker BcResult* r = bc_vec_top(&p->results);
854*5a6e8488SAndroid Build Coastguard Worker assert(BC_NUM_RDX_VALID_NP(r->d.n));
855*5a6e8488SAndroid Build Coastguard Worker }
856*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
857*5a6e8488SAndroid Build Coastguard Worker }
858*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
859*5a6e8488SAndroid Build Coastguard Worker
860*5a6e8488SAndroid Build Coastguard Worker /**
861*5a6e8488SAndroid Build Coastguard Worker * Prints a series of characters, without escapes.
862*5a6e8488SAndroid Build Coastguard Worker * @param str The string (series of characters).
863*5a6e8488SAndroid Build Coastguard Worker */
864*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printChars(const char * str)865*5a6e8488SAndroid Build Coastguard Worker bc_program_printChars(const char* str)
866*5a6e8488SAndroid Build Coastguard Worker {
867*5a6e8488SAndroid Build Coastguard Worker const char* nl;
868*5a6e8488SAndroid Build Coastguard Worker size_t len = vm->nchars + strlen(str);
869*5a6e8488SAndroid Build Coastguard Worker sig_atomic_t lock;
870*5a6e8488SAndroid Build Coastguard Worker
871*5a6e8488SAndroid Build Coastguard Worker BC_SIG_TRYLOCK(lock);
872*5a6e8488SAndroid Build Coastguard Worker
873*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_save, str);
874*5a6e8488SAndroid Build Coastguard Worker
875*5a6e8488SAndroid Build Coastguard Worker // We need to update the number of characters, so we find the last newline
876*5a6e8488SAndroid Build Coastguard Worker // and set the characters accordingly.
877*5a6e8488SAndroid Build Coastguard Worker nl = strrchr(str, '\n');
878*5a6e8488SAndroid Build Coastguard Worker
879*5a6e8488SAndroid Build Coastguard Worker if (nl != NULL) len = strlen(nl + 1);
880*5a6e8488SAndroid Build Coastguard Worker
881*5a6e8488SAndroid Build Coastguard Worker vm->nchars = len > UINT16_MAX ? UINT16_MAX : (uint16_t) len;
882*5a6e8488SAndroid Build Coastguard Worker
883*5a6e8488SAndroid Build Coastguard Worker BC_SIG_TRYUNLOCK(lock);
884*5a6e8488SAndroid Build Coastguard Worker }
885*5a6e8488SAndroid Build Coastguard Worker
886*5a6e8488SAndroid Build Coastguard Worker /**
887*5a6e8488SAndroid Build Coastguard Worker * Prints a string with escapes.
888*5a6e8488SAndroid Build Coastguard Worker * @param str The string.
889*5a6e8488SAndroid Build Coastguard Worker */
890*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printString(const char * restrict str)891*5a6e8488SAndroid Build Coastguard Worker bc_program_printString(const char* restrict str)
892*5a6e8488SAndroid Build Coastguard Worker {
893*5a6e8488SAndroid Build Coastguard Worker size_t i, len = strlen(str);
894*5a6e8488SAndroid Build Coastguard Worker
895*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
896*5a6e8488SAndroid Build Coastguard Worker // This is to ensure a nul byte is printed for dc's stream operation.
897*5a6e8488SAndroid Build Coastguard Worker if (!len && BC_IS_DC)
898*5a6e8488SAndroid Build Coastguard Worker {
899*5a6e8488SAndroid Build Coastguard Worker bc_vm_putchar('\0', bc_flush_save);
900*5a6e8488SAndroid Build Coastguard Worker return;
901*5a6e8488SAndroid Build Coastguard Worker }
902*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
903*5a6e8488SAndroid Build Coastguard Worker
904*5a6e8488SAndroid Build Coastguard Worker // Loop over the characters, processing escapes and printing the rest.
905*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < len; ++i)
906*5a6e8488SAndroid Build Coastguard Worker {
907*5a6e8488SAndroid Build Coastguard Worker int c = str[i];
908*5a6e8488SAndroid Build Coastguard Worker
909*5a6e8488SAndroid Build Coastguard Worker // If we have an escape...
910*5a6e8488SAndroid Build Coastguard Worker if (c == '\\' && i != len - 1)
911*5a6e8488SAndroid Build Coastguard Worker {
912*5a6e8488SAndroid Build Coastguard Worker const char* ptr;
913*5a6e8488SAndroid Build Coastguard Worker
914*5a6e8488SAndroid Build Coastguard Worker // Get the escape character and its companion.
915*5a6e8488SAndroid Build Coastguard Worker c = str[++i];
916*5a6e8488SAndroid Build Coastguard Worker ptr = strchr(bc_program_esc_chars, c);
917*5a6e8488SAndroid Build Coastguard Worker
918*5a6e8488SAndroid Build Coastguard Worker // If we have a companion character...
919*5a6e8488SAndroid Build Coastguard Worker if (ptr != NULL)
920*5a6e8488SAndroid Build Coastguard Worker {
921*5a6e8488SAndroid Build Coastguard Worker // We need to specially handle a newline.
922*5a6e8488SAndroid Build Coastguard Worker if (c == 'n')
923*5a6e8488SAndroid Build Coastguard Worker {
924*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
925*5a6e8488SAndroid Build Coastguard Worker vm->nchars = UINT16_MAX;
926*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
927*5a6e8488SAndroid Build Coastguard Worker }
928*5a6e8488SAndroid Build Coastguard Worker
929*5a6e8488SAndroid Build Coastguard Worker // Grab the actual character.
930*5a6e8488SAndroid Build Coastguard Worker c = bc_program_esc_seqs[(size_t) (ptr - bc_program_esc_chars)];
931*5a6e8488SAndroid Build Coastguard Worker }
932*5a6e8488SAndroid Build Coastguard Worker else
933*5a6e8488SAndroid Build Coastguard Worker {
934*5a6e8488SAndroid Build Coastguard Worker // Just print the backslash if there is no companion character.
935*5a6e8488SAndroid Build Coastguard Worker // The following character will be printed later after the outer
936*5a6e8488SAndroid Build Coastguard Worker // if statement.
937*5a6e8488SAndroid Build Coastguard Worker bc_vm_putchar('\\', bc_flush_save);
938*5a6e8488SAndroid Build Coastguard Worker }
939*5a6e8488SAndroid Build Coastguard Worker }
940*5a6e8488SAndroid Build Coastguard Worker
941*5a6e8488SAndroid Build Coastguard Worker bc_vm_putchar(c, bc_flush_save);
942*5a6e8488SAndroid Build Coastguard Worker }
943*5a6e8488SAndroid Build Coastguard Worker }
944*5a6e8488SAndroid Build Coastguard Worker
945*5a6e8488SAndroid Build Coastguard Worker /**
946*5a6e8488SAndroid Build Coastguard Worker * Executes a print. This function handles all printing except streaming.
947*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
948*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction for the type of print we are doing.
949*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the result that we are printing.
950*5a6e8488SAndroid Build Coastguard Worker */
951*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_print(BcProgram * p,uchar inst,size_t idx)952*5a6e8488SAndroid Build Coastguard Worker bc_program_print(BcProgram* p, uchar inst, size_t idx)
953*5a6e8488SAndroid Build Coastguard Worker {
954*5a6e8488SAndroid Build Coastguard Worker BcResult* r;
955*5a6e8488SAndroid Build Coastguard Worker char* str;
956*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
957*5a6e8488SAndroid Build Coastguard Worker bool pop = (inst != BC_INST_PRINT);
958*5a6e8488SAndroid Build Coastguard Worker
959*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL);
960*5a6e8488SAndroid Build Coastguard Worker
961*5a6e8488SAndroid Build Coastguard Worker #ifndef BC_PROG_NO_STACK_CHECK
962*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
963*5a6e8488SAndroid Build Coastguard Worker {
964*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, idx + 1)))
965*5a6e8488SAndroid Build Coastguard Worker {
966*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
967*5a6e8488SAndroid Build Coastguard Worker }
968*5a6e8488SAndroid Build Coastguard Worker }
969*5a6e8488SAndroid Build Coastguard Worker #endif // BC_PROG_NO_STACK_CHECK
970*5a6e8488SAndroid Build Coastguard Worker
971*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, idx + 1));
972*5a6e8488SAndroid Build Coastguard Worker
973*5a6e8488SAndroid Build Coastguard Worker r = bc_vec_item_rev(&p->results, idx);
974*5a6e8488SAndroid Build Coastguard Worker
975*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
976*5a6e8488SAndroid Build Coastguard Worker // If we have a void value, that's not necessarily an error. It is if pop is
977*5a6e8488SAndroid Build Coastguard Worker // true because that means that we are executing a print statement, but
978*5a6e8488SAndroid Build Coastguard Worker // attempting to do a print on a lone void value is allowed because that's
979*5a6e8488SAndroid Build Coastguard Worker // exactly how we want void values used.
980*5a6e8488SAndroid Build Coastguard Worker if (r->t == BC_RESULT_VOID)
981*5a6e8488SAndroid Build Coastguard Worker {
982*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(pop)) bc_err(BC_ERR_EXEC_VOID_VAL);
983*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
984*5a6e8488SAndroid Build Coastguard Worker return;
985*5a6e8488SAndroid Build Coastguard Worker }
986*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
987*5a6e8488SAndroid Build Coastguard Worker
988*5a6e8488SAndroid Build Coastguard Worker n = bc_program_num(p, r);
989*5a6e8488SAndroid Build Coastguard Worker
990*5a6e8488SAndroid Build Coastguard Worker // If we have a number...
991*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_NUM(r, n))
992*5a6e8488SAndroid Build Coastguard Worker {
993*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
994*5a6e8488SAndroid Build Coastguard Worker assert(inst != BC_INST_PRINT_STR);
995*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
996*5a6e8488SAndroid Build Coastguard Worker
997*5a6e8488SAndroid Build Coastguard Worker // Print the number.
998*5a6e8488SAndroid Build Coastguard Worker bc_num_print(n, BC_PROG_OBASE(p), !pop);
999*5a6e8488SAndroid Build Coastguard Worker
1000*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1001*5a6e8488SAndroid Build Coastguard Worker // Need to store the number in last.
1002*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC) bc_num_copy(&p->last, n);
1003*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1004*5a6e8488SAndroid Build Coastguard Worker }
1005*5a6e8488SAndroid Build Coastguard Worker else
1006*5a6e8488SAndroid Build Coastguard Worker {
1007*5a6e8488SAndroid Build Coastguard Worker // We want to flush any stuff in the stdout buffer first.
1008*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_save);
1009*5a6e8488SAndroid Build Coastguard Worker str = bc_program_string(p, n);
1010*5a6e8488SAndroid Build Coastguard Worker
1011*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1012*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_PRINT_STR) bc_program_printChars(str);
1013*5a6e8488SAndroid Build Coastguard Worker else
1014*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1015*5a6e8488SAndroid Build Coastguard Worker {
1016*5a6e8488SAndroid Build Coastguard Worker bc_program_printString(str);
1017*5a6e8488SAndroid Build Coastguard Worker
1018*5a6e8488SAndroid Build Coastguard Worker // Need to print a newline only in this case.
1019*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_PRINT) bc_vm_putchar('\n', bc_flush_err);
1020*5a6e8488SAndroid Build Coastguard Worker }
1021*5a6e8488SAndroid Build Coastguard Worker }
1022*5a6e8488SAndroid Build Coastguard Worker
1023*5a6e8488SAndroid Build Coastguard Worker // bc always pops. This macro makes sure that happens.
1024*5a6e8488SAndroid Build Coastguard Worker if (BC_PROGRAM_POP(pop)) bc_vec_pop(&p->results);
1025*5a6e8488SAndroid Build Coastguard Worker }
1026*5a6e8488SAndroid Build Coastguard Worker
1027*5a6e8488SAndroid Build Coastguard Worker void
bc_program_negate(BcResult * r,BcNum * n)1028*5a6e8488SAndroid Build Coastguard Worker bc_program_negate(BcResult* r, BcNum* n)
1029*5a6e8488SAndroid Build Coastguard Worker {
1030*5a6e8488SAndroid Build Coastguard Worker bc_num_copy(&r->d.n, n);
1031*5a6e8488SAndroid Build Coastguard Worker if (BC_NUM_NONZERO(&r->d.n)) BC_NUM_NEG_TGL_NP(r->d.n);
1032*5a6e8488SAndroid Build Coastguard Worker }
1033*5a6e8488SAndroid Build Coastguard Worker
1034*5a6e8488SAndroid Build Coastguard Worker void
bc_program_not(BcResult * r,BcNum * n)1035*5a6e8488SAndroid Build Coastguard Worker bc_program_not(BcResult* r, BcNum* n)
1036*5a6e8488SAndroid Build Coastguard Worker {
1037*5a6e8488SAndroid Build Coastguard Worker if (!bc_num_cmpZero(n)) bc_num_one(&r->d.n);
1038*5a6e8488SAndroid Build Coastguard Worker }
1039*5a6e8488SAndroid Build Coastguard Worker
1040*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1041*5a6e8488SAndroid Build Coastguard Worker void
bc_program_trunc(BcResult * r,BcNum * n)1042*5a6e8488SAndroid Build Coastguard Worker bc_program_trunc(BcResult* r, BcNum* n)
1043*5a6e8488SAndroid Build Coastguard Worker {
1044*5a6e8488SAndroid Build Coastguard Worker bc_num_copy(&r->d.n, n);
1045*5a6e8488SAndroid Build Coastguard Worker bc_num_truncate(&r->d.n, n->scale);
1046*5a6e8488SAndroid Build Coastguard Worker }
1047*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1048*5a6e8488SAndroid Build Coastguard Worker
1049*5a6e8488SAndroid Build Coastguard Worker /**
1050*5a6e8488SAndroid Build Coastguard Worker * Runs a unary operation.
1051*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1052*5a6e8488SAndroid Build Coastguard Worker * @param inst The unary operation.
1053*5a6e8488SAndroid Build Coastguard Worker */
1054*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_unary(BcProgram * p,uchar inst)1055*5a6e8488SAndroid Build Coastguard Worker bc_program_unary(BcProgram* p, uchar inst)
1056*5a6e8488SAndroid Build Coastguard Worker {
1057*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
1058*5a6e8488SAndroid Build Coastguard Worker BcResult* ptr;
1059*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
1060*5a6e8488SAndroid Build Coastguard Worker
1061*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
1062*5a6e8488SAndroid Build Coastguard Worker
1063*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(p, &ptr, &num, 1);
1064*5a6e8488SAndroid Build Coastguard Worker
1065*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1066*5a6e8488SAndroid Build Coastguard Worker
1067*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, num->len);
1068*5a6e8488SAndroid Build Coastguard Worker
1069*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1070*5a6e8488SAndroid Build Coastguard Worker
1071*5a6e8488SAndroid Build Coastguard Worker // This calls a function that is in an array.
1072*5a6e8488SAndroid Build Coastguard Worker bc_program_unarys[inst - BC_INST_NEG](res, num);
1073*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, 1);
1074*5a6e8488SAndroid Build Coastguard Worker }
1075*5a6e8488SAndroid Build Coastguard Worker
1076*5a6e8488SAndroid Build Coastguard Worker /**
1077*5a6e8488SAndroid Build Coastguard Worker * Executes a logical operator.
1078*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1079*5a6e8488SAndroid Build Coastguard Worker * @param inst The operator.
1080*5a6e8488SAndroid Build Coastguard Worker */
1081*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_logical(BcProgram * p,uchar inst)1082*5a6e8488SAndroid Build Coastguard Worker bc_program_logical(BcProgram* p, uchar inst)
1083*5a6e8488SAndroid Build Coastguard Worker {
1084*5a6e8488SAndroid Build Coastguard Worker BcResult* opd1;
1085*5a6e8488SAndroid Build Coastguard Worker BcResult* opd2;
1086*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
1087*5a6e8488SAndroid Build Coastguard Worker BcNum* n1;
1088*5a6e8488SAndroid Build Coastguard Worker BcNum* n2;
1089*5a6e8488SAndroid Build Coastguard Worker bool cond = 0;
1090*5a6e8488SAndroid Build Coastguard Worker ssize_t cmp;
1091*5a6e8488SAndroid Build Coastguard Worker
1092*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
1093*5a6e8488SAndroid Build Coastguard Worker
1094*5a6e8488SAndroid Build Coastguard Worker // All logical operators (except boolean not, which is taken care of by
1095*5a6e8488SAndroid Build Coastguard Worker // bc_program_unary()), are binary operators.
1096*5a6e8488SAndroid Build Coastguard Worker bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 1);
1097*5a6e8488SAndroid Build Coastguard Worker
1098*5a6e8488SAndroid Build Coastguard Worker // Boolean and and or are not short circuiting. This is why; they can be
1099*5a6e8488SAndroid Build Coastguard Worker // implemented much easier this way.
1100*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_BOOL_AND)
1101*5a6e8488SAndroid Build Coastguard Worker {
1102*5a6e8488SAndroid Build Coastguard Worker cond = (bc_num_cmpZero(n1) && bc_num_cmpZero(n2));
1103*5a6e8488SAndroid Build Coastguard Worker }
1104*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_BOOL_OR)
1105*5a6e8488SAndroid Build Coastguard Worker {
1106*5a6e8488SAndroid Build Coastguard Worker cond = (bc_num_cmpZero(n1) || bc_num_cmpZero(n2));
1107*5a6e8488SAndroid Build Coastguard Worker }
1108*5a6e8488SAndroid Build Coastguard Worker else
1109*5a6e8488SAndroid Build Coastguard Worker {
1110*5a6e8488SAndroid Build Coastguard Worker // We have a relational operator, so do a comparison.
1111*5a6e8488SAndroid Build Coastguard Worker cmp = bc_num_cmp(n1, n2);
1112*5a6e8488SAndroid Build Coastguard Worker
1113*5a6e8488SAndroid Build Coastguard Worker switch (inst)
1114*5a6e8488SAndroid Build Coastguard Worker {
1115*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_EQ:
1116*5a6e8488SAndroid Build Coastguard Worker {
1117*5a6e8488SAndroid Build Coastguard Worker cond = (cmp == 0);
1118*5a6e8488SAndroid Build Coastguard Worker break;
1119*5a6e8488SAndroid Build Coastguard Worker }
1120*5a6e8488SAndroid Build Coastguard Worker
1121*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_LE:
1122*5a6e8488SAndroid Build Coastguard Worker {
1123*5a6e8488SAndroid Build Coastguard Worker cond = (cmp <= 0);
1124*5a6e8488SAndroid Build Coastguard Worker break;
1125*5a6e8488SAndroid Build Coastguard Worker }
1126*5a6e8488SAndroid Build Coastguard Worker
1127*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_GE:
1128*5a6e8488SAndroid Build Coastguard Worker {
1129*5a6e8488SAndroid Build Coastguard Worker cond = (cmp >= 0);
1130*5a6e8488SAndroid Build Coastguard Worker break;
1131*5a6e8488SAndroid Build Coastguard Worker }
1132*5a6e8488SAndroid Build Coastguard Worker
1133*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_NE:
1134*5a6e8488SAndroid Build Coastguard Worker {
1135*5a6e8488SAndroid Build Coastguard Worker cond = (cmp != 0);
1136*5a6e8488SAndroid Build Coastguard Worker break;
1137*5a6e8488SAndroid Build Coastguard Worker }
1138*5a6e8488SAndroid Build Coastguard Worker
1139*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_LT:
1140*5a6e8488SAndroid Build Coastguard Worker {
1141*5a6e8488SAndroid Build Coastguard Worker cond = (cmp < 0);
1142*5a6e8488SAndroid Build Coastguard Worker break;
1143*5a6e8488SAndroid Build Coastguard Worker }
1144*5a6e8488SAndroid Build Coastguard Worker
1145*5a6e8488SAndroid Build Coastguard Worker case BC_INST_REL_GT:
1146*5a6e8488SAndroid Build Coastguard Worker {
1147*5a6e8488SAndroid Build Coastguard Worker cond = (cmp > 0);
1148*5a6e8488SAndroid Build Coastguard Worker break;
1149*5a6e8488SAndroid Build Coastguard Worker }
1150*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
1151*5a6e8488SAndroid Build Coastguard Worker default:
1152*5a6e8488SAndroid Build Coastguard Worker {
1153*5a6e8488SAndroid Build Coastguard Worker // There is a bug if we get here.
1154*5a6e8488SAndroid Build Coastguard Worker abort();
1155*5a6e8488SAndroid Build Coastguard Worker }
1156*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
1157*5a6e8488SAndroid Build Coastguard Worker }
1158*5a6e8488SAndroid Build Coastguard Worker }
1159*5a6e8488SAndroid Build Coastguard Worker
1160*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1161*5a6e8488SAndroid Build Coastguard Worker
1162*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1163*5a6e8488SAndroid Build Coastguard Worker
1164*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1165*5a6e8488SAndroid Build Coastguard Worker
1166*5a6e8488SAndroid Build Coastguard Worker if (cond) bc_num_one(&res->d.n);
1167*5a6e8488SAndroid Build Coastguard Worker
1168*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, 2);
1169*5a6e8488SAndroid Build Coastguard Worker }
1170*5a6e8488SAndroid Build Coastguard Worker
1171*5a6e8488SAndroid Build Coastguard Worker /**
1172*5a6e8488SAndroid Build Coastguard Worker * Assigns a string to a variable.
1173*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1174*5a6e8488SAndroid Build Coastguard Worker * @param num The location of the string as a BcNum.
1175*5a6e8488SAndroid Build Coastguard Worker * @param v The stack for the variable.
1176*5a6e8488SAndroid Build Coastguard Worker * @param push Whether to push the string or not. To push means to move the
1177*5a6e8488SAndroid Build Coastguard Worker * string from the results stack and push it onto the variable
1178*5a6e8488SAndroid Build Coastguard Worker * stack.
1179*5a6e8488SAndroid Build Coastguard Worker */
1180*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_assignStr(BcProgram * p,BcNum * num,BcVec * v,bool push)1181*5a6e8488SAndroid Build Coastguard Worker bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push)
1182*5a6e8488SAndroid Build Coastguard Worker {
1183*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
1184*5a6e8488SAndroid Build Coastguard Worker
1185*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1 + !push));
1186*5a6e8488SAndroid Build Coastguard Worker assert(num != NULL && num->num == NULL && num->cap == 0);
1187*5a6e8488SAndroid Build Coastguard Worker
1188*5a6e8488SAndroid Build Coastguard Worker // If we are not pushing onto the variable stack, we need to replace the
1189*5a6e8488SAndroid Build Coastguard Worker // top of the variable stack.
1190*5a6e8488SAndroid Build Coastguard Worker if (!push) bc_vec_pop(v);
1191*5a6e8488SAndroid Build Coastguard Worker
1192*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->results, 1 + !push);
1193*5a6e8488SAndroid Build Coastguard Worker
1194*5a6e8488SAndroid Build Coastguard Worker n = bc_vec_pushEmpty(v);
1195*5a6e8488SAndroid Build Coastguard Worker
1196*5a6e8488SAndroid Build Coastguard Worker // We can just copy because the num should not have allocated anything.
1197*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1198*5a6e8488SAndroid Build Coastguard Worker memcpy(n, num, sizeof(BcNum));
1199*5a6e8488SAndroid Build Coastguard Worker }
1200*5a6e8488SAndroid Build Coastguard Worker
1201*5a6e8488SAndroid Build Coastguard Worker /**
1202*5a6e8488SAndroid Build Coastguard Worker * Copies a value to a variable. This is used for storing in dc as well as to
1203*5a6e8488SAndroid Build Coastguard Worker * set function parameters to arguments in bc.
1204*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1205*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the variable or array to copy to.
1206*5a6e8488SAndroid Build Coastguard Worker * @param t The type to copy to. This could be a variable or an array.
1207*5a6e8488SAndroid Build Coastguard Worker */
1208*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_copyToVar(BcProgram * p,size_t idx,BcType t)1209*5a6e8488SAndroid Build Coastguard Worker bc_program_copyToVar(BcProgram* p, size_t idx, BcType t)
1210*5a6e8488SAndroid Build Coastguard Worker {
1211*5a6e8488SAndroid Build Coastguard Worker BcResult *ptr = NULL, r;
1212*5a6e8488SAndroid Build Coastguard Worker BcVec* vec;
1213*5a6e8488SAndroid Build Coastguard Worker BcNum* n = NULL;
1214*5a6e8488SAndroid Build Coastguard Worker bool var = (t == BC_TYPE_VAR);
1215*5a6e8488SAndroid Build Coastguard Worker
1216*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
1217*5a6e8488SAndroid Build Coastguard Worker // Check the stack for dc.
1218*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
1219*5a6e8488SAndroid Build Coastguard Worker {
1220*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
1221*5a6e8488SAndroid Build Coastguard Worker }
1222*5a6e8488SAndroid Build Coastguard Worker #endif
1223*5a6e8488SAndroid Build Coastguard Worker
1224*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
1225*5a6e8488SAndroid Build Coastguard Worker
1226*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &ptr, &n, 0);
1227*5a6e8488SAndroid Build Coastguard Worker
1228*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1229*5a6e8488SAndroid Build Coastguard Worker // Get the variable for a bc function call.
1230*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC)
1231*5a6e8488SAndroid Build Coastguard Worker {
1232*5a6e8488SAndroid Build Coastguard Worker // Type match the result.
1233*5a6e8488SAndroid Build Coastguard Worker bc_program_type_match(ptr, t);
1234*5a6e8488SAndroid Build Coastguard Worker }
1235*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1236*5a6e8488SAndroid Build Coastguard Worker
1237*5a6e8488SAndroid Build Coastguard Worker vec = bc_program_vec(p, idx, t);
1238*5a6e8488SAndroid Build Coastguard Worker
1239*5a6e8488SAndroid Build Coastguard Worker // We can shortcut in dc if it's assigning a string by using
1240*5a6e8488SAndroid Build Coastguard Worker // bc_program_assignStr().
1241*5a6e8488SAndroid Build Coastguard Worker if (ptr->t == BC_RESULT_STR)
1242*5a6e8488SAndroid Build Coastguard Worker {
1243*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STR(n));
1244*5a6e8488SAndroid Build Coastguard Worker
1245*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!var)) bc_err(BC_ERR_EXEC_TYPE);
1246*5a6e8488SAndroid Build Coastguard Worker
1247*5a6e8488SAndroid Build Coastguard Worker bc_program_assignStr(p, n, vec, true);
1248*5a6e8488SAndroid Build Coastguard Worker
1249*5a6e8488SAndroid Build Coastguard Worker return;
1250*5a6e8488SAndroid Build Coastguard Worker }
1251*5a6e8488SAndroid Build Coastguard Worker
1252*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1253*5a6e8488SAndroid Build Coastguard Worker
1254*5a6e8488SAndroid Build Coastguard Worker // Just create and copy for a normal variable.
1255*5a6e8488SAndroid Build Coastguard Worker if (var)
1256*5a6e8488SAndroid Build Coastguard Worker {
1257*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_STR(n))
1258*5a6e8488SAndroid Build Coastguard Worker {
1259*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1260*5a6e8488SAndroid Build Coastguard Worker memcpy(&r.d.n, n, sizeof(BcNum));
1261*5a6e8488SAndroid Build Coastguard Worker }
1262*5a6e8488SAndroid Build Coastguard Worker else bc_num_createCopy(&r.d.n, n);
1263*5a6e8488SAndroid Build Coastguard Worker }
1264*5a6e8488SAndroid Build Coastguard Worker else
1265*5a6e8488SAndroid Build Coastguard Worker {
1266*5a6e8488SAndroid Build Coastguard Worker // If we get here, we are handling an array. This is one place we need
1267*5a6e8488SAndroid Build Coastguard Worker // to cast the number from bc_program_num() to a vector.
1268*5a6e8488SAndroid Build Coastguard Worker BcVec* v = (BcVec*) n;
1269*5a6e8488SAndroid Build Coastguard Worker BcVec* rv = &r.d.v;
1270*5a6e8488SAndroid Build Coastguard Worker
1271*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1272*5a6e8488SAndroid Build Coastguard Worker
1273*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC)
1274*5a6e8488SAndroid Build Coastguard Worker {
1275*5a6e8488SAndroid Build Coastguard Worker bool ref, ref_size;
1276*5a6e8488SAndroid Build Coastguard Worker
1277*5a6e8488SAndroid Build Coastguard Worker // True if we are using a reference.
1278*5a6e8488SAndroid Build Coastguard Worker ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF);
1279*5a6e8488SAndroid Build Coastguard Worker
1280*5a6e8488SAndroid Build Coastguard Worker // True if we already have a reference vector. This is slightly
1281*5a6e8488SAndroid Build Coastguard Worker // (okay, a lot; it just doesn't look that way) different from
1282*5a6e8488SAndroid Build Coastguard Worker // above. The above means that we need to construct a reference
1283*5a6e8488SAndroid Build Coastguard Worker // vector, whereas this means that we have one and we might have to
1284*5a6e8488SAndroid Build Coastguard Worker // *dereference* it.
1285*5a6e8488SAndroid Build Coastguard Worker ref_size = (v->size == sizeof(uchar));
1286*5a6e8488SAndroid Build Coastguard Worker
1287*5a6e8488SAndroid Build Coastguard Worker // If we *should* have a reference.
1288*5a6e8488SAndroid Build Coastguard Worker if (ref || (ref_size && t == BC_TYPE_REF))
1289*5a6e8488SAndroid Build Coastguard Worker {
1290*5a6e8488SAndroid Build Coastguard Worker // Create a new reference vector.
1291*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(rv, sizeof(uchar), BC_DTOR_NONE);
1292*5a6e8488SAndroid Build Coastguard Worker
1293*5a6e8488SAndroid Build Coastguard Worker // If this is true, then we need to construct a reference.
1294*5a6e8488SAndroid Build Coastguard Worker if (ref)
1295*5a6e8488SAndroid Build Coastguard Worker {
1296*5a6e8488SAndroid Build Coastguard Worker // Make sure the pointer was not invalidated.
1297*5a6e8488SAndroid Build Coastguard Worker vec = bc_program_vec(p, idx, t);
1298*5a6e8488SAndroid Build Coastguard Worker
1299*5a6e8488SAndroid Build Coastguard Worker // Push the indices onto the reference vector. This takes
1300*5a6e8488SAndroid Build Coastguard Worker // care of last; it ensures the reference goes to the right
1301*5a6e8488SAndroid Build Coastguard Worker // place.
1302*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushIndex(rv, ptr->d.loc.loc);
1303*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushIndex(rv, ptr->d.loc.stack_idx);
1304*5a6e8488SAndroid Build Coastguard Worker }
1305*5a6e8488SAndroid Build Coastguard Worker // If we get here, we are copying a ref to a ref. Just push a
1306*5a6e8488SAndroid Build Coastguard Worker // copy of all of the bytes.
1307*5a6e8488SAndroid Build Coastguard Worker else bc_vec_npush(rv, v->len * sizeof(uchar), v->v);
1308*5a6e8488SAndroid Build Coastguard Worker
1309*5a6e8488SAndroid Build Coastguard Worker // Push the reference vector onto the array stack and pop the
1310*5a6e8488SAndroid Build Coastguard Worker // source.
1311*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(vec, &r.d);
1312*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
1313*5a6e8488SAndroid Build Coastguard Worker
1314*5a6e8488SAndroid Build Coastguard Worker // We need to return early to avoid executing code that we must
1315*5a6e8488SAndroid Build Coastguard Worker // not touch.
1316*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1317*5a6e8488SAndroid Build Coastguard Worker return;
1318*5a6e8488SAndroid Build Coastguard Worker }
1319*5a6e8488SAndroid Build Coastguard Worker // If we get here, we have a reference, but we need an array, so
1320*5a6e8488SAndroid Build Coastguard Worker // dereference the array.
1321*5a6e8488SAndroid Build Coastguard Worker else if (ref_size && t != BC_TYPE_REF)
1322*5a6e8488SAndroid Build Coastguard Worker {
1323*5a6e8488SAndroid Build Coastguard Worker v = bc_program_dereference(p, v);
1324*5a6e8488SAndroid Build Coastguard Worker }
1325*5a6e8488SAndroid Build Coastguard Worker }
1326*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1327*5a6e8488SAndroid Build Coastguard Worker
1328*5a6e8488SAndroid Build Coastguard Worker // If we get here, we need to copy the array because in bc, all
1329*5a6e8488SAndroid Build Coastguard Worker // arguments are passed by value. Yes, this is expensive.
1330*5a6e8488SAndroid Build Coastguard Worker bc_array_init(rv, true);
1331*5a6e8488SAndroid Build Coastguard Worker bc_array_copy(rv, v);
1332*5a6e8488SAndroid Build Coastguard Worker }
1333*5a6e8488SAndroid Build Coastguard Worker
1334*5a6e8488SAndroid Build Coastguard Worker // Push the vector onto the array stack and pop the source.
1335*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(vec, &r.d);
1336*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
1337*5a6e8488SAndroid Build Coastguard Worker
1338*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1339*5a6e8488SAndroid Build Coastguard Worker }
1340*5a6e8488SAndroid Build Coastguard Worker
1341*5a6e8488SAndroid Build Coastguard Worker void
bc_program_assignBuiltin(BcProgram * p,bool scale,bool obase,BcBigDig val)1342*5a6e8488SAndroid Build Coastguard Worker bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val)
1343*5a6e8488SAndroid Build Coastguard Worker {
1344*5a6e8488SAndroid Build Coastguard Worker BcBigDig* ptr_t;
1345*5a6e8488SAndroid Build Coastguard Worker BcBigDig max, min;
1346*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1347*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
1348*5a6e8488SAndroid Build Coastguard Worker BcBigDig* ptr;
1349*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1350*5a6e8488SAndroid Build Coastguard Worker
1351*5a6e8488SAndroid Build Coastguard Worker assert(!scale || !obase);
1352*5a6e8488SAndroid Build Coastguard Worker
1353*5a6e8488SAndroid Build Coastguard Worker // Scale needs handling separate from ibase and obase.
1354*5a6e8488SAndroid Build Coastguard Worker if (scale)
1355*5a6e8488SAndroid Build Coastguard Worker {
1356*5a6e8488SAndroid Build Coastguard Worker // Set the min and max.
1357*5a6e8488SAndroid Build Coastguard Worker min = 0;
1358*5a6e8488SAndroid Build Coastguard Worker max = vm->maxes[BC_PROG_GLOBALS_SCALE];
1359*5a6e8488SAndroid Build Coastguard Worker
1360*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1361*5a6e8488SAndroid Build Coastguard Worker // Get a pointer to the stack.
1362*5a6e8488SAndroid Build Coastguard Worker v = p->globals_v + BC_PROG_GLOBALS_SCALE;
1363*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1364*5a6e8488SAndroid Build Coastguard Worker
1365*5a6e8488SAndroid Build Coastguard Worker // Get a pointer to the current value.
1366*5a6e8488SAndroid Build Coastguard Worker ptr_t = p->globals + BC_PROG_GLOBALS_SCALE;
1367*5a6e8488SAndroid Build Coastguard Worker }
1368*5a6e8488SAndroid Build Coastguard Worker else
1369*5a6e8488SAndroid Build Coastguard Worker {
1370*5a6e8488SAndroid Build Coastguard Worker // Set the min and max.
1371*5a6e8488SAndroid Build Coastguard Worker min = BC_NUM_MIN_BASE;
1372*5a6e8488SAndroid Build Coastguard Worker if (BC_ENABLE_EXTRA_MATH && obase && (BC_IS_DC || !BC_IS_POSIX))
1373*5a6e8488SAndroid Build Coastguard Worker {
1374*5a6e8488SAndroid Build Coastguard Worker min = 0;
1375*5a6e8488SAndroid Build Coastguard Worker }
1376*5a6e8488SAndroid Build Coastguard Worker max = vm->maxes[obase + BC_PROG_GLOBALS_IBASE];
1377*5a6e8488SAndroid Build Coastguard Worker
1378*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1379*5a6e8488SAndroid Build Coastguard Worker // Get a pointer to the stack.
1380*5a6e8488SAndroid Build Coastguard Worker v = p->globals_v + BC_PROG_GLOBALS_IBASE + obase;
1381*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1382*5a6e8488SAndroid Build Coastguard Worker
1383*5a6e8488SAndroid Build Coastguard Worker // Get a pointer to the current value.
1384*5a6e8488SAndroid Build Coastguard Worker ptr_t = p->globals + BC_PROG_GLOBALS_IBASE + obase;
1385*5a6e8488SAndroid Build Coastguard Worker }
1386*5a6e8488SAndroid Build Coastguard Worker
1387*5a6e8488SAndroid Build Coastguard Worker // Check for error.
1388*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(val > max || val < min))
1389*5a6e8488SAndroid Build Coastguard Worker {
1390*5a6e8488SAndroid Build Coastguard Worker BcErr e;
1391*5a6e8488SAndroid Build Coastguard Worker
1392*5a6e8488SAndroid Build Coastguard Worker // This grabs the right error.
1393*5a6e8488SAndroid Build Coastguard Worker if (scale) e = BC_ERR_EXEC_SCALE;
1394*5a6e8488SAndroid Build Coastguard Worker else if (obase) e = BC_ERR_EXEC_OBASE;
1395*5a6e8488SAndroid Build Coastguard Worker else e = BC_ERR_EXEC_IBASE;
1396*5a6e8488SAndroid Build Coastguard Worker
1397*5a6e8488SAndroid Build Coastguard Worker bc_verr(e, min, max);
1398*5a6e8488SAndroid Build Coastguard Worker }
1399*5a6e8488SAndroid Build Coastguard Worker
1400*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1401*5a6e8488SAndroid Build Coastguard Worker // Set the top of the stack.
1402*5a6e8488SAndroid Build Coastguard Worker ptr = bc_vec_top(v);
1403*5a6e8488SAndroid Build Coastguard Worker *ptr = val;
1404*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1405*5a6e8488SAndroid Build Coastguard Worker
1406*5a6e8488SAndroid Build Coastguard Worker // Set the actual global variable.
1407*5a6e8488SAndroid Build Coastguard Worker *ptr_t = val;
1408*5a6e8488SAndroid Build Coastguard Worker }
1409*5a6e8488SAndroid Build Coastguard Worker
1410*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1411*5a6e8488SAndroid Build Coastguard Worker void
bc_program_assignSeed(BcProgram * p,BcNum * val)1412*5a6e8488SAndroid Build Coastguard Worker bc_program_assignSeed(BcProgram* p, BcNum* val)
1413*5a6e8488SAndroid Build Coastguard Worker {
1414*5a6e8488SAndroid Build Coastguard Worker bc_num_rng(val, &p->rng);
1415*5a6e8488SAndroid Build Coastguard Worker }
1416*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1417*5a6e8488SAndroid Build Coastguard Worker
1418*5a6e8488SAndroid Build Coastguard Worker /**
1419*5a6e8488SAndroid Build Coastguard Worker * Executes an assignment operator.
1420*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1421*5a6e8488SAndroid Build Coastguard Worker * @param inst The assignment operator to execute.
1422*5a6e8488SAndroid Build Coastguard Worker */
1423*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_assign(BcProgram * p,uchar inst)1424*5a6e8488SAndroid Build Coastguard Worker bc_program_assign(BcProgram* p, uchar inst)
1425*5a6e8488SAndroid Build Coastguard Worker {
1426*5a6e8488SAndroid Build Coastguard Worker // The local use_val is true when the assigned value needs to be copied.
1427*5a6e8488SAndroid Build Coastguard Worker BcResult* left;
1428*5a6e8488SAndroid Build Coastguard Worker BcResult* right;
1429*5a6e8488SAndroid Build Coastguard Worker BcResult res;
1430*5a6e8488SAndroid Build Coastguard Worker BcNum* l;
1431*5a6e8488SAndroid Build Coastguard Worker BcNum* r;
1432*5a6e8488SAndroid Build Coastguard Worker bool ob, sc, use_val = BC_INST_USE_VAL(inst);
1433*5a6e8488SAndroid Build Coastguard Worker
1434*5a6e8488SAndroid Build Coastguard Worker bc_program_assignPrep(p, &left, &l, &right, &r);
1435*5a6e8488SAndroid Build Coastguard Worker
1436*5a6e8488SAndroid Build Coastguard Worker // Assigning to a string should be impossible simply because of the parse.
1437*5a6e8488SAndroid Build Coastguard Worker assert(left->t != BC_RESULT_STR);
1438*5a6e8488SAndroid Build Coastguard Worker
1439*5a6e8488SAndroid Build Coastguard Worker // If we are assigning a string...
1440*5a6e8488SAndroid Build Coastguard Worker if (right->t == BC_RESULT_STR)
1441*5a6e8488SAndroid Build Coastguard Worker {
1442*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STR(r));
1443*5a6e8488SAndroid Build Coastguard Worker
1444*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1445*5a6e8488SAndroid Build Coastguard Worker if (inst != BC_INST_ASSIGN && inst != BC_INST_ASSIGN_NO_VAL)
1446*5a6e8488SAndroid Build Coastguard Worker {
1447*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_TYPE);
1448*5a6e8488SAndroid Build Coastguard Worker }
1449*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1450*5a6e8488SAndroid Build Coastguard Worker
1451*5a6e8488SAndroid Build Coastguard Worker // If we are assigning to an array element...
1452*5a6e8488SAndroid Build Coastguard Worker if (left->t == BC_RESULT_ARRAY_ELEM)
1453*5a6e8488SAndroid Build Coastguard Worker {
1454*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1455*5a6e8488SAndroid Build Coastguard Worker
1456*5a6e8488SAndroid Build Coastguard Worker // We need to free the number and clear it.
1457*5a6e8488SAndroid Build Coastguard Worker bc_num_free(l);
1458*5a6e8488SAndroid Build Coastguard Worker
1459*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1460*5a6e8488SAndroid Build Coastguard Worker memcpy(l, r, sizeof(BcNum));
1461*5a6e8488SAndroid Build Coastguard Worker
1462*5a6e8488SAndroid Build Coastguard Worker // Now we can pop the results.
1463*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->results, 2);
1464*5a6e8488SAndroid Build Coastguard Worker
1465*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1466*5a6e8488SAndroid Build Coastguard Worker }
1467*5a6e8488SAndroid Build Coastguard Worker else
1468*5a6e8488SAndroid Build Coastguard Worker {
1469*5a6e8488SAndroid Build Coastguard Worker // If we get here, we are assigning to a variable, which we can use
1470*5a6e8488SAndroid Build Coastguard Worker // bc_program_assignStr() for.
1471*5a6e8488SAndroid Build Coastguard Worker BcVec* v = bc_program_vec(p, left->d.loc.loc, BC_TYPE_VAR);
1472*5a6e8488SAndroid Build Coastguard Worker bc_program_assignStr(p, r, v, false);
1473*5a6e8488SAndroid Build Coastguard Worker }
1474*5a6e8488SAndroid Build Coastguard Worker
1475*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1476*5a6e8488SAndroid Build Coastguard Worker
1477*5a6e8488SAndroid Build Coastguard Worker // If this is true, the value is going to be used again, so we want to
1478*5a6e8488SAndroid Build Coastguard Worker // push a temporary with the string.
1479*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_ASSIGN)
1480*5a6e8488SAndroid Build Coastguard Worker {
1481*5a6e8488SAndroid Build Coastguard Worker res.t = BC_RESULT_STR;
1482*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1483*5a6e8488SAndroid Build Coastguard Worker memcpy(&res.d.n, r, sizeof(BcNum));
1484*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &res);
1485*5a6e8488SAndroid Build Coastguard Worker }
1486*5a6e8488SAndroid Build Coastguard Worker
1487*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1488*5a6e8488SAndroid Build Coastguard Worker
1489*5a6e8488SAndroid Build Coastguard Worker // By using bc_program_assignStr(), we short-circuited this, so return.
1490*5a6e8488SAndroid Build Coastguard Worker return;
1491*5a6e8488SAndroid Build Coastguard Worker }
1492*5a6e8488SAndroid Build Coastguard Worker
1493*5a6e8488SAndroid Build Coastguard Worker // If we have a normal assignment operator, not a math one...
1494*5a6e8488SAndroid Build Coastguard Worker if (BC_INST_IS_ASSIGN(inst))
1495*5a6e8488SAndroid Build Coastguard Worker {
1496*5a6e8488SAndroid Build Coastguard Worker // Assigning to a variable that has a string here is fine because there
1497*5a6e8488SAndroid Build Coastguard Worker // is no math done on it.
1498*5a6e8488SAndroid Build Coastguard Worker
1499*5a6e8488SAndroid Build Coastguard Worker // BC_RESULT_TEMP, BC_RESULT_IBASE, BC_RESULT_OBASE, BC_RESULT_SCALE,
1500*5a6e8488SAndroid Build Coastguard Worker // and BC_RESULT_SEED all have temporary copies. Because that's the
1501*5a6e8488SAndroid Build Coastguard Worker // case, we can free the left and just move the value over. We set the
1502*5a6e8488SAndroid Build Coastguard Worker // type of right to BC_RESULT_ZERO in order to prevent it from being
1503*5a6e8488SAndroid Build Coastguard Worker // freed. We also don't have to worry about BC_RESULT_STR because it's
1504*5a6e8488SAndroid Build Coastguard Worker // take care of above.
1505*5a6e8488SAndroid Build Coastguard Worker if (right->t == BC_RESULT_TEMP || right->t >= BC_RESULT_IBASE)
1506*5a6e8488SAndroid Build Coastguard Worker {
1507*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1508*5a6e8488SAndroid Build Coastguard Worker
1509*5a6e8488SAndroid Build Coastguard Worker bc_num_free(l);
1510*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1511*5a6e8488SAndroid Build Coastguard Worker memcpy(l, r, sizeof(BcNum));
1512*5a6e8488SAndroid Build Coastguard Worker right->t = BC_RESULT_ZERO;
1513*5a6e8488SAndroid Build Coastguard Worker
1514*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1515*5a6e8488SAndroid Build Coastguard Worker }
1516*5a6e8488SAndroid Build Coastguard Worker // Copy over.
1517*5a6e8488SAndroid Build Coastguard Worker else bc_num_copy(l, r);
1518*5a6e8488SAndroid Build Coastguard Worker }
1519*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1520*5a6e8488SAndroid Build Coastguard Worker else
1521*5a6e8488SAndroid Build Coastguard Worker {
1522*5a6e8488SAndroid Build Coastguard Worker // If we get here, we are doing a math assignment (+=, -=, etc.). So
1523*5a6e8488SAndroid Build Coastguard Worker // we need to prepare for a binary operator.
1524*5a6e8488SAndroid Build Coastguard Worker BcBigDig scale = BC_PROG_SCALE(p);
1525*5a6e8488SAndroid Build Coastguard Worker
1526*5a6e8488SAndroid Build Coastguard Worker // At this point, the left side could still be a string because it could
1527*5a6e8488SAndroid Build Coastguard Worker // be a variable that has the string. If that's the case, we have a type
1528*5a6e8488SAndroid Build Coastguard Worker // error.
1529*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_STR(l)) bc_err(BC_ERR_EXEC_TYPE);
1530*5a6e8488SAndroid Build Coastguard Worker
1531*5a6e8488SAndroid Build Coastguard Worker // Get the right type of assignment operator, whether val is used or
1532*5a6e8488SAndroid Build Coastguard Worker // NO_VAL for performance.
1533*5a6e8488SAndroid Build Coastguard Worker if (!use_val)
1534*5a6e8488SAndroid Build Coastguard Worker {
1535*5a6e8488SAndroid Build Coastguard Worker inst -= (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
1536*5a6e8488SAndroid Build Coastguard Worker }
1537*5a6e8488SAndroid Build Coastguard Worker
1538*5a6e8488SAndroid Build Coastguard Worker assert(BC_NUM_RDX_VALID(l));
1539*5a6e8488SAndroid Build Coastguard Worker assert(BC_NUM_RDX_VALID(r));
1540*5a6e8488SAndroid Build Coastguard Worker
1541*5a6e8488SAndroid Build Coastguard Worker // Run the actual operation. We do not need worry about reallocating l
1542*5a6e8488SAndroid Build Coastguard Worker // because bc_num_binary() does that behind the scenes for us.
1543*5a6e8488SAndroid Build Coastguard Worker bc_program_ops[inst - BC_INST_ASSIGN_POWER](l, r, l, scale);
1544*5a6e8488SAndroid Build Coastguard Worker }
1545*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1546*5a6e8488SAndroid Build Coastguard Worker
1547*5a6e8488SAndroid Build Coastguard Worker ob = (left->t == BC_RESULT_OBASE);
1548*5a6e8488SAndroid Build Coastguard Worker sc = (left->t == BC_RESULT_SCALE);
1549*5a6e8488SAndroid Build Coastguard Worker
1550*5a6e8488SAndroid Build Coastguard Worker // The globals need special handling, especially the non-seed ones. The
1551*5a6e8488SAndroid Build Coastguard Worker // first part of the if statement handles them.
1552*5a6e8488SAndroid Build Coastguard Worker if (ob || sc || left->t == BC_RESULT_IBASE)
1553*5a6e8488SAndroid Build Coastguard Worker {
1554*5a6e8488SAndroid Build Coastguard Worker // Get the actual value.
1555*5a6e8488SAndroid Build Coastguard Worker BcBigDig val = bc_num_bigdig(l);
1556*5a6e8488SAndroid Build Coastguard Worker
1557*5a6e8488SAndroid Build Coastguard Worker bc_program_assignBuiltin(p, sc, ob, val);
1558*5a6e8488SAndroid Build Coastguard Worker }
1559*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1560*5a6e8488SAndroid Build Coastguard Worker // To assign to steed, let bc_num_rng() do its magic.
1561*5a6e8488SAndroid Build Coastguard Worker else if (left->t == BC_RESULT_SEED) bc_program_assignSeed(p, l);
1562*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1563*5a6e8488SAndroid Build Coastguard Worker
1564*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1565*5a6e8488SAndroid Build Coastguard Worker
1566*5a6e8488SAndroid Build Coastguard Worker // If we needed to use the value, then we need to copy it. Otherwise, we can
1567*5a6e8488SAndroid Build Coastguard Worker // pop indiscriminately. Oh, and the copy should be a BC_RESULT_TEMP.
1568*5a6e8488SAndroid Build Coastguard Worker if (use_val)
1569*5a6e8488SAndroid Build Coastguard Worker {
1570*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(&res.d.n, l);
1571*5a6e8488SAndroid Build Coastguard Worker res.t = BC_RESULT_TEMP;
1572*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->results, 2);
1573*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &res);
1574*5a6e8488SAndroid Build Coastguard Worker }
1575*5a6e8488SAndroid Build Coastguard Worker else bc_vec_npop(&p->results, 2);
1576*5a6e8488SAndroid Build Coastguard Worker
1577*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1578*5a6e8488SAndroid Build Coastguard Worker }
1579*5a6e8488SAndroid Build Coastguard Worker
1580*5a6e8488SAndroid Build Coastguard Worker /**
1581*5a6e8488SAndroid Build Coastguard Worker * Pushes a variable's value onto the results stack.
1582*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1583*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector to pull the variable's index out of.
1584*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the start of the index in the bytecode
1585*5a6e8488SAndroid Build Coastguard Worker * vector, and will be updated to point after the index on return.
1586*5a6e8488SAndroid Build Coastguard Worker * @param pop True if the variable's value should be popped off its stack.
1587*5a6e8488SAndroid Build Coastguard Worker * This is only used in dc.
1588*5a6e8488SAndroid Build Coastguard Worker * @param copy True if the variable's value should be copied to the results
1589*5a6e8488SAndroid Build Coastguard Worker * stack. This is only used in dc.
1590*5a6e8488SAndroid Build Coastguard Worker */
1591*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_pushVar(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool pop,bool copy)1592*5a6e8488SAndroid Build Coastguard Worker bc_program_pushVar(BcProgram* p, const char* restrict code,
1593*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn, bool pop, bool copy)
1594*5a6e8488SAndroid Build Coastguard Worker {
1595*5a6e8488SAndroid Build Coastguard Worker BcResult r;
1596*5a6e8488SAndroid Build Coastguard Worker size_t idx = bc_program_index(code, bgn);
1597*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
1598*5a6e8488SAndroid Build Coastguard Worker
1599*5a6e8488SAndroid Build Coastguard Worker // Set the result appropriately.
1600*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_VAR;
1601*5a6e8488SAndroid Build Coastguard Worker r.d.loc.loc = idx;
1602*5a6e8488SAndroid Build Coastguard Worker
1603*5a6e8488SAndroid Build Coastguard Worker // Get the stack for the variable. This is used in both bc and dc.
1604*5a6e8488SAndroid Build Coastguard Worker v = bc_program_vec(p, idx, BC_TYPE_VAR);
1605*5a6e8488SAndroid Build Coastguard Worker r.d.loc.stack_idx = v->len - 1;
1606*5a6e8488SAndroid Build Coastguard Worker
1607*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
1608*5a6e8488SAndroid Build Coastguard Worker // If this condition is true, then we have the hard case, where we have to
1609*5a6e8488SAndroid Build Coastguard Worker // adjust dc registers.
1610*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC && (pop || copy))
1611*5a6e8488SAndroid Build Coastguard Worker {
1612*5a6e8488SAndroid Build Coastguard Worker // Get the number at the top at the top of the stack.
1613*5a6e8488SAndroid Build Coastguard Worker BcNum* num = bc_vec_top(v);
1614*5a6e8488SAndroid Build Coastguard Worker
1615*5a6e8488SAndroid Build Coastguard Worker // Ensure there are enough elements on the stack.
1616*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(v, 2 - copy)))
1617*5a6e8488SAndroid Build Coastguard Worker {
1618*5a6e8488SAndroid Build Coastguard Worker const char* name = bc_map_name(&p->var_map, idx);
1619*5a6e8488SAndroid Build Coastguard Worker bc_verr(BC_ERR_EXEC_STACK_REGISTER, name);
1620*5a6e8488SAndroid Build Coastguard Worker }
1621*5a6e8488SAndroid Build Coastguard Worker
1622*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(v, 2 - copy));
1623*5a6e8488SAndroid Build Coastguard Worker
1624*5a6e8488SAndroid Build Coastguard Worker // If the top of the stack is actually a number...
1625*5a6e8488SAndroid Build Coastguard Worker if (!BC_PROG_STR(num))
1626*5a6e8488SAndroid Build Coastguard Worker {
1627*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1628*5a6e8488SAndroid Build Coastguard Worker
1629*5a6e8488SAndroid Build Coastguard Worker // Create a copy to go onto the results stack as appropriate.
1630*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_TEMP;
1631*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(&r.d.n, num);
1632*5a6e8488SAndroid Build Coastguard Worker
1633*5a6e8488SAndroid Build Coastguard Worker // If we are not actually copying, we need to do a replace, so pop.
1634*5a6e8488SAndroid Build Coastguard Worker if (!copy) bc_vec_pop(v);
1635*5a6e8488SAndroid Build Coastguard Worker
1636*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
1637*5a6e8488SAndroid Build Coastguard Worker
1638*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1639*5a6e8488SAndroid Build Coastguard Worker
1640*5a6e8488SAndroid Build Coastguard Worker return;
1641*5a6e8488SAndroid Build Coastguard Worker }
1642*5a6e8488SAndroid Build Coastguard Worker else
1643*5a6e8488SAndroid Build Coastguard Worker {
1644*5a6e8488SAndroid Build Coastguard Worker // Set the string result. We can just memcpy because all of the
1645*5a6e8488SAndroid Build Coastguard Worker // fields in the num should be cleared.
1646*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1647*5a6e8488SAndroid Build Coastguard Worker memcpy(&r.d.n, num, sizeof(BcNum));
1648*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_STR;
1649*5a6e8488SAndroid Build Coastguard Worker }
1650*5a6e8488SAndroid Build Coastguard Worker
1651*5a6e8488SAndroid Build Coastguard Worker // If we are not actually copying, we need to do a replace, so pop.
1652*5a6e8488SAndroid Build Coastguard Worker if (!copy) bc_vec_pop(v);
1653*5a6e8488SAndroid Build Coastguard Worker }
1654*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
1655*5a6e8488SAndroid Build Coastguard Worker
1656*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
1657*5a6e8488SAndroid Build Coastguard Worker }
1658*5a6e8488SAndroid Build Coastguard Worker
1659*5a6e8488SAndroid Build Coastguard Worker /**
1660*5a6e8488SAndroid Build Coastguard Worker * Pushes an array or an array element onto the results stack.
1661*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1662*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector to pull the variable's index out of.
1663*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the start of the index in the bytecode
1664*5a6e8488SAndroid Build Coastguard Worker * vector, and will be updated to point after the index on return.
1665*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction; whether to push an array or an array element.
1666*5a6e8488SAndroid Build Coastguard Worker */
1667*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_pushArray(BcProgram * p,const char * restrict code,size_t * restrict bgn,uchar inst)1668*5a6e8488SAndroid Build Coastguard Worker bc_program_pushArray(BcProgram* p, const char* restrict code,
1669*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn, uchar inst)
1670*5a6e8488SAndroid Build Coastguard Worker {
1671*5a6e8488SAndroid Build Coastguard Worker BcResult r;
1672*5a6e8488SAndroid Build Coastguard Worker BcResult* operand;
1673*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
1674*5a6e8488SAndroid Build Coastguard Worker BcBigDig temp;
1675*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
1676*5a6e8488SAndroid Build Coastguard Worker
1677*5a6e8488SAndroid Build Coastguard Worker // Get the index of the array.
1678*5a6e8488SAndroid Build Coastguard Worker r.d.loc.loc = bc_program_index(code, bgn);
1679*5a6e8488SAndroid Build Coastguard Worker
1680*5a6e8488SAndroid Build Coastguard Worker // We need the array to get its length.
1681*5a6e8488SAndroid Build Coastguard Worker v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY);
1682*5a6e8488SAndroid Build Coastguard Worker assert(v != NULL);
1683*5a6e8488SAndroid Build Coastguard Worker
1684*5a6e8488SAndroid Build Coastguard Worker r.d.loc.stack_idx = v->len - 1;
1685*5a6e8488SAndroid Build Coastguard Worker
1686*5a6e8488SAndroid Build Coastguard Worker // Doing an array is easy; just set the result type and finish.
1687*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_ARRAY)
1688*5a6e8488SAndroid Build Coastguard Worker {
1689*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_ARRAY;
1690*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
1691*5a6e8488SAndroid Build Coastguard Worker return;
1692*5a6e8488SAndroid Build Coastguard Worker }
1693*5a6e8488SAndroid Build Coastguard Worker
1694*5a6e8488SAndroid Build Coastguard Worker // Grab the top element of the results stack for the array index.
1695*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(p, &operand, &num, 0);
1696*5a6e8488SAndroid Build Coastguard Worker temp = bc_num_bigdig(num);
1697*5a6e8488SAndroid Build Coastguard Worker
1698*5a6e8488SAndroid Build Coastguard Worker // Set the result.
1699*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_ARRAY_ELEM;
1700*5a6e8488SAndroid Build Coastguard Worker r.d.loc.idx = (size_t) temp;
1701*5a6e8488SAndroid Build Coastguard Worker
1702*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1703*5a6e8488SAndroid Build Coastguard Worker
1704*5a6e8488SAndroid Build Coastguard Worker // Pop the index and push the element.
1705*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
1706*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
1707*5a6e8488SAndroid Build Coastguard Worker
1708*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1709*5a6e8488SAndroid Build Coastguard Worker }
1710*5a6e8488SAndroid Build Coastguard Worker
1711*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
1712*5a6e8488SAndroid Build Coastguard Worker
1713*5a6e8488SAndroid Build Coastguard Worker /**
1714*5a6e8488SAndroid Build Coastguard Worker * Executes an increment or decrement operator. This only handles postfix
1715*5a6e8488SAndroid Build Coastguard Worker * inc/dec because the parser translates prefix inc/dec into an assignment where
1716*5a6e8488SAndroid Build Coastguard Worker * the value is used.
1717*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1718*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction; whether to do an increment or decrement.
1719*5a6e8488SAndroid Build Coastguard Worker */
1720*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_incdec(BcProgram * p,uchar inst)1721*5a6e8488SAndroid Build Coastguard Worker bc_program_incdec(BcProgram* p, uchar inst)
1722*5a6e8488SAndroid Build Coastguard Worker {
1723*5a6e8488SAndroid Build Coastguard Worker BcResult *ptr, res, copy;
1724*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
1725*5a6e8488SAndroid Build Coastguard Worker uchar inst2;
1726*5a6e8488SAndroid Build Coastguard Worker
1727*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(p, &ptr, &num, 0);
1728*5a6e8488SAndroid Build Coastguard Worker
1729*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1730*5a6e8488SAndroid Build Coastguard Worker
1731*5a6e8488SAndroid Build Coastguard Worker // We need a copy from *before* the operation.
1732*5a6e8488SAndroid Build Coastguard Worker copy.t = BC_RESULT_TEMP;
1733*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(©.d.n, num);
1734*5a6e8488SAndroid Build Coastguard Worker
1735*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exit);
1736*5a6e8488SAndroid Build Coastguard Worker
1737*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1738*5a6e8488SAndroid Build Coastguard Worker
1739*5a6e8488SAndroid Build Coastguard Worker // Create the proper assignment.
1740*5a6e8488SAndroid Build Coastguard Worker res.t = BC_RESULT_ONE;
1741*5a6e8488SAndroid Build Coastguard Worker inst2 = BC_INST_ASSIGN_PLUS_NO_VAL + (inst & 0x01);
1742*5a6e8488SAndroid Build Coastguard Worker
1743*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &res);
1744*5a6e8488SAndroid Build Coastguard Worker bc_program_assign(p, inst2);
1745*5a6e8488SAndroid Build Coastguard Worker
1746*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1747*5a6e8488SAndroid Build Coastguard Worker
1748*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, ©);
1749*5a6e8488SAndroid Build Coastguard Worker
1750*5a6e8488SAndroid Build Coastguard Worker BC_UNSETJMP(vm);
1751*5a6e8488SAndroid Build Coastguard Worker
1752*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1753*5a6e8488SAndroid Build Coastguard Worker
1754*5a6e8488SAndroid Build Coastguard Worker // No need to free the copy here because we pushed it onto the stack.
1755*5a6e8488SAndroid Build Coastguard Worker return;
1756*5a6e8488SAndroid Build Coastguard Worker
1757*5a6e8488SAndroid Build Coastguard Worker exit:
1758*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
1759*5a6e8488SAndroid Build Coastguard Worker bc_num_free(©.d.n);
1760*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
1761*5a6e8488SAndroid Build Coastguard Worker }
1762*5a6e8488SAndroid Build Coastguard Worker
1763*5a6e8488SAndroid Build Coastguard Worker /**
1764*5a6e8488SAndroid Build Coastguard Worker * Executes a function call for bc.
1765*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1766*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector to pull the number of arguments and the
1767*5a6e8488SAndroid Build Coastguard Worker * function index out of.
1768*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the start of the indices in the bytecode
1769*5a6e8488SAndroid Build Coastguard Worker * vector, and will be updated to point after the indices on
1770*5a6e8488SAndroid Build Coastguard Worker * return.
1771*5a6e8488SAndroid Build Coastguard Worker */
1772*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_call(BcProgram * p,const char * restrict code,size_t * restrict bgn)1773*5a6e8488SAndroid Build Coastguard Worker bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn)
1774*5a6e8488SAndroid Build Coastguard Worker {
1775*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
1776*5a6e8488SAndroid Build Coastguard Worker size_t i, nargs;
1777*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
1778*5a6e8488SAndroid Build Coastguard Worker BcVec* v;
1779*5a6e8488SAndroid Build Coastguard Worker BcAuto* a;
1780*5a6e8488SAndroid Build Coastguard Worker BcResult* arg;
1781*5a6e8488SAndroid Build Coastguard Worker
1782*5a6e8488SAndroid Build Coastguard Worker // Pull the number of arguments out of the bytecode vector.
1783*5a6e8488SAndroid Build Coastguard Worker nargs = bc_program_index(code, bgn);
1784*5a6e8488SAndroid Build Coastguard Worker
1785*5a6e8488SAndroid Build Coastguard Worker // Set up instruction pointer.
1786*5a6e8488SAndroid Build Coastguard Worker ip.idx = 0;
1787*5a6e8488SAndroid Build Coastguard Worker ip.func = bc_program_index(code, bgn);
1788*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, ip.func);
1789*5a6e8488SAndroid Build Coastguard Worker
1790*5a6e8488SAndroid Build Coastguard Worker // Error checking.
1791*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!f->code.len)) bc_verr(BC_ERR_EXEC_UNDEF_FUNC, f->name);
1792*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(nargs != f->nparams))
1793*5a6e8488SAndroid Build Coastguard Worker {
1794*5a6e8488SAndroid Build Coastguard Worker bc_verr(BC_ERR_EXEC_PARAMS, f->nparams, nargs);
1795*5a6e8488SAndroid Build Coastguard Worker }
1796*5a6e8488SAndroid Build Coastguard Worker
1797*5a6e8488SAndroid Build Coastguard Worker // Set the length of the results stack. We discount the argument, of course.
1798*5a6e8488SAndroid Build Coastguard Worker ip.len = p->results.len - nargs;
1799*5a6e8488SAndroid Build Coastguard Worker
1800*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, nargs));
1801*5a6e8488SAndroid Build Coastguard Worker
1802*5a6e8488SAndroid Build Coastguard Worker // Prepare the globals' stacks.
1803*5a6e8488SAndroid Build Coastguard Worker if (BC_G) bc_program_prepGlobals(p);
1804*5a6e8488SAndroid Build Coastguard Worker
1805*5a6e8488SAndroid Build Coastguard Worker // Push the arguments onto the stacks of their respective parameters.
1806*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < nargs; ++i)
1807*5a6e8488SAndroid Build Coastguard Worker {
1808*5a6e8488SAndroid Build Coastguard Worker arg = bc_vec_top(&p->results);
1809*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL);
1810*5a6e8488SAndroid Build Coastguard Worker
1811*5a6e8488SAndroid Build Coastguard Worker // Get the corresponding parameter.
1812*5a6e8488SAndroid Build Coastguard Worker a = bc_vec_item(&f->autos, nargs - 1 - i);
1813*5a6e8488SAndroid Build Coastguard Worker
1814*5a6e8488SAndroid Build Coastguard Worker // Actually push the value onto the parameter's stack.
1815*5a6e8488SAndroid Build Coastguard Worker bc_program_copyToVar(p, a->idx, a->type);
1816*5a6e8488SAndroid Build Coastguard Worker }
1817*5a6e8488SAndroid Build Coastguard Worker
1818*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1819*5a6e8488SAndroid Build Coastguard Worker
1820*5a6e8488SAndroid Build Coastguard Worker // Push zeroes onto the stacks of the auto variables.
1821*5a6e8488SAndroid Build Coastguard Worker for (; i < f->autos.len; ++i)
1822*5a6e8488SAndroid Build Coastguard Worker {
1823*5a6e8488SAndroid Build Coastguard Worker // Get the auto and its stack.
1824*5a6e8488SAndroid Build Coastguard Worker a = bc_vec_item(&f->autos, i);
1825*5a6e8488SAndroid Build Coastguard Worker v = bc_program_vec(p, a->idx, a->type);
1826*5a6e8488SAndroid Build Coastguard Worker
1827*5a6e8488SAndroid Build Coastguard Worker // If a variable, just push a 0; otherwise, push an array.
1828*5a6e8488SAndroid Build Coastguard Worker if (a->type == BC_TYPE_VAR)
1829*5a6e8488SAndroid Build Coastguard Worker {
1830*5a6e8488SAndroid Build Coastguard Worker BcNum* n = bc_vec_pushEmpty(v);
1831*5a6e8488SAndroid Build Coastguard Worker bc_num_init(n, BC_NUM_DEF_SIZE);
1832*5a6e8488SAndroid Build Coastguard Worker }
1833*5a6e8488SAndroid Build Coastguard Worker else
1834*5a6e8488SAndroid Build Coastguard Worker {
1835*5a6e8488SAndroid Build Coastguard Worker BcVec* v2;
1836*5a6e8488SAndroid Build Coastguard Worker
1837*5a6e8488SAndroid Build Coastguard Worker assert(a->type == BC_TYPE_ARRAY);
1838*5a6e8488SAndroid Build Coastguard Worker
1839*5a6e8488SAndroid Build Coastguard Worker v2 = bc_vec_pushEmpty(v);
1840*5a6e8488SAndroid Build Coastguard Worker bc_array_init(v2, true);
1841*5a6e8488SAndroid Build Coastguard Worker }
1842*5a6e8488SAndroid Build Coastguard Worker }
1843*5a6e8488SAndroid Build Coastguard Worker
1844*5a6e8488SAndroid Build Coastguard Worker // Push the instruction pointer onto the execution stack.
1845*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->stack, &ip);
1846*5a6e8488SAndroid Build Coastguard Worker
1847*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1848*5a6e8488SAndroid Build Coastguard Worker }
1849*5a6e8488SAndroid Build Coastguard Worker
1850*5a6e8488SAndroid Build Coastguard Worker /**
1851*5a6e8488SAndroid Build Coastguard Worker * Executes a return instruction.
1852*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1853*5a6e8488SAndroid Build Coastguard Worker * @param inst The return instruction. bc can return void, and we need to know
1854*5a6e8488SAndroid Build Coastguard Worker * if it is.
1855*5a6e8488SAndroid Build Coastguard Worker */
1856*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_return(BcProgram * p,uchar inst)1857*5a6e8488SAndroid Build Coastguard Worker bc_program_return(BcProgram* p, uchar inst)
1858*5a6e8488SAndroid Build Coastguard Worker {
1859*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
1860*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
1861*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip;
1862*5a6e8488SAndroid Build Coastguard Worker size_t i, nresults;
1863*5a6e8488SAndroid Build Coastguard Worker
1864*5a6e8488SAndroid Build Coastguard Worker // Get the instruction pointer.
1865*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
1866*5a6e8488SAndroid Build Coastguard Worker
1867*5a6e8488SAndroid Build Coastguard Worker // Get the difference between the actual number of results and the number of
1868*5a6e8488SAndroid Build Coastguard Worker // results the caller expects.
1869*5a6e8488SAndroid Build Coastguard Worker nresults = p->results.len - ip->len;
1870*5a6e8488SAndroid Build Coastguard Worker
1871*5a6e8488SAndroid Build Coastguard Worker // If this isn't true, there was a missing call somewhere.
1872*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->stack, 2));
1873*5a6e8488SAndroid Build Coastguard Worker
1874*5a6e8488SAndroid Build Coastguard Worker // If this isn't true, the parser screwed by giving us no value when we
1875*5a6e8488SAndroid Build Coastguard Worker // expected one, or giving us a value when we expected none.
1876*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, ip->len + (inst == BC_INST_RET)));
1877*5a6e8488SAndroid Build Coastguard Worker
1878*5a6e8488SAndroid Build Coastguard Worker // Get the function we are returning from.
1879*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, ip->func);
1880*5a6e8488SAndroid Build Coastguard Worker
1881*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
1882*5a6e8488SAndroid Build Coastguard Worker
1883*5a6e8488SAndroid Build Coastguard Worker // If we are returning normally...
1884*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_RET)
1885*5a6e8488SAndroid Build Coastguard Worker {
1886*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
1887*5a6e8488SAndroid Build Coastguard Worker BcResult* operand;
1888*5a6e8488SAndroid Build Coastguard Worker
1889*5a6e8488SAndroid Build Coastguard Worker // Prepare and copy the return value.
1890*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &operand, &num, 1);
1891*5a6e8488SAndroid Build Coastguard Worker
1892*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_STR(num))
1893*5a6e8488SAndroid Build Coastguard Worker {
1894*5a6e8488SAndroid Build Coastguard Worker // We need to set this because otherwise, it will be a
1895*5a6e8488SAndroid Build Coastguard Worker // BC_RESULT_TEMP, and BC_RESULT_TEMP needs an actual number to make
1896*5a6e8488SAndroid Build Coastguard Worker // it easier to do type checking.
1897*5a6e8488SAndroid Build Coastguard Worker res->t = BC_RESULT_STR;
1898*5a6e8488SAndroid Build Coastguard Worker
1899*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
1900*5a6e8488SAndroid Build Coastguard Worker memcpy(&res->d.n, num, sizeof(BcNum));
1901*5a6e8488SAndroid Build Coastguard Worker }
1902*5a6e8488SAndroid Build Coastguard Worker else
1903*5a6e8488SAndroid Build Coastguard Worker {
1904*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1905*5a6e8488SAndroid Build Coastguard Worker
1906*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(&res->d.n, num);
1907*5a6e8488SAndroid Build Coastguard Worker }
1908*5a6e8488SAndroid Build Coastguard Worker }
1909*5a6e8488SAndroid Build Coastguard Worker // Void is easy; set the result.
1910*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_RET_VOID) res->t = BC_RESULT_VOID;
1911*5a6e8488SAndroid Build Coastguard Worker else
1912*5a6e8488SAndroid Build Coastguard Worker {
1913*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1914*5a6e8488SAndroid Build Coastguard Worker
1915*5a6e8488SAndroid Build Coastguard Worker // If we get here, the instruction is for returning a zero, so do that.
1916*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
1917*5a6e8488SAndroid Build Coastguard Worker }
1918*5a6e8488SAndroid Build Coastguard Worker
1919*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYUNLOCK;
1920*5a6e8488SAndroid Build Coastguard Worker
1921*5a6e8488SAndroid Build Coastguard Worker // We need to pop items off of the stacks of arguments and autos as well.
1922*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < f->autos.len; ++i)
1923*5a6e8488SAndroid Build Coastguard Worker {
1924*5a6e8488SAndroid Build Coastguard Worker BcAuto* a = bc_vec_item(&f->autos, i);
1925*5a6e8488SAndroid Build Coastguard Worker BcVec* v = bc_program_vec(p, a->idx, a->type);
1926*5a6e8488SAndroid Build Coastguard Worker
1927*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(v);
1928*5a6e8488SAndroid Build Coastguard Worker }
1929*5a6e8488SAndroid Build Coastguard Worker
1930*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1931*5a6e8488SAndroid Build Coastguard Worker
1932*5a6e8488SAndroid Build Coastguard Worker // When we retire, pop all of the unused results.
1933*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, nresults);
1934*5a6e8488SAndroid Build Coastguard Worker
1935*5a6e8488SAndroid Build Coastguard Worker // Pop the globals, if necessary.
1936*5a6e8488SAndroid Build Coastguard Worker if (BC_G) bc_program_popGlobals(p, false);
1937*5a6e8488SAndroid Build Coastguard Worker
1938*5a6e8488SAndroid Build Coastguard Worker // Pop the stack. This is what causes the function to actually "return."
1939*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->stack);
1940*5a6e8488SAndroid Build Coastguard Worker
1941*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
1942*5a6e8488SAndroid Build Coastguard Worker }
1943*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
1944*5a6e8488SAndroid Build Coastguard Worker
1945*5a6e8488SAndroid Build Coastguard Worker /**
1946*5a6e8488SAndroid Build Coastguard Worker * Executes a builtin function.
1947*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
1948*5a6e8488SAndroid Build Coastguard Worker * @param inst The builtin to execute.
1949*5a6e8488SAndroid Build Coastguard Worker */
1950*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_builtin(BcProgram * p,uchar inst)1951*5a6e8488SAndroid Build Coastguard Worker bc_program_builtin(BcProgram* p, uchar inst)
1952*5a6e8488SAndroid Build Coastguard Worker {
1953*5a6e8488SAndroid Build Coastguard Worker BcResult* opd;
1954*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
1955*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
1956*5a6e8488SAndroid Build Coastguard Worker bool len = (inst == BC_INST_LENGTH);
1957*5a6e8488SAndroid Build Coastguard Worker
1958*5a6e8488SAndroid Build Coastguard Worker // Ensure we have a valid builtin.
1959*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1960*5a6e8488SAndroid Build Coastguard Worker assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IRAND);
1961*5a6e8488SAndroid Build Coastguard Worker #else // BC_ENABLE_EXTRA_MATH
1962*5a6e8488SAndroid Build Coastguard Worker assert(inst >= BC_INST_LENGTH && inst <= BC_INST_IS_STRING);
1963*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1964*5a6e8488SAndroid Build Coastguard Worker
1965*5a6e8488SAndroid Build Coastguard Worker #ifndef BC_PROG_NO_STACK_CHECK
1966*5a6e8488SAndroid Build Coastguard Worker // Check stack for dc.
1967*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 1)))
1968*5a6e8488SAndroid Build Coastguard Worker {
1969*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
1970*5a6e8488SAndroid Build Coastguard Worker }
1971*5a6e8488SAndroid Build Coastguard Worker #endif // BC_PROG_NO_STACK_CHECK
1972*5a6e8488SAndroid Build Coastguard Worker
1973*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
1974*5a6e8488SAndroid Build Coastguard Worker
1975*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
1976*5a6e8488SAndroid Build Coastguard Worker
1977*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &opd, &num, 1);
1978*5a6e8488SAndroid Build Coastguard Worker
1979*5a6e8488SAndroid Build Coastguard Worker assert(num != NULL);
1980*5a6e8488SAndroid Build Coastguard Worker
1981*5a6e8488SAndroid Build Coastguard Worker // We need to ensure that strings and arrays aren't passed to most builtins.
1982*5a6e8488SAndroid Build Coastguard Worker // The scale function can take strings in dc.
1983*5a6e8488SAndroid Build Coastguard Worker if (!len && (inst != BC_INST_SCALE_FUNC || BC_IS_BC) &&
1984*5a6e8488SAndroid Build Coastguard Worker inst != BC_INST_IS_NUMBER && inst != BC_INST_IS_STRING)
1985*5a6e8488SAndroid Build Coastguard Worker {
1986*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(opd, num);
1987*5a6e8488SAndroid Build Coastguard Worker }
1988*5a6e8488SAndroid Build Coastguard Worker
1989*5a6e8488SAndroid Build Coastguard Worker // Square root is easy.
1990*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_SQRT) bc_num_sqrt(num, &res->d.n, BC_PROG_SCALE(p));
1991*5a6e8488SAndroid Build Coastguard Worker
1992*5a6e8488SAndroid Build Coastguard Worker // Absolute value is easy.
1993*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_ABS)
1994*5a6e8488SAndroid Build Coastguard Worker {
1995*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
1996*5a6e8488SAndroid Build Coastguard Worker
1997*5a6e8488SAndroid Build Coastguard Worker bc_num_createCopy(&res->d.n, num);
1998*5a6e8488SAndroid Build Coastguard Worker
1999*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2000*5a6e8488SAndroid Build Coastguard Worker
2001*5a6e8488SAndroid Build Coastguard Worker BC_NUM_NEG_CLR_NP(res->d.n);
2002*5a6e8488SAndroid Build Coastguard Worker }
2003*5a6e8488SAndroid Build Coastguard Worker
2004*5a6e8488SAndroid Build Coastguard Worker // Testing for number or string is easy.
2005*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_IS_NUMBER || inst == BC_INST_IS_STRING)
2006*5a6e8488SAndroid Build Coastguard Worker {
2007*5a6e8488SAndroid Build Coastguard Worker bool cond;
2008*5a6e8488SAndroid Build Coastguard Worker bool is_str;
2009*5a6e8488SAndroid Build Coastguard Worker
2010*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2011*5a6e8488SAndroid Build Coastguard Worker
2012*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, BC_NUM_DEF_SIZE);
2013*5a6e8488SAndroid Build Coastguard Worker
2014*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2015*5a6e8488SAndroid Build Coastguard Worker
2016*5a6e8488SAndroid Build Coastguard Worker // Test if the number is a string.
2017*5a6e8488SAndroid Build Coastguard Worker is_str = BC_PROG_STR(num);
2018*5a6e8488SAndroid Build Coastguard Worker
2019*5a6e8488SAndroid Build Coastguard Worker // This confusing condition simply means that the instruction must be
2020*5a6e8488SAndroid Build Coastguard Worker // true if is_str is, or it must be false if is_str is. Otherwise, the
2021*5a6e8488SAndroid Build Coastguard Worker // returned value is false (0).
2022*5a6e8488SAndroid Build Coastguard Worker cond = ((inst == BC_INST_IS_STRING) == is_str);
2023*5a6e8488SAndroid Build Coastguard Worker if (cond) bc_num_one(&res->d.n);
2024*5a6e8488SAndroid Build Coastguard Worker }
2025*5a6e8488SAndroid Build Coastguard Worker
2026*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2027*5a6e8488SAndroid Build Coastguard Worker
2028*5a6e8488SAndroid Build Coastguard Worker // irand() is easy.
2029*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_IRAND)
2030*5a6e8488SAndroid Build Coastguard Worker {
2031*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2032*5a6e8488SAndroid Build Coastguard Worker
2033*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, num->len - BC_NUM_RDX_VAL(num));
2034*5a6e8488SAndroid Build Coastguard Worker
2035*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2036*5a6e8488SAndroid Build Coastguard Worker
2037*5a6e8488SAndroid Build Coastguard Worker bc_num_irand(num, &res->d.n, &p->rng);
2038*5a6e8488SAndroid Build Coastguard Worker }
2039*5a6e8488SAndroid Build Coastguard Worker
2040*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2041*5a6e8488SAndroid Build Coastguard Worker
2042*5a6e8488SAndroid Build Coastguard Worker // Everything else is...not easy.
2043*5a6e8488SAndroid Build Coastguard Worker else
2044*5a6e8488SAndroid Build Coastguard Worker {
2045*5a6e8488SAndroid Build Coastguard Worker BcBigDig val = 0;
2046*5a6e8488SAndroid Build Coastguard Worker
2047*5a6e8488SAndroid Build Coastguard Worker // Well, scale() is easy, but length() is not.
2048*5a6e8488SAndroid Build Coastguard Worker if (len)
2049*5a6e8488SAndroid Build Coastguard Worker {
2050*5a6e8488SAndroid Build Coastguard Worker // If we are bc and we have an array...
2051*5a6e8488SAndroid Build Coastguard Worker if (opd->t == BC_RESULT_ARRAY)
2052*5a6e8488SAndroid Build Coastguard Worker {
2053*5a6e8488SAndroid Build Coastguard Worker // Yes, this is one place where we need to cast the number from
2054*5a6e8488SAndroid Build Coastguard Worker // bc_program_num() to a vector.
2055*5a6e8488SAndroid Build Coastguard Worker BcVec* v = (BcVec*) num;
2056*5a6e8488SAndroid Build Coastguard Worker
2057*5a6e8488SAndroid Build Coastguard Worker // XXX: If this is changed, you should also change the similar
2058*5a6e8488SAndroid Build Coastguard Worker // code in bc_program_asciify().
2059*5a6e8488SAndroid Build Coastguard Worker
2060*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2061*5a6e8488SAndroid Build Coastguard Worker // Dereference the array, if necessary.
2062*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC && v->size == sizeof(uchar))
2063*5a6e8488SAndroid Build Coastguard Worker {
2064*5a6e8488SAndroid Build Coastguard Worker v = bc_program_dereference(p, v);
2065*5a6e8488SAndroid Build Coastguard Worker }
2066*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2067*5a6e8488SAndroid Build Coastguard Worker
2068*5a6e8488SAndroid Build Coastguard Worker assert(v->size == sizeof(BcNum));
2069*5a6e8488SAndroid Build Coastguard Worker
2070*5a6e8488SAndroid Build Coastguard Worker val = (BcBigDig) v->len;
2071*5a6e8488SAndroid Build Coastguard Worker }
2072*5a6e8488SAndroid Build Coastguard Worker else
2073*5a6e8488SAndroid Build Coastguard Worker {
2074*5a6e8488SAndroid Build Coastguard Worker // If the item is a string...
2075*5a6e8488SAndroid Build Coastguard Worker if (!BC_PROG_NUM(opd, num))
2076*5a6e8488SAndroid Build Coastguard Worker {
2077*5a6e8488SAndroid Build Coastguard Worker char* str;
2078*5a6e8488SAndroid Build Coastguard Worker
2079*5a6e8488SAndroid Build Coastguard Worker // Get the string, then get the length.
2080*5a6e8488SAndroid Build Coastguard Worker str = bc_program_string(p, num);
2081*5a6e8488SAndroid Build Coastguard Worker val = (BcBigDig) strlen(str);
2082*5a6e8488SAndroid Build Coastguard Worker }
2083*5a6e8488SAndroid Build Coastguard Worker else
2084*5a6e8488SAndroid Build Coastguard Worker {
2085*5a6e8488SAndroid Build Coastguard Worker // Calculate the length of the number.
2086*5a6e8488SAndroid Build Coastguard Worker val = (BcBigDig) bc_num_len(num);
2087*5a6e8488SAndroid Build Coastguard Worker }
2088*5a6e8488SAndroid Build Coastguard Worker }
2089*5a6e8488SAndroid Build Coastguard Worker }
2090*5a6e8488SAndroid Build Coastguard Worker // Like I said; scale() is actually easy. It just also needs the integer
2091*5a6e8488SAndroid Build Coastguard Worker // conversion that length() does.
2092*5a6e8488SAndroid Build Coastguard Worker else if (BC_IS_BC || BC_PROG_NUM(opd, num))
2093*5a6e8488SAndroid Build Coastguard Worker {
2094*5a6e8488SAndroid Build Coastguard Worker val = (BcBigDig) bc_num_scale(num);
2095*5a6e8488SAndroid Build Coastguard Worker }
2096*5a6e8488SAndroid Build Coastguard Worker
2097*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2098*5a6e8488SAndroid Build Coastguard Worker
2099*5a6e8488SAndroid Build Coastguard Worker // Create the result.
2100*5a6e8488SAndroid Build Coastguard Worker bc_num_createFromBigdig(&res->d.n, val);
2101*5a6e8488SAndroid Build Coastguard Worker
2102*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2103*5a6e8488SAndroid Build Coastguard Worker }
2104*5a6e8488SAndroid Build Coastguard Worker
2105*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, 1);
2106*5a6e8488SAndroid Build Coastguard Worker }
2107*5a6e8488SAndroid Build Coastguard Worker
2108*5a6e8488SAndroid Build Coastguard Worker /**
2109*5a6e8488SAndroid Build Coastguard Worker * Executes a divmod.
2110*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2111*5a6e8488SAndroid Build Coastguard Worker */
2112*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_divmod(BcProgram * p)2113*5a6e8488SAndroid Build Coastguard Worker bc_program_divmod(BcProgram* p)
2114*5a6e8488SAndroid Build Coastguard Worker {
2115*5a6e8488SAndroid Build Coastguard Worker BcResult* opd1;
2116*5a6e8488SAndroid Build Coastguard Worker BcResult* opd2;
2117*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
2118*5a6e8488SAndroid Build Coastguard Worker BcResult* res2;
2119*5a6e8488SAndroid Build Coastguard Worker BcNum* n1;
2120*5a6e8488SAndroid Build Coastguard Worker BcNum* n2;
2121*5a6e8488SAndroid Build Coastguard Worker size_t req;
2122*5a6e8488SAndroid Build Coastguard Worker
2123*5a6e8488SAndroid Build Coastguard Worker // We grow first to avoid pointer invalidation.
2124*5a6e8488SAndroid Build Coastguard Worker bc_vec_grow(&p->results, 2);
2125*5a6e8488SAndroid Build Coastguard Worker
2126*5a6e8488SAndroid Build Coastguard Worker // We don't need to update the pointer because
2127*5a6e8488SAndroid Build Coastguard Worker // the capacity is enough due to the line above.
2128*5a6e8488SAndroid Build Coastguard Worker res2 = bc_program_prepResult(p);
2129*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
2130*5a6e8488SAndroid Build Coastguard Worker
2131*5a6e8488SAndroid Build Coastguard Worker // Prepare the operands.
2132*5a6e8488SAndroid Build Coastguard Worker bc_program_binOpPrep(p, &opd1, &n1, &opd2, &n2, 2);
2133*5a6e8488SAndroid Build Coastguard Worker
2134*5a6e8488SAndroid Build Coastguard Worker req = bc_num_mulReq(n1, n2, BC_PROG_SCALE(p));
2135*5a6e8488SAndroid Build Coastguard Worker
2136*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2137*5a6e8488SAndroid Build Coastguard Worker
2138*5a6e8488SAndroid Build Coastguard Worker // Initialize the results.
2139*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, req);
2140*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res2->d.n, req);
2141*5a6e8488SAndroid Build Coastguard Worker
2142*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2143*5a6e8488SAndroid Build Coastguard Worker
2144*5a6e8488SAndroid Build Coastguard Worker // Execute.
2145*5a6e8488SAndroid Build Coastguard Worker bc_num_divmod(n1, n2, &res2->d.n, &res->d.n, BC_PROG_SCALE(p));
2146*5a6e8488SAndroid Build Coastguard Worker
2147*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 2, 2);
2148*5a6e8488SAndroid Build Coastguard Worker }
2149*5a6e8488SAndroid Build Coastguard Worker
2150*5a6e8488SAndroid Build Coastguard Worker /**
2151*5a6e8488SAndroid Build Coastguard Worker * Executes modular exponentiation.
2152*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2153*5a6e8488SAndroid Build Coastguard Worker */
2154*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_modexp(BcProgram * p)2155*5a6e8488SAndroid Build Coastguard Worker bc_program_modexp(BcProgram* p)
2156*5a6e8488SAndroid Build Coastguard Worker {
2157*5a6e8488SAndroid Build Coastguard Worker BcResult* r1;
2158*5a6e8488SAndroid Build Coastguard Worker BcResult* r2;
2159*5a6e8488SAndroid Build Coastguard Worker BcResult* r3;
2160*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
2161*5a6e8488SAndroid Build Coastguard Worker BcNum* n1;
2162*5a6e8488SAndroid Build Coastguard Worker BcNum* n2;
2163*5a6e8488SAndroid Build Coastguard Worker BcNum* n3;
2164*5a6e8488SAndroid Build Coastguard Worker
2165*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2166*5a6e8488SAndroid Build Coastguard Worker
2167*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
2168*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC && BC_ERR(!BC_PROG_STACK(&p->results, 3)))
2169*5a6e8488SAndroid Build Coastguard Worker {
2170*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
2171*5a6e8488SAndroid Build Coastguard Worker }
2172*5a6e8488SAndroid Build Coastguard Worker
2173*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2174*5a6e8488SAndroid Build Coastguard Worker
2175*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 3));
2176*5a6e8488SAndroid Build Coastguard Worker
2177*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
2178*5a6e8488SAndroid Build Coastguard Worker
2179*5a6e8488SAndroid Build Coastguard Worker // Get the first operand and typecheck.
2180*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &r1, &n1, 3);
2181*5a6e8488SAndroid Build Coastguard Worker bc_program_type_num(r1, n1);
2182*5a6e8488SAndroid Build Coastguard Worker
2183*5a6e8488SAndroid Build Coastguard Worker // Get the last two operands.
2184*5a6e8488SAndroid Build Coastguard Worker bc_program_binOpPrep(p, &r2, &n2, &r3, &n3, 1);
2185*5a6e8488SAndroid Build Coastguard Worker
2186*5a6e8488SAndroid Build Coastguard Worker // Make sure that the values have their pointers updated, if necessary.
2187*5a6e8488SAndroid Build Coastguard Worker // Only array elements are possible because this is dc.
2188*5a6e8488SAndroid Build Coastguard Worker if (r1->t == BC_RESULT_ARRAY_ELEM && (r1->t == r2->t || r1->t == r3->t))
2189*5a6e8488SAndroid Build Coastguard Worker {
2190*5a6e8488SAndroid Build Coastguard Worker n1 = bc_program_num(p, r1);
2191*5a6e8488SAndroid Build Coastguard Worker }
2192*5a6e8488SAndroid Build Coastguard Worker
2193*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2194*5a6e8488SAndroid Build Coastguard Worker
2195*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, n3->len);
2196*5a6e8488SAndroid Build Coastguard Worker
2197*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2198*5a6e8488SAndroid Build Coastguard Worker
2199*5a6e8488SAndroid Build Coastguard Worker bc_num_modexp(n1, n2, n3, &res->d.n);
2200*5a6e8488SAndroid Build Coastguard Worker
2201*5a6e8488SAndroid Build Coastguard Worker bc_program_retire(p, 1, 3);
2202*5a6e8488SAndroid Build Coastguard Worker }
2203*5a6e8488SAndroid Build Coastguard Worker
2204*5a6e8488SAndroid Build Coastguard Worker /**
2205*5a6e8488SAndroid Build Coastguard Worker * Asciifies a number for dc. This is a helper for bc_program_asciify().
2206*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2207*5a6e8488SAndroid Build Coastguard Worker * @param n The number to asciify.
2208*5a6e8488SAndroid Build Coastguard Worker */
2209*5a6e8488SAndroid Build Coastguard Worker static uchar
bc_program_asciifyNum(BcProgram * p,BcNum * n)2210*5a6e8488SAndroid Build Coastguard Worker bc_program_asciifyNum(BcProgram* p, BcNum* n)
2211*5a6e8488SAndroid Build Coastguard Worker {
2212*5a6e8488SAndroid Build Coastguard Worker bc_num_copy(&p->asciify, n);
2213*5a6e8488SAndroid Build Coastguard Worker
2214*5a6e8488SAndroid Build Coastguard Worker // We want to clear the scale and sign for easy mod later.
2215*5a6e8488SAndroid Build Coastguard Worker bc_num_truncate(&p->asciify, p->asciify.scale);
2216*5a6e8488SAndroid Build Coastguard Worker BC_NUM_NEG_CLR(&p->asciify);
2217*5a6e8488SAndroid Build Coastguard Worker
2218*5a6e8488SAndroid Build Coastguard Worker // This is guaranteed to not have a divide by 0
2219*5a6e8488SAndroid Build Coastguard Worker // because strmb is equal to 256.
2220*5a6e8488SAndroid Build Coastguard Worker bc_num_mod(&p->asciify, &p->strmb, &p->asciify, 0);
2221*5a6e8488SAndroid Build Coastguard Worker
2222*5a6e8488SAndroid Build Coastguard Worker // This is also guaranteed to not error because num is in the range
2223*5a6e8488SAndroid Build Coastguard Worker // [0, UCHAR_MAX], which is definitely in range for a BcBigDig. And
2224*5a6e8488SAndroid Build Coastguard Worker // it is not negative.
2225*5a6e8488SAndroid Build Coastguard Worker return (uchar) bc_num_bigdig2(&p->asciify);
2226*5a6e8488SAndroid Build Coastguard Worker }
2227*5a6e8488SAndroid Build Coastguard Worker
2228*5a6e8488SAndroid Build Coastguard Worker /**
2229*5a6e8488SAndroid Build Coastguard Worker * Executes the "asciify" command in bc and dc.
2230*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2231*5a6e8488SAndroid Build Coastguard Worker */
2232*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_asciify(BcProgram * p)2233*5a6e8488SAndroid Build Coastguard Worker bc_program_asciify(BcProgram* p)
2234*5a6e8488SAndroid Build Coastguard Worker {
2235*5a6e8488SAndroid Build Coastguard Worker BcResult *r, res;
2236*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
2237*5a6e8488SAndroid Build Coastguard Worker uchar c;
2238*5a6e8488SAndroid Build Coastguard Worker size_t idx;
2239*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2240*5a6e8488SAndroid Build Coastguard Worker // This is in the outer scope because it has to be freed after a jump.
2241*5a6e8488SAndroid Build Coastguard Worker char* temp_str;
2242*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2243*5a6e8488SAndroid Build Coastguard Worker
2244*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
2245*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2246*5a6e8488SAndroid Build Coastguard Worker
2247*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
2248*5a6e8488SAndroid Build Coastguard Worker
2249*5a6e8488SAndroid Build Coastguard Worker // Get the top of the results stack.
2250*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &r, &n, 0);
2251*5a6e8488SAndroid Build Coastguard Worker
2252*5a6e8488SAndroid Build Coastguard Worker assert(n != NULL);
2253*5a6e8488SAndroid Build Coastguard Worker assert(BC_IS_BC || r->t != BC_RESULT_ARRAY);
2254*5a6e8488SAndroid Build Coastguard Worker
2255*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2256*5a6e8488SAndroid Build Coastguard Worker // Handle arrays in bc specially.
2257*5a6e8488SAndroid Build Coastguard Worker if (r->t == BC_RESULT_ARRAY)
2258*5a6e8488SAndroid Build Coastguard Worker {
2259*5a6e8488SAndroid Build Coastguard Worker // Yes, this is one place where we need to cast the number from
2260*5a6e8488SAndroid Build Coastguard Worker // bc_program_num() to a vector.
2261*5a6e8488SAndroid Build Coastguard Worker BcVec* v = (BcVec*) n;
2262*5a6e8488SAndroid Build Coastguard Worker size_t i;
2263*5a6e8488SAndroid Build Coastguard Worker
2264*5a6e8488SAndroid Build Coastguard Worker // XXX: If this is changed, you should also change the similar code in
2265*5a6e8488SAndroid Build Coastguard Worker // bc_program_builtin().
2266*5a6e8488SAndroid Build Coastguard Worker
2267*5a6e8488SAndroid Build Coastguard Worker // Dereference the array, if necessary.
2268*5a6e8488SAndroid Build Coastguard Worker if (v->size == sizeof(uchar))
2269*5a6e8488SAndroid Build Coastguard Worker {
2270*5a6e8488SAndroid Build Coastguard Worker v = bc_program_dereference(p, v);
2271*5a6e8488SAndroid Build Coastguard Worker }
2272*5a6e8488SAndroid Build Coastguard Worker
2273*5a6e8488SAndroid Build Coastguard Worker assert(v->size == sizeof(BcNum));
2274*5a6e8488SAndroid Build Coastguard Worker
2275*5a6e8488SAndroid Build Coastguard Worker // Allocate the string and set the jump for it.
2276*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2277*5a6e8488SAndroid Build Coastguard Worker temp_str = bc_vm_malloc(v->len + 1);
2278*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exit);
2279*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2280*5a6e8488SAndroid Build Coastguard Worker
2281*5a6e8488SAndroid Build Coastguard Worker // Convert the array.
2282*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < v->len; ++i)
2283*5a6e8488SAndroid Build Coastguard Worker {
2284*5a6e8488SAndroid Build Coastguard Worker BcNum* num = (BcNum*) bc_vec_item(v, i);
2285*5a6e8488SAndroid Build Coastguard Worker
2286*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_STR(num))
2287*5a6e8488SAndroid Build Coastguard Worker {
2288*5a6e8488SAndroid Build Coastguard Worker temp_str[i] = (bc_program_string(p, num))[0];
2289*5a6e8488SAndroid Build Coastguard Worker }
2290*5a6e8488SAndroid Build Coastguard Worker else
2291*5a6e8488SAndroid Build Coastguard Worker {
2292*5a6e8488SAndroid Build Coastguard Worker temp_str[i] = (char) bc_program_asciifyNum(p, num);
2293*5a6e8488SAndroid Build Coastguard Worker }
2294*5a6e8488SAndroid Build Coastguard Worker }
2295*5a6e8488SAndroid Build Coastguard Worker
2296*5a6e8488SAndroid Build Coastguard Worker temp_str[v->len] = '\0';
2297*5a6e8488SAndroid Build Coastguard Worker
2298*5a6e8488SAndroid Build Coastguard Worker // Store the string in the slab and map, and free the temp string.
2299*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2300*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_addString(p, temp_str);
2301*5a6e8488SAndroid Build Coastguard Worker free(temp_str);
2302*5a6e8488SAndroid Build Coastguard Worker BC_UNSETJMP(vm);
2303*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2304*5a6e8488SAndroid Build Coastguard Worker }
2305*5a6e8488SAndroid Build Coastguard Worker else
2306*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2307*5a6e8488SAndroid Build Coastguard Worker {
2308*5a6e8488SAndroid Build Coastguard Worker char str[2];
2309*5a6e8488SAndroid Build Coastguard Worker char* str2;
2310*5a6e8488SAndroid Build Coastguard Worker
2311*5a6e8488SAndroid Build Coastguard Worker // Asciify.
2312*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_NUM(r, n)) c = bc_program_asciifyNum(p, n);
2313*5a6e8488SAndroid Build Coastguard Worker else
2314*5a6e8488SAndroid Build Coastguard Worker {
2315*5a6e8488SAndroid Build Coastguard Worker // Get the string itself, then the first character.
2316*5a6e8488SAndroid Build Coastguard Worker str2 = bc_program_string(p, n);
2317*5a6e8488SAndroid Build Coastguard Worker c = (uchar) str2[0];
2318*5a6e8488SAndroid Build Coastguard Worker }
2319*5a6e8488SAndroid Build Coastguard Worker
2320*5a6e8488SAndroid Build Coastguard Worker // Fill the resulting string.
2321*5a6e8488SAndroid Build Coastguard Worker str[0] = (char) c;
2322*5a6e8488SAndroid Build Coastguard Worker str[1] = '\0';
2323*5a6e8488SAndroid Build Coastguard Worker
2324*5a6e8488SAndroid Build Coastguard Worker // Add the string to the data structures.
2325*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2326*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_addString(p, str);
2327*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2328*5a6e8488SAndroid Build Coastguard Worker }
2329*5a6e8488SAndroid Build Coastguard Worker
2330*5a6e8488SAndroid Build Coastguard Worker // Set the result
2331*5a6e8488SAndroid Build Coastguard Worker res.t = BC_RESULT_STR;
2332*5a6e8488SAndroid Build Coastguard Worker bc_num_clear(&res.d.n);
2333*5a6e8488SAndroid Build Coastguard Worker res.d.n.scale = idx;
2334*5a6e8488SAndroid Build Coastguard Worker
2335*5a6e8488SAndroid Build Coastguard Worker // Pop and push.
2336*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
2337*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &res);
2338*5a6e8488SAndroid Build Coastguard Worker
2339*5a6e8488SAndroid Build Coastguard Worker return;
2340*5a6e8488SAndroid Build Coastguard Worker
2341*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2342*5a6e8488SAndroid Build Coastguard Worker exit:
2343*5a6e8488SAndroid Build Coastguard Worker free(temp_str);
2344*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2345*5a6e8488SAndroid Build Coastguard Worker }
2346*5a6e8488SAndroid Build Coastguard Worker
2347*5a6e8488SAndroid Build Coastguard Worker /**
2348*5a6e8488SAndroid Build Coastguard Worker * Streams a number or a string to stdout.
2349*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2350*5a6e8488SAndroid Build Coastguard Worker */
2351*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printStream(BcProgram * p)2352*5a6e8488SAndroid Build Coastguard Worker bc_program_printStream(BcProgram* p)
2353*5a6e8488SAndroid Build Coastguard Worker {
2354*5a6e8488SAndroid Build Coastguard Worker BcResult* r;
2355*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
2356*5a6e8488SAndroid Build Coastguard Worker
2357*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
2358*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2359*5a6e8488SAndroid Build Coastguard Worker
2360*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
2361*5a6e8488SAndroid Build Coastguard Worker
2362*5a6e8488SAndroid Build Coastguard Worker // Get the top of the results stack.
2363*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &r, &n, 0);
2364*5a6e8488SAndroid Build Coastguard Worker
2365*5a6e8488SAndroid Build Coastguard Worker assert(n != NULL);
2366*5a6e8488SAndroid Build Coastguard Worker
2367*5a6e8488SAndroid Build Coastguard Worker // Stream appropriately.
2368*5a6e8488SAndroid Build Coastguard Worker if (BC_PROG_NUM(r, n)) bc_num_stream(n);
2369*5a6e8488SAndroid Build Coastguard Worker else bc_program_printChars(bc_program_string(p, n));
2370*5a6e8488SAndroid Build Coastguard Worker
2371*5a6e8488SAndroid Build Coastguard Worker // Pop the operand.
2372*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
2373*5a6e8488SAndroid Build Coastguard Worker }
2374*5a6e8488SAndroid Build Coastguard Worker
2375*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2376*5a6e8488SAndroid Build Coastguard Worker
2377*5a6e8488SAndroid Build Coastguard Worker /**
2378*5a6e8488SAndroid Build Coastguard Worker * Gets the length of a register in dc and pushes it onto the results stack.
2379*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2380*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector to pull the register's index out of.
2381*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the start of the index in the bytecode
2382*5a6e8488SAndroid Build Coastguard Worker * vector, and will be updated to point after the index on return.
2383*5a6e8488SAndroid Build Coastguard Worker */
2384*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_regStackLen(BcProgram * p,const char * restrict code,size_t * restrict bgn)2385*5a6e8488SAndroid Build Coastguard Worker bc_program_regStackLen(BcProgram* p, const char* restrict code,
2386*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn)
2387*5a6e8488SAndroid Build Coastguard Worker {
2388*5a6e8488SAndroid Build Coastguard Worker size_t idx = bc_program_index(code, bgn);
2389*5a6e8488SAndroid Build Coastguard Worker BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR);
2390*5a6e8488SAndroid Build Coastguard Worker
2391*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, (BcBigDig) v->len, BC_RESULT_TEMP);
2392*5a6e8488SAndroid Build Coastguard Worker }
2393*5a6e8488SAndroid Build Coastguard Worker
2394*5a6e8488SAndroid Build Coastguard Worker /**
2395*5a6e8488SAndroid Build Coastguard Worker * Pushes the length of the results stack onto the results stack.
2396*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2397*5a6e8488SAndroid Build Coastguard Worker */
2398*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_stackLen(BcProgram * p)2399*5a6e8488SAndroid Build Coastguard Worker bc_program_stackLen(BcProgram* p)
2400*5a6e8488SAndroid Build Coastguard Worker {
2401*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, (BcBigDig) p->results.len, BC_RESULT_TEMP);
2402*5a6e8488SAndroid Build Coastguard Worker }
2403*5a6e8488SAndroid Build Coastguard Worker
2404*5a6e8488SAndroid Build Coastguard Worker /**
2405*5a6e8488SAndroid Build Coastguard Worker * Pops a certain number of elements off the execution stack.
2406*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2407*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction to tell us how many. There is one to pop up to
2408*5a6e8488SAndroid Build Coastguard Worker * 2, and one to pop the amount equal to the number at the top of
2409*5a6e8488SAndroid Build Coastguard Worker * the results stack.
2410*5a6e8488SAndroid Build Coastguard Worker */
2411*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_nquit(BcProgram * p,uchar inst)2412*5a6e8488SAndroid Build Coastguard Worker bc_program_nquit(BcProgram* p, uchar inst)
2413*5a6e8488SAndroid Build Coastguard Worker {
2414*5a6e8488SAndroid Build Coastguard Worker BcResult* opnd;
2415*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
2416*5a6e8488SAndroid Build Coastguard Worker BcBigDig val;
2417*5a6e8488SAndroid Build Coastguard Worker size_t i;
2418*5a6e8488SAndroid Build Coastguard Worker
2419*5a6e8488SAndroid Build Coastguard Worker // Ensure that the tail calls stack is correct.
2420*5a6e8488SAndroid Build Coastguard Worker assert(p->stack.len == p->tail_calls.len);
2421*5a6e8488SAndroid Build Coastguard Worker
2422*5a6e8488SAndroid Build Coastguard Worker // Get the number of executions to pop.
2423*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_QUIT) val = 2;
2424*5a6e8488SAndroid Build Coastguard Worker else
2425*5a6e8488SAndroid Build Coastguard Worker {
2426*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(p, &opnd, &num, 0);
2427*5a6e8488SAndroid Build Coastguard Worker val = bc_num_bigdig(num);
2428*5a6e8488SAndroid Build Coastguard Worker
2429*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
2430*5a6e8488SAndroid Build Coastguard Worker }
2431*5a6e8488SAndroid Build Coastguard Worker
2432*5a6e8488SAndroid Build Coastguard Worker // Loop over the tail call stack and adjust the quit value appropriately.
2433*5a6e8488SAndroid Build Coastguard Worker for (i = 0; val && i < p->tail_calls.len; ++i)
2434*5a6e8488SAndroid Build Coastguard Worker {
2435*5a6e8488SAndroid Build Coastguard Worker // Get the number of tail calls for this one.
2436*5a6e8488SAndroid Build Coastguard Worker size_t calls = *((size_t*) bc_vec_item_rev(&p->tail_calls, i)) + 1;
2437*5a6e8488SAndroid Build Coastguard Worker
2438*5a6e8488SAndroid Build Coastguard Worker // Adjust the value.
2439*5a6e8488SAndroid Build Coastguard Worker if (calls >= val) val = 0;
2440*5a6e8488SAndroid Build Coastguard Worker else val -= (BcBigDig) calls;
2441*5a6e8488SAndroid Build Coastguard Worker }
2442*5a6e8488SAndroid Build Coastguard Worker
2443*5a6e8488SAndroid Build Coastguard Worker // If we don't have enough executions, just quit.
2444*5a6e8488SAndroid Build Coastguard Worker if (i == p->stack.len)
2445*5a6e8488SAndroid Build Coastguard Worker {
2446*5a6e8488SAndroid Build Coastguard Worker vm->status = BC_STATUS_QUIT;
2447*5a6e8488SAndroid Build Coastguard Worker BC_JMP;
2448*5a6e8488SAndroid Build Coastguard Worker }
2449*5a6e8488SAndroid Build Coastguard Worker else
2450*5a6e8488SAndroid Build Coastguard Worker {
2451*5a6e8488SAndroid Build Coastguard Worker // We can always pop the last item we reached on the tail call stack
2452*5a6e8488SAndroid Build Coastguard Worker // because these are for tail calls. That means that any executions that
2453*5a6e8488SAndroid Build Coastguard Worker // we would not have quit in that position on the stack would have quit
2454*5a6e8488SAndroid Build Coastguard Worker // anyway.
2455*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2456*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->stack, i);
2457*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->tail_calls, i);
2458*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2459*5a6e8488SAndroid Build Coastguard Worker }
2460*5a6e8488SAndroid Build Coastguard Worker }
2461*5a6e8488SAndroid Build Coastguard Worker
2462*5a6e8488SAndroid Build Coastguard Worker /**
2463*5a6e8488SAndroid Build Coastguard Worker * Pushes the depth of the execution stack onto the stack.
2464*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2465*5a6e8488SAndroid Build Coastguard Worker */
2466*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_execStackLen(BcProgram * p)2467*5a6e8488SAndroid Build Coastguard Worker bc_program_execStackLen(BcProgram* p)
2468*5a6e8488SAndroid Build Coastguard Worker {
2469*5a6e8488SAndroid Build Coastguard Worker size_t i, amt, len = p->tail_calls.len;
2470*5a6e8488SAndroid Build Coastguard Worker
2471*5a6e8488SAndroid Build Coastguard Worker amt = len;
2472*5a6e8488SAndroid Build Coastguard Worker
2473*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < len; ++i)
2474*5a6e8488SAndroid Build Coastguard Worker {
2475*5a6e8488SAndroid Build Coastguard Worker amt += *((size_t*) bc_vec_item(&p->tail_calls, i));
2476*5a6e8488SAndroid Build Coastguard Worker }
2477*5a6e8488SAndroid Build Coastguard Worker
2478*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, (BcBigDig) amt, BC_RESULT_TEMP);
2479*5a6e8488SAndroid Build Coastguard Worker }
2480*5a6e8488SAndroid Build Coastguard Worker
2481*5a6e8488SAndroid Build Coastguard Worker /**
2482*5a6e8488SAndroid Build Coastguard Worker *
2483*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2484*5a6e8488SAndroid Build Coastguard Worker * @param code The bytecode vector to pull the register's index out of.
2485*5a6e8488SAndroid Build Coastguard Worker * @param bgn An in/out parameter; the start of the index in the bytecode
2486*5a6e8488SAndroid Build Coastguard Worker * vector, and will be updated to point after the index on return.
2487*5a6e8488SAndroid Build Coastguard Worker * @param cond True if the execution is conditional, false otherwise.
2488*5a6e8488SAndroid Build Coastguard Worker * @param len The number of bytes in the bytecode vector.
2489*5a6e8488SAndroid Build Coastguard Worker */
2490*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_execStr(BcProgram * p,const char * restrict code,size_t * restrict bgn,bool cond,size_t len)2491*5a6e8488SAndroid Build Coastguard Worker bc_program_execStr(BcProgram* p, const char* restrict code,
2492*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn, bool cond, size_t len)
2493*5a6e8488SAndroid Build Coastguard Worker {
2494*5a6e8488SAndroid Build Coastguard Worker BcResult* r;
2495*5a6e8488SAndroid Build Coastguard Worker char* str;
2496*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
2497*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
2498*5a6e8488SAndroid Build Coastguard Worker size_t fidx;
2499*5a6e8488SAndroid Build Coastguard Worker BcNum* n;
2500*5a6e8488SAndroid Build Coastguard Worker
2501*5a6e8488SAndroid Build Coastguard Worker assert(p->stack.len == p->tail_calls.len);
2502*5a6e8488SAndroid Build Coastguard Worker
2503*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
2504*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1))) bc_err(BC_ERR_EXEC_STACK);
2505*5a6e8488SAndroid Build Coastguard Worker
2506*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
2507*5a6e8488SAndroid Build Coastguard Worker
2508*5a6e8488SAndroid Build Coastguard Worker // Get the operand.
2509*5a6e8488SAndroid Build Coastguard Worker bc_program_operand(p, &r, &n, 0);
2510*5a6e8488SAndroid Build Coastguard Worker
2511*5a6e8488SAndroid Build Coastguard Worker // If execution is conditional...
2512*5a6e8488SAndroid Build Coastguard Worker if (cond)
2513*5a6e8488SAndroid Build Coastguard Worker {
2514*5a6e8488SAndroid Build Coastguard Worker bool exec;
2515*5a6e8488SAndroid Build Coastguard Worker size_t then_idx;
2516*5a6e8488SAndroid Build Coastguard Worker // These are volatile to quiet warnings on GCC about clobbering with
2517*5a6e8488SAndroid Build Coastguard Worker // longjmp().
2518*5a6e8488SAndroid Build Coastguard Worker volatile size_t else_idx;
2519*5a6e8488SAndroid Build Coastguard Worker volatile size_t idx;
2520*5a6e8488SAndroid Build Coastguard Worker
2521*5a6e8488SAndroid Build Coastguard Worker // Get the index of the "then" var and "else" var.
2522*5a6e8488SAndroid Build Coastguard Worker then_idx = bc_program_index(code, bgn);
2523*5a6e8488SAndroid Build Coastguard Worker else_idx = bc_program_index(code, bgn);
2524*5a6e8488SAndroid Build Coastguard Worker
2525*5a6e8488SAndroid Build Coastguard Worker // Figure out if we should execute.
2526*5a6e8488SAndroid Build Coastguard Worker exec = (r->d.n.len != 0);
2527*5a6e8488SAndroid Build Coastguard Worker
2528*5a6e8488SAndroid Build Coastguard Worker idx = exec ? then_idx : else_idx;
2529*5a6e8488SAndroid Build Coastguard Worker
2530*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2531*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exit);
2532*5a6e8488SAndroid Build Coastguard Worker
2533*5a6e8488SAndroid Build Coastguard Worker // If we are supposed to execute, execute. If else_idx == SIZE_MAX, that
2534*5a6e8488SAndroid Build Coastguard Worker // means there was no else clause, so if execute is false and else does
2535*5a6e8488SAndroid Build Coastguard Worker // not exist, we don't execute. The goto skips all of the setup for the
2536*5a6e8488SAndroid Build Coastguard Worker // execution.
2537*5a6e8488SAndroid Build Coastguard Worker if (exec || (else_idx != SIZE_MAX))
2538*5a6e8488SAndroid Build Coastguard Worker {
2539*5a6e8488SAndroid Build Coastguard Worker n = bc_vec_top(bc_program_vec(p, idx, BC_TYPE_VAR));
2540*5a6e8488SAndroid Build Coastguard Worker }
2541*5a6e8488SAndroid Build Coastguard Worker else goto exit;
2542*5a6e8488SAndroid Build Coastguard Worker
2543*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STR(n))) bc_err(BC_ERR_EXEC_TYPE);
2544*5a6e8488SAndroid Build Coastguard Worker
2545*5a6e8488SAndroid Build Coastguard Worker BC_UNSETJMP(vm);
2546*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2547*5a6e8488SAndroid Build Coastguard Worker }
2548*5a6e8488SAndroid Build Coastguard Worker else
2549*5a6e8488SAndroid Build Coastguard Worker {
2550*5a6e8488SAndroid Build Coastguard Worker // In non-conditional situations, only the top of stack can be executed,
2551*5a6e8488SAndroid Build Coastguard Worker // and in those cases, variables are not allowed to be "on the stack";
2552*5a6e8488SAndroid Build Coastguard Worker // they are only put on the stack to be assigned to.
2553*5a6e8488SAndroid Build Coastguard Worker assert(r->t != BC_RESULT_VAR);
2554*5a6e8488SAndroid Build Coastguard Worker
2555*5a6e8488SAndroid Build Coastguard Worker if (r->t != BC_RESULT_STR) return;
2556*5a6e8488SAndroid Build Coastguard Worker }
2557*5a6e8488SAndroid Build Coastguard Worker
2558*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STR(n));
2559*5a6e8488SAndroid Build Coastguard Worker
2560*5a6e8488SAndroid Build Coastguard Worker // Get the string.
2561*5a6e8488SAndroid Build Coastguard Worker str = bc_program_string(p, n);
2562*5a6e8488SAndroid Build Coastguard Worker
2563*5a6e8488SAndroid Build Coastguard Worker // Get the function index and function.
2564*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2565*5a6e8488SAndroid Build Coastguard Worker fidx = bc_program_insertFunc(p, str);
2566*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2567*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, fidx);
2568*5a6e8488SAndroid Build Coastguard Worker
2569*5a6e8488SAndroid Build Coastguard Worker // If the function has not been parsed yet...
2570*5a6e8488SAndroid Build Coastguard Worker if (!f->code.len)
2571*5a6e8488SAndroid Build Coastguard Worker {
2572*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2573*5a6e8488SAndroid Build Coastguard Worker
2574*5a6e8488SAndroid Build Coastguard Worker if (!BC_PARSE_IS_INITED(&vm->read_prs, p))
2575*5a6e8488SAndroid Build Coastguard Worker {
2576*5a6e8488SAndroid Build Coastguard Worker bc_parse_init(&vm->read_prs, p, fidx);
2577*5a6e8488SAndroid Build Coastguard Worker
2578*5a6e8488SAndroid Build Coastguard Worker // Initialize this too because bc_vm_shutdown() expects them to be
2579*5a6e8488SAndroid Build Coastguard Worker // initialized togther.
2580*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&vm->read_buf, sizeof(char), BC_DTOR_NONE);
2581*5a6e8488SAndroid Build Coastguard Worker }
2582*5a6e8488SAndroid Build Coastguard Worker // This needs to be updated because the parser could have been used
2583*5a6e8488SAndroid Build Coastguard Worker // somewhere else
2584*5a6e8488SAndroid Build Coastguard Worker else bc_parse_updateFunc(&vm->read_prs, fidx);
2585*5a6e8488SAndroid Build Coastguard Worker
2586*5a6e8488SAndroid Build Coastguard Worker bc_lex_file(&vm->read_prs.l, vm->file);
2587*5a6e8488SAndroid Build Coastguard Worker
2588*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, err);
2589*5a6e8488SAndroid Build Coastguard Worker
2590*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2591*5a6e8488SAndroid Build Coastguard Worker
2592*5a6e8488SAndroid Build Coastguard Worker // Parse. Only one expression is needed, so stdin isn't used.
2593*5a6e8488SAndroid Build Coastguard Worker bc_parse_text(&vm->read_prs, str, BC_MODE_FILE);
2594*5a6e8488SAndroid Build Coastguard Worker
2595*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2596*5a6e8488SAndroid Build Coastguard Worker vm->expr(&vm->read_prs, BC_PARSE_NOCALL);
2597*5a6e8488SAndroid Build Coastguard Worker
2598*5a6e8488SAndroid Build Coastguard Worker BC_UNSETJMP(vm);
2599*5a6e8488SAndroid Build Coastguard Worker
2600*5a6e8488SAndroid Build Coastguard Worker // We can just assert this here because
2601*5a6e8488SAndroid Build Coastguard Worker // dc should parse everything until EOF.
2602*5a6e8488SAndroid Build Coastguard Worker assert(vm->read_prs.l.t == BC_LEX_EOF);
2603*5a6e8488SAndroid Build Coastguard Worker
2604*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2605*5a6e8488SAndroid Build Coastguard Worker }
2606*5a6e8488SAndroid Build Coastguard Worker
2607*5a6e8488SAndroid Build Coastguard Worker // Set the instruction pointer.
2608*5a6e8488SAndroid Build Coastguard Worker ip.idx = 0;
2609*5a6e8488SAndroid Build Coastguard Worker ip.len = p->results.len;
2610*5a6e8488SAndroid Build Coastguard Worker ip.func = fidx;
2611*5a6e8488SAndroid Build Coastguard Worker
2612*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2613*5a6e8488SAndroid Build Coastguard Worker
2614*5a6e8488SAndroid Build Coastguard Worker // Pop the operand.
2615*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
2616*5a6e8488SAndroid Build Coastguard Worker
2617*5a6e8488SAndroid Build Coastguard Worker // Tail call processing. This condition means that there is more on the
2618*5a6e8488SAndroid Build Coastguard Worker // execution stack, and we are at the end of the bytecode vector, and the
2619*5a6e8488SAndroid Build Coastguard Worker // last instruction is just a BC_INST_POP_EXEC, which would return.
2620*5a6e8488SAndroid Build Coastguard Worker if (p->stack.len > 1 && *bgn == len - 1 && code[*bgn] == BC_INST_POP_EXEC)
2621*5a6e8488SAndroid Build Coastguard Worker {
2622*5a6e8488SAndroid Build Coastguard Worker size_t* call_ptr = bc_vec_top(&p->tail_calls);
2623*5a6e8488SAndroid Build Coastguard Worker
2624*5a6e8488SAndroid Build Coastguard Worker // Add one to the tail call.
2625*5a6e8488SAndroid Build Coastguard Worker *call_ptr += 1;
2626*5a6e8488SAndroid Build Coastguard Worker
2627*5a6e8488SAndroid Build Coastguard Worker // Pop the execution stack before pushing the new instruction pointer
2628*5a6e8488SAndroid Build Coastguard Worker // on.
2629*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->stack);
2630*5a6e8488SAndroid Build Coastguard Worker }
2631*5a6e8488SAndroid Build Coastguard Worker // If not a tail call, just push a new one.
2632*5a6e8488SAndroid Build Coastguard Worker else bc_vec_push(&p->tail_calls, &ip.idx);
2633*5a6e8488SAndroid Build Coastguard Worker
2634*5a6e8488SAndroid Build Coastguard Worker // Push the new function onto the execution stack and return.
2635*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->stack, &ip);
2636*5a6e8488SAndroid Build Coastguard Worker
2637*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2638*5a6e8488SAndroid Build Coastguard Worker
2639*5a6e8488SAndroid Build Coastguard Worker return;
2640*5a6e8488SAndroid Build Coastguard Worker
2641*5a6e8488SAndroid Build Coastguard Worker err:
2642*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
2643*5a6e8488SAndroid Build Coastguard Worker
2644*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, fidx);
2645*5a6e8488SAndroid Build Coastguard Worker
2646*5a6e8488SAndroid Build Coastguard Worker // Make sure to erase the bytecode vector so dc knows it is not parsed.
2647*5a6e8488SAndroid Build Coastguard Worker bc_vec_popAll(&f->code);
2648*5a6e8488SAndroid Build Coastguard Worker
2649*5a6e8488SAndroid Build Coastguard Worker exit:
2650*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
2651*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
2652*5a6e8488SAndroid Build Coastguard Worker }
2653*5a6e8488SAndroid Build Coastguard Worker
2654*5a6e8488SAndroid Build Coastguard Worker /**
2655*5a6e8488SAndroid Build Coastguard Worker * Prints every item on the results stack, one per line.
2656*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2657*5a6e8488SAndroid Build Coastguard Worker */
2658*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printStack(BcProgram * p)2659*5a6e8488SAndroid Build Coastguard Worker bc_program_printStack(BcProgram* p)
2660*5a6e8488SAndroid Build Coastguard Worker {
2661*5a6e8488SAndroid Build Coastguard Worker size_t idx;
2662*5a6e8488SAndroid Build Coastguard Worker
2663*5a6e8488SAndroid Build Coastguard Worker for (idx = 0; idx < p->results.len; ++idx)
2664*5a6e8488SAndroid Build Coastguard Worker {
2665*5a6e8488SAndroid Build Coastguard Worker bc_program_print(p, BC_INST_PRINT, idx);
2666*5a6e8488SAndroid Build Coastguard Worker }
2667*5a6e8488SAndroid Build Coastguard Worker }
2668*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2669*5a6e8488SAndroid Build Coastguard Worker
2670*5a6e8488SAndroid Build Coastguard Worker /**
2671*5a6e8488SAndroid Build Coastguard Worker * Pushes the value of a global onto the results stack.
2672*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2673*5a6e8488SAndroid Build Coastguard Worker * @param inst Which global to push, as an instruction.
2674*5a6e8488SAndroid Build Coastguard Worker */
2675*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_pushGlobal(BcProgram * p,uchar inst)2676*5a6e8488SAndroid Build Coastguard Worker bc_program_pushGlobal(BcProgram* p, uchar inst)
2677*5a6e8488SAndroid Build Coastguard Worker {
2678*5a6e8488SAndroid Build Coastguard Worker BcResultType t;
2679*5a6e8488SAndroid Build Coastguard Worker
2680*5a6e8488SAndroid Build Coastguard Worker // Make sure the instruction is valid.
2681*5a6e8488SAndroid Build Coastguard Worker assert(inst >= BC_INST_IBASE && inst <= BC_INST_SCALE);
2682*5a6e8488SAndroid Build Coastguard Worker
2683*5a6e8488SAndroid Build Coastguard Worker // Push the global.
2684*5a6e8488SAndroid Build Coastguard Worker t = inst - BC_INST_IBASE + BC_RESULT_IBASE;
2685*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, p->globals[inst - BC_INST_IBASE], t);
2686*5a6e8488SAndroid Build Coastguard Worker }
2687*5a6e8488SAndroid Build Coastguard Worker
2688*5a6e8488SAndroid Build Coastguard Worker /**
2689*5a6e8488SAndroid Build Coastguard Worker * Pushes the value of a global setting onto the stack.
2690*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2691*5a6e8488SAndroid Build Coastguard Worker * @param inst Which global setting to push, as an instruction.
2692*5a6e8488SAndroid Build Coastguard Worker */
2693*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_globalSetting(BcProgram * p,uchar inst)2694*5a6e8488SAndroid Build Coastguard Worker bc_program_globalSetting(BcProgram* p, uchar inst)
2695*5a6e8488SAndroid Build Coastguard Worker {
2696*5a6e8488SAndroid Build Coastguard Worker BcBigDig val;
2697*5a6e8488SAndroid Build Coastguard Worker
2698*5a6e8488SAndroid Build Coastguard Worker // Make sure the instruction is valid.
2699*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2700*5a6e8488SAndroid Build Coastguard Worker assert((inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO) ||
2701*5a6e8488SAndroid Build Coastguard Worker (BC_IS_DC && inst == BC_INST_EXTENDED_REGISTERS));
2702*5a6e8488SAndroid Build Coastguard Worker #else // DC_ENABLED
2703*5a6e8488SAndroid Build Coastguard Worker assert(inst >= BC_INST_LINE_LENGTH && inst <= BC_INST_LEADING_ZERO);
2704*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2705*5a6e8488SAndroid Build Coastguard Worker
2706*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_LINE_LENGTH)
2707*5a6e8488SAndroid Build Coastguard Worker {
2708*5a6e8488SAndroid Build Coastguard Worker val = (BcBigDig) vm->line_len;
2709*5a6e8488SAndroid Build Coastguard Worker }
2710*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2711*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_GLOBAL_STACKS)
2712*5a6e8488SAndroid Build Coastguard Worker {
2713*5a6e8488SAndroid Build Coastguard Worker val = (BC_G != 0);
2714*5a6e8488SAndroid Build Coastguard Worker }
2715*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2716*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2717*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_EXTENDED_REGISTERS)
2718*5a6e8488SAndroid Build Coastguard Worker {
2719*5a6e8488SAndroid Build Coastguard Worker val = (DC_X != 0);
2720*5a6e8488SAndroid Build Coastguard Worker }
2721*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2722*5a6e8488SAndroid Build Coastguard Worker else val = (BC_Z != 0);
2723*5a6e8488SAndroid Build Coastguard Worker
2724*5a6e8488SAndroid Build Coastguard Worker // Push the global.
2725*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, val, BC_RESULT_TEMP);
2726*5a6e8488SAndroid Build Coastguard Worker }
2727*5a6e8488SAndroid Build Coastguard Worker
2728*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2729*5a6e8488SAndroid Build Coastguard Worker
2730*5a6e8488SAndroid Build Coastguard Worker /**
2731*5a6e8488SAndroid Build Coastguard Worker * Pushes the value of seed on the stack.
2732*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2733*5a6e8488SAndroid Build Coastguard Worker */
2734*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_pushSeed(BcProgram * p)2735*5a6e8488SAndroid Build Coastguard Worker bc_program_pushSeed(BcProgram* p)
2736*5a6e8488SAndroid Build Coastguard Worker {
2737*5a6e8488SAndroid Build Coastguard Worker BcResult* res;
2738*5a6e8488SAndroid Build Coastguard Worker
2739*5a6e8488SAndroid Build Coastguard Worker res = bc_program_prepResult(p);
2740*5a6e8488SAndroid Build Coastguard Worker res->t = BC_RESULT_SEED;
2741*5a6e8488SAndroid Build Coastguard Worker
2742*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
2743*5a6e8488SAndroid Build Coastguard Worker
2744*5a6e8488SAndroid Build Coastguard Worker // We need 2*BC_RAND_NUM_SIZE because of the size of the state.
2745*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&res->d.n, 2 * BC_RAND_NUM_SIZE);
2746*5a6e8488SAndroid Build Coastguard Worker
2747*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
2748*5a6e8488SAndroid Build Coastguard Worker
2749*5a6e8488SAndroid Build Coastguard Worker bc_num_createFromRNG(&res->d.n, &p->rng);
2750*5a6e8488SAndroid Build Coastguard Worker }
2751*5a6e8488SAndroid Build Coastguard Worker
2752*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2753*5a6e8488SAndroid Build Coastguard Worker
2754*5a6e8488SAndroid Build Coastguard Worker /**
2755*5a6e8488SAndroid Build Coastguard Worker * Adds a function to the fns array. The function's ID must have already been
2756*5a6e8488SAndroid Build Coastguard Worker * inserted into the map.
2757*5a6e8488SAndroid Build Coastguard Worker * @param p The program.
2758*5a6e8488SAndroid Build Coastguard Worker * @param id_ptr The ID of the function as inserted into the map.
2759*5a6e8488SAndroid Build Coastguard Worker */
2760*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_addFunc(BcProgram * p,BcId * id_ptr)2761*5a6e8488SAndroid Build Coastguard Worker bc_program_addFunc(BcProgram* p, BcId* id_ptr)
2762*5a6e8488SAndroid Build Coastguard Worker {
2763*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
2764*5a6e8488SAndroid Build Coastguard Worker
2765*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
2766*5a6e8488SAndroid Build Coastguard Worker
2767*5a6e8488SAndroid Build Coastguard Worker // Push and init.
2768*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_pushEmpty(&p->fns);
2769*5a6e8488SAndroid Build Coastguard Worker bc_func_init(f, id_ptr->name);
2770*5a6e8488SAndroid Build Coastguard Worker }
2771*5a6e8488SAndroid Build Coastguard Worker
2772*5a6e8488SAndroid Build Coastguard Worker size_t
bc_program_insertFunc(BcProgram * p,const char * name)2773*5a6e8488SAndroid Build Coastguard Worker bc_program_insertFunc(BcProgram* p, const char* name)
2774*5a6e8488SAndroid Build Coastguard Worker {
2775*5a6e8488SAndroid Build Coastguard Worker BcId* id_ptr;
2776*5a6e8488SAndroid Build Coastguard Worker bool new;
2777*5a6e8488SAndroid Build Coastguard Worker size_t idx;
2778*5a6e8488SAndroid Build Coastguard Worker
2779*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
2780*5a6e8488SAndroid Build Coastguard Worker
2781*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL && name != NULL);
2782*5a6e8488SAndroid Build Coastguard Worker
2783*5a6e8488SAndroid Build Coastguard Worker // Insert into the map and get the resulting ID.
2784*5a6e8488SAndroid Build Coastguard Worker new = bc_map_insert(&p->fn_map, name, p->fns.len, &idx);
2785*5a6e8488SAndroid Build Coastguard Worker id_ptr = (BcId*) bc_vec_item(&p->fn_map, idx);
2786*5a6e8488SAndroid Build Coastguard Worker idx = id_ptr->idx;
2787*5a6e8488SAndroid Build Coastguard Worker
2788*5a6e8488SAndroid Build Coastguard Worker // If the function is new...
2789*5a6e8488SAndroid Build Coastguard Worker if (new)
2790*5a6e8488SAndroid Build Coastguard Worker {
2791*5a6e8488SAndroid Build Coastguard Worker // Add the function to the fns array.
2792*5a6e8488SAndroid Build Coastguard Worker bc_program_addFunc(p, id_ptr);
2793*5a6e8488SAndroid Build Coastguard Worker }
2794*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2795*5a6e8488SAndroid Build Coastguard Worker // bc has to reset the function because it's about to be redefined.
2796*5a6e8488SAndroid Build Coastguard Worker else if (BC_IS_BC)
2797*5a6e8488SAndroid Build Coastguard Worker {
2798*5a6e8488SAndroid Build Coastguard Worker BcFunc* func = bc_vec_item(&p->fns, idx);
2799*5a6e8488SAndroid Build Coastguard Worker bc_func_reset(func);
2800*5a6e8488SAndroid Build Coastguard Worker }
2801*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2802*5a6e8488SAndroid Build Coastguard Worker
2803*5a6e8488SAndroid Build Coastguard Worker return idx;
2804*5a6e8488SAndroid Build Coastguard Worker }
2805*5a6e8488SAndroid Build Coastguard Worker
2806*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG || BC_ENABLE_MEMCHECK
2807*5a6e8488SAndroid Build Coastguard Worker void
bc_program_free(BcProgram * p)2808*5a6e8488SAndroid Build Coastguard Worker bc_program_free(BcProgram* p)
2809*5a6e8488SAndroid Build Coastguard Worker {
2810*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2811*5a6e8488SAndroid Build Coastguard Worker size_t i;
2812*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2813*5a6e8488SAndroid Build Coastguard Worker
2814*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
2815*5a6e8488SAndroid Build Coastguard Worker
2816*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL);
2817*5a6e8488SAndroid Build Coastguard Worker
2818*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2819*5a6e8488SAndroid Build Coastguard Worker // Free the globals stacks.
2820*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2821*5a6e8488SAndroid Build Coastguard Worker {
2822*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(p->globals_v + i);
2823*5a6e8488SAndroid Build Coastguard Worker }
2824*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2825*5a6e8488SAndroid Build Coastguard Worker
2826*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->fns);
2827*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->fn_map);
2828*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->vars);
2829*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->var_map);
2830*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->arrs);
2831*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->arr_map);
2832*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->results);
2833*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->stack);
2834*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->consts);
2835*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->const_map);
2836*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->strs);
2837*5a6e8488SAndroid Build Coastguard Worker bc_vec_free(&p->str_map);
2838*5a6e8488SAndroid Build Coastguard Worker
2839*5a6e8488SAndroid Build Coastguard Worker bc_num_free(&p->asciify);
2840*5a6e8488SAndroid Build Coastguard Worker
2841*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2842*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC) bc_num_free(&p->last);
2843*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2844*5a6e8488SAndroid Build Coastguard Worker
2845*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2846*5a6e8488SAndroid Build Coastguard Worker bc_rand_free(&p->rng);
2847*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2848*5a6e8488SAndroid Build Coastguard Worker
2849*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2850*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC) bc_vec_free(&p->tail_calls);
2851*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2852*5a6e8488SAndroid Build Coastguard Worker }
2853*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG || BC_ENABLE_MEMCHECK
2854*5a6e8488SAndroid Build Coastguard Worker
2855*5a6e8488SAndroid Build Coastguard Worker void
bc_program_init(BcProgram * p)2856*5a6e8488SAndroid Build Coastguard Worker bc_program_init(BcProgram* p)
2857*5a6e8488SAndroid Build Coastguard Worker {
2858*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
2859*5a6e8488SAndroid Build Coastguard Worker size_t i;
2860*5a6e8488SAndroid Build Coastguard Worker
2861*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
2862*5a6e8488SAndroid Build Coastguard Worker
2863*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL);
2864*5a6e8488SAndroid Build Coastguard Worker
2865*5a6e8488SAndroid Build Coastguard Worker // We want this clear.
2866*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
2867*5a6e8488SAndroid Build Coastguard Worker memset(&ip, 0, sizeof(BcInstPtr));
2868*5a6e8488SAndroid Build Coastguard Worker
2869*5a6e8488SAndroid Build Coastguard Worker // Setup the globals stacks and the current values.
2870*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < BC_PROG_GLOBALS_LEN; ++i)
2871*5a6e8488SAndroid Build Coastguard Worker {
2872*5a6e8488SAndroid Build Coastguard Worker BcBigDig val = i == BC_PROG_GLOBALS_SCALE ? 0 : BC_BASE;
2873*5a6e8488SAndroid Build Coastguard Worker
2874*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2875*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(p->globals_v + i, sizeof(BcBigDig), BC_DTOR_NONE);
2876*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(p->globals_v + i, &val);
2877*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2878*5a6e8488SAndroid Build Coastguard Worker
2879*5a6e8488SAndroid Build Coastguard Worker p->globals[i] = val;
2880*5a6e8488SAndroid Build Coastguard Worker }
2881*5a6e8488SAndroid Build Coastguard Worker
2882*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2883*5a6e8488SAndroid Build Coastguard Worker // dc-only setup.
2884*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
2885*5a6e8488SAndroid Build Coastguard Worker {
2886*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->tail_calls, sizeof(size_t), BC_DTOR_NONE);
2887*5a6e8488SAndroid Build Coastguard Worker
2888*5a6e8488SAndroid Build Coastguard Worker // We want an item for the main function on the tail call stack.
2889*5a6e8488SAndroid Build Coastguard Worker i = 0;
2890*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->tail_calls, &i);
2891*5a6e8488SAndroid Build Coastguard Worker }
2892*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2893*5a6e8488SAndroid Build Coastguard Worker
2894*5a6e8488SAndroid Build Coastguard Worker bc_num_setup(&p->strmb, p->strmb_num, BC_NUM_BIGDIG_LOG10);
2895*5a6e8488SAndroid Build Coastguard Worker bc_num_bigdig2num(&p->strmb, BC_NUM_STREAM_BASE);
2896*5a6e8488SAndroid Build Coastguard Worker
2897*5a6e8488SAndroid Build Coastguard Worker bc_num_init(&p->asciify, BC_NUM_DEF_SIZE);
2898*5a6e8488SAndroid Build Coastguard Worker
2899*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2900*5a6e8488SAndroid Build Coastguard Worker // We need to initialize srand() just in case /dev/urandom and /dev/random
2901*5a6e8488SAndroid Build Coastguard Worker // are not available.
2902*5a6e8488SAndroid Build Coastguard Worker srand((unsigned int) time(NULL));
2903*5a6e8488SAndroid Build Coastguard Worker bc_rand_init(&p->rng);
2904*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2905*5a6e8488SAndroid Build Coastguard Worker
2906*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2907*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC) bc_num_init(&p->last, BC_NUM_DEF_SIZE);
2908*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2909*5a6e8488SAndroid Build Coastguard Worker
2910*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
2911*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_FUNC);
2912*5a6e8488SAndroid Build Coastguard Worker #else // BC_DEBUG
2913*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->fns, sizeof(BcFunc), BC_DTOR_NONE);
2914*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
2915*5a6e8488SAndroid Build Coastguard Worker bc_map_init(&p->fn_map);
2916*5a6e8488SAndroid Build Coastguard Worker bc_program_insertFunc(p, bc_func_main);
2917*5a6e8488SAndroid Build Coastguard Worker bc_program_insertFunc(p, bc_func_read);
2918*5a6e8488SAndroid Build Coastguard Worker
2919*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->vars, sizeof(BcVec), BC_DTOR_VEC);
2920*5a6e8488SAndroid Build Coastguard Worker bc_map_init(&p->var_map);
2921*5a6e8488SAndroid Build Coastguard Worker
2922*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->arrs, sizeof(BcVec), BC_DTOR_VEC);
2923*5a6e8488SAndroid Build Coastguard Worker bc_map_init(&p->arr_map);
2924*5a6e8488SAndroid Build Coastguard Worker
2925*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->results, sizeof(BcResult), BC_DTOR_RESULT);
2926*5a6e8488SAndroid Build Coastguard Worker
2927*5a6e8488SAndroid Build Coastguard Worker // Push the first instruction pointer onto the execution stack.
2928*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->stack, sizeof(BcInstPtr), BC_DTOR_NONE);
2929*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->stack, &ip);
2930*5a6e8488SAndroid Build Coastguard Worker
2931*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->consts, sizeof(BcConst), BC_DTOR_CONST);
2932*5a6e8488SAndroid Build Coastguard Worker bc_map_init(&p->const_map);
2933*5a6e8488SAndroid Build Coastguard Worker bc_vec_init(&p->strs, sizeof(char*), BC_DTOR_NONE);
2934*5a6e8488SAndroid Build Coastguard Worker bc_map_init(&p->str_map);
2935*5a6e8488SAndroid Build Coastguard Worker }
2936*5a6e8488SAndroid Build Coastguard Worker
2937*5a6e8488SAndroid Build Coastguard Worker void
bc_program_printStackTrace(BcProgram * p)2938*5a6e8488SAndroid Build Coastguard Worker bc_program_printStackTrace(BcProgram* p)
2939*5a6e8488SAndroid Build Coastguard Worker {
2940*5a6e8488SAndroid Build Coastguard Worker size_t i, max_digits;
2941*5a6e8488SAndroid Build Coastguard Worker
2942*5a6e8488SAndroid Build Coastguard Worker max_digits = bc_vm_numDigits(p->stack.len - 1);
2943*5a6e8488SAndroid Build Coastguard Worker
2944*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < p->stack.len; ++i)
2945*5a6e8488SAndroid Build Coastguard Worker {
2946*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip = bc_vec_item_rev(&p->stack, i);
2947*5a6e8488SAndroid Build Coastguard Worker BcFunc* f = bc_vec_item(&p->fns, ip->func);
2948*5a6e8488SAndroid Build Coastguard Worker size_t j, digits;
2949*5a6e8488SAndroid Build Coastguard Worker
2950*5a6e8488SAndroid Build Coastguard Worker digits = bc_vm_numDigits(i);
2951*5a6e8488SAndroid Build Coastguard Worker
2952*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->ferr, bc_flush_none, " ");
2953*5a6e8488SAndroid Build Coastguard Worker
2954*5a6e8488SAndroid Build Coastguard Worker for (j = 0; j < max_digits - digits; ++j)
2955*5a6e8488SAndroid Build Coastguard Worker {
2956*5a6e8488SAndroid Build Coastguard Worker bc_file_putchar(&vm->ferr, bc_flush_none, ' ');
2957*5a6e8488SAndroid Build Coastguard Worker }
2958*5a6e8488SAndroid Build Coastguard Worker
2959*5a6e8488SAndroid Build Coastguard Worker bc_file_printf(&vm->ferr, "%zu: %s", i, f->name);
2960*5a6e8488SAndroid Build Coastguard Worker
2961*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2962*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC && ip->func != BC_PROG_MAIN && ip->func != BC_PROG_READ)
2963*5a6e8488SAndroid Build Coastguard Worker {
2964*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->ferr, bc_flush_none, "()");
2965*5a6e8488SAndroid Build Coastguard Worker }
2966*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2967*5a6e8488SAndroid Build Coastguard Worker
2968*5a6e8488SAndroid Build Coastguard Worker bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
2969*5a6e8488SAndroid Build Coastguard Worker }
2970*5a6e8488SAndroid Build Coastguard Worker }
2971*5a6e8488SAndroid Build Coastguard Worker
2972*5a6e8488SAndroid Build Coastguard Worker void
bc_program_reset(BcProgram * p)2973*5a6e8488SAndroid Build Coastguard Worker bc_program_reset(BcProgram* p)
2974*5a6e8488SAndroid Build Coastguard Worker {
2975*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
2976*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip;
2977*5a6e8488SAndroid Build Coastguard Worker
2978*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
2979*5a6e8488SAndroid Build Coastguard Worker
2980*5a6e8488SAndroid Build Coastguard Worker // Pop all but the last execution.
2981*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&p->stack, p->stack.len - 1);
2982*5a6e8488SAndroid Build Coastguard Worker
2983*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2984*5a6e8488SAndroid Build Coastguard Worker // We need to pop tail calls too.
2985*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC) bc_vec_npop(&p->tail_calls, p->tail_calls.len - 1);
2986*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2987*5a6e8488SAndroid Build Coastguard Worker
2988*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
2989*5a6e8488SAndroid Build Coastguard Worker // Clear the stack if we are in bc. We have to do this in bc because bc's
2990*5a6e8488SAndroid Build Coastguard Worker // stack is implicit.
2991*5a6e8488SAndroid Build Coastguard Worker //
2992*5a6e8488SAndroid Build Coastguard Worker // XXX: We don't do this in dc because other dc implementations don't.
2993*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_BC || !BC_I) bc_vec_popAll(&p->results);
2994*5a6e8488SAndroid Build Coastguard Worker
2995*5a6e8488SAndroid Build Coastguard Worker // Clear the globals' stacks.
2996*5a6e8488SAndroid Build Coastguard Worker if (BC_G) bc_program_popGlobals(p, true);
2997*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2998*5a6e8488SAndroid Build Coastguard Worker
2999*5a6e8488SAndroid Build Coastguard Worker // Clear the bytecode vector of the main function.
3000*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, BC_PROG_MAIN);
3001*5a6e8488SAndroid Build Coastguard Worker bc_vec_npop(&f->code, f->code.len);
3002*5a6e8488SAndroid Build Coastguard Worker
3003*5a6e8488SAndroid Build Coastguard Worker // Reset the instruction pointer.
3004*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3005*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
3006*5a6e8488SAndroid Build Coastguard Worker memset(ip, 0, sizeof(BcInstPtr));
3007*5a6e8488SAndroid Build Coastguard Worker
3008*5a6e8488SAndroid Build Coastguard Worker if (BC_SIG_INTERRUPT(vm))
3009*5a6e8488SAndroid Build Coastguard Worker {
3010*5a6e8488SAndroid Build Coastguard Worker // Write the ready message for a signal.
3011*5a6e8488SAndroid Build Coastguard Worker bc_file_printf(&vm->fout, "%s", bc_program_ready_msg);
3012*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_err);
3013*5a6e8488SAndroid Build Coastguard Worker }
3014*5a6e8488SAndroid Build Coastguard Worker
3015*5a6e8488SAndroid Build Coastguard Worker // Clear the signal.
3016*5a6e8488SAndroid Build Coastguard Worker vm->sig = 0;
3017*5a6e8488SAndroid Build Coastguard Worker }
3018*5a6e8488SAndroid Build Coastguard Worker
3019*5a6e8488SAndroid Build Coastguard Worker void
bc_program_exec(BcProgram * p)3020*5a6e8488SAndroid Build Coastguard Worker bc_program_exec(BcProgram* p)
3021*5a6e8488SAndroid Build Coastguard Worker {
3022*5a6e8488SAndroid Build Coastguard Worker size_t idx;
3023*5a6e8488SAndroid Build Coastguard Worker BcResult r;
3024*5a6e8488SAndroid Build Coastguard Worker BcResult* ptr;
3025*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip;
3026*5a6e8488SAndroid Build Coastguard Worker BcFunc* func;
3027*5a6e8488SAndroid Build Coastguard Worker char* code;
3028*5a6e8488SAndroid Build Coastguard Worker bool cond = false;
3029*5a6e8488SAndroid Build Coastguard Worker uchar inst;
3030*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3031*5a6e8488SAndroid Build Coastguard Worker BcNum* num;
3032*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3033*5a6e8488SAndroid Build Coastguard Worker #if !BC_HAS_COMPUTED_GOTO
3034*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
3035*5a6e8488SAndroid Build Coastguard Worker size_t jmp_bufs_len;
3036*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
3037*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_HAS_COMPUTED_GOTO
3038*5a6e8488SAndroid Build Coastguard Worker
3039*5a6e8488SAndroid Build Coastguard Worker #if BC_HAS_COMPUTED_GOTO
3040*5a6e8488SAndroid Build Coastguard Worker
3041*5a6e8488SAndroid Build Coastguard Worker #if BC_GCC
3042*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic push
3043*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wpedantic"
3044*5a6e8488SAndroid Build Coastguard Worker #endif // BC_GCC
3045*5a6e8488SAndroid Build Coastguard Worker
3046*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
3047*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic push
3048*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wgnu-label-as-value"
3049*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
3050*5a6e8488SAndroid Build Coastguard Worker
3051*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBLS;
3052*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBLS_ASSERT;
3053*5a6e8488SAndroid Build Coastguard Worker
3054*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
3055*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic pop
3056*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
3057*5a6e8488SAndroid Build Coastguard Worker
3058*5a6e8488SAndroid Build Coastguard Worker #if BC_GCC
3059*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
3060*5a6e8488SAndroid Build Coastguard Worker #endif // BC_GCC
3061*5a6e8488SAndroid Build Coastguard Worker
3062*5a6e8488SAndroid Build Coastguard Worker // BC_INST_INVALID is a marker for the end so that we don't have to have an
3063*5a6e8488SAndroid Build Coastguard Worker // execution loop.
3064*5a6e8488SAndroid Build Coastguard Worker func = (BcFunc*) bc_vec_item(&p->fns, BC_PROG_MAIN);
3065*5a6e8488SAndroid Build Coastguard Worker bc_vec_pushByte(&func->code, BC_INST_INVALID);
3066*5a6e8488SAndroid Build Coastguard Worker #endif // BC_HAS_COMPUTED_GOTO
3067*5a6e8488SAndroid Build Coastguard Worker
3068*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP(vm, end);
3069*5a6e8488SAndroid Build Coastguard Worker
3070*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3071*5a6e8488SAndroid Build Coastguard Worker func = (BcFunc*) bc_vec_item(&p->fns, ip->func);
3072*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3073*5a6e8488SAndroid Build Coastguard Worker
3074*5a6e8488SAndroid Build Coastguard Worker #if !BC_HAS_COMPUTED_GOTO
3075*5a6e8488SAndroid Build Coastguard Worker
3076*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
3077*5a6e8488SAndroid Build Coastguard Worker jmp_bufs_len = vm->jmp_bufs.len;
3078*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
3079*5a6e8488SAndroid Build Coastguard Worker
3080*5a6e8488SAndroid Build Coastguard Worker // This loop is the heart of the execution engine. It *is* the engine. For
3081*5a6e8488SAndroid Build Coastguard Worker // computed goto, it is ignored.
3082*5a6e8488SAndroid Build Coastguard Worker while (ip->idx < func->code.len)
3083*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_HAS_COMPUTED_GOTO
3084*5a6e8488SAndroid Build Coastguard Worker {
3085*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_NOT_LOCKED;
3086*5a6e8488SAndroid Build Coastguard Worker
3087*5a6e8488SAndroid Build Coastguard Worker #if BC_HAS_COMPUTED_GOTO
3088*5a6e8488SAndroid Build Coastguard Worker
3089*5a6e8488SAndroid Build Coastguard Worker #if BC_GCC
3090*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic push
3091*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic ignored "-Wpedantic"
3092*5a6e8488SAndroid Build Coastguard Worker #endif // BC_GCC
3093*5a6e8488SAndroid Build Coastguard Worker
3094*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
3095*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic push
3096*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wgnu-label-as-value"
3097*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
3098*5a6e8488SAndroid Build Coastguard Worker
3099*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3100*5a6e8488SAndroid Build Coastguard Worker
3101*5a6e8488SAndroid Build Coastguard Worker #else // BC_HAS_COMPUTED_GOTO
3102*5a6e8488SAndroid Build Coastguard Worker
3103*5a6e8488SAndroid Build Coastguard Worker // Get the next instruction and increment the index.
3104*5a6e8488SAndroid Build Coastguard Worker inst = (uchar) code[(ip->idx)++];
3105*5a6e8488SAndroid Build Coastguard Worker
3106*5a6e8488SAndroid Build Coastguard Worker #endif // BC_HAS_COMPUTED_GOTO
3107*5a6e8488SAndroid Build Coastguard Worker
3108*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG_CODE
3109*5a6e8488SAndroid Build Coastguard Worker bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]);
3110*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->ferr, bc_flush_none);
3111*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG_CODE
3112*5a6e8488SAndroid Build Coastguard Worker
3113*5a6e8488SAndroid Build Coastguard Worker #if !BC_HAS_COMPUTED_GOTO
3114*5a6e8488SAndroid Build Coastguard Worker switch (inst)
3115*5a6e8488SAndroid Build Coastguard Worker #endif // !BC_HAS_COMPUTED_GOTO
3116*5a6e8488SAndroid Build Coastguard Worker {
3117*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3118*5a6e8488SAndroid Build Coastguard Worker // This just sets up the condition for the unconditional jump below,
3119*5a6e8488SAndroid Build Coastguard Worker // which checks the condition, if necessary.
3120*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3121*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_JUMP_ZERO):
3122*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3123*5a6e8488SAndroid Build Coastguard Worker {
3124*5a6e8488SAndroid Build Coastguard Worker bc_program_prep(p, &ptr, &num, 0);
3125*5a6e8488SAndroid Build Coastguard Worker
3126*5a6e8488SAndroid Build Coastguard Worker cond = !bc_num_cmpZero(num);
3127*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
3128*5a6e8488SAndroid Build Coastguard Worker
3129*5a6e8488SAndroid Build Coastguard Worker BC_PROG_DIRECT_JUMP(BC_INST_JUMP)
3130*5a6e8488SAndroid Build Coastguard Worker }
3131*5a6e8488SAndroid Build Coastguard Worker // Fallthrough.
3132*5a6e8488SAndroid Build Coastguard Worker BC_PROG_FALLTHROUGH
3133*5a6e8488SAndroid Build Coastguard Worker
3134*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3135*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_JUMP):
3136*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3137*5a6e8488SAndroid Build Coastguard Worker {
3138*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_index(code, &ip->idx);
3139*5a6e8488SAndroid Build Coastguard Worker
3140*5a6e8488SAndroid Build Coastguard Worker // If a jump is required...
3141*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_JUMP || cond)
3142*5a6e8488SAndroid Build Coastguard Worker {
3143*5a6e8488SAndroid Build Coastguard Worker // Get the address to jump to.
3144*5a6e8488SAndroid Build Coastguard Worker size_t* addr = bc_vec_item(&func->labels, idx);
3145*5a6e8488SAndroid Build Coastguard Worker
3146*5a6e8488SAndroid Build Coastguard Worker // If this fails, then the parser failed to set up the
3147*5a6e8488SAndroid Build Coastguard Worker // labels correctly.
3148*5a6e8488SAndroid Build Coastguard Worker assert(*addr != SIZE_MAX);
3149*5a6e8488SAndroid Build Coastguard Worker
3150*5a6e8488SAndroid Build Coastguard Worker // Set the new address.
3151*5a6e8488SAndroid Build Coastguard Worker ip->idx = *addr;
3152*5a6e8488SAndroid Build Coastguard Worker }
3153*5a6e8488SAndroid Build Coastguard Worker
3154*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3155*5a6e8488SAndroid Build Coastguard Worker }
3156*5a6e8488SAndroid Build Coastguard Worker
3157*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3158*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_CALL):
3159*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3160*5a6e8488SAndroid Build Coastguard Worker {
3161*5a6e8488SAndroid Build Coastguard Worker assert(BC_IS_BC);
3162*5a6e8488SAndroid Build Coastguard Worker
3163*5a6e8488SAndroid Build Coastguard Worker bc_program_call(p, code, &ip->idx);
3164*5a6e8488SAndroid Build Coastguard Worker
3165*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3166*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3167*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3168*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3169*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3170*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3171*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3172*5a6e8488SAndroid Build Coastguard Worker
3173*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3174*5a6e8488SAndroid Build Coastguard Worker }
3175*5a6e8488SAndroid Build Coastguard Worker
3176*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3177*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_INC):
3178*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_DEC):
3179*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3180*5a6e8488SAndroid Build Coastguard Worker {
3181*5a6e8488SAndroid Build Coastguard Worker bc_program_incdec(p, inst);
3182*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3183*5a6e8488SAndroid Build Coastguard Worker }
3184*5a6e8488SAndroid Build Coastguard Worker
3185*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3186*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_HALT):
3187*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3188*5a6e8488SAndroid Build Coastguard Worker {
3189*5a6e8488SAndroid Build Coastguard Worker vm->status = BC_STATUS_QUIT;
3190*5a6e8488SAndroid Build Coastguard Worker
3191*5a6e8488SAndroid Build Coastguard Worker // Just jump out. The jump series will take care of everything.
3192*5a6e8488SAndroid Build Coastguard Worker BC_JMP;
3193*5a6e8488SAndroid Build Coastguard Worker
3194*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3195*5a6e8488SAndroid Build Coastguard Worker }
3196*5a6e8488SAndroid Build Coastguard Worker
3197*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3198*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_RET):
3199*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_RET0):
3200*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_RET_VOID):
3201*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3202*5a6e8488SAndroid Build Coastguard Worker {
3203*5a6e8488SAndroid Build Coastguard Worker bc_program_return(p, inst);
3204*5a6e8488SAndroid Build Coastguard Worker
3205*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3206*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3207*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3208*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3209*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3210*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3211*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3212*5a6e8488SAndroid Build Coastguard Worker
3213*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3214*5a6e8488SAndroid Build Coastguard Worker }
3215*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3216*5a6e8488SAndroid Build Coastguard Worker
3217*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3218*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_BOOL_OR):
3219*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_BOOL_AND):
3220*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_EQ):
3221*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_LE):
3222*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_GE):
3223*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_NE):
3224*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_LT):
3225*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REL_GT):
3226*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3227*5a6e8488SAndroid Build Coastguard Worker {
3228*5a6e8488SAndroid Build Coastguard Worker bc_program_logical(p, inst);
3229*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3230*5a6e8488SAndroid Build Coastguard Worker }
3231*5a6e8488SAndroid Build Coastguard Worker
3232*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3233*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_READ):
3234*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3235*5a6e8488SAndroid Build Coastguard Worker {
3236*5a6e8488SAndroid Build Coastguard Worker // We want to flush output before
3237*5a6e8488SAndroid Build Coastguard Worker // this in case there is a prompt.
3238*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_save);
3239*5a6e8488SAndroid Build Coastguard Worker
3240*5a6e8488SAndroid Build Coastguard Worker bc_program_read(p);
3241*5a6e8488SAndroid Build Coastguard Worker
3242*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3243*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3244*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3245*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3246*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3247*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3248*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3249*5a6e8488SAndroid Build Coastguard Worker
3250*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3251*5a6e8488SAndroid Build Coastguard Worker }
3252*5a6e8488SAndroid Build Coastguard Worker
3253*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3254*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3255*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_RAND):
3256*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3257*5a6e8488SAndroid Build Coastguard Worker {
3258*5a6e8488SAndroid Build Coastguard Worker bc_program_rand(p);
3259*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3260*5a6e8488SAndroid Build Coastguard Worker }
3261*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3262*5a6e8488SAndroid Build Coastguard Worker
3263*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3264*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MAXIBASE):
3265*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MAXOBASE):
3266*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MAXSCALE):
3267*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3268*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MAXRAND):
3269*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3270*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3271*5a6e8488SAndroid Build Coastguard Worker {
3272*5a6e8488SAndroid Build Coastguard Worker BcBigDig dig = vm->maxes[inst - BC_INST_MAXIBASE];
3273*5a6e8488SAndroid Build Coastguard Worker bc_program_pushBigdig(p, dig, BC_RESULT_TEMP);
3274*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3275*5a6e8488SAndroid Build Coastguard Worker }
3276*5a6e8488SAndroid Build Coastguard Worker
3277*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3278*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LINE_LENGTH):
3279*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3280*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_GLOBAL_STACKS):
3281*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3282*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
3283*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_EXTENDED_REGISTERS):
3284*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLE
3285*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LEADING_ZERO):
3286*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3287*5a6e8488SAndroid Build Coastguard Worker {
3288*5a6e8488SAndroid Build Coastguard Worker bc_program_globalSetting(p, inst);
3289*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3290*5a6e8488SAndroid Build Coastguard Worker }
3291*5a6e8488SAndroid Build Coastguard Worker
3292*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3293*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_VAR):
3294*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3295*5a6e8488SAndroid Build Coastguard Worker {
3296*5a6e8488SAndroid Build Coastguard Worker bc_program_pushVar(p, code, &ip->idx, false, false);
3297*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3298*5a6e8488SAndroid Build Coastguard Worker }
3299*5a6e8488SAndroid Build Coastguard Worker
3300*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3301*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ARRAY_ELEM):
3302*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ARRAY):
3303*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3304*5a6e8488SAndroid Build Coastguard Worker {
3305*5a6e8488SAndroid Build Coastguard Worker bc_program_pushArray(p, code, &ip->idx, inst);
3306*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3307*5a6e8488SAndroid Build Coastguard Worker }
3308*5a6e8488SAndroid Build Coastguard Worker
3309*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3310*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_IBASE):
3311*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_SCALE):
3312*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_OBASE):
3313*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3314*5a6e8488SAndroid Build Coastguard Worker {
3315*5a6e8488SAndroid Build Coastguard Worker bc_program_pushGlobal(p, inst);
3316*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3317*5a6e8488SAndroid Build Coastguard Worker }
3318*5a6e8488SAndroid Build Coastguard Worker
3319*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3320*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3321*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_SEED):
3322*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3323*5a6e8488SAndroid Build Coastguard Worker {
3324*5a6e8488SAndroid Build Coastguard Worker bc_program_pushSeed(p);
3325*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3326*5a6e8488SAndroid Build Coastguard Worker }
3327*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3328*5a6e8488SAndroid Build Coastguard Worker
3329*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3330*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LENGTH):
3331*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_SCALE_FUNC):
3332*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_SQRT):
3333*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ABS):
3334*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_IS_NUMBER):
3335*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_IS_STRING):
3336*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3337*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_IRAND):
3338*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3339*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3340*5a6e8488SAndroid Build Coastguard Worker {
3341*5a6e8488SAndroid Build Coastguard Worker bc_program_builtin(p, inst);
3342*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3343*5a6e8488SAndroid Build Coastguard Worker }
3344*5a6e8488SAndroid Build Coastguard Worker
3345*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3346*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASCIIFY):
3347*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3348*5a6e8488SAndroid Build Coastguard Worker {
3349*5a6e8488SAndroid Build Coastguard Worker bc_program_asciify(p);
3350*5a6e8488SAndroid Build Coastguard Worker
3351*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3352*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3353*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3354*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3355*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3356*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3357*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3358*5a6e8488SAndroid Build Coastguard Worker
3359*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3360*5a6e8488SAndroid Build Coastguard Worker }
3361*5a6e8488SAndroid Build Coastguard Worker
3362*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3363*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_NUM):
3364*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3365*5a6e8488SAndroid Build Coastguard Worker {
3366*5a6e8488SAndroid Build Coastguard Worker bc_program_const(p, code, &ip->idx);
3367*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3368*5a6e8488SAndroid Build Coastguard Worker }
3369*5a6e8488SAndroid Build Coastguard Worker
3370*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3371*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ZERO):
3372*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ONE):
3373*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3374*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LAST):
3375*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3376*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3377*5a6e8488SAndroid Build Coastguard Worker {
3378*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_ZERO + (inst - BC_INST_ZERO);
3379*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
3380*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3381*5a6e8488SAndroid Build Coastguard Worker }
3382*5a6e8488SAndroid Build Coastguard Worker
3383*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3384*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PRINT):
3385*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PRINT_POP):
3386*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3387*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PRINT_STR):
3388*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3389*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3390*5a6e8488SAndroid Build Coastguard Worker {
3391*5a6e8488SAndroid Build Coastguard Worker bc_program_print(p, inst, 0);
3392*5a6e8488SAndroid Build Coastguard Worker
3393*5a6e8488SAndroid Build Coastguard Worker // We want to flush right away to save the output for history,
3394*5a6e8488SAndroid Build Coastguard Worker // if history must preserve it when taking input.
3395*5a6e8488SAndroid Build Coastguard Worker bc_file_flush(&vm->fout, bc_flush_save);
3396*5a6e8488SAndroid Build Coastguard Worker
3397*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3398*5a6e8488SAndroid Build Coastguard Worker }
3399*5a6e8488SAndroid Build Coastguard Worker
3400*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3401*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_STR):
3402*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3403*5a6e8488SAndroid Build Coastguard Worker {
3404*5a6e8488SAndroid Build Coastguard Worker // Set up the result and push.
3405*5a6e8488SAndroid Build Coastguard Worker r.t = BC_RESULT_STR;
3406*5a6e8488SAndroid Build Coastguard Worker bc_num_clear(&r.d.n);
3407*5a6e8488SAndroid Build Coastguard Worker r.d.n.scale = bc_program_index(code, &ip->idx);
3408*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
3409*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3410*5a6e8488SAndroid Build Coastguard Worker }
3411*5a6e8488SAndroid Build Coastguard Worker
3412*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3413*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_POWER):
3414*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MULTIPLY):
3415*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_DIVIDE):
3416*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MODULUS):
3417*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PLUS):
3418*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MINUS):
3419*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3420*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PLACES):
3421*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LSHIFT):
3422*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_RSHIFT):
3423*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3424*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3425*5a6e8488SAndroid Build Coastguard Worker {
3426*5a6e8488SAndroid Build Coastguard Worker bc_program_op(p, inst);
3427*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3428*5a6e8488SAndroid Build Coastguard Worker }
3429*5a6e8488SAndroid Build Coastguard Worker
3430*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3431*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_NEG):
3432*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_BOOL_NOT):
3433*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3434*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_TRUNC):
3435*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3436*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3437*5a6e8488SAndroid Build Coastguard Worker {
3438*5a6e8488SAndroid Build Coastguard Worker bc_program_unary(p, inst);
3439*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3440*5a6e8488SAndroid Build Coastguard Worker }
3441*5a6e8488SAndroid Build Coastguard Worker
3442*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3443*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
3444*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_POWER):
3445*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY):
3446*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE):
3447*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MODULUS):
3448*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_PLUS):
3449*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MINUS):
3450*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3451*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_PLACES):
3452*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT):
3453*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT):
3454*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3455*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN):
3456*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_POWER_NO_VAL):
3457*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MULTIPLY_NO_VAL):
3458*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_DIVIDE_NO_VAL):
3459*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MODULUS_NO_VAL):
3460*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_PLUS_NO_VAL):
3461*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_MINUS_NO_VAL):
3462*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
3463*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_PLACES_NO_VAL):
3464*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_LSHIFT_NO_VAL):
3465*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_RSHIFT_NO_VAL):
3466*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
3467*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
3468*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_ASSIGN_NO_VAL):
3469*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3470*5a6e8488SAndroid Build Coastguard Worker {
3471*5a6e8488SAndroid Build Coastguard Worker bc_program_assign(p, inst);
3472*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3473*5a6e8488SAndroid Build Coastguard Worker }
3474*5a6e8488SAndroid Build Coastguard Worker
3475*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3476*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_POP):
3477*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3478*5a6e8488SAndroid Build Coastguard Worker {
3479*5a6e8488SAndroid Build Coastguard Worker #ifndef BC_PROG_NO_STACK_CHECK
3480*5a6e8488SAndroid Build Coastguard Worker // dc must do a stack check, but bc does not.
3481*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_DC)
3482*5a6e8488SAndroid Build Coastguard Worker {
3483*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3484*5a6e8488SAndroid Build Coastguard Worker {
3485*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
3486*5a6e8488SAndroid Build Coastguard Worker }
3487*5a6e8488SAndroid Build Coastguard Worker }
3488*5a6e8488SAndroid Build Coastguard Worker #endif // BC_PROG_NO_STACK_CHECK
3489*5a6e8488SAndroid Build Coastguard Worker
3490*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
3491*5a6e8488SAndroid Build Coastguard Worker
3492*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->results);
3493*5a6e8488SAndroid Build Coastguard Worker
3494*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3495*5a6e8488SAndroid Build Coastguard Worker }
3496*5a6e8488SAndroid Build Coastguard Worker
3497*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3498*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_SWAP):
3499*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3500*5a6e8488SAndroid Build Coastguard Worker {
3501*5a6e8488SAndroid Build Coastguard Worker BcResult* ptr2;
3502*5a6e8488SAndroid Build Coastguard Worker
3503*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
3504*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 2)))
3505*5a6e8488SAndroid Build Coastguard Worker {
3506*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
3507*5a6e8488SAndroid Build Coastguard Worker }
3508*5a6e8488SAndroid Build Coastguard Worker
3509*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 2));
3510*5a6e8488SAndroid Build Coastguard Worker
3511*5a6e8488SAndroid Build Coastguard Worker // Get the two items.
3512*5a6e8488SAndroid Build Coastguard Worker ptr = bc_vec_item_rev(&p->results, 0);
3513*5a6e8488SAndroid Build Coastguard Worker ptr2 = bc_vec_item_rev(&p->results, 1);
3514*5a6e8488SAndroid Build Coastguard Worker
3515*5a6e8488SAndroid Build Coastguard Worker // Swap. It's just easiest to do it this way.
3516*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
3517*5a6e8488SAndroid Build Coastguard Worker memcpy(&r, ptr, sizeof(BcResult));
3518*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
3519*5a6e8488SAndroid Build Coastguard Worker memcpy(ptr, ptr2, sizeof(BcResult));
3520*5a6e8488SAndroid Build Coastguard Worker // NOLINTNEXTLINE
3521*5a6e8488SAndroid Build Coastguard Worker memcpy(ptr2, &r, sizeof(BcResult));
3522*5a6e8488SAndroid Build Coastguard Worker
3523*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3524*5a6e8488SAndroid Build Coastguard Worker }
3525*5a6e8488SAndroid Build Coastguard Worker
3526*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3527*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_MODEXP):
3528*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3529*5a6e8488SAndroid Build Coastguard Worker {
3530*5a6e8488SAndroid Build Coastguard Worker bc_program_modexp(p);
3531*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3532*5a6e8488SAndroid Build Coastguard Worker }
3533*5a6e8488SAndroid Build Coastguard Worker
3534*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3535*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_DIVMOD):
3536*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3537*5a6e8488SAndroid Build Coastguard Worker {
3538*5a6e8488SAndroid Build Coastguard Worker bc_program_divmod(p);
3539*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3540*5a6e8488SAndroid Build Coastguard Worker }
3541*5a6e8488SAndroid Build Coastguard Worker
3542*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3543*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PRINT_STREAM):
3544*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3545*5a6e8488SAndroid Build Coastguard Worker {
3546*5a6e8488SAndroid Build Coastguard Worker bc_program_printStream(p);
3547*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3548*5a6e8488SAndroid Build Coastguard Worker }
3549*5a6e8488SAndroid Build Coastguard Worker
3550*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
3551*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3552*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_POP_EXEC):
3553*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3554*5a6e8488SAndroid Build Coastguard Worker {
3555*5a6e8488SAndroid Build Coastguard Worker // If this fails, the dc parser got something wrong.
3556*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->stack, 2));
3557*5a6e8488SAndroid Build Coastguard Worker
3558*5a6e8488SAndroid Build Coastguard Worker // Pop the execution stack and tail call stack.
3559*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->stack);
3560*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->tail_calls);
3561*5a6e8488SAndroid Build Coastguard Worker
3562*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3563*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3564*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3565*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3566*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3567*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3568*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3569*5a6e8488SAndroid Build Coastguard Worker
3570*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3571*5a6e8488SAndroid Build Coastguard Worker }
3572*5a6e8488SAndroid Build Coastguard Worker
3573*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3574*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_EXECUTE):
3575*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_EXEC_COND):
3576*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3577*5a6e8488SAndroid Build Coastguard Worker {
3578*5a6e8488SAndroid Build Coastguard Worker cond = (inst == BC_INST_EXEC_COND);
3579*5a6e8488SAndroid Build Coastguard Worker
3580*5a6e8488SAndroid Build Coastguard Worker bc_program_execStr(p, code, &ip->idx, cond, func->code.len);
3581*5a6e8488SAndroid Build Coastguard Worker
3582*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3583*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3584*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3585*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3586*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3587*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3588*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3589*5a6e8488SAndroid Build Coastguard Worker
3590*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3591*5a6e8488SAndroid Build Coastguard Worker }
3592*5a6e8488SAndroid Build Coastguard Worker
3593*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3594*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PRINT_STACK):
3595*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3596*5a6e8488SAndroid Build Coastguard Worker {
3597*5a6e8488SAndroid Build Coastguard Worker bc_program_printStack(p);
3598*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3599*5a6e8488SAndroid Build Coastguard Worker }
3600*5a6e8488SAndroid Build Coastguard Worker
3601*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3602*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_CLEAR_STACK):
3603*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3604*5a6e8488SAndroid Build Coastguard Worker {
3605*5a6e8488SAndroid Build Coastguard Worker bc_vec_popAll(&p->results);
3606*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3607*5a6e8488SAndroid Build Coastguard Worker }
3608*5a6e8488SAndroid Build Coastguard Worker
3609*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3610*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_REG_STACK_LEN):
3611*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3612*5a6e8488SAndroid Build Coastguard Worker {
3613*5a6e8488SAndroid Build Coastguard Worker bc_program_regStackLen(p, code, &ip->idx);
3614*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3615*5a6e8488SAndroid Build Coastguard Worker }
3616*5a6e8488SAndroid Build Coastguard Worker
3617*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3618*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_STACK_LEN):
3619*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3620*5a6e8488SAndroid Build Coastguard Worker {
3621*5a6e8488SAndroid Build Coastguard Worker bc_program_stackLen(p);
3622*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3623*5a6e8488SAndroid Build Coastguard Worker }
3624*5a6e8488SAndroid Build Coastguard Worker
3625*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3626*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_DUPLICATE):
3627*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3628*5a6e8488SAndroid Build Coastguard Worker {
3629*5a6e8488SAndroid Build Coastguard Worker // Check the stack.
3630*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PROG_STACK(&p->results, 1)))
3631*5a6e8488SAndroid Build Coastguard Worker {
3632*5a6e8488SAndroid Build Coastguard Worker bc_err(BC_ERR_EXEC_STACK);
3633*5a6e8488SAndroid Build Coastguard Worker }
3634*5a6e8488SAndroid Build Coastguard Worker
3635*5a6e8488SAndroid Build Coastguard Worker assert(BC_PROG_STACK(&p->results, 1));
3636*5a6e8488SAndroid Build Coastguard Worker
3637*5a6e8488SAndroid Build Coastguard Worker // Get the top of the stack.
3638*5a6e8488SAndroid Build Coastguard Worker ptr = bc_vec_top(&p->results);
3639*5a6e8488SAndroid Build Coastguard Worker
3640*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3641*5a6e8488SAndroid Build Coastguard Worker
3642*5a6e8488SAndroid Build Coastguard Worker // Copy and push.
3643*5a6e8488SAndroid Build Coastguard Worker bc_result_copy(&r, ptr);
3644*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->results, &r);
3645*5a6e8488SAndroid Build Coastguard Worker
3646*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3647*5a6e8488SAndroid Build Coastguard Worker
3648*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3649*5a6e8488SAndroid Build Coastguard Worker }
3650*5a6e8488SAndroid Build Coastguard Worker
3651*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3652*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_LOAD):
3653*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PUSH_VAR):
3654*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3655*5a6e8488SAndroid Build Coastguard Worker {
3656*5a6e8488SAndroid Build Coastguard Worker bool copy = (inst == BC_INST_LOAD);
3657*5a6e8488SAndroid Build Coastguard Worker bc_program_pushVar(p, code, &ip->idx, true, copy);
3658*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3659*5a6e8488SAndroid Build Coastguard Worker }
3660*5a6e8488SAndroid Build Coastguard Worker
3661*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3662*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_PUSH_TO_VAR):
3663*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3664*5a6e8488SAndroid Build Coastguard Worker {
3665*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_index(code, &ip->idx);
3666*5a6e8488SAndroid Build Coastguard Worker bc_program_copyToVar(p, idx, BC_TYPE_VAR);
3667*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3668*5a6e8488SAndroid Build Coastguard Worker }
3669*5a6e8488SAndroid Build Coastguard Worker
3670*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3671*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_QUIT):
3672*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_NQUIT):
3673*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3674*5a6e8488SAndroid Build Coastguard Worker {
3675*5a6e8488SAndroid Build Coastguard Worker bc_program_nquit(p, inst);
3676*5a6e8488SAndroid Build Coastguard Worker
3677*5a6e8488SAndroid Build Coastguard Worker // Because we changed the execution stack and where we are
3678*5a6e8488SAndroid Build Coastguard Worker // executing, we have to update all of this.
3679*5a6e8488SAndroid Build Coastguard Worker BC_SIG_LOCK;
3680*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_top(&p->stack);
3681*5a6e8488SAndroid Build Coastguard Worker func = bc_vec_item(&p->fns, ip->func);
3682*5a6e8488SAndroid Build Coastguard Worker code = func->code.v;
3683*5a6e8488SAndroid Build Coastguard Worker BC_SIG_UNLOCK;
3684*5a6e8488SAndroid Build Coastguard Worker
3685*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3686*5a6e8488SAndroid Build Coastguard Worker }
3687*5a6e8488SAndroid Build Coastguard Worker
3688*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3689*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_EXEC_STACK_LEN):
3690*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3691*5a6e8488SAndroid Build Coastguard Worker {
3692*5a6e8488SAndroid Build Coastguard Worker bc_program_execStackLen(p);
3693*5a6e8488SAndroid Build Coastguard Worker BC_PROG_JUMP(inst, code, ip);
3694*5a6e8488SAndroid Build Coastguard Worker }
3695*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
3696*5a6e8488SAndroid Build Coastguard Worker
3697*5a6e8488SAndroid Build Coastguard Worker #if BC_HAS_COMPUTED_GOTO
3698*5a6e8488SAndroid Build Coastguard Worker // clang-format off
3699*5a6e8488SAndroid Build Coastguard Worker BC_PROG_LBL(BC_INST_INVALID):
3700*5a6e8488SAndroid Build Coastguard Worker // clang-format on
3701*5a6e8488SAndroid Build Coastguard Worker {
3702*5a6e8488SAndroid Build Coastguard Worker goto end;
3703*5a6e8488SAndroid Build Coastguard Worker }
3704*5a6e8488SAndroid Build Coastguard Worker #else // BC_HAS_COMPUTED_GOTO
3705*5a6e8488SAndroid Build Coastguard Worker default:
3706*5a6e8488SAndroid Build Coastguard Worker {
3707*5a6e8488SAndroid Build Coastguard Worker BC_UNREACHABLE
3708*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG && !BC_CLANG
3709*5a6e8488SAndroid Build Coastguard Worker abort();
3710*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG && !BC_CLANG
3711*5a6e8488SAndroid Build Coastguard Worker }
3712*5a6e8488SAndroid Build Coastguard Worker #endif // BC_HAS_COMPUTED_GOTO
3713*5a6e8488SAndroid Build Coastguard Worker }
3714*5a6e8488SAndroid Build Coastguard Worker
3715*5a6e8488SAndroid Build Coastguard Worker #if BC_HAS_COMPUTED_GOTO
3716*5a6e8488SAndroid Build Coastguard Worker
3717*5a6e8488SAndroid Build Coastguard Worker #if BC_CLANG
3718*5a6e8488SAndroid Build Coastguard Worker #pragma clang diagnostic pop
3719*5a6e8488SAndroid Build Coastguard Worker #endif // BC_CLANG
3720*5a6e8488SAndroid Build Coastguard Worker
3721*5a6e8488SAndroid Build Coastguard Worker #if BC_GCC
3722*5a6e8488SAndroid Build Coastguard Worker #pragma GCC diagnostic pop
3723*5a6e8488SAndroid Build Coastguard Worker #endif // BC_GCC
3724*5a6e8488SAndroid Build Coastguard Worker
3725*5a6e8488SAndroid Build Coastguard Worker #else // BC_HAS_COMPUTED_GOTO
3726*5a6e8488SAndroid Build Coastguard Worker
3727*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
3728*5a6e8488SAndroid Build Coastguard Worker // This is to allow me to use a debugger to see the last instruction,
3729*5a6e8488SAndroid Build Coastguard Worker // which will point to which function was the problem. But it's also a
3730*5a6e8488SAndroid Build Coastguard Worker // good smoke test for error handling changes.
3731*5a6e8488SAndroid Build Coastguard Worker assert(jmp_bufs_len == vm->jmp_bufs.len);
3732*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
3733*5a6e8488SAndroid Build Coastguard Worker
3734*5a6e8488SAndroid Build Coastguard Worker #endif // BC_HAS_COMPUTED_GOTO
3735*5a6e8488SAndroid Build Coastguard Worker }
3736*5a6e8488SAndroid Build Coastguard Worker
3737*5a6e8488SAndroid Build Coastguard Worker end:
3738*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
3739*5a6e8488SAndroid Build Coastguard Worker
3740*5a6e8488SAndroid Build Coastguard Worker // This is here just to print a stack trace on interrupts. This is for
3741*5a6e8488SAndroid Build Coastguard Worker // finding infinite loops.
3742*5a6e8488SAndroid Build Coastguard Worker if (BC_SIG_INTERRUPT(vm))
3743*5a6e8488SAndroid Build Coastguard Worker {
3744*5a6e8488SAndroid Build Coastguard Worker BcStatus s;
3745*5a6e8488SAndroid Build Coastguard Worker
3746*5a6e8488SAndroid Build Coastguard Worker bc_file_putchar(&vm->ferr, bc_flush_none, '\n');
3747*5a6e8488SAndroid Build Coastguard Worker
3748*5a6e8488SAndroid Build Coastguard Worker bc_program_printStackTrace(p);
3749*5a6e8488SAndroid Build Coastguard Worker
3750*5a6e8488SAndroid Build Coastguard Worker s = bc_file_flushErr(&vm->ferr, bc_flush_err);
3751*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(s != BC_STATUS_SUCCESS && vm->status == BC_STATUS_SUCCESS))
3752*5a6e8488SAndroid Build Coastguard Worker {
3753*5a6e8488SAndroid Build Coastguard Worker vm->status = (sig_atomic_t) s;
3754*5a6e8488SAndroid Build Coastguard Worker }
3755*5a6e8488SAndroid Build Coastguard Worker }
3756*5a6e8488SAndroid Build Coastguard Worker
3757*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
3758*5a6e8488SAndroid Build Coastguard Worker }
3759*5a6e8488SAndroid Build Coastguard Worker
3760*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG_CODE
3761*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED && DC_ENABLED
3762*5a6e8488SAndroid Build Coastguard Worker void
bc_program_printStackDebug(BcProgram * p)3763*5a6e8488SAndroid Build Coastguard Worker bc_program_printStackDebug(BcProgram* p)
3764*5a6e8488SAndroid Build Coastguard Worker {
3765*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack ----------\n");
3766*5a6e8488SAndroid Build Coastguard Worker bc_program_printStack(p);
3767*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_err, "-------------- Stack End ------\n");
3768*5a6e8488SAndroid Build Coastguard Worker }
3769*5a6e8488SAndroid Build Coastguard Worker
3770*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printIndex(const char * restrict code,size_t * restrict bgn)3771*5a6e8488SAndroid Build Coastguard Worker bc_program_printIndex(const char* restrict code, size_t* restrict bgn)
3772*5a6e8488SAndroid Build Coastguard Worker {
3773*5a6e8488SAndroid Build Coastguard Worker uchar byte, i, bytes = (uchar) code[(*bgn)++];
3774*5a6e8488SAndroid Build Coastguard Worker ulong val = 0;
3775*5a6e8488SAndroid Build Coastguard Worker
3776*5a6e8488SAndroid Build Coastguard Worker for (byte = 1, i = 0; byte && i < bytes; ++i)
3777*5a6e8488SAndroid Build Coastguard Worker {
3778*5a6e8488SAndroid Build Coastguard Worker byte = (uchar) code[(*bgn)++];
3779*5a6e8488SAndroid Build Coastguard Worker if (byte) val |= ((ulong) byte) << (CHAR_BIT * i);
3780*5a6e8488SAndroid Build Coastguard Worker }
3781*5a6e8488SAndroid Build Coastguard Worker
3782*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf(" (%lu) ", val);
3783*5a6e8488SAndroid Build Coastguard Worker }
3784*5a6e8488SAndroid Build Coastguard Worker
3785*5a6e8488SAndroid Build Coastguard Worker static void
bc_program_printStr(const BcProgram * p,const char * restrict code,size_t * restrict bgn)3786*5a6e8488SAndroid Build Coastguard Worker bc_program_printStr(const BcProgram* p, const char* restrict code,
3787*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn)
3788*5a6e8488SAndroid Build Coastguard Worker {
3789*5a6e8488SAndroid Build Coastguard Worker size_t idx = bc_program_index(code, bgn);
3790*5a6e8488SAndroid Build Coastguard Worker char* s;
3791*5a6e8488SAndroid Build Coastguard Worker
3792*5a6e8488SAndroid Build Coastguard Worker s = *((char**) bc_vec_item(&p->strs, idx));
3793*5a6e8488SAndroid Build Coastguard Worker
3794*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf(" (\"%s\") ", s);
3795*5a6e8488SAndroid Build Coastguard Worker }
3796*5a6e8488SAndroid Build Coastguard Worker
3797*5a6e8488SAndroid Build Coastguard Worker void
bc_program_printInst(const BcProgram * p,const char * restrict code,size_t * restrict bgn)3798*5a6e8488SAndroid Build Coastguard Worker bc_program_printInst(const BcProgram* p, const char* restrict code,
3799*5a6e8488SAndroid Build Coastguard Worker size_t* restrict bgn)
3800*5a6e8488SAndroid Build Coastguard Worker {
3801*5a6e8488SAndroid Build Coastguard Worker uchar inst = (uchar) code[(*bgn)++];
3802*5a6e8488SAndroid Build Coastguard Worker
3803*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("Inst[%zu]: %s [%lu]; ", *bgn - 1, bc_inst_names[inst],
3804*5a6e8488SAndroid Build Coastguard Worker (unsigned long) inst);
3805*5a6e8488SAndroid Build Coastguard Worker
3806*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_VAR || inst == BC_INST_ARRAY_ELEM ||
3807*5a6e8488SAndroid Build Coastguard Worker inst == BC_INST_ARRAY)
3808*5a6e8488SAndroid Build Coastguard Worker {
3809*5a6e8488SAndroid Build Coastguard Worker bc_program_printIndex(code, bgn);
3810*5a6e8488SAndroid Build Coastguard Worker }
3811*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_STR) bc_program_printStr(p, code, bgn);
3812*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_NUM)
3813*5a6e8488SAndroid Build Coastguard Worker {
3814*5a6e8488SAndroid Build Coastguard Worker size_t idx = bc_program_index(code, bgn);
3815*5a6e8488SAndroid Build Coastguard Worker BcConst* c = bc_vec_item(&p->consts, idx);
3816*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("(%s)", c->val);
3817*5a6e8488SAndroid Build Coastguard Worker }
3818*5a6e8488SAndroid Build Coastguard Worker else if (inst == BC_INST_CALL ||
3819*5a6e8488SAndroid Build Coastguard Worker (inst > BC_INST_STR && inst <= BC_INST_JUMP_ZERO))
3820*5a6e8488SAndroid Build Coastguard Worker {
3821*5a6e8488SAndroid Build Coastguard Worker bc_program_printIndex(code, bgn);
3822*5a6e8488SAndroid Build Coastguard Worker if (inst == BC_INST_CALL) bc_program_printIndex(code, bgn);
3823*5a6e8488SAndroid Build Coastguard Worker }
3824*5a6e8488SAndroid Build Coastguard Worker
3825*5a6e8488SAndroid Build Coastguard Worker bc_vm_putchar('\n', bc_flush_err);
3826*5a6e8488SAndroid Build Coastguard Worker }
3827*5a6e8488SAndroid Build Coastguard Worker
3828*5a6e8488SAndroid Build Coastguard Worker void
bc_program_code(const BcProgram * p)3829*5a6e8488SAndroid Build Coastguard Worker bc_program_code(const BcProgram* p)
3830*5a6e8488SAndroid Build Coastguard Worker {
3831*5a6e8488SAndroid Build Coastguard Worker BcFunc* f;
3832*5a6e8488SAndroid Build Coastguard Worker char* code;
3833*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
3834*5a6e8488SAndroid Build Coastguard Worker size_t i;
3835*5a6e8488SAndroid Build Coastguard Worker
3836*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < p->fns.len; ++i)
3837*5a6e8488SAndroid Build Coastguard Worker {
3838*5a6e8488SAndroid Build Coastguard Worker ip.idx = ip.len = 0;
3839*5a6e8488SAndroid Build Coastguard Worker ip.func = i;
3840*5a6e8488SAndroid Build Coastguard Worker
3841*5a6e8488SAndroid Build Coastguard Worker f = bc_vec_item(&p->fns, ip.func);
3842*5a6e8488SAndroid Build Coastguard Worker code = f->code.v;
3843*5a6e8488SAndroid Build Coastguard Worker
3844*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("func[%zu]:\n", ip.func);
3845*5a6e8488SAndroid Build Coastguard Worker while (ip.idx < f->code.len)
3846*5a6e8488SAndroid Build Coastguard Worker {
3847*5a6e8488SAndroid Build Coastguard Worker bc_program_printInst(p, code, &ip.idx);
3848*5a6e8488SAndroid Build Coastguard Worker }
3849*5a6e8488SAndroid Build Coastguard Worker bc_file_puts(&vm->fout, bc_flush_err, "\n\n");
3850*5a6e8488SAndroid Build Coastguard Worker }
3851*5a6e8488SAndroid Build Coastguard Worker }
3852*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED && DC_ENABLED
3853*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG_CODE
3854