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 * The parser for dc.
33*5a6e8488SAndroid Build Coastguard Worker *
34*5a6e8488SAndroid Build Coastguard Worker */
35*5a6e8488SAndroid Build Coastguard Worker
36*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
37*5a6e8488SAndroid Build Coastguard Worker
38*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
39*5a6e8488SAndroid Build Coastguard Worker #include <stdlib.h>
40*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
41*5a6e8488SAndroid Build Coastguard Worker #include <setjmp.h>
42*5a6e8488SAndroid Build Coastguard Worker
43*5a6e8488SAndroid Build Coastguard Worker #include <dc.h>
44*5a6e8488SAndroid Build Coastguard Worker #include <program.h>
45*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
46*5a6e8488SAndroid Build Coastguard Worker
47*5a6e8488SAndroid Build Coastguard Worker /**
48*5a6e8488SAndroid Build Coastguard Worker * Parses a register. The lexer should have already lexed the true name of the
49*5a6e8488SAndroid Build Coastguard Worker * register, per extended registers and such.
50*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
51*5a6e8488SAndroid Build Coastguard Worker * @param var True if the parser is for a variable, false otherwise.
52*5a6e8488SAndroid Build Coastguard Worker */
53*5a6e8488SAndroid Build Coastguard Worker static void
dc_parse_register(BcParse * p,bool var)54*5a6e8488SAndroid Build Coastguard Worker dc_parse_register(BcParse* p, bool var)
55*5a6e8488SAndroid Build Coastguard Worker {
56*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
57*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_NAME) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
58*5a6e8488SAndroid Build Coastguard Worker
59*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushName(p, p->l.str.v, var);
60*5a6e8488SAndroid Build Coastguard Worker }
61*5a6e8488SAndroid Build Coastguard Worker
62*5a6e8488SAndroid Build Coastguard Worker /**
63*5a6e8488SAndroid Build Coastguard Worker * Parses a dc string.
64*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
65*5a6e8488SAndroid Build Coastguard Worker */
66*5a6e8488SAndroid Build Coastguard Worker static inline void
dc_parse_string(BcParse * p)67*5a6e8488SAndroid Build Coastguard Worker dc_parse_string(BcParse* p)
68*5a6e8488SAndroid Build Coastguard Worker {
69*5a6e8488SAndroid Build Coastguard Worker bc_parse_addString(p);
70*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
71*5a6e8488SAndroid Build Coastguard Worker }
72*5a6e8488SAndroid Build Coastguard Worker
73*5a6e8488SAndroid Build Coastguard Worker /**
74*5a6e8488SAndroid Build Coastguard Worker * Parses a token that requires a memory operation, like load or store.
75*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
76*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction to push for the memory operation.
77*5a6e8488SAndroid Build Coastguard Worker * @param name Whether the load or store is to a variable or array, and not to
78*5a6e8488SAndroid Build Coastguard Worker * a global.
79*5a6e8488SAndroid Build Coastguard Worker * @param store True if the operation is a store, false otherwise.
80*5a6e8488SAndroid Build Coastguard Worker */
81*5a6e8488SAndroid Build Coastguard Worker static void
dc_parse_mem(BcParse * p,uchar inst,bool name,bool store)82*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(BcParse* p, uchar inst, bool name, bool store)
83*5a6e8488SAndroid Build Coastguard Worker {
84*5a6e8488SAndroid Build Coastguard Worker // Push the instruction.
85*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
86*5a6e8488SAndroid Build Coastguard Worker
87*5a6e8488SAndroid Build Coastguard Worker // Parse the register if necessary.
88*5a6e8488SAndroid Build Coastguard Worker if (name) dc_parse_register(p, inst != BC_INST_ARRAY_ELEM);
89*5a6e8488SAndroid Build Coastguard Worker
90*5a6e8488SAndroid Build Coastguard Worker // Stores use the bc assign infrastructure, but they need to do a swap
91*5a6e8488SAndroid Build Coastguard Worker // first.
92*5a6e8488SAndroid Build Coastguard Worker if (store)
93*5a6e8488SAndroid Build Coastguard Worker {
94*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_SWAP);
95*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
96*5a6e8488SAndroid Build Coastguard Worker }
97*5a6e8488SAndroid Build Coastguard Worker
98*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
99*5a6e8488SAndroid Build Coastguard Worker }
100*5a6e8488SAndroid Build Coastguard Worker
101*5a6e8488SAndroid Build Coastguard Worker /**
102*5a6e8488SAndroid Build Coastguard Worker * Parses a conditional execution instruction.
103*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
104*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction for the condition.
105*5a6e8488SAndroid Build Coastguard Worker */
106*5a6e8488SAndroid Build Coastguard Worker static void
dc_parse_cond(BcParse * p,uchar inst)107*5a6e8488SAndroid Build Coastguard Worker dc_parse_cond(BcParse* p, uchar inst)
108*5a6e8488SAndroid Build Coastguard Worker {
109*5a6e8488SAndroid Build Coastguard Worker // Push the instruction for the condition and the conditional execution.
110*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
111*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_EXEC_COND);
112*5a6e8488SAndroid Build Coastguard Worker
113*5a6e8488SAndroid Build Coastguard Worker // Parse the register.
114*5a6e8488SAndroid Build Coastguard Worker dc_parse_register(p, true);
115*5a6e8488SAndroid Build Coastguard Worker
116*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
117*5a6e8488SAndroid Build Coastguard Worker
118*5a6e8488SAndroid Build Coastguard Worker // If the next token is an else, parse the else.
119*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_KW_ELSE)
120*5a6e8488SAndroid Build Coastguard Worker {
121*5a6e8488SAndroid Build Coastguard Worker dc_parse_register(p, true);
122*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
123*5a6e8488SAndroid Build Coastguard Worker }
124*5a6e8488SAndroid Build Coastguard Worker // Otherwise, push a marker for no else.
125*5a6e8488SAndroid Build Coastguard Worker else bc_parse_pushIndex(p, SIZE_MAX);
126*5a6e8488SAndroid Build Coastguard Worker }
127*5a6e8488SAndroid Build Coastguard Worker
128*5a6e8488SAndroid Build Coastguard Worker /**
129*5a6e8488SAndroid Build Coastguard Worker * Parses a token for dc.
130*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
131*5a6e8488SAndroid Build Coastguard Worker * @param t The token to parse.
132*5a6e8488SAndroid Build Coastguard Worker * @param flags The flags that say what is allowed or not.
133*5a6e8488SAndroid Build Coastguard Worker */
134*5a6e8488SAndroid Build Coastguard Worker static void
dc_parse_token(BcParse * p,BcLexType t,uint8_t flags)135*5a6e8488SAndroid Build Coastguard Worker dc_parse_token(BcParse* p, BcLexType t, uint8_t flags)
136*5a6e8488SAndroid Build Coastguard Worker {
137*5a6e8488SAndroid Build Coastguard Worker uchar inst;
138*5a6e8488SAndroid Build Coastguard Worker bool assign, get_token = false;
139*5a6e8488SAndroid Build Coastguard Worker
140*5a6e8488SAndroid Build Coastguard Worker switch (t)
141*5a6e8488SAndroid Build Coastguard Worker {
142*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_EQ:
143*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LE:
144*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GE:
145*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_NE:
146*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LT:
147*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GT:
148*5a6e8488SAndroid Build Coastguard Worker {
149*5a6e8488SAndroid Build Coastguard Worker inst = (uchar) (t - BC_LEX_OP_REL_EQ + BC_INST_REL_EQ);
150*5a6e8488SAndroid Build Coastguard Worker dc_parse_cond(p, inst);
151*5a6e8488SAndroid Build Coastguard Worker break;
152*5a6e8488SAndroid Build Coastguard Worker }
153*5a6e8488SAndroid Build Coastguard Worker
154*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCOLON:
155*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COLON:
156*5a6e8488SAndroid Build Coastguard Worker {
157*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(p, BC_INST_ARRAY_ELEM, true, t == BC_LEX_COLON);
158*5a6e8488SAndroid Build Coastguard Worker break;
159*5a6e8488SAndroid Build Coastguard Worker }
160*5a6e8488SAndroid Build Coastguard Worker
161*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STR:
162*5a6e8488SAndroid Build Coastguard Worker {
163*5a6e8488SAndroid Build Coastguard Worker dc_parse_string(p);
164*5a6e8488SAndroid Build Coastguard Worker break;
165*5a6e8488SAndroid Build Coastguard Worker }
166*5a6e8488SAndroid Build Coastguard Worker
167*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NEG:
168*5a6e8488SAndroid Build Coastguard Worker {
169*5a6e8488SAndroid Build Coastguard Worker // This tells us whether or not the neg is for a command or at the
170*5a6e8488SAndroid Build Coastguard Worker // beginning of a number. If it's a command, push it. Otherwise,
171*5a6e8488SAndroid Build Coastguard Worker // fallthrough and parse the number.
172*5a6e8488SAndroid Build Coastguard Worker if (dc_lex_negCommand(&p->l))
173*5a6e8488SAndroid Build Coastguard Worker {
174*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_NEG);
175*5a6e8488SAndroid Build Coastguard Worker get_token = true;
176*5a6e8488SAndroid Build Coastguard Worker break;
177*5a6e8488SAndroid Build Coastguard Worker }
178*5a6e8488SAndroid Build Coastguard Worker
179*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
180*5a6e8488SAndroid Build Coastguard Worker
181*5a6e8488SAndroid Build Coastguard Worker // Fallthrough.
182*5a6e8488SAndroid Build Coastguard Worker BC_FALLTHROUGH
183*5a6e8488SAndroid Build Coastguard Worker }
184*5a6e8488SAndroid Build Coastguard Worker
185*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NUMBER:
186*5a6e8488SAndroid Build Coastguard Worker {
187*5a6e8488SAndroid Build Coastguard Worker bc_parse_number(p);
188*5a6e8488SAndroid Build Coastguard Worker
189*5a6e8488SAndroid Build Coastguard Worker // Push the negative instruction if we fell through from above.
190*5a6e8488SAndroid Build Coastguard Worker if (t == BC_LEX_NEG) bc_parse_push(p, BC_INST_NEG);
191*5a6e8488SAndroid Build Coastguard Worker get_token = true;
192*5a6e8488SAndroid Build Coastguard Worker
193*5a6e8488SAndroid Build Coastguard Worker break;
194*5a6e8488SAndroid Build Coastguard Worker }
195*5a6e8488SAndroid Build Coastguard Worker
196*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_READ:
197*5a6e8488SAndroid Build Coastguard Worker {
198*5a6e8488SAndroid Build Coastguard Worker // Make sure the read is not recursive.
199*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(flags & BC_PARSE_NOREAD))
200*5a6e8488SAndroid Build Coastguard Worker {
201*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_EXEC_REC_READ);
202*5a6e8488SAndroid Build Coastguard Worker }
203*5a6e8488SAndroid Build Coastguard Worker else bc_parse_push(p, BC_INST_READ);
204*5a6e8488SAndroid Build Coastguard Worker
205*5a6e8488SAndroid Build Coastguard Worker get_token = true;
206*5a6e8488SAndroid Build Coastguard Worker
207*5a6e8488SAndroid Build Coastguard Worker break;
208*5a6e8488SAndroid Build Coastguard Worker }
209*5a6e8488SAndroid Build Coastguard Worker
210*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN:
211*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_PUSH:
212*5a6e8488SAndroid Build Coastguard Worker {
213*5a6e8488SAndroid Build Coastguard Worker assign = t == BC_LEX_OP_ASSIGN;
214*5a6e8488SAndroid Build Coastguard Worker inst = assign ? BC_INST_VAR : BC_INST_PUSH_TO_VAR;
215*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(p, inst, true, assign);
216*5a6e8488SAndroid Build Coastguard Worker break;
217*5a6e8488SAndroid Build Coastguard Worker }
218*5a6e8488SAndroid Build Coastguard Worker
219*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD:
220*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD_POP:
221*5a6e8488SAndroid Build Coastguard Worker {
222*5a6e8488SAndroid Build Coastguard Worker inst = t == BC_LEX_LOAD_POP ? BC_INST_PUSH_VAR : BC_INST_LOAD;
223*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(p, inst, true, false);
224*5a6e8488SAndroid Build Coastguard Worker break;
225*5a6e8488SAndroid Build Coastguard Worker }
226*5a6e8488SAndroid Build Coastguard Worker
227*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_REG_STACK_LEVEL:
228*5a6e8488SAndroid Build Coastguard Worker {
229*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(p, BC_INST_REG_STACK_LEN, true, false);
230*5a6e8488SAndroid Build Coastguard Worker break;
231*5a6e8488SAndroid Build Coastguard Worker }
232*5a6e8488SAndroid Build Coastguard Worker
233*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_IBASE:
234*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_OBASE:
235*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SCALE:
236*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
237*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SEED:
238*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
239*5a6e8488SAndroid Build Coastguard Worker {
240*5a6e8488SAndroid Build Coastguard Worker inst = (uchar) (t - BC_LEX_STORE_IBASE + BC_INST_IBASE);
241*5a6e8488SAndroid Build Coastguard Worker dc_parse_mem(p, inst, false, true);
242*5a6e8488SAndroid Build Coastguard Worker break;
243*5a6e8488SAndroid Build Coastguard Worker }
244*5a6e8488SAndroid Build Coastguard Worker
245*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_ARRAY_LENGTH:
246*5a6e8488SAndroid Build Coastguard Worker {
247*5a6e8488SAndroid Build Coastguard Worker // Need to push the array first, based on how length is implemented.
248*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ARRAY);
249*5a6e8488SAndroid Build Coastguard Worker dc_parse_register(p, false);
250*5a6e8488SAndroid Build Coastguard Worker
251*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_LENGTH);
252*5a6e8488SAndroid Build Coastguard Worker
253*5a6e8488SAndroid Build Coastguard Worker get_token = true;
254*5a6e8488SAndroid Build Coastguard Worker
255*5a6e8488SAndroid Build Coastguard Worker break;
256*5a6e8488SAndroid Build Coastguard Worker }
257*5a6e8488SAndroid Build Coastguard Worker
258*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EOF:
259*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_INVALID:
260*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
261*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_INC:
262*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DEC:
263*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
264*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_NOT:
265*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
266*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_TRUNC:
267*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
268*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_POWER:
269*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MULTIPLY:
270*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DIVIDE:
271*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MODULUS:
272*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLUS:
273*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MINUS:
274*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
275*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLACES:
276*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_LSHIFT:
277*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_RSHIFT:
278*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
279*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_OR:
280*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_AND:
281*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
282*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_POWER:
283*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MULTIPLY:
284*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_DIVIDE:
285*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MODULUS:
286*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLUS:
287*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MINUS:
288*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
289*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLACES:
290*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_LSHIFT:
291*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_RSHIFT:
292*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
293*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
294*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NLINE:
295*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_WHITESPACE:
296*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LPAREN:
297*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RPAREN:
298*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACKET:
299*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COMMA:
300*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACKET:
301*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACE:
302*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NAME:
303*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACE:
304*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
305*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_AUTO:
306*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_BREAK:
307*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_CONTINUE:
308*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DEFINE:
309*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_FOR:
310*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IF:
311*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LIMITS:
312*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RETURN:
313*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_WHILE:
314*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_HALT:
315*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LAST:
316*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
317*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IBASE:
318*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_OBASE:
319*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SCALE:
320*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
321*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SEED:
322*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
323*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LENGTH:
324*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_PRINT:
325*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SQRT:
326*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ABS:
327*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_NUMBER:
328*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_STRING:
329*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
330*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IRAND:
331*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
332*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ASCIIFY:
333*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MODEXP:
334*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DIVMOD:
335*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_QUIT:
336*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
337*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RAND:
338*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
339*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXIBASE:
340*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXOBASE:
341*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXSCALE:
342*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
343*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXRAND:
344*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
345*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LINE_LENGTH:
346*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
347*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_GLOBAL_STACKS:
348*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
349*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LEADING_ZERO:
350*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_STREAM:
351*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ELSE:
352*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXTENDED_REGISTERS:
353*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EQ_NO_REG:
354*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXECUTE:
355*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_STACK:
356*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_CLEAR_STACK:
357*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STACK_LEVEL:
358*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_DUPLICATE:
359*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SWAP:
360*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_POP:
361*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_POP:
362*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NQUIT:
363*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXEC_STACK_LENGTH:
364*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCALE_FACTOR:
365*5a6e8488SAndroid Build Coastguard Worker {
366*5a6e8488SAndroid Build Coastguard Worker // All other tokens should be taken care of by the caller, or they
367*5a6e8488SAndroid Build Coastguard Worker // actually *are* invalid.
368*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
369*5a6e8488SAndroid Build Coastguard Worker }
370*5a6e8488SAndroid Build Coastguard Worker }
371*5a6e8488SAndroid Build Coastguard Worker
372*5a6e8488SAndroid Build Coastguard Worker if (get_token) bc_lex_next(&p->l);
373*5a6e8488SAndroid Build Coastguard Worker }
374*5a6e8488SAndroid Build Coastguard Worker
375*5a6e8488SAndroid Build Coastguard Worker void
dc_parse_expr(BcParse * p,uint8_t flags)376*5a6e8488SAndroid Build Coastguard Worker dc_parse_expr(BcParse* p, uint8_t flags)
377*5a6e8488SAndroid Build Coastguard Worker {
378*5a6e8488SAndroid Build Coastguard Worker BcInst inst;
379*5a6e8488SAndroid Build Coastguard Worker BcLexType t;
380*5a6e8488SAndroid Build Coastguard Worker bool need_expr, have_expr = false;
381*5a6e8488SAndroid Build Coastguard Worker
382*5a6e8488SAndroid Build Coastguard Worker need_expr = ((flags & BC_PARSE_NOREAD) != 0);
383*5a6e8488SAndroid Build Coastguard Worker
384*5a6e8488SAndroid Build Coastguard Worker // dc can just keep parsing forever basically, unlike bc, which has to have
385*5a6e8488SAndroid Build Coastguard Worker // a whole bunch of complicated nonsense because its language was horribly
386*5a6e8488SAndroid Build Coastguard Worker // designed.
387*5a6e8488SAndroid Build Coastguard Worker
388*5a6e8488SAndroid Build Coastguard Worker // While we don't have EOF...
389*5a6e8488SAndroid Build Coastguard Worker while ((t = p->l.t) != BC_LEX_EOF)
390*5a6e8488SAndroid Build Coastguard Worker {
391*5a6e8488SAndroid Build Coastguard Worker // Eat newline.
392*5a6e8488SAndroid Build Coastguard Worker if (t == BC_LEX_NLINE)
393*5a6e8488SAndroid Build Coastguard Worker {
394*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
395*5a6e8488SAndroid Build Coastguard Worker continue;
396*5a6e8488SAndroid Build Coastguard Worker }
397*5a6e8488SAndroid Build Coastguard Worker
398*5a6e8488SAndroid Build Coastguard Worker // Get the instruction that corresponds to the token.
399*5a6e8488SAndroid Build Coastguard Worker inst = dc_parse_insts[t];
400*5a6e8488SAndroid Build Coastguard Worker
401*5a6e8488SAndroid Build Coastguard Worker // If the instruction is invalid, that means we have to do some harder
402*5a6e8488SAndroid Build Coastguard Worker // parsing. So if not invalid, just push the instruction; otherwise,
403*5a6e8488SAndroid Build Coastguard Worker // parse the token.
404*5a6e8488SAndroid Build Coastguard Worker if (inst != BC_INST_INVALID)
405*5a6e8488SAndroid Build Coastguard Worker {
406*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
407*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
408*5a6e8488SAndroid Build Coastguard Worker }
409*5a6e8488SAndroid Build Coastguard Worker else dc_parse_token(p, t, flags);
410*5a6e8488SAndroid Build Coastguard Worker
411*5a6e8488SAndroid Build Coastguard Worker have_expr = true;
412*5a6e8488SAndroid Build Coastguard Worker }
413*5a6e8488SAndroid Build Coastguard Worker
414*5a6e8488SAndroid Build Coastguard Worker // If we don't have an expression and need one, barf. Otherwise, just push a
415*5a6e8488SAndroid Build Coastguard Worker // BC_INST_POP_EXEC if we have EOF and BC_PARSE_NOCALL, which dc uses to
416*5a6e8488SAndroid Build Coastguard Worker // indicate that it is executing a string.
417*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(need_expr && !have_expr)) bc_err(BC_ERR_EXEC_READ_EXPR);
418*5a6e8488SAndroid Build Coastguard Worker else if (p->l.t == BC_LEX_EOF && (flags & BC_PARSE_NOCALL))
419*5a6e8488SAndroid Build Coastguard Worker {
420*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_POP_EXEC);
421*5a6e8488SAndroid Build Coastguard Worker }
422*5a6e8488SAndroid Build Coastguard Worker }
423*5a6e8488SAndroid Build Coastguard Worker
424*5a6e8488SAndroid Build Coastguard Worker void
dc_parse_parse(BcParse * p)425*5a6e8488SAndroid Build Coastguard Worker dc_parse_parse(BcParse* p)
426*5a6e8488SAndroid Build Coastguard Worker {
427*5a6e8488SAndroid Build Coastguard Worker assert(p != NULL);
428*5a6e8488SAndroid Build Coastguard Worker
429*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exit);
430*5a6e8488SAndroid Build Coastguard Worker
431*5a6e8488SAndroid Build Coastguard Worker // If we have EOF, someone called this function one too many times.
432*5a6e8488SAndroid Build Coastguard Worker // Otherwise, parse.
433*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
434*5a6e8488SAndroid Build Coastguard Worker else dc_parse_expr(p, 0);
435*5a6e8488SAndroid Build Coastguard Worker
436*5a6e8488SAndroid Build Coastguard Worker exit:
437*5a6e8488SAndroid Build Coastguard Worker
438*5a6e8488SAndroid Build Coastguard Worker // Need to reset if there was an error.
439*5a6e8488SAndroid Build Coastguard Worker if (BC_SIG_EXC(vm)) bc_parse_reset(p);
440*5a6e8488SAndroid Build Coastguard Worker
441*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
442*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
443*5a6e8488SAndroid Build Coastguard Worker }
444*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
445