xref: /freebsd/contrib/bc/src/bc_parse.c (revision 103d7cdf)
150696a6eSStefan Eßer /*
250696a6eSStefan Eßer  * *****************************************************************************
350696a6eSStefan Eßer  *
450696a6eSStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
550696a6eSStefan Eßer  *
6d101cdd6SStefan Eßer  * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
750696a6eSStefan Eßer  *
850696a6eSStefan Eßer  * Redistribution and use in source and binary forms, with or without
950696a6eSStefan Eßer  * modification, are permitted provided that the following conditions are met:
1050696a6eSStefan Eßer  *
1150696a6eSStefan Eßer  * * Redistributions of source code must retain the above copyright notice, this
1250696a6eSStefan Eßer  *   list of conditions and the following disclaimer.
1350696a6eSStefan Eßer  *
1450696a6eSStefan Eßer  * * Redistributions in binary form must reproduce the above copyright notice,
1550696a6eSStefan Eßer  *   this list of conditions and the following disclaimer in the documentation
1650696a6eSStefan Eßer  *   and/or other materials provided with the distribution.
1750696a6eSStefan Eßer  *
1850696a6eSStefan Eßer  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1950696a6eSStefan Eßer  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2050696a6eSStefan Eßer  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2150696a6eSStefan Eßer  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2250696a6eSStefan Eßer  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2350696a6eSStefan Eßer  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2450696a6eSStefan Eßer  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2550696a6eSStefan Eßer  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2650696a6eSStefan Eßer  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2750696a6eSStefan Eßer  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2850696a6eSStefan Eßer  * POSSIBILITY OF SUCH DAMAGE.
2950696a6eSStefan Eßer  *
3050696a6eSStefan Eßer  * *****************************************************************************
3150696a6eSStefan Eßer  *
3250696a6eSStefan Eßer  * The parser for bc.
3350696a6eSStefan Eßer  *
3450696a6eSStefan Eßer  */
3550696a6eSStefan Eßer 
3650696a6eSStefan Eßer #if BC_ENABLED
3750696a6eSStefan Eßer 
3850696a6eSStefan Eßer #include <assert.h>
3950696a6eSStefan Eßer #include <stdbool.h>
4050696a6eSStefan Eßer #include <stdlib.h>
4150696a6eSStefan Eßer #include <string.h>
4250696a6eSStefan Eßer 
4350696a6eSStefan Eßer #include <setjmp.h>
4450696a6eSStefan Eßer 
4550696a6eSStefan Eßer #include <bc.h>
4650696a6eSStefan Eßer #include <num.h>
4750696a6eSStefan Eßer #include <vm.h>
4850696a6eSStefan Eßer 
4944d4804dSStefan Eßer // Before you embark on trying to understand this code, have you read the
5044d4804dSStefan Eßer // Development manual (manuals/development.md) and the comment in include/bc.h
5144d4804dSStefan Eßer // yet? No? Do that first. I'm serious.
5244d4804dSStefan Eßer //
5344d4804dSStefan Eßer // The reason is because this file holds the most sensitive and finicky code in
5444d4804dSStefan Eßer // the entire codebase. Even getting history to work on Windows was nothing
5544d4804dSStefan Eßer // compared to this. This is where dreams go to die, where dragons live, and
5644d4804dSStefan Eßer // from which Ken Thompson himself would flee.
5744d4804dSStefan Eßer 
5878bc019dSStefan Eßer static void
5978bc019dSStefan Eßer bc_parse_else(BcParse* p);
6078bc019dSStefan Eßer 
6178bc019dSStefan Eßer static void
6278bc019dSStefan Eßer bc_parse_stmt(BcParse* p);
6378bc019dSStefan Eßer 
6478bc019dSStefan Eßer static BcParseStatus
6578bc019dSStefan Eßer bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next);
6678bc019dSStefan Eßer 
6778bc019dSStefan Eßer static void
6878bc019dSStefan Eßer bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next);
6950696a6eSStefan Eßer 
7044d4804dSStefan Eßer /**
7144d4804dSStefan Eßer  * Returns true if an instruction could only have come from a "leaf" expression.
7244d4804dSStefan Eßer  * For more on what leaf expressions are, read the comment for BC_PARSE_LEAF().
7344d4804dSStefan Eßer  * @param t  The instruction to test.
74d101cdd6SStefan Eßer  * @return   True if the instruction is a from a leaf expression.
7544d4804dSStefan Eßer  */
7678bc019dSStefan Eßer static bool
bc_parse_inst_isLeaf(BcInst t)7778bc019dSStefan Eßer bc_parse_inst_isLeaf(BcInst t)
7878bc019dSStefan Eßer {
79d101cdd6SStefan Eßer 	return (t >= BC_INST_NUM && t <= BC_INST_LEADING_ZERO) ||
8050696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
8150696a6eSStefan Eßer 	       t == BC_INST_TRUNC ||
8250696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
8350696a6eSStefan Eßer 	       t <= BC_INST_DEC;
8450696a6eSStefan Eßer }
8550696a6eSStefan Eßer 
8644d4804dSStefan Eßer /**
8744d4804dSStefan Eßer  * Returns true if the *previous* token was a delimiter. A delimiter is anything
8844d4804dSStefan Eßer  * that can legally end a statement. In bc's case, it could be a newline, a
8944d4804dSStefan Eßer  * semicolon, and a brace in certain cases.
9044d4804dSStefan Eßer  * @param p  The parser.
9110041e99SStefan Eßer  * @return   True if the token is a legal delimiter.
9244d4804dSStefan Eßer  */
9378bc019dSStefan Eßer static bool
bc_parse_isDelimiter(const BcParse * p)9478bc019dSStefan Eßer bc_parse_isDelimiter(const BcParse* p)
9578bc019dSStefan Eßer {
9650696a6eSStefan Eßer 	BcLexType t = p->l.t;
9744d4804dSStefan Eßer 	bool good;
9850696a6eSStefan Eßer 
9944d4804dSStefan Eßer 	// If it's an obvious delimiter, say so.
10050696a6eSStefan Eßer 	if (BC_PARSE_DELIMITER(t)) return true;
10150696a6eSStefan Eßer 
10244d4804dSStefan Eßer 	good = false;
10344d4804dSStefan Eßer 
10444d4804dSStefan Eßer 	// If the current token is a keyword, then...beware. That means that we need
10544d4804dSStefan Eßer 	// to check for a "dangling" else, where there was no brace-delimited block
10644d4804dSStefan Eßer 	// on the previous if.
10778bc019dSStefan Eßer 	if (t == BC_LEX_KW_ELSE)
10878bc019dSStefan Eßer 	{
10950696a6eSStefan Eßer 		size_t i;
11050696a6eSStefan Eßer 		uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
11150696a6eSStefan Eßer 
11244d4804dSStefan Eßer 		// As long as going up the stack is valid for a dangling else, keep on.
11378bc019dSStefan Eßer 		for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i)
11478bc019dSStefan Eßer 		{
11550696a6eSStefan Eßer 			fptr = bc_vec_item_rev(&p->flags, i);
11650696a6eSStefan Eßer 			flags = *fptr;
11750696a6eSStefan Eßer 
11844d4804dSStefan Eßer 			// If we need a brace and don't have one, then we don't have a
11944d4804dSStefan Eßer 			// delimiter.
12050696a6eSStefan Eßer 			if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
12178bc019dSStefan Eßer 			{
12250696a6eSStefan Eßer 				return false;
12350696a6eSStefan Eßer 			}
12478bc019dSStefan Eßer 		}
12550696a6eSStefan Eßer 
12644d4804dSStefan Eßer 		// Oh, and we had also better have an if statement somewhere.
12750696a6eSStefan Eßer 		good = ((flags & BC_PARSE_FLAG_IF) != 0);
12850696a6eSStefan Eßer 	}
12978bc019dSStefan Eßer 	else if (t == BC_LEX_RBRACE)
13078bc019dSStefan Eßer 	{
13150696a6eSStefan Eßer 		size_t i;
13250696a6eSStefan Eßer 
13344d4804dSStefan Eßer 		// Since we have a brace, we need to just check if a brace was needed.
13478bc019dSStefan Eßer 		for (i = 0; !good && i < p->flags.len; ++i)
13578bc019dSStefan Eßer 		{
13650696a6eSStefan Eßer 			uint16_t* fptr = bc_vec_item_rev(&p->flags, i);
13750696a6eSStefan Eßer 			good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
13850696a6eSStefan Eßer 		}
13950696a6eSStefan Eßer 	}
14050696a6eSStefan Eßer 
14150696a6eSStefan Eßer 	return good;
14250696a6eSStefan Eßer }
14350696a6eSStefan Eßer 
14444d4804dSStefan Eßer /**
14510041e99SStefan Eßer  * Returns true if we are in top level of a function body. The POSIX grammar
14610041e99SStefan Eßer  * is defined such that anything is allowed after a function body, so we must
14710041e99SStefan Eßer  * use this function to detect that case when ending a function body.
14810041e99SStefan Eßer  * @param p  The parser.
14910041e99SStefan Eßer  * @return   True if we are in the top level of parsing a function body.
15010041e99SStefan Eßer  */
15178bc019dSStefan Eßer static bool
bc_parse_TopFunc(const BcParse * p)15278bc019dSStefan Eßer bc_parse_TopFunc(const BcParse* p)
15378bc019dSStefan Eßer {
15410041e99SStefan Eßer 	bool good = p->flags.len == 2;
15510041e99SStefan Eßer 
15610041e99SStefan Eßer 	uint16_t val = BC_PARSE_FLAG_BRACE | BC_PARSE_FLAG_FUNC_INNER;
15710041e99SStefan Eßer 	val |= BC_PARSE_FLAG_FUNC;
15810041e99SStefan Eßer 
15910041e99SStefan Eßer 	return good && BC_PARSE_TOP_FLAG(p) == val;
16010041e99SStefan Eßer }
16110041e99SStefan Eßer 
16210041e99SStefan Eßer /**
16344d4804dSStefan Eßer  * Sets a previously defined exit label. What are labels? See the bc Parsing
16444d4804dSStefan Eßer  * section of the Development manual (manuals/development.md).
16544d4804dSStefan Eßer  * @param p  The parser.
16644d4804dSStefan Eßer  */
16778bc019dSStefan Eßer static void
bc_parse_setLabel(BcParse * p)16878bc019dSStefan Eßer bc_parse_setLabel(BcParse* p)
16978bc019dSStefan Eßer {
17050696a6eSStefan Eßer 	BcFunc* func = p->func;
17150696a6eSStefan Eßer 	BcInstPtr* ip = bc_vec_top(&p->exits);
17250696a6eSStefan Eßer 	size_t* label;
17350696a6eSStefan Eßer 
17450696a6eSStefan Eßer 	assert(func == bc_vec_item(&p->prog->fns, p->fidx));
17550696a6eSStefan Eßer 
17644d4804dSStefan Eßer 	// Set the preallocated label to the correct index.
17750696a6eSStefan Eßer 	label = bc_vec_item(&func->labels, ip->idx);
17850696a6eSStefan Eßer 	*label = func->code.len;
17950696a6eSStefan Eßer 
18044d4804dSStefan Eßer 	// Now, we don't need the exit label; it is done.
18150696a6eSStefan Eßer 	bc_vec_pop(&p->exits);
18250696a6eSStefan Eßer }
18350696a6eSStefan Eßer 
18444d4804dSStefan Eßer /**
18544d4804dSStefan Eßer  * Creates a label and sets it to idx. If this is an exit label, then idx is
18644d4804dSStefan Eßer  * actually invalid, but it doesn't matter because it will be fixed by
18744d4804dSStefan Eßer  * bc_parse_setLabel() later.
18844d4804dSStefan Eßer  * @param p    The parser.
18944d4804dSStefan Eßer  * @param idx  The index of the label.
19044d4804dSStefan Eßer  */
19178bc019dSStefan Eßer static void
bc_parse_createLabel(BcParse * p,size_t idx)19278bc019dSStefan Eßer bc_parse_createLabel(BcParse* p, size_t idx)
19378bc019dSStefan Eßer {
19450696a6eSStefan Eßer 	bc_vec_push(&p->func->labels, &idx);
19550696a6eSStefan Eßer }
19650696a6eSStefan Eßer 
19744d4804dSStefan Eßer /**
19844d4804dSStefan Eßer  * Creates a conditional label. Unlike an exit label, this label is set at
19944d4804dSStefan Eßer  * creation time because it comes *before* the code that will target it.
20044d4804dSStefan Eßer  * @param p    The parser.
20144d4804dSStefan Eßer  * @param idx  The index of the label.
20244d4804dSStefan Eßer  */
20378bc019dSStefan Eßer static void
bc_parse_createCondLabel(BcParse * p,size_t idx)20478bc019dSStefan Eßer bc_parse_createCondLabel(BcParse* p, size_t idx)
20578bc019dSStefan Eßer {
20650696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
20750696a6eSStefan Eßer 	bc_vec_push(&p->conds, &idx);
20850696a6eSStefan Eßer }
20950696a6eSStefan Eßer 
210d101cdd6SStefan Eßer /**
21144d4804dSStefan Eßer  * Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
21244d4804dSStefan Eßer  * create a label to be filled in later? Because exit labels are meant to be
21344d4804dSStefan Eßer  * targeted by code that comes *before* the label. Since we have to parse that
21444d4804dSStefan Eßer  * code first, and don't know how long it will be, we need to just make sure to
21544d4804dSStefan Eßer  * reserve a slot to be filled in later when we know.
21644d4804dSStefan Eßer  *
21744d4804dSStefan Eßer  * By the way, this uses BcInstPtr because it was convenient. The field idx
21844d4804dSStefan Eßer  * holds the index, and the field func holds the loop boolean.
21944d4804dSStefan Eßer  *
22044d4804dSStefan Eßer  * @param p     The parser.
22144d4804dSStefan Eßer  * @param idx   The index of the label's position.
22244d4804dSStefan Eßer  * @param loop  True if the exit label is for a loop or not.
22344d4804dSStefan Eßer  */
22478bc019dSStefan Eßer static void
bc_parse_createExitLabel(BcParse * p,size_t idx,bool loop)22578bc019dSStefan Eßer bc_parse_createExitLabel(BcParse* p, size_t idx, bool loop)
22678bc019dSStefan Eßer {
22750696a6eSStefan Eßer 	BcInstPtr ip;
22850696a6eSStefan Eßer 
22950696a6eSStefan Eßer 	assert(p->func == bc_vec_item(&p->prog->fns, p->fidx));
23050696a6eSStefan Eßer 
23150696a6eSStefan Eßer 	ip.func = loop;
23250696a6eSStefan Eßer 	ip.idx = idx;
23350696a6eSStefan Eßer 	ip.len = 0;
23450696a6eSStefan Eßer 
23550696a6eSStefan Eßer 	bc_vec_push(&p->exits, &ip);
23650696a6eSStefan Eßer 	bc_parse_createLabel(p, SIZE_MAX);
23750696a6eSStefan Eßer }
23850696a6eSStefan Eßer 
23944d4804dSStefan Eßer /**
24044d4804dSStefan Eßer  * Pops the correct operators off of the operator stack based on the current
24144d4804dSStefan Eßer  * operator. This is because of the Shunting-Yard algorithm. Lower prec means
24244d4804dSStefan Eßer  * higher precedence.
24344d4804dSStefan Eßer  * @param p       The parser.
24444d4804dSStefan Eßer  * @param type    The operator.
24544d4804dSStefan Eßer  * @param start   The previous start of the operator stack. For more
24644d4804dSStefan Eßer  *                information, see the bc Parsing section of the Development
24744d4804dSStefan Eßer  *                manual (manuals/development.md).
24844d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
24944d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
25044d4804dSStefan Eßer  */
25178bc019dSStefan Eßer static void
bc_parse_operator(BcParse * p,BcLexType type,size_t start,size_t * nexprs)25278bc019dSStefan Eßer bc_parse_operator(BcParse* p, BcLexType type, size_t start, size_t* nexprs)
25350696a6eSStefan Eßer {
25450696a6eSStefan Eßer 	BcLexType t;
25550696a6eSStefan Eßer 	uchar l, r = BC_PARSE_OP_PREC(type);
25650696a6eSStefan Eßer 	uchar left = BC_PARSE_OP_LEFT(type);
25750696a6eSStefan Eßer 
258d101cdd6SStefan Eßer 	// While we haven't hit the stop point yet...
25978bc019dSStefan Eßer 	while (p->ops.len > start)
26078bc019dSStefan Eßer 	{
26144d4804dSStefan Eßer 		// Get the top operator.
26250696a6eSStefan Eßer 		t = BC_PARSE_TOP_OP(p);
26344d4804dSStefan Eßer 
264d101cdd6SStefan Eßer 		// If it's a left paren, we have reached the end of whatever expression
265d101cdd6SStefan Eßer 		// this is no matter what. We also don't pop the left paren because it
266d101cdd6SStefan Eßer 		// will need to stay for the rest of the subexpression.
26750696a6eSStefan Eßer 		if (t == BC_LEX_LPAREN) break;
26850696a6eSStefan Eßer 
26944d4804dSStefan Eßer 		// Break for precedence. Precedence operates differently on left and
27044d4804dSStefan Eßer 		// right associativity, by the way. A left associative operator that
27144d4804dSStefan Eßer 		// matches the current precedence should take priority, but a right
27244d4804dSStefan Eßer 		// associative operator should not.
273d101cdd6SStefan Eßer 		//
274d101cdd6SStefan Eßer 		// Also, a lower precedence value means a higher precedence.
27550696a6eSStefan Eßer 		l = BC_PARSE_OP_PREC(t);
27650696a6eSStefan Eßer 		if (l >= r && (l != r || !left)) break;
27750696a6eSStefan Eßer 
27844d4804dSStefan Eßer 		// Do the housekeeping. In particular, make sure to note that one
279d101cdd6SStefan Eßer 		// expression was consumed (well, two were, but another was added) if
280d101cdd6SStefan Eßer 		// the operator was not a prefix operator. (Postfix operators are not
281d101cdd6SStefan Eßer 		// handled by this function at all.)
28250696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
28350696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
28450696a6eSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(t);
28550696a6eSStefan Eßer 	}
28650696a6eSStefan Eßer 
28750696a6eSStefan Eßer 	bc_vec_push(&p->ops, &type);
28850696a6eSStefan Eßer }
28950696a6eSStefan Eßer 
29044d4804dSStefan Eßer /**
29144d4804dSStefan Eßer  * Parses a right paren. In the Shunting-Yard algorithm, it needs to be put on
29244d4804dSStefan Eßer  * the operator stack. But before that, it needs to consume whatever operators
29344d4804dSStefan Eßer  * there are until it hits a left paren.
29444d4804dSStefan Eßer  * @param p       The parser.
29544d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
29644d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
29744d4804dSStefan Eßer  */
29878bc019dSStefan Eßer static void
bc_parse_rightParen(BcParse * p,size_t * nexprs)29978bc019dSStefan Eßer bc_parse_rightParen(BcParse* p, size_t* nexprs)
30078bc019dSStefan Eßer {
30150696a6eSStefan Eßer 	BcLexType top;
30250696a6eSStefan Eßer 
30344d4804dSStefan Eßer 	// Consume operators until a left paren.
30478bc019dSStefan Eßer 	while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN)
30578bc019dSStefan Eßer 	{
30650696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
30750696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
30844d4804dSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(top);
30950696a6eSStefan Eßer 	}
31050696a6eSStefan Eßer 
31144d4804dSStefan Eßer 	// We need to pop the left paren as well.
31250696a6eSStefan Eßer 	bc_vec_pop(&p->ops);
31350696a6eSStefan Eßer 
31444d4804dSStefan Eßer 	// Oh, and we also want the next token.
31550696a6eSStefan Eßer 	bc_lex_next(&p->l);
31650696a6eSStefan Eßer }
31750696a6eSStefan Eßer 
31844d4804dSStefan Eßer /**
31944d4804dSStefan Eßer  * Parses function arguments.
32044d4804dSStefan Eßer  * @param p      The parser.
32144d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
32244d4804dSStefan Eßer  *               be.
32344d4804dSStefan Eßer  */
32478bc019dSStefan Eßer static void
bc_parse_args(BcParse * p,uint8_t flags)32578bc019dSStefan Eßer bc_parse_args(BcParse* p, uint8_t flags)
32678bc019dSStefan Eßer {
32750696a6eSStefan Eßer 	bool comma = false;
32844d4804dSStefan Eßer 	size_t nargs;
32950696a6eSStefan Eßer 
33050696a6eSStefan Eßer 	bc_lex_next(&p->l);
33150696a6eSStefan Eßer 
33244d4804dSStefan Eßer 	// Print and comparison operators not allowed. Well, comparison operators
33344d4804dSStefan Eßer 	// only for POSIX. But we do allow arrays, and we *must* get a value.
33450696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
33550696a6eSStefan Eßer 	flags |= (BC_PARSE_ARRAY | BC_PARSE_NEEDVAL);
33650696a6eSStefan Eßer 
33744d4804dSStefan Eßer 	// Count the arguments and parse them.
33878bc019dSStefan Eßer 	for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs)
33978bc019dSStefan Eßer 	{
34044d4804dSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_arg);
34150696a6eSStefan Eßer 
34250696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
34350696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
34450696a6eSStefan Eßer 	}
34550696a6eSStefan Eßer 
34644d4804dSStefan Eßer 	// An ending comma is FAIL.
34750696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
34844d4804dSStefan Eßer 
34944d4804dSStefan Eßer 	// Now do the call with the number of arguments.
35050696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_CALL);
35144d4804dSStefan Eßer 	bc_parse_pushIndex(p, nargs);
35250696a6eSStefan Eßer }
35350696a6eSStefan Eßer 
35444d4804dSStefan Eßer /**
35544d4804dSStefan Eßer  * Parses a function call.
35644d4804dSStefan Eßer  * @param p      The parser.
35744d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
35844d4804dSStefan Eßer  *               be.
35944d4804dSStefan Eßer  */
36078bc019dSStefan Eßer static void
bc_parse_call(BcParse * p,const char * name,uint8_t flags)36178bc019dSStefan Eßer bc_parse_call(BcParse* p, const char* name, uint8_t flags)
36278bc019dSStefan Eßer {
36350696a6eSStefan Eßer 	size_t idx;
36450696a6eSStefan Eßer 
36544d4804dSStefan Eßer 	bc_parse_args(p, flags);
36650696a6eSStefan Eßer 
36744d4804dSStefan Eßer 	// We just assert this because bc_parse_args() should
36850696a6eSStefan Eßer 	// ensure that the next token is what it should be.
36950696a6eSStefan Eßer 	assert(p->l.t == BC_LEX_RPAREN);
37050696a6eSStefan Eßer 
37150696a6eSStefan Eßer 	// We cannot use bc_program_insertFunc() here
37250696a6eSStefan Eßer 	// because it will overwrite an existing function.
37350696a6eSStefan Eßer 	idx = bc_map_index(&p->prog->fn_map, name);
37450696a6eSStefan Eßer 
37544d4804dSStefan Eßer 	// The function does not exist yet. Create a space for it. If the user does
37644d4804dSStefan Eßer 	// not define it, it's a *runtime* error, not a parse error.
37778bc019dSStefan Eßer 	if (idx == BC_VEC_INVALID_IDX)
37878bc019dSStefan Eßer 	{
37950696a6eSStefan Eßer 		idx = bc_program_insertFunc(p->prog, name);
38050696a6eSStefan Eßer 
38150696a6eSStefan Eßer 		assert(idx != BC_VEC_INVALID_IDX);
38250696a6eSStefan Eßer 
38350696a6eSStefan Eßer 		// Make sure that this pointer was not invalidated.
38450696a6eSStefan Eßer 		p->func = bc_vec_item(&p->prog->fns, p->fidx);
38550696a6eSStefan Eßer 	}
38644d4804dSStefan Eßer 	// The function exists, so set the right function index.
38750696a6eSStefan Eßer 	else idx = ((BcId*) bc_vec_item(&p->prog->fn_map, idx))->idx;
38850696a6eSStefan Eßer 
38950696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
39050696a6eSStefan Eßer 
39144d4804dSStefan Eßer 	// Make sure to get the next token.
39250696a6eSStefan Eßer 	bc_lex_next(&p->l);
39350696a6eSStefan Eßer }
39450696a6eSStefan Eßer 
39544d4804dSStefan Eßer /**
39644d4804dSStefan Eßer  * Parses a name/identifier-based expression. It could be a variable, an array
39744d4804dSStefan Eßer  * element, an array itself (for function arguments), a function call, etc.
398d101cdd6SStefan Eßer  * @param p           The parser.
399d101cdd6SStefan Eßer  * @param type        A pointer to return the resulting instruction.
400d101cdd6SStefan Eßer  * @param can_assign  A pointer to return true if the name can be assigned to,
401d101cdd6SStefan Eßer  *                    false otherwise.
402d101cdd6SStefan Eßer  * @param flags       Flags restricting what kind of expression the name can be.
40344d4804dSStefan Eßer  */
40478bc019dSStefan Eßer static void
bc_parse_name(BcParse * p,BcInst * type,bool * can_assign,uint8_t flags)40578bc019dSStefan Eßer bc_parse_name(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
40650696a6eSStefan Eßer {
40750696a6eSStefan Eßer 	char* name;
40850696a6eSStefan Eßer 
40910041e99SStefan Eßer 	BC_SIG_ASSERT_LOCKED;
41050696a6eSStefan Eßer 
41144d4804dSStefan Eßer 	// We want a copy of the name since the lexer might overwrite its copy.
41250696a6eSStefan Eßer 	name = bc_vm_strdup(p->l.str.v);
41350696a6eSStefan Eßer 
414d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, err);
41550696a6eSStefan Eßer 
41644d4804dSStefan Eßer 	// We need the next token to see if it's just a variable or something more.
41750696a6eSStefan Eßer 	bc_lex_next(&p->l);
41850696a6eSStefan Eßer 
41944d4804dSStefan Eßer 	// Array element or array.
42078bc019dSStefan Eßer 	if (p->l.t == BC_LEX_LBRACKET)
42178bc019dSStefan Eßer 	{
42250696a6eSStefan Eßer 		bc_lex_next(&p->l);
42350696a6eSStefan Eßer 
42444d4804dSStefan Eßer 		// Array only. This has to be a function parameter.
42578bc019dSStefan Eßer 		if (p->l.t == BC_LEX_RBRACKET)
42678bc019dSStefan Eßer 		{
42744d4804dSStefan Eßer 			// Error if arrays are not allowed.
42850696a6eSStefan Eßer 			if (BC_ERR(!(flags & BC_PARSE_ARRAY)))
42978bc019dSStefan Eßer 			{
43050696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_EXPR);
43178bc019dSStefan Eßer 			}
43250696a6eSStefan Eßer 
43350696a6eSStefan Eßer 			*type = BC_INST_ARRAY;
43450696a6eSStefan Eßer 			*can_assign = false;
43550696a6eSStefan Eßer 		}
43678bc019dSStefan Eßer 		else
43778bc019dSStefan Eßer 		{
43844d4804dSStefan Eßer 			// If we are here, we have an array element. We need to set the
43944d4804dSStefan Eßer 			// expression parsing flags.
44050696a6eSStefan Eßer 			uint8_t flags2 = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) |
44150696a6eSStefan Eßer 			                 BC_PARSE_NEEDVAL;
44250696a6eSStefan Eßer 
44350696a6eSStefan Eßer 			bc_parse_expr_status(p, flags2, bc_parse_next_elem);
44450696a6eSStefan Eßer 
44544d4804dSStefan Eßer 			// The next token *must* be a right bracket.
44650696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
44778bc019dSStefan Eßer 			{
44850696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
44978bc019dSStefan Eßer 			}
45050696a6eSStefan Eßer 
45150696a6eSStefan Eßer 			*type = BC_INST_ARRAY_ELEM;
45250696a6eSStefan Eßer 			*can_assign = true;
45350696a6eSStefan Eßer 		}
45450696a6eSStefan Eßer 
45544d4804dSStefan Eßer 		// Make sure to get the next token.
45650696a6eSStefan Eßer 		bc_lex_next(&p->l);
45750696a6eSStefan Eßer 
45844d4804dSStefan Eßer 		// Push the instruction and the name of the identifier.
45950696a6eSStefan Eßer 		bc_parse_push(p, *type);
46050696a6eSStefan Eßer 		bc_parse_pushName(p, name, false);
46150696a6eSStefan Eßer 	}
46278bc019dSStefan Eßer 	else if (p->l.t == BC_LEX_LPAREN)
46378bc019dSStefan Eßer 	{
46444d4804dSStefan Eßer 		// We are parsing a function call; error if not allowed.
46550696a6eSStefan Eßer 		if (BC_ERR(flags & BC_PARSE_NOCALL))
46678bc019dSStefan Eßer 		{
46750696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
46878bc019dSStefan Eßer 		}
46950696a6eSStefan Eßer 
47050696a6eSStefan Eßer 		*type = BC_INST_CALL;
47150696a6eSStefan Eßer 		*can_assign = false;
47250696a6eSStefan Eßer 
47350696a6eSStefan Eßer 		bc_parse_call(p, name, flags);
47450696a6eSStefan Eßer 	}
47578bc019dSStefan Eßer 	else
47678bc019dSStefan Eßer 	{
47744d4804dSStefan Eßer 		// Just a variable.
47850696a6eSStefan Eßer 		*type = BC_INST_VAR;
47950696a6eSStefan Eßer 		*can_assign = true;
48050696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_VAR);
48150696a6eSStefan Eßer 		bc_parse_pushName(p, name, true);
48250696a6eSStefan Eßer 	}
48350696a6eSStefan Eßer 
48450696a6eSStefan Eßer err:
48544d4804dSStefan Eßer 	// Need to make sure to unallocate the name.
48650696a6eSStefan Eßer 	free(name);
487d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
48810041e99SStefan Eßer 	BC_SIG_MAYLOCK;
48950696a6eSStefan Eßer }
49050696a6eSStefan Eßer 
49144d4804dSStefan Eßer /**
49244d4804dSStefan Eßer  * Parses a builtin function that takes no arguments. This includes read(),
49344d4804dSStefan Eßer  * rand(), maxibase(), maxobase(), maxscale(), and maxrand().
49444d4804dSStefan Eßer  * @param p     The parser.
49544d4804dSStefan Eßer  * @param inst  The instruction corresponding to the builtin.
49644d4804dSStefan Eßer  */
49778bc019dSStefan Eßer static void
bc_parse_noArgBuiltin(BcParse * p,BcInst inst)49878bc019dSStefan Eßer bc_parse_noArgBuiltin(BcParse* p, BcInst inst)
49978bc019dSStefan Eßer {
50044d4804dSStefan Eßer 	// Must have a left paren.
50150696a6eSStefan Eßer 	bc_lex_next(&p->l);
50250696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
50350696a6eSStefan Eßer 
50444d4804dSStefan Eßer 	// Must have a right paren.
50550696a6eSStefan Eßer 	bc_lex_next(&p->l);
50650696a6eSStefan Eßer 	if ((p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
50750696a6eSStefan Eßer 
50850696a6eSStefan Eßer 	bc_parse_push(p, inst);
50950696a6eSStefan Eßer 
51050696a6eSStefan Eßer 	bc_lex_next(&p->l);
51150696a6eSStefan Eßer }
51250696a6eSStefan Eßer 
51344d4804dSStefan Eßer /**
51444d4804dSStefan Eßer  * Parses a builtin function that takes 1 argument. This includes length(),
51544d4804dSStefan Eßer  * sqrt(), abs(), scale(), and irand().
51644d4804dSStefan Eßer  * @param p      The parser.
51744d4804dSStefan Eßer  * @param type   The lex token.
51844d4804dSStefan Eßer  * @param flags  The expression parsing flags for parsing the argument.
51944d4804dSStefan Eßer  * @param prev   An out parameter; the previous instruction pointer.
52044d4804dSStefan Eßer  */
52178bc019dSStefan Eßer static void
bc_parse_builtin(BcParse * p,BcLexType type,uint8_t flags,BcInst * prev)52278bc019dSStefan Eßer bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
52350696a6eSStefan Eßer {
52444d4804dSStefan Eßer 	// Must have a left paren.
52550696a6eSStefan Eßer 	bc_lex_next(&p->l);
52678bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
52750696a6eSStefan Eßer 
52850696a6eSStefan Eßer 	bc_lex_next(&p->l);
52950696a6eSStefan Eßer 
53044d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
53150696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
53250696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
53344d4804dSStefan Eßer 
53444d4804dSStefan Eßer 	// Since length can take arrays, we need to specially add that flag.
535d101cdd6SStefan Eßer 	if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY)
536d101cdd6SStefan Eßer 	{
537d101cdd6SStefan Eßer 		flags |= BC_PARSE_ARRAY;
538d101cdd6SStefan Eßer 	}
539d101cdd6SStefan Eßer 
540d101cdd6SStefan Eßer 	// Otherwise, we need to clear it because it could be set.
541d101cdd6SStefan Eßer 	else flags &= ~(BC_PARSE_ARRAY);
54250696a6eSStefan Eßer 
54350696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
54450696a6eSStefan Eßer 
54544d4804dSStefan Eßer 	// Must have a right paren.
54678bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
54750696a6eSStefan Eßer 
54844d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
54950696a6eSStefan Eßer 	*prev = type - BC_LEX_KW_LENGTH + BC_INST_LENGTH;
55050696a6eSStefan Eßer 	bc_parse_push(p, *prev);
55150696a6eSStefan Eßer 
55250696a6eSStefan Eßer 	bc_lex_next(&p->l);
55350696a6eSStefan Eßer }
55450696a6eSStefan Eßer 
55544d4804dSStefan Eßer /**
55644d4804dSStefan Eßer  * Parses a builtin function that takes 3 arguments. This includes modexp() and
55744d4804dSStefan Eßer  * divmod().
558d101cdd6SStefan Eßer  * @param p      The parser.
559d101cdd6SStefan Eßer  * @param type   The lex token.
560d101cdd6SStefan Eßer  * @param flags  The expression parsing flags for parsing the argument.
561d101cdd6SStefan Eßer  * @param prev   An out parameter; the previous instruction pointer.
56244d4804dSStefan Eßer  */
56378bc019dSStefan Eßer static void
bc_parse_builtin3(BcParse * p,BcLexType type,uint8_t flags,BcInst * prev)56478bc019dSStefan Eßer bc_parse_builtin3(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev)
56544d4804dSStefan Eßer {
56644d4804dSStefan Eßer 	assert(type == BC_LEX_KW_MODEXP || type == BC_LEX_KW_DIVMOD);
56744d4804dSStefan Eßer 
56844d4804dSStefan Eßer 	// Must have a left paren.
56944d4804dSStefan Eßer 	bc_lex_next(&p->l);
57078bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
57144d4804dSStefan Eßer 
57244d4804dSStefan Eßer 	bc_lex_next(&p->l);
57344d4804dSStefan Eßer 
57444d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
57544d4804dSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
57644d4804dSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
57744d4804dSStefan Eßer 
57844d4804dSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
57944d4804dSStefan Eßer 
58044d4804dSStefan Eßer 	// Must have a comma.
58178bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
58244d4804dSStefan Eßer 
58344d4804dSStefan Eßer 	bc_lex_next(&p->l);
58444d4804dSStefan Eßer 
58544d4804dSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
58644d4804dSStefan Eßer 
58744d4804dSStefan Eßer 	// Must have a comma.
58878bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
58944d4804dSStefan Eßer 
59044d4804dSStefan Eßer 	bc_lex_next(&p->l);
59144d4804dSStefan Eßer 
59244d4804dSStefan Eßer 	// If it is a divmod, parse an array name. Otherwise, just parse another
59344d4804dSStefan Eßer 	// expression.
59478bc019dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD)
59578bc019dSStefan Eßer 	{
59644d4804dSStefan Eßer 		// Must have a name.
59744d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
59844d4804dSStefan Eßer 
59944d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
60044d4804dSStefan Eßer 		bc_lex_next(&p->l);
60144d4804dSStefan Eßer 
60244d4804dSStefan Eßer 		// Must have a left bracket.
60344d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_LBRACKET))
60478bc019dSStefan Eßer 		{
60544d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
60678bc019dSStefan Eßer 		}
60744d4804dSStefan Eßer 
60844d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
60944d4804dSStefan Eßer 		bc_lex_next(&p->l);
61044d4804dSStefan Eßer 
61144d4804dSStefan Eßer 		// Must have a right bracket.
61244d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
61378bc019dSStefan Eßer 		{
61444d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
61578bc019dSStefan Eßer 		}
61644d4804dSStefan Eßer 
61744d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
61844d4804dSStefan Eßer 		bc_lex_next(&p->l);
61944d4804dSStefan Eßer 	}
62044d4804dSStefan Eßer 	else bc_parse_expr_status(p, flags, bc_parse_next_rel);
62144d4804dSStefan Eßer 
62244d4804dSStefan Eßer 	// Must have a right paren.
62378bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
62444d4804dSStefan Eßer 
62544d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
62644d4804dSStefan Eßer 	*prev = type - BC_LEX_KW_MODEXP + BC_INST_MODEXP;
62744d4804dSStefan Eßer 	bc_parse_push(p, *prev);
62844d4804dSStefan Eßer 
62944d4804dSStefan Eßer 	// If we have divmod, we need to assign the modulus to the array element, so
63044d4804dSStefan Eßer 	// we need to push the instructions for doing so.
63178bc019dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD)
63278bc019dSStefan Eßer 	{
63344d4804dSStefan Eßer 		// The zeroth element.
63444d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ZERO);
63544d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ARRAY_ELEM);
63644d4804dSStefan Eßer 
63744d4804dSStefan Eßer 		// Push the array.
63844d4804dSStefan Eßer 		bc_parse_pushName(p, p->l.str.v, false);
63944d4804dSStefan Eßer 
64044d4804dSStefan Eßer 		// Swap them and assign. After this, the top item on the stack should
64144d4804dSStefan Eßer 		// be the quotient.
64244d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_SWAP);
64344d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
64444d4804dSStefan Eßer 	}
64544d4804dSStefan Eßer 
64644d4804dSStefan Eßer 	bc_lex_next(&p->l);
64744d4804dSStefan Eßer }
64844d4804dSStefan Eßer 
64944d4804dSStefan Eßer /**
65044d4804dSStefan Eßer  * Parses the scale keyword. This is special because scale can be a value or a
65144d4804dSStefan Eßer  * builtin function.
65244d4804dSStefan Eßer  * @param p           The parser.
65344d4804dSStefan Eßer  * @param type        An out parameter; the instruction for the parse.
65444d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
65544d4804dSStefan Eßer  *                    to.
65644d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
65744d4804dSStefan Eßer  */
65878bc019dSStefan Eßer static void
bc_parse_scale(BcParse * p,BcInst * type,bool * can_assign,uint8_t flags)65978bc019dSStefan Eßer bc_parse_scale(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags)
66050696a6eSStefan Eßer {
66150696a6eSStefan Eßer 	bc_lex_next(&p->l);
66250696a6eSStefan Eßer 
66344d4804dSStefan Eßer 	// Without the left paren, it's just the keyword.
66478bc019dSStefan Eßer 	if (p->l.t != BC_LEX_LPAREN)
66578bc019dSStefan Eßer 	{
66644d4804dSStefan Eßer 		// Set, push, and return.
66750696a6eSStefan Eßer 		*type = BC_INST_SCALE;
66850696a6eSStefan Eßer 		*can_assign = true;
66950696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_SCALE);
67050696a6eSStefan Eßer 		return;
67150696a6eSStefan Eßer 	}
67250696a6eSStefan Eßer 
67344d4804dSStefan Eßer 	// Handle the scale function.
67450696a6eSStefan Eßer 	*type = BC_INST_SCALE_FUNC;
67550696a6eSStefan Eßer 	*can_assign = false;
67644d4804dSStefan Eßer 
67744d4804dSStefan Eßer 	// Once again, adjust the flags.
67850696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
67950696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
68050696a6eSStefan Eßer 
68150696a6eSStefan Eßer 	bc_lex_next(&p->l);
68250696a6eSStefan Eßer 
68350696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
68444d4804dSStefan Eßer 
68544d4804dSStefan Eßer 	// Must have a right paren.
68678bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
68750696a6eSStefan Eßer 
68850696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_SCALE_FUNC);
68950696a6eSStefan Eßer 
69050696a6eSStefan Eßer 	bc_lex_next(&p->l);
69150696a6eSStefan Eßer }
69250696a6eSStefan Eßer 
69344d4804dSStefan Eßer /**
69444d4804dSStefan Eßer  * Parses and increment or decrement operator. This is a bit complex.
69544d4804dSStefan Eßer  * @param p           The parser.
69644d4804dSStefan Eßer  * @param prev        An out parameter; the previous instruction pointer.
69744d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
69844d4804dSStefan Eßer  *                    to.
69944d4804dSStefan Eßer  * @param nexs        An in/out parameter; the number of expressions in the
70044d4804dSStefan Eßer  *                    parse tree that are not used.
70144d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
70244d4804dSStefan Eßer  */
70378bc019dSStefan Eßer static void
bc_parse_incdec(BcParse * p,BcInst * prev,bool * can_assign,size_t * nexs,uint8_t flags)70478bc019dSStefan Eßer bc_parse_incdec(BcParse* p, BcInst* prev, bool* can_assign, size_t* nexs,
70578bc019dSStefan Eßer                 uint8_t flags)
70650696a6eSStefan Eßer {
70750696a6eSStefan Eßer 	BcLexType type;
70850696a6eSStefan Eßer 	uchar inst;
70950696a6eSStefan Eßer 	BcInst etype = *prev;
71050696a6eSStefan Eßer 	BcLexType last = p->l.last;
71150696a6eSStefan Eßer 
71250696a6eSStefan Eßer 	assert(prev != NULL && can_assign != NULL);
71350696a6eSStefan Eßer 
71444d4804dSStefan Eßer 	// If we can't assign to the previous token, then we have an error.
71550696a6eSStefan Eßer 	if (BC_ERR(last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC ||
71650696a6eSStefan Eßer 	           last == BC_LEX_RPAREN))
71750696a6eSStefan Eßer 	{
71850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
71950696a6eSStefan Eßer 	}
72050696a6eSStefan Eßer 
72144d4804dSStefan Eßer 	// Is the previous instruction for a variable?
72278bc019dSStefan Eßer 	if (BC_PARSE_INST_VAR(etype))
72378bc019dSStefan Eßer 	{
72444d4804dSStefan Eßer 		// If so, this is a postfix operator.
72550696a6eSStefan Eßer 		if (!*can_assign) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
72650696a6eSStefan Eßer 
72744d4804dSStefan Eßer 		// Only postfix uses BC_INST_INC and BC_INST_DEC.
72850696a6eSStefan Eßer 		*prev = inst = BC_INST_INC + (p->l.t != BC_LEX_OP_INC);
72950696a6eSStefan Eßer 		bc_parse_push(p, inst);
73050696a6eSStefan Eßer 		bc_lex_next(&p->l);
73150696a6eSStefan Eßer 		*can_assign = false;
73250696a6eSStefan Eßer 	}
73378bc019dSStefan Eßer 	else
73478bc019dSStefan Eßer 	{
73544d4804dSStefan Eßer 		// This is a prefix operator. In that case, we just convert it to
73644d4804dSStefan Eßer 		// an assignment instruction.
73750696a6eSStefan Eßer 		*prev = inst = BC_INST_ASSIGN_PLUS + (p->l.t != BC_LEX_OP_INC);
73850696a6eSStefan Eßer 
73950696a6eSStefan Eßer 		bc_lex_next(&p->l);
74050696a6eSStefan Eßer 		type = p->l.t;
74150696a6eSStefan Eßer 
74250696a6eSStefan Eßer 		// Because we parse the next part of the expression
74350696a6eSStefan Eßer 		// right here, we need to increment this.
74450696a6eSStefan Eßer 		*nexs = *nexs + 1;
74550696a6eSStefan Eßer 
74644d4804dSStefan Eßer 		// Is the next token a normal identifier?
74778bc019dSStefan Eßer 		if (type == BC_LEX_NAME)
74878bc019dSStefan Eßer 		{
74944d4804dSStefan Eßer 			// Parse the name.
750d101cdd6SStefan Eßer 			uint8_t flags2 = flags & ~(BC_PARSE_ARRAY);
75150696a6eSStefan Eßer 			bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
75250696a6eSStefan Eßer 		}
75344d4804dSStefan Eßer 		// Is the next token a global?
75478bc019dSStefan Eßer 		else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE)
75578bc019dSStefan Eßer 		{
75650696a6eSStefan Eßer 			bc_parse_push(p, type - BC_LEX_KW_LAST + BC_INST_LAST);
75750696a6eSStefan Eßer 			bc_lex_next(&p->l);
75850696a6eSStefan Eßer 		}
75944d4804dSStefan Eßer 		// Is the next token specifically scale, which needs special treatment?
76078bc019dSStefan Eßer 		else if (BC_NO_ERR(type == BC_LEX_KW_SCALE))
76178bc019dSStefan Eßer 		{
76250696a6eSStefan Eßer 			bc_lex_next(&p->l);
76350696a6eSStefan Eßer 
76444d4804dSStefan Eßer 			// Check that scale() was not used.
76550696a6eSStefan Eßer 			if (BC_ERR(p->l.t == BC_LEX_LPAREN))
76678bc019dSStefan Eßer 			{
76750696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
76878bc019dSStefan Eßer 			}
76950696a6eSStefan Eßer 			else bc_parse_push(p, BC_INST_SCALE);
77050696a6eSStefan Eßer 		}
77144d4804dSStefan Eßer 		// Now we know we have an error.
77250696a6eSStefan Eßer 		else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
77350696a6eSStefan Eßer 
77450696a6eSStefan Eßer 		*can_assign = false;
77550696a6eSStefan Eßer 
77650696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_ONE);
77750696a6eSStefan Eßer 		bc_parse_push(p, inst);
77850696a6eSStefan Eßer 	}
77950696a6eSStefan Eßer }
78050696a6eSStefan Eßer 
78144d4804dSStefan Eßer /**
78244d4804dSStefan Eßer  * Parses the minus operator. This needs special treatment because it is either
78344d4804dSStefan Eßer  * subtract or negation.
78444d4804dSStefan Eßer  * @param p        The parser.
78544d4804dSStefan Eßer  * @param prev     An in/out parameter; the previous instruction.
78644d4804dSStefan Eßer  * @param ops_bgn  The size of the operator stack.
78744d4804dSStefan Eßer  * @param rparen   True if the last token was a right paren.
78844d4804dSStefan Eßer  * @param binlast  True if the last token was a binary operator.
78944d4804dSStefan Eßer  * @param nexprs   An in/out parameter; the number of unused expressions.
79044d4804dSStefan Eßer  */
79178bc019dSStefan Eßer static void
bc_parse_minus(BcParse * p,BcInst * prev,size_t ops_bgn,bool rparen,bool binlast,size_t * nexprs)79278bc019dSStefan Eßer bc_parse_minus(BcParse* p, BcInst* prev, size_t ops_bgn, bool rparen,
79378bc019dSStefan Eßer                bool binlast, size_t* nexprs)
79450696a6eSStefan Eßer {
79550696a6eSStefan Eßer 	BcLexType type;
79650696a6eSStefan Eßer 
79750696a6eSStefan Eßer 	bc_lex_next(&p->l);
79850696a6eSStefan Eßer 
79944d4804dSStefan Eßer 	// Figure out if it's a minus or a negation.
80050696a6eSStefan Eßer 	type = BC_PARSE_LEAF(*prev, binlast, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
80150696a6eSStefan Eßer 	*prev = BC_PARSE_TOKEN_INST(type);
80250696a6eSStefan Eßer 
80350696a6eSStefan Eßer 	// We can just push onto the op stack because this is the largest
80450696a6eSStefan Eßer 	// precedence operator that gets pushed. Inc/dec does not.
80550696a6eSStefan Eßer 	if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
80650696a6eSStefan Eßer 	else bc_parse_operator(p, type, ops_bgn, nexprs);
80750696a6eSStefan Eßer }
80850696a6eSStefan Eßer 
80944d4804dSStefan Eßer /**
81044d4804dSStefan Eßer  * Parses a string.
81144d4804dSStefan Eßer  * @param p     The parser.
81244d4804dSStefan Eßer  * @param inst  The instruction corresponding to how the string was found and
81344d4804dSStefan Eßer  *              how it should be printed.
81444d4804dSStefan Eßer  */
81578bc019dSStefan Eßer static void
bc_parse_str(BcParse * p,BcInst inst)81678bc019dSStefan Eßer bc_parse_str(BcParse* p, BcInst inst)
81778bc019dSStefan Eßer {
81850696a6eSStefan Eßer 	bc_parse_addString(p);
81950696a6eSStefan Eßer 	bc_parse_push(p, inst);
82050696a6eSStefan Eßer 	bc_lex_next(&p->l);
82150696a6eSStefan Eßer }
82250696a6eSStefan Eßer 
82344d4804dSStefan Eßer /**
82444d4804dSStefan Eßer  * Parses a print statement.
82544d4804dSStefan Eßer  * @param p  The parser.
82644d4804dSStefan Eßer  */
82778bc019dSStefan Eßer static void
bc_parse_print(BcParse * p,BcLexType type)82878bc019dSStefan Eßer bc_parse_print(BcParse* p, BcLexType type)
82978bc019dSStefan Eßer {
83050696a6eSStefan Eßer 	BcLexType t;
83150696a6eSStefan Eßer 	bool comma = false;
83278bc019dSStefan Eßer 	BcInst inst = type == BC_LEX_KW_STREAM ? BC_INST_PRINT_STREAM :
83378bc019dSStefan Eßer 	                                         BC_INST_PRINT_POP;
83450696a6eSStefan Eßer 
83550696a6eSStefan Eßer 	bc_lex_next(&p->l);
83650696a6eSStefan Eßer 
83750696a6eSStefan Eßer 	t = p->l.t;
83850696a6eSStefan Eßer 
83944d4804dSStefan Eßer 	// A print or stream statement has to have *something*.
84050696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_PRINT);
84150696a6eSStefan Eßer 
84278bc019dSStefan Eßer 	do
84378bc019dSStefan Eßer 	{
84444d4804dSStefan Eßer 		// If the token is a string, then print it with escapes.
84544d4804dSStefan Eßer 		// BC_INST_PRINT_POP plays that role for bc.
84644d4804dSStefan Eßer 		if (t == BC_LEX_STR) bc_parse_str(p, inst);
84778bc019dSStefan Eßer 		else
84878bc019dSStefan Eßer 		{
84944d4804dSStefan Eßer 			// We have an actual number; parse and add a print instruction.
85050696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_NEEDVAL, bc_parse_next_print);
85144d4804dSStefan Eßer 			bc_parse_push(p, inst);
85250696a6eSStefan Eßer 		}
85350696a6eSStefan Eßer 
85444d4804dSStefan Eßer 		// Is the next token a comma?
85550696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
85650696a6eSStefan Eßer 
85744d4804dSStefan Eßer 		// Get the next token if we have a comma.
85850696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
85978bc019dSStefan Eßer 		else
86078bc019dSStefan Eßer 		{
86144d4804dSStefan Eßer 			// If we don't have a comma, the statement needs to end.
86278bc019dSStefan Eßer 			if (!bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
86350696a6eSStefan Eßer 			else break;
86450696a6eSStefan Eßer 		}
86550696a6eSStefan Eßer 
86650696a6eSStefan Eßer 		t = p->l.t;
86778bc019dSStefan Eßer 	}
86878bc019dSStefan Eßer 	while (true);
86950696a6eSStefan Eßer 
87044d4804dSStefan Eßer 	// If we have a comma but no token, that's bad.
87150696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
87250696a6eSStefan Eßer }
87350696a6eSStefan Eßer 
87444d4804dSStefan Eßer /**
87544d4804dSStefan Eßer  * Parses a return statement.
87644d4804dSStefan Eßer  * @param p  The parser.
87744d4804dSStefan Eßer  */
87878bc019dSStefan Eßer static void
bc_parse_return(BcParse * p)87978bc019dSStefan Eßer bc_parse_return(BcParse* p)
88078bc019dSStefan Eßer {
88150696a6eSStefan Eßer 	BcLexType t;
88250696a6eSStefan Eßer 	bool paren;
88350696a6eSStefan Eßer 	uchar inst = BC_INST_RET0;
88450696a6eSStefan Eßer 
88544d4804dSStefan Eßer 	// If we are not in a function, that's an error.
88650696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_FUNC(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
88750696a6eSStefan Eßer 
88844d4804dSStefan Eßer 	// If we are in a void function, make sure to return void.
88950696a6eSStefan Eßer 	if (p->func->voidfn) inst = BC_INST_RET_VOID;
89050696a6eSStefan Eßer 
89150696a6eSStefan Eßer 	bc_lex_next(&p->l);
89250696a6eSStefan Eßer 
89350696a6eSStefan Eßer 	t = p->l.t;
89444d4804dSStefan Eßer 	paren = (t == BC_LEX_LPAREN);
89550696a6eSStefan Eßer 
89644d4804dSStefan Eßer 	// An empty return statement just needs to push the selected instruction.
89750696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
89878bc019dSStefan Eßer 	else
89978bc019dSStefan Eßer 	{
90050696a6eSStefan Eßer 		BcParseStatus s;
90150696a6eSStefan Eßer 
90244d4804dSStefan Eßer 		// Need to parse the expression whose value will be returned.
90350696a6eSStefan Eßer 		s = bc_parse_expr_err(p, BC_PARSE_NEEDVAL, bc_parse_next_expr);
90450696a6eSStefan Eßer 
90544d4804dSStefan Eßer 		// If the expression was empty, just push the selected instruction.
90678bc019dSStefan Eßer 		if (s == BC_PARSE_STATUS_EMPTY_EXPR)
90778bc019dSStefan Eßer 		{
90850696a6eSStefan Eßer 			bc_parse_push(p, inst);
90950696a6eSStefan Eßer 			bc_lex_next(&p->l);
91050696a6eSStefan Eßer 		}
91150696a6eSStefan Eßer 
91244d4804dSStefan Eßer 		// POSIX requires parentheses.
91378bc019dSStefan Eßer 		if (!paren || p->l.last != BC_LEX_RPAREN)
91478bc019dSStefan Eßer 		{
91550696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_RET);
91650696a6eSStefan Eßer 		}
91744d4804dSStefan Eßer 
91844d4804dSStefan Eßer 		// Void functions require an empty expression.
91978bc019dSStefan Eßer 		if (BC_ERR(p->func->voidfn))
92078bc019dSStefan Eßer 		{
92144d4804dSStefan Eßer 			if (s != BC_PARSE_STATUS_EMPTY_EXPR)
92278bc019dSStefan Eßer 			{
92350696a6eSStefan Eßer 				bc_parse_verr(p, BC_ERR_PARSE_RET_VOID, p->func->name);
92444d4804dSStefan Eßer 			}
92578bc019dSStefan Eßer 		}
92644d4804dSStefan Eßer 		// If we got here, we want to be sure to end the function with a real
92744d4804dSStefan Eßer 		// return instruction, just in case.
92844d4804dSStefan Eßer 		else bc_parse_push(p, BC_INST_RET);
92950696a6eSStefan Eßer 	}
93050696a6eSStefan Eßer }
93150696a6eSStefan Eßer 
93244d4804dSStefan Eßer /**
93344d4804dSStefan Eßer  * Clears flags that indicate the end of an if statement and its block and sets
93444d4804dSStefan Eßer  * the jump location.
93544d4804dSStefan Eßer  * @param p  The parser.
93644d4804dSStefan Eßer  */
93778bc019dSStefan Eßer static void
bc_parse_noElse(BcParse * p)93878bc019dSStefan Eßer bc_parse_noElse(BcParse* p)
93978bc019dSStefan Eßer {
94050696a6eSStefan Eßer 	uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
94150696a6eSStefan Eßer 	*flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
94250696a6eSStefan Eßer 	bc_parse_setLabel(p);
94350696a6eSStefan Eßer }
94450696a6eSStefan Eßer 
94544d4804dSStefan Eßer /**
94644d4804dSStefan Eßer  * Ends (finishes parsing) the body of a control statement or a function.
94744d4804dSStefan Eßer  * @param p      The parser.
94844d4804dSStefan Eßer  * @param brace  True if the body was ended by a brace, false otherwise.
94944d4804dSStefan Eßer  */
95078bc019dSStefan Eßer static void
bc_parse_endBody(BcParse * p,bool brace)95178bc019dSStefan Eßer bc_parse_endBody(BcParse* p, bool brace)
95278bc019dSStefan Eßer {
95350696a6eSStefan Eßer 	bool has_brace, new_else = false;
95450696a6eSStefan Eßer 
95544d4804dSStefan Eßer 	// We cannot be ending a body if there are no bodies to end.
95650696a6eSStefan Eßer 	if (BC_ERR(p->flags.len <= 1)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
95750696a6eSStefan Eßer 
95878bc019dSStefan Eßer 	if (brace)
95978bc019dSStefan Eßer 	{
96044d4804dSStefan Eßer 		// The brace was already gotten; make sure that the caller did not lie.
96144d4804dSStefan Eßer 		// We check for the requirement of braces later.
96250696a6eSStefan Eßer 		assert(p->l.t == BC_LEX_RBRACE);
96350696a6eSStefan Eßer 
96450696a6eSStefan Eßer 		bc_lex_next(&p->l);
96544d4804dSStefan Eßer 
96644d4804dSStefan Eßer 		// If the next token is not a delimiter, that is a problem.
96710041e99SStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p) && !bc_parse_TopFunc(p)))
96878bc019dSStefan Eßer 		{
96950696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
97050696a6eSStefan Eßer 		}
97178bc019dSStefan Eßer 	}
97250696a6eSStefan Eßer 
97344d4804dSStefan Eßer 	// Do we have a brace flag?
97450696a6eSStefan Eßer 	has_brace = (BC_PARSE_BRACE(p) != 0);
97550696a6eSStefan Eßer 
97678bc019dSStefan Eßer 	do
97778bc019dSStefan Eßer 	{
97850696a6eSStefan Eßer 		size_t len = p->flags.len;
97950696a6eSStefan Eßer 		bool loop;
98050696a6eSStefan Eßer 
98144d4804dSStefan Eßer 		// If we have a brace flag but not a brace, that's a problem.
98250696a6eSStefan Eßer 		if (has_brace && !brace) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
98350696a6eSStefan Eßer 
98444d4804dSStefan Eßer 		// Are we inside a loop?
98550696a6eSStefan Eßer 		loop = (BC_PARSE_LOOP_INNER(p) != 0);
98650696a6eSStefan Eßer 
98744d4804dSStefan Eßer 		// If we are ending a loop or an else...
98878bc019dSStefan Eßer 		if (loop || BC_PARSE_ELSE(p))
98978bc019dSStefan Eßer 		{
99044d4804dSStefan Eßer 			// Loops have condition labels that we have to take care of as well.
99178bc019dSStefan Eßer 			if (loop)
99278bc019dSStefan Eßer 			{
99350696a6eSStefan Eßer 				size_t* label = bc_vec_top(&p->conds);
99450696a6eSStefan Eßer 
99550696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_JUMP);
99650696a6eSStefan Eßer 				bc_parse_pushIndex(p, *label);
99750696a6eSStefan Eßer 
99850696a6eSStefan Eßer 				bc_vec_pop(&p->conds);
99950696a6eSStefan Eßer 			}
100050696a6eSStefan Eßer 
100150696a6eSStefan Eßer 			bc_parse_setLabel(p);
100250696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
100350696a6eSStefan Eßer 		}
100444d4804dSStefan Eßer 		// If we are ending a function...
100578bc019dSStefan Eßer 		else if (BC_PARSE_FUNC_INNER(p))
100678bc019dSStefan Eßer 		{
100750696a6eSStefan Eßer 			BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
100850696a6eSStefan Eßer 			bc_parse_push(p, inst);
100950696a6eSStefan Eßer 			bc_parse_updateFunc(p, BC_PROG_MAIN);
101050696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
101150696a6eSStefan Eßer 		}
101244d4804dSStefan Eßer 		// If we have a brace flag and not an if statement, we can pop the top
101344d4804dSStefan Eßer 		// of the flags stack because they have been taken care of above.
101444d4804dSStefan Eßer 		else if (has_brace && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
101550696a6eSStefan Eßer 
101650696a6eSStefan Eßer 		// This needs to be last to parse nested if's properly.
101778bc019dSStefan Eßer 		if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p)))
101878bc019dSStefan Eßer 		{
101944d4804dSStefan Eßer 			// Eat newlines.
102078bc019dSStefan Eßer 			while (p->l.t == BC_LEX_NLINE)
102178bc019dSStefan Eßer 			{
102278bc019dSStefan Eßer 				bc_lex_next(&p->l);
102378bc019dSStefan Eßer 			}
102450696a6eSStefan Eßer 
102544d4804dSStefan Eßer 			// *Now* we can pop the flags.
102650696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
102750696a6eSStefan Eßer 
102844d4804dSStefan Eßer 			// If we are allowed non-POSIX stuff...
102978bc019dSStefan Eßer 			if (!BC_S)
103078bc019dSStefan Eßer 			{
103144d4804dSStefan Eßer 				// Have we found yet another dangling else?
103250696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
103350696a6eSStefan Eßer 				new_else = (p->l.t == BC_LEX_KW_ELSE);
103450696a6eSStefan Eßer 
103544d4804dSStefan Eßer 				// Parse the else or end the if statement body.
103650696a6eSStefan Eßer 				if (new_else) bc_parse_else(p);
103750696a6eSStefan Eßer 				else if (!has_brace && (!BC_PARSE_IF_END(p) || brace))
103878bc019dSStefan Eßer 				{
103950696a6eSStefan Eßer 					bc_parse_noElse(p);
104050696a6eSStefan Eßer 				}
104178bc019dSStefan Eßer 			}
104244d4804dSStefan Eßer 			// POSIX requires us to do the bare minimum only.
104350696a6eSStefan Eßer 			else bc_parse_noElse(p);
104450696a6eSStefan Eßer 		}
104550696a6eSStefan Eßer 
104644d4804dSStefan Eßer 		// If these are both true, we have "used" the braces that we found.
104750696a6eSStefan Eßer 		if (brace && has_brace) brace = false;
104878bc019dSStefan Eßer 	}
104978bc019dSStefan Eßer 	// This condition was perhaps the hardest single part of the parser. If
105078bc019dSStefan Eßer 	// the flags stack does not have enough, we should stop. If we have a
105178bc019dSStefan Eßer 	// new else statement, we should stop. If we do have the end of an if
105278bc019dSStefan Eßer 	// statement and we have eaten the brace, we should stop. If we do have
105378bc019dSStefan Eßer 	// a brace flag, we should stop.
105478bc019dSStefan Eßer 	while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
105550696a6eSStefan Eßer 	       !(has_brace = (BC_PARSE_BRACE(p) != 0)));
105650696a6eSStefan Eßer 
105744d4804dSStefan Eßer 	// If we have a brace, yet no body for it, that's a problem.
105878bc019dSStefan Eßer 	if (BC_ERR(p->flags.len == 1 && brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
105978bc019dSStefan Eßer 	else if (brace && BC_PARSE_BRACE(p))
106078bc019dSStefan Eßer 	{
106144d4804dSStefan Eßer 		// If we make it here, we have a brace and a flag for it.
106250696a6eSStefan Eßer 		uint16_t flags = BC_PARSE_TOP_FLAG(p);
106350696a6eSStefan Eßer 
106444d4804dSStefan Eßer 		// This condition ensure that the *last* body is correctly finished by
106544d4804dSStefan Eßer 		// popping its flags.
106650696a6eSStefan Eßer 		if (!(flags & (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_LOOP_INNER)) &&
106750696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF | BC_PARSE_FLAG_ELSE)) &&
106850696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF_END)))
106950696a6eSStefan Eßer 		{
107050696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
107150696a6eSStefan Eßer 		}
107250696a6eSStefan Eßer 	}
107350696a6eSStefan Eßer }
107450696a6eSStefan Eßer 
107544d4804dSStefan Eßer /**
107644d4804dSStefan Eßer  * Starts the body of a control statement or function.
107744d4804dSStefan Eßer  * @param p      The parser.
107844d4804dSStefan Eßer  * @param flags  The current flags (will be edited).
107944d4804dSStefan Eßer  */
108078bc019dSStefan Eßer static void
bc_parse_startBody(BcParse * p,uint16_t flags)108178bc019dSStefan Eßer bc_parse_startBody(BcParse* p, uint16_t flags)
108278bc019dSStefan Eßer {
108350696a6eSStefan Eßer 	assert(flags);
108450696a6eSStefan Eßer 	flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
108550696a6eSStefan Eßer 	flags |= BC_PARSE_FLAG_BODY;
108650696a6eSStefan Eßer 	bc_vec_push(&p->flags, &flags);
108750696a6eSStefan Eßer }
108850696a6eSStefan Eßer 
108978bc019dSStefan Eßer void
bc_parse_endif(BcParse * p)109078bc019dSStefan Eßer bc_parse_endif(BcParse* p)
109178bc019dSStefan Eßer {
1092a30efc5cSStefan Eßer 	size_t i;
1093a30efc5cSStefan Eßer 	bool good;
1094a30efc5cSStefan Eßer 
1095a30efc5cSStefan Eßer 	// Not a problem if this is true.
1096a30efc5cSStefan Eßer 	if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
1097a30efc5cSStefan Eßer 
1098a30efc5cSStefan Eßer 	good = true;
1099a30efc5cSStefan Eßer 
1100a30efc5cSStefan Eßer 	// Find an instance of a body that needs closing, i.e., a statement that did
1101a30efc5cSStefan Eßer 	// not have a right brace when it should have.
110278bc019dSStefan Eßer 	for (i = 0; good && i < p->flags.len; ++i)
110378bc019dSStefan Eßer 	{
1104a30efc5cSStefan Eßer 		uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
1105a30efc5cSStefan Eßer 		good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
1106a30efc5cSStefan Eßer 	}
1107a30efc5cSStefan Eßer 
1108a30efc5cSStefan Eßer 	// If we did not find such an instance...
110978bc019dSStefan Eßer 	if (good)
111078bc019dSStefan Eßer 	{
1111a30efc5cSStefan Eßer 		// We set this to restore it later. We don't want the parser thinking
1112a30efc5cSStefan Eßer 		// that we are on stdin for this one because it will want more.
1113d101cdd6SStefan Eßer 		BcMode mode = vm->mode;
1114a30efc5cSStefan Eßer 
1115d101cdd6SStefan Eßer 		vm->mode = BC_MODE_FILE;
1116a30efc5cSStefan Eßer 
1117a30efc5cSStefan Eßer 		// End all of the if statements and loops.
111878bc019dSStefan Eßer 		while (p->flags.len > 1 || BC_PARSE_IF_END(p))
111978bc019dSStefan Eßer 		{
1120a30efc5cSStefan Eßer 			if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
1121a30efc5cSStefan Eßer 			if (p->flags.len > 1) bc_parse_endBody(p, false);
1122a30efc5cSStefan Eßer 		}
1123a30efc5cSStefan Eßer 
1124d101cdd6SStefan Eßer 		vm->mode = (uchar) mode;
1125a30efc5cSStefan Eßer 	}
1126a30efc5cSStefan Eßer 	// If we reach here, a block was not properly closed, and we should error.
1127d101cdd6SStefan Eßer 	else bc_parse_err(&vm->prs, BC_ERR_PARSE_BLOCK);
1128a30efc5cSStefan Eßer }
1129a30efc5cSStefan Eßer 
113044d4804dSStefan Eßer /**
113144d4804dSStefan Eßer  * Parses an if statement.
113244d4804dSStefan Eßer  * @param p  The parser.
113344d4804dSStefan Eßer  */
113478bc019dSStefan Eßer static void
bc_parse_if(BcParse * p)113578bc019dSStefan Eßer bc_parse_if(BcParse* p)
113678bc019dSStefan Eßer {
113744d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
113850696a6eSStefan Eßer 	size_t idx;
113950696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
114050696a6eSStefan Eßer 
114144d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
114250696a6eSStefan Eßer 	bc_lex_next(&p->l);
114378bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
114450696a6eSStefan Eßer 
114544d4804dSStefan Eßer 	// Parse the condition.
114650696a6eSStefan Eßer 	bc_lex_next(&p->l);
114750696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
114844d4804dSStefan Eßer 
114944d4804dSStefan Eßer 	// Must have a right paren.
115078bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
115150696a6eSStefan Eßer 
115250696a6eSStefan Eßer 	bc_lex_next(&p->l);
115344d4804dSStefan Eßer 
115444d4804dSStefan Eßer 	// Insert the conditional jump instruction.
115550696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
115650696a6eSStefan Eßer 
115750696a6eSStefan Eßer 	idx = p->func->labels.len;
115850696a6eSStefan Eßer 
115944d4804dSStefan Eßer 	// Push the index for the instruction and create an exit label for an else
116044d4804dSStefan Eßer 	// statement.
116150696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
116250696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
116344d4804dSStefan Eßer 
116450696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_IF);
116550696a6eSStefan Eßer }
116650696a6eSStefan Eßer 
116744d4804dSStefan Eßer /**
116844d4804dSStefan Eßer  * Parses an else statement.
116944d4804dSStefan Eßer  * @param p  The parser.
117044d4804dSStefan Eßer  */
117178bc019dSStefan Eßer static void
bc_parse_else(BcParse * p)117278bc019dSStefan Eßer bc_parse_else(BcParse* p)
117378bc019dSStefan Eßer {
117450696a6eSStefan Eßer 	size_t idx = p->func->labels.len;
117550696a6eSStefan Eßer 
117644d4804dSStefan Eßer 	// We must be at the end of an if statement.
117778bc019dSStefan Eßer 	if (BC_ERR(!BC_PARSE_IF_END(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
117850696a6eSStefan Eßer 
117944d4804dSStefan Eßer 	// Push an unconditional jump to make bc jump over the else statement if it
118044d4804dSStefan Eßer 	// executed the original if statement.
118150696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
118250696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
118350696a6eSStefan Eßer 
118444d4804dSStefan Eßer 	// Clear the else stuff. Yes, that function is misnamed for its use here,
118544d4804dSStefan Eßer 	// but deal with it.
118650696a6eSStefan Eßer 	bc_parse_noElse(p);
118750696a6eSStefan Eßer 
118844d4804dSStefan Eßer 	// Create the exit label and parse the body.
118950696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
119050696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
119150696a6eSStefan Eßer 
119250696a6eSStefan Eßer 	bc_lex_next(&p->l);
119350696a6eSStefan Eßer }
119450696a6eSStefan Eßer 
119544d4804dSStefan Eßer /**
119644d4804dSStefan Eßer  * Parse a while loop.
119744d4804dSStefan Eßer  * @param p  The parser.
119844d4804dSStefan Eßer  */
119978bc019dSStefan Eßer static void
bc_parse_while(BcParse * p)120078bc019dSStefan Eßer bc_parse_while(BcParse* p)
120178bc019dSStefan Eßer {
120244d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
120350696a6eSStefan Eßer 	size_t idx;
120450696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
120550696a6eSStefan Eßer 
120644d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
120750696a6eSStefan Eßer 	bc_lex_next(&p->l);
120878bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
120950696a6eSStefan Eßer 	bc_lex_next(&p->l);
121050696a6eSStefan Eßer 
121144d4804dSStefan Eßer 	// Create the labels. Loops need both.
121250696a6eSStefan Eßer 	bc_parse_createCondLabel(p, p->func->labels.len);
121350696a6eSStefan Eßer 	idx = p->func->labels.len;
121450696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, true);
121550696a6eSStefan Eßer 
121644d4804dSStefan Eßer 	// Parse the actual condition and barf on non-right paren.
121750696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
121878bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
121950696a6eSStefan Eßer 	bc_lex_next(&p->l);
122050696a6eSStefan Eßer 
122144d4804dSStefan Eßer 	// Now we can push the conditional jump and start the body.
122250696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
122350696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
122450696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
122550696a6eSStefan Eßer }
122650696a6eSStefan Eßer 
122744d4804dSStefan Eßer /**
122844d4804dSStefan Eßer  * Parse a for loop.
122944d4804dSStefan Eßer  * @param p  The parser.
123044d4804dSStefan Eßer  */
123178bc019dSStefan Eßer static void
bc_parse_for(BcParse * p)123278bc019dSStefan Eßer bc_parse_for(BcParse* p)
123378bc019dSStefan Eßer {
123450696a6eSStefan Eßer 	size_t cond_idx, exit_idx, body_idx, update_idx;
123550696a6eSStefan Eßer 
123644d4804dSStefan Eßer 	// Barf on the missing left paren.
123750696a6eSStefan Eßer 	bc_lex_next(&p->l);
123878bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
123950696a6eSStefan Eßer 	bc_lex_next(&p->l);
124050696a6eSStefan Eßer 
124144d4804dSStefan Eßer 	// The first statement can be empty, but if it is, check for error in POSIX
124244d4804dSStefan Eßer 	// mode. Otherwise, parse it.
124378bc019dSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON) bc_parse_expr_status(p, 0, bc_parse_next_for);
124450696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
124550696a6eSStefan Eßer 
124644d4804dSStefan Eßer 	// Must have a semicolon.
124744d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
124850696a6eSStefan Eßer 	bc_lex_next(&p->l);
124950696a6eSStefan Eßer 
125044d4804dSStefan Eßer 	// These are indices for labels. There are so many of them because the end
125144d4804dSStefan Eßer 	// of the loop must unconditionally jump to the update code. Then the update
125244d4804dSStefan Eßer 	// code must unconditionally jump to the condition code. Then the condition
125344d4804dSStefan Eßer 	// code must *conditionally* jump to the exit.
125450696a6eSStefan Eßer 	cond_idx = p->func->labels.len;
125550696a6eSStefan Eßer 	update_idx = cond_idx + 1;
125650696a6eSStefan Eßer 	body_idx = update_idx + 1;
125750696a6eSStefan Eßer 	exit_idx = body_idx + 1;
125850696a6eSStefan Eßer 
125944d4804dSStefan Eßer 	// This creates the condition label.
126050696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
126150696a6eSStefan Eßer 
126244d4804dSStefan Eßer 	// Parse an expression if it exists.
126378bc019dSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON)
126478bc019dSStefan Eßer 	{
126550696a6eSStefan Eßer 		uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
126650696a6eSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_for);
126750696a6eSStefan Eßer 	}
126878bc019dSStefan Eßer 	else
126978bc019dSStefan Eßer 	{
127044d4804dSStefan Eßer 		// Set this for the next call to bc_parse_number because an empty
127144d4804dSStefan Eßer 		// condition means that it is an infinite loop, so the condition must be
127244d4804dSStefan Eßer 		// non-zero. This is safe to set because the current token is a
127344d4804dSStefan Eßer 		// semicolon, which has no string requirement.
127450696a6eSStefan Eßer 		bc_vec_string(&p->l.str, sizeof(bc_parse_one) - 1, bc_parse_one);
127550696a6eSStefan Eßer 		bc_parse_number(p);
127650696a6eSStefan Eßer 
127744d4804dSStefan Eßer 		// An empty condition makes POSIX mad.
127850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_FOR);
127950696a6eSStefan Eßer 	}
128050696a6eSStefan Eßer 
128144d4804dSStefan Eßer 	// Must have a semicolon.
128278bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
128350696a6eSStefan Eßer 	bc_lex_next(&p->l);
128450696a6eSStefan Eßer 
128544d4804dSStefan Eßer 	// Now we can set up the conditional jump to the exit and an unconditional
128644d4804dSStefan Eßer 	// jump to the body right after. The unconditional jump to the body is
128744d4804dSStefan Eßer 	// because there is update code coming right after the condition, so we need
128844d4804dSStefan Eßer 	// to skip it to get to the body.
128950696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
129050696a6eSStefan Eßer 	bc_parse_pushIndex(p, exit_idx);
129150696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
129250696a6eSStefan Eßer 	bc_parse_pushIndex(p, body_idx);
129350696a6eSStefan Eßer 
129444d4804dSStefan Eßer 	// Now create the label for the update code.
129550696a6eSStefan Eßer 	bc_parse_createCondLabel(p, update_idx);
129650696a6eSStefan Eßer 
129744d4804dSStefan Eßer 	// Parse if not empty, and if it is, let POSIX yell if necessary.
129878bc019dSStefan Eßer 	if (p->l.t != BC_LEX_RPAREN) bc_parse_expr_status(p, 0, bc_parse_next_rel);
129950696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
130050696a6eSStefan Eßer 
130144d4804dSStefan Eßer 	// Must have a right paren.
130278bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
130344d4804dSStefan Eßer 
130444d4804dSStefan Eßer 	// Set up a jump to the condition right after the update code.
130550696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
130650696a6eSStefan Eßer 	bc_parse_pushIndex(p, cond_idx);
130750696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
130850696a6eSStefan Eßer 
130944d4804dSStefan Eßer 	// Create an exit label for the body and start the body.
131050696a6eSStefan Eßer 	bc_parse_createExitLabel(p, exit_idx, true);
131150696a6eSStefan Eßer 	bc_lex_next(&p->l);
131250696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
131350696a6eSStefan Eßer }
131450696a6eSStefan Eßer 
131544d4804dSStefan Eßer /**
131644d4804dSStefan Eßer  * Parse a statement or token that indicates a loop exit. This includes an
131744d4804dSStefan Eßer  * actual loop exit, the break keyword, or the continue keyword.
131844d4804dSStefan Eßer  * @param p     The parser.
131944d4804dSStefan Eßer  * @param type  The type of exit.
132044d4804dSStefan Eßer  */
132178bc019dSStefan Eßer static void
bc_parse_loopExit(BcParse * p,BcLexType type)132278bc019dSStefan Eßer bc_parse_loopExit(BcParse* p, BcLexType type)
132378bc019dSStefan Eßer {
132450696a6eSStefan Eßer 	size_t i;
132550696a6eSStefan Eßer 	BcInstPtr* ip;
132650696a6eSStefan Eßer 
132744d4804dSStefan Eßer 	// Must have a loop. If we don't, that's an error.
132850696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_LOOP(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
132950696a6eSStefan Eßer 
133044d4804dSStefan Eßer 	// If we have a break statement...
133178bc019dSStefan Eßer 	if (type == BC_LEX_KW_BREAK)
133278bc019dSStefan Eßer 	{
133344d4804dSStefan Eßer 		// If there are no exits, something went wrong somewhere.
133450696a6eSStefan Eßer 		if (BC_ERR(!p->exits.len)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
133550696a6eSStefan Eßer 
133644d4804dSStefan Eßer 		// Get the exit.
133750696a6eSStefan Eßer 		i = p->exits.len - 1;
133850696a6eSStefan Eßer 		ip = bc_vec_item(&p->exits, i);
133950696a6eSStefan Eßer 
134044d4804dSStefan Eßer 		// The condition !ip->func is true if the exit is not for a loop, so we
134144d4804dSStefan Eßer 		// need to find the first actual loop exit.
134278bc019dSStefan Eßer 		while (!ip->func && i < p->exits.len)
134378bc019dSStefan Eßer 		{
134478bc019dSStefan Eßer 			ip = bc_vec_item(&p->exits, i);
134578bc019dSStefan Eßer 			i -= 1;
134678bc019dSStefan Eßer 		}
134744d4804dSStefan Eßer 
134844d4804dSStefan Eßer 		// Make sure everything is hunky dory.
134950696a6eSStefan Eßer 		assert(ip != NULL && (i < p->exits.len || ip->func));
135044d4804dSStefan Eßer 
135144d4804dSStefan Eßer 		// Set the index for the exit.
135250696a6eSStefan Eßer 		i = ip->idx;
135350696a6eSStefan Eßer 	}
135444d4804dSStefan Eßer 	// If we have a continue statement or just the loop end, jump to the
135544d4804dSStefan Eßer 	// condition (or update for a foor loop).
135650696a6eSStefan Eßer 	else i = *((size_t*) bc_vec_top(&p->conds));
135750696a6eSStefan Eßer 
135844d4804dSStefan Eßer 	// Add the unconditional jump.
135950696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
136050696a6eSStefan Eßer 	bc_parse_pushIndex(p, i);
136150696a6eSStefan Eßer 
136250696a6eSStefan Eßer 	bc_lex_next(&p->l);
136350696a6eSStefan Eßer }
136450696a6eSStefan Eßer 
136544d4804dSStefan Eßer /**
136644d4804dSStefan Eßer  * Parse a function (header).
136744d4804dSStefan Eßer  * @param p  The parser.
136844d4804dSStefan Eßer  */
136978bc019dSStefan Eßer static void
bc_parse_func(BcParse * p)137078bc019dSStefan Eßer bc_parse_func(BcParse* p)
137178bc019dSStefan Eßer {
137250696a6eSStefan Eßer 	bool comma = false, voidfn;
137350696a6eSStefan Eßer 	uint16_t flags;
137450696a6eSStefan Eßer 	size_t idx;
137550696a6eSStefan Eßer 
137650696a6eSStefan Eßer 	bc_lex_next(&p->l);
137750696a6eSStefan Eßer 
137844d4804dSStefan Eßer 	// Must have a name.
137944d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
138050696a6eSStefan Eßer 
138144d4804dSStefan Eßer 	// If the name is "void", and POSIX is not on, mark as void.
138250696a6eSStefan Eßer 	voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME &&
138350696a6eSStefan Eßer 	          !strcmp(p->l.str.v, "void"));
138450696a6eSStefan Eßer 
138544d4804dSStefan Eßer 	// We can safely do this because the expected token should not overwrite the
138644d4804dSStefan Eßer 	// function name.
138750696a6eSStefan Eßer 	bc_lex_next(&p->l);
138850696a6eSStefan Eßer 
138944d4804dSStefan Eßer 	// If we *don't* have another name, then void is the name of the function.
139050696a6eSStefan Eßer 	voidfn = (voidfn && p->l.t == BC_LEX_NAME);
139150696a6eSStefan Eßer 
139244d4804dSStefan Eßer 	// With a void function, allow POSIX to complain and get a new token.
139378bc019dSStefan Eßer 	if (voidfn)
139478bc019dSStefan Eßer 	{
139550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_VOID);
139644d4804dSStefan Eßer 
139744d4804dSStefan Eßer 		// We can safely do this because the expected token should not overwrite
139844d4804dSStefan Eßer 		// the function name.
139950696a6eSStefan Eßer 		bc_lex_next(&p->l);
140050696a6eSStefan Eßer 	}
140150696a6eSStefan Eßer 
140244d4804dSStefan Eßer 	// Must have a left paren.
140378bc019dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
140450696a6eSStefan Eßer 
140544d4804dSStefan Eßer 	// Make sure the functions map and vector are synchronized.
140650696a6eSStefan Eßer 	assert(p->prog->fns.len == p->prog->fn_map.len);
140750696a6eSStefan Eßer 
140844d4804dSStefan Eßer 	// Insert the function by name into the map and vector.
140950696a6eSStefan Eßer 	idx = bc_program_insertFunc(p->prog, p->l.str.v);
141050696a6eSStefan Eßer 
141144d4804dSStefan Eßer 	// Make sure the insert worked.
141250696a6eSStefan Eßer 	assert(idx);
141344d4804dSStefan Eßer 
141444d4804dSStefan Eßer 	// Update the function pointer and stuff in the parser and set its void.
141550696a6eSStefan Eßer 	bc_parse_updateFunc(p, idx);
141650696a6eSStefan Eßer 	p->func->voidfn = voidfn;
141750696a6eSStefan Eßer 
141850696a6eSStefan Eßer 	bc_lex_next(&p->l);
141950696a6eSStefan Eßer 
142044d4804dSStefan Eßer 	// While we do not have a right paren, we are still parsing arguments.
142178bc019dSStefan Eßer 	while (p->l.t != BC_LEX_RPAREN)
142278bc019dSStefan Eßer 	{
142350696a6eSStefan Eßer 		BcType t = BC_TYPE_VAR;
142450696a6eSStefan Eßer 
142544d4804dSStefan Eßer 		// If we have an asterisk, we are parsing a reference argument.
142678bc019dSStefan Eßer 		if (p->l.t == BC_LEX_OP_MULTIPLY)
142778bc019dSStefan Eßer 		{
142850696a6eSStefan Eßer 			t = BC_TYPE_REF;
142950696a6eSStefan Eßer 			bc_lex_next(&p->l);
143044d4804dSStefan Eßer 
143144d4804dSStefan Eßer 			// Let POSIX complain if necessary.
143250696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_REF);
143350696a6eSStefan Eßer 		}
143450696a6eSStefan Eßer 
143544d4804dSStefan Eßer 		// If we don't have a name, the argument will not have a name. Barf.
143678bc019dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
143750696a6eSStefan Eßer 
143844d4804dSStefan Eßer 		// Increment the number of parameters.
143950696a6eSStefan Eßer 		p->func->nparams += 1;
144050696a6eSStefan Eßer 
144144d4804dSStefan Eßer 		// Copy the string in the lexer so that we can use the lexer again.
144250696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len, p->l.str.v);
144350696a6eSStefan Eßer 
144450696a6eSStefan Eßer 		bc_lex_next(&p->l);
144550696a6eSStefan Eßer 
144644d4804dSStefan Eßer 		// We are parsing an array parameter if this is true.
144778bc019dSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET)
144878bc019dSStefan Eßer 		{
144944d4804dSStefan Eßer 			// Set the array type, unless we are already parsing a reference.
145050696a6eSStefan Eßer 			if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
145150696a6eSStefan Eßer 
145250696a6eSStefan Eßer 			bc_lex_next(&p->l);
145350696a6eSStefan Eßer 
145444d4804dSStefan Eßer 			// The brackets *must* be empty.
145550696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
145678bc019dSStefan Eßer 			{
145750696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
145878bc019dSStefan Eßer 			}
145950696a6eSStefan Eßer 
146050696a6eSStefan Eßer 			bc_lex_next(&p->l);
146150696a6eSStefan Eßer 		}
146244d4804dSStefan Eßer 		// If we did *not* get a bracket, but we are expecting a reference, we
146344d4804dSStefan Eßer 		// have a problem.
146450696a6eSStefan Eßer 		else if (BC_ERR(t == BC_TYPE_REF))
146578bc019dSStefan Eßer 		{
146650696a6eSStefan Eßer 			bc_parse_verr(p, BC_ERR_PARSE_REF_VAR, p->buf.v);
146778bc019dSStefan Eßer 		}
146850696a6eSStefan Eßer 
146944d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
147050696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
147144d4804dSStefan Eßer 		if (comma) bc_lex_next(&p->l);
147250696a6eSStefan Eßer 
147344d4804dSStefan Eßer 		// Insert the parameter into the function.
147450696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
147550696a6eSStefan Eßer 	}
147650696a6eSStefan Eßer 
147744d4804dSStefan Eßer 	// If we have a comma, but no parameter, barf.
147850696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
147950696a6eSStefan Eßer 
148044d4804dSStefan Eßer 	// Start the body.
148150696a6eSStefan Eßer 	flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER;
148250696a6eSStefan Eßer 	bc_parse_startBody(p, flags);
148350696a6eSStefan Eßer 
148450696a6eSStefan Eßer 	bc_lex_next(&p->l);
148550696a6eSStefan Eßer 
148644d4804dSStefan Eßer 	// POSIX requires that a brace be on the same line as the function header.
148744d4804dSStefan Eßer 	// If we don't have a brace, let POSIX throw an error.
148850696a6eSStefan Eßer 	if (p->l.t != BC_LEX_LBRACE) bc_parse_err(p, BC_ERR_POSIX_BRACE);
148950696a6eSStefan Eßer }
149050696a6eSStefan Eßer 
149144d4804dSStefan Eßer /**
149244d4804dSStefan Eßer  * Parse an auto list.
149344d4804dSStefan Eßer  * @param p  The parser.
149444d4804dSStefan Eßer  */
149578bc019dSStefan Eßer static void
bc_parse_auto(BcParse * p)149678bc019dSStefan Eßer bc_parse_auto(BcParse* p)
149778bc019dSStefan Eßer {
149850696a6eSStefan Eßer 	bool comma, one;
149950696a6eSStefan Eßer 
150044d4804dSStefan Eßer 	// Error if the auto keyword appeared in the wrong place.
150150696a6eSStefan Eßer 	if (BC_ERR(!p->auto_part)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
150250696a6eSStefan Eßer 	bc_lex_next(&p->l);
150350696a6eSStefan Eßer 
150450696a6eSStefan Eßer 	p->auto_part = comma = false;
150550696a6eSStefan Eßer 
150644d4804dSStefan Eßer 	// We need at least one variable or array.
150744d4804dSStefan Eßer 	one = (p->l.t == BC_LEX_NAME);
150844d4804dSStefan Eßer 
150944d4804dSStefan Eßer 	// While we have a variable or array.
151078bc019dSStefan Eßer 	while (p->l.t == BC_LEX_NAME)
151178bc019dSStefan Eßer 	{
151250696a6eSStefan Eßer 		BcType t;
151350696a6eSStefan Eßer 
151444d4804dSStefan Eßer 		// Copy the name from the lexer, so we can use it again.
151550696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len - 1, p->l.str.v);
151650696a6eSStefan Eßer 
151750696a6eSStefan Eßer 		bc_lex_next(&p->l);
151850696a6eSStefan Eßer 
151944d4804dSStefan Eßer 		// If we are parsing an array...
152078bc019dSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET)
152178bc019dSStefan Eßer 		{
152250696a6eSStefan Eßer 			t = BC_TYPE_ARRAY;
152350696a6eSStefan Eßer 
152450696a6eSStefan Eßer 			bc_lex_next(&p->l);
152550696a6eSStefan Eßer 
152644d4804dSStefan Eßer 			// The brackets *must* be empty.
152750696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
152878bc019dSStefan Eßer 			{
152950696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
153078bc019dSStefan Eßer 			}
153150696a6eSStefan Eßer 
153250696a6eSStefan Eßer 			bc_lex_next(&p->l);
153350696a6eSStefan Eßer 		}
153450696a6eSStefan Eßer 		else t = BC_TYPE_VAR;
153550696a6eSStefan Eßer 
153644d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
153750696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
153850696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
153950696a6eSStefan Eßer 
154044d4804dSStefan Eßer 		// Insert the auto into the function.
154150696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
154250696a6eSStefan Eßer 	}
154350696a6eSStefan Eßer 
154444d4804dSStefan Eßer 	// If we have a comma, but no auto, barf.
154550696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
154644d4804dSStefan Eßer 
154744d4804dSStefan Eßer 	// If we don't have any variables or arrays, barf.
154850696a6eSStefan Eßer 	if (BC_ERR(!one)) bc_parse_err(p, BC_ERR_PARSE_NO_AUTO);
154944d4804dSStefan Eßer 
155044d4804dSStefan Eßer 	// The auto statement should be all that's in the statement.
155178bc019dSStefan Eßer 	if (BC_ERR(!bc_parse_isDelimiter(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
155250696a6eSStefan Eßer }
155350696a6eSStefan Eßer 
155444d4804dSStefan Eßer /**
155544d4804dSStefan Eßer  * Parses a body.
155644d4804dSStefan Eßer  * @param p      The parser.
155744d4804dSStefan Eßer  * @param brace  True if a brace was encountered, false otherwise.
155844d4804dSStefan Eßer  */
155978bc019dSStefan Eßer static void
bc_parse_body(BcParse * p,bool brace)156078bc019dSStefan Eßer bc_parse_body(BcParse* p, bool brace)
156178bc019dSStefan Eßer {
156250696a6eSStefan Eßer 	uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
156350696a6eSStefan Eßer 
156450696a6eSStefan Eßer 	assert(flag_ptr != NULL);
156550696a6eSStefan Eßer 	assert(p->flags.len >= 2);
156650696a6eSStefan Eßer 
156744d4804dSStefan Eßer 	// The body flag is for when we expect a body. We got a body, so clear the
156844d4804dSStefan Eßer 	// flag.
156950696a6eSStefan Eßer 	*flag_ptr &= ~(BC_PARSE_FLAG_BODY);
157050696a6eSStefan Eßer 
157144d4804dSStefan Eßer 	// If we are inside a function, that means we just barely entered it, and
157244d4804dSStefan Eßer 	// we can expect an auto list.
157378bc019dSStefan Eßer 	if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER)
157478bc019dSStefan Eßer 	{
157544d4804dSStefan Eßer 		// We *must* have a brace in this case.
157650696a6eSStefan Eßer 		if (BC_ERR(!brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
157750696a6eSStefan Eßer 
157850696a6eSStefan Eßer 		p->auto_part = (p->l.t != BC_LEX_KW_AUTO);
157950696a6eSStefan Eßer 
158078bc019dSStefan Eßer 		if (!p->auto_part)
158178bc019dSStefan Eßer 		{
158250696a6eSStefan Eßer 			// Make sure this is true to not get a parse error.
158350696a6eSStefan Eßer 			p->auto_part = true;
158450696a6eSStefan Eßer 
158544d4804dSStefan Eßer 			// Since we already have the auto keyword, parse.
158650696a6eSStefan Eßer 			bc_parse_auto(p);
158750696a6eSStefan Eßer 		}
158850696a6eSStefan Eßer 
158944d4804dSStefan Eßer 		// Eat a newline.
159050696a6eSStefan Eßer 		if (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
159150696a6eSStefan Eßer 	}
159278bc019dSStefan Eßer 	else
159378bc019dSStefan Eßer 	{
159444d4804dSStefan Eßer 		// This is the easy part.
159550696a6eSStefan Eßer 		size_t len = p->flags.len;
159650696a6eSStefan Eßer 
159750696a6eSStefan Eßer 		assert(*flag_ptr);
159850696a6eSStefan Eßer 
159944d4804dSStefan Eßer 		// Parse a statement.
160050696a6eSStefan Eßer 		bc_parse_stmt(p);
160150696a6eSStefan Eßer 
160244d4804dSStefan Eßer 		// This is a very important condition to get right. If there is no
160344d4804dSStefan Eßer 		// brace, and no body flag, and the flags len hasn't shrunk, then we
160444d4804dSStefan Eßer 		// have a body that was not delimited by braces, so we need to end it
160544d4804dSStefan Eßer 		// now, after just one statement.
160650696a6eSStefan Eßer 		if (!brace && !BC_PARSE_BODY(p) && len <= p->flags.len)
160778bc019dSStefan Eßer 		{
160850696a6eSStefan Eßer 			bc_parse_endBody(p, false);
160950696a6eSStefan Eßer 		}
161050696a6eSStefan Eßer 	}
161178bc019dSStefan Eßer }
161250696a6eSStefan Eßer 
161344d4804dSStefan Eßer /**
161444d4804dSStefan Eßer  * Parses a statement. This is the entry point for just about everything, except
161544d4804dSStefan Eßer  * function definitions.
161644d4804dSStefan Eßer  * @param p  The parser.
161744d4804dSStefan Eßer  */
161878bc019dSStefan Eßer static void
bc_parse_stmt(BcParse * p)161978bc019dSStefan Eßer bc_parse_stmt(BcParse* p)
162078bc019dSStefan Eßer {
162150696a6eSStefan Eßer 	size_t len;
162250696a6eSStefan Eßer 	uint16_t flags;
162350696a6eSStefan Eßer 	BcLexType type = p->l.t;
162450696a6eSStefan Eßer 
162544d4804dSStefan Eßer 	// Eat newline.
162678bc019dSStefan Eßer 	if (type == BC_LEX_NLINE)
162778bc019dSStefan Eßer 	{
162850696a6eSStefan Eßer 		bc_lex_next(&p->l);
162950696a6eSStefan Eßer 		return;
163050696a6eSStefan Eßer 	}
163144d4804dSStefan Eßer 
163244d4804dSStefan Eßer 	// Eat auto list.
163378bc019dSStefan Eßer 	if (type == BC_LEX_KW_AUTO)
163478bc019dSStefan Eßer 	{
163550696a6eSStefan Eßer 		bc_parse_auto(p);
163650696a6eSStefan Eßer 		return;
163750696a6eSStefan Eßer 	}
163850696a6eSStefan Eßer 
163944d4804dSStefan Eßer 	// If we reach this point, no auto list is allowed.
164050696a6eSStefan Eßer 	p->auto_part = false;
164150696a6eSStefan Eßer 
164244d4804dSStefan Eßer 	// Everything but an else needs to be taken care of here, but else is
164344d4804dSStefan Eßer 	// special.
164478bc019dSStefan Eßer 	if (type != BC_LEX_KW_ELSE)
164578bc019dSStefan Eßer 	{
164644d4804dSStefan Eßer 		// After an if, no else found.
164778bc019dSStefan Eßer 		if (BC_PARSE_IF_END(p))
164878bc019dSStefan Eßer 		{
164944d4804dSStefan Eßer 			// Clear the expectation for else, end body, and return. Returning
165044d4804dSStefan Eßer 			// gives us a clean slate for parsing again.
165150696a6eSStefan Eßer 			bc_parse_noElse(p);
165250696a6eSStefan Eßer 			if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
165378bc019dSStefan Eßer 			{
165450696a6eSStefan Eßer 				bc_parse_endBody(p, false);
165578bc019dSStefan Eßer 			}
165678bc019dSStefan Eßer 
165750696a6eSStefan Eßer 			return;
165850696a6eSStefan Eßer 		}
165944d4804dSStefan Eßer 		// With a left brace, we are parsing a body.
166078bc019dSStefan Eßer 		else if (type == BC_LEX_LBRACE)
166178bc019dSStefan Eßer 		{
166244d4804dSStefan Eßer 			// We need to start a body if we are not expecting one yet.
166378bc019dSStefan Eßer 			if (!BC_PARSE_BODY(p))
166478bc019dSStefan Eßer 			{
166550696a6eSStefan Eßer 				bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
166650696a6eSStefan Eßer 				bc_lex_next(&p->l);
166750696a6eSStefan Eßer 			}
166844d4804dSStefan Eßer 			// If we *are* expecting a body, that body should get a brace. This
166944d4804dSStefan Eßer 			// takes care of braces being on a different line than if and loop
167044d4804dSStefan Eßer 			// headers.
167178bc019dSStefan Eßer 			else
167278bc019dSStefan Eßer 			{
167350696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
167450696a6eSStefan Eßer 				bc_lex_next(&p->l);
167550696a6eSStefan Eßer 				bc_parse_body(p, true);
167650696a6eSStefan Eßer 			}
167750696a6eSStefan Eßer 
167844d4804dSStefan Eßer 			// If we have reached this point, we need to return for a clean
167944d4804dSStefan Eßer 			// slate.
168050696a6eSStefan Eßer 			return;
168150696a6eSStefan Eßer 		}
168244d4804dSStefan Eßer 		// This happens when we are expecting a body and get a single statement,
168344d4804dSStefan Eßer 		// i.e., a body with no braces surrounding it. Returns after for a clean
168444d4804dSStefan Eßer 		// slate.
168578bc019dSStefan Eßer 		else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p))
168678bc019dSStefan Eßer 		{
168750696a6eSStefan Eßer 			bc_parse_body(p, false);
168850696a6eSStefan Eßer 			return;
168950696a6eSStefan Eßer 		}
169050696a6eSStefan Eßer 	}
169150696a6eSStefan Eßer 
169250696a6eSStefan Eßer 	len = p->flags.len;
169350696a6eSStefan Eßer 	flags = BC_PARSE_TOP_FLAG(p);
169450696a6eSStefan Eßer 
169578bc019dSStefan Eßer 	switch (type)
169678bc019dSStefan Eßer 	{
169744d4804dSStefan Eßer 		// All of these are valid for expressions.
169850696a6eSStefan Eßer 		case BC_LEX_OP_INC:
169950696a6eSStefan Eßer 		case BC_LEX_OP_DEC:
170050696a6eSStefan Eßer 		case BC_LEX_OP_MINUS:
170150696a6eSStefan Eßer 		case BC_LEX_OP_BOOL_NOT:
170250696a6eSStefan Eßer 		case BC_LEX_LPAREN:
170350696a6eSStefan Eßer 		case BC_LEX_NAME:
170450696a6eSStefan Eßer 		case BC_LEX_NUMBER:
170550696a6eSStefan Eßer 		case BC_LEX_KW_IBASE:
170650696a6eSStefan Eßer 		case BC_LEX_KW_LAST:
170750696a6eSStefan Eßer 		case BC_LEX_KW_LENGTH:
170850696a6eSStefan Eßer 		case BC_LEX_KW_OBASE:
170950696a6eSStefan Eßer 		case BC_LEX_KW_SCALE:
171044d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
171150696a6eSStefan Eßer 		case BC_LEX_KW_SEED:
171244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
171350696a6eSStefan Eßer 		case BC_LEX_KW_SQRT:
171450696a6eSStefan Eßer 		case BC_LEX_KW_ABS:
1715d101cdd6SStefan Eßer 		case BC_LEX_KW_IS_NUMBER:
1716d101cdd6SStefan Eßer 		case BC_LEX_KW_IS_STRING:
171744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
171850696a6eSStefan Eßer 		case BC_LEX_KW_IRAND:
171944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
172044d4804dSStefan Eßer 		case BC_LEX_KW_ASCIIFY:
172144d4804dSStefan Eßer 		case BC_LEX_KW_MODEXP:
172244d4804dSStefan Eßer 		case BC_LEX_KW_DIVMOD:
172350696a6eSStefan Eßer 		case BC_LEX_KW_READ:
172444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
172550696a6eSStefan Eßer 		case BC_LEX_KW_RAND:
172644d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
172750696a6eSStefan Eßer 		case BC_LEX_KW_MAXIBASE:
172850696a6eSStefan Eßer 		case BC_LEX_KW_MAXOBASE:
172950696a6eSStefan Eßer 		case BC_LEX_KW_MAXSCALE:
173044d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
173150696a6eSStefan Eßer 		case BC_LEX_KW_MAXRAND:
173244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1733d43fa8efSStefan Eßer 		case BC_LEX_KW_LINE_LENGTH:
1734d43fa8efSStefan Eßer 		case BC_LEX_KW_GLOBAL_STACKS:
1735d43fa8efSStefan Eßer 		case BC_LEX_KW_LEADING_ZERO:
173650696a6eSStefan Eßer 		{
173750696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
173850696a6eSStefan Eßer 			break;
173950696a6eSStefan Eßer 		}
174050696a6eSStefan Eßer 
174150696a6eSStefan Eßer 		case BC_LEX_KW_ELSE:
174250696a6eSStefan Eßer 		{
174350696a6eSStefan Eßer 			bc_parse_else(p);
174450696a6eSStefan Eßer 			break;
174550696a6eSStefan Eßer 		}
174650696a6eSStefan Eßer 
174744d4804dSStefan Eßer 		// Just eat.
174850696a6eSStefan Eßer 		case BC_LEX_SCOLON:
174950696a6eSStefan Eßer 		{
175050696a6eSStefan Eßer 			// Do nothing.
175150696a6eSStefan Eßer 			break;
175250696a6eSStefan Eßer 		}
175350696a6eSStefan Eßer 
175450696a6eSStefan Eßer 		case BC_LEX_RBRACE:
175550696a6eSStefan Eßer 		{
175650696a6eSStefan Eßer 			bc_parse_endBody(p, true);
175750696a6eSStefan Eßer 			break;
175850696a6eSStefan Eßer 		}
175950696a6eSStefan Eßer 
176050696a6eSStefan Eßer 		case BC_LEX_STR:
176150696a6eSStefan Eßer 		{
176250696a6eSStefan Eßer 			bc_parse_str(p, BC_INST_PRINT_STR);
176350696a6eSStefan Eßer 			break;
176450696a6eSStefan Eßer 		}
176550696a6eSStefan Eßer 
176650696a6eSStefan Eßer 		case BC_LEX_KW_BREAK:
176750696a6eSStefan Eßer 		case BC_LEX_KW_CONTINUE:
176850696a6eSStefan Eßer 		{
176950696a6eSStefan Eßer 			bc_parse_loopExit(p, p->l.t);
177050696a6eSStefan Eßer 			break;
177150696a6eSStefan Eßer 		}
177250696a6eSStefan Eßer 
177350696a6eSStefan Eßer 		case BC_LEX_KW_FOR:
177450696a6eSStefan Eßer 		{
177550696a6eSStefan Eßer 			bc_parse_for(p);
177650696a6eSStefan Eßer 			break;
177750696a6eSStefan Eßer 		}
177850696a6eSStefan Eßer 
177950696a6eSStefan Eßer 		case BC_LEX_KW_HALT:
178050696a6eSStefan Eßer 		{
178150696a6eSStefan Eßer 			bc_parse_push(p, BC_INST_HALT);
178250696a6eSStefan Eßer 			bc_lex_next(&p->l);
178350696a6eSStefan Eßer 			break;
178450696a6eSStefan Eßer 		}
178550696a6eSStefan Eßer 
178650696a6eSStefan Eßer 		case BC_LEX_KW_IF:
178750696a6eSStefan Eßer 		{
178850696a6eSStefan Eßer 			bc_parse_if(p);
178950696a6eSStefan Eßer 			break;
179050696a6eSStefan Eßer 		}
179150696a6eSStefan Eßer 
179250696a6eSStefan Eßer 		case BC_LEX_KW_LIMITS:
179350696a6eSStefan Eßer 		{
179444d4804dSStefan Eßer 			// `limits` is a compile-time command, so execute it right away.
179550696a6eSStefan Eßer 			bc_vm_printf("BC_LONG_BIT      = %lu\n", (ulong) BC_LONG_BIT);
179650696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_DIGS     = %lu\n", (ulong) BC_BASE_DIGS);
179750696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_POW      = %lu\n", (ulong) BC_BASE_POW);
179850696a6eSStefan Eßer 			bc_vm_printf("BC_OVERFLOW_MAX  = %lu\n", (ulong) BC_NUM_BIGDIG_MAX);
179950696a6eSStefan Eßer 			bc_vm_printf("\n");
180050696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_MAX      = %lu\n", BC_MAX_OBASE);
180150696a6eSStefan Eßer 			bc_vm_printf("BC_DIM_MAX       = %lu\n", BC_MAX_DIM);
180250696a6eSStefan Eßer 			bc_vm_printf("BC_SCALE_MAX     = %lu\n", BC_MAX_SCALE);
180350696a6eSStefan Eßer 			bc_vm_printf("BC_STRING_MAX    = %lu\n", BC_MAX_STRING);
180450696a6eSStefan Eßer 			bc_vm_printf("BC_NAME_MAX      = %lu\n", BC_MAX_NAME);
180550696a6eSStefan Eßer 			bc_vm_printf("BC_NUM_MAX       = %lu\n", BC_MAX_NUM);
180644d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
180750696a6eSStefan Eßer 			bc_vm_printf("BC_RAND_MAX      = %lu\n", BC_MAX_RAND);
180844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
180950696a6eSStefan Eßer 			bc_vm_printf("MAX Exponent     = %lu\n", BC_MAX_EXP);
181050696a6eSStefan Eßer 			bc_vm_printf("Number of vars   = %lu\n", BC_MAX_VARS);
181150696a6eSStefan Eßer 
181250696a6eSStefan Eßer 			bc_lex_next(&p->l);
181350696a6eSStefan Eßer 
181450696a6eSStefan Eßer 			break;
181550696a6eSStefan Eßer 		}
181650696a6eSStefan Eßer 
181744d4804dSStefan Eßer 		case BC_LEX_KW_STREAM:
181850696a6eSStefan Eßer 		case BC_LEX_KW_PRINT:
181950696a6eSStefan Eßer 		{
182044d4804dSStefan Eßer 			bc_parse_print(p, type);
182150696a6eSStefan Eßer 			break;
182250696a6eSStefan Eßer 		}
182350696a6eSStefan Eßer 
182450696a6eSStefan Eßer 		case BC_LEX_KW_QUIT:
182550696a6eSStefan Eßer 		{
182644d4804dSStefan Eßer 			// Quit is a compile-time command. We don't exit directly, so the vm
182744d4804dSStefan Eßer 			// can clean up.
1828d101cdd6SStefan Eßer 			vm->status = BC_STATUS_QUIT;
182944d4804dSStefan Eßer 			BC_JMP;
183050696a6eSStefan Eßer 			break;
183150696a6eSStefan Eßer 		}
183250696a6eSStefan Eßer 
183350696a6eSStefan Eßer 		case BC_LEX_KW_RETURN:
183450696a6eSStefan Eßer 		{
183550696a6eSStefan Eßer 			bc_parse_return(p);
183650696a6eSStefan Eßer 			break;
183750696a6eSStefan Eßer 		}
183850696a6eSStefan Eßer 
183950696a6eSStefan Eßer 		case BC_LEX_KW_WHILE:
184050696a6eSStefan Eßer 		{
184150696a6eSStefan Eßer 			bc_parse_while(p);
184250696a6eSStefan Eßer 			break;
184350696a6eSStefan Eßer 		}
184450696a6eSStefan Eßer 
1845d101cdd6SStefan Eßer 		case BC_LEX_EOF:
1846d101cdd6SStefan Eßer 		case BC_LEX_INVALID:
1847d101cdd6SStefan Eßer 		case BC_LEX_NEG:
1848d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH
1849d101cdd6SStefan Eßer 		case BC_LEX_OP_TRUNC:
1850d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1851d101cdd6SStefan Eßer 		case BC_LEX_OP_POWER:
1852d101cdd6SStefan Eßer 		case BC_LEX_OP_MULTIPLY:
1853d101cdd6SStefan Eßer 		case BC_LEX_OP_DIVIDE:
1854d101cdd6SStefan Eßer 		case BC_LEX_OP_MODULUS:
1855d101cdd6SStefan Eßer 		case BC_LEX_OP_PLUS:
1856d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH
1857d101cdd6SStefan Eßer 		case BC_LEX_OP_PLACES:
1858d101cdd6SStefan Eßer 		case BC_LEX_OP_LSHIFT:
1859d101cdd6SStefan Eßer 		case BC_LEX_OP_RSHIFT:
1860d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1861d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_EQ:
1862d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_LE:
1863d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_GE:
1864d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_NE:
1865d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_LT:
1866d101cdd6SStefan Eßer 		case BC_LEX_OP_REL_GT:
1867d101cdd6SStefan Eßer 		case BC_LEX_OP_BOOL_OR:
1868d101cdd6SStefan Eßer 		case BC_LEX_OP_BOOL_AND:
1869d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_POWER:
1870d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_MULTIPLY:
1871d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_DIVIDE:
1872d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_MODULUS:
1873d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_PLUS:
1874d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_MINUS:
1875d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH
1876d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_PLACES:
1877d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_LSHIFT:
1878d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN_RSHIFT:
1879d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1880d101cdd6SStefan Eßer 		case BC_LEX_OP_ASSIGN:
1881d101cdd6SStefan Eßer 		case BC_LEX_NLINE:
1882d101cdd6SStefan Eßer 		case BC_LEX_WHITESPACE:
1883d101cdd6SStefan Eßer 		case BC_LEX_RPAREN:
1884d101cdd6SStefan Eßer 		case BC_LEX_LBRACKET:
1885d101cdd6SStefan Eßer 		case BC_LEX_COMMA:
1886d101cdd6SStefan Eßer 		case BC_LEX_RBRACKET:
1887d101cdd6SStefan Eßer 		case BC_LEX_LBRACE:
1888d101cdd6SStefan Eßer 		case BC_LEX_KW_AUTO:
1889d101cdd6SStefan Eßer 		case BC_LEX_KW_DEFINE:
1890d101cdd6SStefan Eßer #if DC_ENABLED
1891103d7cdfSStefan Eßer 		case BC_LEX_EXTENDED_REGISTERS:
1892d101cdd6SStefan Eßer 		case BC_LEX_EQ_NO_REG:
1893d101cdd6SStefan Eßer 		case BC_LEX_COLON:
1894d101cdd6SStefan Eßer 		case BC_LEX_EXECUTE:
1895d101cdd6SStefan Eßer 		case BC_LEX_PRINT_STACK:
1896d101cdd6SStefan Eßer 		case BC_LEX_CLEAR_STACK:
1897d101cdd6SStefan Eßer 		case BC_LEX_REG_STACK_LEVEL:
1898d101cdd6SStefan Eßer 		case BC_LEX_STACK_LEVEL:
1899d101cdd6SStefan Eßer 		case BC_LEX_DUPLICATE:
1900d101cdd6SStefan Eßer 		case BC_LEX_SWAP:
1901d101cdd6SStefan Eßer 		case BC_LEX_POP:
1902d101cdd6SStefan Eßer 		case BC_LEX_STORE_IBASE:
1903d101cdd6SStefan Eßer 		case BC_LEX_STORE_OBASE:
1904d101cdd6SStefan Eßer 		case BC_LEX_STORE_SCALE:
1905d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH
1906d101cdd6SStefan Eßer 		case BC_LEX_STORE_SEED:
1907d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1908d101cdd6SStefan Eßer 		case BC_LEX_LOAD:
1909d101cdd6SStefan Eßer 		case BC_LEX_LOAD_POP:
1910d101cdd6SStefan Eßer 		case BC_LEX_STORE_PUSH:
1911d101cdd6SStefan Eßer 		case BC_LEX_PRINT_POP:
1912d101cdd6SStefan Eßer 		case BC_LEX_NQUIT:
1913d101cdd6SStefan Eßer 		case BC_LEX_EXEC_STACK_LENGTH:
1914d101cdd6SStefan Eßer 		case BC_LEX_SCALE_FACTOR:
1915d101cdd6SStefan Eßer 		case BC_LEX_ARRAY_LENGTH:
1916d101cdd6SStefan Eßer #endif // DC_ENABLED
191750696a6eSStefan Eßer 		{
191850696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
191950696a6eSStefan Eßer 		}
192050696a6eSStefan Eßer 	}
192150696a6eSStefan Eßer 
192244d4804dSStefan Eßer 	// If the flags did not change, we expect a delimiter.
192378bc019dSStefan Eßer 	if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p))
192478bc019dSStefan Eßer 	{
192550696a6eSStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p)))
192678bc019dSStefan Eßer 		{
192750696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
192850696a6eSStefan Eßer 		}
192978bc019dSStefan Eßer 	}
193050696a6eSStefan Eßer 
193150696a6eSStefan Eßer 	// Make sure semicolons are eaten.
1932d101cdd6SStefan Eßer 	while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE)
193378bc019dSStefan Eßer 	{
193478bc019dSStefan Eßer 		bc_lex_next(&p->l);
193578bc019dSStefan Eßer 	}
193610041e99SStefan Eßer 
193710041e99SStefan Eßer 	// POSIX's grammar does not allow a function definition after a semicolon
193810041e99SStefan Eßer 	// without a newline, so check specifically for that case and error if
193910041e99SStefan Eßer 	// the POSIX standard flag is set.
194010041e99SStefan Eßer 	if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX)
194110041e99SStefan Eßer 	{
194210041e99SStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON);
194310041e99SStefan Eßer 	}
194450696a6eSStefan Eßer }
194550696a6eSStefan Eßer 
194678bc019dSStefan Eßer void
bc_parse_parse(BcParse * p)194778bc019dSStefan Eßer bc_parse_parse(BcParse* p)
194878bc019dSStefan Eßer {
194950696a6eSStefan Eßer 	assert(p);
195050696a6eSStefan Eßer 
1951d101cdd6SStefan Eßer 	BC_SETJMP_LOCKED(vm, exit);
195250696a6eSStefan Eßer 
195344d4804dSStefan Eßer 	// We should not let an EOF get here unless some partial parse was not
195444d4804dSStefan Eßer 	// completed, in which case, it's the user's fault.
195550696a6eSStefan Eßer 	if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
195644d4804dSStefan Eßer 
195744d4804dSStefan Eßer 	// Functions need special parsing.
195878bc019dSStefan Eßer 	else if (p->l.t == BC_LEX_KW_DEFINE)
195978bc019dSStefan Eßer 	{
196078bc019dSStefan Eßer 		if (BC_ERR(BC_PARSE_NO_EXEC(p)))
196178bc019dSStefan Eßer 		{
1962a30efc5cSStefan Eßer 			bc_parse_endif(p);
1963a30efc5cSStefan Eßer 			if (BC_ERR(BC_PARSE_NO_EXEC(p)))
196478bc019dSStefan Eßer 			{
1965a30efc5cSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1966d43fa8efSStefan Eßer 			}
196778bc019dSStefan Eßer 		}
196850696a6eSStefan Eßer 		bc_parse_func(p);
196950696a6eSStefan Eßer 	}
197044d4804dSStefan Eßer 
197144d4804dSStefan Eßer 	// Otherwise, parse a normal statement.
197250696a6eSStefan Eßer 	else bc_parse_stmt(p);
197350696a6eSStefan Eßer 
197450696a6eSStefan Eßer exit:
197544d4804dSStefan Eßer 
197644d4804dSStefan Eßer 	// We need to reset on error.
1977d101cdd6SStefan Eßer 	if (BC_ERR(((vm->status && vm->status != BC_STATUS_QUIT) || vm->sig != 0)))
197878bc019dSStefan Eßer 	{
197950696a6eSStefan Eßer 		bc_parse_reset(p);
198078bc019dSStefan Eßer 	}
198144d4804dSStefan Eßer 
1982d101cdd6SStefan Eßer 	BC_LONGJMP_CONT(vm);
198310041e99SStefan Eßer 	BC_SIG_MAYLOCK;
198450696a6eSStefan Eßer }
198550696a6eSStefan Eßer 
198644d4804dSStefan Eßer /**
198744d4804dSStefan Eßer  * Parse an expression. This is the actual implementation of the Shunting-Yard
198844d4804dSStefan Eßer  * Algorithm.
198944d4804dSStefan Eßer  * @param p      The parser.
199044d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
199144d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
199244d4804dSStefan Eßer  * @return       A parse status. In some places, an empty expression is an
199344d4804dSStefan Eßer  *               error, and sometimes, it is required. This allows this function
199444d4804dSStefan Eßer  *               to tell the caller if the expression was empty and let the
199544d4804dSStefan Eßer  *               caller handle it.
199644d4804dSStefan Eßer  */
199778bc019dSStefan Eßer static BcParseStatus
bc_parse_expr_err(BcParse * p,uint8_t flags,BcParseNext next)199878bc019dSStefan Eßer bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next)
199950696a6eSStefan Eßer {
200050696a6eSStefan Eßer 	BcInst prev = BC_INST_PRINT;
200150696a6eSStefan Eßer 	uchar inst = BC_INST_INVALID;
200244d4804dSStefan Eßer 	BcLexType top, t;
200344d4804dSStefan Eßer 	size_t nexprs, ops_bgn;
200450696a6eSStefan Eßer 	uint32_t i, nparens, nrelops;
200550696a6eSStefan Eßer 	bool pfirst, rprn, done, get_token, assign, bin_last, incdec, can_assign;
200650696a6eSStefan Eßer 
200744d4804dSStefan Eßer 	// One of these *must* be true.
200850696a6eSStefan Eßer 	assert(!(flags & BC_PARSE_PRINT) || !(flags & BC_PARSE_NEEDVAL));
200950696a6eSStefan Eßer 
201044d4804dSStefan Eßer 	// These are set very carefully. In fact, controlling the values of these
201144d4804dSStefan Eßer 	// locals is the biggest part of making this work. ops_bgn especially is
201244d4804dSStefan Eßer 	// important because it marks where the operator stack begins for *this*
201344d4804dSStefan Eßer 	// invocation of this function. That's because bc_parse_expr_err() is
201444d4804dSStefan Eßer 	// recursive (the Shunting-Yard Algorithm is most easily expressed
201544d4804dSStefan Eßer 	// recursively when parsing subexpressions), and each invocation needs to
201644d4804dSStefan Eßer 	// know where to stop.
201744d4804dSStefan Eßer 	//
201844d4804dSStefan Eßer 	// - nparens is the number of left parens without matches.
201944d4804dSStefan Eßer 	// - nrelops is the number of relational operators that appear in the expr.
202044d4804dSStefan Eßer 	// - nexprs is the number of unused expressions.
202144d4804dSStefan Eßer 	// - rprn is a right paren encountered last.
202244d4804dSStefan Eßer 	// - done means the expression has been fully parsed.
202344d4804dSStefan Eßer 	// - get_token is true when a token is needed at the end of an iteration.
202444d4804dSStefan Eßer 	// - assign is true when an assignment statement was parsed last.
202544d4804dSStefan Eßer 	// - incdec is true when the previous operator was an inc or dec operator.
202644d4804dSStefan Eßer 	// - can_assign is true when an assignemnt is valid.
202744d4804dSStefan Eßer 	// - bin_last is true when the previous instruction was a binary operator.
202844d4804dSStefan Eßer 	t = p->l.t;
202950696a6eSStefan Eßer 	pfirst = (p->l.t == BC_LEX_LPAREN);
203050696a6eSStefan Eßer 	nparens = nrelops = 0;
203144d4804dSStefan Eßer 	nexprs = 0;
203244d4804dSStefan Eßer 	ops_bgn = p->ops.len;
203350696a6eSStefan Eßer 	rprn = done = get_token = assign = incdec = can_assign = false;
203450696a6eSStefan Eßer 	bin_last = true;
203550696a6eSStefan Eßer 
203650696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
203750696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
203878bc019dSStefan Eßer 	if (!(flags & BC_PARSE_NOREAD))
203978bc019dSStefan Eßer 	{
204078bc019dSStefan Eßer 		while ((t = p->l.t) == BC_LEX_NLINE)
204178bc019dSStefan Eßer 		{
204278bc019dSStefan Eßer 			bc_lex_next(&p->l);
204378bc019dSStefan Eßer 		}
204450696a6eSStefan Eßer 	}
204550696a6eSStefan Eßer 
204644d4804dSStefan Eßer 	// This is the Shunting-Yard algorithm loop.
204750696a6eSStefan Eßer 	for (; !done && BC_PARSE_EXPR(t); t = p->l.t)
204850696a6eSStefan Eßer 	{
204978bc019dSStefan Eßer 		switch (t)
205078bc019dSStefan Eßer 		{
205150696a6eSStefan Eßer 			case BC_LEX_OP_INC:
205250696a6eSStefan Eßer 			case BC_LEX_OP_DEC:
205350696a6eSStefan Eßer 			{
205444d4804dSStefan Eßer 				// These operators can only be used with items that can be
205544d4804dSStefan Eßer 				// assigned to.
205650696a6eSStefan Eßer 				if (BC_ERR(incdec)) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
205744d4804dSStefan Eßer 
205850696a6eSStefan Eßer 				bc_parse_incdec(p, &prev, &can_assign, &nexprs, flags);
205944d4804dSStefan Eßer 
206050696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
206150696a6eSStefan Eßer 				incdec = true;
206250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
206344d4804dSStefan Eßer 
206450696a6eSStefan Eßer 				break;
206550696a6eSStefan Eßer 			}
206650696a6eSStefan Eßer 
206750696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
206850696a6eSStefan Eßer 			case BC_LEX_OP_TRUNC:
206950696a6eSStefan Eßer 			{
207044d4804dSStefan Eßer 				// The previous token must have been a leaf expression, or the
207144d4804dSStefan Eßer 				// operator is in the wrong place.
207250696a6eSStefan Eßer 				if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn)))
207378bc019dSStefan Eßer 				{
207450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_TOKEN);
207578bc019dSStefan Eßer 				}
207650696a6eSStefan Eßer 
207750696a6eSStefan Eßer 				// I can just add the instruction because
207850696a6eSStefan Eßer 				// negative will already be taken care of.
207950696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_TRUNC);
208044d4804dSStefan Eßer 
208150696a6eSStefan Eßer 				rprn = can_assign = incdec = false;
208250696a6eSStefan Eßer 				get_token = true;
208350696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
208444d4804dSStefan Eßer 
208550696a6eSStefan Eßer 				break;
208650696a6eSStefan Eßer 			}
208750696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
208850696a6eSStefan Eßer 
208950696a6eSStefan Eßer 			case BC_LEX_OP_MINUS:
209050696a6eSStefan Eßer 			{
209150696a6eSStefan Eßer 				bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
209244d4804dSStefan Eßer 
209350696a6eSStefan Eßer 				rprn = get_token = can_assign = false;
209444d4804dSStefan Eßer 
209544d4804dSStefan Eßer 				// This is true if it was a binary operator last.
209650696a6eSStefan Eßer 				bin_last = (prev == BC_INST_MINUS);
209750696a6eSStefan Eßer 				if (bin_last) incdec = false;
209844d4804dSStefan Eßer 
209950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
210044d4804dSStefan Eßer 
210150696a6eSStefan Eßer 				break;
210250696a6eSStefan Eßer 			}
210350696a6eSStefan Eßer 
210444d4804dSStefan Eßer 			// All of this group, including the fallthrough, is to parse binary
210544d4804dSStefan Eßer 			// operators.
210650696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_POWER:
210750696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MULTIPLY:
210850696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_DIVIDE:
210950696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MODULUS:
211050696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLUS:
211150696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MINUS:
211250696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
211350696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLACES:
211450696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_LSHIFT:
211550696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_RSHIFT:
211650696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
211750696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN:
211850696a6eSStefan Eßer 			{
211944d4804dSStefan Eßer 				// We need to make sure the assignment is valid.
212050696a6eSStefan Eßer 				if (!BC_PARSE_INST_VAR(prev))
212178bc019dSStefan Eßer 				{
212250696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
212350696a6eSStefan Eßer 				}
212478bc019dSStefan Eßer 
212550696a6eSStefan Eßer 				// Fallthrough.
212650696a6eSStefan Eßer 				BC_FALLTHROUGH
212778bc019dSStefan Eßer 			}
212850696a6eSStefan Eßer 
212950696a6eSStefan Eßer 			case BC_LEX_OP_POWER:
213050696a6eSStefan Eßer 			case BC_LEX_OP_MULTIPLY:
213150696a6eSStefan Eßer 			case BC_LEX_OP_DIVIDE:
213250696a6eSStefan Eßer 			case BC_LEX_OP_MODULUS:
213350696a6eSStefan Eßer 			case BC_LEX_OP_PLUS:
213450696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
213550696a6eSStefan Eßer 			case BC_LEX_OP_PLACES:
213650696a6eSStefan Eßer 			case BC_LEX_OP_LSHIFT:
213750696a6eSStefan Eßer 			case BC_LEX_OP_RSHIFT:
213850696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
213950696a6eSStefan Eßer 			case BC_LEX_OP_REL_EQ:
214050696a6eSStefan Eßer 			case BC_LEX_OP_REL_LE:
214150696a6eSStefan Eßer 			case BC_LEX_OP_REL_GE:
214250696a6eSStefan Eßer 			case BC_LEX_OP_REL_NE:
214350696a6eSStefan Eßer 			case BC_LEX_OP_REL_LT:
214450696a6eSStefan Eßer 			case BC_LEX_OP_REL_GT:
214550696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_NOT:
214650696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_OR:
214750696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_AND:
214850696a6eSStefan Eßer 			{
214944d4804dSStefan Eßer 				// This is true if the operator if the token is a prefix
215044d4804dSStefan Eßer 				// operator. This is only for boolean not.
215178bc019dSStefan Eßer 				if (BC_PARSE_OP_PREFIX(t))
215278bc019dSStefan Eßer 				{
215344d4804dSStefan Eßer 					// Prefix operators are only allowed after binary operators
215444d4804dSStefan Eßer 					// or prefix operators.
215550696a6eSStefan Eßer 					if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last)))
215678bc019dSStefan Eßer 					{
215750696a6eSStefan Eßer 						bc_parse_err(p, BC_ERR_PARSE_EXPR);
215850696a6eSStefan Eßer 					}
215978bc019dSStefan Eßer 				}
216044d4804dSStefan Eßer 				// If we execute the else, that means we have a binary operator.
216144d4804dSStefan Eßer 				// If the previous operator was a prefix or a binary operator,
216244d4804dSStefan Eßer 				// then a binary operator is not allowed.
216350696a6eSStefan Eßer 				else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last))
216478bc019dSStefan Eßer 				{
216550696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
216678bc019dSStefan Eßer 				}
216750696a6eSStefan Eßer 
216850696a6eSStefan Eßer 				nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
216950696a6eSStefan Eßer 				prev = BC_PARSE_TOKEN_INST(t);
217044d4804dSStefan Eßer 
217150696a6eSStefan Eßer 				bc_parse_operator(p, t, ops_bgn, &nexprs);
217244d4804dSStefan Eßer 
217350696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
217450696a6eSStefan Eßer 				get_token = true;
217550696a6eSStefan Eßer 				bin_last = !BC_PARSE_OP_PREFIX(t);
217650696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
217750696a6eSStefan Eßer 
217850696a6eSStefan Eßer 				break;
217950696a6eSStefan Eßer 			}
218050696a6eSStefan Eßer 
218150696a6eSStefan Eßer 			case BC_LEX_LPAREN:
218250696a6eSStefan Eßer 			{
218344d4804dSStefan Eßer 				// A left paren is *not* allowed right after a leaf expr.
218450696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
218578bc019dSStefan Eßer 				{
218650696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
218778bc019dSStefan Eßer 				}
218850696a6eSStefan Eßer 
218950696a6eSStefan Eßer 				nparens += 1;
219050696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
219150696a6eSStefan Eßer 				get_token = true;
219244d4804dSStefan Eßer 
219344d4804dSStefan Eßer 				// Push the paren onto the operator stack.
219450696a6eSStefan Eßer 				bc_vec_push(&p->ops, &t);
219550696a6eSStefan Eßer 
219650696a6eSStefan Eßer 				break;
219750696a6eSStefan Eßer 			}
219850696a6eSStefan Eßer 
219950696a6eSStefan Eßer 			case BC_LEX_RPAREN:
220050696a6eSStefan Eßer 			{
220144d4804dSStefan Eßer 				// This needs to be a status. The error is handled in
220244d4804dSStefan Eßer 				// bc_parse_expr_status().
220350696a6eSStefan Eßer 				if (BC_ERR(p->l.last == BC_LEX_LPAREN))
220478bc019dSStefan Eßer 				{
220550696a6eSStefan Eßer 					return BC_PARSE_STATUS_EMPTY_EXPR;
220678bc019dSStefan Eßer 				}
220750696a6eSStefan Eßer 
220844d4804dSStefan Eßer 				// The right paren must not come after a prefix or binary
220944d4804dSStefan Eßer 				// operator.
221050696a6eSStefan Eßer 				if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev)))
221178bc019dSStefan Eßer 				{
221250696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
221378bc019dSStefan Eßer 				}
221450696a6eSStefan Eßer 
221544d4804dSStefan Eßer 				// If there are no parens left, we are done, but we need another
221644d4804dSStefan Eßer 				// token.
221778bc019dSStefan Eßer 				if (!nparens)
221878bc019dSStefan Eßer 				{
221950696a6eSStefan Eßer 					done = true;
222050696a6eSStefan Eßer 					get_token = false;
222150696a6eSStefan Eßer 					break;
222250696a6eSStefan Eßer 				}
222350696a6eSStefan Eßer 
222450696a6eSStefan Eßer 				nparens -= 1;
222550696a6eSStefan Eßer 				rprn = true;
222650696a6eSStefan Eßer 				get_token = bin_last = incdec = false;
222750696a6eSStefan Eßer 
222850696a6eSStefan Eßer 				bc_parse_rightParen(p, &nexprs);
222950696a6eSStefan Eßer 
223050696a6eSStefan Eßer 				break;
223150696a6eSStefan Eßer 			}
223250696a6eSStefan Eßer 
223344d4804dSStefan Eßer 			case BC_LEX_STR:
223444d4804dSStefan Eßer 			{
223544d4804dSStefan Eßer 				// POSIX only allows strings alone.
223644d4804dSStefan Eßer 				if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_EXPR_STRING);
223744d4804dSStefan Eßer 
223844d4804dSStefan Eßer 				// A string is a leaf and cannot come right after a leaf.
223944d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
224078bc019dSStefan Eßer 				{
224144d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
224278bc019dSStefan Eßer 				}
224344d4804dSStefan Eßer 
224444d4804dSStefan Eßer 				bc_parse_addString(p);
224544d4804dSStefan Eßer 
224644d4804dSStefan Eßer 				get_token = true;
224744d4804dSStefan Eßer 				bin_last = rprn = false;
224844d4804dSStefan Eßer 				nexprs += 1;
224944d4804dSStefan Eßer 
225044d4804dSStefan Eßer 				break;
225144d4804dSStefan Eßer 			}
225244d4804dSStefan Eßer 
225350696a6eSStefan Eßer 			case BC_LEX_NAME:
225450696a6eSStefan Eßer 			{
225544d4804dSStefan Eßer 				// A name is a leaf and cannot come right after a leaf.
225650696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
225778bc019dSStefan Eßer 				{
225850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
225978bc019dSStefan Eßer 				}
226050696a6eSStefan Eßer 
226150696a6eSStefan Eßer 				get_token = bin_last = false;
226244d4804dSStefan Eßer 
226344d4804dSStefan Eßer 				bc_parse_name(p, &prev, &can_assign, flags & ~BC_PARSE_NOCALL);
226444d4804dSStefan Eßer 
226550696a6eSStefan Eßer 				rprn = (prev == BC_INST_CALL);
226650696a6eSStefan Eßer 				nexprs += 1;
226750696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
226850696a6eSStefan Eßer 
226950696a6eSStefan Eßer 				break;
227050696a6eSStefan Eßer 			}
227150696a6eSStefan Eßer 
227250696a6eSStefan Eßer 			case BC_LEX_NUMBER:
227350696a6eSStefan Eßer 			{
227444d4804dSStefan Eßer 				// A number is a leaf and cannot come right after a leaf.
227550696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
227678bc019dSStefan Eßer 				{
227750696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
227878bc019dSStefan Eßer 				}
227950696a6eSStefan Eßer 
228044d4804dSStefan Eßer 				// The number instruction is pushed in here.
228150696a6eSStefan Eßer 				bc_parse_number(p);
228244d4804dSStefan Eßer 
228350696a6eSStefan Eßer 				nexprs += 1;
228450696a6eSStefan Eßer 				prev = BC_INST_NUM;
228550696a6eSStefan Eßer 				get_token = true;
228650696a6eSStefan Eßer 				rprn = bin_last = can_assign = false;
228750696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
228850696a6eSStefan Eßer 
228950696a6eSStefan Eßer 				break;
229050696a6eSStefan Eßer 			}
229150696a6eSStefan Eßer 
229250696a6eSStefan Eßer 			case BC_LEX_KW_IBASE:
229350696a6eSStefan Eßer 			case BC_LEX_KW_LAST:
229450696a6eSStefan Eßer 			case BC_LEX_KW_OBASE:
229544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
229650696a6eSStefan Eßer 			case BC_LEX_KW_SEED:
229744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
229850696a6eSStefan Eßer 			{
229944d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
230050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
230178bc019dSStefan Eßer 				{
230250696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
230378bc019dSStefan Eßer 				}
230450696a6eSStefan Eßer 
230550696a6eSStefan Eßer 				prev = t - BC_LEX_KW_LAST + BC_INST_LAST;
230650696a6eSStefan Eßer 				bc_parse_push(p, prev);
230750696a6eSStefan Eßer 
230850696a6eSStefan Eßer 				get_token = can_assign = true;
230950696a6eSStefan Eßer 				rprn = bin_last = false;
231050696a6eSStefan Eßer 				nexprs += 1;
231150696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
231250696a6eSStefan Eßer 
231350696a6eSStefan Eßer 				break;
231450696a6eSStefan Eßer 			}
231550696a6eSStefan Eßer 
231650696a6eSStefan Eßer 			case BC_LEX_KW_LENGTH:
231750696a6eSStefan Eßer 			case BC_LEX_KW_SQRT:
231850696a6eSStefan Eßer 			case BC_LEX_KW_ABS:
2319d101cdd6SStefan Eßer 			case BC_LEX_KW_IS_NUMBER:
2320d101cdd6SStefan Eßer 			case BC_LEX_KW_IS_STRING:
232144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
232250696a6eSStefan Eßer 			case BC_LEX_KW_IRAND:
232344d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
232444d4804dSStefan Eßer 			case BC_LEX_KW_ASCIIFY:
232550696a6eSStefan Eßer 			{
232644d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
232750696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
232878bc019dSStefan Eßer 				{
232950696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
233078bc019dSStefan Eßer 				}
233150696a6eSStefan Eßer 
233250696a6eSStefan Eßer 				bc_parse_builtin(p, t, flags, &prev);
233344d4804dSStefan Eßer 
233450696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
233550696a6eSStefan Eßer 				nexprs += 1;
233650696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
233750696a6eSStefan Eßer 
233850696a6eSStefan Eßer 				break;
233950696a6eSStefan Eßer 			}
234050696a6eSStefan Eßer 
234150696a6eSStefan Eßer 			case BC_LEX_KW_READ:
234244d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
234350696a6eSStefan Eßer 			case BC_LEX_KW_RAND:
234444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
234550696a6eSStefan Eßer 			case BC_LEX_KW_MAXIBASE:
234650696a6eSStefan Eßer 			case BC_LEX_KW_MAXOBASE:
234750696a6eSStefan Eßer 			case BC_LEX_KW_MAXSCALE:
234844d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
234950696a6eSStefan Eßer 			case BC_LEX_KW_MAXRAND:
235044d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2351d43fa8efSStefan Eßer 			case BC_LEX_KW_LINE_LENGTH:
2352d43fa8efSStefan Eßer 			case BC_LEX_KW_GLOBAL_STACKS:
2353d43fa8efSStefan Eßer 			case BC_LEX_KW_LEADING_ZERO:
235450696a6eSStefan Eßer 			{
235544d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
235650696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
235778bc019dSStefan Eßer 				{
235850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
235978bc019dSStefan Eßer 				}
236044d4804dSStefan Eßer 
236144d4804dSStefan Eßer 				// Error if we have read and it's not allowed.
236250696a6eSStefan Eßer 				else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD))
236378bc019dSStefan Eßer 				{
236450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_EXEC_REC_READ);
236578bc019dSStefan Eßer 				}
236644d4804dSStefan Eßer 
236750696a6eSStefan Eßer 				prev = t - BC_LEX_KW_READ + BC_INST_READ;
236850696a6eSStefan Eßer 				bc_parse_noArgBuiltin(p, prev);
236950696a6eSStefan Eßer 
237050696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
237150696a6eSStefan Eßer 				nexprs += 1;
237250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
237350696a6eSStefan Eßer 
237450696a6eSStefan Eßer 				break;
237550696a6eSStefan Eßer 			}
237650696a6eSStefan Eßer 
237750696a6eSStefan Eßer 			case BC_LEX_KW_SCALE:
237850696a6eSStefan Eßer 			{
237944d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
238050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
238178bc019dSStefan Eßer 				{
238250696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
238378bc019dSStefan Eßer 				}
238450696a6eSStefan Eßer 
238544d4804dSStefan Eßer 				// Scale needs special work because it can be a variable *or* a
238644d4804dSStefan Eßer 				// function.
238750696a6eSStefan Eßer 				bc_parse_scale(p, &prev, &can_assign, flags);
238844d4804dSStefan Eßer 
238950696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
239050696a6eSStefan Eßer 				nexprs += 1;
239150696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
239250696a6eSStefan Eßer 
239350696a6eSStefan Eßer 				break;
239450696a6eSStefan Eßer 			}
239550696a6eSStefan Eßer 
239644d4804dSStefan Eßer 			case BC_LEX_KW_MODEXP:
239744d4804dSStefan Eßer 			case BC_LEX_KW_DIVMOD:
239844d4804dSStefan Eßer 			{
239944d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
240044d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
240178bc019dSStefan Eßer 				{
240244d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
240378bc019dSStefan Eßer 				}
240444d4804dSStefan Eßer 
240544d4804dSStefan Eßer 				bc_parse_builtin3(p, t, flags, &prev);
240644d4804dSStefan Eßer 
240744d4804dSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
240844d4804dSStefan Eßer 				nexprs += 1;
240944d4804dSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
241044d4804dSStefan Eßer 
241144d4804dSStefan Eßer 				break;
241244d4804dSStefan Eßer 			}
241344d4804dSStefan Eßer 
2414d101cdd6SStefan Eßer 			case BC_LEX_EOF:
2415d101cdd6SStefan Eßer 			case BC_LEX_INVALID:
2416d101cdd6SStefan Eßer 			case BC_LEX_NEG:
2417d101cdd6SStefan Eßer 			case BC_LEX_NLINE:
2418d101cdd6SStefan Eßer 			case BC_LEX_WHITESPACE:
2419d101cdd6SStefan Eßer 			case BC_LEX_LBRACKET:
2420d101cdd6SStefan Eßer 			case BC_LEX_COMMA:
2421d101cdd6SStefan Eßer 			case BC_LEX_RBRACKET:
2422d101cdd6SStefan Eßer 			case BC_LEX_LBRACE:
2423d101cdd6SStefan Eßer 			case BC_LEX_SCOLON:
2424d101cdd6SStefan Eßer 			case BC_LEX_RBRACE:
2425d101cdd6SStefan Eßer 			case BC_LEX_KW_AUTO:
2426d101cdd6SStefan Eßer 			case BC_LEX_KW_BREAK:
2427d101cdd6SStefan Eßer 			case BC_LEX_KW_CONTINUE:
2428d101cdd6SStefan Eßer 			case BC_LEX_KW_DEFINE:
2429d101cdd6SStefan Eßer 			case BC_LEX_KW_FOR:
2430d101cdd6SStefan Eßer 			case BC_LEX_KW_IF:
2431d101cdd6SStefan Eßer 			case BC_LEX_KW_LIMITS:
2432d101cdd6SStefan Eßer 			case BC_LEX_KW_RETURN:
2433d101cdd6SStefan Eßer 			case BC_LEX_KW_WHILE:
2434d101cdd6SStefan Eßer 			case BC_LEX_KW_HALT:
2435d101cdd6SStefan Eßer 			case BC_LEX_KW_PRINT:
2436d101cdd6SStefan Eßer 			case BC_LEX_KW_QUIT:
2437d101cdd6SStefan Eßer 			case BC_LEX_KW_STREAM:
2438d101cdd6SStefan Eßer 			case BC_LEX_KW_ELSE:
2439d101cdd6SStefan Eßer #if DC_ENABLED
2440103d7cdfSStefan Eßer 			case BC_LEX_EXTENDED_REGISTERS:
2441d101cdd6SStefan Eßer 			case BC_LEX_EQ_NO_REG:
2442d101cdd6SStefan Eßer 			case BC_LEX_COLON:
2443d101cdd6SStefan Eßer 			case BC_LEX_EXECUTE:
2444d101cdd6SStefan Eßer 			case BC_LEX_PRINT_STACK:
2445d101cdd6SStefan Eßer 			case BC_LEX_CLEAR_STACK:
2446d101cdd6SStefan Eßer 			case BC_LEX_REG_STACK_LEVEL:
2447d101cdd6SStefan Eßer 			case BC_LEX_STACK_LEVEL:
2448d101cdd6SStefan Eßer 			case BC_LEX_DUPLICATE:
2449d101cdd6SStefan Eßer 			case BC_LEX_SWAP:
2450d101cdd6SStefan Eßer 			case BC_LEX_POP:
2451d101cdd6SStefan Eßer 			case BC_LEX_STORE_IBASE:
2452d101cdd6SStefan Eßer 			case BC_LEX_STORE_OBASE:
2453d101cdd6SStefan Eßer 			case BC_LEX_STORE_SCALE:
2454d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH
2455d101cdd6SStefan Eßer 			case BC_LEX_STORE_SEED:
2456d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2457d101cdd6SStefan Eßer 			case BC_LEX_LOAD:
2458d101cdd6SStefan Eßer 			case BC_LEX_LOAD_POP:
2459d101cdd6SStefan Eßer 			case BC_LEX_STORE_PUSH:
2460d101cdd6SStefan Eßer 			case BC_LEX_PRINT_POP:
2461d101cdd6SStefan Eßer 			case BC_LEX_NQUIT:
2462d101cdd6SStefan Eßer 			case BC_LEX_EXEC_STACK_LENGTH:
2463d101cdd6SStefan Eßer 			case BC_LEX_SCALE_FACTOR:
2464d101cdd6SStefan Eßer 			case BC_LEX_ARRAY_LENGTH:
2465d101cdd6SStefan Eßer #endif // DC_ENABLED
246650696a6eSStefan Eßer 			{
2467103d7cdfSStefan Eßer #if BC_DEBUG
246844d4804dSStefan Eßer 				// We should never get here, even in debug builds.
246950696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
247050696a6eSStefan Eßer 				break;
2471103d7cdfSStefan Eßer #endif // BC_DEBUG
247250696a6eSStefan Eßer 			}
247350696a6eSStefan Eßer 		}
247450696a6eSStefan Eßer 
247550696a6eSStefan Eßer 		if (get_token) bc_lex_next(&p->l);
247650696a6eSStefan Eßer 	}
247750696a6eSStefan Eßer 
247844d4804dSStefan Eßer 	// Now that we have parsed the expression, we need to empty the operator
247944d4804dSStefan Eßer 	// stack.
248078bc019dSStefan Eßer 	while (p->ops.len > ops_bgn)
248178bc019dSStefan Eßer 	{
248250696a6eSStefan Eßer 		top = BC_PARSE_TOP_OP(p);
248350696a6eSStefan Eßer 		assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
248450696a6eSStefan Eßer 
248544d4804dSStefan Eßer 		// There should not be *any* parens on the stack anymore.
248650696a6eSStefan Eßer 		if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN))
248778bc019dSStefan Eßer 		{
248850696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_EXPR);
248978bc019dSStefan Eßer 		}
249050696a6eSStefan Eßer 
249150696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
249250696a6eSStefan Eßer 
249344d4804dSStefan Eßer 		// Adjust the number of unused expressions.
249450696a6eSStefan Eßer 		nexprs -= !BC_PARSE_OP_PREFIX(top);
249550696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
249650696a6eSStefan Eßer 
249750696a6eSStefan Eßer 		incdec = false;
249850696a6eSStefan Eßer 	}
249950696a6eSStefan Eßer 
250044d4804dSStefan Eßer 	// There must be only one expression at the top.
250150696a6eSStefan Eßer 	if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR);
250250696a6eSStefan Eßer 
250344d4804dSStefan Eßer 	// Check that the next token is correct.
250478bc019dSStefan Eßer 	for (i = 0; i < next.len && t != next.tokens[i]; ++i)
250578bc019dSStefan Eßer 	{
250678bc019dSStefan Eßer 		continue;
250778bc019dSStefan Eßer 	}
250850696a6eSStefan Eßer 	if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p)))
250978bc019dSStefan Eßer 	{
251050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EXPR);
251178bc019dSStefan Eßer 	}
251250696a6eSStefan Eßer 
251344d4804dSStefan Eßer 	// Check that POSIX would be happy with the number of relational operators.
251450696a6eSStefan Eßer 	if (!(flags & BC_PARSE_REL) && nrelops)
251578bc019dSStefan Eßer 	{
251650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_REL_POS);
251778bc019dSStefan Eßer 	}
251850696a6eSStefan Eßer 	else if ((flags & BC_PARSE_REL) && nrelops > 1)
251978bc019dSStefan Eßer 	{
252050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_MULTIREL);
252178bc019dSStefan Eßer 	}
252250696a6eSStefan Eßer 
252344d4804dSStefan Eßer 	// If this is true, then we might be in a situation where we don't print.
252444d4804dSStefan Eßer 	// We would want to have the increment/decrement operator not make an extra
252544d4804dSStefan Eßer 	// copy if it's not necessary.
252678bc019dSStefan Eßer 	if (!(flags & BC_PARSE_NEEDVAL) && !pfirst)
252778bc019dSStefan Eßer 	{
252844d4804dSStefan Eßer 		// We have the easy case if the last operator was an assignment
252944d4804dSStefan Eßer 		// operator.
253078bc019dSStefan Eßer 		if (assign)
253178bc019dSStefan Eßer 		{
253250696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
253350696a6eSStefan Eßer 			inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
253450696a6eSStefan Eßer 			incdec = false;
253550696a6eSStefan Eßer 		}
253644d4804dSStefan Eßer 		// If we have an inc/dec operator and we are *not* printing, implement
253744d4804dSStefan Eßer 		// the optimization to get rid of the extra copy.
253878bc019dSStefan Eßer 		else if (incdec && !(flags & BC_PARSE_PRINT))
253978bc019dSStefan Eßer 		{
254050696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
254150696a6eSStefan Eßer 			incdec = (inst <= BC_INST_DEC);
254278bc019dSStefan Eßer 			inst = BC_INST_ASSIGN_PLUS_NO_VAL +
254378bc019dSStefan Eßer 			       (inst != BC_INST_INC && inst != BC_INST_ASSIGN_PLUS);
254450696a6eSStefan Eßer 		}
254550696a6eSStefan Eßer 
254644d4804dSStefan Eßer 		// This condition allows us to change the previous assignment
254744d4804dSStefan Eßer 		// instruction (which does a copy) for a NO_VAL version, which does not.
254844d4804dSStefan Eßer 		// This condition is set if either of the above if statements ends up
254944d4804dSStefan Eßer 		// being true.
255050696a6eSStefan Eßer 		if (inst >= BC_INST_ASSIGN_POWER_NO_VAL &&
255150696a6eSStefan Eßer 		    inst <= BC_INST_ASSIGN_NO_VAL)
255250696a6eSStefan Eßer 		{
255344d4804dSStefan Eßer 			// Pop the previous assignment instruction and push a new one.
255444d4804dSStefan Eßer 			// Inc/dec needs the extra instruction because it is now a binary
255544d4804dSStefan Eßer 			// operator and needs a second operand.
255650696a6eSStefan Eßer 			bc_vec_pop(&p->func->code);
255750696a6eSStefan Eßer 			if (incdec) bc_parse_push(p, BC_INST_ONE);
255850696a6eSStefan Eßer 			bc_parse_push(p, inst);
255950696a6eSStefan Eßer 		}
256050696a6eSStefan Eßer 	}
256150696a6eSStefan Eßer 
256244d4804dSStefan Eßer 	// If we might have to print...
256378bc019dSStefan Eßer 	if ((flags & BC_PARSE_PRINT))
256478bc019dSStefan Eßer 	{
256544d4804dSStefan Eßer 		// With a paren first or the last operator not being an assignment, we
256644d4804dSStefan Eßer 		// *do* want to print.
256750696a6eSStefan Eßer 		if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
256850696a6eSStefan Eßer 	}
256944d4804dSStefan Eßer 	// We need to make sure to push a pop instruction for assignment statements
257044d4804dSStefan Eßer 	// that will not print. The print will pop, but without it, we need to pop.
257150696a6eSStefan Eßer 	else if (!(flags & BC_PARSE_NEEDVAL) &&
257250696a6eSStefan Eßer 	         (inst < BC_INST_ASSIGN_POWER_NO_VAL ||
257350696a6eSStefan Eßer 	          inst > BC_INST_ASSIGN_NO_VAL))
257450696a6eSStefan Eßer 	{
257550696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_POP);
257650696a6eSStefan Eßer 	}
257750696a6eSStefan Eßer 
257850696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
257950696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
258044d4804dSStefan Eßer 	//
258144d4804dSStefan Eßer 	// Yes, this is one case where I reuse a variable for a different purpose;
258244d4804dSStefan Eßer 	// in this case, incdec being true now means that newlines are not valid.
258350696a6eSStefan Eßer 	for (incdec = true, i = 0; i < next.len && incdec; ++i)
258478bc019dSStefan Eßer 	{
258550696a6eSStefan Eßer 		incdec = (next.tokens[i] != BC_LEX_NLINE);
258678bc019dSStefan Eßer 	}
258778bc019dSStefan Eßer 	if (incdec)
258878bc019dSStefan Eßer 	{
258978bc019dSStefan Eßer 		while (p->l.t == BC_LEX_NLINE)
259078bc019dSStefan Eßer 		{
259178bc019dSStefan Eßer 			bc_lex_next(&p->l);
259278bc019dSStefan Eßer 		}
259350696a6eSStefan Eßer 	}
259450696a6eSStefan Eßer 
259550696a6eSStefan Eßer 	return BC_PARSE_STATUS_SUCCESS;
259650696a6eSStefan Eßer }
259750696a6eSStefan Eßer 
259844d4804dSStefan Eßer /**
259944d4804dSStefan Eßer  * Parses an expression with bc_parse_expr_err(), but throws an error if it gets
260044d4804dSStefan Eßer  * an empty expression.
260144d4804dSStefan Eßer  * @param p      The parser.
260244d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
260344d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
260444d4804dSStefan Eßer  */
260578bc019dSStefan Eßer static void
bc_parse_expr_status(BcParse * p,uint8_t flags,BcParseNext next)260678bc019dSStefan Eßer bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next)
260778bc019dSStefan Eßer {
260850696a6eSStefan Eßer 	BcParseStatus s = bc_parse_expr_err(p, flags, next);
260950696a6eSStefan Eßer 
261050696a6eSStefan Eßer 	if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR))
261178bc019dSStefan Eßer 	{
261250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR);
261350696a6eSStefan Eßer 	}
261478bc019dSStefan Eßer }
261550696a6eSStefan Eßer 
261678bc019dSStefan Eßer void
bc_parse_expr(BcParse * p,uint8_t flags)261778bc019dSStefan Eßer bc_parse_expr(BcParse* p, uint8_t flags)
261878bc019dSStefan Eßer {
261950696a6eSStefan Eßer 	assert(p);
262050696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_read);
262150696a6eSStefan Eßer }
262250696a6eSStefan Eßer #endif // BC_ENABLED
2623