xref: /aosp_15_r20/external/bc/src/dc_parse.c (revision 5a6e848804d15c18a0125914844ee4eb0bda4fcf)
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