xref: /freebsd/contrib/bc/src/bc_parse.c (revision 10041e99a0c29c9f99c4148fc173bb12dd26aa8d)
150696a6eSStefan Eßer /*
250696a6eSStefan Eßer  * *****************************************************************************
350696a6eSStefan Eßer  *
450696a6eSStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
550696a6eSStefan Eßer  *
610328f8bSStefan Eßer  * Copyright (c) 2018-2021 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 
5850696a6eSStefan Eßer static void bc_parse_else(BcParse *p);
5950696a6eSStefan Eßer static void bc_parse_stmt(BcParse *p);
6050696a6eSStefan Eßer static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags,
6150696a6eSStefan Eßer                                        BcParseNext next);
6244d4804dSStefan Eßer static void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next);
6350696a6eSStefan Eßer 
6444d4804dSStefan Eßer /**
6544d4804dSStefan Eßer  * Returns true if an instruction could only have come from a "leaf" expression.
6644d4804dSStefan Eßer  * For more on what leaf expressions are, read the comment for BC_PARSE_LEAF().
6744d4804dSStefan Eßer  * @param t  The instruction to test.
6844d4804dSStefan Eßer  */
6950696a6eSStefan Eßer static bool bc_parse_inst_isLeaf(BcInst t) {
7050696a6eSStefan Eßer 	return (t >= BC_INST_NUM && t <= BC_INST_MAXSCALE) ||
7150696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
7250696a6eSStefan Eßer 	        t == BC_INST_TRUNC ||
7350696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
7450696a6eSStefan Eßer 	        t <= BC_INST_DEC;
7550696a6eSStefan Eßer }
7650696a6eSStefan Eßer 
7744d4804dSStefan Eßer /**
7844d4804dSStefan Eßer  * Returns true if the *previous* token was a delimiter. A delimiter is anything
7944d4804dSStefan Eßer  * that can legally end a statement. In bc's case, it could be a newline, a
8044d4804dSStefan Eßer  * semicolon, and a brace in certain cases.
8144d4804dSStefan Eßer  * @param p  The parser.
82*10041e99SStefan Eßer  * @return   True if the token is a legal delimiter.
8344d4804dSStefan Eßer  */
8450696a6eSStefan Eßer static bool bc_parse_isDelimiter(const BcParse *p) {
8550696a6eSStefan Eßer 
8650696a6eSStefan Eßer 	BcLexType t = p->l.t;
8744d4804dSStefan Eßer 	bool good;
8850696a6eSStefan Eßer 
8944d4804dSStefan Eßer 	// If it's an obvious delimiter, say so.
9050696a6eSStefan Eßer 	if (BC_PARSE_DELIMITER(t)) return true;
9150696a6eSStefan Eßer 
9244d4804dSStefan Eßer 	good = false;
9344d4804dSStefan Eßer 
9444d4804dSStefan Eßer 	// If the current token is a keyword, then...beware. That means that we need
9544d4804dSStefan Eßer 	// to check for a "dangling" else, where there was no brace-delimited block
9644d4804dSStefan Eßer 	// on the previous if.
9750696a6eSStefan Eßer 	if (t == BC_LEX_KW_ELSE) {
9850696a6eSStefan Eßer 
9950696a6eSStefan Eßer 		size_t i;
10050696a6eSStefan Eßer 		uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
10150696a6eSStefan Eßer 
10244d4804dSStefan Eßer 		// As long as going up the stack is valid for a dangling else, keep on.
10350696a6eSStefan Eßer 		for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) {
10450696a6eSStefan Eßer 
10550696a6eSStefan Eßer 			fptr = bc_vec_item_rev(&p->flags, i);
10650696a6eSStefan Eßer 			flags = *fptr;
10750696a6eSStefan Eßer 
10844d4804dSStefan Eßer 			// If we need a brace and don't have one, then we don't have a
10944d4804dSStefan Eßer 			// delimiter.
11050696a6eSStefan Eßer 			if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
11150696a6eSStefan Eßer 				return false;
11250696a6eSStefan Eßer 		}
11350696a6eSStefan Eßer 
11444d4804dSStefan Eßer 		// Oh, and we had also better have an if statement somewhere.
11550696a6eSStefan Eßer 		good = ((flags & BC_PARSE_FLAG_IF) != 0);
11650696a6eSStefan Eßer 	}
11750696a6eSStefan Eßer 	else if (t == BC_LEX_RBRACE) {
11850696a6eSStefan Eßer 
11950696a6eSStefan Eßer 		size_t i;
12050696a6eSStefan Eßer 
12144d4804dSStefan Eßer 		// Since we have a brace, we need to just check if a brace was needed.
12250696a6eSStefan Eßer 		for (i = 0; !good && i < p->flags.len; ++i) {
12350696a6eSStefan Eßer 			uint16_t *fptr = bc_vec_item_rev(&p->flags, i);
12450696a6eSStefan Eßer 			good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
12550696a6eSStefan Eßer 		}
12650696a6eSStefan Eßer 	}
12750696a6eSStefan Eßer 
12850696a6eSStefan Eßer 	return good;
12950696a6eSStefan Eßer }
13050696a6eSStefan Eßer 
13144d4804dSStefan Eßer /**
132*10041e99SStefan Eßer  * Returns true if we are in top level of a function body. The POSIX grammar
133*10041e99SStefan Eßer  * is defined such that anything is allowed after a function body, so we must
134*10041e99SStefan Eßer  * use this function to detect that case when ending a function body.
135*10041e99SStefan Eßer  * @param p  The parser.
136*10041e99SStefan Eßer  * @return   True if we are in the top level of parsing a function body.
137*10041e99SStefan Eßer  */
138*10041e99SStefan Eßer static bool bc_parse_TopFunc(const BcParse *p) {
139*10041e99SStefan Eßer 
140*10041e99SStefan Eßer 	bool good = p->flags.len == 2;
141*10041e99SStefan Eßer 
142*10041e99SStefan Eßer 	uint16_t val = BC_PARSE_FLAG_BRACE | BC_PARSE_FLAG_FUNC_INNER;
143*10041e99SStefan Eßer 	val |= BC_PARSE_FLAG_FUNC;
144*10041e99SStefan Eßer 
145*10041e99SStefan Eßer 	return good && BC_PARSE_TOP_FLAG(p) == val;
146*10041e99SStefan Eßer }
147*10041e99SStefan Eßer 
148*10041e99SStefan Eßer /**
14944d4804dSStefan Eßer  * Sets a previously defined exit label. What are labels? See the bc Parsing
15044d4804dSStefan Eßer  * section of the Development manual (manuals/development.md).
15144d4804dSStefan Eßer  * @param p  The parser.
15244d4804dSStefan Eßer  */
15350696a6eSStefan Eßer static void bc_parse_setLabel(BcParse *p) {
15450696a6eSStefan Eßer 
15550696a6eSStefan Eßer 	BcFunc *func = p->func;
15650696a6eSStefan Eßer 	BcInstPtr *ip = bc_vec_top(&p->exits);
15750696a6eSStefan Eßer 	size_t *label;
15850696a6eSStefan Eßer 
15950696a6eSStefan Eßer 	assert(func == bc_vec_item(&p->prog->fns, p->fidx));
16050696a6eSStefan Eßer 
16144d4804dSStefan Eßer 	// Set the preallocated label to the correct index.
16250696a6eSStefan Eßer 	label = bc_vec_item(&func->labels, ip->idx);
16350696a6eSStefan Eßer 	*label = func->code.len;
16450696a6eSStefan Eßer 
16544d4804dSStefan Eßer 	// Now, we don't need the exit label; it is done.
16650696a6eSStefan Eßer 	bc_vec_pop(&p->exits);
16750696a6eSStefan Eßer }
16850696a6eSStefan Eßer 
16944d4804dSStefan Eßer /**
17044d4804dSStefan Eßer  * Creates a label and sets it to idx. If this is an exit label, then idx is
17144d4804dSStefan Eßer  * actually invalid, but it doesn't matter because it will be fixed by
17244d4804dSStefan Eßer  * bc_parse_setLabel() later.
17344d4804dSStefan Eßer  * @param p    The parser.
17444d4804dSStefan Eßer  * @param idx  The index of the label.
17544d4804dSStefan Eßer  */
17650696a6eSStefan Eßer static void bc_parse_createLabel(BcParse *p, size_t idx) {
17750696a6eSStefan Eßer 	bc_vec_push(&p->func->labels, &idx);
17850696a6eSStefan Eßer }
17950696a6eSStefan Eßer 
18044d4804dSStefan Eßer /**
18144d4804dSStefan Eßer  * Creates a conditional label. Unlike an exit label, this label is set at
18244d4804dSStefan Eßer  * creation time because it comes *before* the code that will target it.
18344d4804dSStefan Eßer  * @param p    The parser.
18444d4804dSStefan Eßer  * @param idx  The index of the label.
18544d4804dSStefan Eßer  */
18650696a6eSStefan Eßer static void bc_parse_createCondLabel(BcParse *p, size_t idx) {
18750696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
18850696a6eSStefan Eßer 	bc_vec_push(&p->conds, &idx);
18950696a6eSStefan Eßer }
19050696a6eSStefan Eßer 
19144d4804dSStefan Eßer /*
19244d4804dSStefan Eßer  * Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
19344d4804dSStefan Eßer  * create a label to be filled in later? Because exit labels are meant to be
19444d4804dSStefan Eßer  * targeted by code that comes *before* the label. Since we have to parse that
19544d4804dSStefan Eßer  * code first, and don't know how long it will be, we need to just make sure to
19644d4804dSStefan Eßer  * reserve a slot to be filled in later when we know.
19744d4804dSStefan Eßer  *
19844d4804dSStefan Eßer  * By the way, this uses BcInstPtr because it was convenient. The field idx
19944d4804dSStefan Eßer  * holds the index, and the field func holds the loop boolean.
20044d4804dSStefan Eßer  *
20144d4804dSStefan Eßer  * @param p     The parser.
20244d4804dSStefan Eßer  * @param idx   The index of the label's position.
20344d4804dSStefan Eßer  * @param loop  True if the exit label is for a loop or not.
20444d4804dSStefan Eßer  */
20550696a6eSStefan Eßer static void bc_parse_createExitLabel(BcParse *p, size_t idx, bool loop) {
20650696a6eSStefan Eßer 
20750696a6eSStefan Eßer 	BcInstPtr ip;
20850696a6eSStefan Eßer 
20950696a6eSStefan Eßer 	assert(p->func == bc_vec_item(&p->prog->fns, p->fidx));
21050696a6eSStefan Eßer 
21150696a6eSStefan Eßer 	ip.func = loop;
21250696a6eSStefan Eßer 	ip.idx = idx;
21350696a6eSStefan Eßer 	ip.len = 0;
21450696a6eSStefan Eßer 
21550696a6eSStefan Eßer 	bc_vec_push(&p->exits, &ip);
21650696a6eSStefan Eßer 	bc_parse_createLabel(p, SIZE_MAX);
21750696a6eSStefan Eßer }
21850696a6eSStefan Eßer 
21944d4804dSStefan Eßer /**
22044d4804dSStefan Eßer  * Pops the correct operators off of the operator stack based on the current
22144d4804dSStefan Eßer  * operator. This is because of the Shunting-Yard algorithm. Lower prec means
22244d4804dSStefan Eßer  * higher precedence.
22344d4804dSStefan Eßer  * @param p       The parser.
22444d4804dSStefan Eßer  * @param type    The operator.
22544d4804dSStefan Eßer  * @param start   The previous start of the operator stack. For more
22644d4804dSStefan Eßer  *                information, see the bc Parsing section of the Development
22744d4804dSStefan Eßer  *                manual (manuals/development.md).
22844d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
22944d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
23044d4804dSStefan Eßer  */
23150696a6eSStefan Eßer static void bc_parse_operator(BcParse *p, BcLexType type,
23250696a6eSStefan Eßer                               size_t start, size_t *nexprs)
23350696a6eSStefan Eßer {
23450696a6eSStefan Eßer 	BcLexType t;
23550696a6eSStefan Eßer 	uchar l, r = BC_PARSE_OP_PREC(type);
23650696a6eSStefan Eßer 	uchar left = BC_PARSE_OP_LEFT(type);
23750696a6eSStefan Eßer 
23844d4804dSStefan Eßer 	// While we haven't hit the stop point yet.
23950696a6eSStefan Eßer 	while (p->ops.len > start) {
24050696a6eSStefan Eßer 
24144d4804dSStefan Eßer 		// Get the top operator.
24250696a6eSStefan Eßer 		t = BC_PARSE_TOP_OP(p);
24344d4804dSStefan Eßer 
24444d4804dSStefan Eßer 		// If it's a right paren, we have reached the end of whatever expression
24544d4804dSStefan Eßer 		// this is no matter what.
24650696a6eSStefan Eßer 		if (t == BC_LEX_LPAREN) break;
24750696a6eSStefan Eßer 
24844d4804dSStefan Eßer 		// Break for precedence. Precedence operates differently on left and
24944d4804dSStefan Eßer 		// right associativity, by the way. A left associative operator that
25044d4804dSStefan Eßer 		// matches the current precedence should take priority, but a right
25144d4804dSStefan Eßer 		// associative operator should not.
25250696a6eSStefan Eßer 		l = BC_PARSE_OP_PREC(t);
25350696a6eSStefan Eßer 		if (l >= r && (l != r || !left)) break;
25450696a6eSStefan Eßer 
25544d4804dSStefan Eßer 		// Do the housekeeping. In particular, make sure to note that one
25644d4804dSStefan Eßer 		// expression was consumed. (Two were, but another was added.)
25750696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
25850696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
25950696a6eSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(t);
26050696a6eSStefan Eßer 	}
26150696a6eSStefan Eßer 
26250696a6eSStefan Eßer 	bc_vec_push(&p->ops, &type);
26350696a6eSStefan Eßer }
26450696a6eSStefan Eßer 
26544d4804dSStefan Eßer /**
26644d4804dSStefan Eßer  * Parses a right paren. In the Shunting-Yard algorithm, it needs to be put on
26744d4804dSStefan Eßer  * the operator stack. But before that, it needs to consume whatever operators
26844d4804dSStefan Eßer  * there are until it hits a left paren.
26944d4804dSStefan Eßer  * @param p       The parser.
27044d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
27144d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
27244d4804dSStefan Eßer  */
27344d4804dSStefan Eßer static void bc_parse_rightParen(BcParse *p, size_t *nexprs) {
27450696a6eSStefan Eßer 
27550696a6eSStefan Eßer 	BcLexType top;
27650696a6eSStefan Eßer 
27744d4804dSStefan Eßer 	// Consume operators until a left paren.
27850696a6eSStefan Eßer 	while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) {
27950696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
28050696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
28144d4804dSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(top);
28250696a6eSStefan Eßer 	}
28350696a6eSStefan Eßer 
28444d4804dSStefan Eßer 	// We need to pop the left paren as well.
28550696a6eSStefan Eßer 	bc_vec_pop(&p->ops);
28650696a6eSStefan Eßer 
28744d4804dSStefan Eßer 	// Oh, and we also want the next token.
28850696a6eSStefan Eßer 	bc_lex_next(&p->l);
28950696a6eSStefan Eßer }
29050696a6eSStefan Eßer 
29144d4804dSStefan Eßer /**
29244d4804dSStefan Eßer  * Parses function arguments.
29344d4804dSStefan Eßer  * @param p      The parser.
29444d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
29544d4804dSStefan Eßer  *               be.
29644d4804dSStefan Eßer  */
29744d4804dSStefan Eßer static void bc_parse_args(BcParse *p, uint8_t flags) {
29850696a6eSStefan Eßer 
29950696a6eSStefan Eßer 	bool comma = false;
30044d4804dSStefan Eßer 	size_t nargs;
30150696a6eSStefan Eßer 
30250696a6eSStefan Eßer 	bc_lex_next(&p->l);
30350696a6eSStefan Eßer 
30444d4804dSStefan Eßer 	// Print and comparison operators not allowed. Well, comparison operators
30544d4804dSStefan Eßer 	// only for POSIX. But we do allow arrays, and we *must* get a value.
30650696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
30750696a6eSStefan Eßer 	flags |= (BC_PARSE_ARRAY | BC_PARSE_NEEDVAL);
30850696a6eSStefan Eßer 
30944d4804dSStefan Eßer 	// Count the arguments and parse them.
31044d4804dSStefan Eßer 	for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs) {
31150696a6eSStefan Eßer 
31244d4804dSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_arg);
31350696a6eSStefan Eßer 
31450696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
31550696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
31650696a6eSStefan Eßer 	}
31750696a6eSStefan Eßer 
31844d4804dSStefan Eßer 	// An ending comma is FAIL.
31950696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
32044d4804dSStefan Eßer 
32144d4804dSStefan Eßer 	// Now do the call with the number of arguments.
32250696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_CALL);
32344d4804dSStefan Eßer 	bc_parse_pushIndex(p, nargs);
32450696a6eSStefan Eßer }
32550696a6eSStefan Eßer 
32644d4804dSStefan Eßer /**
32744d4804dSStefan Eßer  * Parses a function call.
32844d4804dSStefan Eßer  * @param p      The parser.
32944d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
33044d4804dSStefan Eßer  *               be.
33144d4804dSStefan Eßer  */
33250696a6eSStefan Eßer static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) {
33350696a6eSStefan Eßer 
33450696a6eSStefan Eßer 	size_t idx;
33550696a6eSStefan Eßer 
33644d4804dSStefan Eßer 	bc_parse_args(p, flags);
33750696a6eSStefan Eßer 
33844d4804dSStefan Eßer 	// We just assert this because bc_parse_args() should
33950696a6eSStefan Eßer 	// ensure that the next token is what it should be.
34050696a6eSStefan Eßer 	assert(p->l.t == BC_LEX_RPAREN);
34150696a6eSStefan Eßer 
34250696a6eSStefan Eßer 	// We cannot use bc_program_insertFunc() here
34350696a6eSStefan Eßer 	// because it will overwrite an existing function.
34450696a6eSStefan Eßer 	idx = bc_map_index(&p->prog->fn_map, name);
34550696a6eSStefan Eßer 
34644d4804dSStefan Eßer 	// The function does not exist yet. Create a space for it. If the user does
34744d4804dSStefan Eßer 	// not define it, it's a *runtime* error, not a parse error.
34850696a6eSStefan Eßer 	if (idx == BC_VEC_INVALID_IDX) {
34950696a6eSStefan Eßer 
35050696a6eSStefan Eßer 		idx = bc_program_insertFunc(p->prog, name);
35150696a6eSStefan Eßer 
35250696a6eSStefan Eßer 		assert(idx != BC_VEC_INVALID_IDX);
35350696a6eSStefan Eßer 
35450696a6eSStefan Eßer 		// Make sure that this pointer was not invalidated.
35550696a6eSStefan Eßer 		p->func = bc_vec_item(&p->prog->fns, p->fidx);
35650696a6eSStefan Eßer 	}
35744d4804dSStefan Eßer 	// The function exists, so set the right function index.
35850696a6eSStefan Eßer 	else idx = ((BcId*) bc_vec_item(&p->prog->fn_map, idx))->idx;
35950696a6eSStefan Eßer 
36050696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
36150696a6eSStefan Eßer 
36244d4804dSStefan Eßer 	// Make sure to get the next token.
36350696a6eSStefan Eßer 	bc_lex_next(&p->l);
36450696a6eSStefan Eßer }
36550696a6eSStefan Eßer 
36644d4804dSStefan Eßer /**
36744d4804dSStefan Eßer  * Parses a name/identifier-based expression. It could be a variable, an array
36844d4804dSStefan Eßer  * element, an array itself (for function arguments), a function call, etc.
36944d4804dSStefan Eßer  *
37044d4804dSStefan Eßer  */
37150696a6eSStefan Eßer static void bc_parse_name(BcParse *p, BcInst *type,
37250696a6eSStefan Eßer                           bool *can_assign, uint8_t flags)
37350696a6eSStefan Eßer {
37450696a6eSStefan Eßer 	char *name;
37550696a6eSStefan Eßer 
376*10041e99SStefan Eßer 	BC_SIG_ASSERT_LOCKED;
37750696a6eSStefan Eßer 
37844d4804dSStefan Eßer 	// We want a copy of the name since the lexer might overwrite its copy.
37950696a6eSStefan Eßer 	name = bc_vm_strdup(p->l.str.v);
38050696a6eSStefan Eßer 
38150696a6eSStefan Eßer 	BC_SETJMP_LOCKED(err);
38250696a6eSStefan Eßer 
38344d4804dSStefan Eßer 	// We need the next token to see if it's just a variable or something more.
38450696a6eSStefan Eßer 	bc_lex_next(&p->l);
38550696a6eSStefan Eßer 
38644d4804dSStefan Eßer 	// Array element or array.
38750696a6eSStefan Eßer 	if (p->l.t == BC_LEX_LBRACKET) {
38850696a6eSStefan Eßer 
38950696a6eSStefan Eßer 		bc_lex_next(&p->l);
39050696a6eSStefan Eßer 
39144d4804dSStefan Eßer 		// Array only. This has to be a function parameter.
39250696a6eSStefan Eßer 		if (p->l.t == BC_LEX_RBRACKET) {
39350696a6eSStefan Eßer 
39444d4804dSStefan Eßer 			// Error if arrays are not allowed.
39550696a6eSStefan Eßer 			if (BC_ERR(!(flags & BC_PARSE_ARRAY)))
39650696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_EXPR);
39750696a6eSStefan Eßer 
39850696a6eSStefan Eßer 			*type = BC_INST_ARRAY;
39950696a6eSStefan Eßer 			*can_assign = false;
40050696a6eSStefan Eßer 		}
40150696a6eSStefan Eßer 		else {
40250696a6eSStefan Eßer 
40344d4804dSStefan Eßer 			// If we are here, we have an array element. We need to set the
40444d4804dSStefan Eßer 			// expression parsing flags.
40550696a6eSStefan Eßer 			uint8_t flags2 = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) |
40650696a6eSStefan Eßer 			                 BC_PARSE_NEEDVAL;
40750696a6eSStefan Eßer 
40850696a6eSStefan Eßer 			bc_parse_expr_status(p, flags2, bc_parse_next_elem);
40950696a6eSStefan Eßer 
41044d4804dSStefan Eßer 			// The next token *must* be a right bracket.
41150696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
41250696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
41350696a6eSStefan Eßer 
41450696a6eSStefan Eßer 			*type = BC_INST_ARRAY_ELEM;
41550696a6eSStefan Eßer 			*can_assign = true;
41650696a6eSStefan Eßer 		}
41750696a6eSStefan Eßer 
41844d4804dSStefan Eßer 		// Make sure to get the next token.
41950696a6eSStefan Eßer 		bc_lex_next(&p->l);
42050696a6eSStefan Eßer 
42144d4804dSStefan Eßer 		// Push the instruction and the name of the identifier.
42250696a6eSStefan Eßer 		bc_parse_push(p, *type);
42350696a6eSStefan Eßer 		bc_parse_pushName(p, name, false);
42450696a6eSStefan Eßer 	}
42550696a6eSStefan Eßer 	else if (p->l.t == BC_LEX_LPAREN) {
42650696a6eSStefan Eßer 
42744d4804dSStefan Eßer 		// We are parsing a function call; error if not allowed.
42850696a6eSStefan Eßer 		if (BC_ERR(flags & BC_PARSE_NOCALL))
42950696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
43050696a6eSStefan Eßer 
43150696a6eSStefan Eßer 		*type = BC_INST_CALL;
43250696a6eSStefan Eßer 		*can_assign = false;
43350696a6eSStefan Eßer 
43450696a6eSStefan Eßer 		bc_parse_call(p, name, flags);
43550696a6eSStefan Eßer 	}
43650696a6eSStefan Eßer 	else {
43744d4804dSStefan Eßer 		// Just a variable.
43850696a6eSStefan Eßer 		*type = BC_INST_VAR;
43950696a6eSStefan Eßer 		*can_assign = true;
44050696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_VAR);
44150696a6eSStefan Eßer 		bc_parse_pushName(p, name, true);
44250696a6eSStefan Eßer 	}
44350696a6eSStefan Eßer 
44450696a6eSStefan Eßer err:
44544d4804dSStefan Eßer 	// Need to make sure to unallocate the name.
44650696a6eSStefan Eßer 	free(name);
44750696a6eSStefan Eßer 	BC_LONGJMP_CONT;
448*10041e99SStefan Eßer 	BC_SIG_MAYLOCK;
44950696a6eSStefan Eßer }
45050696a6eSStefan Eßer 
45144d4804dSStefan Eßer /**
45244d4804dSStefan Eßer  * Parses a builtin function that takes no arguments. This includes read(),
45344d4804dSStefan Eßer  * rand(), maxibase(), maxobase(), maxscale(), and maxrand().
45444d4804dSStefan Eßer  * @param p     The parser.
45544d4804dSStefan Eßer  * @param inst  The instruction corresponding to the builtin.
45644d4804dSStefan Eßer  */
45750696a6eSStefan Eßer static void bc_parse_noArgBuiltin(BcParse *p, BcInst inst) {
45850696a6eSStefan Eßer 
45944d4804dSStefan Eßer 	// Must have a left paren.
46050696a6eSStefan Eßer 	bc_lex_next(&p->l);
46150696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
46250696a6eSStefan Eßer 
46344d4804dSStefan Eßer 	// Must have a right paren.
46450696a6eSStefan Eßer 	bc_lex_next(&p->l);
46550696a6eSStefan Eßer 	if ((p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
46650696a6eSStefan Eßer 
46750696a6eSStefan Eßer 	bc_parse_push(p, inst);
46850696a6eSStefan Eßer 
46950696a6eSStefan Eßer 	bc_lex_next(&p->l);
47050696a6eSStefan Eßer }
47150696a6eSStefan Eßer 
47244d4804dSStefan Eßer /**
47344d4804dSStefan Eßer  * Parses a builtin function that takes 1 argument. This includes length(),
47444d4804dSStefan Eßer  * sqrt(), abs(), scale(), and irand().
47544d4804dSStefan Eßer  * @param p      The parser.
47644d4804dSStefan Eßer  * @param type   The lex token.
47744d4804dSStefan Eßer  * @param flags  The expression parsing flags for parsing the argument.
47844d4804dSStefan Eßer  * @param prev   An out parameter; the previous instruction pointer.
47944d4804dSStefan Eßer  */
48050696a6eSStefan Eßer static void bc_parse_builtin(BcParse *p, BcLexType type,
48150696a6eSStefan Eßer                              uint8_t flags, BcInst *prev)
48250696a6eSStefan Eßer {
48344d4804dSStefan Eßer 	// Must have a left paren.
48450696a6eSStefan Eßer 	bc_lex_next(&p->l);
48550696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
48650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
48750696a6eSStefan Eßer 
48850696a6eSStefan Eßer 	bc_lex_next(&p->l);
48950696a6eSStefan Eßer 
49044d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
49150696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
49250696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
49344d4804dSStefan Eßer 
49444d4804dSStefan Eßer 	// Since length can take arrays, we need to specially add that flag.
49550696a6eSStefan Eßer 	if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY;
49650696a6eSStefan Eßer 
49750696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
49850696a6eSStefan Eßer 
49944d4804dSStefan Eßer 	// Must have a right paren.
50050696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
50150696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
50250696a6eSStefan Eßer 
50344d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
50450696a6eSStefan Eßer 	*prev = type - BC_LEX_KW_LENGTH + BC_INST_LENGTH;
50550696a6eSStefan Eßer 	bc_parse_push(p, *prev);
50650696a6eSStefan Eßer 
50750696a6eSStefan Eßer 	bc_lex_next(&p->l);
50850696a6eSStefan Eßer }
50950696a6eSStefan Eßer 
51044d4804dSStefan Eßer /**
51144d4804dSStefan Eßer  * Parses a builtin function that takes 3 arguments. This includes modexp() and
51244d4804dSStefan Eßer  * divmod().
51344d4804dSStefan Eßer  */
51444d4804dSStefan Eßer static void bc_parse_builtin3(BcParse *p, BcLexType type,
51544d4804dSStefan Eßer                               uint8_t flags, BcInst *prev)
51644d4804dSStefan Eßer {
51744d4804dSStefan Eßer 	assert(type == BC_LEX_KW_MODEXP || type == BC_LEX_KW_DIVMOD);
51844d4804dSStefan Eßer 
51944d4804dSStefan Eßer 	// Must have a left paren.
52044d4804dSStefan Eßer 	bc_lex_next(&p->l);
52144d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
52244d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
52344d4804dSStefan Eßer 
52444d4804dSStefan Eßer 	bc_lex_next(&p->l);
52544d4804dSStefan Eßer 
52644d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
52744d4804dSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
52844d4804dSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
52944d4804dSStefan Eßer 
53044d4804dSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
53144d4804dSStefan Eßer 
53244d4804dSStefan Eßer 	// Must have a comma.
53344d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA))
53444d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
53544d4804dSStefan Eßer 
53644d4804dSStefan Eßer 	bc_lex_next(&p->l);
53744d4804dSStefan Eßer 
53844d4804dSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
53944d4804dSStefan Eßer 
54044d4804dSStefan Eßer 	// Must have a comma.
54144d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA))
54244d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
54344d4804dSStefan Eßer 
54444d4804dSStefan Eßer 	bc_lex_next(&p->l);
54544d4804dSStefan Eßer 
54644d4804dSStefan Eßer 	// If it is a divmod, parse an array name. Otherwise, just parse another
54744d4804dSStefan Eßer 	// expression.
54844d4804dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD) {
54944d4804dSStefan Eßer 
55044d4804dSStefan Eßer 		// Must have a name.
55144d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
55244d4804dSStefan Eßer 
55344d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
55444d4804dSStefan Eßer 		bc_lex_next(&p->l);
55544d4804dSStefan Eßer 
55644d4804dSStefan Eßer 		// Must have a left bracket.
55744d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_LBRACKET))
55844d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
55944d4804dSStefan Eßer 
56044d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
56144d4804dSStefan Eßer 		bc_lex_next(&p->l);
56244d4804dSStefan Eßer 
56344d4804dSStefan Eßer 		// Must have a right bracket.
56444d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
56544d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
56644d4804dSStefan Eßer 
56744d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
56844d4804dSStefan Eßer 		bc_lex_next(&p->l);
56944d4804dSStefan Eßer 	}
57044d4804dSStefan Eßer 	else bc_parse_expr_status(p, flags, bc_parse_next_rel);
57144d4804dSStefan Eßer 
57244d4804dSStefan Eßer 	// Must have a right paren.
57344d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
57444d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
57544d4804dSStefan Eßer 
57644d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
57744d4804dSStefan Eßer 	*prev = type - BC_LEX_KW_MODEXP + BC_INST_MODEXP;
57844d4804dSStefan Eßer 	bc_parse_push(p, *prev);
57944d4804dSStefan Eßer 
58044d4804dSStefan Eßer 	// If we have divmod, we need to assign the modulus to the array element, so
58144d4804dSStefan Eßer 	// we need to push the instructions for doing so.
58244d4804dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD) {
58344d4804dSStefan Eßer 
58444d4804dSStefan Eßer 		// The zeroth element.
58544d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ZERO);
58644d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ARRAY_ELEM);
58744d4804dSStefan Eßer 
58844d4804dSStefan Eßer 		// Push the array.
58944d4804dSStefan Eßer 		bc_parse_pushName(p, p->l.str.v, false);
59044d4804dSStefan Eßer 
59144d4804dSStefan Eßer 		// Swap them and assign. After this, the top item on the stack should
59244d4804dSStefan Eßer 		// be the quotient.
59344d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_SWAP);
59444d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
59544d4804dSStefan Eßer 	}
59644d4804dSStefan Eßer 
59744d4804dSStefan Eßer 	bc_lex_next(&p->l);
59844d4804dSStefan Eßer }
59944d4804dSStefan Eßer 
60044d4804dSStefan Eßer /**
60144d4804dSStefan Eßer  * Parses the scale keyword. This is special because scale can be a value or a
60244d4804dSStefan Eßer  * builtin function.
60344d4804dSStefan Eßer  * @param p           The parser.
60444d4804dSStefan Eßer  * @param type        An out parameter; the instruction for the parse.
60544d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
60644d4804dSStefan Eßer  *                    to.
60744d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
60844d4804dSStefan Eßer  */
60950696a6eSStefan Eßer static void bc_parse_scale(BcParse *p, BcInst *type,
61050696a6eSStefan Eßer                            bool *can_assign, uint8_t flags)
61150696a6eSStefan Eßer {
61250696a6eSStefan Eßer 	bc_lex_next(&p->l);
61350696a6eSStefan Eßer 
61444d4804dSStefan Eßer 	// Without the left paren, it's just the keyword.
61550696a6eSStefan Eßer 	if (p->l.t != BC_LEX_LPAREN) {
61644d4804dSStefan Eßer 
61744d4804dSStefan Eßer 		// Set, push, and return.
61850696a6eSStefan Eßer 		*type = BC_INST_SCALE;
61950696a6eSStefan Eßer 		*can_assign = true;
62050696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_SCALE);
62150696a6eSStefan Eßer 		return;
62250696a6eSStefan Eßer 	}
62350696a6eSStefan Eßer 
62444d4804dSStefan Eßer 	// Handle the scale function.
62550696a6eSStefan Eßer 	*type = BC_INST_SCALE_FUNC;
62650696a6eSStefan Eßer 	*can_assign = false;
62744d4804dSStefan Eßer 
62844d4804dSStefan Eßer 	// Once again, adjust the flags.
62950696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
63050696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
63150696a6eSStefan Eßer 
63250696a6eSStefan Eßer 	bc_lex_next(&p->l);
63350696a6eSStefan Eßer 
63450696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
63544d4804dSStefan Eßer 
63644d4804dSStefan Eßer 	// Must have a right paren.
63750696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
63850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
63950696a6eSStefan Eßer 
64050696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_SCALE_FUNC);
64150696a6eSStefan Eßer 
64250696a6eSStefan Eßer 	bc_lex_next(&p->l);
64350696a6eSStefan Eßer }
64450696a6eSStefan Eßer 
64544d4804dSStefan Eßer /**
64644d4804dSStefan Eßer  * Parses and increment or decrement operator. This is a bit complex.
64744d4804dSStefan Eßer  * @param p           The parser.
64844d4804dSStefan Eßer  * @param prev        An out parameter; the previous instruction pointer.
64944d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
65044d4804dSStefan Eßer  *                    to.
65144d4804dSStefan Eßer  * @param nexs        An in/out parameter; the number of expressions in the
65244d4804dSStefan Eßer  *                    parse tree that are not used.
65344d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
65444d4804dSStefan Eßer  */
65550696a6eSStefan Eßer static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign,
65650696a6eSStefan Eßer                             size_t *nexs, uint8_t flags)
65750696a6eSStefan Eßer {
65850696a6eSStefan Eßer 	BcLexType type;
65950696a6eSStefan Eßer 	uchar inst;
66050696a6eSStefan Eßer 	BcInst etype = *prev;
66150696a6eSStefan Eßer 	BcLexType last = p->l.last;
66250696a6eSStefan Eßer 
66350696a6eSStefan Eßer 	assert(prev != NULL && can_assign != NULL);
66450696a6eSStefan Eßer 
66544d4804dSStefan Eßer 	// If we can't assign to the previous token, then we have an error.
66650696a6eSStefan Eßer 	if (BC_ERR(last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC ||
66750696a6eSStefan Eßer 	           last == BC_LEX_RPAREN))
66850696a6eSStefan Eßer 	{
66950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
67050696a6eSStefan Eßer 	}
67150696a6eSStefan Eßer 
67244d4804dSStefan Eßer 	// Is the previous instruction for a variable?
67350696a6eSStefan Eßer 	if (BC_PARSE_INST_VAR(etype)) {
67450696a6eSStefan Eßer 
67544d4804dSStefan Eßer 		// If so, this is a postfix operator.
67650696a6eSStefan Eßer 		if (!*can_assign) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
67750696a6eSStefan Eßer 
67844d4804dSStefan Eßer 		// Only postfix uses BC_INST_INC and BC_INST_DEC.
67950696a6eSStefan Eßer 		*prev = inst = BC_INST_INC + (p->l.t != BC_LEX_OP_INC);
68050696a6eSStefan Eßer 		bc_parse_push(p, inst);
68150696a6eSStefan Eßer 		bc_lex_next(&p->l);
68250696a6eSStefan Eßer 		*can_assign = false;
68350696a6eSStefan Eßer 	}
68450696a6eSStefan Eßer 	else {
68550696a6eSStefan Eßer 
68644d4804dSStefan Eßer 		// This is a prefix operator. In that case, we just convert it to
68744d4804dSStefan Eßer 		// an assignment instruction.
68850696a6eSStefan Eßer 		*prev = inst = BC_INST_ASSIGN_PLUS + (p->l.t != BC_LEX_OP_INC);
68950696a6eSStefan Eßer 
69050696a6eSStefan Eßer 		bc_lex_next(&p->l);
69150696a6eSStefan Eßer 		type = p->l.t;
69250696a6eSStefan Eßer 
69350696a6eSStefan Eßer 		// Because we parse the next part of the expression
69450696a6eSStefan Eßer 		// right here, we need to increment this.
69550696a6eSStefan Eßer 		*nexs = *nexs + 1;
69650696a6eSStefan Eßer 
69744d4804dSStefan Eßer 		// Is the next token a normal identifier?
69850696a6eSStefan Eßer 		if (type == BC_LEX_NAME) {
69944d4804dSStefan Eßer 
70044d4804dSStefan Eßer 			// Parse the name.
70150696a6eSStefan Eßer 			uint8_t flags2 = flags & ~BC_PARSE_ARRAY;
70250696a6eSStefan Eßer 			bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
70350696a6eSStefan Eßer 		}
70444d4804dSStefan Eßer 		// Is the next token a global?
70550696a6eSStefan Eßer 		else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE) {
70650696a6eSStefan Eßer 			bc_parse_push(p, type - BC_LEX_KW_LAST + BC_INST_LAST);
70750696a6eSStefan Eßer 			bc_lex_next(&p->l);
70850696a6eSStefan Eßer 		}
70944d4804dSStefan Eßer 		// Is the next token specifically scale, which needs special treatment?
71050696a6eSStefan Eßer 		else if (BC_NO_ERR(type == BC_LEX_KW_SCALE)) {
71150696a6eSStefan Eßer 
71250696a6eSStefan Eßer 			bc_lex_next(&p->l);
71350696a6eSStefan Eßer 
71444d4804dSStefan Eßer 			// Check that scale() was not used.
71550696a6eSStefan Eßer 			if (BC_ERR(p->l.t == BC_LEX_LPAREN))
71650696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
71750696a6eSStefan Eßer 			else bc_parse_push(p, BC_INST_SCALE);
71850696a6eSStefan Eßer 		}
71944d4804dSStefan Eßer 		// Now we know we have an error.
72050696a6eSStefan Eßer 		else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
72150696a6eSStefan Eßer 
72250696a6eSStefan Eßer 		*can_assign = false;
72350696a6eSStefan Eßer 
72450696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_ONE);
72550696a6eSStefan Eßer 		bc_parse_push(p, inst);
72650696a6eSStefan Eßer 	}
72750696a6eSStefan Eßer }
72850696a6eSStefan Eßer 
72944d4804dSStefan Eßer /**
73044d4804dSStefan Eßer  * Parses the minus operator. This needs special treatment because it is either
73144d4804dSStefan Eßer  * subtract or negation.
73244d4804dSStefan Eßer  * @param p        The parser.
73344d4804dSStefan Eßer  * @param prev     An in/out parameter; the previous instruction.
73444d4804dSStefan Eßer  * @param ops_bgn  The size of the operator stack.
73544d4804dSStefan Eßer  * @param rparen   True if the last token was a right paren.
73644d4804dSStefan Eßer  * @param binlast  True if the last token was a binary operator.
73744d4804dSStefan Eßer  * @param nexprs   An in/out parameter; the number of unused expressions.
73844d4804dSStefan Eßer  */
73950696a6eSStefan Eßer static void bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
74050696a6eSStefan Eßer                            bool rparen, bool binlast, size_t *nexprs)
74150696a6eSStefan Eßer {
74250696a6eSStefan Eßer 	BcLexType type;
74350696a6eSStefan Eßer 
74450696a6eSStefan Eßer 	bc_lex_next(&p->l);
74550696a6eSStefan Eßer 
74644d4804dSStefan Eßer 	// Figure out if it's a minus or a negation.
74750696a6eSStefan Eßer 	type = BC_PARSE_LEAF(*prev, binlast, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
74850696a6eSStefan Eßer 	*prev = BC_PARSE_TOKEN_INST(type);
74950696a6eSStefan Eßer 
75050696a6eSStefan Eßer 	// We can just push onto the op stack because this is the largest
75150696a6eSStefan Eßer 	// precedence operator that gets pushed. Inc/dec does not.
75250696a6eSStefan Eßer 	if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
75350696a6eSStefan Eßer 	else bc_parse_operator(p, type, ops_bgn, nexprs);
75450696a6eSStefan Eßer }
75550696a6eSStefan Eßer 
75644d4804dSStefan Eßer /**
75744d4804dSStefan Eßer  * Parses a string.
75844d4804dSStefan Eßer  * @param p     The parser.
75944d4804dSStefan Eßer  * @param inst  The instruction corresponding to how the string was found and
76044d4804dSStefan Eßer  *              how it should be printed.
76144d4804dSStefan Eßer  */
76244d4804dSStefan Eßer static void bc_parse_str(BcParse *p, BcInst inst) {
76350696a6eSStefan Eßer 	bc_parse_addString(p);
76450696a6eSStefan Eßer 	bc_parse_push(p, inst);
76550696a6eSStefan Eßer 	bc_lex_next(&p->l);
76650696a6eSStefan Eßer }
76750696a6eSStefan Eßer 
76844d4804dSStefan Eßer /**
76944d4804dSStefan Eßer  * Parses a print statement.
77044d4804dSStefan Eßer  * @param p  The parser.
77144d4804dSStefan Eßer  */
77244d4804dSStefan Eßer static void bc_parse_print(BcParse *p, BcLexType type) {
77350696a6eSStefan Eßer 
77450696a6eSStefan Eßer 	BcLexType t;
77550696a6eSStefan Eßer 	bool comma = false;
77644d4804dSStefan Eßer 	BcInst inst = type == BC_LEX_KW_STREAM ?
77744d4804dSStefan Eßer 	              BC_INST_PRINT_STREAM : BC_INST_PRINT_POP;
77850696a6eSStefan Eßer 
77950696a6eSStefan Eßer 	bc_lex_next(&p->l);
78050696a6eSStefan Eßer 
78150696a6eSStefan Eßer 	t = p->l.t;
78250696a6eSStefan Eßer 
78344d4804dSStefan Eßer 	// A print or stream statement has to have *something*.
78450696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_PRINT);
78550696a6eSStefan Eßer 
78650696a6eSStefan Eßer 	do {
78744d4804dSStefan Eßer 
78844d4804dSStefan Eßer 		// If the token is a string, then print it with escapes.
78944d4804dSStefan Eßer 		// BC_INST_PRINT_POP plays that role for bc.
79044d4804dSStefan Eßer 		if (t == BC_LEX_STR) bc_parse_str(p, inst);
79150696a6eSStefan Eßer 		else {
79244d4804dSStefan Eßer 			// We have an actual number; parse and add a print instruction.
79350696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_NEEDVAL, bc_parse_next_print);
79444d4804dSStefan Eßer 			bc_parse_push(p, inst);
79550696a6eSStefan Eßer 		}
79650696a6eSStefan Eßer 
79744d4804dSStefan Eßer 		// Is the next token a comma?
79850696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
79950696a6eSStefan Eßer 
80044d4804dSStefan Eßer 		// Get the next token if we have a comma.
80150696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
80250696a6eSStefan Eßer 		else {
80344d4804dSStefan Eßer 
80444d4804dSStefan Eßer 			// If we don't have a comma, the statement needs to end.
80550696a6eSStefan Eßer 			if (!bc_parse_isDelimiter(p))
80650696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
80750696a6eSStefan Eßer 			else break;
80850696a6eSStefan Eßer 		}
80950696a6eSStefan Eßer 
81050696a6eSStefan Eßer 		t = p->l.t;
81144d4804dSStefan Eßer 
81250696a6eSStefan Eßer 	} while (true);
81350696a6eSStefan Eßer 
81444d4804dSStefan Eßer 	// If we have a comma but no token, that's bad.
81550696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
81650696a6eSStefan Eßer }
81750696a6eSStefan Eßer 
81844d4804dSStefan Eßer /**
81944d4804dSStefan Eßer  * Parses a return statement.
82044d4804dSStefan Eßer  * @param p  The parser.
82144d4804dSStefan Eßer  */
82250696a6eSStefan Eßer static void bc_parse_return(BcParse *p) {
82350696a6eSStefan Eßer 
82450696a6eSStefan Eßer 	BcLexType t;
82550696a6eSStefan Eßer 	bool paren;
82650696a6eSStefan Eßer 	uchar inst = BC_INST_RET0;
82750696a6eSStefan Eßer 
82844d4804dSStefan Eßer 	// If we are not in a function, that's an error.
82950696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_FUNC(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
83050696a6eSStefan Eßer 
83144d4804dSStefan Eßer 	// If we are in a void function, make sure to return void.
83250696a6eSStefan Eßer 	if (p->func->voidfn) inst = BC_INST_RET_VOID;
83350696a6eSStefan Eßer 
83450696a6eSStefan Eßer 	bc_lex_next(&p->l);
83550696a6eSStefan Eßer 
83650696a6eSStefan Eßer 	t = p->l.t;
83744d4804dSStefan Eßer 	paren = (t == BC_LEX_LPAREN);
83850696a6eSStefan Eßer 
83944d4804dSStefan Eßer 	// An empty return statement just needs to push the selected instruction.
84050696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
84150696a6eSStefan Eßer 	else {
84250696a6eSStefan Eßer 
84350696a6eSStefan Eßer 		BcParseStatus s;
84450696a6eSStefan Eßer 
84544d4804dSStefan Eßer 		// Need to parse the expression whose value will be returned.
84650696a6eSStefan Eßer 		s = bc_parse_expr_err(p, BC_PARSE_NEEDVAL, bc_parse_next_expr);
84750696a6eSStefan Eßer 
84844d4804dSStefan Eßer 		// If the expression was empty, just push the selected instruction.
84950696a6eSStefan Eßer 		if (s == BC_PARSE_STATUS_EMPTY_EXPR) {
85050696a6eSStefan Eßer 			bc_parse_push(p, inst);
85150696a6eSStefan Eßer 			bc_lex_next(&p->l);
85250696a6eSStefan Eßer 		}
85350696a6eSStefan Eßer 
85444d4804dSStefan Eßer 		// POSIX requires parentheses.
85550696a6eSStefan Eßer 		if (!paren || p->l.last != BC_LEX_RPAREN) {
85650696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_RET);
85750696a6eSStefan Eßer 		}
85844d4804dSStefan Eßer 
85944d4804dSStefan Eßer 		// Void functions require an empty expression.
86044d4804dSStefan Eßer 		if (BC_ERR(p->func->voidfn)) {
86144d4804dSStefan Eßer 			if (s != BC_PARSE_STATUS_EMPTY_EXPR)
86250696a6eSStefan Eßer 				bc_parse_verr(p, BC_ERR_PARSE_RET_VOID, p->func->name);
86344d4804dSStefan Eßer 		}
86444d4804dSStefan Eßer 		// If we got here, we want to be sure to end the function with a real
86544d4804dSStefan Eßer 		// return instruction, just in case.
86644d4804dSStefan Eßer 		else bc_parse_push(p, BC_INST_RET);
86750696a6eSStefan Eßer 	}
86850696a6eSStefan Eßer }
86950696a6eSStefan Eßer 
87044d4804dSStefan Eßer /**
87144d4804dSStefan Eßer  * Clears flags that indicate the end of an if statement and its block and sets
87244d4804dSStefan Eßer  * the jump location.
87344d4804dSStefan Eßer  * @param p  The parser.
87444d4804dSStefan Eßer  */
87550696a6eSStefan Eßer static void bc_parse_noElse(BcParse *p) {
87650696a6eSStefan Eßer 	uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
87750696a6eSStefan Eßer 	*flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
87850696a6eSStefan Eßer 	bc_parse_setLabel(p);
87950696a6eSStefan Eßer }
88050696a6eSStefan Eßer 
88144d4804dSStefan Eßer /**
88244d4804dSStefan Eßer  * Ends (finishes parsing) the body of a control statement or a function.
88344d4804dSStefan Eßer  * @param p      The parser.
88444d4804dSStefan Eßer  * @param brace  True if the body was ended by a brace, false otherwise.
88544d4804dSStefan Eßer  */
88650696a6eSStefan Eßer static void bc_parse_endBody(BcParse *p, bool brace) {
88750696a6eSStefan Eßer 
88850696a6eSStefan Eßer 	bool has_brace, new_else = false;
88950696a6eSStefan Eßer 
89044d4804dSStefan Eßer 	// We cannot be ending a body if there are no bodies to end.
89150696a6eSStefan Eßer 	if (BC_ERR(p->flags.len <= 1)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
89250696a6eSStefan Eßer 
89350696a6eSStefan Eßer 	if (brace) {
89450696a6eSStefan Eßer 
89544d4804dSStefan Eßer 		// The brace was already gotten; make sure that the caller did not lie.
89644d4804dSStefan Eßer 		// We check for the requirement of braces later.
89750696a6eSStefan Eßer 		assert(p->l.t == BC_LEX_RBRACE);
89850696a6eSStefan Eßer 
89950696a6eSStefan Eßer 		bc_lex_next(&p->l);
90044d4804dSStefan Eßer 
90144d4804dSStefan Eßer 		// If the next token is not a delimiter, that is a problem.
902*10041e99SStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p) && !bc_parse_TopFunc(p)))
90350696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
90450696a6eSStefan Eßer 	}
90550696a6eSStefan Eßer 
90644d4804dSStefan Eßer 	// Do we have a brace flag?
90750696a6eSStefan Eßer 	has_brace = (BC_PARSE_BRACE(p) != 0);
90850696a6eSStefan Eßer 
90950696a6eSStefan Eßer 	do {
91050696a6eSStefan Eßer 		size_t len = p->flags.len;
91150696a6eSStefan Eßer 		bool loop;
91250696a6eSStefan Eßer 
91344d4804dSStefan Eßer 		// If we have a brace flag but not a brace, that's a problem.
91450696a6eSStefan Eßer 		if (has_brace && !brace) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
91550696a6eSStefan Eßer 
91644d4804dSStefan Eßer 		// Are we inside a loop?
91750696a6eSStefan Eßer 		loop = (BC_PARSE_LOOP_INNER(p) != 0);
91850696a6eSStefan Eßer 
91944d4804dSStefan Eßer 		// If we are ending a loop or an else...
92050696a6eSStefan Eßer 		if (loop || BC_PARSE_ELSE(p)) {
92150696a6eSStefan Eßer 
92244d4804dSStefan Eßer 			// Loops have condition labels that we have to take care of as well.
92350696a6eSStefan Eßer 			if (loop) {
92450696a6eSStefan Eßer 
92550696a6eSStefan Eßer 				size_t *label = bc_vec_top(&p->conds);
92650696a6eSStefan Eßer 
92750696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_JUMP);
92850696a6eSStefan Eßer 				bc_parse_pushIndex(p, *label);
92950696a6eSStefan Eßer 
93050696a6eSStefan Eßer 				bc_vec_pop(&p->conds);
93150696a6eSStefan Eßer 			}
93250696a6eSStefan Eßer 
93350696a6eSStefan Eßer 			bc_parse_setLabel(p);
93450696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
93550696a6eSStefan Eßer 		}
93644d4804dSStefan Eßer 		// If we are ending a function...
93750696a6eSStefan Eßer 		else if (BC_PARSE_FUNC_INNER(p)) {
93850696a6eSStefan Eßer 			BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
93950696a6eSStefan Eßer 			bc_parse_push(p, inst);
94050696a6eSStefan Eßer 			bc_parse_updateFunc(p, BC_PROG_MAIN);
94150696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
94250696a6eSStefan Eßer 		}
94344d4804dSStefan Eßer 		// If we have a brace flag and not an if statement, we can pop the top
94444d4804dSStefan Eßer 		// of the flags stack because they have been taken care of above.
94544d4804dSStefan Eßer 		else if (has_brace && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
94650696a6eSStefan Eßer 
94750696a6eSStefan Eßer 		// This needs to be last to parse nested if's properly.
94850696a6eSStefan Eßer 		if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) {
94950696a6eSStefan Eßer 
95044d4804dSStefan Eßer 			// Eat newlines.
95150696a6eSStefan Eßer 			while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
95250696a6eSStefan Eßer 
95344d4804dSStefan Eßer 			// *Now* we can pop the flags.
95450696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
95550696a6eSStefan Eßer 
95644d4804dSStefan Eßer 			// If we are allowed non-POSIX stuff...
95750696a6eSStefan Eßer 			if (!BC_S) {
95850696a6eSStefan Eßer 
95944d4804dSStefan Eßer 				// Have we found yet another dangling else?
96050696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
96150696a6eSStefan Eßer 				new_else = (p->l.t == BC_LEX_KW_ELSE);
96250696a6eSStefan Eßer 
96344d4804dSStefan Eßer 				// Parse the else or end the if statement body.
96450696a6eSStefan Eßer 				if (new_else) bc_parse_else(p);
96550696a6eSStefan Eßer 				else if (!has_brace && (!BC_PARSE_IF_END(p) || brace))
96650696a6eSStefan Eßer 					bc_parse_noElse(p);
96750696a6eSStefan Eßer 			}
96844d4804dSStefan Eßer 			// POSIX requires us to do the bare minimum only.
96950696a6eSStefan Eßer 			else bc_parse_noElse(p);
97050696a6eSStefan Eßer 		}
97150696a6eSStefan Eßer 
97244d4804dSStefan Eßer 		// If these are both true, we have "used" the braces that we found.
97350696a6eSStefan Eßer 		if (brace && has_brace) brace = false;
97450696a6eSStefan Eßer 
97544d4804dSStefan Eßer 	// This condition was perhaps the hardest single part of the parser. If the
97644d4804dSStefan Eßer 	// flags stack does not have enough, we should stop. If we have a new else
97744d4804dSStefan Eßer 	// statement, we should stop. If we do have the end of an if statement and
97844d4804dSStefan Eßer 	// we have eaten the brace, we should stop. If we do have a brace flag, we
97944d4804dSStefan Eßer 	// should stop.
98050696a6eSStefan Eßer 	} while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
98150696a6eSStefan Eßer 	         !(has_brace = (BC_PARSE_BRACE(p) != 0)));
98250696a6eSStefan Eßer 
98344d4804dSStefan Eßer 	// If we have a brace, yet no body for it, that's a problem.
98450696a6eSStefan Eßer 	if (BC_ERR(p->flags.len == 1 && brace))
98550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
98650696a6eSStefan Eßer 	else if (brace && BC_PARSE_BRACE(p)) {
98750696a6eSStefan Eßer 
98844d4804dSStefan Eßer 		// If we make it here, we have a brace and a flag for it.
98950696a6eSStefan Eßer 		uint16_t flags = BC_PARSE_TOP_FLAG(p);
99050696a6eSStefan Eßer 
99144d4804dSStefan Eßer 		// This condition ensure that the *last* body is correctly finished by
99244d4804dSStefan Eßer 		// popping its flags.
99350696a6eSStefan Eßer 		if (!(flags & (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_LOOP_INNER)) &&
99450696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF | BC_PARSE_FLAG_ELSE)) &&
99550696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF_END)))
99650696a6eSStefan Eßer 		{
99750696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
99850696a6eSStefan Eßer 		}
99950696a6eSStefan Eßer 	}
100050696a6eSStefan Eßer }
100150696a6eSStefan Eßer 
100244d4804dSStefan Eßer /**
100344d4804dSStefan Eßer  * Starts the body of a control statement or function.
100444d4804dSStefan Eßer  * @param p      The parser.
100544d4804dSStefan Eßer  * @param flags  The current flags (will be edited).
100644d4804dSStefan Eßer  */
100750696a6eSStefan Eßer static void bc_parse_startBody(BcParse *p, uint16_t flags) {
100850696a6eSStefan Eßer 	assert(flags);
100950696a6eSStefan Eßer 	flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
101050696a6eSStefan Eßer 	flags |= BC_PARSE_FLAG_BODY;
101150696a6eSStefan Eßer 	bc_vec_push(&p->flags, &flags);
101250696a6eSStefan Eßer }
101350696a6eSStefan Eßer 
1014a30efc5cSStefan Eßer void bc_parse_endif(BcParse *p) {
1015a30efc5cSStefan Eßer 
1016a30efc5cSStefan Eßer 	size_t i;
1017a30efc5cSStefan Eßer 	bool good;
1018a30efc5cSStefan Eßer 
1019a30efc5cSStefan Eßer 	// Not a problem if this is true.
1020a30efc5cSStefan Eßer 	if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
1021a30efc5cSStefan Eßer 
1022a30efc5cSStefan Eßer 	good = true;
1023a30efc5cSStefan Eßer 
1024a30efc5cSStefan Eßer 	// Find an instance of a body that needs closing, i.e., a statement that did
1025a30efc5cSStefan Eßer 	// not have a right brace when it should have.
1026a30efc5cSStefan Eßer 	for (i = 0; good && i < p->flags.len; ++i) {
1027a30efc5cSStefan Eßer 		uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
1028a30efc5cSStefan Eßer 		good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
1029a30efc5cSStefan Eßer 	}
1030a30efc5cSStefan Eßer 
1031a30efc5cSStefan Eßer 	// If we did not find such an instance...
1032a30efc5cSStefan Eßer 	if (good) {
1033a30efc5cSStefan Eßer 
1034a30efc5cSStefan Eßer 		// We set this to restore it later. We don't want the parser thinking
1035a30efc5cSStefan Eßer 		// that we are on stdin for this one because it will want more.
1036a30efc5cSStefan Eßer 		bool is_stdin = vm.is_stdin;
1037a30efc5cSStefan Eßer 
1038a30efc5cSStefan Eßer 		vm.is_stdin = false;
1039a30efc5cSStefan Eßer 
1040a30efc5cSStefan Eßer 		// End all of the if statements and loops.
1041a30efc5cSStefan Eßer 		while (p->flags.len > 1 || BC_PARSE_IF_END(p)) {
1042a30efc5cSStefan Eßer 			if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
1043a30efc5cSStefan Eßer 			if (p->flags.len > 1) bc_parse_endBody(p, false);
1044a30efc5cSStefan Eßer 		}
1045a30efc5cSStefan Eßer 
1046a30efc5cSStefan Eßer 		vm.is_stdin = is_stdin;
1047a30efc5cSStefan Eßer 	}
1048a30efc5cSStefan Eßer 	// If we reach here, a block was not properly closed, and we should error.
1049a30efc5cSStefan Eßer 	else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
1050a30efc5cSStefan Eßer }
1051a30efc5cSStefan Eßer 
105244d4804dSStefan Eßer /**
105344d4804dSStefan Eßer  * Parses an if statement.
105444d4804dSStefan Eßer  * @param p  The parser.
105544d4804dSStefan Eßer  */
105650696a6eSStefan Eßer static void bc_parse_if(BcParse *p) {
105750696a6eSStefan Eßer 
105844d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
105950696a6eSStefan Eßer 	size_t idx;
106050696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
106150696a6eSStefan Eßer 
106244d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
106350696a6eSStefan Eßer 	bc_lex_next(&p->l);
106450696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
106550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
106650696a6eSStefan Eßer 
106744d4804dSStefan Eßer 	// Parse the condition.
106850696a6eSStefan Eßer 	bc_lex_next(&p->l);
106950696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
107044d4804dSStefan Eßer 
107144d4804dSStefan Eßer 	// Must have a right paren.
107250696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
107350696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
107450696a6eSStefan Eßer 
107550696a6eSStefan Eßer 	bc_lex_next(&p->l);
107644d4804dSStefan Eßer 
107744d4804dSStefan Eßer 	// Insert the conditional jump instruction.
107850696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
107950696a6eSStefan Eßer 
108050696a6eSStefan Eßer 	idx = p->func->labels.len;
108150696a6eSStefan Eßer 
108244d4804dSStefan Eßer 	// Push the index for the instruction and create an exit label for an else
108344d4804dSStefan Eßer 	// statement.
108450696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
108550696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
108644d4804dSStefan Eßer 
108750696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_IF);
108850696a6eSStefan Eßer }
108950696a6eSStefan Eßer 
109044d4804dSStefan Eßer /**
109144d4804dSStefan Eßer  * Parses an else statement.
109244d4804dSStefan Eßer  * @param p  The parser.
109344d4804dSStefan Eßer  */
109450696a6eSStefan Eßer static void bc_parse_else(BcParse *p) {
109550696a6eSStefan Eßer 
109650696a6eSStefan Eßer 	size_t idx = p->func->labels.len;
109750696a6eSStefan Eßer 
109844d4804dSStefan Eßer 	// We must be at the end of an if statement.
109950696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_IF_END(p)))
110050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
110150696a6eSStefan Eßer 
110244d4804dSStefan Eßer 	// Push an unconditional jump to make bc jump over the else statement if it
110344d4804dSStefan Eßer 	// executed the original if statement.
110450696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
110550696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
110650696a6eSStefan Eßer 
110744d4804dSStefan Eßer 	// Clear the else stuff. Yes, that function is misnamed for its use here,
110844d4804dSStefan Eßer 	// but deal with it.
110950696a6eSStefan Eßer 	bc_parse_noElse(p);
111050696a6eSStefan Eßer 
111144d4804dSStefan Eßer 	// Create the exit label and parse the body.
111250696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
111350696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
111450696a6eSStefan Eßer 
111550696a6eSStefan Eßer 	bc_lex_next(&p->l);
111650696a6eSStefan Eßer }
111750696a6eSStefan Eßer 
111844d4804dSStefan Eßer /**
111944d4804dSStefan Eßer  * Parse a while loop.
112044d4804dSStefan Eßer  * @param p  The parser.
112144d4804dSStefan Eßer  */
112250696a6eSStefan Eßer static void bc_parse_while(BcParse *p) {
112350696a6eSStefan Eßer 
112444d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
112550696a6eSStefan Eßer 	size_t idx;
112650696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
112750696a6eSStefan Eßer 
112844d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
112950696a6eSStefan Eßer 	bc_lex_next(&p->l);
113050696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
113150696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
113250696a6eSStefan Eßer 	bc_lex_next(&p->l);
113350696a6eSStefan Eßer 
113444d4804dSStefan Eßer 	// Create the labels. Loops need both.
113550696a6eSStefan Eßer 	bc_parse_createCondLabel(p, p->func->labels.len);
113650696a6eSStefan Eßer 	idx = p->func->labels.len;
113750696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, true);
113850696a6eSStefan Eßer 
113944d4804dSStefan Eßer 	// Parse the actual condition and barf on non-right paren.
114050696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
114150696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
114250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
114350696a6eSStefan Eßer 	bc_lex_next(&p->l);
114450696a6eSStefan Eßer 
114544d4804dSStefan Eßer 	// Now we can push the conditional jump and start the body.
114650696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
114750696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
114850696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
114950696a6eSStefan Eßer }
115050696a6eSStefan Eßer 
115144d4804dSStefan Eßer /**
115244d4804dSStefan Eßer  * Parse a for loop.
115344d4804dSStefan Eßer  * @param p  The parser.
115444d4804dSStefan Eßer  */
115550696a6eSStefan Eßer static void bc_parse_for(BcParse *p) {
115650696a6eSStefan Eßer 
115750696a6eSStefan Eßer 	size_t cond_idx, exit_idx, body_idx, update_idx;
115850696a6eSStefan Eßer 
115944d4804dSStefan Eßer 	// Barf on the missing left paren.
116050696a6eSStefan Eßer 	bc_lex_next(&p->l);
116150696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
116250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
116350696a6eSStefan Eßer 	bc_lex_next(&p->l);
116450696a6eSStefan Eßer 
116544d4804dSStefan Eßer 	// The first statement can be empty, but if it is, check for error in POSIX
116644d4804dSStefan Eßer 	// mode. Otherwise, parse it.
116750696a6eSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON)
116850696a6eSStefan Eßer 		bc_parse_expr_status(p, 0, bc_parse_next_for);
116950696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
117050696a6eSStefan Eßer 
117144d4804dSStefan Eßer 	// Must have a semicolon.
117244d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
117350696a6eSStefan Eßer 	bc_lex_next(&p->l);
117450696a6eSStefan Eßer 
117544d4804dSStefan Eßer 	// These are indices for labels. There are so many of them because the end
117644d4804dSStefan Eßer 	// of the loop must unconditionally jump to the update code. Then the update
117744d4804dSStefan Eßer 	// code must unconditionally jump to the condition code. Then the condition
117844d4804dSStefan Eßer 	// code must *conditionally* jump to the exit.
117950696a6eSStefan Eßer 	cond_idx = p->func->labels.len;
118050696a6eSStefan Eßer 	update_idx = cond_idx + 1;
118150696a6eSStefan Eßer 	body_idx = update_idx + 1;
118250696a6eSStefan Eßer 	exit_idx = body_idx + 1;
118350696a6eSStefan Eßer 
118444d4804dSStefan Eßer 	// This creates the condition label.
118550696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
118650696a6eSStefan Eßer 
118744d4804dSStefan Eßer 	// Parse an expression if it exists.
118850696a6eSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON) {
118950696a6eSStefan Eßer 		uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
119050696a6eSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_for);
119150696a6eSStefan Eßer 	}
119250696a6eSStefan Eßer 	else {
119350696a6eSStefan Eßer 
119444d4804dSStefan Eßer 		// Set this for the next call to bc_parse_number because an empty
119544d4804dSStefan Eßer 		// condition means that it is an infinite loop, so the condition must be
119644d4804dSStefan Eßer 		// non-zero. This is safe to set because the current token is a
119744d4804dSStefan Eßer 		// semicolon, which has no string requirement.
119850696a6eSStefan Eßer 		bc_vec_string(&p->l.str, sizeof(bc_parse_one) - 1, bc_parse_one);
119950696a6eSStefan Eßer 		bc_parse_number(p);
120050696a6eSStefan Eßer 
120144d4804dSStefan Eßer 		// An empty condition makes POSIX mad.
120250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_FOR);
120350696a6eSStefan Eßer 	}
120450696a6eSStefan Eßer 
120544d4804dSStefan Eßer 	// Must have a semicolon.
120650696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON))
120750696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
120850696a6eSStefan Eßer 	bc_lex_next(&p->l);
120950696a6eSStefan Eßer 
121044d4804dSStefan Eßer 	// Now we can set up the conditional jump to the exit and an unconditional
121144d4804dSStefan Eßer 	// jump to the body right after. The unconditional jump to the body is
121244d4804dSStefan Eßer 	// because there is update code coming right after the condition, so we need
121344d4804dSStefan Eßer 	// to skip it to get to the body.
121450696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
121550696a6eSStefan Eßer 	bc_parse_pushIndex(p, exit_idx);
121650696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
121750696a6eSStefan Eßer 	bc_parse_pushIndex(p, body_idx);
121850696a6eSStefan Eßer 
121944d4804dSStefan Eßer 	// Now create the label for the update code.
122050696a6eSStefan Eßer 	bc_parse_createCondLabel(p, update_idx);
122150696a6eSStefan Eßer 
122244d4804dSStefan Eßer 	// Parse if not empty, and if it is, let POSIX yell if necessary.
122350696a6eSStefan Eßer 	if (p->l.t != BC_LEX_RPAREN)
122450696a6eSStefan Eßer 		bc_parse_expr_status(p, 0, bc_parse_next_rel);
122550696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
122650696a6eSStefan Eßer 
122744d4804dSStefan Eßer 	// Must have a right paren.
122850696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
122950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
123044d4804dSStefan Eßer 
123144d4804dSStefan Eßer 	// Set up a jump to the condition right after the update code.
123250696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
123350696a6eSStefan Eßer 	bc_parse_pushIndex(p, cond_idx);
123450696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
123550696a6eSStefan Eßer 
123644d4804dSStefan Eßer 	// Create an exit label for the body and start the body.
123750696a6eSStefan Eßer 	bc_parse_createExitLabel(p, exit_idx, true);
123850696a6eSStefan Eßer 	bc_lex_next(&p->l);
123950696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
124050696a6eSStefan Eßer }
124150696a6eSStefan Eßer 
124244d4804dSStefan Eßer /**
124344d4804dSStefan Eßer  * Parse a statement or token that indicates a loop exit. This includes an
124444d4804dSStefan Eßer  * actual loop exit, the break keyword, or the continue keyword.
124544d4804dSStefan Eßer  * @param p     The parser.
124644d4804dSStefan Eßer  * @param type  The type of exit.
124744d4804dSStefan Eßer  */
124850696a6eSStefan Eßer static void bc_parse_loopExit(BcParse *p, BcLexType type) {
124950696a6eSStefan Eßer 
125050696a6eSStefan Eßer 	size_t i;
125150696a6eSStefan Eßer 	BcInstPtr *ip;
125250696a6eSStefan Eßer 
125344d4804dSStefan Eßer 	// Must have a loop. If we don't, that's an error.
125450696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_LOOP(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
125550696a6eSStefan Eßer 
125644d4804dSStefan Eßer 	// If we have a break statement...
125750696a6eSStefan Eßer 	if (type == BC_LEX_KW_BREAK) {
125850696a6eSStefan Eßer 
125944d4804dSStefan Eßer 		// If there are no exits, something went wrong somewhere.
126050696a6eSStefan Eßer 		if (BC_ERR(!p->exits.len)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
126150696a6eSStefan Eßer 
126244d4804dSStefan Eßer 		// Get the exit.
126350696a6eSStefan Eßer 		i = p->exits.len - 1;
126450696a6eSStefan Eßer 		ip = bc_vec_item(&p->exits, i);
126550696a6eSStefan Eßer 
126644d4804dSStefan Eßer 		// The condition !ip->func is true if the exit is not for a loop, so we
126744d4804dSStefan Eßer 		// need to find the first actual loop exit.
126850696a6eSStefan Eßer 		while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
126944d4804dSStefan Eßer 
127044d4804dSStefan Eßer 		// Make sure everything is hunky dory.
127150696a6eSStefan Eßer 		assert(ip != NULL && (i < p->exits.len || ip->func));
127244d4804dSStefan Eßer 
127344d4804dSStefan Eßer 		// Set the index for the exit.
127450696a6eSStefan Eßer 		i = ip->idx;
127550696a6eSStefan Eßer 	}
127644d4804dSStefan Eßer 	// If we have a continue statement or just the loop end, jump to the
127744d4804dSStefan Eßer 	// condition (or update for a foor loop).
127850696a6eSStefan Eßer 	else i = *((size_t*) bc_vec_top(&p->conds));
127950696a6eSStefan Eßer 
128044d4804dSStefan Eßer 	// Add the unconditional jump.
128150696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
128250696a6eSStefan Eßer 	bc_parse_pushIndex(p, i);
128350696a6eSStefan Eßer 
128450696a6eSStefan Eßer 	bc_lex_next(&p->l);
128550696a6eSStefan Eßer }
128650696a6eSStefan Eßer 
128744d4804dSStefan Eßer /**
128844d4804dSStefan Eßer  * Parse a function (header).
128944d4804dSStefan Eßer  * @param p  The parser.
129044d4804dSStefan Eßer  */
129150696a6eSStefan Eßer static void bc_parse_func(BcParse *p) {
129250696a6eSStefan Eßer 
129350696a6eSStefan Eßer 	bool comma = false, voidfn;
129450696a6eSStefan Eßer 	uint16_t flags;
129550696a6eSStefan Eßer 	size_t idx;
129650696a6eSStefan Eßer 
129750696a6eSStefan Eßer 	bc_lex_next(&p->l);
129850696a6eSStefan Eßer 
129944d4804dSStefan Eßer 	// Must have a name.
130044d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
130150696a6eSStefan Eßer 
130244d4804dSStefan Eßer 	// If the name is "void", and POSIX is not on, mark as void.
130350696a6eSStefan Eßer 	voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME &&
130450696a6eSStefan Eßer 	          !strcmp(p->l.str.v, "void"));
130550696a6eSStefan Eßer 
130644d4804dSStefan Eßer 	// We can safely do this because the expected token should not overwrite the
130744d4804dSStefan Eßer 	// function name.
130850696a6eSStefan Eßer 	bc_lex_next(&p->l);
130950696a6eSStefan Eßer 
131044d4804dSStefan Eßer 	// If we *don't* have another name, then void is the name of the function.
131150696a6eSStefan Eßer 	voidfn = (voidfn && p->l.t == BC_LEX_NAME);
131250696a6eSStefan Eßer 
131344d4804dSStefan Eßer 	// With a void function, allow POSIX to complain and get a new token.
131450696a6eSStefan Eßer 	if (voidfn) {
131544d4804dSStefan Eßer 
131650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_VOID);
131744d4804dSStefan Eßer 
131844d4804dSStefan Eßer 		// We can safely do this because the expected token should not overwrite
131944d4804dSStefan Eßer 		// the function name.
132050696a6eSStefan Eßer 		bc_lex_next(&p->l);
132150696a6eSStefan Eßer 	}
132250696a6eSStefan Eßer 
132344d4804dSStefan Eßer 	// Must have a left paren.
132450696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
132550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_FUNC);
132650696a6eSStefan Eßer 
132744d4804dSStefan Eßer 	// Make sure the functions map and vector are synchronized.
132850696a6eSStefan Eßer 	assert(p->prog->fns.len == p->prog->fn_map.len);
132950696a6eSStefan Eßer 
133044d4804dSStefan Eßer 	// Insert the function by name into the map and vector.
133150696a6eSStefan Eßer 	idx = bc_program_insertFunc(p->prog, p->l.str.v);
133250696a6eSStefan Eßer 
133344d4804dSStefan Eßer 	// Make sure the insert worked.
133450696a6eSStefan Eßer 	assert(idx);
133544d4804dSStefan Eßer 
133644d4804dSStefan Eßer 	// Update the function pointer and stuff in the parser and set its void.
133750696a6eSStefan Eßer 	bc_parse_updateFunc(p, idx);
133850696a6eSStefan Eßer 	p->func->voidfn = voidfn;
133950696a6eSStefan Eßer 
134050696a6eSStefan Eßer 	bc_lex_next(&p->l);
134150696a6eSStefan Eßer 
134244d4804dSStefan Eßer 	// While we do not have a right paren, we are still parsing arguments.
134350696a6eSStefan Eßer 	while (p->l.t != BC_LEX_RPAREN) {
134450696a6eSStefan Eßer 
134550696a6eSStefan Eßer 		BcType t = BC_TYPE_VAR;
134650696a6eSStefan Eßer 
134744d4804dSStefan Eßer 		// If we have an asterisk, we are parsing a reference argument.
134850696a6eSStefan Eßer 		if (p->l.t == BC_LEX_OP_MULTIPLY) {
134944d4804dSStefan Eßer 
135050696a6eSStefan Eßer 			t = BC_TYPE_REF;
135150696a6eSStefan Eßer 			bc_lex_next(&p->l);
135244d4804dSStefan Eßer 
135344d4804dSStefan Eßer 			// Let POSIX complain if necessary.
135450696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_REF);
135550696a6eSStefan Eßer 		}
135650696a6eSStefan Eßer 
135744d4804dSStefan Eßer 		// If we don't have a name, the argument will not have a name. Barf.
135850696a6eSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME))
135950696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_FUNC);
136050696a6eSStefan Eßer 
136144d4804dSStefan Eßer 		// Increment the number of parameters.
136250696a6eSStefan Eßer 		p->func->nparams += 1;
136350696a6eSStefan Eßer 
136444d4804dSStefan Eßer 		// Copy the string in the lexer so that we can use the lexer again.
136550696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len, p->l.str.v);
136650696a6eSStefan Eßer 
136750696a6eSStefan Eßer 		bc_lex_next(&p->l);
136850696a6eSStefan Eßer 
136944d4804dSStefan Eßer 		// We are parsing an array parameter if this is true.
137050696a6eSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET) {
137150696a6eSStefan Eßer 
137244d4804dSStefan Eßer 			// Set the array type, unless we are already parsing a reference.
137350696a6eSStefan Eßer 			if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
137450696a6eSStefan Eßer 
137550696a6eSStefan Eßer 			bc_lex_next(&p->l);
137650696a6eSStefan Eßer 
137744d4804dSStefan Eßer 			// The brackets *must* be empty.
137850696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
137950696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
138050696a6eSStefan Eßer 
138150696a6eSStefan Eßer 			bc_lex_next(&p->l);
138250696a6eSStefan Eßer 		}
138344d4804dSStefan Eßer 		// If we did *not* get a bracket, but we are expecting a reference, we
138444d4804dSStefan Eßer 		// have a problem.
138550696a6eSStefan Eßer 		else if (BC_ERR(t == BC_TYPE_REF))
138650696a6eSStefan Eßer 			bc_parse_verr(p, BC_ERR_PARSE_REF_VAR, p->buf.v);
138750696a6eSStefan Eßer 
138844d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
138950696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
139044d4804dSStefan Eßer 		if (comma) bc_lex_next(&p->l);
139150696a6eSStefan Eßer 
139244d4804dSStefan Eßer 		// Insert the parameter into the function.
139350696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
139450696a6eSStefan Eßer 	}
139550696a6eSStefan Eßer 
139644d4804dSStefan Eßer 	// If we have a comma, but no parameter, barf.
139750696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
139850696a6eSStefan Eßer 
139944d4804dSStefan Eßer 	// Start the body.
140050696a6eSStefan Eßer 	flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER;
140150696a6eSStefan Eßer 	bc_parse_startBody(p, flags);
140250696a6eSStefan Eßer 
140350696a6eSStefan Eßer 	bc_lex_next(&p->l);
140450696a6eSStefan Eßer 
140544d4804dSStefan Eßer 	// POSIX requires that a brace be on the same line as the function header.
140644d4804dSStefan Eßer 	// If we don't have a brace, let POSIX throw an error.
140750696a6eSStefan Eßer 	if (p->l.t != BC_LEX_LBRACE) bc_parse_err(p, BC_ERR_POSIX_BRACE);
140850696a6eSStefan Eßer }
140950696a6eSStefan Eßer 
141044d4804dSStefan Eßer /**
141144d4804dSStefan Eßer  * Parse an auto list.
141244d4804dSStefan Eßer  * @param p  The parser.
141344d4804dSStefan Eßer  */
141450696a6eSStefan Eßer static void bc_parse_auto(BcParse *p) {
141550696a6eSStefan Eßer 
141650696a6eSStefan Eßer 	bool comma, one;
141750696a6eSStefan Eßer 
141844d4804dSStefan Eßer 	// Error if the auto keyword appeared in the wrong place.
141950696a6eSStefan Eßer 	if (BC_ERR(!p->auto_part)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
142050696a6eSStefan Eßer 	bc_lex_next(&p->l);
142150696a6eSStefan Eßer 
142250696a6eSStefan Eßer 	p->auto_part = comma = false;
142350696a6eSStefan Eßer 
142444d4804dSStefan Eßer 	// We need at least one variable or array.
142544d4804dSStefan Eßer 	one = (p->l.t == BC_LEX_NAME);
142644d4804dSStefan Eßer 
142744d4804dSStefan Eßer 	// While we have a variable or array.
142850696a6eSStefan Eßer 	while (p->l.t == BC_LEX_NAME) {
142950696a6eSStefan Eßer 
143050696a6eSStefan Eßer 		BcType t;
143150696a6eSStefan Eßer 
143244d4804dSStefan Eßer 		// Copy the name from the lexer, so we can use it again.
143350696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len - 1, p->l.str.v);
143450696a6eSStefan Eßer 
143550696a6eSStefan Eßer 		bc_lex_next(&p->l);
143650696a6eSStefan Eßer 
143744d4804dSStefan Eßer 		// If we are parsing an array...
143850696a6eSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET) {
143950696a6eSStefan Eßer 
144050696a6eSStefan Eßer 			t = BC_TYPE_ARRAY;
144150696a6eSStefan Eßer 
144250696a6eSStefan Eßer 			bc_lex_next(&p->l);
144350696a6eSStefan Eßer 
144444d4804dSStefan Eßer 			// The brackets *must* be empty.
144550696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
144650696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
144750696a6eSStefan Eßer 
144850696a6eSStefan Eßer 			bc_lex_next(&p->l);
144950696a6eSStefan Eßer 		}
145050696a6eSStefan Eßer 		else t = BC_TYPE_VAR;
145150696a6eSStefan Eßer 
145244d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
145350696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
145450696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
145550696a6eSStefan Eßer 
145644d4804dSStefan Eßer 		// Insert the auto into the function.
145750696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
145850696a6eSStefan Eßer 	}
145950696a6eSStefan Eßer 
146044d4804dSStefan Eßer 	// If we have a comma, but no auto, barf.
146150696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
146244d4804dSStefan Eßer 
146344d4804dSStefan Eßer 	// If we don't have any variables or arrays, barf.
146450696a6eSStefan Eßer 	if (BC_ERR(!one)) bc_parse_err(p, BC_ERR_PARSE_NO_AUTO);
146544d4804dSStefan Eßer 
146644d4804dSStefan Eßer 	// The auto statement should be all that's in the statement.
146750696a6eSStefan Eßer 	if (BC_ERR(!bc_parse_isDelimiter(p)))
146850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
146950696a6eSStefan Eßer }
147050696a6eSStefan Eßer 
147144d4804dSStefan Eßer /**
147244d4804dSStefan Eßer  * Parses a body.
147344d4804dSStefan Eßer  * @param p      The parser.
147444d4804dSStefan Eßer  * @param brace  True if a brace was encountered, false otherwise.
147544d4804dSStefan Eßer  */
147650696a6eSStefan Eßer static void bc_parse_body(BcParse *p, bool brace) {
147750696a6eSStefan Eßer 
147850696a6eSStefan Eßer 	uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
147950696a6eSStefan Eßer 
148050696a6eSStefan Eßer 	assert(flag_ptr != NULL);
148150696a6eSStefan Eßer 	assert(p->flags.len >= 2);
148250696a6eSStefan Eßer 
148344d4804dSStefan Eßer 	// The body flag is for when we expect a body. We got a body, so clear the
148444d4804dSStefan Eßer 	// flag.
148550696a6eSStefan Eßer 	*flag_ptr &= ~(BC_PARSE_FLAG_BODY);
148650696a6eSStefan Eßer 
148744d4804dSStefan Eßer 	// If we are inside a function, that means we just barely entered it, and
148844d4804dSStefan Eßer 	// we can expect an auto list.
148950696a6eSStefan Eßer 	if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
149050696a6eSStefan Eßer 
149144d4804dSStefan Eßer 		// We *must* have a brace in this case.
149250696a6eSStefan Eßer 		if (BC_ERR(!brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
149350696a6eSStefan Eßer 
149450696a6eSStefan Eßer 		p->auto_part = (p->l.t != BC_LEX_KW_AUTO);
149550696a6eSStefan Eßer 
149650696a6eSStefan Eßer 		if (!p->auto_part) {
149750696a6eSStefan Eßer 
149850696a6eSStefan Eßer 			// Make sure this is true to not get a parse error.
149950696a6eSStefan Eßer 			p->auto_part = true;
150050696a6eSStefan Eßer 
150144d4804dSStefan Eßer 			// Since we already have the auto keyword, parse.
150250696a6eSStefan Eßer 			bc_parse_auto(p);
150350696a6eSStefan Eßer 		}
150450696a6eSStefan Eßer 
150544d4804dSStefan Eßer 		// Eat a newline.
150650696a6eSStefan Eßer 		if (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
150750696a6eSStefan Eßer 	}
150850696a6eSStefan Eßer 	else {
150950696a6eSStefan Eßer 
151044d4804dSStefan Eßer 		// This is the easy part.
151150696a6eSStefan Eßer 		size_t len = p->flags.len;
151250696a6eSStefan Eßer 
151350696a6eSStefan Eßer 		assert(*flag_ptr);
151450696a6eSStefan Eßer 
151544d4804dSStefan Eßer 		// Parse a statement.
151650696a6eSStefan Eßer 		bc_parse_stmt(p);
151750696a6eSStefan Eßer 
151844d4804dSStefan Eßer 		// This is a very important condition to get right. If there is no
151944d4804dSStefan Eßer 		// brace, and no body flag, and the flags len hasn't shrunk, then we
152044d4804dSStefan Eßer 		// have a body that was not delimited by braces, so we need to end it
152144d4804dSStefan Eßer 		// now, after just one statement.
152250696a6eSStefan Eßer 		if (!brace && !BC_PARSE_BODY(p) && len <= p->flags.len)
152350696a6eSStefan Eßer 			bc_parse_endBody(p, false);
152450696a6eSStefan Eßer 	}
152550696a6eSStefan Eßer }
152650696a6eSStefan Eßer 
152744d4804dSStefan Eßer /**
152844d4804dSStefan Eßer  * Parses a statement. This is the entry point for just about everything, except
152944d4804dSStefan Eßer  * function definitions.
153044d4804dSStefan Eßer  * @param p  The parser.
153144d4804dSStefan Eßer  */
153250696a6eSStefan Eßer static void bc_parse_stmt(BcParse *p) {
153350696a6eSStefan Eßer 
153450696a6eSStefan Eßer 	size_t len;
153550696a6eSStefan Eßer 	uint16_t flags;
153650696a6eSStefan Eßer 	BcLexType type = p->l.t;
153750696a6eSStefan Eßer 
153844d4804dSStefan Eßer 	// Eat newline.
153950696a6eSStefan Eßer 	if (type == BC_LEX_NLINE) {
154050696a6eSStefan Eßer 		bc_lex_next(&p->l);
154150696a6eSStefan Eßer 		return;
154250696a6eSStefan Eßer 	}
154344d4804dSStefan Eßer 
154444d4804dSStefan Eßer 	// Eat auto list.
154550696a6eSStefan Eßer 	if (type == BC_LEX_KW_AUTO) {
154650696a6eSStefan Eßer 		bc_parse_auto(p);
154750696a6eSStefan Eßer 		return;
154850696a6eSStefan Eßer 	}
154950696a6eSStefan Eßer 
155044d4804dSStefan Eßer 	// If we reach this point, no auto list is allowed.
155150696a6eSStefan Eßer 	p->auto_part = false;
155250696a6eSStefan Eßer 
155344d4804dSStefan Eßer 	// Everything but an else needs to be taken care of here, but else is
155444d4804dSStefan Eßer 	// special.
155550696a6eSStefan Eßer 	if (type != BC_LEX_KW_ELSE) {
155650696a6eSStefan Eßer 
155744d4804dSStefan Eßer 		// After an if, no else found.
155850696a6eSStefan Eßer 		if (BC_PARSE_IF_END(p)) {
155944d4804dSStefan Eßer 
156044d4804dSStefan Eßer 			// Clear the expectation for else, end body, and return. Returning
156144d4804dSStefan Eßer 			// gives us a clean slate for parsing again.
156250696a6eSStefan Eßer 			bc_parse_noElse(p);
156350696a6eSStefan Eßer 			if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
156450696a6eSStefan Eßer 				bc_parse_endBody(p, false);
156550696a6eSStefan Eßer 			return;
156650696a6eSStefan Eßer 		}
156744d4804dSStefan Eßer 		// With a left brace, we are parsing a body.
156850696a6eSStefan Eßer 		else if (type == BC_LEX_LBRACE) {
156950696a6eSStefan Eßer 
157044d4804dSStefan Eßer 			// We need to start a body if we are not expecting one yet.
157150696a6eSStefan Eßer 			if (!BC_PARSE_BODY(p)) {
157250696a6eSStefan Eßer 				bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
157350696a6eSStefan Eßer 				bc_lex_next(&p->l);
157450696a6eSStefan Eßer 			}
157544d4804dSStefan Eßer 			// If we *are* expecting a body, that body should get a brace. This
157644d4804dSStefan Eßer 			// takes care of braces being on a different line than if and loop
157744d4804dSStefan Eßer 			// headers.
157850696a6eSStefan Eßer 			else {
157950696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
158050696a6eSStefan Eßer 				bc_lex_next(&p->l);
158150696a6eSStefan Eßer 				bc_parse_body(p, true);
158250696a6eSStefan Eßer 			}
158350696a6eSStefan Eßer 
158444d4804dSStefan Eßer 			// If we have reached this point, we need to return for a clean
158544d4804dSStefan Eßer 			// slate.
158650696a6eSStefan Eßer 			return;
158750696a6eSStefan Eßer 		}
158844d4804dSStefan Eßer 		// This happens when we are expecting a body and get a single statement,
158944d4804dSStefan Eßer 		// i.e., a body with no braces surrounding it. Returns after for a clean
159044d4804dSStefan Eßer 		// slate.
159150696a6eSStefan Eßer 		else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p)) {
159250696a6eSStefan Eßer 			bc_parse_body(p, false);
159350696a6eSStefan Eßer 			return;
159450696a6eSStefan Eßer 		}
159550696a6eSStefan Eßer 	}
159650696a6eSStefan Eßer 
159750696a6eSStefan Eßer 	len = p->flags.len;
159850696a6eSStefan Eßer 	flags = BC_PARSE_TOP_FLAG(p);
159950696a6eSStefan Eßer 
160050696a6eSStefan Eßer 	switch (type) {
160150696a6eSStefan Eßer 
160244d4804dSStefan Eßer 		// All of these are valid for expressions.
160350696a6eSStefan Eßer 		case BC_LEX_OP_INC:
160450696a6eSStefan Eßer 		case BC_LEX_OP_DEC:
160550696a6eSStefan Eßer 		case BC_LEX_OP_MINUS:
160650696a6eSStefan Eßer 		case BC_LEX_OP_BOOL_NOT:
160750696a6eSStefan Eßer 		case BC_LEX_LPAREN:
160850696a6eSStefan Eßer 		case BC_LEX_NAME:
160950696a6eSStefan Eßer 		case BC_LEX_NUMBER:
161050696a6eSStefan Eßer 		case BC_LEX_KW_IBASE:
161150696a6eSStefan Eßer 		case BC_LEX_KW_LAST:
161250696a6eSStefan Eßer 		case BC_LEX_KW_LENGTH:
161350696a6eSStefan Eßer 		case BC_LEX_KW_OBASE:
161450696a6eSStefan Eßer 		case BC_LEX_KW_SCALE:
161544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
161650696a6eSStefan Eßer 		case BC_LEX_KW_SEED:
161744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
161850696a6eSStefan Eßer 		case BC_LEX_KW_SQRT:
161950696a6eSStefan Eßer 		case BC_LEX_KW_ABS:
162044d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
162150696a6eSStefan Eßer 		case BC_LEX_KW_IRAND:
162244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
162344d4804dSStefan Eßer 		case BC_LEX_KW_ASCIIFY:
162444d4804dSStefan Eßer 		case BC_LEX_KW_MODEXP:
162544d4804dSStefan Eßer 		case BC_LEX_KW_DIVMOD:
162650696a6eSStefan Eßer 		case BC_LEX_KW_READ:
162744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
162850696a6eSStefan Eßer 		case BC_LEX_KW_RAND:
162944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
163050696a6eSStefan Eßer 		case BC_LEX_KW_MAXIBASE:
163150696a6eSStefan Eßer 		case BC_LEX_KW_MAXOBASE:
163250696a6eSStefan Eßer 		case BC_LEX_KW_MAXSCALE:
163344d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
163450696a6eSStefan Eßer 		case BC_LEX_KW_MAXRAND:
163544d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1636d43fa8efSStefan Eßer 		case BC_LEX_KW_LINE_LENGTH:
1637d43fa8efSStefan Eßer 		case BC_LEX_KW_GLOBAL_STACKS:
1638d43fa8efSStefan Eßer 		case BC_LEX_KW_LEADING_ZERO:
163950696a6eSStefan Eßer 		{
164050696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
164150696a6eSStefan Eßer 			break;
164250696a6eSStefan Eßer 		}
164350696a6eSStefan Eßer 
164450696a6eSStefan Eßer 		case BC_LEX_KW_ELSE:
164550696a6eSStefan Eßer 		{
164650696a6eSStefan Eßer 			bc_parse_else(p);
164750696a6eSStefan Eßer 			break;
164850696a6eSStefan Eßer 		}
164950696a6eSStefan Eßer 
165044d4804dSStefan Eßer 		// Just eat.
165150696a6eSStefan Eßer 		case BC_LEX_SCOLON:
165250696a6eSStefan Eßer 		{
165350696a6eSStefan Eßer 			// Do nothing.
165450696a6eSStefan Eßer 			break;
165550696a6eSStefan Eßer 		}
165650696a6eSStefan Eßer 
165750696a6eSStefan Eßer 		case BC_LEX_RBRACE:
165850696a6eSStefan Eßer 		{
165950696a6eSStefan Eßer 			bc_parse_endBody(p, true);
166050696a6eSStefan Eßer 			break;
166150696a6eSStefan Eßer 		}
166250696a6eSStefan Eßer 
166350696a6eSStefan Eßer 		case BC_LEX_STR:
166450696a6eSStefan Eßer 		{
166550696a6eSStefan Eßer 			bc_parse_str(p, BC_INST_PRINT_STR);
166650696a6eSStefan Eßer 			break;
166750696a6eSStefan Eßer 		}
166850696a6eSStefan Eßer 
166950696a6eSStefan Eßer 		case BC_LEX_KW_BREAK:
167050696a6eSStefan Eßer 		case BC_LEX_KW_CONTINUE:
167150696a6eSStefan Eßer 		{
167250696a6eSStefan Eßer 			bc_parse_loopExit(p, p->l.t);
167350696a6eSStefan Eßer 			break;
167450696a6eSStefan Eßer 		}
167550696a6eSStefan Eßer 
167650696a6eSStefan Eßer 		case BC_LEX_KW_FOR:
167750696a6eSStefan Eßer 		{
167850696a6eSStefan Eßer 			bc_parse_for(p);
167950696a6eSStefan Eßer 			break;
168050696a6eSStefan Eßer 		}
168150696a6eSStefan Eßer 
168250696a6eSStefan Eßer 		case BC_LEX_KW_HALT:
168350696a6eSStefan Eßer 		{
168450696a6eSStefan Eßer 			bc_parse_push(p, BC_INST_HALT);
168550696a6eSStefan Eßer 			bc_lex_next(&p->l);
168650696a6eSStefan Eßer 			break;
168750696a6eSStefan Eßer 		}
168850696a6eSStefan Eßer 
168950696a6eSStefan Eßer 		case BC_LEX_KW_IF:
169050696a6eSStefan Eßer 		{
169150696a6eSStefan Eßer 			bc_parse_if(p);
169250696a6eSStefan Eßer 			break;
169350696a6eSStefan Eßer 		}
169450696a6eSStefan Eßer 
169550696a6eSStefan Eßer 		case BC_LEX_KW_LIMITS:
169650696a6eSStefan Eßer 		{
169744d4804dSStefan Eßer 			// `limits` is a compile-time command, so execute it right away.
169850696a6eSStefan Eßer 			bc_vm_printf("BC_LONG_BIT      = %lu\n", (ulong) BC_LONG_BIT);
169950696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_DIGS     = %lu\n", (ulong) BC_BASE_DIGS);
170050696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_POW      = %lu\n", (ulong) BC_BASE_POW);
170150696a6eSStefan Eßer 			bc_vm_printf("BC_OVERFLOW_MAX  = %lu\n", (ulong) BC_NUM_BIGDIG_MAX);
170250696a6eSStefan Eßer 			bc_vm_printf("\n");
170350696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_MAX      = %lu\n", BC_MAX_OBASE);
170450696a6eSStefan Eßer 			bc_vm_printf("BC_DIM_MAX       = %lu\n", BC_MAX_DIM);
170550696a6eSStefan Eßer 			bc_vm_printf("BC_SCALE_MAX     = %lu\n", BC_MAX_SCALE);
170650696a6eSStefan Eßer 			bc_vm_printf("BC_STRING_MAX    = %lu\n", BC_MAX_STRING);
170750696a6eSStefan Eßer 			bc_vm_printf("BC_NAME_MAX      = %lu\n", BC_MAX_NAME);
170850696a6eSStefan Eßer 			bc_vm_printf("BC_NUM_MAX       = %lu\n", BC_MAX_NUM);
170944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
171050696a6eSStefan Eßer 			bc_vm_printf("BC_RAND_MAX      = %lu\n", BC_MAX_RAND);
171144d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
171250696a6eSStefan Eßer 			bc_vm_printf("MAX Exponent     = %lu\n", BC_MAX_EXP);
171350696a6eSStefan Eßer 			bc_vm_printf("Number of vars   = %lu\n", BC_MAX_VARS);
171450696a6eSStefan Eßer 
171550696a6eSStefan Eßer 			bc_lex_next(&p->l);
171650696a6eSStefan Eßer 
171750696a6eSStefan Eßer 			break;
171850696a6eSStefan Eßer 		}
171950696a6eSStefan Eßer 
172044d4804dSStefan Eßer 		case BC_LEX_KW_STREAM:
172150696a6eSStefan Eßer 		case BC_LEX_KW_PRINT:
172250696a6eSStefan Eßer 		{
172344d4804dSStefan Eßer 			bc_parse_print(p, type);
172450696a6eSStefan Eßer 			break;
172550696a6eSStefan Eßer 		}
172650696a6eSStefan Eßer 
172750696a6eSStefan Eßer 		case BC_LEX_KW_QUIT:
172850696a6eSStefan Eßer 		{
172944d4804dSStefan Eßer 			// Quit is a compile-time command. We don't exit directly, so the vm
173044d4804dSStefan Eßer 			// can clean up.
173150696a6eSStefan Eßer 			vm.status = BC_STATUS_QUIT;
173244d4804dSStefan Eßer 			BC_JMP;
173350696a6eSStefan Eßer 			break;
173450696a6eSStefan Eßer 		}
173550696a6eSStefan Eßer 
173650696a6eSStefan Eßer 		case BC_LEX_KW_RETURN:
173750696a6eSStefan Eßer 		{
173850696a6eSStefan Eßer 			bc_parse_return(p);
173950696a6eSStefan Eßer 			break;
174050696a6eSStefan Eßer 		}
174150696a6eSStefan Eßer 
174250696a6eSStefan Eßer 		case BC_LEX_KW_WHILE:
174350696a6eSStefan Eßer 		{
174450696a6eSStefan Eßer 			bc_parse_while(p);
174550696a6eSStefan Eßer 			break;
174650696a6eSStefan Eßer 		}
174750696a6eSStefan Eßer 
174850696a6eSStefan Eßer 		default:
174950696a6eSStefan Eßer 		{
175050696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
175150696a6eSStefan Eßer 		}
175250696a6eSStefan Eßer 	}
175350696a6eSStefan Eßer 
175444d4804dSStefan Eßer 	// If the flags did not change, we expect a delimiter.
175550696a6eSStefan Eßer 	if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) {
175650696a6eSStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p)))
175750696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
175850696a6eSStefan Eßer 	}
175950696a6eSStefan Eßer 
176050696a6eSStefan Eßer 	// Make sure semicolons are eaten.
176150696a6eSStefan Eßer 	while (p->l.t == BC_LEX_SCOLON) bc_lex_next(&p->l);
1762*10041e99SStefan Eßer 
1763*10041e99SStefan Eßer 	// POSIX's grammar does not allow a function definition after a semicolon
1764*10041e99SStefan Eßer 	// without a newline, so check specifically for that case and error if
1765*10041e99SStefan Eßer 	// the POSIX standard flag is set.
1766*10041e99SStefan Eßer 	if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX)
1767*10041e99SStefan Eßer 	{
1768*10041e99SStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON);
1769*10041e99SStefan Eßer 	}
177050696a6eSStefan Eßer }
177150696a6eSStefan Eßer 
177250696a6eSStefan Eßer void bc_parse_parse(BcParse *p) {
177350696a6eSStefan Eßer 
177450696a6eSStefan Eßer 	assert(p);
177550696a6eSStefan Eßer 
1776*10041e99SStefan Eßer 	BC_SETJMP_LOCKED(exit);
177750696a6eSStefan Eßer 
177844d4804dSStefan Eßer 	// We should not let an EOF get here unless some partial parse was not
177944d4804dSStefan Eßer 	// completed, in which case, it's the user's fault.
178050696a6eSStefan Eßer 	if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
178144d4804dSStefan Eßer 
178244d4804dSStefan Eßer 	// Functions need special parsing.
178350696a6eSStefan Eßer 	else if (p->l.t == BC_LEX_KW_DEFINE) {
1784d43fa8efSStefan Eßer 		if (BC_ERR(BC_PARSE_NO_EXEC(p))) {
1785a30efc5cSStefan Eßer 			bc_parse_endif(p);
1786a30efc5cSStefan Eßer 			if (BC_ERR(BC_PARSE_NO_EXEC(p)))
1787a30efc5cSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1788d43fa8efSStefan Eßer 		}
178950696a6eSStefan Eßer 		bc_parse_func(p);
179050696a6eSStefan Eßer 	}
179144d4804dSStefan Eßer 
179244d4804dSStefan Eßer 	// Otherwise, parse a normal statement.
179350696a6eSStefan Eßer 	else bc_parse_stmt(p);
179450696a6eSStefan Eßer 
179550696a6eSStefan Eßer exit:
179644d4804dSStefan Eßer 
179744d4804dSStefan Eßer 	// We need to reset on error.
179850696a6eSStefan Eßer 	if (BC_ERR(((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig)))
179950696a6eSStefan Eßer 		bc_parse_reset(p);
180044d4804dSStefan Eßer 
180150696a6eSStefan Eßer 	BC_LONGJMP_CONT;
1802*10041e99SStefan Eßer 	BC_SIG_MAYLOCK;
180350696a6eSStefan Eßer }
180450696a6eSStefan Eßer 
180544d4804dSStefan Eßer /**
180644d4804dSStefan Eßer  * Parse an expression. This is the actual implementation of the Shunting-Yard
180744d4804dSStefan Eßer  * Algorithm.
180844d4804dSStefan Eßer  * @param p      The parser.
180944d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
181044d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
181144d4804dSStefan Eßer  * @return       A parse status. In some places, an empty expression is an
181244d4804dSStefan Eßer  *               error, and sometimes, it is required. This allows this function
181344d4804dSStefan Eßer  *               to tell the caller if the expression was empty and let the
181444d4804dSStefan Eßer  *               caller handle it.
181544d4804dSStefan Eßer  */
181650696a6eSStefan Eßer static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags,
181750696a6eSStefan Eßer                                        BcParseNext next)
181850696a6eSStefan Eßer {
181950696a6eSStefan Eßer 	BcInst prev = BC_INST_PRINT;
182050696a6eSStefan Eßer 	uchar inst = BC_INST_INVALID;
182144d4804dSStefan Eßer 	BcLexType top, t;
182244d4804dSStefan Eßer 	size_t nexprs, ops_bgn;
182350696a6eSStefan Eßer 	uint32_t i, nparens, nrelops;
182450696a6eSStefan Eßer 	bool pfirst, rprn, done, get_token, assign, bin_last, incdec, can_assign;
182550696a6eSStefan Eßer 
182644d4804dSStefan Eßer 	// One of these *must* be true.
182750696a6eSStefan Eßer 	assert(!(flags & BC_PARSE_PRINT) || !(flags & BC_PARSE_NEEDVAL));
182850696a6eSStefan Eßer 
182944d4804dSStefan Eßer 	// These are set very carefully. In fact, controlling the values of these
183044d4804dSStefan Eßer 	// locals is the biggest part of making this work. ops_bgn especially is
183144d4804dSStefan Eßer 	// important because it marks where the operator stack begins for *this*
183244d4804dSStefan Eßer 	// invocation of this function. That's because bc_parse_expr_err() is
183344d4804dSStefan Eßer 	// recursive (the Shunting-Yard Algorithm is most easily expressed
183444d4804dSStefan Eßer 	// recursively when parsing subexpressions), and each invocation needs to
183544d4804dSStefan Eßer 	// know where to stop.
183644d4804dSStefan Eßer 	//
183744d4804dSStefan Eßer 	// - nparens is the number of left parens without matches.
183844d4804dSStefan Eßer 	// - nrelops is the number of relational operators that appear in the expr.
183944d4804dSStefan Eßer 	// - nexprs is the number of unused expressions.
184044d4804dSStefan Eßer 	// - rprn is a right paren encountered last.
184144d4804dSStefan Eßer 	// - done means the expression has been fully parsed.
184244d4804dSStefan Eßer 	// - get_token is true when a token is needed at the end of an iteration.
184344d4804dSStefan Eßer 	// - assign is true when an assignment statement was parsed last.
184444d4804dSStefan Eßer 	// - incdec is true when the previous operator was an inc or dec operator.
184544d4804dSStefan Eßer 	// - can_assign is true when an assignemnt is valid.
184644d4804dSStefan Eßer 	// - bin_last is true when the previous instruction was a binary operator.
184744d4804dSStefan Eßer 	t = p->l.t;
184850696a6eSStefan Eßer 	pfirst = (p->l.t == BC_LEX_LPAREN);
184950696a6eSStefan Eßer 	nparens = nrelops = 0;
185044d4804dSStefan Eßer 	nexprs = 0;
185144d4804dSStefan Eßer 	ops_bgn = p->ops.len;
185250696a6eSStefan Eßer 	rprn = done = get_token = assign = incdec = can_assign = false;
185350696a6eSStefan Eßer 	bin_last = true;
185450696a6eSStefan Eßer 
185550696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
185650696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
185750696a6eSStefan Eßer 	if (!(flags & BC_PARSE_NOREAD)) {
185850696a6eSStefan Eßer 		while ((t = p->l.t) == BC_LEX_NLINE) bc_lex_next(&p->l);
185950696a6eSStefan Eßer 	}
186050696a6eSStefan Eßer 
186144d4804dSStefan Eßer 	// This is the Shunting-Yard algorithm loop.
186250696a6eSStefan Eßer 	for (; !done && BC_PARSE_EXPR(t); t = p->l.t)
186350696a6eSStefan Eßer 	{
186450696a6eSStefan Eßer 		switch (t) {
186550696a6eSStefan Eßer 
186650696a6eSStefan Eßer 			case BC_LEX_OP_INC:
186750696a6eSStefan Eßer 			case BC_LEX_OP_DEC:
186850696a6eSStefan Eßer 			{
186944d4804dSStefan Eßer 				// These operators can only be used with items that can be
187044d4804dSStefan Eßer 				// assigned to.
187150696a6eSStefan Eßer 				if (BC_ERR(incdec)) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
187244d4804dSStefan Eßer 
187350696a6eSStefan Eßer 				bc_parse_incdec(p, &prev, &can_assign, &nexprs, flags);
187444d4804dSStefan Eßer 
187550696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
187650696a6eSStefan Eßer 				incdec = true;
187750696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
187844d4804dSStefan Eßer 
187950696a6eSStefan Eßer 				break;
188050696a6eSStefan Eßer 			}
188150696a6eSStefan Eßer 
188250696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
188350696a6eSStefan Eßer 			case BC_LEX_OP_TRUNC:
188450696a6eSStefan Eßer 			{
188544d4804dSStefan Eßer 				// The previous token must have been a leaf expression, or the
188644d4804dSStefan Eßer 				// operator is in the wrong place.
188750696a6eSStefan Eßer 				if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn)))
188850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_TOKEN);
188950696a6eSStefan Eßer 
189050696a6eSStefan Eßer 				// I can just add the instruction because
189150696a6eSStefan Eßer 				// negative will already be taken care of.
189250696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_TRUNC);
189344d4804dSStefan Eßer 
189450696a6eSStefan Eßer 				rprn = can_assign = incdec = false;
189550696a6eSStefan Eßer 				get_token = true;
189650696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
189744d4804dSStefan Eßer 
189850696a6eSStefan Eßer 				break;
189950696a6eSStefan Eßer 			}
190050696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
190150696a6eSStefan Eßer 
190250696a6eSStefan Eßer 			case BC_LEX_OP_MINUS:
190350696a6eSStefan Eßer 			{
190450696a6eSStefan Eßer 				bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
190544d4804dSStefan Eßer 
190650696a6eSStefan Eßer 				rprn = get_token = can_assign = false;
190744d4804dSStefan Eßer 
190844d4804dSStefan Eßer 				// This is true if it was a binary operator last.
190950696a6eSStefan Eßer 				bin_last = (prev == BC_INST_MINUS);
191050696a6eSStefan Eßer 				if (bin_last) incdec = false;
191144d4804dSStefan Eßer 
191250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
191344d4804dSStefan Eßer 
191450696a6eSStefan Eßer 				break;
191550696a6eSStefan Eßer 			}
191650696a6eSStefan Eßer 
191744d4804dSStefan Eßer 			// All of this group, including the fallthrough, is to parse binary
191844d4804dSStefan Eßer 			// operators.
191950696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_POWER:
192050696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MULTIPLY:
192150696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_DIVIDE:
192250696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MODULUS:
192350696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLUS:
192450696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MINUS:
192550696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
192650696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLACES:
192750696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_LSHIFT:
192850696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_RSHIFT:
192950696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
193050696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN:
193150696a6eSStefan Eßer 			{
193244d4804dSStefan Eßer 				// We need to make sure the assignment is valid.
193350696a6eSStefan Eßer 				if (!BC_PARSE_INST_VAR(prev))
193450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
193550696a6eSStefan Eßer 			}
193650696a6eSStefan Eßer 			// Fallthrough.
193750696a6eSStefan Eßer 			BC_FALLTHROUGH
193850696a6eSStefan Eßer 
193950696a6eSStefan Eßer 			case BC_LEX_OP_POWER:
194050696a6eSStefan Eßer 			case BC_LEX_OP_MULTIPLY:
194150696a6eSStefan Eßer 			case BC_LEX_OP_DIVIDE:
194250696a6eSStefan Eßer 			case BC_LEX_OP_MODULUS:
194350696a6eSStefan Eßer 			case BC_LEX_OP_PLUS:
194450696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
194550696a6eSStefan Eßer 			case BC_LEX_OP_PLACES:
194650696a6eSStefan Eßer 			case BC_LEX_OP_LSHIFT:
194750696a6eSStefan Eßer 			case BC_LEX_OP_RSHIFT:
194850696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
194950696a6eSStefan Eßer 			case BC_LEX_OP_REL_EQ:
195050696a6eSStefan Eßer 			case BC_LEX_OP_REL_LE:
195150696a6eSStefan Eßer 			case BC_LEX_OP_REL_GE:
195250696a6eSStefan Eßer 			case BC_LEX_OP_REL_NE:
195350696a6eSStefan Eßer 			case BC_LEX_OP_REL_LT:
195450696a6eSStefan Eßer 			case BC_LEX_OP_REL_GT:
195550696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_NOT:
195650696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_OR:
195750696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_AND:
195850696a6eSStefan Eßer 			{
195944d4804dSStefan Eßer 				// This is true if the operator if the token is a prefix
196044d4804dSStefan Eßer 				// operator. This is only for boolean not.
196150696a6eSStefan Eßer 				if (BC_PARSE_OP_PREFIX(t)) {
196244d4804dSStefan Eßer 
196344d4804dSStefan Eßer 					// Prefix operators are only allowed after binary operators
196444d4804dSStefan Eßer 					// or prefix operators.
196550696a6eSStefan Eßer 					if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last)))
196650696a6eSStefan Eßer 						bc_parse_err(p, BC_ERR_PARSE_EXPR);
196750696a6eSStefan Eßer 				}
196844d4804dSStefan Eßer 				// If we execute the else, that means we have a binary operator.
196944d4804dSStefan Eßer 				// If the previous operator was a prefix or a binary operator,
197044d4804dSStefan Eßer 				// then a binary operator is not allowed.
197150696a6eSStefan Eßer 				else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last))
197250696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
197350696a6eSStefan Eßer 
197450696a6eSStefan Eßer 				nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
197550696a6eSStefan Eßer 				prev = BC_PARSE_TOKEN_INST(t);
197644d4804dSStefan Eßer 
197750696a6eSStefan Eßer 				bc_parse_operator(p, t, ops_bgn, &nexprs);
197844d4804dSStefan Eßer 
197950696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
198050696a6eSStefan Eßer 				get_token = true;
198150696a6eSStefan Eßer 				bin_last = !BC_PARSE_OP_PREFIX(t);
198250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
198350696a6eSStefan Eßer 
198450696a6eSStefan Eßer 				break;
198550696a6eSStefan Eßer 			}
198650696a6eSStefan Eßer 
198750696a6eSStefan Eßer 			case BC_LEX_LPAREN:
198850696a6eSStefan Eßer 			{
198944d4804dSStefan Eßer 				// A left paren is *not* allowed right after a leaf expr.
199050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
199150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
199250696a6eSStefan Eßer 
199350696a6eSStefan Eßer 				nparens += 1;
199450696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
199550696a6eSStefan Eßer 				get_token = true;
199644d4804dSStefan Eßer 
199744d4804dSStefan Eßer 				// Push the paren onto the operator stack.
199850696a6eSStefan Eßer 				bc_vec_push(&p->ops, &t);
199950696a6eSStefan Eßer 
200050696a6eSStefan Eßer 				break;
200150696a6eSStefan Eßer 			}
200250696a6eSStefan Eßer 
200350696a6eSStefan Eßer 			case BC_LEX_RPAREN:
200450696a6eSStefan Eßer 			{
200544d4804dSStefan Eßer 				// This needs to be a status. The error is handled in
200644d4804dSStefan Eßer 				// bc_parse_expr_status().
200750696a6eSStefan Eßer 				if (BC_ERR(p->l.last == BC_LEX_LPAREN))
200850696a6eSStefan Eßer 					return BC_PARSE_STATUS_EMPTY_EXPR;
200950696a6eSStefan Eßer 
201044d4804dSStefan Eßer 				// The right paren must not come after a prefix or binary
201144d4804dSStefan Eßer 				// operator.
201250696a6eSStefan Eßer 				if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev)))
201350696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
201450696a6eSStefan Eßer 
201544d4804dSStefan Eßer 				// If there are no parens left, we are done, but we need another
201644d4804dSStefan Eßer 				// token.
201750696a6eSStefan Eßer 				if (!nparens) {
201850696a6eSStefan Eßer 					done = true;
201950696a6eSStefan Eßer 					get_token = false;
202050696a6eSStefan Eßer 					break;
202150696a6eSStefan Eßer 				}
202250696a6eSStefan Eßer 
202350696a6eSStefan Eßer 				nparens -= 1;
202450696a6eSStefan Eßer 				rprn = true;
202550696a6eSStefan Eßer 				get_token = bin_last = incdec = false;
202650696a6eSStefan Eßer 
202750696a6eSStefan Eßer 				bc_parse_rightParen(p, &nexprs);
202850696a6eSStefan Eßer 
202950696a6eSStefan Eßer 				break;
203050696a6eSStefan Eßer 			}
203150696a6eSStefan Eßer 
203244d4804dSStefan Eßer 			case BC_LEX_STR:
203344d4804dSStefan Eßer 			{
203444d4804dSStefan Eßer 				// POSIX only allows strings alone.
203544d4804dSStefan Eßer 				if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_EXPR_STRING);
203644d4804dSStefan Eßer 
203744d4804dSStefan Eßer 				// A string is a leaf and cannot come right after a leaf.
203844d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
203944d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
204044d4804dSStefan Eßer 
204144d4804dSStefan Eßer 				bc_parse_addString(p);
204244d4804dSStefan Eßer 
204344d4804dSStefan Eßer 				get_token = true;
204444d4804dSStefan Eßer 				bin_last = rprn = false;
204544d4804dSStefan Eßer 				nexprs += 1;
204644d4804dSStefan Eßer 
204744d4804dSStefan Eßer 				break;
204844d4804dSStefan Eßer 			}
204944d4804dSStefan Eßer 
205050696a6eSStefan Eßer 			case BC_LEX_NAME:
205150696a6eSStefan Eßer 			{
205244d4804dSStefan Eßer 				// A name is a leaf and cannot come right after a leaf.
205350696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
205450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
205550696a6eSStefan Eßer 
205650696a6eSStefan Eßer 				get_token = bin_last = false;
205744d4804dSStefan Eßer 
205844d4804dSStefan Eßer 				bc_parse_name(p, &prev, &can_assign, flags & ~BC_PARSE_NOCALL);
205944d4804dSStefan Eßer 
206050696a6eSStefan Eßer 				rprn = (prev == BC_INST_CALL);
206150696a6eSStefan Eßer 				nexprs += 1;
206250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
206350696a6eSStefan Eßer 
206450696a6eSStefan Eßer 				break;
206550696a6eSStefan Eßer 			}
206650696a6eSStefan Eßer 
206750696a6eSStefan Eßer 			case BC_LEX_NUMBER:
206850696a6eSStefan Eßer 			{
206944d4804dSStefan Eßer 				// A number is a leaf and cannot come right after a leaf.
207050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
207150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
207250696a6eSStefan Eßer 
207344d4804dSStefan Eßer 				// The number instruction is pushed in here.
207450696a6eSStefan Eßer 				bc_parse_number(p);
207544d4804dSStefan Eßer 
207650696a6eSStefan Eßer 				nexprs += 1;
207750696a6eSStefan Eßer 				prev = BC_INST_NUM;
207850696a6eSStefan Eßer 				get_token = true;
207950696a6eSStefan Eßer 				rprn = bin_last = can_assign = false;
208050696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
208150696a6eSStefan Eßer 
208250696a6eSStefan Eßer 				break;
208350696a6eSStefan Eßer 			}
208450696a6eSStefan Eßer 
208550696a6eSStefan Eßer 			case BC_LEX_KW_IBASE:
208650696a6eSStefan Eßer 			case BC_LEX_KW_LAST:
208750696a6eSStefan Eßer 			case BC_LEX_KW_OBASE:
208844d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
208950696a6eSStefan Eßer 			case BC_LEX_KW_SEED:
209044d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
209150696a6eSStefan Eßer 			{
209244d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
209350696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
209450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
209550696a6eSStefan Eßer 
209650696a6eSStefan Eßer 				prev = t - BC_LEX_KW_LAST + BC_INST_LAST;
209750696a6eSStefan Eßer 				bc_parse_push(p, prev);
209850696a6eSStefan Eßer 
209950696a6eSStefan Eßer 				get_token = can_assign = true;
210050696a6eSStefan Eßer 				rprn = bin_last = false;
210150696a6eSStefan Eßer 				nexprs += 1;
210250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
210350696a6eSStefan Eßer 
210450696a6eSStefan Eßer 				break;
210550696a6eSStefan Eßer 			}
210650696a6eSStefan Eßer 
210750696a6eSStefan Eßer 			case BC_LEX_KW_LENGTH:
210850696a6eSStefan Eßer 			case BC_LEX_KW_SQRT:
210950696a6eSStefan Eßer 			case BC_LEX_KW_ABS:
211044d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
211150696a6eSStefan Eßer 			case BC_LEX_KW_IRAND:
211244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
211344d4804dSStefan Eßer 			case BC_LEX_KW_ASCIIFY:
211450696a6eSStefan Eßer 			{
211544d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
211650696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
211750696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
211850696a6eSStefan Eßer 
211950696a6eSStefan Eßer 				bc_parse_builtin(p, t, flags, &prev);
212044d4804dSStefan Eßer 
212150696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
212250696a6eSStefan Eßer 				nexprs += 1;
212350696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
212450696a6eSStefan Eßer 
212550696a6eSStefan Eßer 				break;
212650696a6eSStefan Eßer 			}
212750696a6eSStefan Eßer 
212850696a6eSStefan Eßer 			case BC_LEX_KW_READ:
212944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
213050696a6eSStefan Eßer 			case BC_LEX_KW_RAND:
213144d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
213250696a6eSStefan Eßer 			case BC_LEX_KW_MAXIBASE:
213350696a6eSStefan Eßer 			case BC_LEX_KW_MAXOBASE:
213450696a6eSStefan Eßer 			case BC_LEX_KW_MAXSCALE:
213544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
213650696a6eSStefan Eßer 			case BC_LEX_KW_MAXRAND:
213744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2138d43fa8efSStefan Eßer 			case BC_LEX_KW_LINE_LENGTH:
2139d43fa8efSStefan Eßer 			case BC_LEX_KW_GLOBAL_STACKS:
2140d43fa8efSStefan Eßer 			case BC_LEX_KW_LEADING_ZERO:
214150696a6eSStefan Eßer 			{
214244d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
214350696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
214450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
214544d4804dSStefan Eßer 
214644d4804dSStefan Eßer 				// Error if we have read and it's not allowed.
214750696a6eSStefan Eßer 				else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD))
214850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_EXEC_REC_READ);
214944d4804dSStefan Eßer 
215050696a6eSStefan Eßer 				prev = t - BC_LEX_KW_READ + BC_INST_READ;
215150696a6eSStefan Eßer 				bc_parse_noArgBuiltin(p, prev);
215250696a6eSStefan Eßer 
215350696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
215450696a6eSStefan Eßer 				nexprs += 1;
215550696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
215650696a6eSStefan Eßer 
215750696a6eSStefan Eßer 				break;
215850696a6eSStefan Eßer 			}
215950696a6eSStefan Eßer 
216050696a6eSStefan Eßer 			case BC_LEX_KW_SCALE:
216150696a6eSStefan Eßer 			{
216244d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
216350696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
216450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
216550696a6eSStefan Eßer 
216644d4804dSStefan Eßer 				// Scale needs special work because it can be a variable *or* a
216744d4804dSStefan Eßer 				// function.
216850696a6eSStefan Eßer 				bc_parse_scale(p, &prev, &can_assign, flags);
216944d4804dSStefan Eßer 
217050696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
217150696a6eSStefan Eßer 				nexprs += 1;
217250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
217350696a6eSStefan Eßer 
217450696a6eSStefan Eßer 				break;
217550696a6eSStefan Eßer 			}
217650696a6eSStefan Eßer 
217744d4804dSStefan Eßer 			case BC_LEX_KW_MODEXP:
217844d4804dSStefan Eßer 			case BC_LEX_KW_DIVMOD:
217944d4804dSStefan Eßer 			{
218044d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
218144d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
218244d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
218344d4804dSStefan Eßer 
218444d4804dSStefan Eßer 				bc_parse_builtin3(p, t, flags, &prev);
218544d4804dSStefan Eßer 
218644d4804dSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
218744d4804dSStefan Eßer 				nexprs += 1;
218844d4804dSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
218944d4804dSStefan Eßer 
219044d4804dSStefan Eßer 				break;
219144d4804dSStefan Eßer 			}
219244d4804dSStefan Eßer 
219350696a6eSStefan Eßer 			default:
219450696a6eSStefan Eßer 			{
219550696a6eSStefan Eßer #ifndef NDEBUG
219644d4804dSStefan Eßer 				// We should never get here, even in debug builds.
219750696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
219850696a6eSStefan Eßer 				break;
219950696a6eSStefan Eßer #endif // NDEBUG
220050696a6eSStefan Eßer 			}
220150696a6eSStefan Eßer 		}
220250696a6eSStefan Eßer 
220350696a6eSStefan Eßer 		if (get_token) bc_lex_next(&p->l);
220450696a6eSStefan Eßer 	}
220550696a6eSStefan Eßer 
220644d4804dSStefan Eßer 	// Now that we have parsed the expression, we need to empty the operator
220744d4804dSStefan Eßer 	// stack.
220850696a6eSStefan Eßer 	while (p->ops.len > ops_bgn) {
220950696a6eSStefan Eßer 
221050696a6eSStefan Eßer 		top = BC_PARSE_TOP_OP(p);
221150696a6eSStefan Eßer 		assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
221250696a6eSStefan Eßer 
221344d4804dSStefan Eßer 		// There should not be *any* parens on the stack anymore.
221450696a6eSStefan Eßer 		if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN))
221550696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_EXPR);
221650696a6eSStefan Eßer 
221750696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
221850696a6eSStefan Eßer 
221944d4804dSStefan Eßer 		// Adjust the number of unused expressions.
222050696a6eSStefan Eßer 		nexprs -= !BC_PARSE_OP_PREFIX(top);
222150696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
222250696a6eSStefan Eßer 
222350696a6eSStefan Eßer 		incdec = false;
222450696a6eSStefan Eßer 	}
222550696a6eSStefan Eßer 
222644d4804dSStefan Eßer 	// There must be only one expression at the top.
222750696a6eSStefan Eßer 	if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR);
222850696a6eSStefan Eßer 
222944d4804dSStefan Eßer 	// Check that the next token is correct.
223050696a6eSStefan Eßer 	for (i = 0; i < next.len && t != next.tokens[i]; ++i);
223150696a6eSStefan Eßer 	if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p)))
223250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EXPR);
223350696a6eSStefan Eßer 
223444d4804dSStefan Eßer 	// Check that POSIX would be happy with the number of relational operators.
223550696a6eSStefan Eßer 	if (!(flags & BC_PARSE_REL) && nrelops)
223650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_REL_POS);
223750696a6eSStefan Eßer 	else if ((flags & BC_PARSE_REL) && nrelops > 1)
223850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_MULTIREL);
223950696a6eSStefan Eßer 
224044d4804dSStefan Eßer 	// If this is true, then we might be in a situation where we don't print.
224144d4804dSStefan Eßer 	// We would want to have the increment/decrement operator not make an extra
224244d4804dSStefan Eßer 	// copy if it's not necessary.
224350696a6eSStefan Eßer 	if (!(flags & BC_PARSE_NEEDVAL) && !pfirst) {
224450696a6eSStefan Eßer 
224544d4804dSStefan Eßer 		// We have the easy case if the last operator was an assignment
224644d4804dSStefan Eßer 		// operator.
224750696a6eSStefan Eßer 		if (assign) {
224850696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
224950696a6eSStefan Eßer 			inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
225050696a6eSStefan Eßer 			incdec = false;
225150696a6eSStefan Eßer 		}
225244d4804dSStefan Eßer 		// If we have an inc/dec operator and we are *not* printing, implement
225344d4804dSStefan Eßer 		// the optimization to get rid of the extra copy.
225450696a6eSStefan Eßer 		else if (incdec && !(flags & BC_PARSE_PRINT)) {
225550696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
225650696a6eSStefan Eßer 			incdec = (inst <= BC_INST_DEC);
225750696a6eSStefan Eßer 			inst = BC_INST_ASSIGN_PLUS_NO_VAL + (inst != BC_INST_INC &&
225850696a6eSStefan Eßer 			                                     inst != BC_INST_ASSIGN_PLUS);
225950696a6eSStefan Eßer 		}
226050696a6eSStefan Eßer 
226144d4804dSStefan Eßer 		// This condition allows us to change the previous assignment
226244d4804dSStefan Eßer 		// instruction (which does a copy) for a NO_VAL version, which does not.
226344d4804dSStefan Eßer 		// This condition is set if either of the above if statements ends up
226444d4804dSStefan Eßer 		// being true.
226550696a6eSStefan Eßer 		if (inst >= BC_INST_ASSIGN_POWER_NO_VAL &&
226650696a6eSStefan Eßer 		    inst <= BC_INST_ASSIGN_NO_VAL)
226750696a6eSStefan Eßer 		{
226844d4804dSStefan Eßer 			// Pop the previous assignment instruction and push a new one.
226944d4804dSStefan Eßer 			// Inc/dec needs the extra instruction because it is now a binary
227044d4804dSStefan Eßer 			// operator and needs a second operand.
227150696a6eSStefan Eßer 			bc_vec_pop(&p->func->code);
227250696a6eSStefan Eßer 			if (incdec) bc_parse_push(p, BC_INST_ONE);
227350696a6eSStefan Eßer 			bc_parse_push(p, inst);
227450696a6eSStefan Eßer 		}
227550696a6eSStefan Eßer 	}
227650696a6eSStefan Eßer 
227744d4804dSStefan Eßer 	// If we might have to print...
227850696a6eSStefan Eßer 	if ((flags & BC_PARSE_PRINT)) {
227944d4804dSStefan Eßer 
228044d4804dSStefan Eßer 		// With a paren first or the last operator not being an assignment, we
228144d4804dSStefan Eßer 		// *do* want to print.
228250696a6eSStefan Eßer 		if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
228350696a6eSStefan Eßer 	}
228444d4804dSStefan Eßer 	// We need to make sure to push a pop instruction for assignment statements
228544d4804dSStefan Eßer 	// that will not print. The print will pop, but without it, we need to pop.
228650696a6eSStefan Eßer 	else if (!(flags & BC_PARSE_NEEDVAL) &&
228750696a6eSStefan Eßer 	         (inst < BC_INST_ASSIGN_POWER_NO_VAL ||
228850696a6eSStefan Eßer 	          inst > BC_INST_ASSIGN_NO_VAL))
228950696a6eSStefan Eßer 	{
229050696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_POP);
229150696a6eSStefan Eßer 	}
229250696a6eSStefan Eßer 
229350696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
229450696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
229544d4804dSStefan Eßer 	//
229644d4804dSStefan Eßer 	// Yes, this is one case where I reuse a variable for a different purpose;
229744d4804dSStefan Eßer 	// in this case, incdec being true now means that newlines are not valid.
229850696a6eSStefan Eßer 	for (incdec = true, i = 0; i < next.len && incdec; ++i)
229950696a6eSStefan Eßer 		incdec = (next.tokens[i] != BC_LEX_NLINE);
230050696a6eSStefan Eßer 	if (incdec) {
230150696a6eSStefan Eßer 		while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
230250696a6eSStefan Eßer 	}
230350696a6eSStefan Eßer 
230450696a6eSStefan Eßer 	return BC_PARSE_STATUS_SUCCESS;
230550696a6eSStefan Eßer }
230650696a6eSStefan Eßer 
230744d4804dSStefan Eßer /**
230844d4804dSStefan Eßer  * Parses an expression with bc_parse_expr_err(), but throws an error if it gets
230944d4804dSStefan Eßer  * an empty expression.
231044d4804dSStefan Eßer  * @param p      The parser.
231144d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
231244d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
231344d4804dSStefan Eßer  */
231444d4804dSStefan Eßer static void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) {
231550696a6eSStefan Eßer 
231650696a6eSStefan Eßer 	BcParseStatus s = bc_parse_expr_err(p, flags, next);
231750696a6eSStefan Eßer 
231850696a6eSStefan Eßer 	if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR))
231950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR);
232050696a6eSStefan Eßer }
232150696a6eSStefan Eßer 
232250696a6eSStefan Eßer void bc_parse_expr(BcParse *p, uint8_t flags) {
232350696a6eSStefan Eßer 	assert(p);
232450696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_read);
232550696a6eSStefan Eßer }
232650696a6eSStefan Eßer #endif // BC_ENABLED
2327