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 bc.
33*5a6e8488SAndroid Build Coastguard Worker *
34*5a6e8488SAndroid Build Coastguard Worker */
35*5a6e8488SAndroid Build Coastguard Worker
36*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLED
37*5a6e8488SAndroid Build Coastguard Worker
38*5a6e8488SAndroid Build Coastguard Worker #include <assert.h>
39*5a6e8488SAndroid Build Coastguard Worker #include <stdbool.h>
40*5a6e8488SAndroid Build Coastguard Worker #include <stdlib.h>
41*5a6e8488SAndroid Build Coastguard Worker #include <string.h>
42*5a6e8488SAndroid Build Coastguard Worker
43*5a6e8488SAndroid Build Coastguard Worker #include <setjmp.h>
44*5a6e8488SAndroid Build Coastguard Worker
45*5a6e8488SAndroid Build Coastguard Worker #include <bc.h>
46*5a6e8488SAndroid Build Coastguard Worker #include <num.h>
47*5a6e8488SAndroid Build Coastguard Worker #include <vm.h>
48*5a6e8488SAndroid Build Coastguard Worker
49*5a6e8488SAndroid Build Coastguard Worker // Before you embark on trying to understand this code, have you read the
50*5a6e8488SAndroid Build Coastguard Worker // Development manual (manuals/development.md) and the comment in include/bc.h
51*5a6e8488SAndroid Build Coastguard Worker // yet? No? Do that first. I'm serious.
52*5a6e8488SAndroid Build Coastguard Worker //
53*5a6e8488SAndroid Build Coastguard Worker // The reason is because this file holds the most sensitive and finicky code in
54*5a6e8488SAndroid Build Coastguard Worker // the entire codebase. Even getting history to work on Windows was nothing
55*5a6e8488SAndroid Build Coastguard Worker // compared to this. This is where dreams go to die, where dragons live, and
56*5a6e8488SAndroid Build Coastguard Worker // from which Ken Thompson himself would flee.
57*5a6e8488SAndroid Build Coastguard Worker
58*5a6e8488SAndroid Build Coastguard Worker static void
59*5a6e8488SAndroid Build Coastguard Worker bc_parse_else(BcParse* p);
60*5a6e8488SAndroid Build Coastguard Worker
61*5a6e8488SAndroid Build Coastguard Worker static void
62*5a6e8488SAndroid Build Coastguard Worker bc_parse_stmt(BcParse* p);
63*5a6e8488SAndroid Build Coastguard Worker
64*5a6e8488SAndroid Build Coastguard Worker static BcParseStatus
65*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next);
66*5a6e8488SAndroid Build Coastguard Worker
67*5a6e8488SAndroid Build Coastguard Worker static void
68*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next);
69*5a6e8488SAndroid Build Coastguard Worker
70*5a6e8488SAndroid Build Coastguard Worker /**
71*5a6e8488SAndroid Build Coastguard Worker * Returns true if an instruction could only have come from a "leaf" expression.
72*5a6e8488SAndroid Build Coastguard Worker * For more on what leaf expressions are, read the comment for BC_PARSE_LEAF().
73*5a6e8488SAndroid Build Coastguard Worker * @param t The instruction to test.
74*5a6e8488SAndroid Build Coastguard Worker * @return True if the instruction is a from a leaf expression.
75*5a6e8488SAndroid Build Coastguard Worker */
76*5a6e8488SAndroid Build Coastguard Worker static bool
bc_parse_inst_isLeaf(BcInst t)77*5a6e8488SAndroid Build Coastguard Worker bc_parse_inst_isLeaf(BcInst t)
78*5a6e8488SAndroid Build Coastguard Worker {
79*5a6e8488SAndroid Build Coastguard Worker return (t >= BC_INST_NUM && t <= BC_INST_LEADING_ZERO) ||
80*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
81*5a6e8488SAndroid Build Coastguard Worker t == BC_INST_TRUNC ||
82*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
83*5a6e8488SAndroid Build Coastguard Worker t <= BC_INST_DEC;
84*5a6e8488SAndroid Build Coastguard Worker }
85*5a6e8488SAndroid Build Coastguard Worker
86*5a6e8488SAndroid Build Coastguard Worker /**
87*5a6e8488SAndroid Build Coastguard Worker * Returns true if the *previous* token was a delimiter. A delimiter is anything
88*5a6e8488SAndroid Build Coastguard Worker * that can legally end a statement. In bc's case, it could be a newline, a
89*5a6e8488SAndroid Build Coastguard Worker * semicolon, and a brace in certain cases.
90*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
91*5a6e8488SAndroid Build Coastguard Worker * @return True if the token is a legal delimiter.
92*5a6e8488SAndroid Build Coastguard Worker */
93*5a6e8488SAndroid Build Coastguard Worker static bool
bc_parse_isDelimiter(const BcParse * p)94*5a6e8488SAndroid Build Coastguard Worker bc_parse_isDelimiter(const BcParse* p)
95*5a6e8488SAndroid Build Coastguard Worker {
96*5a6e8488SAndroid Build Coastguard Worker BcLexType t = p->l.t;
97*5a6e8488SAndroid Build Coastguard Worker bool good;
98*5a6e8488SAndroid Build Coastguard Worker
99*5a6e8488SAndroid Build Coastguard Worker // If it's an obvious delimiter, say so.
100*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_DELIMITER(t)) return true;
101*5a6e8488SAndroid Build Coastguard Worker
102*5a6e8488SAndroid Build Coastguard Worker good = false;
103*5a6e8488SAndroid Build Coastguard Worker
104*5a6e8488SAndroid Build Coastguard Worker // If the current token is a keyword, then...beware. That means that we need
105*5a6e8488SAndroid Build Coastguard Worker // to check for a "dangling" else, where there was no brace-delimited block
106*5a6e8488SAndroid Build Coastguard Worker // on the previous if.
107*5a6e8488SAndroid Build Coastguard Worker if (t == BC_LEX_KW_ELSE)
108*5a6e8488SAndroid Build Coastguard Worker {
109*5a6e8488SAndroid Build Coastguard Worker size_t i;
110*5a6e8488SAndroid Build Coastguard Worker uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
111*5a6e8488SAndroid Build Coastguard Worker
112*5a6e8488SAndroid Build Coastguard Worker // As long as going up the stack is valid for a dangling else, keep on.
113*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i)
114*5a6e8488SAndroid Build Coastguard Worker {
115*5a6e8488SAndroid Build Coastguard Worker fptr = bc_vec_item_rev(&p->flags, i);
116*5a6e8488SAndroid Build Coastguard Worker flags = *fptr;
117*5a6e8488SAndroid Build Coastguard Worker
118*5a6e8488SAndroid Build Coastguard Worker // If we need a brace and don't have one, then we don't have a
119*5a6e8488SAndroid Build Coastguard Worker // delimiter.
120*5a6e8488SAndroid Build Coastguard Worker if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
121*5a6e8488SAndroid Build Coastguard Worker {
122*5a6e8488SAndroid Build Coastguard Worker return false;
123*5a6e8488SAndroid Build Coastguard Worker }
124*5a6e8488SAndroid Build Coastguard Worker }
125*5a6e8488SAndroid Build Coastguard Worker
126*5a6e8488SAndroid Build Coastguard Worker // Oh, and we had also better have an if statement somewhere.
127*5a6e8488SAndroid Build Coastguard Worker good = ((flags & BC_PARSE_FLAG_IF) != 0);
128*5a6e8488SAndroid Build Coastguard Worker }
129*5a6e8488SAndroid Build Coastguard Worker else if (t == BC_LEX_RBRACE)
130*5a6e8488SAndroid Build Coastguard Worker {
131*5a6e8488SAndroid Build Coastguard Worker size_t i;
132*5a6e8488SAndroid Build Coastguard Worker
133*5a6e8488SAndroid Build Coastguard Worker // Since we have a brace, we need to just check if a brace was needed.
134*5a6e8488SAndroid Build Coastguard Worker for (i = 0; !good && i < p->flags.len; ++i)
135*5a6e8488SAndroid Build Coastguard Worker {
136*5a6e8488SAndroid Build Coastguard Worker uint16_t* fptr = bc_vec_item_rev(&p->flags, i);
137*5a6e8488SAndroid Build Coastguard Worker good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
138*5a6e8488SAndroid Build Coastguard Worker }
139*5a6e8488SAndroid Build Coastguard Worker }
140*5a6e8488SAndroid Build Coastguard Worker
141*5a6e8488SAndroid Build Coastguard Worker return good;
142*5a6e8488SAndroid Build Coastguard Worker }
143*5a6e8488SAndroid Build Coastguard Worker
144*5a6e8488SAndroid Build Coastguard Worker /**
145*5a6e8488SAndroid Build Coastguard Worker * Returns true if we are in top level of a function body. The POSIX grammar
146*5a6e8488SAndroid Build Coastguard Worker * is defined such that anything is allowed after a function body, so we must
147*5a6e8488SAndroid Build Coastguard Worker * use this function to detect that case when ending a function body.
148*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
149*5a6e8488SAndroid Build Coastguard Worker * @return True if we are in the top level of parsing a function body.
150*5a6e8488SAndroid Build Coastguard Worker */
151*5a6e8488SAndroid Build Coastguard Worker static bool
bc_parse_TopFunc(const BcParse * p)152*5a6e8488SAndroid Build Coastguard Worker bc_parse_TopFunc(const BcParse* p)
153*5a6e8488SAndroid Build Coastguard Worker {
154*5a6e8488SAndroid Build Coastguard Worker bool good = p->flags.len == 2;
155*5a6e8488SAndroid Build Coastguard Worker
156*5a6e8488SAndroid Build Coastguard Worker uint16_t val = BC_PARSE_FLAG_BRACE | BC_PARSE_FLAG_FUNC_INNER;
157*5a6e8488SAndroid Build Coastguard Worker val |= BC_PARSE_FLAG_FUNC;
158*5a6e8488SAndroid Build Coastguard Worker
159*5a6e8488SAndroid Build Coastguard Worker return good && BC_PARSE_TOP_FLAG(p) == val;
160*5a6e8488SAndroid Build Coastguard Worker }
161*5a6e8488SAndroid Build Coastguard Worker
162*5a6e8488SAndroid Build Coastguard Worker /**
163*5a6e8488SAndroid Build Coastguard Worker * Sets a previously defined exit label. What are labels? See the bc Parsing
164*5a6e8488SAndroid Build Coastguard Worker * section of the Development manual (manuals/development.md).
165*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
166*5a6e8488SAndroid Build Coastguard Worker */
167*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_setLabel(BcParse * p)168*5a6e8488SAndroid Build Coastguard Worker bc_parse_setLabel(BcParse* p)
169*5a6e8488SAndroid Build Coastguard Worker {
170*5a6e8488SAndroid Build Coastguard Worker BcFunc* func = p->func;
171*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip = bc_vec_top(&p->exits);
172*5a6e8488SAndroid Build Coastguard Worker size_t* label;
173*5a6e8488SAndroid Build Coastguard Worker
174*5a6e8488SAndroid Build Coastguard Worker assert(func == bc_vec_item(&p->prog->fns, p->fidx));
175*5a6e8488SAndroid Build Coastguard Worker
176*5a6e8488SAndroid Build Coastguard Worker // Set the preallocated label to the correct index.
177*5a6e8488SAndroid Build Coastguard Worker label = bc_vec_item(&func->labels, ip->idx);
178*5a6e8488SAndroid Build Coastguard Worker *label = func->code.len;
179*5a6e8488SAndroid Build Coastguard Worker
180*5a6e8488SAndroid Build Coastguard Worker // Now, we don't need the exit label; it is done.
181*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->exits);
182*5a6e8488SAndroid Build Coastguard Worker }
183*5a6e8488SAndroid Build Coastguard Worker
184*5a6e8488SAndroid Build Coastguard Worker /**
185*5a6e8488SAndroid Build Coastguard Worker * Creates a label and sets it to idx. If this is an exit label, then idx is
186*5a6e8488SAndroid Build Coastguard Worker * actually invalid, but it doesn't matter because it will be fixed by
187*5a6e8488SAndroid Build Coastguard Worker * bc_parse_setLabel() later.
188*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
189*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the label.
190*5a6e8488SAndroid Build Coastguard Worker */
191*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_createLabel(BcParse * p,size_t idx)192*5a6e8488SAndroid Build Coastguard Worker bc_parse_createLabel(BcParse* p, size_t idx)
193*5a6e8488SAndroid Build Coastguard Worker {
194*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->func->labels, &idx);
195*5a6e8488SAndroid Build Coastguard Worker }
196*5a6e8488SAndroid Build Coastguard Worker
197*5a6e8488SAndroid Build Coastguard Worker /**
198*5a6e8488SAndroid Build Coastguard Worker * Creates a conditional label. Unlike an exit label, this label is set at
199*5a6e8488SAndroid Build Coastguard Worker * creation time because it comes *before* the code that will target it.
200*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
201*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the label.
202*5a6e8488SAndroid Build Coastguard Worker */
203*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_createCondLabel(BcParse * p,size_t idx)204*5a6e8488SAndroid Build Coastguard Worker bc_parse_createCondLabel(BcParse* p, size_t idx)
205*5a6e8488SAndroid Build Coastguard Worker {
206*5a6e8488SAndroid Build Coastguard Worker bc_parse_createLabel(p, p->func->code.len);
207*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->conds, &idx);
208*5a6e8488SAndroid Build Coastguard Worker }
209*5a6e8488SAndroid Build Coastguard Worker
210*5a6e8488SAndroid Build Coastguard Worker /**
211*5a6e8488SAndroid Build Coastguard Worker * Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
212*5a6e8488SAndroid Build Coastguard Worker * create a label to be filled in later? Because exit labels are meant to be
213*5a6e8488SAndroid Build Coastguard Worker * targeted by code that comes *before* the label. Since we have to parse that
214*5a6e8488SAndroid Build Coastguard Worker * code first, and don't know how long it will be, we need to just make sure to
215*5a6e8488SAndroid Build Coastguard Worker * reserve a slot to be filled in later when we know.
216*5a6e8488SAndroid Build Coastguard Worker *
217*5a6e8488SAndroid Build Coastguard Worker * By the way, this uses BcInstPtr because it was convenient. The field idx
218*5a6e8488SAndroid Build Coastguard Worker * holds the index, and the field func holds the loop boolean.
219*5a6e8488SAndroid Build Coastguard Worker *
220*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
221*5a6e8488SAndroid Build Coastguard Worker * @param idx The index of the label's position.
222*5a6e8488SAndroid Build Coastguard Worker * @param loop True if the exit label is for a loop or not.
223*5a6e8488SAndroid Build Coastguard Worker */
224*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_createExitLabel(BcParse * p,size_t idx,bool loop)225*5a6e8488SAndroid Build Coastguard Worker bc_parse_createExitLabel(BcParse* p, size_t idx, bool loop)
226*5a6e8488SAndroid Build Coastguard Worker {
227*5a6e8488SAndroid Build Coastguard Worker BcInstPtr ip;
228*5a6e8488SAndroid Build Coastguard Worker
229*5a6e8488SAndroid Build Coastguard Worker assert(p->func == bc_vec_item(&p->prog->fns, p->fidx));
230*5a6e8488SAndroid Build Coastguard Worker
231*5a6e8488SAndroid Build Coastguard Worker ip.func = loop;
232*5a6e8488SAndroid Build Coastguard Worker ip.idx = idx;
233*5a6e8488SAndroid Build Coastguard Worker ip.len = 0;
234*5a6e8488SAndroid Build Coastguard Worker
235*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->exits, &ip);
236*5a6e8488SAndroid Build Coastguard Worker bc_parse_createLabel(p, SIZE_MAX);
237*5a6e8488SAndroid Build Coastguard Worker }
238*5a6e8488SAndroid Build Coastguard Worker
239*5a6e8488SAndroid Build Coastguard Worker /**
240*5a6e8488SAndroid Build Coastguard Worker * Pops the correct operators off of the operator stack based on the current
241*5a6e8488SAndroid Build Coastguard Worker * operator. This is because of the Shunting-Yard algorithm. Lower prec means
242*5a6e8488SAndroid Build Coastguard Worker * higher precedence.
243*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
244*5a6e8488SAndroid Build Coastguard Worker * @param type The operator.
245*5a6e8488SAndroid Build Coastguard Worker * @param start The previous start of the operator stack. For more
246*5a6e8488SAndroid Build Coastguard Worker * information, see the bc Parsing section of the Development
247*5a6e8488SAndroid Build Coastguard Worker * manual (manuals/development.md).
248*5a6e8488SAndroid Build Coastguard Worker * @param nexprs A pointer to the current number of expressions that have not
249*5a6e8488SAndroid Build Coastguard Worker * been consumed yet. This is an IN and OUT parameter.
250*5a6e8488SAndroid Build Coastguard Worker */
251*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_operator(BcParse * p,BcLexType type,size_t start,size_t * nexprs)252*5a6e8488SAndroid Build Coastguard Worker bc_parse_operator(BcParse* p, BcLexType type, size_t start, size_t* nexprs)
253*5a6e8488SAndroid Build Coastguard Worker {
254*5a6e8488SAndroid Build Coastguard Worker BcLexType t;
255*5a6e8488SAndroid Build Coastguard Worker uchar l, r = BC_PARSE_OP_PREC(type);
256*5a6e8488SAndroid Build Coastguard Worker uchar left = BC_PARSE_OP_LEFT(type);
257*5a6e8488SAndroid Build Coastguard Worker
258*5a6e8488SAndroid Build Coastguard Worker // While we haven't hit the stop point yet...
259*5a6e8488SAndroid Build Coastguard Worker while (p->ops.len > start)
260*5a6e8488SAndroid Build Coastguard Worker {
261*5a6e8488SAndroid Build Coastguard Worker // Get the top operator.
262*5a6e8488SAndroid Build Coastguard Worker t = BC_PARSE_TOP_OP(p);
263*5a6e8488SAndroid Build Coastguard Worker
264*5a6e8488SAndroid Build Coastguard Worker // If it's a left paren, we have reached the end of whatever expression
265*5a6e8488SAndroid Build Coastguard Worker // this is no matter what. We also don't pop the left paren because it
266*5a6e8488SAndroid Build Coastguard Worker // will need to stay for the rest of the subexpression.
267*5a6e8488SAndroid Build Coastguard Worker if (t == BC_LEX_LPAREN) break;
268*5a6e8488SAndroid Build Coastguard Worker
269*5a6e8488SAndroid Build Coastguard Worker // Break for precedence. Precedence operates differently on left and
270*5a6e8488SAndroid Build Coastguard Worker // right associativity, by the way. A left associative operator that
271*5a6e8488SAndroid Build Coastguard Worker // matches the current precedence should take priority, but a right
272*5a6e8488SAndroid Build Coastguard Worker // associative operator should not.
273*5a6e8488SAndroid Build Coastguard Worker //
274*5a6e8488SAndroid Build Coastguard Worker // Also, a lower precedence value means a higher precedence.
275*5a6e8488SAndroid Build Coastguard Worker l = BC_PARSE_OP_PREC(t);
276*5a6e8488SAndroid Build Coastguard Worker if (l >= r && (l != r || !left)) break;
277*5a6e8488SAndroid Build Coastguard Worker
278*5a6e8488SAndroid Build Coastguard Worker // Do the housekeeping. In particular, make sure to note that one
279*5a6e8488SAndroid Build Coastguard Worker // expression was consumed (well, two were, but another was added) if
280*5a6e8488SAndroid Build Coastguard Worker // the operator was not a prefix operator. (Postfix operators are not
281*5a6e8488SAndroid Build Coastguard Worker // handled by this function at all.)
282*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
283*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->ops);
284*5a6e8488SAndroid Build Coastguard Worker *nexprs -= !BC_PARSE_OP_PREFIX(t);
285*5a6e8488SAndroid Build Coastguard Worker }
286*5a6e8488SAndroid Build Coastguard Worker
287*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->ops, &type);
288*5a6e8488SAndroid Build Coastguard Worker }
289*5a6e8488SAndroid Build Coastguard Worker
290*5a6e8488SAndroid Build Coastguard Worker /**
291*5a6e8488SAndroid Build Coastguard Worker * Parses a right paren. In the Shunting-Yard algorithm, it needs to be put on
292*5a6e8488SAndroid Build Coastguard Worker * the operator stack. But before that, it needs to consume whatever operators
293*5a6e8488SAndroid Build Coastguard Worker * there are until it hits a left paren.
294*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
295*5a6e8488SAndroid Build Coastguard Worker * @param nexprs A pointer to the current number of expressions that have not
296*5a6e8488SAndroid Build Coastguard Worker * been consumed yet. This is an IN and OUT parameter.
297*5a6e8488SAndroid Build Coastguard Worker */
298*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_rightParen(BcParse * p,size_t * nexprs)299*5a6e8488SAndroid Build Coastguard Worker bc_parse_rightParen(BcParse* p, size_t* nexprs)
300*5a6e8488SAndroid Build Coastguard Worker {
301*5a6e8488SAndroid Build Coastguard Worker BcLexType top;
302*5a6e8488SAndroid Build Coastguard Worker
303*5a6e8488SAndroid Build Coastguard Worker // Consume operators until a left paren.
304*5a6e8488SAndroid Build Coastguard Worker while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN)
305*5a6e8488SAndroid Build Coastguard Worker {
306*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
307*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->ops);
308*5a6e8488SAndroid Build Coastguard Worker *nexprs -= !BC_PARSE_OP_PREFIX(top);
309*5a6e8488SAndroid Build Coastguard Worker }
310*5a6e8488SAndroid Build Coastguard Worker
311*5a6e8488SAndroid Build Coastguard Worker // We need to pop the left paren as well.
312*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->ops);
313*5a6e8488SAndroid Build Coastguard Worker
314*5a6e8488SAndroid Build Coastguard Worker // Oh, and we also want the next token.
315*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
316*5a6e8488SAndroid Build Coastguard Worker }
317*5a6e8488SAndroid Build Coastguard Worker
318*5a6e8488SAndroid Build Coastguard Worker /**
319*5a6e8488SAndroid Build Coastguard Worker * Parses function arguments.
320*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
321*5a6e8488SAndroid Build Coastguard Worker * @param flags Flags restricting what kind of expressions the arguments can
322*5a6e8488SAndroid Build Coastguard Worker * be.
323*5a6e8488SAndroid Build Coastguard Worker */
324*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_args(BcParse * p,uint8_t flags)325*5a6e8488SAndroid Build Coastguard Worker bc_parse_args(BcParse* p, uint8_t flags)
326*5a6e8488SAndroid Build Coastguard Worker {
327*5a6e8488SAndroid Build Coastguard Worker bool comma = false;
328*5a6e8488SAndroid Build Coastguard Worker size_t nargs;
329*5a6e8488SAndroid Build Coastguard Worker
330*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
331*5a6e8488SAndroid Build Coastguard Worker
332*5a6e8488SAndroid Build Coastguard Worker // Print and comparison operators not allowed. Well, comparison operators
333*5a6e8488SAndroid Build Coastguard Worker // only for POSIX. But we do allow arrays, and we *must* get a value.
334*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
335*5a6e8488SAndroid Build Coastguard Worker flags |= (BC_PARSE_ARRAY | BC_PARSE_NEEDVAL);
336*5a6e8488SAndroid Build Coastguard Worker
337*5a6e8488SAndroid Build Coastguard Worker // Count the arguments and parse them.
338*5a6e8488SAndroid Build Coastguard Worker for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs)
339*5a6e8488SAndroid Build Coastguard Worker {
340*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_arg);
341*5a6e8488SAndroid Build Coastguard Worker
342*5a6e8488SAndroid Build Coastguard Worker comma = (p->l.t == BC_LEX_COMMA);
343*5a6e8488SAndroid Build Coastguard Worker if (comma) bc_lex_next(&p->l);
344*5a6e8488SAndroid Build Coastguard Worker }
345*5a6e8488SAndroid Build Coastguard Worker
346*5a6e8488SAndroid Build Coastguard Worker // An ending comma is FAIL.
347*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
348*5a6e8488SAndroid Build Coastguard Worker
349*5a6e8488SAndroid Build Coastguard Worker // Now do the call with the number of arguments.
350*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_CALL);
351*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, nargs);
352*5a6e8488SAndroid Build Coastguard Worker }
353*5a6e8488SAndroid Build Coastguard Worker
354*5a6e8488SAndroid Build Coastguard Worker /**
355*5a6e8488SAndroid Build Coastguard Worker * Parses a function call.
356*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
357*5a6e8488SAndroid Build Coastguard Worker * @param flags Flags restricting what kind of expressions the arguments can
358*5a6e8488SAndroid Build Coastguard Worker * be.
359*5a6e8488SAndroid Build Coastguard Worker */
360*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_call(BcParse * p,const char * name,uint8_t flags)361*5a6e8488SAndroid Build Coastguard Worker bc_parse_call(BcParse* p, const char* name, uint8_t flags)
362*5a6e8488SAndroid Build Coastguard Worker {
363*5a6e8488SAndroid Build Coastguard Worker size_t idx;
364*5a6e8488SAndroid Build Coastguard Worker
365*5a6e8488SAndroid Build Coastguard Worker bc_parse_args(p, flags);
366*5a6e8488SAndroid Build Coastguard Worker
367*5a6e8488SAndroid Build Coastguard Worker // We just assert this because bc_parse_args() should
368*5a6e8488SAndroid Build Coastguard Worker // ensure that the next token is what it should be.
369*5a6e8488SAndroid Build Coastguard Worker assert(p->l.t == BC_LEX_RPAREN);
370*5a6e8488SAndroid Build Coastguard Worker
371*5a6e8488SAndroid Build Coastguard Worker // We cannot use bc_program_insertFunc() here
372*5a6e8488SAndroid Build Coastguard Worker // because it will overwrite an existing function.
373*5a6e8488SAndroid Build Coastguard Worker idx = bc_map_index(&p->prog->fn_map, name);
374*5a6e8488SAndroid Build Coastguard Worker
375*5a6e8488SAndroid Build Coastguard Worker // The function does not exist yet. Create a space for it. If the user does
376*5a6e8488SAndroid Build Coastguard Worker // not define it, it's a *runtime* error, not a parse error.
377*5a6e8488SAndroid Build Coastguard Worker if (idx == BC_VEC_INVALID_IDX)
378*5a6e8488SAndroid Build Coastguard Worker {
379*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_insertFunc(p->prog, name);
380*5a6e8488SAndroid Build Coastguard Worker
381*5a6e8488SAndroid Build Coastguard Worker assert(idx != BC_VEC_INVALID_IDX);
382*5a6e8488SAndroid Build Coastguard Worker
383*5a6e8488SAndroid Build Coastguard Worker // Make sure that this pointer was not invalidated.
384*5a6e8488SAndroid Build Coastguard Worker p->func = bc_vec_item(&p->prog->fns, p->fidx);
385*5a6e8488SAndroid Build Coastguard Worker }
386*5a6e8488SAndroid Build Coastguard Worker // The function exists, so set the right function index.
387*5a6e8488SAndroid Build Coastguard Worker else idx = ((BcId*) bc_vec_item(&p->prog->fn_map, idx))->idx;
388*5a6e8488SAndroid Build Coastguard Worker
389*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, idx);
390*5a6e8488SAndroid Build Coastguard Worker
391*5a6e8488SAndroid Build Coastguard Worker // Make sure to get the next token.
392*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
393*5a6e8488SAndroid Build Coastguard Worker }
394*5a6e8488SAndroid Build Coastguard Worker
395*5a6e8488SAndroid Build Coastguard Worker /**
396*5a6e8488SAndroid Build Coastguard Worker * Parses a name/identifier-based expression. It could be a variable, an array
397*5a6e8488SAndroid Build Coastguard Worker * element, an array itself (for function arguments), a function call, etc.
398*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
399*5a6e8488SAndroid Build Coastguard Worker * @param type A pointer to return the resulting instruction.
400*5a6e8488SAndroid Build Coastguard Worker * @param can_assign A pointer to return true if the name can be assigned to,
401*5a6e8488SAndroid Build Coastguard Worker * false otherwise.
402*5a6e8488SAndroid Build Coastguard Worker * @param flags Flags restricting what kind of expression the name can be.
403*5a6e8488SAndroid Build Coastguard Worker */
404*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_name(BcParse * p,BcInst * type,bool * can_assign,uint8_t flags)405*5a6e8488SAndroid Build Coastguard Worker bc_parse_name(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
406*5a6e8488SAndroid Build Coastguard Worker {
407*5a6e8488SAndroid Build Coastguard Worker char* name;
408*5a6e8488SAndroid Build Coastguard Worker
409*5a6e8488SAndroid Build Coastguard Worker BC_SIG_ASSERT_LOCKED;
410*5a6e8488SAndroid Build Coastguard Worker
411*5a6e8488SAndroid Build Coastguard Worker // We want a copy of the name since the lexer might overwrite its copy.
412*5a6e8488SAndroid Build Coastguard Worker name = bc_vm_strdup(p->l.str.v);
413*5a6e8488SAndroid Build Coastguard Worker
414*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, err);
415*5a6e8488SAndroid Build Coastguard Worker
416*5a6e8488SAndroid Build Coastguard Worker // We need the next token to see if it's just a variable or something more.
417*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
418*5a6e8488SAndroid Build Coastguard Worker
419*5a6e8488SAndroid Build Coastguard Worker // Array element or array.
420*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_LBRACKET)
421*5a6e8488SAndroid Build Coastguard Worker {
422*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
423*5a6e8488SAndroid Build Coastguard Worker
424*5a6e8488SAndroid Build Coastguard Worker // Array only. This has to be a function parameter.
425*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_RBRACKET)
426*5a6e8488SAndroid Build Coastguard Worker {
427*5a6e8488SAndroid Build Coastguard Worker // Error if arrays are not allowed.
428*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!(flags & BC_PARSE_ARRAY)))
429*5a6e8488SAndroid Build Coastguard Worker {
430*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
431*5a6e8488SAndroid Build Coastguard Worker }
432*5a6e8488SAndroid Build Coastguard Worker
433*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_ARRAY;
434*5a6e8488SAndroid Build Coastguard Worker *can_assign = false;
435*5a6e8488SAndroid Build Coastguard Worker }
436*5a6e8488SAndroid Build Coastguard Worker else
437*5a6e8488SAndroid Build Coastguard Worker {
438*5a6e8488SAndroid Build Coastguard Worker // If we are here, we have an array element. We need to set the
439*5a6e8488SAndroid Build Coastguard Worker // expression parsing flags.
440*5a6e8488SAndroid Build Coastguard Worker uint8_t flags2 = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) |
441*5a6e8488SAndroid Build Coastguard Worker BC_PARSE_NEEDVAL;
442*5a6e8488SAndroid Build Coastguard Worker
443*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags2, bc_parse_next_elem);
444*5a6e8488SAndroid Build Coastguard Worker
445*5a6e8488SAndroid Build Coastguard Worker // The next token *must* be a right bracket.
446*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
447*5a6e8488SAndroid Build Coastguard Worker {
448*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
449*5a6e8488SAndroid Build Coastguard Worker }
450*5a6e8488SAndroid Build Coastguard Worker
451*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_ARRAY_ELEM;
452*5a6e8488SAndroid Build Coastguard Worker *can_assign = true;
453*5a6e8488SAndroid Build Coastguard Worker }
454*5a6e8488SAndroid Build Coastguard Worker
455*5a6e8488SAndroid Build Coastguard Worker // Make sure to get the next token.
456*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
457*5a6e8488SAndroid Build Coastguard Worker
458*5a6e8488SAndroid Build Coastguard Worker // Push the instruction and the name of the identifier.
459*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, *type);
460*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushName(p, name, false);
461*5a6e8488SAndroid Build Coastguard Worker }
462*5a6e8488SAndroid Build Coastguard Worker else if (p->l.t == BC_LEX_LPAREN)
463*5a6e8488SAndroid Build Coastguard Worker {
464*5a6e8488SAndroid Build Coastguard Worker // We are parsing a function call; error if not allowed.
465*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(flags & BC_PARSE_NOCALL))
466*5a6e8488SAndroid Build Coastguard Worker {
467*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
468*5a6e8488SAndroid Build Coastguard Worker }
469*5a6e8488SAndroid Build Coastguard Worker
470*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_CALL;
471*5a6e8488SAndroid Build Coastguard Worker *can_assign = false;
472*5a6e8488SAndroid Build Coastguard Worker
473*5a6e8488SAndroid Build Coastguard Worker bc_parse_call(p, name, flags);
474*5a6e8488SAndroid Build Coastguard Worker }
475*5a6e8488SAndroid Build Coastguard Worker else
476*5a6e8488SAndroid Build Coastguard Worker {
477*5a6e8488SAndroid Build Coastguard Worker // Just a variable.
478*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_VAR;
479*5a6e8488SAndroid Build Coastguard Worker *can_assign = true;
480*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_VAR);
481*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushName(p, name, true);
482*5a6e8488SAndroid Build Coastguard Worker }
483*5a6e8488SAndroid Build Coastguard Worker
484*5a6e8488SAndroid Build Coastguard Worker err:
485*5a6e8488SAndroid Build Coastguard Worker // Need to make sure to unallocate the name.
486*5a6e8488SAndroid Build Coastguard Worker free(name);
487*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
488*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
489*5a6e8488SAndroid Build Coastguard Worker }
490*5a6e8488SAndroid Build Coastguard Worker
491*5a6e8488SAndroid Build Coastguard Worker /**
492*5a6e8488SAndroid Build Coastguard Worker * Parses a builtin function that takes no arguments. This includes read(),
493*5a6e8488SAndroid Build Coastguard Worker * rand(), maxibase(), maxobase(), maxscale(), and maxrand().
494*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
495*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction corresponding to the builtin.
496*5a6e8488SAndroid Build Coastguard Worker */
497*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_noArgBuiltin(BcParse * p,BcInst inst)498*5a6e8488SAndroid Build Coastguard Worker bc_parse_noArgBuiltin(BcParse* p, BcInst inst)
499*5a6e8488SAndroid Build Coastguard Worker {
500*5a6e8488SAndroid Build Coastguard Worker // Must have a left paren.
501*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
502*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
503*5a6e8488SAndroid Build Coastguard Worker
504*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
505*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
506*5a6e8488SAndroid Build Coastguard Worker if ((p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
507*5a6e8488SAndroid Build Coastguard Worker
508*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
509*5a6e8488SAndroid Build Coastguard Worker
510*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
511*5a6e8488SAndroid Build Coastguard Worker }
512*5a6e8488SAndroid Build Coastguard Worker
513*5a6e8488SAndroid Build Coastguard Worker /**
514*5a6e8488SAndroid Build Coastguard Worker * Parses a builtin function that takes 1 argument. This includes length(),
515*5a6e8488SAndroid Build Coastguard Worker * sqrt(), abs(), scale(), and irand().
516*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
517*5a6e8488SAndroid Build Coastguard Worker * @param type The lex token.
518*5a6e8488SAndroid Build Coastguard Worker * @param flags The expression parsing flags for parsing the argument.
519*5a6e8488SAndroid Build Coastguard Worker * @param prev An out parameter; the previous instruction pointer.
520*5a6e8488SAndroid Build Coastguard Worker */
521*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_builtin(BcParse * p,BcLexType type,uint8_t flags,BcInst * prev)522*5a6e8488SAndroid Build Coastguard Worker bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
523*5a6e8488SAndroid Build Coastguard Worker {
524*5a6e8488SAndroid Build Coastguard Worker // Must have a left paren.
525*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
526*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
527*5a6e8488SAndroid Build Coastguard Worker
528*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
529*5a6e8488SAndroid Build Coastguard Worker
530*5a6e8488SAndroid Build Coastguard Worker // Change the flags as needed for parsing the argument.
531*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
532*5a6e8488SAndroid Build Coastguard Worker flags |= BC_PARSE_NEEDVAL;
533*5a6e8488SAndroid Build Coastguard Worker
534*5a6e8488SAndroid Build Coastguard Worker // Since length can take arrays, we need to specially add that flag.
535*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY)
536*5a6e8488SAndroid Build Coastguard Worker {
537*5a6e8488SAndroid Build Coastguard Worker flags |= BC_PARSE_ARRAY;
538*5a6e8488SAndroid Build Coastguard Worker }
539*5a6e8488SAndroid Build Coastguard Worker
540*5a6e8488SAndroid Build Coastguard Worker // Otherwise, we need to clear it because it could be set.
541*5a6e8488SAndroid Build Coastguard Worker else flags &= ~(BC_PARSE_ARRAY);
542*5a6e8488SAndroid Build Coastguard Worker
543*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_rel);
544*5a6e8488SAndroid Build Coastguard Worker
545*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
546*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
547*5a6e8488SAndroid Build Coastguard Worker
548*5a6e8488SAndroid Build Coastguard Worker // Adjust previous based on the token and push it.
549*5a6e8488SAndroid Build Coastguard Worker *prev = type - BC_LEX_KW_LENGTH + BC_INST_LENGTH;
550*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, *prev);
551*5a6e8488SAndroid Build Coastguard Worker
552*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
553*5a6e8488SAndroid Build Coastguard Worker }
554*5a6e8488SAndroid Build Coastguard Worker
555*5a6e8488SAndroid Build Coastguard Worker /**
556*5a6e8488SAndroid Build Coastguard Worker * Parses a builtin function that takes 3 arguments. This includes modexp() and
557*5a6e8488SAndroid Build Coastguard Worker * divmod().
558*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
559*5a6e8488SAndroid Build Coastguard Worker * @param type The lex token.
560*5a6e8488SAndroid Build Coastguard Worker * @param flags The expression parsing flags for parsing the argument.
561*5a6e8488SAndroid Build Coastguard Worker * @param prev An out parameter; the previous instruction pointer.
562*5a6e8488SAndroid Build Coastguard Worker */
563*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_builtin3(BcParse * p,BcLexType type,uint8_t flags,BcInst * prev)564*5a6e8488SAndroid Build Coastguard Worker bc_parse_builtin3(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
565*5a6e8488SAndroid Build Coastguard Worker {
566*5a6e8488SAndroid Build Coastguard Worker assert(type == BC_LEX_KW_MODEXP || type == BC_LEX_KW_DIVMOD);
567*5a6e8488SAndroid Build Coastguard Worker
568*5a6e8488SAndroid Build Coastguard Worker // Must have a left paren.
569*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
570*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
571*5a6e8488SAndroid Build Coastguard Worker
572*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
573*5a6e8488SAndroid Build Coastguard Worker
574*5a6e8488SAndroid Build Coastguard Worker // Change the flags as needed for parsing the argument.
575*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
576*5a6e8488SAndroid Build Coastguard Worker flags |= BC_PARSE_NEEDVAL;
577*5a6e8488SAndroid Build Coastguard Worker
578*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_builtin);
579*5a6e8488SAndroid Build Coastguard Worker
580*5a6e8488SAndroid Build Coastguard Worker // Must have a comma.
581*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
582*5a6e8488SAndroid Build Coastguard Worker
583*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
584*5a6e8488SAndroid Build Coastguard Worker
585*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_builtin);
586*5a6e8488SAndroid Build Coastguard Worker
587*5a6e8488SAndroid Build Coastguard Worker // Must have a comma.
588*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
589*5a6e8488SAndroid Build Coastguard Worker
590*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
591*5a6e8488SAndroid Build Coastguard Worker
592*5a6e8488SAndroid Build Coastguard Worker // If it is a divmod, parse an array name. Otherwise, just parse another
593*5a6e8488SAndroid Build Coastguard Worker // expression.
594*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_KW_DIVMOD)
595*5a6e8488SAndroid Build Coastguard Worker {
596*5a6e8488SAndroid Build Coastguard Worker // Must have a name.
597*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
598*5a6e8488SAndroid Build Coastguard Worker
599*5a6e8488SAndroid Build Coastguard Worker // This is safe because the next token should not overwrite the name.
600*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
601*5a6e8488SAndroid Build Coastguard Worker
602*5a6e8488SAndroid Build Coastguard Worker // Must have a left bracket.
603*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LBRACKET))
604*5a6e8488SAndroid Build Coastguard Worker {
605*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
606*5a6e8488SAndroid Build Coastguard Worker }
607*5a6e8488SAndroid Build Coastguard Worker
608*5a6e8488SAndroid Build Coastguard Worker // This is safe because the next token should not overwrite the name.
609*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
610*5a6e8488SAndroid Build Coastguard Worker
611*5a6e8488SAndroid Build Coastguard Worker // Must have a right bracket.
612*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
613*5a6e8488SAndroid Build Coastguard Worker {
614*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
615*5a6e8488SAndroid Build Coastguard Worker }
616*5a6e8488SAndroid Build Coastguard Worker
617*5a6e8488SAndroid Build Coastguard Worker // This is safe because the next token should not overwrite the name.
618*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
619*5a6e8488SAndroid Build Coastguard Worker }
620*5a6e8488SAndroid Build Coastguard Worker else bc_parse_expr_status(p, flags, bc_parse_next_rel);
621*5a6e8488SAndroid Build Coastguard Worker
622*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
623*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
624*5a6e8488SAndroid Build Coastguard Worker
625*5a6e8488SAndroid Build Coastguard Worker // Adjust previous based on the token and push it.
626*5a6e8488SAndroid Build Coastguard Worker *prev = type - BC_LEX_KW_MODEXP + BC_INST_MODEXP;
627*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, *prev);
628*5a6e8488SAndroid Build Coastguard Worker
629*5a6e8488SAndroid Build Coastguard Worker // If we have divmod, we need to assign the modulus to the array element, so
630*5a6e8488SAndroid Build Coastguard Worker // we need to push the instructions for doing so.
631*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_KW_DIVMOD)
632*5a6e8488SAndroid Build Coastguard Worker {
633*5a6e8488SAndroid Build Coastguard Worker // The zeroth element.
634*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ZERO);
635*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ARRAY_ELEM);
636*5a6e8488SAndroid Build Coastguard Worker
637*5a6e8488SAndroid Build Coastguard Worker // Push the array.
638*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushName(p, p->l.str.v, false);
639*5a6e8488SAndroid Build Coastguard Worker
640*5a6e8488SAndroid Build Coastguard Worker // Swap them and assign. After this, the top item on the stack should
641*5a6e8488SAndroid Build Coastguard Worker // be the quotient.
642*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_SWAP);
643*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
644*5a6e8488SAndroid Build Coastguard Worker }
645*5a6e8488SAndroid Build Coastguard Worker
646*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
647*5a6e8488SAndroid Build Coastguard Worker }
648*5a6e8488SAndroid Build Coastguard Worker
649*5a6e8488SAndroid Build Coastguard Worker /**
650*5a6e8488SAndroid Build Coastguard Worker * Parses the scale keyword. This is special because scale can be a value or a
651*5a6e8488SAndroid Build Coastguard Worker * builtin function.
652*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
653*5a6e8488SAndroid Build Coastguard Worker * @param type An out parameter; the instruction for the parse.
654*5a6e8488SAndroid Build Coastguard Worker * @param can_assign An out parameter; whether the expression can be assigned
655*5a6e8488SAndroid Build Coastguard Worker * to.
656*5a6e8488SAndroid Build Coastguard Worker * @param flags The expression parsing flags for parsing a scale() arg.
657*5a6e8488SAndroid Build Coastguard Worker */
658*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_scale(BcParse * p,BcInst * type,bool * can_assign,uint8_t flags)659*5a6e8488SAndroid Build Coastguard Worker bc_parse_scale(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
660*5a6e8488SAndroid Build Coastguard Worker {
661*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
662*5a6e8488SAndroid Build Coastguard Worker
663*5a6e8488SAndroid Build Coastguard Worker // Without the left paren, it's just the keyword.
664*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_LPAREN)
665*5a6e8488SAndroid Build Coastguard Worker {
666*5a6e8488SAndroid Build Coastguard Worker // Set, push, and return.
667*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_SCALE;
668*5a6e8488SAndroid Build Coastguard Worker *can_assign = true;
669*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_SCALE);
670*5a6e8488SAndroid Build Coastguard Worker return;
671*5a6e8488SAndroid Build Coastguard Worker }
672*5a6e8488SAndroid Build Coastguard Worker
673*5a6e8488SAndroid Build Coastguard Worker // Handle the scale function.
674*5a6e8488SAndroid Build Coastguard Worker *type = BC_INST_SCALE_FUNC;
675*5a6e8488SAndroid Build Coastguard Worker *can_assign = false;
676*5a6e8488SAndroid Build Coastguard Worker
677*5a6e8488SAndroid Build Coastguard Worker // Once again, adjust the flags.
678*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
679*5a6e8488SAndroid Build Coastguard Worker flags |= BC_PARSE_NEEDVAL;
680*5a6e8488SAndroid Build Coastguard Worker
681*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
682*5a6e8488SAndroid Build Coastguard Worker
683*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_rel);
684*5a6e8488SAndroid Build Coastguard Worker
685*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
686*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
687*5a6e8488SAndroid Build Coastguard Worker
688*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_SCALE_FUNC);
689*5a6e8488SAndroid Build Coastguard Worker
690*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
691*5a6e8488SAndroid Build Coastguard Worker }
692*5a6e8488SAndroid Build Coastguard Worker
693*5a6e8488SAndroid Build Coastguard Worker /**
694*5a6e8488SAndroid Build Coastguard Worker * Parses and increment or decrement operator. This is a bit complex.
695*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
696*5a6e8488SAndroid Build Coastguard Worker * @param prev An out parameter; the previous instruction pointer.
697*5a6e8488SAndroid Build Coastguard Worker * @param can_assign An out parameter; whether the expression can be assigned
698*5a6e8488SAndroid Build Coastguard Worker * to.
699*5a6e8488SAndroid Build Coastguard Worker * @param nexs An in/out parameter; the number of expressions in the
700*5a6e8488SAndroid Build Coastguard Worker * parse tree that are not used.
701*5a6e8488SAndroid Build Coastguard Worker * @param flags The expression parsing flags for parsing a scale() arg.
702*5a6e8488SAndroid Build Coastguard Worker */
703*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_incdec(BcParse * p,BcInst * prev,bool * can_assign,size_t * nexs,uint8_t flags)704*5a6e8488SAndroid Build Coastguard Worker bc_parse_incdec(BcParse* p, BcInst* prev, bool* can_assign, size_t* nexs,
705*5a6e8488SAndroid Build Coastguard Worker uint8_t flags)
706*5a6e8488SAndroid Build Coastguard Worker {
707*5a6e8488SAndroid Build Coastguard Worker BcLexType type;
708*5a6e8488SAndroid Build Coastguard Worker uchar inst;
709*5a6e8488SAndroid Build Coastguard Worker BcInst etype = *prev;
710*5a6e8488SAndroid Build Coastguard Worker BcLexType last = p->l.last;
711*5a6e8488SAndroid Build Coastguard Worker
712*5a6e8488SAndroid Build Coastguard Worker assert(prev != NULL && can_assign != NULL);
713*5a6e8488SAndroid Build Coastguard Worker
714*5a6e8488SAndroid Build Coastguard Worker // If we can't assign to the previous token, then we have an error.
715*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC ||
716*5a6e8488SAndroid Build Coastguard Worker last == BC_LEX_RPAREN))
717*5a6e8488SAndroid Build Coastguard Worker {
718*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
719*5a6e8488SAndroid Build Coastguard Worker }
720*5a6e8488SAndroid Build Coastguard Worker
721*5a6e8488SAndroid Build Coastguard Worker // Is the previous instruction for a variable?
722*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_INST_VAR(etype))
723*5a6e8488SAndroid Build Coastguard Worker {
724*5a6e8488SAndroid Build Coastguard Worker // If so, this is a postfix operator.
725*5a6e8488SAndroid Build Coastguard Worker if (!*can_assign) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
726*5a6e8488SAndroid Build Coastguard Worker
727*5a6e8488SAndroid Build Coastguard Worker // Only postfix uses BC_INST_INC and BC_INST_DEC.
728*5a6e8488SAndroid Build Coastguard Worker *prev = inst = BC_INST_INC + (p->l.t != BC_LEX_OP_INC);
729*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
730*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
731*5a6e8488SAndroid Build Coastguard Worker *can_assign = false;
732*5a6e8488SAndroid Build Coastguard Worker }
733*5a6e8488SAndroid Build Coastguard Worker else
734*5a6e8488SAndroid Build Coastguard Worker {
735*5a6e8488SAndroid Build Coastguard Worker // This is a prefix operator. In that case, we just convert it to
736*5a6e8488SAndroid Build Coastguard Worker // an assignment instruction.
737*5a6e8488SAndroid Build Coastguard Worker *prev = inst = BC_INST_ASSIGN_PLUS + (p->l.t != BC_LEX_OP_INC);
738*5a6e8488SAndroid Build Coastguard Worker
739*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
740*5a6e8488SAndroid Build Coastguard Worker type = p->l.t;
741*5a6e8488SAndroid Build Coastguard Worker
742*5a6e8488SAndroid Build Coastguard Worker // Because we parse the next part of the expression
743*5a6e8488SAndroid Build Coastguard Worker // right here, we need to increment this.
744*5a6e8488SAndroid Build Coastguard Worker *nexs = *nexs + 1;
745*5a6e8488SAndroid Build Coastguard Worker
746*5a6e8488SAndroid Build Coastguard Worker // Is the next token a normal identifier?
747*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_NAME)
748*5a6e8488SAndroid Build Coastguard Worker {
749*5a6e8488SAndroid Build Coastguard Worker // Parse the name.
750*5a6e8488SAndroid Build Coastguard Worker uint8_t flags2 = flags & ~(BC_PARSE_ARRAY);
751*5a6e8488SAndroid Build Coastguard Worker bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
752*5a6e8488SAndroid Build Coastguard Worker }
753*5a6e8488SAndroid Build Coastguard Worker // Is the next token a global?
754*5a6e8488SAndroid Build Coastguard Worker else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE)
755*5a6e8488SAndroid Build Coastguard Worker {
756*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, type - BC_LEX_KW_LAST + BC_INST_LAST);
757*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
758*5a6e8488SAndroid Build Coastguard Worker }
759*5a6e8488SAndroid Build Coastguard Worker // Is the next token specifically scale, which needs special treatment?
760*5a6e8488SAndroid Build Coastguard Worker else if (BC_NO_ERR(type == BC_LEX_KW_SCALE))
761*5a6e8488SAndroid Build Coastguard Worker {
762*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
763*5a6e8488SAndroid Build Coastguard Worker
764*5a6e8488SAndroid Build Coastguard Worker // Check that scale() was not used.
765*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t == BC_LEX_LPAREN))
766*5a6e8488SAndroid Build Coastguard Worker {
767*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
768*5a6e8488SAndroid Build Coastguard Worker }
769*5a6e8488SAndroid Build Coastguard Worker else bc_parse_push(p, BC_INST_SCALE);
770*5a6e8488SAndroid Build Coastguard Worker }
771*5a6e8488SAndroid Build Coastguard Worker // Now we know we have an error.
772*5a6e8488SAndroid Build Coastguard Worker else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
773*5a6e8488SAndroid Build Coastguard Worker
774*5a6e8488SAndroid Build Coastguard Worker *can_assign = false;
775*5a6e8488SAndroid Build Coastguard Worker
776*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_ONE);
777*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
778*5a6e8488SAndroid Build Coastguard Worker }
779*5a6e8488SAndroid Build Coastguard Worker }
780*5a6e8488SAndroid Build Coastguard Worker
781*5a6e8488SAndroid Build Coastguard Worker /**
782*5a6e8488SAndroid Build Coastguard Worker * Parses the minus operator. This needs special treatment because it is either
783*5a6e8488SAndroid Build Coastguard Worker * subtract or negation.
784*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
785*5a6e8488SAndroid Build Coastguard Worker * @param prev An in/out parameter; the previous instruction.
786*5a6e8488SAndroid Build Coastguard Worker * @param ops_bgn The size of the operator stack.
787*5a6e8488SAndroid Build Coastguard Worker * @param rparen True if the last token was a right paren.
788*5a6e8488SAndroid Build Coastguard Worker * @param binlast True if the last token was a binary operator.
789*5a6e8488SAndroid Build Coastguard Worker * @param nexprs An in/out parameter; the number of unused expressions.
790*5a6e8488SAndroid Build Coastguard Worker */
791*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_minus(BcParse * p,BcInst * prev,size_t ops_bgn,bool rparen,bool binlast,size_t * nexprs)792*5a6e8488SAndroid Build Coastguard Worker bc_parse_minus(BcParse* p, BcInst* prev, size_t ops_bgn, bool rparen,
793*5a6e8488SAndroid Build Coastguard Worker bool binlast, size_t* nexprs)
794*5a6e8488SAndroid Build Coastguard Worker {
795*5a6e8488SAndroid Build Coastguard Worker BcLexType type;
796*5a6e8488SAndroid Build Coastguard Worker
797*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
798*5a6e8488SAndroid Build Coastguard Worker
799*5a6e8488SAndroid Build Coastguard Worker // Figure out if it's a minus or a negation.
800*5a6e8488SAndroid Build Coastguard Worker type = BC_PARSE_LEAF(*prev, binlast, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
801*5a6e8488SAndroid Build Coastguard Worker *prev = BC_PARSE_TOKEN_INST(type);
802*5a6e8488SAndroid Build Coastguard Worker
803*5a6e8488SAndroid Build Coastguard Worker // We can just push onto the op stack because this is the largest
804*5a6e8488SAndroid Build Coastguard Worker // precedence operator that gets pushed. Inc/dec does not.
805*5a6e8488SAndroid Build Coastguard Worker if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
806*5a6e8488SAndroid Build Coastguard Worker else bc_parse_operator(p, type, ops_bgn, nexprs);
807*5a6e8488SAndroid Build Coastguard Worker }
808*5a6e8488SAndroid Build Coastguard Worker
809*5a6e8488SAndroid Build Coastguard Worker /**
810*5a6e8488SAndroid Build Coastguard Worker * Parses a string.
811*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
812*5a6e8488SAndroid Build Coastguard Worker * @param inst The instruction corresponding to how the string was found and
813*5a6e8488SAndroid Build Coastguard Worker * how it should be printed.
814*5a6e8488SAndroid Build Coastguard Worker */
815*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_str(BcParse * p,BcInst inst)816*5a6e8488SAndroid Build Coastguard Worker bc_parse_str(BcParse* p, BcInst inst)
817*5a6e8488SAndroid Build Coastguard Worker {
818*5a6e8488SAndroid Build Coastguard Worker bc_parse_addString(p);
819*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
820*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
821*5a6e8488SAndroid Build Coastguard Worker }
822*5a6e8488SAndroid Build Coastguard Worker
823*5a6e8488SAndroid Build Coastguard Worker /**
824*5a6e8488SAndroid Build Coastguard Worker * Parses a print statement.
825*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
826*5a6e8488SAndroid Build Coastguard Worker */
827*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_print(BcParse * p,BcLexType type)828*5a6e8488SAndroid Build Coastguard Worker bc_parse_print(BcParse* p, BcLexType type)
829*5a6e8488SAndroid Build Coastguard Worker {
830*5a6e8488SAndroid Build Coastguard Worker BcLexType t;
831*5a6e8488SAndroid Build Coastguard Worker bool comma = false;
832*5a6e8488SAndroid Build Coastguard Worker BcInst inst = type == BC_LEX_KW_STREAM ? BC_INST_PRINT_STREAM :
833*5a6e8488SAndroid Build Coastguard Worker BC_INST_PRINT_POP;
834*5a6e8488SAndroid Build Coastguard Worker
835*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
836*5a6e8488SAndroid Build Coastguard Worker
837*5a6e8488SAndroid Build Coastguard Worker t = p->l.t;
838*5a6e8488SAndroid Build Coastguard Worker
839*5a6e8488SAndroid Build Coastguard Worker // A print or stream statement has to have *something*.
840*5a6e8488SAndroid Build Coastguard Worker if (bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_PRINT);
841*5a6e8488SAndroid Build Coastguard Worker
842*5a6e8488SAndroid Build Coastguard Worker do
843*5a6e8488SAndroid Build Coastguard Worker {
844*5a6e8488SAndroid Build Coastguard Worker // If the token is a string, then print it with escapes.
845*5a6e8488SAndroid Build Coastguard Worker // BC_INST_PRINT_POP plays that role for bc.
846*5a6e8488SAndroid Build Coastguard Worker if (t == BC_LEX_STR) bc_parse_str(p, inst);
847*5a6e8488SAndroid Build Coastguard Worker else
848*5a6e8488SAndroid Build Coastguard Worker {
849*5a6e8488SAndroid Build Coastguard Worker // We have an actual number; parse and add a print instruction.
850*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, BC_PARSE_NEEDVAL, bc_parse_next_print);
851*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
852*5a6e8488SAndroid Build Coastguard Worker }
853*5a6e8488SAndroid Build Coastguard Worker
854*5a6e8488SAndroid Build Coastguard Worker // Is the next token a comma?
855*5a6e8488SAndroid Build Coastguard Worker comma = (p->l.t == BC_LEX_COMMA);
856*5a6e8488SAndroid Build Coastguard Worker
857*5a6e8488SAndroid Build Coastguard Worker // Get the next token if we have a comma.
858*5a6e8488SAndroid Build Coastguard Worker if (comma) bc_lex_next(&p->l);
859*5a6e8488SAndroid Build Coastguard Worker else
860*5a6e8488SAndroid Build Coastguard Worker {
861*5a6e8488SAndroid Build Coastguard Worker // If we don't have a comma, the statement needs to end.
862*5a6e8488SAndroid Build Coastguard Worker if (!bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
863*5a6e8488SAndroid Build Coastguard Worker else break;
864*5a6e8488SAndroid Build Coastguard Worker }
865*5a6e8488SAndroid Build Coastguard Worker
866*5a6e8488SAndroid Build Coastguard Worker t = p->l.t;
867*5a6e8488SAndroid Build Coastguard Worker }
868*5a6e8488SAndroid Build Coastguard Worker while (true);
869*5a6e8488SAndroid Build Coastguard Worker
870*5a6e8488SAndroid Build Coastguard Worker // If we have a comma but no token, that's bad.
871*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
872*5a6e8488SAndroid Build Coastguard Worker }
873*5a6e8488SAndroid Build Coastguard Worker
874*5a6e8488SAndroid Build Coastguard Worker /**
875*5a6e8488SAndroid Build Coastguard Worker * Parses a return statement.
876*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
877*5a6e8488SAndroid Build Coastguard Worker */
878*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_return(BcParse * p)879*5a6e8488SAndroid Build Coastguard Worker bc_parse_return(BcParse* p)
880*5a6e8488SAndroid Build Coastguard Worker {
881*5a6e8488SAndroid Build Coastguard Worker BcLexType t;
882*5a6e8488SAndroid Build Coastguard Worker bool paren;
883*5a6e8488SAndroid Build Coastguard Worker uchar inst = BC_INST_RET0;
884*5a6e8488SAndroid Build Coastguard Worker
885*5a6e8488SAndroid Build Coastguard Worker // If we are not in a function, that's an error.
886*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PARSE_FUNC(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
887*5a6e8488SAndroid Build Coastguard Worker
888*5a6e8488SAndroid Build Coastguard Worker // If we are in a void function, make sure to return void.
889*5a6e8488SAndroid Build Coastguard Worker if (p->func->voidfn) inst = BC_INST_RET_VOID;
890*5a6e8488SAndroid Build Coastguard Worker
891*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
892*5a6e8488SAndroid Build Coastguard Worker
893*5a6e8488SAndroid Build Coastguard Worker t = p->l.t;
894*5a6e8488SAndroid Build Coastguard Worker paren = (t == BC_LEX_LPAREN);
895*5a6e8488SAndroid Build Coastguard Worker
896*5a6e8488SAndroid Build Coastguard Worker // An empty return statement just needs to push the selected instruction.
897*5a6e8488SAndroid Build Coastguard Worker if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
898*5a6e8488SAndroid Build Coastguard Worker else
899*5a6e8488SAndroid Build Coastguard Worker {
900*5a6e8488SAndroid Build Coastguard Worker BcParseStatus s;
901*5a6e8488SAndroid Build Coastguard Worker
902*5a6e8488SAndroid Build Coastguard Worker // Need to parse the expression whose value will be returned.
903*5a6e8488SAndroid Build Coastguard Worker s = bc_parse_expr_err(p, BC_PARSE_NEEDVAL, bc_parse_next_expr);
904*5a6e8488SAndroid Build Coastguard Worker
905*5a6e8488SAndroid Build Coastguard Worker // If the expression was empty, just push the selected instruction.
906*5a6e8488SAndroid Build Coastguard Worker if (s == BC_PARSE_STATUS_EMPTY_EXPR)
907*5a6e8488SAndroid Build Coastguard Worker {
908*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
909*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
910*5a6e8488SAndroid Build Coastguard Worker }
911*5a6e8488SAndroid Build Coastguard Worker
912*5a6e8488SAndroid Build Coastguard Worker // POSIX requires parentheses.
913*5a6e8488SAndroid Build Coastguard Worker if (!paren || p->l.last != BC_LEX_RPAREN)
914*5a6e8488SAndroid Build Coastguard Worker {
915*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_RET);
916*5a6e8488SAndroid Build Coastguard Worker }
917*5a6e8488SAndroid Build Coastguard Worker
918*5a6e8488SAndroid Build Coastguard Worker // Void functions require an empty expression.
919*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->func->voidfn))
920*5a6e8488SAndroid Build Coastguard Worker {
921*5a6e8488SAndroid Build Coastguard Worker if (s != BC_PARSE_STATUS_EMPTY_EXPR)
922*5a6e8488SAndroid Build Coastguard Worker {
923*5a6e8488SAndroid Build Coastguard Worker bc_parse_verr(p, BC_ERR_PARSE_RET_VOID, p->func->name);
924*5a6e8488SAndroid Build Coastguard Worker }
925*5a6e8488SAndroid Build Coastguard Worker }
926*5a6e8488SAndroid Build Coastguard Worker // If we got here, we want to be sure to end the function with a real
927*5a6e8488SAndroid Build Coastguard Worker // return instruction, just in case.
928*5a6e8488SAndroid Build Coastguard Worker else bc_parse_push(p, BC_INST_RET);
929*5a6e8488SAndroid Build Coastguard Worker }
930*5a6e8488SAndroid Build Coastguard Worker }
931*5a6e8488SAndroid Build Coastguard Worker
932*5a6e8488SAndroid Build Coastguard Worker /**
933*5a6e8488SAndroid Build Coastguard Worker * Clears flags that indicate the end of an if statement and its block and sets
934*5a6e8488SAndroid Build Coastguard Worker * the jump location.
935*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
936*5a6e8488SAndroid Build Coastguard Worker */
937*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_noElse(BcParse * p)938*5a6e8488SAndroid Build Coastguard Worker bc_parse_noElse(BcParse* p)
939*5a6e8488SAndroid Build Coastguard Worker {
940*5a6e8488SAndroid Build Coastguard Worker uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
941*5a6e8488SAndroid Build Coastguard Worker *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
942*5a6e8488SAndroid Build Coastguard Worker bc_parse_setLabel(p);
943*5a6e8488SAndroid Build Coastguard Worker }
944*5a6e8488SAndroid Build Coastguard Worker
945*5a6e8488SAndroid Build Coastguard Worker /**
946*5a6e8488SAndroid Build Coastguard Worker * Ends (finishes parsing) the body of a control statement or a function.
947*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
948*5a6e8488SAndroid Build Coastguard Worker * @param brace True if the body was ended by a brace, false otherwise.
949*5a6e8488SAndroid Build Coastguard Worker */
950*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_endBody(BcParse * p,bool brace)951*5a6e8488SAndroid Build Coastguard Worker bc_parse_endBody(BcParse* p, bool brace)
952*5a6e8488SAndroid Build Coastguard Worker {
953*5a6e8488SAndroid Build Coastguard Worker bool has_brace, new_else = false;
954*5a6e8488SAndroid Build Coastguard Worker
955*5a6e8488SAndroid Build Coastguard Worker // We cannot be ending a body if there are no bodies to end.
956*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->flags.len <= 1)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
957*5a6e8488SAndroid Build Coastguard Worker
958*5a6e8488SAndroid Build Coastguard Worker if (brace)
959*5a6e8488SAndroid Build Coastguard Worker {
960*5a6e8488SAndroid Build Coastguard Worker // The brace was already gotten; make sure that the caller did not lie.
961*5a6e8488SAndroid Build Coastguard Worker // We check for the requirement of braces later.
962*5a6e8488SAndroid Build Coastguard Worker assert(p->l.t == BC_LEX_RBRACE);
963*5a6e8488SAndroid Build Coastguard Worker
964*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
965*5a6e8488SAndroid Build Coastguard Worker
966*5a6e8488SAndroid Build Coastguard Worker // If the next token is not a delimiter, that is a problem.
967*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!bc_parse_isDelimiter(p) && !bc_parse_TopFunc(p)))
968*5a6e8488SAndroid Build Coastguard Worker {
969*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
970*5a6e8488SAndroid Build Coastguard Worker }
971*5a6e8488SAndroid Build Coastguard Worker }
972*5a6e8488SAndroid Build Coastguard Worker
973*5a6e8488SAndroid Build Coastguard Worker // Do we have a brace flag?
974*5a6e8488SAndroid Build Coastguard Worker has_brace = (BC_PARSE_BRACE(p) != 0);
975*5a6e8488SAndroid Build Coastguard Worker
976*5a6e8488SAndroid Build Coastguard Worker do
977*5a6e8488SAndroid Build Coastguard Worker {
978*5a6e8488SAndroid Build Coastguard Worker size_t len = p->flags.len;
979*5a6e8488SAndroid Build Coastguard Worker bool loop;
980*5a6e8488SAndroid Build Coastguard Worker
981*5a6e8488SAndroid Build Coastguard Worker // If we have a brace flag but not a brace, that's a problem.
982*5a6e8488SAndroid Build Coastguard Worker if (has_brace && !brace) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
983*5a6e8488SAndroid Build Coastguard Worker
984*5a6e8488SAndroid Build Coastguard Worker // Are we inside a loop?
985*5a6e8488SAndroid Build Coastguard Worker loop = (BC_PARSE_LOOP_INNER(p) != 0);
986*5a6e8488SAndroid Build Coastguard Worker
987*5a6e8488SAndroid Build Coastguard Worker // If we are ending a loop or an else...
988*5a6e8488SAndroid Build Coastguard Worker if (loop || BC_PARSE_ELSE(p))
989*5a6e8488SAndroid Build Coastguard Worker {
990*5a6e8488SAndroid Build Coastguard Worker // Loops have condition labels that we have to take care of as well.
991*5a6e8488SAndroid Build Coastguard Worker if (loop)
992*5a6e8488SAndroid Build Coastguard Worker {
993*5a6e8488SAndroid Build Coastguard Worker size_t* label = bc_vec_top(&p->conds);
994*5a6e8488SAndroid Build Coastguard Worker
995*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP);
996*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, *label);
997*5a6e8488SAndroid Build Coastguard Worker
998*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->conds);
999*5a6e8488SAndroid Build Coastguard Worker }
1000*5a6e8488SAndroid Build Coastguard Worker
1001*5a6e8488SAndroid Build Coastguard Worker bc_parse_setLabel(p);
1002*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->flags);
1003*5a6e8488SAndroid Build Coastguard Worker }
1004*5a6e8488SAndroid Build Coastguard Worker // If we are ending a function...
1005*5a6e8488SAndroid Build Coastguard Worker else if (BC_PARSE_FUNC_INNER(p))
1006*5a6e8488SAndroid Build Coastguard Worker {
1007*5a6e8488SAndroid Build Coastguard Worker BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
1008*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
1009*5a6e8488SAndroid Build Coastguard Worker bc_parse_updateFunc(p, BC_PROG_MAIN);
1010*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->flags);
1011*5a6e8488SAndroid Build Coastguard Worker }
1012*5a6e8488SAndroid Build Coastguard Worker // If we have a brace flag and not an if statement, we can pop the top
1013*5a6e8488SAndroid Build Coastguard Worker // of the flags stack because they have been taken care of above.
1014*5a6e8488SAndroid Build Coastguard Worker else if (has_brace && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
1015*5a6e8488SAndroid Build Coastguard Worker
1016*5a6e8488SAndroid Build Coastguard Worker // This needs to be last to parse nested if's properly.
1017*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p)))
1018*5a6e8488SAndroid Build Coastguard Worker {
1019*5a6e8488SAndroid Build Coastguard Worker // Eat newlines.
1020*5a6e8488SAndroid Build Coastguard Worker while (p->l.t == BC_LEX_NLINE)
1021*5a6e8488SAndroid Build Coastguard Worker {
1022*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1023*5a6e8488SAndroid Build Coastguard Worker }
1024*5a6e8488SAndroid Build Coastguard Worker
1025*5a6e8488SAndroid Build Coastguard Worker // *Now* we can pop the flags.
1026*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->flags);
1027*5a6e8488SAndroid Build Coastguard Worker
1028*5a6e8488SAndroid Build Coastguard Worker // If we are allowed non-POSIX stuff...
1029*5a6e8488SAndroid Build Coastguard Worker if (!BC_S)
1030*5a6e8488SAndroid Build Coastguard Worker {
1031*5a6e8488SAndroid Build Coastguard Worker // Have we found yet another dangling else?
1032*5a6e8488SAndroid Build Coastguard Worker *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
1033*5a6e8488SAndroid Build Coastguard Worker new_else = (p->l.t == BC_LEX_KW_ELSE);
1034*5a6e8488SAndroid Build Coastguard Worker
1035*5a6e8488SAndroid Build Coastguard Worker // Parse the else or end the if statement body.
1036*5a6e8488SAndroid Build Coastguard Worker if (new_else) bc_parse_else(p);
1037*5a6e8488SAndroid Build Coastguard Worker else if (!has_brace && (!BC_PARSE_IF_END(p) || brace))
1038*5a6e8488SAndroid Build Coastguard Worker {
1039*5a6e8488SAndroid Build Coastguard Worker bc_parse_noElse(p);
1040*5a6e8488SAndroid Build Coastguard Worker }
1041*5a6e8488SAndroid Build Coastguard Worker }
1042*5a6e8488SAndroid Build Coastguard Worker // POSIX requires us to do the bare minimum only.
1043*5a6e8488SAndroid Build Coastguard Worker else bc_parse_noElse(p);
1044*5a6e8488SAndroid Build Coastguard Worker }
1045*5a6e8488SAndroid Build Coastguard Worker
1046*5a6e8488SAndroid Build Coastguard Worker // If these are both true, we have "used" the braces that we found.
1047*5a6e8488SAndroid Build Coastguard Worker if (brace && has_brace) brace = false;
1048*5a6e8488SAndroid Build Coastguard Worker }
1049*5a6e8488SAndroid Build Coastguard Worker // This condition was perhaps the hardest single part of the parser. If
1050*5a6e8488SAndroid Build Coastguard Worker // the flags stack does not have enough, we should stop. If we have a
1051*5a6e8488SAndroid Build Coastguard Worker // new else statement, we should stop. If we do have the end of an if
1052*5a6e8488SAndroid Build Coastguard Worker // statement and we have eaten the brace, we should stop. If we do have
1053*5a6e8488SAndroid Build Coastguard Worker // a brace flag, we should stop.
1054*5a6e8488SAndroid Build Coastguard Worker while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
1055*5a6e8488SAndroid Build Coastguard Worker !(has_brace = (BC_PARSE_BRACE(p) != 0)));
1056*5a6e8488SAndroid Build Coastguard Worker
1057*5a6e8488SAndroid Build Coastguard Worker // If we have a brace, yet no body for it, that's a problem.
1058*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->flags.len == 1 && brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1059*5a6e8488SAndroid Build Coastguard Worker else if (brace && BC_PARSE_BRACE(p))
1060*5a6e8488SAndroid Build Coastguard Worker {
1061*5a6e8488SAndroid Build Coastguard Worker // If we make it here, we have a brace and a flag for it.
1062*5a6e8488SAndroid Build Coastguard Worker uint16_t flags = BC_PARSE_TOP_FLAG(p);
1063*5a6e8488SAndroid Build Coastguard Worker
1064*5a6e8488SAndroid Build Coastguard Worker // This condition ensure that the *last* body is correctly finished by
1065*5a6e8488SAndroid Build Coastguard Worker // popping its flags.
1066*5a6e8488SAndroid Build Coastguard Worker if (!(flags & (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_LOOP_INNER)) &&
1067*5a6e8488SAndroid Build Coastguard Worker !(flags & (BC_PARSE_FLAG_IF | BC_PARSE_FLAG_ELSE)) &&
1068*5a6e8488SAndroid Build Coastguard Worker !(flags & (BC_PARSE_FLAG_IF_END)))
1069*5a6e8488SAndroid Build Coastguard Worker {
1070*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->flags);
1071*5a6e8488SAndroid Build Coastguard Worker }
1072*5a6e8488SAndroid Build Coastguard Worker }
1073*5a6e8488SAndroid Build Coastguard Worker }
1074*5a6e8488SAndroid Build Coastguard Worker
1075*5a6e8488SAndroid Build Coastguard Worker /**
1076*5a6e8488SAndroid Build Coastguard Worker * Starts the body of a control statement or function.
1077*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1078*5a6e8488SAndroid Build Coastguard Worker * @param flags The current flags (will be edited).
1079*5a6e8488SAndroid Build Coastguard Worker */
1080*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_startBody(BcParse * p,uint16_t flags)1081*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(BcParse* p, uint16_t flags)
1082*5a6e8488SAndroid Build Coastguard Worker {
1083*5a6e8488SAndroid Build Coastguard Worker assert(flags);
1084*5a6e8488SAndroid Build Coastguard Worker flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
1085*5a6e8488SAndroid Build Coastguard Worker flags |= BC_PARSE_FLAG_BODY;
1086*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->flags, &flags);
1087*5a6e8488SAndroid Build Coastguard Worker }
1088*5a6e8488SAndroid Build Coastguard Worker
1089*5a6e8488SAndroid Build Coastguard Worker void
bc_parse_endif(BcParse * p)1090*5a6e8488SAndroid Build Coastguard Worker bc_parse_endif(BcParse* p)
1091*5a6e8488SAndroid Build Coastguard Worker {
1092*5a6e8488SAndroid Build Coastguard Worker size_t i;
1093*5a6e8488SAndroid Build Coastguard Worker bool good;
1094*5a6e8488SAndroid Build Coastguard Worker
1095*5a6e8488SAndroid Build Coastguard Worker // Not a problem if this is true.
1096*5a6e8488SAndroid Build Coastguard Worker if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
1097*5a6e8488SAndroid Build Coastguard Worker
1098*5a6e8488SAndroid Build Coastguard Worker good = true;
1099*5a6e8488SAndroid Build Coastguard Worker
1100*5a6e8488SAndroid Build Coastguard Worker // Find an instance of a body that needs closing, i.e., a statement that did
1101*5a6e8488SAndroid Build Coastguard Worker // not have a right brace when it should have.
1102*5a6e8488SAndroid Build Coastguard Worker for (i = 0; good && i < p->flags.len; ++i)
1103*5a6e8488SAndroid Build Coastguard Worker {
1104*5a6e8488SAndroid Build Coastguard Worker uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
1105*5a6e8488SAndroid Build Coastguard Worker good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
1106*5a6e8488SAndroid Build Coastguard Worker }
1107*5a6e8488SAndroid Build Coastguard Worker
1108*5a6e8488SAndroid Build Coastguard Worker // If we did not find such an instance...
1109*5a6e8488SAndroid Build Coastguard Worker if (good)
1110*5a6e8488SAndroid Build Coastguard Worker {
1111*5a6e8488SAndroid Build Coastguard Worker // We set this to restore it later. We don't want the parser thinking
1112*5a6e8488SAndroid Build Coastguard Worker // that we are on stdin for this one because it will want more.
1113*5a6e8488SAndroid Build Coastguard Worker BcMode mode = vm->mode;
1114*5a6e8488SAndroid Build Coastguard Worker
1115*5a6e8488SAndroid Build Coastguard Worker vm->mode = BC_MODE_FILE;
1116*5a6e8488SAndroid Build Coastguard Worker
1117*5a6e8488SAndroid Build Coastguard Worker // End all of the if statements and loops.
1118*5a6e8488SAndroid Build Coastguard Worker while (p->flags.len > 1 || BC_PARSE_IF_END(p))
1119*5a6e8488SAndroid Build Coastguard Worker {
1120*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
1121*5a6e8488SAndroid Build Coastguard Worker if (p->flags.len > 1) bc_parse_endBody(p, false);
1122*5a6e8488SAndroid Build Coastguard Worker }
1123*5a6e8488SAndroid Build Coastguard Worker
1124*5a6e8488SAndroid Build Coastguard Worker vm->mode = (uchar) mode;
1125*5a6e8488SAndroid Build Coastguard Worker }
1126*5a6e8488SAndroid Build Coastguard Worker // If we reach here, a block was not properly closed, and we should error.
1127*5a6e8488SAndroid Build Coastguard Worker else bc_parse_err(&vm->prs, BC_ERR_PARSE_BLOCK);
1128*5a6e8488SAndroid Build Coastguard Worker }
1129*5a6e8488SAndroid Build Coastguard Worker
1130*5a6e8488SAndroid Build Coastguard Worker /**
1131*5a6e8488SAndroid Build Coastguard Worker * Parses an if statement.
1132*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1133*5a6e8488SAndroid Build Coastguard Worker */
1134*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_if(BcParse * p)1135*5a6e8488SAndroid Build Coastguard Worker bc_parse_if(BcParse* p)
1136*5a6e8488SAndroid Build Coastguard Worker {
1137*5a6e8488SAndroid Build Coastguard Worker // We are allowed relational operators, and we must have a value.
1138*5a6e8488SAndroid Build Coastguard Worker size_t idx;
1139*5a6e8488SAndroid Build Coastguard Worker uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
1140*5a6e8488SAndroid Build Coastguard Worker
1141*5a6e8488SAndroid Build Coastguard Worker // Get the left paren and barf if necessary.
1142*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1143*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1144*5a6e8488SAndroid Build Coastguard Worker
1145*5a6e8488SAndroid Build Coastguard Worker // Parse the condition.
1146*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1147*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_rel);
1148*5a6e8488SAndroid Build Coastguard Worker
1149*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
1150*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1151*5a6e8488SAndroid Build Coastguard Worker
1152*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1153*5a6e8488SAndroid Build Coastguard Worker
1154*5a6e8488SAndroid Build Coastguard Worker // Insert the conditional jump instruction.
1155*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP_ZERO);
1156*5a6e8488SAndroid Build Coastguard Worker
1157*5a6e8488SAndroid Build Coastguard Worker idx = p->func->labels.len;
1158*5a6e8488SAndroid Build Coastguard Worker
1159*5a6e8488SAndroid Build Coastguard Worker // Push the index for the instruction and create an exit label for an else
1160*5a6e8488SAndroid Build Coastguard Worker // statement.
1161*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, idx);
1162*5a6e8488SAndroid Build Coastguard Worker bc_parse_createExitLabel(p, idx, false);
1163*5a6e8488SAndroid Build Coastguard Worker
1164*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, BC_PARSE_FLAG_IF);
1165*5a6e8488SAndroid Build Coastguard Worker }
1166*5a6e8488SAndroid Build Coastguard Worker
1167*5a6e8488SAndroid Build Coastguard Worker /**
1168*5a6e8488SAndroid Build Coastguard Worker * Parses an else statement.
1169*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1170*5a6e8488SAndroid Build Coastguard Worker */
1171*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_else(BcParse * p)1172*5a6e8488SAndroid Build Coastguard Worker bc_parse_else(BcParse* p)
1173*5a6e8488SAndroid Build Coastguard Worker {
1174*5a6e8488SAndroid Build Coastguard Worker size_t idx = p->func->labels.len;
1175*5a6e8488SAndroid Build Coastguard Worker
1176*5a6e8488SAndroid Build Coastguard Worker // We must be at the end of an if statement.
1177*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PARSE_IF_END(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1178*5a6e8488SAndroid Build Coastguard Worker
1179*5a6e8488SAndroid Build Coastguard Worker // Push an unconditional jump to make bc jump over the else statement if it
1180*5a6e8488SAndroid Build Coastguard Worker // executed the original if statement.
1181*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP);
1182*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, idx);
1183*5a6e8488SAndroid Build Coastguard Worker
1184*5a6e8488SAndroid Build Coastguard Worker // Clear the else stuff. Yes, that function is misnamed for its use here,
1185*5a6e8488SAndroid Build Coastguard Worker // but deal with it.
1186*5a6e8488SAndroid Build Coastguard Worker bc_parse_noElse(p);
1187*5a6e8488SAndroid Build Coastguard Worker
1188*5a6e8488SAndroid Build Coastguard Worker // Create the exit label and parse the body.
1189*5a6e8488SAndroid Build Coastguard Worker bc_parse_createExitLabel(p, idx, false);
1190*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
1191*5a6e8488SAndroid Build Coastguard Worker
1192*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1193*5a6e8488SAndroid Build Coastguard Worker }
1194*5a6e8488SAndroid Build Coastguard Worker
1195*5a6e8488SAndroid Build Coastguard Worker /**
1196*5a6e8488SAndroid Build Coastguard Worker * Parse a while loop.
1197*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1198*5a6e8488SAndroid Build Coastguard Worker */
1199*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_while(BcParse * p)1200*5a6e8488SAndroid Build Coastguard Worker bc_parse_while(BcParse* p)
1201*5a6e8488SAndroid Build Coastguard Worker {
1202*5a6e8488SAndroid Build Coastguard Worker // We are allowed relational operators, and we must have a value.
1203*5a6e8488SAndroid Build Coastguard Worker size_t idx;
1204*5a6e8488SAndroid Build Coastguard Worker uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
1205*5a6e8488SAndroid Build Coastguard Worker
1206*5a6e8488SAndroid Build Coastguard Worker // Get the left paren and barf if necessary.
1207*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1208*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1209*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1210*5a6e8488SAndroid Build Coastguard Worker
1211*5a6e8488SAndroid Build Coastguard Worker // Create the labels. Loops need both.
1212*5a6e8488SAndroid Build Coastguard Worker bc_parse_createCondLabel(p, p->func->labels.len);
1213*5a6e8488SAndroid Build Coastguard Worker idx = p->func->labels.len;
1214*5a6e8488SAndroid Build Coastguard Worker bc_parse_createExitLabel(p, idx, true);
1215*5a6e8488SAndroid Build Coastguard Worker
1216*5a6e8488SAndroid Build Coastguard Worker // Parse the actual condition and barf on non-right paren.
1217*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_rel);
1218*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1219*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1220*5a6e8488SAndroid Build Coastguard Worker
1221*5a6e8488SAndroid Build Coastguard Worker // Now we can push the conditional jump and start the body.
1222*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP_ZERO);
1223*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, idx);
1224*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
1225*5a6e8488SAndroid Build Coastguard Worker }
1226*5a6e8488SAndroid Build Coastguard Worker
1227*5a6e8488SAndroid Build Coastguard Worker /**
1228*5a6e8488SAndroid Build Coastguard Worker * Parse a for loop.
1229*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1230*5a6e8488SAndroid Build Coastguard Worker */
1231*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_for(BcParse * p)1232*5a6e8488SAndroid Build Coastguard Worker bc_parse_for(BcParse* p)
1233*5a6e8488SAndroid Build Coastguard Worker {
1234*5a6e8488SAndroid Build Coastguard Worker size_t cond_idx, exit_idx, body_idx, update_idx;
1235*5a6e8488SAndroid Build Coastguard Worker
1236*5a6e8488SAndroid Build Coastguard Worker // Barf on the missing left paren.
1237*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1238*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1239*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1240*5a6e8488SAndroid Build Coastguard Worker
1241*5a6e8488SAndroid Build Coastguard Worker // The first statement can be empty, but if it is, check for error in POSIX
1242*5a6e8488SAndroid Build Coastguard Worker // mode. Otherwise, parse it.
1243*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_SCOLON) bc_parse_expr_status(p, 0, bc_parse_next_for);
1244*5a6e8488SAndroid Build Coastguard Worker else bc_parse_err(p, BC_ERR_POSIX_FOR);
1245*5a6e8488SAndroid Build Coastguard Worker
1246*5a6e8488SAndroid Build Coastguard Worker // Must have a semicolon.
1247*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1248*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1249*5a6e8488SAndroid Build Coastguard Worker
1250*5a6e8488SAndroid Build Coastguard Worker // These are indices for labels. There are so many of them because the end
1251*5a6e8488SAndroid Build Coastguard Worker // of the loop must unconditionally jump to the update code. Then the update
1252*5a6e8488SAndroid Build Coastguard Worker // code must unconditionally jump to the condition code. Then the condition
1253*5a6e8488SAndroid Build Coastguard Worker // code must *conditionally* jump to the exit.
1254*5a6e8488SAndroid Build Coastguard Worker cond_idx = p->func->labels.len;
1255*5a6e8488SAndroid Build Coastguard Worker update_idx = cond_idx + 1;
1256*5a6e8488SAndroid Build Coastguard Worker body_idx = update_idx + 1;
1257*5a6e8488SAndroid Build Coastguard Worker exit_idx = body_idx + 1;
1258*5a6e8488SAndroid Build Coastguard Worker
1259*5a6e8488SAndroid Build Coastguard Worker // This creates the condition label.
1260*5a6e8488SAndroid Build Coastguard Worker bc_parse_createLabel(p, p->func->code.len);
1261*5a6e8488SAndroid Build Coastguard Worker
1262*5a6e8488SAndroid Build Coastguard Worker // Parse an expression if it exists.
1263*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_SCOLON)
1264*5a6e8488SAndroid Build Coastguard Worker {
1265*5a6e8488SAndroid Build Coastguard Worker uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
1266*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_for);
1267*5a6e8488SAndroid Build Coastguard Worker }
1268*5a6e8488SAndroid Build Coastguard Worker else
1269*5a6e8488SAndroid Build Coastguard Worker {
1270*5a6e8488SAndroid Build Coastguard Worker // Set this for the next call to bc_parse_number because an empty
1271*5a6e8488SAndroid Build Coastguard Worker // condition means that it is an infinite loop, so the condition must be
1272*5a6e8488SAndroid Build Coastguard Worker // non-zero. This is safe to set because the current token is a
1273*5a6e8488SAndroid Build Coastguard Worker // semicolon, which has no string requirement.
1274*5a6e8488SAndroid Build Coastguard Worker bc_vec_string(&p->l.str, sizeof(bc_parse_one) - 1, bc_parse_one);
1275*5a6e8488SAndroid Build Coastguard Worker bc_parse_number(p);
1276*5a6e8488SAndroid Build Coastguard Worker
1277*5a6e8488SAndroid Build Coastguard Worker // An empty condition makes POSIX mad.
1278*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_FOR);
1279*5a6e8488SAndroid Build Coastguard Worker }
1280*5a6e8488SAndroid Build Coastguard Worker
1281*5a6e8488SAndroid Build Coastguard Worker // Must have a semicolon.
1282*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1283*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1284*5a6e8488SAndroid Build Coastguard Worker
1285*5a6e8488SAndroid Build Coastguard Worker // Now we can set up the conditional jump to the exit and an unconditional
1286*5a6e8488SAndroid Build Coastguard Worker // jump to the body right after. The unconditional jump to the body is
1287*5a6e8488SAndroid Build Coastguard Worker // because there is update code coming right after the condition, so we need
1288*5a6e8488SAndroid Build Coastguard Worker // to skip it to get to the body.
1289*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP_ZERO);
1290*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, exit_idx);
1291*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP);
1292*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, body_idx);
1293*5a6e8488SAndroid Build Coastguard Worker
1294*5a6e8488SAndroid Build Coastguard Worker // Now create the label for the update code.
1295*5a6e8488SAndroid Build Coastguard Worker bc_parse_createCondLabel(p, update_idx);
1296*5a6e8488SAndroid Build Coastguard Worker
1297*5a6e8488SAndroid Build Coastguard Worker // Parse if not empty, and if it is, let POSIX yell if necessary.
1298*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_RPAREN) bc_parse_expr_status(p, 0, bc_parse_next_rel);
1299*5a6e8488SAndroid Build Coastguard Worker else bc_parse_err(p, BC_ERR_POSIX_FOR);
1300*5a6e8488SAndroid Build Coastguard Worker
1301*5a6e8488SAndroid Build Coastguard Worker // Must have a right paren.
1302*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1303*5a6e8488SAndroid Build Coastguard Worker
1304*5a6e8488SAndroid Build Coastguard Worker // Set up a jump to the condition right after the update code.
1305*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP);
1306*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, cond_idx);
1307*5a6e8488SAndroid Build Coastguard Worker bc_parse_createLabel(p, p->func->code.len);
1308*5a6e8488SAndroid Build Coastguard Worker
1309*5a6e8488SAndroid Build Coastguard Worker // Create an exit label for the body and start the body.
1310*5a6e8488SAndroid Build Coastguard Worker bc_parse_createExitLabel(p, exit_idx, true);
1311*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1312*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
1313*5a6e8488SAndroid Build Coastguard Worker }
1314*5a6e8488SAndroid Build Coastguard Worker
1315*5a6e8488SAndroid Build Coastguard Worker /**
1316*5a6e8488SAndroid Build Coastguard Worker * Parse a statement or token that indicates a loop exit. This includes an
1317*5a6e8488SAndroid Build Coastguard Worker * actual loop exit, the break keyword, or the continue keyword.
1318*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1319*5a6e8488SAndroid Build Coastguard Worker * @param type The type of exit.
1320*5a6e8488SAndroid Build Coastguard Worker */
1321*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_loopExit(BcParse * p,BcLexType type)1322*5a6e8488SAndroid Build Coastguard Worker bc_parse_loopExit(BcParse* p, BcLexType type)
1323*5a6e8488SAndroid Build Coastguard Worker {
1324*5a6e8488SAndroid Build Coastguard Worker size_t i;
1325*5a6e8488SAndroid Build Coastguard Worker BcInstPtr* ip;
1326*5a6e8488SAndroid Build Coastguard Worker
1327*5a6e8488SAndroid Build Coastguard Worker // Must have a loop. If we don't, that's an error.
1328*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PARSE_LOOP(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1329*5a6e8488SAndroid Build Coastguard Worker
1330*5a6e8488SAndroid Build Coastguard Worker // If we have a break statement...
1331*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_KW_BREAK)
1332*5a6e8488SAndroid Build Coastguard Worker {
1333*5a6e8488SAndroid Build Coastguard Worker // If there are no exits, something went wrong somewhere.
1334*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!p->exits.len)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1335*5a6e8488SAndroid Build Coastguard Worker
1336*5a6e8488SAndroid Build Coastguard Worker // Get the exit.
1337*5a6e8488SAndroid Build Coastguard Worker i = p->exits.len - 1;
1338*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_item(&p->exits, i);
1339*5a6e8488SAndroid Build Coastguard Worker
1340*5a6e8488SAndroid Build Coastguard Worker // The condition !ip->func is true if the exit is not for a loop, so we
1341*5a6e8488SAndroid Build Coastguard Worker // need to find the first actual loop exit.
1342*5a6e8488SAndroid Build Coastguard Worker while (!ip->func && i < p->exits.len)
1343*5a6e8488SAndroid Build Coastguard Worker {
1344*5a6e8488SAndroid Build Coastguard Worker ip = bc_vec_item(&p->exits, i);
1345*5a6e8488SAndroid Build Coastguard Worker i -= 1;
1346*5a6e8488SAndroid Build Coastguard Worker }
1347*5a6e8488SAndroid Build Coastguard Worker
1348*5a6e8488SAndroid Build Coastguard Worker // Make sure everything is hunky dory.
1349*5a6e8488SAndroid Build Coastguard Worker assert(ip != NULL && (i < p->exits.len || ip->func));
1350*5a6e8488SAndroid Build Coastguard Worker
1351*5a6e8488SAndroid Build Coastguard Worker // Set the index for the exit.
1352*5a6e8488SAndroid Build Coastguard Worker i = ip->idx;
1353*5a6e8488SAndroid Build Coastguard Worker }
1354*5a6e8488SAndroid Build Coastguard Worker // If we have a continue statement or just the loop end, jump to the
1355*5a6e8488SAndroid Build Coastguard Worker // condition (or update for a foor loop).
1356*5a6e8488SAndroid Build Coastguard Worker else i = *((size_t*) bc_vec_top(&p->conds));
1357*5a6e8488SAndroid Build Coastguard Worker
1358*5a6e8488SAndroid Build Coastguard Worker // Add the unconditional jump.
1359*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_JUMP);
1360*5a6e8488SAndroid Build Coastguard Worker bc_parse_pushIndex(p, i);
1361*5a6e8488SAndroid Build Coastguard Worker
1362*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1363*5a6e8488SAndroid Build Coastguard Worker }
1364*5a6e8488SAndroid Build Coastguard Worker
1365*5a6e8488SAndroid Build Coastguard Worker /**
1366*5a6e8488SAndroid Build Coastguard Worker * Parse a function (header).
1367*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1368*5a6e8488SAndroid Build Coastguard Worker */
1369*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_func(BcParse * p)1370*5a6e8488SAndroid Build Coastguard Worker bc_parse_func(BcParse* p)
1371*5a6e8488SAndroid Build Coastguard Worker {
1372*5a6e8488SAndroid Build Coastguard Worker bool comma = false, voidfn;
1373*5a6e8488SAndroid Build Coastguard Worker uint16_t flags;
1374*5a6e8488SAndroid Build Coastguard Worker size_t idx;
1375*5a6e8488SAndroid Build Coastguard Worker
1376*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1377*5a6e8488SAndroid Build Coastguard Worker
1378*5a6e8488SAndroid Build Coastguard Worker // Must have a name.
1379*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
1380*5a6e8488SAndroid Build Coastguard Worker
1381*5a6e8488SAndroid Build Coastguard Worker // If the name is "void", and POSIX is not on, mark as void.
1382*5a6e8488SAndroid Build Coastguard Worker voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME &&
1383*5a6e8488SAndroid Build Coastguard Worker !strcmp(p->l.str.v, "void"));
1384*5a6e8488SAndroid Build Coastguard Worker
1385*5a6e8488SAndroid Build Coastguard Worker // We can safely do this because the expected token should not overwrite the
1386*5a6e8488SAndroid Build Coastguard Worker // function name.
1387*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1388*5a6e8488SAndroid Build Coastguard Worker
1389*5a6e8488SAndroid Build Coastguard Worker // If we *don't* have another name, then void is the name of the function.
1390*5a6e8488SAndroid Build Coastguard Worker voidfn = (voidfn && p->l.t == BC_LEX_NAME);
1391*5a6e8488SAndroid Build Coastguard Worker
1392*5a6e8488SAndroid Build Coastguard Worker // With a void function, allow POSIX to complain and get a new token.
1393*5a6e8488SAndroid Build Coastguard Worker if (voidfn)
1394*5a6e8488SAndroid Build Coastguard Worker {
1395*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_VOID);
1396*5a6e8488SAndroid Build Coastguard Worker
1397*5a6e8488SAndroid Build Coastguard Worker // We can safely do this because the expected token should not overwrite
1398*5a6e8488SAndroid Build Coastguard Worker // the function name.
1399*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1400*5a6e8488SAndroid Build Coastguard Worker }
1401*5a6e8488SAndroid Build Coastguard Worker
1402*5a6e8488SAndroid Build Coastguard Worker // Must have a left paren.
1403*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
1404*5a6e8488SAndroid Build Coastguard Worker
1405*5a6e8488SAndroid Build Coastguard Worker // Make sure the functions map and vector are synchronized.
1406*5a6e8488SAndroid Build Coastguard Worker assert(p->prog->fns.len == p->prog->fn_map.len);
1407*5a6e8488SAndroid Build Coastguard Worker
1408*5a6e8488SAndroid Build Coastguard Worker // Insert the function by name into the map and vector.
1409*5a6e8488SAndroid Build Coastguard Worker idx = bc_program_insertFunc(p->prog, p->l.str.v);
1410*5a6e8488SAndroid Build Coastguard Worker
1411*5a6e8488SAndroid Build Coastguard Worker // Make sure the insert worked.
1412*5a6e8488SAndroid Build Coastguard Worker assert(idx);
1413*5a6e8488SAndroid Build Coastguard Worker
1414*5a6e8488SAndroid Build Coastguard Worker // Update the function pointer and stuff in the parser and set its void.
1415*5a6e8488SAndroid Build Coastguard Worker bc_parse_updateFunc(p, idx);
1416*5a6e8488SAndroid Build Coastguard Worker p->func->voidfn = voidfn;
1417*5a6e8488SAndroid Build Coastguard Worker
1418*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1419*5a6e8488SAndroid Build Coastguard Worker
1420*5a6e8488SAndroid Build Coastguard Worker // While we do not have a right paren, we are still parsing arguments.
1421*5a6e8488SAndroid Build Coastguard Worker while (p->l.t != BC_LEX_RPAREN)
1422*5a6e8488SAndroid Build Coastguard Worker {
1423*5a6e8488SAndroid Build Coastguard Worker BcType t = BC_TYPE_VAR;
1424*5a6e8488SAndroid Build Coastguard Worker
1425*5a6e8488SAndroid Build Coastguard Worker // If we have an asterisk, we are parsing a reference argument.
1426*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_OP_MULTIPLY)
1427*5a6e8488SAndroid Build Coastguard Worker {
1428*5a6e8488SAndroid Build Coastguard Worker t = BC_TYPE_REF;
1429*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1430*5a6e8488SAndroid Build Coastguard Worker
1431*5a6e8488SAndroid Build Coastguard Worker // Let POSIX complain if necessary.
1432*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_REF);
1433*5a6e8488SAndroid Build Coastguard Worker }
1434*5a6e8488SAndroid Build Coastguard Worker
1435*5a6e8488SAndroid Build Coastguard Worker // If we don't have a name, the argument will not have a name. Barf.
1436*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
1437*5a6e8488SAndroid Build Coastguard Worker
1438*5a6e8488SAndroid Build Coastguard Worker // Increment the number of parameters.
1439*5a6e8488SAndroid Build Coastguard Worker p->func->nparams += 1;
1440*5a6e8488SAndroid Build Coastguard Worker
1441*5a6e8488SAndroid Build Coastguard Worker // Copy the string in the lexer so that we can use the lexer again.
1442*5a6e8488SAndroid Build Coastguard Worker bc_vec_string(&p->buf, p->l.str.len, p->l.str.v);
1443*5a6e8488SAndroid Build Coastguard Worker
1444*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1445*5a6e8488SAndroid Build Coastguard Worker
1446*5a6e8488SAndroid Build Coastguard Worker // We are parsing an array parameter if this is true.
1447*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_LBRACKET)
1448*5a6e8488SAndroid Build Coastguard Worker {
1449*5a6e8488SAndroid Build Coastguard Worker // Set the array type, unless we are already parsing a reference.
1450*5a6e8488SAndroid Build Coastguard Worker if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
1451*5a6e8488SAndroid Build Coastguard Worker
1452*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1453*5a6e8488SAndroid Build Coastguard Worker
1454*5a6e8488SAndroid Build Coastguard Worker // The brackets *must* be empty.
1455*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
1456*5a6e8488SAndroid Build Coastguard Worker {
1457*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_FUNC);
1458*5a6e8488SAndroid Build Coastguard Worker }
1459*5a6e8488SAndroid Build Coastguard Worker
1460*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1461*5a6e8488SAndroid Build Coastguard Worker }
1462*5a6e8488SAndroid Build Coastguard Worker // If we did *not* get a bracket, but we are expecting a reference, we
1463*5a6e8488SAndroid Build Coastguard Worker // have a problem.
1464*5a6e8488SAndroid Build Coastguard Worker else if (BC_ERR(t == BC_TYPE_REF))
1465*5a6e8488SAndroid Build Coastguard Worker {
1466*5a6e8488SAndroid Build Coastguard Worker bc_parse_verr(p, BC_ERR_PARSE_REF_VAR, p->buf.v);
1467*5a6e8488SAndroid Build Coastguard Worker }
1468*5a6e8488SAndroid Build Coastguard Worker
1469*5a6e8488SAndroid Build Coastguard Worker // Test for comma and get the next token if it exists.
1470*5a6e8488SAndroid Build Coastguard Worker comma = (p->l.t == BC_LEX_COMMA);
1471*5a6e8488SAndroid Build Coastguard Worker if (comma) bc_lex_next(&p->l);
1472*5a6e8488SAndroid Build Coastguard Worker
1473*5a6e8488SAndroid Build Coastguard Worker // Insert the parameter into the function.
1474*5a6e8488SAndroid Build Coastguard Worker bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
1475*5a6e8488SAndroid Build Coastguard Worker }
1476*5a6e8488SAndroid Build Coastguard Worker
1477*5a6e8488SAndroid Build Coastguard Worker // If we have a comma, but no parameter, barf.
1478*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
1479*5a6e8488SAndroid Build Coastguard Worker
1480*5a6e8488SAndroid Build Coastguard Worker // Start the body.
1481*5a6e8488SAndroid Build Coastguard Worker flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER;
1482*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, flags);
1483*5a6e8488SAndroid Build Coastguard Worker
1484*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1485*5a6e8488SAndroid Build Coastguard Worker
1486*5a6e8488SAndroid Build Coastguard Worker // POSIX requires that a brace be on the same line as the function header.
1487*5a6e8488SAndroid Build Coastguard Worker // If we don't have a brace, let POSIX throw an error.
1488*5a6e8488SAndroid Build Coastguard Worker if (p->l.t != BC_LEX_LBRACE) bc_parse_err(p, BC_ERR_POSIX_BRACE);
1489*5a6e8488SAndroid Build Coastguard Worker }
1490*5a6e8488SAndroid Build Coastguard Worker
1491*5a6e8488SAndroid Build Coastguard Worker /**
1492*5a6e8488SAndroid Build Coastguard Worker * Parse an auto list.
1493*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1494*5a6e8488SAndroid Build Coastguard Worker */
1495*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_auto(BcParse * p)1496*5a6e8488SAndroid Build Coastguard Worker bc_parse_auto(BcParse* p)
1497*5a6e8488SAndroid Build Coastguard Worker {
1498*5a6e8488SAndroid Build Coastguard Worker bool comma, one;
1499*5a6e8488SAndroid Build Coastguard Worker
1500*5a6e8488SAndroid Build Coastguard Worker // Error if the auto keyword appeared in the wrong place.
1501*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!p->auto_part)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1502*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1503*5a6e8488SAndroid Build Coastguard Worker
1504*5a6e8488SAndroid Build Coastguard Worker p->auto_part = comma = false;
1505*5a6e8488SAndroid Build Coastguard Worker
1506*5a6e8488SAndroid Build Coastguard Worker // We need at least one variable or array.
1507*5a6e8488SAndroid Build Coastguard Worker one = (p->l.t == BC_LEX_NAME);
1508*5a6e8488SAndroid Build Coastguard Worker
1509*5a6e8488SAndroid Build Coastguard Worker // While we have a variable or array.
1510*5a6e8488SAndroid Build Coastguard Worker while (p->l.t == BC_LEX_NAME)
1511*5a6e8488SAndroid Build Coastguard Worker {
1512*5a6e8488SAndroid Build Coastguard Worker BcType t;
1513*5a6e8488SAndroid Build Coastguard Worker
1514*5a6e8488SAndroid Build Coastguard Worker // Copy the name from the lexer, so we can use it again.
1515*5a6e8488SAndroid Build Coastguard Worker bc_vec_string(&p->buf, p->l.str.len - 1, p->l.str.v);
1516*5a6e8488SAndroid Build Coastguard Worker
1517*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1518*5a6e8488SAndroid Build Coastguard Worker
1519*5a6e8488SAndroid Build Coastguard Worker // If we are parsing an array...
1520*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_LBRACKET)
1521*5a6e8488SAndroid Build Coastguard Worker {
1522*5a6e8488SAndroid Build Coastguard Worker t = BC_TYPE_ARRAY;
1523*5a6e8488SAndroid Build Coastguard Worker
1524*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1525*5a6e8488SAndroid Build Coastguard Worker
1526*5a6e8488SAndroid Build Coastguard Worker // The brackets *must* be empty.
1527*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
1528*5a6e8488SAndroid Build Coastguard Worker {
1529*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_FUNC);
1530*5a6e8488SAndroid Build Coastguard Worker }
1531*5a6e8488SAndroid Build Coastguard Worker
1532*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1533*5a6e8488SAndroid Build Coastguard Worker }
1534*5a6e8488SAndroid Build Coastguard Worker else t = BC_TYPE_VAR;
1535*5a6e8488SAndroid Build Coastguard Worker
1536*5a6e8488SAndroid Build Coastguard Worker // Test for comma and get the next token if it exists.
1537*5a6e8488SAndroid Build Coastguard Worker comma = (p->l.t == BC_LEX_COMMA);
1538*5a6e8488SAndroid Build Coastguard Worker if (comma) bc_lex_next(&p->l);
1539*5a6e8488SAndroid Build Coastguard Worker
1540*5a6e8488SAndroid Build Coastguard Worker // Insert the auto into the function.
1541*5a6e8488SAndroid Build Coastguard Worker bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
1542*5a6e8488SAndroid Build Coastguard Worker }
1543*5a6e8488SAndroid Build Coastguard Worker
1544*5a6e8488SAndroid Build Coastguard Worker // If we have a comma, but no auto, barf.
1545*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
1546*5a6e8488SAndroid Build Coastguard Worker
1547*5a6e8488SAndroid Build Coastguard Worker // If we don't have any variables or arrays, barf.
1548*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!one)) bc_parse_err(p, BC_ERR_PARSE_NO_AUTO);
1549*5a6e8488SAndroid Build Coastguard Worker
1550*5a6e8488SAndroid Build Coastguard Worker // The auto statement should be all that's in the statement.
1551*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!bc_parse_isDelimiter(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1552*5a6e8488SAndroid Build Coastguard Worker }
1553*5a6e8488SAndroid Build Coastguard Worker
1554*5a6e8488SAndroid Build Coastguard Worker /**
1555*5a6e8488SAndroid Build Coastguard Worker * Parses a body.
1556*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1557*5a6e8488SAndroid Build Coastguard Worker * @param brace True if a brace was encountered, false otherwise.
1558*5a6e8488SAndroid Build Coastguard Worker */
1559*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_body(BcParse * p,bool brace)1560*5a6e8488SAndroid Build Coastguard Worker bc_parse_body(BcParse* p, bool brace)
1561*5a6e8488SAndroid Build Coastguard Worker {
1562*5a6e8488SAndroid Build Coastguard Worker uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
1563*5a6e8488SAndroid Build Coastguard Worker
1564*5a6e8488SAndroid Build Coastguard Worker assert(flag_ptr != NULL);
1565*5a6e8488SAndroid Build Coastguard Worker assert(p->flags.len >= 2);
1566*5a6e8488SAndroid Build Coastguard Worker
1567*5a6e8488SAndroid Build Coastguard Worker // The body flag is for when we expect a body. We got a body, so clear the
1568*5a6e8488SAndroid Build Coastguard Worker // flag.
1569*5a6e8488SAndroid Build Coastguard Worker *flag_ptr &= ~(BC_PARSE_FLAG_BODY);
1570*5a6e8488SAndroid Build Coastguard Worker
1571*5a6e8488SAndroid Build Coastguard Worker // If we are inside a function, that means we just barely entered it, and
1572*5a6e8488SAndroid Build Coastguard Worker // we can expect an auto list.
1573*5a6e8488SAndroid Build Coastguard Worker if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER)
1574*5a6e8488SAndroid Build Coastguard Worker {
1575*5a6e8488SAndroid Build Coastguard Worker // We *must* have a brace in this case.
1576*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1577*5a6e8488SAndroid Build Coastguard Worker
1578*5a6e8488SAndroid Build Coastguard Worker p->auto_part = (p->l.t != BC_LEX_KW_AUTO);
1579*5a6e8488SAndroid Build Coastguard Worker
1580*5a6e8488SAndroid Build Coastguard Worker if (!p->auto_part)
1581*5a6e8488SAndroid Build Coastguard Worker {
1582*5a6e8488SAndroid Build Coastguard Worker // Make sure this is true to not get a parse error.
1583*5a6e8488SAndroid Build Coastguard Worker p->auto_part = true;
1584*5a6e8488SAndroid Build Coastguard Worker
1585*5a6e8488SAndroid Build Coastguard Worker // Since we already have the auto keyword, parse.
1586*5a6e8488SAndroid Build Coastguard Worker bc_parse_auto(p);
1587*5a6e8488SAndroid Build Coastguard Worker }
1588*5a6e8488SAndroid Build Coastguard Worker
1589*5a6e8488SAndroid Build Coastguard Worker // Eat a newline.
1590*5a6e8488SAndroid Build Coastguard Worker if (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
1591*5a6e8488SAndroid Build Coastguard Worker }
1592*5a6e8488SAndroid Build Coastguard Worker else
1593*5a6e8488SAndroid Build Coastguard Worker {
1594*5a6e8488SAndroid Build Coastguard Worker // This is the easy part.
1595*5a6e8488SAndroid Build Coastguard Worker size_t len = p->flags.len;
1596*5a6e8488SAndroid Build Coastguard Worker
1597*5a6e8488SAndroid Build Coastguard Worker assert(*flag_ptr);
1598*5a6e8488SAndroid Build Coastguard Worker
1599*5a6e8488SAndroid Build Coastguard Worker // Parse a statement.
1600*5a6e8488SAndroid Build Coastguard Worker bc_parse_stmt(p);
1601*5a6e8488SAndroid Build Coastguard Worker
1602*5a6e8488SAndroid Build Coastguard Worker // This is a very important condition to get right. If there is no
1603*5a6e8488SAndroid Build Coastguard Worker // brace, and no body flag, and the flags len hasn't shrunk, then we
1604*5a6e8488SAndroid Build Coastguard Worker // have a body that was not delimited by braces, so we need to end it
1605*5a6e8488SAndroid Build Coastguard Worker // now, after just one statement.
1606*5a6e8488SAndroid Build Coastguard Worker if (!brace && !BC_PARSE_BODY(p) && len <= p->flags.len)
1607*5a6e8488SAndroid Build Coastguard Worker {
1608*5a6e8488SAndroid Build Coastguard Worker bc_parse_endBody(p, false);
1609*5a6e8488SAndroid Build Coastguard Worker }
1610*5a6e8488SAndroid Build Coastguard Worker }
1611*5a6e8488SAndroid Build Coastguard Worker }
1612*5a6e8488SAndroid Build Coastguard Worker
1613*5a6e8488SAndroid Build Coastguard Worker /**
1614*5a6e8488SAndroid Build Coastguard Worker * Parses a statement. This is the entry point for just about everything, except
1615*5a6e8488SAndroid Build Coastguard Worker * function definitions.
1616*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1617*5a6e8488SAndroid Build Coastguard Worker */
1618*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_stmt(BcParse * p)1619*5a6e8488SAndroid Build Coastguard Worker bc_parse_stmt(BcParse* p)
1620*5a6e8488SAndroid Build Coastguard Worker {
1621*5a6e8488SAndroid Build Coastguard Worker size_t len;
1622*5a6e8488SAndroid Build Coastguard Worker uint16_t flags;
1623*5a6e8488SAndroid Build Coastguard Worker BcLexType type = p->l.t;
1624*5a6e8488SAndroid Build Coastguard Worker
1625*5a6e8488SAndroid Build Coastguard Worker // Eat newline.
1626*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_NLINE)
1627*5a6e8488SAndroid Build Coastguard Worker {
1628*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1629*5a6e8488SAndroid Build Coastguard Worker return;
1630*5a6e8488SAndroid Build Coastguard Worker }
1631*5a6e8488SAndroid Build Coastguard Worker
1632*5a6e8488SAndroid Build Coastguard Worker // Eat auto list.
1633*5a6e8488SAndroid Build Coastguard Worker if (type == BC_LEX_KW_AUTO)
1634*5a6e8488SAndroid Build Coastguard Worker {
1635*5a6e8488SAndroid Build Coastguard Worker bc_parse_auto(p);
1636*5a6e8488SAndroid Build Coastguard Worker return;
1637*5a6e8488SAndroid Build Coastguard Worker }
1638*5a6e8488SAndroid Build Coastguard Worker
1639*5a6e8488SAndroid Build Coastguard Worker // If we reach this point, no auto list is allowed.
1640*5a6e8488SAndroid Build Coastguard Worker p->auto_part = false;
1641*5a6e8488SAndroid Build Coastguard Worker
1642*5a6e8488SAndroid Build Coastguard Worker // Everything but an else needs to be taken care of here, but else is
1643*5a6e8488SAndroid Build Coastguard Worker // special.
1644*5a6e8488SAndroid Build Coastguard Worker if (type != BC_LEX_KW_ELSE)
1645*5a6e8488SAndroid Build Coastguard Worker {
1646*5a6e8488SAndroid Build Coastguard Worker // After an if, no else found.
1647*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_IF_END(p))
1648*5a6e8488SAndroid Build Coastguard Worker {
1649*5a6e8488SAndroid Build Coastguard Worker // Clear the expectation for else, end body, and return. Returning
1650*5a6e8488SAndroid Build Coastguard Worker // gives us a clean slate for parsing again.
1651*5a6e8488SAndroid Build Coastguard Worker bc_parse_noElse(p);
1652*5a6e8488SAndroid Build Coastguard Worker if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
1653*5a6e8488SAndroid Build Coastguard Worker {
1654*5a6e8488SAndroid Build Coastguard Worker bc_parse_endBody(p, false);
1655*5a6e8488SAndroid Build Coastguard Worker }
1656*5a6e8488SAndroid Build Coastguard Worker
1657*5a6e8488SAndroid Build Coastguard Worker return;
1658*5a6e8488SAndroid Build Coastguard Worker }
1659*5a6e8488SAndroid Build Coastguard Worker // With a left brace, we are parsing a body.
1660*5a6e8488SAndroid Build Coastguard Worker else if (type == BC_LEX_LBRACE)
1661*5a6e8488SAndroid Build Coastguard Worker {
1662*5a6e8488SAndroid Build Coastguard Worker // We need to start a body if we are not expecting one yet.
1663*5a6e8488SAndroid Build Coastguard Worker if (!BC_PARSE_BODY(p))
1664*5a6e8488SAndroid Build Coastguard Worker {
1665*5a6e8488SAndroid Build Coastguard Worker bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
1666*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1667*5a6e8488SAndroid Build Coastguard Worker }
1668*5a6e8488SAndroid Build Coastguard Worker // If we *are* expecting a body, that body should get a brace. This
1669*5a6e8488SAndroid Build Coastguard Worker // takes care of braces being on a different line than if and loop
1670*5a6e8488SAndroid Build Coastguard Worker // headers.
1671*5a6e8488SAndroid Build Coastguard Worker else
1672*5a6e8488SAndroid Build Coastguard Worker {
1673*5a6e8488SAndroid Build Coastguard Worker *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
1674*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1675*5a6e8488SAndroid Build Coastguard Worker bc_parse_body(p, true);
1676*5a6e8488SAndroid Build Coastguard Worker }
1677*5a6e8488SAndroid Build Coastguard Worker
1678*5a6e8488SAndroid Build Coastguard Worker // If we have reached this point, we need to return for a clean
1679*5a6e8488SAndroid Build Coastguard Worker // slate.
1680*5a6e8488SAndroid Build Coastguard Worker return;
1681*5a6e8488SAndroid Build Coastguard Worker }
1682*5a6e8488SAndroid Build Coastguard Worker // This happens when we are expecting a body and get a single statement,
1683*5a6e8488SAndroid Build Coastguard Worker // i.e., a body with no braces surrounding it. Returns after for a clean
1684*5a6e8488SAndroid Build Coastguard Worker // slate.
1685*5a6e8488SAndroid Build Coastguard Worker else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p))
1686*5a6e8488SAndroid Build Coastguard Worker {
1687*5a6e8488SAndroid Build Coastguard Worker bc_parse_body(p, false);
1688*5a6e8488SAndroid Build Coastguard Worker return;
1689*5a6e8488SAndroid Build Coastguard Worker }
1690*5a6e8488SAndroid Build Coastguard Worker }
1691*5a6e8488SAndroid Build Coastguard Worker
1692*5a6e8488SAndroid Build Coastguard Worker len = p->flags.len;
1693*5a6e8488SAndroid Build Coastguard Worker flags = BC_PARSE_TOP_FLAG(p);
1694*5a6e8488SAndroid Build Coastguard Worker
1695*5a6e8488SAndroid Build Coastguard Worker switch (type)
1696*5a6e8488SAndroid Build Coastguard Worker {
1697*5a6e8488SAndroid Build Coastguard Worker // All of these are valid for expressions.
1698*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_INC:
1699*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DEC:
1700*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MINUS:
1701*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_NOT:
1702*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LPAREN:
1703*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NAME:
1704*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NUMBER:
1705*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IBASE:
1706*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LAST:
1707*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LENGTH:
1708*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_OBASE:
1709*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SCALE:
1710*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1711*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SEED:
1712*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1713*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SQRT:
1714*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ABS:
1715*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_NUMBER:
1716*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_STRING:
1717*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1718*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IRAND:
1719*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1720*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ASCIIFY:
1721*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MODEXP:
1722*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DIVMOD:
1723*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_READ:
1724*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1725*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RAND:
1726*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1727*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXIBASE:
1728*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXOBASE:
1729*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXSCALE:
1730*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1731*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXRAND:
1732*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1733*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LINE_LENGTH:
1734*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_GLOBAL_STACKS:
1735*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LEADING_ZERO:
1736*5a6e8488SAndroid Build Coastguard Worker {
1737*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
1738*5a6e8488SAndroid Build Coastguard Worker break;
1739*5a6e8488SAndroid Build Coastguard Worker }
1740*5a6e8488SAndroid Build Coastguard Worker
1741*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ELSE:
1742*5a6e8488SAndroid Build Coastguard Worker {
1743*5a6e8488SAndroid Build Coastguard Worker bc_parse_else(p);
1744*5a6e8488SAndroid Build Coastguard Worker break;
1745*5a6e8488SAndroid Build Coastguard Worker }
1746*5a6e8488SAndroid Build Coastguard Worker
1747*5a6e8488SAndroid Build Coastguard Worker // Just eat.
1748*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCOLON:
1749*5a6e8488SAndroid Build Coastguard Worker {
1750*5a6e8488SAndroid Build Coastguard Worker // Do nothing.
1751*5a6e8488SAndroid Build Coastguard Worker break;
1752*5a6e8488SAndroid Build Coastguard Worker }
1753*5a6e8488SAndroid Build Coastguard Worker
1754*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACE:
1755*5a6e8488SAndroid Build Coastguard Worker {
1756*5a6e8488SAndroid Build Coastguard Worker bc_parse_endBody(p, true);
1757*5a6e8488SAndroid Build Coastguard Worker break;
1758*5a6e8488SAndroid Build Coastguard Worker }
1759*5a6e8488SAndroid Build Coastguard Worker
1760*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STR:
1761*5a6e8488SAndroid Build Coastguard Worker {
1762*5a6e8488SAndroid Build Coastguard Worker bc_parse_str(p, BC_INST_PRINT_STR);
1763*5a6e8488SAndroid Build Coastguard Worker break;
1764*5a6e8488SAndroid Build Coastguard Worker }
1765*5a6e8488SAndroid Build Coastguard Worker
1766*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_BREAK:
1767*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_CONTINUE:
1768*5a6e8488SAndroid Build Coastguard Worker {
1769*5a6e8488SAndroid Build Coastguard Worker bc_parse_loopExit(p, p->l.t);
1770*5a6e8488SAndroid Build Coastguard Worker break;
1771*5a6e8488SAndroid Build Coastguard Worker }
1772*5a6e8488SAndroid Build Coastguard Worker
1773*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_FOR:
1774*5a6e8488SAndroid Build Coastguard Worker {
1775*5a6e8488SAndroid Build Coastguard Worker bc_parse_for(p);
1776*5a6e8488SAndroid Build Coastguard Worker break;
1777*5a6e8488SAndroid Build Coastguard Worker }
1778*5a6e8488SAndroid Build Coastguard Worker
1779*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_HALT:
1780*5a6e8488SAndroid Build Coastguard Worker {
1781*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_HALT);
1782*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1783*5a6e8488SAndroid Build Coastguard Worker break;
1784*5a6e8488SAndroid Build Coastguard Worker }
1785*5a6e8488SAndroid Build Coastguard Worker
1786*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IF:
1787*5a6e8488SAndroid Build Coastguard Worker {
1788*5a6e8488SAndroid Build Coastguard Worker bc_parse_if(p);
1789*5a6e8488SAndroid Build Coastguard Worker break;
1790*5a6e8488SAndroid Build Coastguard Worker }
1791*5a6e8488SAndroid Build Coastguard Worker
1792*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LIMITS:
1793*5a6e8488SAndroid Build Coastguard Worker {
1794*5a6e8488SAndroid Build Coastguard Worker // `limits` is a compile-time command, so execute it right away.
1795*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_LONG_BIT = %lu\n", (ulong) BC_LONG_BIT);
1796*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_BASE_DIGS = %lu\n", (ulong) BC_BASE_DIGS);
1797*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_BASE_POW = %lu\n", (ulong) BC_BASE_POW);
1798*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_OVERFLOW_MAX = %lu\n", (ulong) BC_NUM_BIGDIG_MAX);
1799*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("\n");
1800*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_BASE_MAX = %lu\n", BC_MAX_OBASE);
1801*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_DIM_MAX = %lu\n", BC_MAX_DIM);
1802*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_SCALE_MAX = %lu\n", BC_MAX_SCALE);
1803*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_STRING_MAX = %lu\n", BC_MAX_STRING);
1804*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_NAME_MAX = %lu\n", BC_MAX_NAME);
1805*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_NUM_MAX = %lu\n", BC_MAX_NUM);
1806*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1807*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("BC_RAND_MAX = %lu\n", BC_MAX_RAND);
1808*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1809*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("MAX Exponent = %lu\n", BC_MAX_EXP);
1810*5a6e8488SAndroid Build Coastguard Worker bc_vm_printf("Number of vars = %lu\n", BC_MAX_VARS);
1811*5a6e8488SAndroid Build Coastguard Worker
1812*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1813*5a6e8488SAndroid Build Coastguard Worker
1814*5a6e8488SAndroid Build Coastguard Worker break;
1815*5a6e8488SAndroid Build Coastguard Worker }
1816*5a6e8488SAndroid Build Coastguard Worker
1817*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_STREAM:
1818*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_PRINT:
1819*5a6e8488SAndroid Build Coastguard Worker {
1820*5a6e8488SAndroid Build Coastguard Worker bc_parse_print(p, type);
1821*5a6e8488SAndroid Build Coastguard Worker break;
1822*5a6e8488SAndroid Build Coastguard Worker }
1823*5a6e8488SAndroid Build Coastguard Worker
1824*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_QUIT:
1825*5a6e8488SAndroid Build Coastguard Worker {
1826*5a6e8488SAndroid Build Coastguard Worker // Quit is a compile-time command. We don't exit directly, so the vm
1827*5a6e8488SAndroid Build Coastguard Worker // can clean up.
1828*5a6e8488SAndroid Build Coastguard Worker vm->status = BC_STATUS_QUIT;
1829*5a6e8488SAndroid Build Coastguard Worker BC_JMP;
1830*5a6e8488SAndroid Build Coastguard Worker break;
1831*5a6e8488SAndroid Build Coastguard Worker }
1832*5a6e8488SAndroid Build Coastguard Worker
1833*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RETURN:
1834*5a6e8488SAndroid Build Coastguard Worker {
1835*5a6e8488SAndroid Build Coastguard Worker bc_parse_return(p);
1836*5a6e8488SAndroid Build Coastguard Worker break;
1837*5a6e8488SAndroid Build Coastguard Worker }
1838*5a6e8488SAndroid Build Coastguard Worker
1839*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_WHILE:
1840*5a6e8488SAndroid Build Coastguard Worker {
1841*5a6e8488SAndroid Build Coastguard Worker bc_parse_while(p);
1842*5a6e8488SAndroid Build Coastguard Worker break;
1843*5a6e8488SAndroid Build Coastguard Worker }
1844*5a6e8488SAndroid Build Coastguard Worker
1845*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EOF:
1846*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_INVALID:
1847*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NEG:
1848*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1849*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_TRUNC:
1850*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1851*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_POWER:
1852*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MULTIPLY:
1853*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DIVIDE:
1854*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MODULUS:
1855*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLUS:
1856*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1857*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLACES:
1858*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_LSHIFT:
1859*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_RSHIFT:
1860*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1861*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_EQ:
1862*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LE:
1863*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GE:
1864*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_NE:
1865*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LT:
1866*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GT:
1867*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_OR:
1868*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_AND:
1869*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_POWER:
1870*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MULTIPLY:
1871*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_DIVIDE:
1872*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MODULUS:
1873*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLUS:
1874*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MINUS:
1875*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1876*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLACES:
1877*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_LSHIFT:
1878*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_RSHIFT:
1879*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1880*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN:
1881*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NLINE:
1882*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_WHITESPACE:
1883*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RPAREN:
1884*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACKET:
1885*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COMMA:
1886*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACKET:
1887*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACE:
1888*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_AUTO:
1889*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DEFINE:
1890*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
1891*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXTENDED_REGISTERS:
1892*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EQ_NO_REG:
1893*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COLON:
1894*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXECUTE:
1895*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_STACK:
1896*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_CLEAR_STACK:
1897*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_REG_STACK_LEVEL:
1898*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STACK_LEVEL:
1899*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_DUPLICATE:
1900*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SWAP:
1901*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_POP:
1902*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_IBASE:
1903*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_OBASE:
1904*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SCALE:
1905*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
1906*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SEED:
1907*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
1908*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD:
1909*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD_POP:
1910*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_PUSH:
1911*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_POP:
1912*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NQUIT:
1913*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXEC_STACK_LENGTH:
1914*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCALE_FACTOR:
1915*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_ARRAY_LENGTH:
1916*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
1917*5a6e8488SAndroid Build Coastguard Worker {
1918*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1919*5a6e8488SAndroid Build Coastguard Worker }
1920*5a6e8488SAndroid Build Coastguard Worker }
1921*5a6e8488SAndroid Build Coastguard Worker
1922*5a6e8488SAndroid Build Coastguard Worker // If the flags did not change, we expect a delimiter.
1923*5a6e8488SAndroid Build Coastguard Worker if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p))
1924*5a6e8488SAndroid Build Coastguard Worker {
1925*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!bc_parse_isDelimiter(p)))
1926*5a6e8488SAndroid Build Coastguard Worker {
1927*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1928*5a6e8488SAndroid Build Coastguard Worker }
1929*5a6e8488SAndroid Build Coastguard Worker }
1930*5a6e8488SAndroid Build Coastguard Worker
1931*5a6e8488SAndroid Build Coastguard Worker // Make sure semicolons are eaten.
1932*5a6e8488SAndroid Build Coastguard Worker while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE)
1933*5a6e8488SAndroid Build Coastguard Worker {
1934*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
1935*5a6e8488SAndroid Build Coastguard Worker }
1936*5a6e8488SAndroid Build Coastguard Worker
1937*5a6e8488SAndroid Build Coastguard Worker // POSIX's grammar does not allow a function definition after a semicolon
1938*5a6e8488SAndroid Build Coastguard Worker // without a newline, so check specifically for that case and error if
1939*5a6e8488SAndroid Build Coastguard Worker // the POSIX standard flag is set.
1940*5a6e8488SAndroid Build Coastguard Worker if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX)
1941*5a6e8488SAndroid Build Coastguard Worker {
1942*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON);
1943*5a6e8488SAndroid Build Coastguard Worker }
1944*5a6e8488SAndroid Build Coastguard Worker }
1945*5a6e8488SAndroid Build Coastguard Worker
1946*5a6e8488SAndroid Build Coastguard Worker void
bc_parse_parse(BcParse * p)1947*5a6e8488SAndroid Build Coastguard Worker bc_parse_parse(BcParse* p)
1948*5a6e8488SAndroid Build Coastguard Worker {
1949*5a6e8488SAndroid Build Coastguard Worker assert(p);
1950*5a6e8488SAndroid Build Coastguard Worker
1951*5a6e8488SAndroid Build Coastguard Worker BC_SETJMP_LOCKED(vm, exit);
1952*5a6e8488SAndroid Build Coastguard Worker
1953*5a6e8488SAndroid Build Coastguard Worker // We should not let an EOF get here unless some partial parse was not
1954*5a6e8488SAndroid Build Coastguard Worker // completed, in which case, it's the user's fault.
1955*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
1956*5a6e8488SAndroid Build Coastguard Worker
1957*5a6e8488SAndroid Build Coastguard Worker // Functions need special parsing.
1958*5a6e8488SAndroid Build Coastguard Worker else if (p->l.t == BC_LEX_KW_DEFINE)
1959*5a6e8488SAndroid Build Coastguard Worker {
1960*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_NO_EXEC(p)))
1961*5a6e8488SAndroid Build Coastguard Worker {
1962*5a6e8488SAndroid Build Coastguard Worker bc_parse_endif(p);
1963*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_NO_EXEC(p)))
1964*5a6e8488SAndroid Build Coastguard Worker {
1965*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1966*5a6e8488SAndroid Build Coastguard Worker }
1967*5a6e8488SAndroid Build Coastguard Worker }
1968*5a6e8488SAndroid Build Coastguard Worker bc_parse_func(p);
1969*5a6e8488SAndroid Build Coastguard Worker }
1970*5a6e8488SAndroid Build Coastguard Worker
1971*5a6e8488SAndroid Build Coastguard Worker // Otherwise, parse a normal statement.
1972*5a6e8488SAndroid Build Coastguard Worker else bc_parse_stmt(p);
1973*5a6e8488SAndroid Build Coastguard Worker
1974*5a6e8488SAndroid Build Coastguard Worker exit:
1975*5a6e8488SAndroid Build Coastguard Worker
1976*5a6e8488SAndroid Build Coastguard Worker // We need to reset on error.
1977*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(((vm->status && vm->status != BC_STATUS_QUIT) || vm->sig != 0)))
1978*5a6e8488SAndroid Build Coastguard Worker {
1979*5a6e8488SAndroid Build Coastguard Worker bc_parse_reset(p);
1980*5a6e8488SAndroid Build Coastguard Worker }
1981*5a6e8488SAndroid Build Coastguard Worker
1982*5a6e8488SAndroid Build Coastguard Worker BC_LONGJMP_CONT(vm);
1983*5a6e8488SAndroid Build Coastguard Worker BC_SIG_MAYLOCK;
1984*5a6e8488SAndroid Build Coastguard Worker }
1985*5a6e8488SAndroid Build Coastguard Worker
1986*5a6e8488SAndroid Build Coastguard Worker /**
1987*5a6e8488SAndroid Build Coastguard Worker * Parse an expression. This is the actual implementation of the Shunting-Yard
1988*5a6e8488SAndroid Build Coastguard Worker * Algorithm.
1989*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
1990*5a6e8488SAndroid Build Coastguard Worker * @param flags The flags for what is valid in the expression.
1991*5a6e8488SAndroid Build Coastguard Worker * @param next A set of tokens for what is valid *after* the expression.
1992*5a6e8488SAndroid Build Coastguard Worker * @return A parse status. In some places, an empty expression is an
1993*5a6e8488SAndroid Build Coastguard Worker * error, and sometimes, it is required. This allows this function
1994*5a6e8488SAndroid Build Coastguard Worker * to tell the caller if the expression was empty and let the
1995*5a6e8488SAndroid Build Coastguard Worker * caller handle it.
1996*5a6e8488SAndroid Build Coastguard Worker */
1997*5a6e8488SAndroid Build Coastguard Worker static BcParseStatus
bc_parse_expr_err(BcParse * p,uint8_t flags,BcParseNext next)1998*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next)
1999*5a6e8488SAndroid Build Coastguard Worker {
2000*5a6e8488SAndroid Build Coastguard Worker BcInst prev = BC_INST_PRINT;
2001*5a6e8488SAndroid Build Coastguard Worker uchar inst = BC_INST_INVALID;
2002*5a6e8488SAndroid Build Coastguard Worker BcLexType top, t;
2003*5a6e8488SAndroid Build Coastguard Worker size_t nexprs, ops_bgn;
2004*5a6e8488SAndroid Build Coastguard Worker uint32_t i, nparens, nrelops;
2005*5a6e8488SAndroid Build Coastguard Worker bool pfirst, rprn, array_last, done, get_token, assign;
2006*5a6e8488SAndroid Build Coastguard Worker bool bin_last, incdec, can_assign;
2007*5a6e8488SAndroid Build Coastguard Worker
2008*5a6e8488SAndroid Build Coastguard Worker // One of these *must* be true.
2009*5a6e8488SAndroid Build Coastguard Worker assert(!(flags & BC_PARSE_PRINT) || !(flags & BC_PARSE_NEEDVAL));
2010*5a6e8488SAndroid Build Coastguard Worker
2011*5a6e8488SAndroid Build Coastguard Worker // These are set very carefully. In fact, controlling the values of these
2012*5a6e8488SAndroid Build Coastguard Worker // locals is the biggest part of making this work. ops_bgn especially is
2013*5a6e8488SAndroid Build Coastguard Worker // important because it marks where the operator stack begins for *this*
2014*5a6e8488SAndroid Build Coastguard Worker // invocation of this function. That's because bc_parse_expr_err() is
2015*5a6e8488SAndroid Build Coastguard Worker // recursive (the Shunting-Yard Algorithm is most easily expressed
2016*5a6e8488SAndroid Build Coastguard Worker // recursively when parsing subexpressions), and each invocation needs to
2017*5a6e8488SAndroid Build Coastguard Worker // know where to stop.
2018*5a6e8488SAndroid Build Coastguard Worker //
2019*5a6e8488SAndroid Build Coastguard Worker // - nparens is the number of left parens without matches.
2020*5a6e8488SAndroid Build Coastguard Worker // - nrelops is the number of relational operators that appear in the expr.
2021*5a6e8488SAndroid Build Coastguard Worker // - nexprs is the number of unused expressions.
2022*5a6e8488SAndroid Build Coastguard Worker // - rprn is a right paren encountered last.
2023*5a6e8488SAndroid Build Coastguard Worker // - array_last is an array item encountered last.
2024*5a6e8488SAndroid Build Coastguard Worker // - done means the expression has been fully parsed.
2025*5a6e8488SAndroid Build Coastguard Worker // - get_token is true when a token is needed at the end of an iteration.
2026*5a6e8488SAndroid Build Coastguard Worker // - assign is true when an assignment statement was parsed last.
2027*5a6e8488SAndroid Build Coastguard Worker // - incdec is true when the previous operator was an inc or dec operator.
2028*5a6e8488SAndroid Build Coastguard Worker // - can_assign is true when an assignemnt is valid.
2029*5a6e8488SAndroid Build Coastguard Worker // - bin_last is true when the previous instruction was a binary operator.
2030*5a6e8488SAndroid Build Coastguard Worker t = p->l.t;
2031*5a6e8488SAndroid Build Coastguard Worker pfirst = (p->l.t == BC_LEX_LPAREN);
2032*5a6e8488SAndroid Build Coastguard Worker nparens = nrelops = 0;
2033*5a6e8488SAndroid Build Coastguard Worker nexprs = 0;
2034*5a6e8488SAndroid Build Coastguard Worker ops_bgn = p->ops.len;
2035*5a6e8488SAndroid Build Coastguard Worker rprn = array_last = done = get_token = assign = incdec = can_assign = false;
2036*5a6e8488SAndroid Build Coastguard Worker bin_last = true;
2037*5a6e8488SAndroid Build Coastguard Worker
2038*5a6e8488SAndroid Build Coastguard Worker // We want to eat newlines if newlines are not a valid ending token.
2039*5a6e8488SAndroid Build Coastguard Worker // This is for spacing in things like for loop headers.
2040*5a6e8488SAndroid Build Coastguard Worker if (!(flags & BC_PARSE_NOREAD))
2041*5a6e8488SAndroid Build Coastguard Worker {
2042*5a6e8488SAndroid Build Coastguard Worker while ((t = p->l.t) == BC_LEX_NLINE)
2043*5a6e8488SAndroid Build Coastguard Worker {
2044*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
2045*5a6e8488SAndroid Build Coastguard Worker }
2046*5a6e8488SAndroid Build Coastguard Worker }
2047*5a6e8488SAndroid Build Coastguard Worker
2048*5a6e8488SAndroid Build Coastguard Worker // This is the Shunting-Yard algorithm loop.
2049*5a6e8488SAndroid Build Coastguard Worker for (; !done && BC_PARSE_EXPR(t); t = p->l.t)
2050*5a6e8488SAndroid Build Coastguard Worker {
2051*5a6e8488SAndroid Build Coastguard Worker // Make sure an array expression is not mixed with any others. However,
2052*5a6e8488SAndroid Build Coastguard Worker // a right parenthesis may end the expression, so we will need to take
2053*5a6e8488SAndroid Build Coastguard Worker // care of that right there.
2054*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(array_last && t != BC_LEX_RPAREN))
2055*5a6e8488SAndroid Build Coastguard Worker {
2056*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2057*5a6e8488SAndroid Build Coastguard Worker }
2058*5a6e8488SAndroid Build Coastguard Worker
2059*5a6e8488SAndroid Build Coastguard Worker switch (t)
2060*5a6e8488SAndroid Build Coastguard Worker {
2061*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_INC:
2062*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DEC:
2063*5a6e8488SAndroid Build Coastguard Worker {
2064*5a6e8488SAndroid Build Coastguard Worker // These operators can only be used with items that can be
2065*5a6e8488SAndroid Build Coastguard Worker // assigned to.
2066*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(incdec)) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
2067*5a6e8488SAndroid Build Coastguard Worker
2068*5a6e8488SAndroid Build Coastguard Worker bc_parse_incdec(p, &prev, &can_assign, &nexprs, flags);
2069*5a6e8488SAndroid Build Coastguard Worker
2070*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = bin_last = false;
2071*5a6e8488SAndroid Build Coastguard Worker incdec = true;
2072*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2073*5a6e8488SAndroid Build Coastguard Worker
2074*5a6e8488SAndroid Build Coastguard Worker break;
2075*5a6e8488SAndroid Build Coastguard Worker }
2076*5a6e8488SAndroid Build Coastguard Worker
2077*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2078*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_TRUNC:
2079*5a6e8488SAndroid Build Coastguard Worker {
2080*5a6e8488SAndroid Build Coastguard Worker // The previous token must have been a leaf expression, or the
2081*5a6e8488SAndroid Build Coastguard Worker // operator is in the wrong place.
2082*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn)))
2083*5a6e8488SAndroid Build Coastguard Worker {
2084*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
2085*5a6e8488SAndroid Build Coastguard Worker }
2086*5a6e8488SAndroid Build Coastguard Worker
2087*5a6e8488SAndroid Build Coastguard Worker // I can just add the instruction because
2088*5a6e8488SAndroid Build Coastguard Worker // negative will already be taken care of.
2089*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_TRUNC);
2090*5a6e8488SAndroid Build Coastguard Worker
2091*5a6e8488SAndroid Build Coastguard Worker rprn = can_assign = incdec = false;
2092*5a6e8488SAndroid Build Coastguard Worker get_token = true;
2093*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2094*5a6e8488SAndroid Build Coastguard Worker
2095*5a6e8488SAndroid Build Coastguard Worker break;
2096*5a6e8488SAndroid Build Coastguard Worker }
2097*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2098*5a6e8488SAndroid Build Coastguard Worker
2099*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MINUS:
2100*5a6e8488SAndroid Build Coastguard Worker {
2101*5a6e8488SAndroid Build Coastguard Worker bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
2102*5a6e8488SAndroid Build Coastguard Worker
2103*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = can_assign = false;
2104*5a6e8488SAndroid Build Coastguard Worker
2105*5a6e8488SAndroid Build Coastguard Worker // This is true if it was a binary operator last.
2106*5a6e8488SAndroid Build Coastguard Worker bin_last = (prev == BC_INST_MINUS);
2107*5a6e8488SAndroid Build Coastguard Worker if (bin_last) incdec = false;
2108*5a6e8488SAndroid Build Coastguard Worker
2109*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2110*5a6e8488SAndroid Build Coastguard Worker
2111*5a6e8488SAndroid Build Coastguard Worker break;
2112*5a6e8488SAndroid Build Coastguard Worker }
2113*5a6e8488SAndroid Build Coastguard Worker
2114*5a6e8488SAndroid Build Coastguard Worker // All of this group, including the fallthrough, is to parse binary
2115*5a6e8488SAndroid Build Coastguard Worker // operators.
2116*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_POWER:
2117*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MULTIPLY:
2118*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_DIVIDE:
2119*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MODULUS:
2120*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLUS:
2121*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_MINUS:
2122*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2123*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_PLACES:
2124*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_LSHIFT:
2125*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN_RSHIFT:
2126*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2127*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_ASSIGN:
2128*5a6e8488SAndroid Build Coastguard Worker {
2129*5a6e8488SAndroid Build Coastguard Worker // We need to make sure the assignment is valid.
2130*5a6e8488SAndroid Build Coastguard Worker if (!BC_PARSE_INST_VAR(prev))
2131*5a6e8488SAndroid Build Coastguard Worker {
2132*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
2133*5a6e8488SAndroid Build Coastguard Worker }
2134*5a6e8488SAndroid Build Coastguard Worker
2135*5a6e8488SAndroid Build Coastguard Worker // Fallthrough.
2136*5a6e8488SAndroid Build Coastguard Worker BC_FALLTHROUGH
2137*5a6e8488SAndroid Build Coastguard Worker }
2138*5a6e8488SAndroid Build Coastguard Worker
2139*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_POWER:
2140*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MULTIPLY:
2141*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_DIVIDE:
2142*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_MODULUS:
2143*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLUS:
2144*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2145*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_PLACES:
2146*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_LSHIFT:
2147*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_RSHIFT:
2148*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2149*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_EQ:
2150*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LE:
2151*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GE:
2152*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_NE:
2153*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_LT:
2154*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_REL_GT:
2155*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_NOT:
2156*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_OR:
2157*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_OP_BOOL_AND:
2158*5a6e8488SAndroid Build Coastguard Worker {
2159*5a6e8488SAndroid Build Coastguard Worker // This is true if the operator if the token is a prefix
2160*5a6e8488SAndroid Build Coastguard Worker // operator. This is only for boolean not.
2161*5a6e8488SAndroid Build Coastguard Worker if (BC_PARSE_OP_PREFIX(t))
2162*5a6e8488SAndroid Build Coastguard Worker {
2163*5a6e8488SAndroid Build Coastguard Worker // Prefix operators are only allowed after binary operators
2164*5a6e8488SAndroid Build Coastguard Worker // or prefix operators.
2165*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last)))
2166*5a6e8488SAndroid Build Coastguard Worker {
2167*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2168*5a6e8488SAndroid Build Coastguard Worker }
2169*5a6e8488SAndroid Build Coastguard Worker }
2170*5a6e8488SAndroid Build Coastguard Worker // If we execute the else, that means we have a binary operator.
2171*5a6e8488SAndroid Build Coastguard Worker // If the previous operator was a prefix or a binary operator,
2172*5a6e8488SAndroid Build Coastguard Worker // then a binary operator is not allowed.
2173*5a6e8488SAndroid Build Coastguard Worker else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last))
2174*5a6e8488SAndroid Build Coastguard Worker {
2175*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2176*5a6e8488SAndroid Build Coastguard Worker }
2177*5a6e8488SAndroid Build Coastguard Worker
2178*5a6e8488SAndroid Build Coastguard Worker nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
2179*5a6e8488SAndroid Build Coastguard Worker prev = BC_PARSE_TOKEN_INST(t);
2180*5a6e8488SAndroid Build Coastguard Worker
2181*5a6e8488SAndroid Build Coastguard Worker bc_parse_operator(p, t, ops_bgn, &nexprs);
2182*5a6e8488SAndroid Build Coastguard Worker
2183*5a6e8488SAndroid Build Coastguard Worker rprn = incdec = can_assign = false;
2184*5a6e8488SAndroid Build Coastguard Worker get_token = true;
2185*5a6e8488SAndroid Build Coastguard Worker bin_last = !BC_PARSE_OP_PREFIX(t);
2186*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2187*5a6e8488SAndroid Build Coastguard Worker
2188*5a6e8488SAndroid Build Coastguard Worker break;
2189*5a6e8488SAndroid Build Coastguard Worker }
2190*5a6e8488SAndroid Build Coastguard Worker
2191*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LPAREN:
2192*5a6e8488SAndroid Build Coastguard Worker {
2193*5a6e8488SAndroid Build Coastguard Worker // A left paren is *not* allowed right after a leaf expr.
2194*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2195*5a6e8488SAndroid Build Coastguard Worker {
2196*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2197*5a6e8488SAndroid Build Coastguard Worker }
2198*5a6e8488SAndroid Build Coastguard Worker
2199*5a6e8488SAndroid Build Coastguard Worker nparens += 1;
2200*5a6e8488SAndroid Build Coastguard Worker rprn = incdec = can_assign = false;
2201*5a6e8488SAndroid Build Coastguard Worker get_token = true;
2202*5a6e8488SAndroid Build Coastguard Worker
2203*5a6e8488SAndroid Build Coastguard Worker // Push the paren onto the operator stack.
2204*5a6e8488SAndroid Build Coastguard Worker bc_vec_push(&p->ops, &t);
2205*5a6e8488SAndroid Build Coastguard Worker
2206*5a6e8488SAndroid Build Coastguard Worker break;
2207*5a6e8488SAndroid Build Coastguard Worker }
2208*5a6e8488SAndroid Build Coastguard Worker
2209*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RPAREN:
2210*5a6e8488SAndroid Build Coastguard Worker {
2211*5a6e8488SAndroid Build Coastguard Worker // This needs to be a status. The error is handled in
2212*5a6e8488SAndroid Build Coastguard Worker // bc_parse_expr_status().
2213*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(p->l.last == BC_LEX_LPAREN))
2214*5a6e8488SAndroid Build Coastguard Worker {
2215*5a6e8488SAndroid Build Coastguard Worker return BC_PARSE_STATUS_EMPTY_EXPR;
2216*5a6e8488SAndroid Build Coastguard Worker }
2217*5a6e8488SAndroid Build Coastguard Worker
2218*5a6e8488SAndroid Build Coastguard Worker // The right paren must not come after a prefix or binary
2219*5a6e8488SAndroid Build Coastguard Worker // operator.
2220*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev)))
2221*5a6e8488SAndroid Build Coastguard Worker {
2222*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2223*5a6e8488SAndroid Build Coastguard Worker }
2224*5a6e8488SAndroid Build Coastguard Worker
2225*5a6e8488SAndroid Build Coastguard Worker // If there are no parens left, we are done, but we need another
2226*5a6e8488SAndroid Build Coastguard Worker // token.
2227*5a6e8488SAndroid Build Coastguard Worker if (!nparens)
2228*5a6e8488SAndroid Build Coastguard Worker {
2229*5a6e8488SAndroid Build Coastguard Worker done = true;
2230*5a6e8488SAndroid Build Coastguard Worker get_token = false;
2231*5a6e8488SAndroid Build Coastguard Worker break;
2232*5a6e8488SAndroid Build Coastguard Worker }
2233*5a6e8488SAndroid Build Coastguard Worker
2234*5a6e8488SAndroid Build Coastguard Worker // Now that we know the right paren has not ended the
2235*5a6e8488SAndroid Build Coastguard Worker // expression, make sure an array expression is not mixed with
2236*5a6e8488SAndroid Build Coastguard Worker // any others.
2237*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(array_last))
2238*5a6e8488SAndroid Build Coastguard Worker {
2239*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2240*5a6e8488SAndroid Build Coastguard Worker }
2241*5a6e8488SAndroid Build Coastguard Worker
2242*5a6e8488SAndroid Build Coastguard Worker nparens -= 1;
2243*5a6e8488SAndroid Build Coastguard Worker rprn = true;
2244*5a6e8488SAndroid Build Coastguard Worker get_token = bin_last = incdec = false;
2245*5a6e8488SAndroid Build Coastguard Worker
2246*5a6e8488SAndroid Build Coastguard Worker bc_parse_rightParen(p, &nexprs);
2247*5a6e8488SAndroid Build Coastguard Worker
2248*5a6e8488SAndroid Build Coastguard Worker break;
2249*5a6e8488SAndroid Build Coastguard Worker }
2250*5a6e8488SAndroid Build Coastguard Worker
2251*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STR:
2252*5a6e8488SAndroid Build Coastguard Worker {
2253*5a6e8488SAndroid Build Coastguard Worker // POSIX only allows strings alone.
2254*5a6e8488SAndroid Build Coastguard Worker if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_EXPR_STRING);
2255*5a6e8488SAndroid Build Coastguard Worker
2256*5a6e8488SAndroid Build Coastguard Worker // A string is a leaf and cannot come right after a leaf.
2257*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2258*5a6e8488SAndroid Build Coastguard Worker {
2259*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2260*5a6e8488SAndroid Build Coastguard Worker }
2261*5a6e8488SAndroid Build Coastguard Worker
2262*5a6e8488SAndroid Build Coastguard Worker bc_parse_addString(p);
2263*5a6e8488SAndroid Build Coastguard Worker
2264*5a6e8488SAndroid Build Coastguard Worker get_token = true;
2265*5a6e8488SAndroid Build Coastguard Worker bin_last = rprn = false;
2266*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2267*5a6e8488SAndroid Build Coastguard Worker
2268*5a6e8488SAndroid Build Coastguard Worker break;
2269*5a6e8488SAndroid Build Coastguard Worker }
2270*5a6e8488SAndroid Build Coastguard Worker
2271*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NAME:
2272*5a6e8488SAndroid Build Coastguard Worker {
2273*5a6e8488SAndroid Build Coastguard Worker // A name is a leaf and cannot come right after a leaf.
2274*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2275*5a6e8488SAndroid Build Coastguard Worker {
2276*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2277*5a6e8488SAndroid Build Coastguard Worker }
2278*5a6e8488SAndroid Build Coastguard Worker
2279*5a6e8488SAndroid Build Coastguard Worker get_token = bin_last = false;
2280*5a6e8488SAndroid Build Coastguard Worker
2281*5a6e8488SAndroid Build Coastguard Worker bc_parse_name(p, &prev, &can_assign, flags & ~BC_PARSE_NOCALL);
2282*5a6e8488SAndroid Build Coastguard Worker
2283*5a6e8488SAndroid Build Coastguard Worker rprn = (prev == BC_INST_CALL);
2284*5a6e8488SAndroid Build Coastguard Worker array_last = (prev == BC_INST_ARRAY);
2285*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2286*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2287*5a6e8488SAndroid Build Coastguard Worker
2288*5a6e8488SAndroid Build Coastguard Worker break;
2289*5a6e8488SAndroid Build Coastguard Worker }
2290*5a6e8488SAndroid Build Coastguard Worker
2291*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NUMBER:
2292*5a6e8488SAndroid Build Coastguard Worker {
2293*5a6e8488SAndroid Build Coastguard Worker // A number is a leaf and cannot come right after a leaf.
2294*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2295*5a6e8488SAndroid Build Coastguard Worker {
2296*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2297*5a6e8488SAndroid Build Coastguard Worker }
2298*5a6e8488SAndroid Build Coastguard Worker
2299*5a6e8488SAndroid Build Coastguard Worker // The number instruction is pushed in here.
2300*5a6e8488SAndroid Build Coastguard Worker bc_parse_number(p);
2301*5a6e8488SAndroid Build Coastguard Worker
2302*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2303*5a6e8488SAndroid Build Coastguard Worker prev = BC_INST_NUM;
2304*5a6e8488SAndroid Build Coastguard Worker get_token = true;
2305*5a6e8488SAndroid Build Coastguard Worker rprn = bin_last = can_assign = false;
2306*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2307*5a6e8488SAndroid Build Coastguard Worker
2308*5a6e8488SAndroid Build Coastguard Worker break;
2309*5a6e8488SAndroid Build Coastguard Worker }
2310*5a6e8488SAndroid Build Coastguard Worker
2311*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IBASE:
2312*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LAST:
2313*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_OBASE:
2314*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2315*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SEED:
2316*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2317*5a6e8488SAndroid Build Coastguard Worker {
2318*5a6e8488SAndroid Build Coastguard Worker // All of these are leaves and cannot come right after a leaf.
2319*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2320*5a6e8488SAndroid Build Coastguard Worker {
2321*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2322*5a6e8488SAndroid Build Coastguard Worker }
2323*5a6e8488SAndroid Build Coastguard Worker
2324*5a6e8488SAndroid Build Coastguard Worker prev = t - BC_LEX_KW_LAST + BC_INST_LAST;
2325*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, prev);
2326*5a6e8488SAndroid Build Coastguard Worker
2327*5a6e8488SAndroid Build Coastguard Worker get_token = can_assign = true;
2328*5a6e8488SAndroid Build Coastguard Worker rprn = bin_last = false;
2329*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2330*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2331*5a6e8488SAndroid Build Coastguard Worker
2332*5a6e8488SAndroid Build Coastguard Worker break;
2333*5a6e8488SAndroid Build Coastguard Worker }
2334*5a6e8488SAndroid Build Coastguard Worker
2335*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LENGTH:
2336*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SQRT:
2337*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ABS:
2338*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_NUMBER:
2339*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IS_STRING:
2340*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2341*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IRAND:
2342*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2343*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ASCIIFY:
2344*5a6e8488SAndroid Build Coastguard Worker {
2345*5a6e8488SAndroid Build Coastguard Worker // All of these are leaves and cannot come right after a leaf.
2346*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2347*5a6e8488SAndroid Build Coastguard Worker {
2348*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2349*5a6e8488SAndroid Build Coastguard Worker }
2350*5a6e8488SAndroid Build Coastguard Worker
2351*5a6e8488SAndroid Build Coastguard Worker bc_parse_builtin(p, t, flags, &prev);
2352*5a6e8488SAndroid Build Coastguard Worker
2353*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = bin_last = incdec = can_assign = false;
2354*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2355*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2356*5a6e8488SAndroid Build Coastguard Worker
2357*5a6e8488SAndroid Build Coastguard Worker break;
2358*5a6e8488SAndroid Build Coastguard Worker }
2359*5a6e8488SAndroid Build Coastguard Worker
2360*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_READ:
2361*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2362*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RAND:
2363*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2364*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXIBASE:
2365*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXOBASE:
2366*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXSCALE:
2367*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2368*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MAXRAND:
2369*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2370*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LINE_LENGTH:
2371*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_GLOBAL_STACKS:
2372*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LEADING_ZERO:
2373*5a6e8488SAndroid Build Coastguard Worker {
2374*5a6e8488SAndroid Build Coastguard Worker // All of these are leaves and cannot come right after a leaf.
2375*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2376*5a6e8488SAndroid Build Coastguard Worker {
2377*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2378*5a6e8488SAndroid Build Coastguard Worker }
2379*5a6e8488SAndroid Build Coastguard Worker
2380*5a6e8488SAndroid Build Coastguard Worker // Error if we have read and it's not allowed.
2381*5a6e8488SAndroid Build Coastguard Worker else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD))
2382*5a6e8488SAndroid Build Coastguard Worker {
2383*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_EXEC_REC_READ);
2384*5a6e8488SAndroid Build Coastguard Worker }
2385*5a6e8488SAndroid Build Coastguard Worker
2386*5a6e8488SAndroid Build Coastguard Worker prev = t - BC_LEX_KW_READ + BC_INST_READ;
2387*5a6e8488SAndroid Build Coastguard Worker bc_parse_noArgBuiltin(p, prev);
2388*5a6e8488SAndroid Build Coastguard Worker
2389*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = bin_last = incdec = can_assign = false;
2390*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2391*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2392*5a6e8488SAndroid Build Coastguard Worker
2393*5a6e8488SAndroid Build Coastguard Worker break;
2394*5a6e8488SAndroid Build Coastguard Worker }
2395*5a6e8488SAndroid Build Coastguard Worker
2396*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_SCALE:
2397*5a6e8488SAndroid Build Coastguard Worker {
2398*5a6e8488SAndroid Build Coastguard Worker // This is a leaf and cannot come right after a leaf.
2399*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2400*5a6e8488SAndroid Build Coastguard Worker {
2401*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2402*5a6e8488SAndroid Build Coastguard Worker }
2403*5a6e8488SAndroid Build Coastguard Worker
2404*5a6e8488SAndroid Build Coastguard Worker // Scale needs special work because it can be a variable *or* a
2405*5a6e8488SAndroid Build Coastguard Worker // function.
2406*5a6e8488SAndroid Build Coastguard Worker bc_parse_scale(p, &prev, &can_assign, flags);
2407*5a6e8488SAndroid Build Coastguard Worker
2408*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = bin_last = false;
2409*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2410*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2411*5a6e8488SAndroid Build Coastguard Worker
2412*5a6e8488SAndroid Build Coastguard Worker break;
2413*5a6e8488SAndroid Build Coastguard Worker }
2414*5a6e8488SAndroid Build Coastguard Worker
2415*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_MODEXP:
2416*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DIVMOD:
2417*5a6e8488SAndroid Build Coastguard Worker {
2418*5a6e8488SAndroid Build Coastguard Worker // This is a leaf and cannot come right after a leaf.
2419*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
2420*5a6e8488SAndroid Build Coastguard Worker {
2421*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2422*5a6e8488SAndroid Build Coastguard Worker }
2423*5a6e8488SAndroid Build Coastguard Worker
2424*5a6e8488SAndroid Build Coastguard Worker bc_parse_builtin3(p, t, flags, &prev);
2425*5a6e8488SAndroid Build Coastguard Worker
2426*5a6e8488SAndroid Build Coastguard Worker rprn = get_token = bin_last = incdec = can_assign = false;
2427*5a6e8488SAndroid Build Coastguard Worker nexprs += 1;
2428*5a6e8488SAndroid Build Coastguard Worker flags &= ~(BC_PARSE_ARRAY);
2429*5a6e8488SAndroid Build Coastguard Worker
2430*5a6e8488SAndroid Build Coastguard Worker break;
2431*5a6e8488SAndroid Build Coastguard Worker }
2432*5a6e8488SAndroid Build Coastguard Worker
2433*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EOF:
2434*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_INVALID:
2435*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NEG:
2436*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NLINE:
2437*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_WHITESPACE:
2438*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACKET:
2439*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COMMA:
2440*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACKET:
2441*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LBRACE:
2442*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCOLON:
2443*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_RBRACE:
2444*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_AUTO:
2445*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_BREAK:
2446*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_CONTINUE:
2447*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_DEFINE:
2448*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_FOR:
2449*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_IF:
2450*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_LIMITS:
2451*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_RETURN:
2452*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_WHILE:
2453*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_HALT:
2454*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_PRINT:
2455*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_QUIT:
2456*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_STREAM:
2457*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_KW_ELSE:
2458*5a6e8488SAndroid Build Coastguard Worker #if DC_ENABLED
2459*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXTENDED_REGISTERS:
2460*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EQ_NO_REG:
2461*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_COLON:
2462*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXECUTE:
2463*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_STACK:
2464*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_CLEAR_STACK:
2465*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_REG_STACK_LEVEL:
2466*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STACK_LEVEL:
2467*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_DUPLICATE:
2468*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SWAP:
2469*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_POP:
2470*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_IBASE:
2471*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_OBASE:
2472*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SCALE:
2473*5a6e8488SAndroid Build Coastguard Worker #if BC_ENABLE_EXTRA_MATH
2474*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_SEED:
2475*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLE_EXTRA_MATH
2476*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD:
2477*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_LOAD_POP:
2478*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_STORE_PUSH:
2479*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_PRINT_POP:
2480*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_NQUIT:
2481*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_EXEC_STACK_LENGTH:
2482*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_SCALE_FACTOR:
2483*5a6e8488SAndroid Build Coastguard Worker case BC_LEX_ARRAY_LENGTH:
2484*5a6e8488SAndroid Build Coastguard Worker #endif // DC_ENABLED
2485*5a6e8488SAndroid Build Coastguard Worker {
2486*5a6e8488SAndroid Build Coastguard Worker #if BC_DEBUG
2487*5a6e8488SAndroid Build Coastguard Worker // We should never get here, even in debug builds.
2488*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_TOKEN);
2489*5a6e8488SAndroid Build Coastguard Worker break;
2490*5a6e8488SAndroid Build Coastguard Worker #endif // BC_DEBUG
2491*5a6e8488SAndroid Build Coastguard Worker }
2492*5a6e8488SAndroid Build Coastguard Worker }
2493*5a6e8488SAndroid Build Coastguard Worker
2494*5a6e8488SAndroid Build Coastguard Worker if (get_token) bc_lex_next(&p->l);
2495*5a6e8488SAndroid Build Coastguard Worker }
2496*5a6e8488SAndroid Build Coastguard Worker
2497*5a6e8488SAndroid Build Coastguard Worker // Now that we have parsed the expression, we need to empty the operator
2498*5a6e8488SAndroid Build Coastguard Worker // stack.
2499*5a6e8488SAndroid Build Coastguard Worker while (p->ops.len > ops_bgn)
2500*5a6e8488SAndroid Build Coastguard Worker {
2501*5a6e8488SAndroid Build Coastguard Worker top = BC_PARSE_TOP_OP(p);
2502*5a6e8488SAndroid Build Coastguard Worker assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
2503*5a6e8488SAndroid Build Coastguard Worker
2504*5a6e8488SAndroid Build Coastguard Worker // There should not be *any* parens on the stack anymore.
2505*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN))
2506*5a6e8488SAndroid Build Coastguard Worker {
2507*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2508*5a6e8488SAndroid Build Coastguard Worker }
2509*5a6e8488SAndroid Build Coastguard Worker
2510*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
2511*5a6e8488SAndroid Build Coastguard Worker
2512*5a6e8488SAndroid Build Coastguard Worker // Adjust the number of unused expressions.
2513*5a6e8488SAndroid Build Coastguard Worker nexprs -= !BC_PARSE_OP_PREFIX(top);
2514*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->ops);
2515*5a6e8488SAndroid Build Coastguard Worker
2516*5a6e8488SAndroid Build Coastguard Worker incdec = false;
2517*5a6e8488SAndroid Build Coastguard Worker }
2518*5a6e8488SAndroid Build Coastguard Worker
2519*5a6e8488SAndroid Build Coastguard Worker // There must be only one expression at the top.
2520*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR);
2521*5a6e8488SAndroid Build Coastguard Worker
2522*5a6e8488SAndroid Build Coastguard Worker // Check that the next token is correct.
2523*5a6e8488SAndroid Build Coastguard Worker for (i = 0; i < next.len && t != next.tokens[i]; ++i)
2524*5a6e8488SAndroid Build Coastguard Worker {
2525*5a6e8488SAndroid Build Coastguard Worker continue;
2526*5a6e8488SAndroid Build Coastguard Worker }
2527*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p)))
2528*5a6e8488SAndroid Build Coastguard Worker {
2529*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EXPR);
2530*5a6e8488SAndroid Build Coastguard Worker }
2531*5a6e8488SAndroid Build Coastguard Worker
2532*5a6e8488SAndroid Build Coastguard Worker // Check that POSIX would be happy with the number of relational operators.
2533*5a6e8488SAndroid Build Coastguard Worker if (!(flags & BC_PARSE_REL) && nrelops)
2534*5a6e8488SAndroid Build Coastguard Worker {
2535*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_REL_POS);
2536*5a6e8488SAndroid Build Coastguard Worker }
2537*5a6e8488SAndroid Build Coastguard Worker else if ((flags & BC_PARSE_REL) && nrelops > 1)
2538*5a6e8488SAndroid Build Coastguard Worker {
2539*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_POSIX_MULTIREL);
2540*5a6e8488SAndroid Build Coastguard Worker }
2541*5a6e8488SAndroid Build Coastguard Worker
2542*5a6e8488SAndroid Build Coastguard Worker // If this is true, then we might be in a situation where we don't print.
2543*5a6e8488SAndroid Build Coastguard Worker // We would want to have the increment/decrement operator not make an extra
2544*5a6e8488SAndroid Build Coastguard Worker // copy if it's not necessary.
2545*5a6e8488SAndroid Build Coastguard Worker if (!(flags & BC_PARSE_NEEDVAL) && !pfirst)
2546*5a6e8488SAndroid Build Coastguard Worker {
2547*5a6e8488SAndroid Build Coastguard Worker // We have the easy case if the last operator was an assignment
2548*5a6e8488SAndroid Build Coastguard Worker // operator.
2549*5a6e8488SAndroid Build Coastguard Worker if (assign)
2550*5a6e8488SAndroid Build Coastguard Worker {
2551*5a6e8488SAndroid Build Coastguard Worker inst = *((uchar*) bc_vec_top(&p->func->code));
2552*5a6e8488SAndroid Build Coastguard Worker inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
2553*5a6e8488SAndroid Build Coastguard Worker incdec = false;
2554*5a6e8488SAndroid Build Coastguard Worker }
2555*5a6e8488SAndroid Build Coastguard Worker // If we have an inc/dec operator and we are *not* printing, implement
2556*5a6e8488SAndroid Build Coastguard Worker // the optimization to get rid of the extra copy.
2557*5a6e8488SAndroid Build Coastguard Worker else if (incdec && !(flags & BC_PARSE_PRINT))
2558*5a6e8488SAndroid Build Coastguard Worker {
2559*5a6e8488SAndroid Build Coastguard Worker inst = *((uchar*) bc_vec_top(&p->func->code));
2560*5a6e8488SAndroid Build Coastguard Worker incdec = (inst <= BC_INST_DEC);
2561*5a6e8488SAndroid Build Coastguard Worker inst = BC_INST_ASSIGN_PLUS_NO_VAL +
2562*5a6e8488SAndroid Build Coastguard Worker (inst != BC_INST_INC && inst != BC_INST_ASSIGN_PLUS);
2563*5a6e8488SAndroid Build Coastguard Worker }
2564*5a6e8488SAndroid Build Coastguard Worker
2565*5a6e8488SAndroid Build Coastguard Worker // This condition allows us to change the previous assignment
2566*5a6e8488SAndroid Build Coastguard Worker // instruction (which does a copy) for a NO_VAL version, which does not.
2567*5a6e8488SAndroid Build Coastguard Worker // This condition is set if either of the above if statements ends up
2568*5a6e8488SAndroid Build Coastguard Worker // being true.
2569*5a6e8488SAndroid Build Coastguard Worker if (inst >= BC_INST_ASSIGN_POWER_NO_VAL &&
2570*5a6e8488SAndroid Build Coastguard Worker inst <= BC_INST_ASSIGN_NO_VAL)
2571*5a6e8488SAndroid Build Coastguard Worker {
2572*5a6e8488SAndroid Build Coastguard Worker // Pop the previous assignment instruction and push a new one.
2573*5a6e8488SAndroid Build Coastguard Worker // Inc/dec needs the extra instruction because it is now a binary
2574*5a6e8488SAndroid Build Coastguard Worker // operator and needs a second operand.
2575*5a6e8488SAndroid Build Coastguard Worker bc_vec_pop(&p->func->code);
2576*5a6e8488SAndroid Build Coastguard Worker if (incdec) bc_parse_push(p, BC_INST_ONE);
2577*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, inst);
2578*5a6e8488SAndroid Build Coastguard Worker }
2579*5a6e8488SAndroid Build Coastguard Worker }
2580*5a6e8488SAndroid Build Coastguard Worker
2581*5a6e8488SAndroid Build Coastguard Worker // If we might have to print...
2582*5a6e8488SAndroid Build Coastguard Worker if ((flags & BC_PARSE_PRINT))
2583*5a6e8488SAndroid Build Coastguard Worker {
2584*5a6e8488SAndroid Build Coastguard Worker // With a paren first or the last operator not being an assignment, we
2585*5a6e8488SAndroid Build Coastguard Worker // *do* want to print.
2586*5a6e8488SAndroid Build Coastguard Worker if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
2587*5a6e8488SAndroid Build Coastguard Worker }
2588*5a6e8488SAndroid Build Coastguard Worker // We need to make sure to push a pop instruction for assignment statements
2589*5a6e8488SAndroid Build Coastguard Worker // that will not print. The print will pop, but without it, we need to pop.
2590*5a6e8488SAndroid Build Coastguard Worker else if (!(flags & BC_PARSE_NEEDVAL) &&
2591*5a6e8488SAndroid Build Coastguard Worker (inst < BC_INST_ASSIGN_POWER_NO_VAL ||
2592*5a6e8488SAndroid Build Coastguard Worker inst > BC_INST_ASSIGN_NO_VAL))
2593*5a6e8488SAndroid Build Coastguard Worker {
2594*5a6e8488SAndroid Build Coastguard Worker bc_parse_push(p, BC_INST_POP);
2595*5a6e8488SAndroid Build Coastguard Worker }
2596*5a6e8488SAndroid Build Coastguard Worker
2597*5a6e8488SAndroid Build Coastguard Worker // We want to eat newlines if newlines are not a valid ending token.
2598*5a6e8488SAndroid Build Coastguard Worker // This is for spacing in things like for loop headers.
2599*5a6e8488SAndroid Build Coastguard Worker //
2600*5a6e8488SAndroid Build Coastguard Worker // Yes, this is one case where I reuse a variable for a different purpose;
2601*5a6e8488SAndroid Build Coastguard Worker // in this case, incdec being true now means that newlines are not valid.
2602*5a6e8488SAndroid Build Coastguard Worker for (incdec = true, i = 0; i < next.len && incdec; ++i)
2603*5a6e8488SAndroid Build Coastguard Worker {
2604*5a6e8488SAndroid Build Coastguard Worker incdec = (next.tokens[i] != BC_LEX_NLINE);
2605*5a6e8488SAndroid Build Coastguard Worker }
2606*5a6e8488SAndroid Build Coastguard Worker if (incdec)
2607*5a6e8488SAndroid Build Coastguard Worker {
2608*5a6e8488SAndroid Build Coastguard Worker while (p->l.t == BC_LEX_NLINE)
2609*5a6e8488SAndroid Build Coastguard Worker {
2610*5a6e8488SAndroid Build Coastguard Worker bc_lex_next(&p->l);
2611*5a6e8488SAndroid Build Coastguard Worker }
2612*5a6e8488SAndroid Build Coastguard Worker }
2613*5a6e8488SAndroid Build Coastguard Worker
2614*5a6e8488SAndroid Build Coastguard Worker return BC_PARSE_STATUS_SUCCESS;
2615*5a6e8488SAndroid Build Coastguard Worker }
2616*5a6e8488SAndroid Build Coastguard Worker
2617*5a6e8488SAndroid Build Coastguard Worker /**
2618*5a6e8488SAndroid Build Coastguard Worker * Parses an expression with bc_parse_expr_err(), but throws an error if it gets
2619*5a6e8488SAndroid Build Coastguard Worker * an empty expression.
2620*5a6e8488SAndroid Build Coastguard Worker * @param p The parser.
2621*5a6e8488SAndroid Build Coastguard Worker * @param flags The flags for what is valid in the expression.
2622*5a6e8488SAndroid Build Coastguard Worker * @param next A set of tokens for what is valid *after* the expression.
2623*5a6e8488SAndroid Build Coastguard Worker */
2624*5a6e8488SAndroid Build Coastguard Worker static void
bc_parse_expr_status(BcParse * p,uint8_t flags,BcParseNext next)2625*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next)
2626*5a6e8488SAndroid Build Coastguard Worker {
2627*5a6e8488SAndroid Build Coastguard Worker BcParseStatus s = bc_parse_expr_err(p, flags, next);
2628*5a6e8488SAndroid Build Coastguard Worker
2629*5a6e8488SAndroid Build Coastguard Worker if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR))
2630*5a6e8488SAndroid Build Coastguard Worker {
2631*5a6e8488SAndroid Build Coastguard Worker bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR);
2632*5a6e8488SAndroid Build Coastguard Worker }
2633*5a6e8488SAndroid Build Coastguard Worker }
2634*5a6e8488SAndroid Build Coastguard Worker
2635*5a6e8488SAndroid Build Coastguard Worker void
bc_parse_expr(BcParse * p,uint8_t flags)2636*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr(BcParse* p, uint8_t flags)
2637*5a6e8488SAndroid Build Coastguard Worker {
2638*5a6e8488SAndroid Build Coastguard Worker assert(p);
2639*5a6e8488SAndroid Build Coastguard Worker bc_parse_expr_status(p, flags, bc_parse_next_read);
2640*5a6e8488SAndroid Build Coastguard Worker }
2641*5a6e8488SAndroid Build Coastguard Worker #endif // BC_ENABLED
2642