xref: /freebsd/contrib/bc/src/bc_parse.c (revision a30efc5ca7272e446abb71f0d72c76539f267bb6)
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.
8244d4804dSStefan Eßer  */
8350696a6eSStefan Eßer static bool bc_parse_isDelimiter(const BcParse *p) {
8450696a6eSStefan Eßer 
8550696a6eSStefan Eßer 	BcLexType t = p->l.t;
8644d4804dSStefan Eßer 	bool good;
8750696a6eSStefan Eßer 
8844d4804dSStefan Eßer 	// If it's an obvious delimiter, say so.
8950696a6eSStefan Eßer 	if (BC_PARSE_DELIMITER(t)) return true;
9050696a6eSStefan Eßer 
9144d4804dSStefan Eßer 	good = false;
9244d4804dSStefan Eßer 
9344d4804dSStefan Eßer 	// If the current token is a keyword, then...beware. That means that we need
9444d4804dSStefan Eßer 	// to check for a "dangling" else, where there was no brace-delimited block
9544d4804dSStefan Eßer 	// on the previous if.
9650696a6eSStefan Eßer 	if (t == BC_LEX_KW_ELSE) {
9750696a6eSStefan Eßer 
9850696a6eSStefan Eßer 		size_t i;
9950696a6eSStefan Eßer 		uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE;
10050696a6eSStefan Eßer 
10144d4804dSStefan Eßer 		// As long as going up the stack is valid for a dangling else, keep on.
10250696a6eSStefan Eßer 		for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) {
10350696a6eSStefan Eßer 
10450696a6eSStefan Eßer 			fptr = bc_vec_item_rev(&p->flags, i);
10550696a6eSStefan Eßer 			flags = *fptr;
10650696a6eSStefan Eßer 
10744d4804dSStefan Eßer 			// If we need a brace and don't have one, then we don't have a
10844d4804dSStefan Eßer 			// delimiter.
10950696a6eSStefan Eßer 			if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE)
11050696a6eSStefan Eßer 				return false;
11150696a6eSStefan Eßer 		}
11250696a6eSStefan Eßer 
11344d4804dSStefan Eßer 		// Oh, and we had also better have an if statement somewhere.
11450696a6eSStefan Eßer 		good = ((flags & BC_PARSE_FLAG_IF) != 0);
11550696a6eSStefan Eßer 	}
11650696a6eSStefan Eßer 	else if (t == BC_LEX_RBRACE) {
11750696a6eSStefan Eßer 
11850696a6eSStefan Eßer 		size_t i;
11950696a6eSStefan Eßer 
12044d4804dSStefan Eßer 		// Since we have a brace, we need to just check if a brace was needed.
12150696a6eSStefan Eßer 		for (i = 0; !good && i < p->flags.len; ++i) {
12250696a6eSStefan Eßer 			uint16_t *fptr = bc_vec_item_rev(&p->flags, i);
12350696a6eSStefan Eßer 			good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0);
12450696a6eSStefan Eßer 		}
12550696a6eSStefan Eßer 	}
12650696a6eSStefan Eßer 
12750696a6eSStefan Eßer 	return good;
12850696a6eSStefan Eßer }
12950696a6eSStefan Eßer 
13044d4804dSStefan Eßer /**
13144d4804dSStefan Eßer  * Sets a previously defined exit label. What are labels? See the bc Parsing
13244d4804dSStefan Eßer  * section of the Development manual (manuals/development.md).
13344d4804dSStefan Eßer  * @param p  The parser.
13444d4804dSStefan Eßer  */
13550696a6eSStefan Eßer static void bc_parse_setLabel(BcParse *p) {
13650696a6eSStefan Eßer 
13750696a6eSStefan Eßer 	BcFunc *func = p->func;
13850696a6eSStefan Eßer 	BcInstPtr *ip = bc_vec_top(&p->exits);
13950696a6eSStefan Eßer 	size_t *label;
14050696a6eSStefan Eßer 
14150696a6eSStefan Eßer 	assert(func == bc_vec_item(&p->prog->fns, p->fidx));
14250696a6eSStefan Eßer 
14344d4804dSStefan Eßer 	// Set the preallocated label to the correct index.
14450696a6eSStefan Eßer 	label = bc_vec_item(&func->labels, ip->idx);
14550696a6eSStefan Eßer 	*label = func->code.len;
14650696a6eSStefan Eßer 
14744d4804dSStefan Eßer 	// Now, we don't need the exit label; it is done.
14850696a6eSStefan Eßer 	bc_vec_pop(&p->exits);
14950696a6eSStefan Eßer }
15050696a6eSStefan Eßer 
15144d4804dSStefan Eßer /**
15244d4804dSStefan Eßer  * Creates a label and sets it to idx. If this is an exit label, then idx is
15344d4804dSStefan Eßer  * actually invalid, but it doesn't matter because it will be fixed by
15444d4804dSStefan Eßer  * bc_parse_setLabel() later.
15544d4804dSStefan Eßer  * @param p    The parser.
15644d4804dSStefan Eßer  * @param idx  The index of the label.
15744d4804dSStefan Eßer  */
15850696a6eSStefan Eßer static void bc_parse_createLabel(BcParse *p, size_t idx) {
15950696a6eSStefan Eßer 	bc_vec_push(&p->func->labels, &idx);
16050696a6eSStefan Eßer }
16150696a6eSStefan Eßer 
16244d4804dSStefan Eßer /**
16344d4804dSStefan Eßer  * Creates a conditional label. Unlike an exit label, this label is set at
16444d4804dSStefan Eßer  * creation time because it comes *before* the code that will target it.
16544d4804dSStefan Eßer  * @param p    The parser.
16644d4804dSStefan Eßer  * @param idx  The index of the label.
16744d4804dSStefan Eßer  */
16850696a6eSStefan Eßer static void bc_parse_createCondLabel(BcParse *p, size_t idx) {
16950696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
17050696a6eSStefan Eßer 	bc_vec_push(&p->conds, &idx);
17150696a6eSStefan Eßer }
17250696a6eSStefan Eßer 
17344d4804dSStefan Eßer /*
17444d4804dSStefan Eßer  * Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why
17544d4804dSStefan Eßer  * create a label to be filled in later? Because exit labels are meant to be
17644d4804dSStefan Eßer  * targeted by code that comes *before* the label. Since we have to parse that
17744d4804dSStefan Eßer  * code first, and don't know how long it will be, we need to just make sure to
17844d4804dSStefan Eßer  * reserve a slot to be filled in later when we know.
17944d4804dSStefan Eßer  *
18044d4804dSStefan Eßer  * By the way, this uses BcInstPtr because it was convenient. The field idx
18144d4804dSStefan Eßer  * holds the index, and the field func holds the loop boolean.
18244d4804dSStefan Eßer  *
18344d4804dSStefan Eßer  * @param p     The parser.
18444d4804dSStefan Eßer  * @param idx   The index of the label's position.
18544d4804dSStefan Eßer  * @param loop  True if the exit label is for a loop or not.
18644d4804dSStefan Eßer  */
18750696a6eSStefan Eßer static void bc_parse_createExitLabel(BcParse *p, size_t idx, bool loop) {
18850696a6eSStefan Eßer 
18950696a6eSStefan Eßer 	BcInstPtr ip;
19050696a6eSStefan Eßer 
19150696a6eSStefan Eßer 	assert(p->func == bc_vec_item(&p->prog->fns, p->fidx));
19250696a6eSStefan Eßer 
19350696a6eSStefan Eßer 	ip.func = loop;
19450696a6eSStefan Eßer 	ip.idx = idx;
19550696a6eSStefan Eßer 	ip.len = 0;
19650696a6eSStefan Eßer 
19750696a6eSStefan Eßer 	bc_vec_push(&p->exits, &ip);
19850696a6eSStefan Eßer 	bc_parse_createLabel(p, SIZE_MAX);
19950696a6eSStefan Eßer }
20050696a6eSStefan Eßer 
20144d4804dSStefan Eßer /**
20244d4804dSStefan Eßer  * Pops the correct operators off of the operator stack based on the current
20344d4804dSStefan Eßer  * operator. This is because of the Shunting-Yard algorithm. Lower prec means
20444d4804dSStefan Eßer  * higher precedence.
20544d4804dSStefan Eßer  * @param p       The parser.
20644d4804dSStefan Eßer  * @param type    The operator.
20744d4804dSStefan Eßer  * @param start   The previous start of the operator stack. For more
20844d4804dSStefan Eßer  *                information, see the bc Parsing section of the Development
20944d4804dSStefan Eßer  *                manual (manuals/development.md).
21044d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
21144d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
21244d4804dSStefan Eßer  */
21350696a6eSStefan Eßer static void bc_parse_operator(BcParse *p, BcLexType type,
21450696a6eSStefan Eßer                               size_t start, size_t *nexprs)
21550696a6eSStefan Eßer {
21650696a6eSStefan Eßer 	BcLexType t;
21750696a6eSStefan Eßer 	uchar l, r = BC_PARSE_OP_PREC(type);
21850696a6eSStefan Eßer 	uchar left = BC_PARSE_OP_LEFT(type);
21950696a6eSStefan Eßer 
22044d4804dSStefan Eßer 	// While we haven't hit the stop point yet.
22150696a6eSStefan Eßer 	while (p->ops.len > start) {
22250696a6eSStefan Eßer 
22344d4804dSStefan Eßer 		// Get the top operator.
22450696a6eSStefan Eßer 		t = BC_PARSE_TOP_OP(p);
22544d4804dSStefan Eßer 
22644d4804dSStefan Eßer 		// If it's a right paren, we have reached the end of whatever expression
22744d4804dSStefan Eßer 		// this is no matter what.
22850696a6eSStefan Eßer 		if (t == BC_LEX_LPAREN) break;
22950696a6eSStefan Eßer 
23044d4804dSStefan Eßer 		// Break for precedence. Precedence operates differently on left and
23144d4804dSStefan Eßer 		// right associativity, by the way. A left associative operator that
23244d4804dSStefan Eßer 		// matches the current precedence should take priority, but a right
23344d4804dSStefan Eßer 		// associative operator should not.
23450696a6eSStefan Eßer 		l = BC_PARSE_OP_PREC(t);
23550696a6eSStefan Eßer 		if (l >= r && (l != r || !left)) break;
23650696a6eSStefan Eßer 
23744d4804dSStefan Eßer 		// Do the housekeeping. In particular, make sure to note that one
23844d4804dSStefan Eßer 		// expression was consumed. (Two were, but another was added.)
23950696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(t));
24050696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
24150696a6eSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(t);
24250696a6eSStefan Eßer 	}
24350696a6eSStefan Eßer 
24450696a6eSStefan Eßer 	bc_vec_push(&p->ops, &type);
24550696a6eSStefan Eßer }
24650696a6eSStefan Eßer 
24744d4804dSStefan Eßer /**
24844d4804dSStefan Eßer  * Parses a right paren. In the Shunting-Yard algorithm, it needs to be put on
24944d4804dSStefan Eßer  * the operator stack. But before that, it needs to consume whatever operators
25044d4804dSStefan Eßer  * there are until it hits a left paren.
25144d4804dSStefan Eßer  * @param p       The parser.
25244d4804dSStefan Eßer  * @param nexprs  A pointer to the current number of expressions that have not
25344d4804dSStefan Eßer  *                been consumed yet. This is an IN and OUT parameter.
25444d4804dSStefan Eßer  */
25544d4804dSStefan Eßer static void bc_parse_rightParen(BcParse *p, size_t *nexprs) {
25650696a6eSStefan Eßer 
25750696a6eSStefan Eßer 	BcLexType top;
25850696a6eSStefan Eßer 
25944d4804dSStefan Eßer 	// Consume operators until a left paren.
26050696a6eSStefan Eßer 	while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) {
26150696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
26250696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
26344d4804dSStefan Eßer 		*nexprs -= !BC_PARSE_OP_PREFIX(top);
26450696a6eSStefan Eßer 	}
26550696a6eSStefan Eßer 
26644d4804dSStefan Eßer 	// We need to pop the left paren as well.
26750696a6eSStefan Eßer 	bc_vec_pop(&p->ops);
26850696a6eSStefan Eßer 
26944d4804dSStefan Eßer 	// Oh, and we also want the next token.
27050696a6eSStefan Eßer 	bc_lex_next(&p->l);
27150696a6eSStefan Eßer }
27250696a6eSStefan Eßer 
27344d4804dSStefan Eßer /**
27444d4804dSStefan Eßer  * Parses function arguments.
27544d4804dSStefan Eßer  * @param p      The parser.
27644d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
27744d4804dSStefan Eßer  *               be.
27844d4804dSStefan Eßer  */
27944d4804dSStefan Eßer static void bc_parse_args(BcParse *p, uint8_t flags) {
28050696a6eSStefan Eßer 
28150696a6eSStefan Eßer 	bool comma = false;
28244d4804dSStefan Eßer 	size_t nargs;
28350696a6eSStefan Eßer 
28450696a6eSStefan Eßer 	bc_lex_next(&p->l);
28550696a6eSStefan Eßer 
28644d4804dSStefan Eßer 	// Print and comparison operators not allowed. Well, comparison operators
28744d4804dSStefan Eßer 	// only for POSIX. But we do allow arrays, and we *must* get a value.
28850696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
28950696a6eSStefan Eßer 	flags |= (BC_PARSE_ARRAY | BC_PARSE_NEEDVAL);
29050696a6eSStefan Eßer 
29144d4804dSStefan Eßer 	// Count the arguments and parse them.
29244d4804dSStefan Eßer 	for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs) {
29350696a6eSStefan Eßer 
29444d4804dSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_arg);
29550696a6eSStefan Eßer 
29650696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
29750696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
29850696a6eSStefan Eßer 	}
29950696a6eSStefan Eßer 
30044d4804dSStefan Eßer 	// An ending comma is FAIL.
30150696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
30244d4804dSStefan Eßer 
30344d4804dSStefan Eßer 	// Now do the call with the number of arguments.
30450696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_CALL);
30544d4804dSStefan Eßer 	bc_parse_pushIndex(p, nargs);
30650696a6eSStefan Eßer }
30750696a6eSStefan Eßer 
30844d4804dSStefan Eßer /**
30944d4804dSStefan Eßer  * Parses a function call.
31044d4804dSStefan Eßer  * @param p      The parser.
31144d4804dSStefan Eßer  * @param flags  Flags restricting what kind of expressions the arguments can
31244d4804dSStefan Eßer  *               be.
31344d4804dSStefan Eßer  */
31450696a6eSStefan Eßer static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) {
31550696a6eSStefan Eßer 
31650696a6eSStefan Eßer 	size_t idx;
31750696a6eSStefan Eßer 
31844d4804dSStefan Eßer 	bc_parse_args(p, flags);
31950696a6eSStefan Eßer 
32044d4804dSStefan Eßer 	// We just assert this because bc_parse_args() should
32150696a6eSStefan Eßer 	// ensure that the next token is what it should be.
32250696a6eSStefan Eßer 	assert(p->l.t == BC_LEX_RPAREN);
32350696a6eSStefan Eßer 
32450696a6eSStefan Eßer 	// We cannot use bc_program_insertFunc() here
32550696a6eSStefan Eßer 	// because it will overwrite an existing function.
32650696a6eSStefan Eßer 	idx = bc_map_index(&p->prog->fn_map, name);
32750696a6eSStefan Eßer 
32844d4804dSStefan Eßer 	// The function does not exist yet. Create a space for it. If the user does
32944d4804dSStefan Eßer 	// not define it, it's a *runtime* error, not a parse error.
33050696a6eSStefan Eßer 	if (idx == BC_VEC_INVALID_IDX) {
33150696a6eSStefan Eßer 
33250696a6eSStefan Eßer 		BC_SIG_LOCK;
33350696a6eSStefan Eßer 
33450696a6eSStefan Eßer 		idx = bc_program_insertFunc(p->prog, name);
33550696a6eSStefan Eßer 
33650696a6eSStefan Eßer 		BC_SIG_UNLOCK;
33750696a6eSStefan Eßer 
33850696a6eSStefan Eßer 		assert(idx != BC_VEC_INVALID_IDX);
33950696a6eSStefan Eßer 
34050696a6eSStefan Eßer 		// Make sure that this pointer was not invalidated.
34150696a6eSStefan Eßer 		p->func = bc_vec_item(&p->prog->fns, p->fidx);
34250696a6eSStefan Eßer 	}
34344d4804dSStefan Eßer 	// The function exists, so set the right function index.
34450696a6eSStefan Eßer 	else idx = ((BcId*) bc_vec_item(&p->prog->fn_map, idx))->idx;
34550696a6eSStefan Eßer 
34650696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
34750696a6eSStefan Eßer 
34844d4804dSStefan Eßer 	// Make sure to get the next token.
34950696a6eSStefan Eßer 	bc_lex_next(&p->l);
35050696a6eSStefan Eßer }
35150696a6eSStefan Eßer 
35244d4804dSStefan Eßer /**
35344d4804dSStefan Eßer  * Parses a name/identifier-based expression. It could be a variable, an array
35444d4804dSStefan Eßer  * element, an array itself (for function arguments), a function call, etc.
35544d4804dSStefan Eßer  *
35644d4804dSStefan Eßer  */
35750696a6eSStefan Eßer static void bc_parse_name(BcParse *p, BcInst *type,
35850696a6eSStefan Eßer                           bool *can_assign, uint8_t flags)
35950696a6eSStefan Eßer {
36050696a6eSStefan Eßer 	char *name;
36150696a6eSStefan Eßer 
36250696a6eSStefan Eßer 	BC_SIG_LOCK;
36350696a6eSStefan Eßer 
36444d4804dSStefan Eßer 	// We want a copy of the name since the lexer might overwrite its copy.
36550696a6eSStefan Eßer 	name = bc_vm_strdup(p->l.str.v);
36650696a6eSStefan Eßer 
36750696a6eSStefan Eßer 	BC_SETJMP_LOCKED(err);
36850696a6eSStefan Eßer 
36950696a6eSStefan Eßer 	BC_SIG_UNLOCK;
37050696a6eSStefan Eßer 
37144d4804dSStefan Eßer 	// We need the next token to see if it's just a variable or something more.
37250696a6eSStefan Eßer 	bc_lex_next(&p->l);
37350696a6eSStefan Eßer 
37444d4804dSStefan Eßer 	// Array element or array.
37550696a6eSStefan Eßer 	if (p->l.t == BC_LEX_LBRACKET) {
37650696a6eSStefan Eßer 
37750696a6eSStefan Eßer 		bc_lex_next(&p->l);
37850696a6eSStefan Eßer 
37944d4804dSStefan Eßer 		// Array only. This has to be a function parameter.
38050696a6eSStefan Eßer 		if (p->l.t == BC_LEX_RBRACKET) {
38150696a6eSStefan Eßer 
38244d4804dSStefan Eßer 			// Error if arrays are not allowed.
38350696a6eSStefan Eßer 			if (BC_ERR(!(flags & BC_PARSE_ARRAY)))
38450696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_EXPR);
38550696a6eSStefan Eßer 
38650696a6eSStefan Eßer 			*type = BC_INST_ARRAY;
38750696a6eSStefan Eßer 			*can_assign = false;
38850696a6eSStefan Eßer 		}
38950696a6eSStefan Eßer 		else {
39050696a6eSStefan Eßer 
39144d4804dSStefan Eßer 			// If we are here, we have an array element. We need to set the
39244d4804dSStefan Eßer 			// expression parsing flags.
39350696a6eSStefan Eßer 			uint8_t flags2 = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) |
39450696a6eSStefan Eßer 			                 BC_PARSE_NEEDVAL;
39550696a6eSStefan Eßer 
39650696a6eSStefan Eßer 			bc_parse_expr_status(p, flags2, bc_parse_next_elem);
39750696a6eSStefan Eßer 
39844d4804dSStefan Eßer 			// The next token *must* be a right bracket.
39950696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
40050696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
40150696a6eSStefan Eßer 
40250696a6eSStefan Eßer 			*type = BC_INST_ARRAY_ELEM;
40350696a6eSStefan Eßer 			*can_assign = true;
40450696a6eSStefan Eßer 		}
40550696a6eSStefan Eßer 
40644d4804dSStefan Eßer 		// Make sure to get the next token.
40750696a6eSStefan Eßer 		bc_lex_next(&p->l);
40850696a6eSStefan Eßer 
40944d4804dSStefan Eßer 		// Push the instruction and the name of the identifier.
41050696a6eSStefan Eßer 		bc_parse_push(p, *type);
41150696a6eSStefan Eßer 		bc_parse_pushName(p, name, false);
41250696a6eSStefan Eßer 	}
41350696a6eSStefan Eßer 	else if (p->l.t == BC_LEX_LPAREN) {
41450696a6eSStefan Eßer 
41544d4804dSStefan Eßer 		// We are parsing a function call; error if not allowed.
41650696a6eSStefan Eßer 		if (BC_ERR(flags & BC_PARSE_NOCALL))
41750696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
41850696a6eSStefan Eßer 
41950696a6eSStefan Eßer 		*type = BC_INST_CALL;
42050696a6eSStefan Eßer 		*can_assign = false;
42150696a6eSStefan Eßer 
42250696a6eSStefan Eßer 		bc_parse_call(p, name, flags);
42350696a6eSStefan Eßer 	}
42450696a6eSStefan Eßer 	else {
42544d4804dSStefan Eßer 		// Just a variable.
42650696a6eSStefan Eßer 		*type = BC_INST_VAR;
42750696a6eSStefan Eßer 		*can_assign = true;
42850696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_VAR);
42950696a6eSStefan Eßer 		bc_parse_pushName(p, name, true);
43050696a6eSStefan Eßer 	}
43150696a6eSStefan Eßer 
43250696a6eSStefan Eßer err:
43344d4804dSStefan Eßer 	// Need to make sure to unallocate the name.
43450696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
43550696a6eSStefan Eßer 	free(name);
43650696a6eSStefan Eßer 	BC_LONGJMP_CONT;
43750696a6eSStefan Eßer }
43850696a6eSStefan Eßer 
43944d4804dSStefan Eßer /**
44044d4804dSStefan Eßer  * Parses a builtin function that takes no arguments. This includes read(),
44144d4804dSStefan Eßer  * rand(), maxibase(), maxobase(), maxscale(), and maxrand().
44244d4804dSStefan Eßer  * @param p     The parser.
44344d4804dSStefan Eßer  * @param inst  The instruction corresponding to the builtin.
44444d4804dSStefan Eßer  */
44550696a6eSStefan Eßer static void bc_parse_noArgBuiltin(BcParse *p, BcInst inst) {
44650696a6eSStefan Eßer 
44744d4804dSStefan Eßer 	// Must have a left paren.
44850696a6eSStefan Eßer 	bc_lex_next(&p->l);
44950696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
45050696a6eSStefan Eßer 
45144d4804dSStefan Eßer 	// Must have a right paren.
45250696a6eSStefan Eßer 	bc_lex_next(&p->l);
45350696a6eSStefan Eßer 	if ((p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
45450696a6eSStefan Eßer 
45550696a6eSStefan Eßer 	bc_parse_push(p, inst);
45650696a6eSStefan Eßer 
45750696a6eSStefan Eßer 	bc_lex_next(&p->l);
45850696a6eSStefan Eßer }
45950696a6eSStefan Eßer 
46044d4804dSStefan Eßer /**
46144d4804dSStefan Eßer  * Parses a builtin function that takes 1 argument. This includes length(),
46244d4804dSStefan Eßer  * sqrt(), abs(), scale(), and irand().
46344d4804dSStefan Eßer  * @param p      The parser.
46444d4804dSStefan Eßer  * @param type   The lex token.
46544d4804dSStefan Eßer  * @param flags  The expression parsing flags for parsing the argument.
46644d4804dSStefan Eßer  * @param prev   An out parameter; the previous instruction pointer.
46744d4804dSStefan Eßer  */
46850696a6eSStefan Eßer static void bc_parse_builtin(BcParse *p, BcLexType type,
46950696a6eSStefan Eßer                              uint8_t flags, BcInst *prev)
47050696a6eSStefan Eßer {
47144d4804dSStefan Eßer 	// Must have a left paren.
47250696a6eSStefan Eßer 	bc_lex_next(&p->l);
47350696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
47450696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
47550696a6eSStefan Eßer 
47650696a6eSStefan Eßer 	bc_lex_next(&p->l);
47750696a6eSStefan Eßer 
47844d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
47950696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
48050696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
48144d4804dSStefan Eßer 
48244d4804dSStefan Eßer 	// Since length can take arrays, we need to specially add that flag.
48350696a6eSStefan Eßer 	if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY;
48450696a6eSStefan Eßer 
48550696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
48650696a6eSStefan Eßer 
48744d4804dSStefan Eßer 	// Must have a right paren.
48850696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
48950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
49050696a6eSStefan Eßer 
49144d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
49250696a6eSStefan Eßer 	*prev = type - BC_LEX_KW_LENGTH + BC_INST_LENGTH;
49350696a6eSStefan Eßer 	bc_parse_push(p, *prev);
49450696a6eSStefan Eßer 
49550696a6eSStefan Eßer 	bc_lex_next(&p->l);
49650696a6eSStefan Eßer }
49750696a6eSStefan Eßer 
49844d4804dSStefan Eßer /**
49944d4804dSStefan Eßer  * Parses a builtin function that takes 3 arguments. This includes modexp() and
50044d4804dSStefan Eßer  * divmod().
50144d4804dSStefan Eßer  */
50244d4804dSStefan Eßer static void bc_parse_builtin3(BcParse *p, BcLexType type,
50344d4804dSStefan Eßer                               uint8_t flags, BcInst *prev)
50444d4804dSStefan Eßer {
50544d4804dSStefan Eßer 	assert(type == BC_LEX_KW_MODEXP || type == BC_LEX_KW_DIVMOD);
50644d4804dSStefan Eßer 
50744d4804dSStefan Eßer 	// Must have a left paren.
50844d4804dSStefan Eßer 	bc_lex_next(&p->l);
50944d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
51044d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
51144d4804dSStefan Eßer 
51244d4804dSStefan Eßer 	bc_lex_next(&p->l);
51344d4804dSStefan Eßer 
51444d4804dSStefan Eßer 	// Change the flags as needed for parsing the argument.
51544d4804dSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
51644d4804dSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
51744d4804dSStefan Eßer 
51844d4804dSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
51944d4804dSStefan Eßer 
52044d4804dSStefan Eßer 	// Must have a comma.
52144d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA))
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 	bc_parse_expr_status(p, flags, bc_parse_next_builtin);
52744d4804dSStefan Eßer 
52844d4804dSStefan Eßer 	// Must have a comma.
52944d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_COMMA))
53044d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
53144d4804dSStefan Eßer 
53244d4804dSStefan Eßer 	bc_lex_next(&p->l);
53344d4804dSStefan Eßer 
53444d4804dSStefan Eßer 	// If it is a divmod, parse an array name. Otherwise, just parse another
53544d4804dSStefan Eßer 	// expression.
53644d4804dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD) {
53744d4804dSStefan Eßer 
53844d4804dSStefan Eßer 		// Must have a name.
53944d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
54044d4804dSStefan Eßer 
54144d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
54244d4804dSStefan Eßer 		bc_lex_next(&p->l);
54344d4804dSStefan Eßer 
54444d4804dSStefan Eßer 		// Must have a left bracket.
54544d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_LBRACKET))
54644d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
54744d4804dSStefan Eßer 
54844d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
54944d4804dSStefan Eßer 		bc_lex_next(&p->l);
55044d4804dSStefan Eßer 
55144d4804dSStefan Eßer 		// Must have a right bracket.
55244d4804dSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
55344d4804dSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
55444d4804dSStefan Eßer 
55544d4804dSStefan Eßer 		// This is safe because the next token should not overwrite the name.
55644d4804dSStefan Eßer 		bc_lex_next(&p->l);
55744d4804dSStefan Eßer 	}
55844d4804dSStefan Eßer 	else bc_parse_expr_status(p, flags, bc_parse_next_rel);
55944d4804dSStefan Eßer 
56044d4804dSStefan Eßer 	// Must have a right paren.
56144d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
56244d4804dSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
56344d4804dSStefan Eßer 
56444d4804dSStefan Eßer 	// Adjust previous based on the token and push it.
56544d4804dSStefan Eßer 	*prev = type - BC_LEX_KW_MODEXP + BC_INST_MODEXP;
56644d4804dSStefan Eßer 	bc_parse_push(p, *prev);
56744d4804dSStefan Eßer 
56844d4804dSStefan Eßer 	// If we have divmod, we need to assign the modulus to the array element, so
56944d4804dSStefan Eßer 	// we need to push the instructions for doing so.
57044d4804dSStefan Eßer 	if (type == BC_LEX_KW_DIVMOD) {
57144d4804dSStefan Eßer 
57244d4804dSStefan Eßer 		// The zeroth element.
57344d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ZERO);
57444d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ARRAY_ELEM);
57544d4804dSStefan Eßer 
57644d4804dSStefan Eßer 		// Push the array.
57744d4804dSStefan Eßer 		bc_parse_pushName(p, p->l.str.v, false);
57844d4804dSStefan Eßer 
57944d4804dSStefan Eßer 		// Swap them and assign. After this, the top item on the stack should
58044d4804dSStefan Eßer 		// be the quotient.
58144d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_SWAP);
58244d4804dSStefan Eßer 		bc_parse_push(p, BC_INST_ASSIGN_NO_VAL);
58344d4804dSStefan Eßer 	}
58444d4804dSStefan Eßer 
58544d4804dSStefan Eßer 	bc_lex_next(&p->l);
58644d4804dSStefan Eßer }
58744d4804dSStefan Eßer 
58844d4804dSStefan Eßer /**
58944d4804dSStefan Eßer  * Parses the scale keyword. This is special because scale can be a value or a
59044d4804dSStefan Eßer  * builtin function.
59144d4804dSStefan Eßer  * @param p           The parser.
59244d4804dSStefan Eßer  * @param type        An out parameter; the instruction for the parse.
59344d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
59444d4804dSStefan Eßer  *                    to.
59544d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
59644d4804dSStefan Eßer  */
59750696a6eSStefan Eßer static void bc_parse_scale(BcParse *p, BcInst *type,
59850696a6eSStefan Eßer                            bool *can_assign, uint8_t flags)
59950696a6eSStefan Eßer {
60050696a6eSStefan Eßer 	bc_lex_next(&p->l);
60150696a6eSStefan Eßer 
60244d4804dSStefan Eßer 	// Without the left paren, it's just the keyword.
60350696a6eSStefan Eßer 	if (p->l.t != BC_LEX_LPAREN) {
60444d4804dSStefan Eßer 
60544d4804dSStefan Eßer 		// Set, push, and return.
60650696a6eSStefan Eßer 		*type = BC_INST_SCALE;
60750696a6eSStefan Eßer 		*can_assign = true;
60850696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_SCALE);
60950696a6eSStefan Eßer 		return;
61050696a6eSStefan Eßer 	}
61150696a6eSStefan Eßer 
61244d4804dSStefan Eßer 	// Handle the scale function.
61350696a6eSStefan Eßer 	*type = BC_INST_SCALE_FUNC;
61450696a6eSStefan Eßer 	*can_assign = false;
61544d4804dSStefan Eßer 
61644d4804dSStefan Eßer 	// Once again, adjust the flags.
61750696a6eSStefan Eßer 	flags &= ~(BC_PARSE_PRINT | BC_PARSE_REL);
61850696a6eSStefan Eßer 	flags |= BC_PARSE_NEEDVAL;
61950696a6eSStefan Eßer 
62050696a6eSStefan Eßer 	bc_lex_next(&p->l);
62150696a6eSStefan Eßer 
62250696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
62344d4804dSStefan Eßer 
62444d4804dSStefan Eßer 	// Must have a right paren.
62550696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
62650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
62750696a6eSStefan Eßer 
62850696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_SCALE_FUNC);
62950696a6eSStefan Eßer 
63050696a6eSStefan Eßer 	bc_lex_next(&p->l);
63150696a6eSStefan Eßer }
63250696a6eSStefan Eßer 
63344d4804dSStefan Eßer /**
63444d4804dSStefan Eßer  * Parses and increment or decrement operator. This is a bit complex.
63544d4804dSStefan Eßer  * @param p           The parser.
63644d4804dSStefan Eßer  * @param prev        An out parameter; the previous instruction pointer.
63744d4804dSStefan Eßer  * @param can_assign  An out parameter; whether the expression can be assigned
63844d4804dSStefan Eßer  *                    to.
63944d4804dSStefan Eßer  * @param nexs        An in/out parameter; the number of expressions in the
64044d4804dSStefan Eßer  *                    parse tree that are not used.
64144d4804dSStefan Eßer  * @param flags       The expression parsing flags for parsing a scale() arg.
64244d4804dSStefan Eßer  */
64350696a6eSStefan Eßer static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign,
64450696a6eSStefan Eßer                             size_t *nexs, uint8_t flags)
64550696a6eSStefan Eßer {
64650696a6eSStefan Eßer 	BcLexType type;
64750696a6eSStefan Eßer 	uchar inst;
64850696a6eSStefan Eßer 	BcInst etype = *prev;
64950696a6eSStefan Eßer 	BcLexType last = p->l.last;
65050696a6eSStefan Eßer 
65150696a6eSStefan Eßer 	assert(prev != NULL && can_assign != NULL);
65250696a6eSStefan Eßer 
65344d4804dSStefan Eßer 	// If we can't assign to the previous token, then we have an error.
65450696a6eSStefan Eßer 	if (BC_ERR(last == BC_LEX_OP_INC || last == BC_LEX_OP_DEC ||
65550696a6eSStefan Eßer 	           last == BC_LEX_RPAREN))
65650696a6eSStefan Eßer 	{
65750696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
65850696a6eSStefan Eßer 	}
65950696a6eSStefan Eßer 
66044d4804dSStefan Eßer 	// Is the previous instruction for a variable?
66150696a6eSStefan Eßer 	if (BC_PARSE_INST_VAR(etype)) {
66250696a6eSStefan Eßer 
66344d4804dSStefan Eßer 		// If so, this is a postfix operator.
66450696a6eSStefan Eßer 		if (!*can_assign) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
66550696a6eSStefan Eßer 
66644d4804dSStefan Eßer 		// Only postfix uses BC_INST_INC and BC_INST_DEC.
66750696a6eSStefan Eßer 		*prev = inst = BC_INST_INC + (p->l.t != BC_LEX_OP_INC);
66850696a6eSStefan Eßer 		bc_parse_push(p, inst);
66950696a6eSStefan Eßer 		bc_lex_next(&p->l);
67050696a6eSStefan Eßer 		*can_assign = false;
67150696a6eSStefan Eßer 	}
67250696a6eSStefan Eßer 	else {
67350696a6eSStefan Eßer 
67444d4804dSStefan Eßer 		// This is a prefix operator. In that case, we just convert it to
67544d4804dSStefan Eßer 		// an assignment instruction.
67650696a6eSStefan Eßer 		*prev = inst = BC_INST_ASSIGN_PLUS + (p->l.t != BC_LEX_OP_INC);
67750696a6eSStefan Eßer 
67850696a6eSStefan Eßer 		bc_lex_next(&p->l);
67950696a6eSStefan Eßer 		type = p->l.t;
68050696a6eSStefan Eßer 
68150696a6eSStefan Eßer 		// Because we parse the next part of the expression
68250696a6eSStefan Eßer 		// right here, we need to increment this.
68350696a6eSStefan Eßer 		*nexs = *nexs + 1;
68450696a6eSStefan Eßer 
68544d4804dSStefan Eßer 		// Is the next token a normal identifier?
68650696a6eSStefan Eßer 		if (type == BC_LEX_NAME) {
68744d4804dSStefan Eßer 
68844d4804dSStefan Eßer 			// Parse the name.
68950696a6eSStefan Eßer 			uint8_t flags2 = flags & ~BC_PARSE_ARRAY;
69050696a6eSStefan Eßer 			bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL);
69150696a6eSStefan Eßer 		}
69244d4804dSStefan Eßer 		// Is the next token a global?
69350696a6eSStefan Eßer 		else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE) {
69450696a6eSStefan Eßer 			bc_parse_push(p, type - BC_LEX_KW_LAST + BC_INST_LAST);
69550696a6eSStefan Eßer 			bc_lex_next(&p->l);
69650696a6eSStefan Eßer 		}
69744d4804dSStefan Eßer 		// Is the next token specifically scale, which needs special treatment?
69850696a6eSStefan Eßer 		else if (BC_NO_ERR(type == BC_LEX_KW_SCALE)) {
69950696a6eSStefan Eßer 
70050696a6eSStefan Eßer 			bc_lex_next(&p->l);
70150696a6eSStefan Eßer 
70244d4804dSStefan Eßer 			// Check that scale() was not used.
70350696a6eSStefan Eßer 			if (BC_ERR(p->l.t == BC_LEX_LPAREN))
70450696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
70550696a6eSStefan Eßer 			else bc_parse_push(p, BC_INST_SCALE);
70650696a6eSStefan Eßer 		}
70744d4804dSStefan Eßer 		// Now we know we have an error.
70850696a6eSStefan Eßer 		else bc_parse_err(p, BC_ERR_PARSE_TOKEN);
70950696a6eSStefan Eßer 
71050696a6eSStefan Eßer 		*can_assign = false;
71150696a6eSStefan Eßer 
71250696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_ONE);
71350696a6eSStefan Eßer 		bc_parse_push(p, inst);
71450696a6eSStefan Eßer 	}
71550696a6eSStefan Eßer }
71650696a6eSStefan Eßer 
71744d4804dSStefan Eßer /**
71844d4804dSStefan Eßer  * Parses the minus operator. This needs special treatment because it is either
71944d4804dSStefan Eßer  * subtract or negation.
72044d4804dSStefan Eßer  * @param p        The parser.
72144d4804dSStefan Eßer  * @param prev     An in/out parameter; the previous instruction.
72244d4804dSStefan Eßer  * @param ops_bgn  The size of the operator stack.
72344d4804dSStefan Eßer  * @param rparen   True if the last token was a right paren.
72444d4804dSStefan Eßer  * @param binlast  True if the last token was a binary operator.
72544d4804dSStefan Eßer  * @param nexprs   An in/out parameter; the number of unused expressions.
72644d4804dSStefan Eßer  */
72750696a6eSStefan Eßer static void bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn,
72850696a6eSStefan Eßer                            bool rparen, bool binlast, size_t *nexprs)
72950696a6eSStefan Eßer {
73050696a6eSStefan Eßer 	BcLexType type;
73150696a6eSStefan Eßer 
73250696a6eSStefan Eßer 	bc_lex_next(&p->l);
73350696a6eSStefan Eßer 
73444d4804dSStefan Eßer 	// Figure out if it's a minus or a negation.
73550696a6eSStefan Eßer 	type = BC_PARSE_LEAF(*prev, binlast, rparen) ? BC_LEX_OP_MINUS : BC_LEX_NEG;
73650696a6eSStefan Eßer 	*prev = BC_PARSE_TOKEN_INST(type);
73750696a6eSStefan Eßer 
73850696a6eSStefan Eßer 	// We can just push onto the op stack because this is the largest
73950696a6eSStefan Eßer 	// precedence operator that gets pushed. Inc/dec does not.
74050696a6eSStefan Eßer 	if (type != BC_LEX_OP_MINUS) bc_vec_push(&p->ops, &type);
74150696a6eSStefan Eßer 	else bc_parse_operator(p, type, ops_bgn, nexprs);
74250696a6eSStefan Eßer }
74350696a6eSStefan Eßer 
74444d4804dSStefan Eßer /**
74544d4804dSStefan Eßer  * Parses a string.
74644d4804dSStefan Eßer  * @param p     The parser.
74744d4804dSStefan Eßer  * @param inst  The instruction corresponding to how the string was found and
74844d4804dSStefan Eßer  *              how it should be printed.
74944d4804dSStefan Eßer  */
75044d4804dSStefan Eßer static void bc_parse_str(BcParse *p, BcInst inst) {
75150696a6eSStefan Eßer 	bc_parse_addString(p);
75250696a6eSStefan Eßer 	bc_parse_push(p, inst);
75350696a6eSStefan Eßer 	bc_lex_next(&p->l);
75450696a6eSStefan Eßer }
75550696a6eSStefan Eßer 
75644d4804dSStefan Eßer /**
75744d4804dSStefan Eßer  * Parses a print statement.
75844d4804dSStefan Eßer  * @param p  The parser.
75944d4804dSStefan Eßer  */
76044d4804dSStefan Eßer static void bc_parse_print(BcParse *p, BcLexType type) {
76150696a6eSStefan Eßer 
76250696a6eSStefan Eßer 	BcLexType t;
76350696a6eSStefan Eßer 	bool comma = false;
76444d4804dSStefan Eßer 	BcInst inst = type == BC_LEX_KW_STREAM ?
76544d4804dSStefan Eßer 	              BC_INST_PRINT_STREAM : BC_INST_PRINT_POP;
76650696a6eSStefan Eßer 
76750696a6eSStefan Eßer 	bc_lex_next(&p->l);
76850696a6eSStefan Eßer 
76950696a6eSStefan Eßer 	t = p->l.t;
77050696a6eSStefan Eßer 
77144d4804dSStefan Eßer 	// A print or stream statement has to have *something*.
77250696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_PRINT);
77350696a6eSStefan Eßer 
77450696a6eSStefan Eßer 	do {
77544d4804dSStefan Eßer 
77644d4804dSStefan Eßer 		// If the token is a string, then print it with escapes.
77744d4804dSStefan Eßer 		// BC_INST_PRINT_POP plays that role for bc.
77844d4804dSStefan Eßer 		if (t == BC_LEX_STR) bc_parse_str(p, inst);
77950696a6eSStefan Eßer 		else {
78044d4804dSStefan Eßer 			// We have an actual number; parse and add a print instruction.
78150696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_NEEDVAL, bc_parse_next_print);
78244d4804dSStefan Eßer 			bc_parse_push(p, inst);
78350696a6eSStefan Eßer 		}
78450696a6eSStefan Eßer 
78544d4804dSStefan Eßer 		// Is the next token a comma?
78650696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
78750696a6eSStefan Eßer 
78844d4804dSStefan Eßer 		// Get the next token if we have a comma.
78950696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
79050696a6eSStefan Eßer 		else {
79144d4804dSStefan Eßer 
79244d4804dSStefan Eßer 			// If we don't have a comma, the statement needs to end.
79350696a6eSStefan Eßer 			if (!bc_parse_isDelimiter(p))
79450696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
79550696a6eSStefan Eßer 			else break;
79650696a6eSStefan Eßer 		}
79750696a6eSStefan Eßer 
79850696a6eSStefan Eßer 		t = p->l.t;
79944d4804dSStefan Eßer 
80050696a6eSStefan Eßer 	} while (true);
80150696a6eSStefan Eßer 
80244d4804dSStefan Eßer 	// If we have a comma but no token, that's bad.
80350696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
80450696a6eSStefan Eßer }
80550696a6eSStefan Eßer 
80644d4804dSStefan Eßer /**
80744d4804dSStefan Eßer  * Parses a return statement.
80844d4804dSStefan Eßer  * @param p  The parser.
80944d4804dSStefan Eßer  */
81050696a6eSStefan Eßer static void bc_parse_return(BcParse *p) {
81150696a6eSStefan Eßer 
81250696a6eSStefan Eßer 	BcLexType t;
81350696a6eSStefan Eßer 	bool paren;
81450696a6eSStefan Eßer 	uchar inst = BC_INST_RET0;
81550696a6eSStefan Eßer 
81644d4804dSStefan Eßer 	// If we are not in a function, that's an error.
81750696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_FUNC(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
81850696a6eSStefan Eßer 
81944d4804dSStefan Eßer 	// If we are in a void function, make sure to return void.
82050696a6eSStefan Eßer 	if (p->func->voidfn) inst = BC_INST_RET_VOID;
82150696a6eSStefan Eßer 
82250696a6eSStefan Eßer 	bc_lex_next(&p->l);
82350696a6eSStefan Eßer 
82450696a6eSStefan Eßer 	t = p->l.t;
82544d4804dSStefan Eßer 	paren = (t == BC_LEX_LPAREN);
82650696a6eSStefan Eßer 
82744d4804dSStefan Eßer 	// An empty return statement just needs to push the selected instruction.
82850696a6eSStefan Eßer 	if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst);
82950696a6eSStefan Eßer 	else {
83050696a6eSStefan Eßer 
83150696a6eSStefan Eßer 		BcParseStatus s;
83250696a6eSStefan Eßer 
83344d4804dSStefan Eßer 		// Need to parse the expression whose value will be returned.
83450696a6eSStefan Eßer 		s = bc_parse_expr_err(p, BC_PARSE_NEEDVAL, bc_parse_next_expr);
83550696a6eSStefan Eßer 
83644d4804dSStefan Eßer 		// If the expression was empty, just push the selected instruction.
83750696a6eSStefan Eßer 		if (s == BC_PARSE_STATUS_EMPTY_EXPR) {
83850696a6eSStefan Eßer 			bc_parse_push(p, inst);
83950696a6eSStefan Eßer 			bc_lex_next(&p->l);
84050696a6eSStefan Eßer 		}
84150696a6eSStefan Eßer 
84244d4804dSStefan Eßer 		// POSIX requires parentheses.
84350696a6eSStefan Eßer 		if (!paren || p->l.last != BC_LEX_RPAREN) {
84450696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_RET);
84550696a6eSStefan Eßer 		}
84644d4804dSStefan Eßer 
84744d4804dSStefan Eßer 		// Void functions require an empty expression.
84844d4804dSStefan Eßer 		if (BC_ERR(p->func->voidfn)) {
84944d4804dSStefan Eßer 			if (s != BC_PARSE_STATUS_EMPTY_EXPR)
85050696a6eSStefan Eßer 				bc_parse_verr(p, BC_ERR_PARSE_RET_VOID, p->func->name);
85144d4804dSStefan Eßer 		}
85244d4804dSStefan Eßer 		// If we got here, we want to be sure to end the function with a real
85344d4804dSStefan Eßer 		// return instruction, just in case.
85444d4804dSStefan Eßer 		else bc_parse_push(p, BC_INST_RET);
85550696a6eSStefan Eßer 	}
85650696a6eSStefan Eßer }
85750696a6eSStefan Eßer 
85844d4804dSStefan Eßer /**
85944d4804dSStefan Eßer  * Clears flags that indicate the end of an if statement and its block and sets
86044d4804dSStefan Eßer  * the jump location.
86144d4804dSStefan Eßer  * @param p  The parser.
86244d4804dSStefan Eßer  */
86350696a6eSStefan Eßer static void bc_parse_noElse(BcParse *p) {
86450696a6eSStefan Eßer 	uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
86550696a6eSStefan Eßer 	*flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END));
86650696a6eSStefan Eßer 	bc_parse_setLabel(p);
86750696a6eSStefan Eßer }
86850696a6eSStefan Eßer 
86944d4804dSStefan Eßer /**
87044d4804dSStefan Eßer  * Ends (finishes parsing) the body of a control statement or a function.
87144d4804dSStefan Eßer  * @param p      The parser.
87244d4804dSStefan Eßer  * @param brace  True if the body was ended by a brace, false otherwise.
87344d4804dSStefan Eßer  */
87450696a6eSStefan Eßer static void bc_parse_endBody(BcParse *p, bool brace) {
87550696a6eSStefan Eßer 
87650696a6eSStefan Eßer 	bool has_brace, new_else = false;
87750696a6eSStefan Eßer 
87844d4804dSStefan Eßer 	// We cannot be ending a body if there are no bodies to end.
87950696a6eSStefan Eßer 	if (BC_ERR(p->flags.len <= 1)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
88050696a6eSStefan Eßer 
88150696a6eSStefan Eßer 	if (brace) {
88250696a6eSStefan Eßer 
88344d4804dSStefan Eßer 		// The brace was already gotten; make sure that the caller did not lie.
88444d4804dSStefan Eßer 		// We check for the requirement of braces later.
88550696a6eSStefan Eßer 		assert(p->l.t == BC_LEX_RBRACE);
88650696a6eSStefan Eßer 
88750696a6eSStefan Eßer 		bc_lex_next(&p->l);
88844d4804dSStefan Eßer 
88944d4804dSStefan Eßer 		// If the next token is not a delimiter, that is a problem.
89050696a6eSStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p)))
89150696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
89250696a6eSStefan Eßer 	}
89350696a6eSStefan Eßer 
89444d4804dSStefan Eßer 	// Do we have a brace flag?
89550696a6eSStefan Eßer 	has_brace = (BC_PARSE_BRACE(p) != 0);
89650696a6eSStefan Eßer 
89750696a6eSStefan Eßer 	do {
89850696a6eSStefan Eßer 		size_t len = p->flags.len;
89950696a6eSStefan Eßer 		bool loop;
90050696a6eSStefan Eßer 
90144d4804dSStefan Eßer 		// If we have a brace flag but not a brace, that's a problem.
90250696a6eSStefan Eßer 		if (has_brace && !brace) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
90350696a6eSStefan Eßer 
90444d4804dSStefan Eßer 		// Are we inside a loop?
90550696a6eSStefan Eßer 		loop = (BC_PARSE_LOOP_INNER(p) != 0);
90650696a6eSStefan Eßer 
90744d4804dSStefan Eßer 		// If we are ending a loop or an else...
90850696a6eSStefan Eßer 		if (loop || BC_PARSE_ELSE(p)) {
90950696a6eSStefan Eßer 
91044d4804dSStefan Eßer 			// Loops have condition labels that we have to take care of as well.
91150696a6eSStefan Eßer 			if (loop) {
91250696a6eSStefan Eßer 
91350696a6eSStefan Eßer 				size_t *label = bc_vec_top(&p->conds);
91450696a6eSStefan Eßer 
91550696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_JUMP);
91650696a6eSStefan Eßer 				bc_parse_pushIndex(p, *label);
91750696a6eSStefan Eßer 
91850696a6eSStefan Eßer 				bc_vec_pop(&p->conds);
91950696a6eSStefan Eßer 			}
92050696a6eSStefan Eßer 
92150696a6eSStefan Eßer 			bc_parse_setLabel(p);
92250696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
92350696a6eSStefan Eßer 		}
92444d4804dSStefan Eßer 		// If we are ending a function...
92550696a6eSStefan Eßer 		else if (BC_PARSE_FUNC_INNER(p)) {
92650696a6eSStefan Eßer 			BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0);
92750696a6eSStefan Eßer 			bc_parse_push(p, inst);
92850696a6eSStefan Eßer 			bc_parse_updateFunc(p, BC_PROG_MAIN);
92950696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
93050696a6eSStefan Eßer 		}
93144d4804dSStefan Eßer 		// If we have a brace flag and not an if statement, we can pop the top
93244d4804dSStefan Eßer 		// of the flags stack because they have been taken care of above.
93344d4804dSStefan Eßer 		else if (has_brace && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags);
93450696a6eSStefan Eßer 
93550696a6eSStefan Eßer 		// This needs to be last to parse nested if's properly.
93650696a6eSStefan Eßer 		if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) {
93750696a6eSStefan Eßer 
93844d4804dSStefan Eßer 			// Eat newlines.
93950696a6eSStefan Eßer 			while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
94050696a6eSStefan Eßer 
94144d4804dSStefan Eßer 			// *Now* we can pop the flags.
94250696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
94350696a6eSStefan Eßer 
94444d4804dSStefan Eßer 			// If we are allowed non-POSIX stuff...
94550696a6eSStefan Eßer 			if (!BC_S) {
94650696a6eSStefan Eßer 
94744d4804dSStefan Eßer 				// Have we found yet another dangling else?
94850696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END;
94950696a6eSStefan Eßer 				new_else = (p->l.t == BC_LEX_KW_ELSE);
95050696a6eSStefan Eßer 
95144d4804dSStefan Eßer 				// Parse the else or end the if statement body.
95250696a6eSStefan Eßer 				if (new_else) bc_parse_else(p);
95350696a6eSStefan Eßer 				else if (!has_brace && (!BC_PARSE_IF_END(p) || brace))
95450696a6eSStefan Eßer 					bc_parse_noElse(p);
95550696a6eSStefan Eßer 			}
95644d4804dSStefan Eßer 			// POSIX requires us to do the bare minimum only.
95750696a6eSStefan Eßer 			else bc_parse_noElse(p);
95850696a6eSStefan Eßer 		}
95950696a6eSStefan Eßer 
96044d4804dSStefan Eßer 		// If these are both true, we have "used" the braces that we found.
96150696a6eSStefan Eßer 		if (brace && has_brace) brace = false;
96250696a6eSStefan Eßer 
96344d4804dSStefan Eßer 	// This condition was perhaps the hardest single part of the parser. If the
96444d4804dSStefan Eßer 	// flags stack does not have enough, we should stop. If we have a new else
96544d4804dSStefan Eßer 	// statement, we should stop. If we do have the end of an if statement and
96644d4804dSStefan Eßer 	// we have eaten the brace, we should stop. If we do have a brace flag, we
96744d4804dSStefan Eßer 	// should stop.
96850696a6eSStefan Eßer 	} while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) &&
96950696a6eSStefan Eßer 	         !(has_brace = (BC_PARSE_BRACE(p) != 0)));
97050696a6eSStefan Eßer 
97144d4804dSStefan Eßer 	// If we have a brace, yet no body for it, that's a problem.
97250696a6eSStefan Eßer 	if (BC_ERR(p->flags.len == 1 && brace))
97350696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
97450696a6eSStefan Eßer 	else if (brace && BC_PARSE_BRACE(p)) {
97550696a6eSStefan Eßer 
97644d4804dSStefan Eßer 		// If we make it here, we have a brace and a flag for it.
97750696a6eSStefan Eßer 		uint16_t flags = BC_PARSE_TOP_FLAG(p);
97850696a6eSStefan Eßer 
97944d4804dSStefan Eßer 		// This condition ensure that the *last* body is correctly finished by
98044d4804dSStefan Eßer 		// popping its flags.
98150696a6eSStefan Eßer 		if (!(flags & (BC_PARSE_FLAG_FUNC_INNER | BC_PARSE_FLAG_LOOP_INNER)) &&
98250696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF | BC_PARSE_FLAG_ELSE)) &&
98350696a6eSStefan Eßer 		    !(flags & (BC_PARSE_FLAG_IF_END)))
98450696a6eSStefan Eßer 		{
98550696a6eSStefan Eßer 			bc_vec_pop(&p->flags);
98650696a6eSStefan Eßer 		}
98750696a6eSStefan Eßer 	}
98850696a6eSStefan Eßer }
98950696a6eSStefan Eßer 
99044d4804dSStefan Eßer /**
99144d4804dSStefan Eßer  * Starts the body of a control statement or function.
99244d4804dSStefan Eßer  * @param p      The parser.
99344d4804dSStefan Eßer  * @param flags  The current flags (will be edited).
99444d4804dSStefan Eßer  */
99550696a6eSStefan Eßer static void bc_parse_startBody(BcParse *p, uint16_t flags) {
99650696a6eSStefan Eßer 	assert(flags);
99750696a6eSStefan Eßer 	flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP));
99850696a6eSStefan Eßer 	flags |= BC_PARSE_FLAG_BODY;
99950696a6eSStefan Eßer 	bc_vec_push(&p->flags, &flags);
100050696a6eSStefan Eßer }
100150696a6eSStefan Eßer 
1002*a30efc5cSStefan Eßer void bc_parse_endif(BcParse *p) {
1003*a30efc5cSStefan Eßer 
1004*a30efc5cSStefan Eßer 	size_t i;
1005*a30efc5cSStefan Eßer 	bool good;
1006*a30efc5cSStefan Eßer 
1007*a30efc5cSStefan Eßer 	// Not a problem if this is true.
1008*a30efc5cSStefan Eßer 	if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return;
1009*a30efc5cSStefan Eßer 
1010*a30efc5cSStefan Eßer 	good = true;
1011*a30efc5cSStefan Eßer 
1012*a30efc5cSStefan Eßer 	// Find an instance of a body that needs closing, i.e., a statement that did
1013*a30efc5cSStefan Eßer 	// not have a right brace when it should have.
1014*a30efc5cSStefan Eßer 	for (i = 0; good && i < p->flags.len; ++i) {
1015*a30efc5cSStefan Eßer 		uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i));
1016*a30efc5cSStefan Eßer 		good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE);
1017*a30efc5cSStefan Eßer 	}
1018*a30efc5cSStefan Eßer 
1019*a30efc5cSStefan Eßer 	// If we did not find such an instance...
1020*a30efc5cSStefan Eßer 	if (good) {
1021*a30efc5cSStefan Eßer 
1022*a30efc5cSStefan Eßer 		// We set this to restore it later. We don't want the parser thinking
1023*a30efc5cSStefan Eßer 		// that we are on stdin for this one because it will want more.
1024*a30efc5cSStefan Eßer 		bool is_stdin = vm.is_stdin;
1025*a30efc5cSStefan Eßer 
1026*a30efc5cSStefan Eßer 		vm.is_stdin = false;
1027*a30efc5cSStefan Eßer 
1028*a30efc5cSStefan Eßer 		// End all of the if statements and loops.
1029*a30efc5cSStefan Eßer 		while (p->flags.len > 1 || BC_PARSE_IF_END(p)) {
1030*a30efc5cSStefan Eßer 			if (BC_PARSE_IF_END(p)) bc_parse_noElse(p);
1031*a30efc5cSStefan Eßer 			if (p->flags.len > 1) bc_parse_endBody(p, false);
1032*a30efc5cSStefan Eßer 		}
1033*a30efc5cSStefan Eßer 
1034*a30efc5cSStefan Eßer 		vm.is_stdin = is_stdin;
1035*a30efc5cSStefan Eßer 	}
1036*a30efc5cSStefan Eßer 	// If we reach here, a block was not properly closed, and we should error.
1037*a30efc5cSStefan Eßer 	else bc_parse_err(&vm.prs, BC_ERR_PARSE_BLOCK);
1038*a30efc5cSStefan Eßer }
1039*a30efc5cSStefan Eßer 
104044d4804dSStefan Eßer /**
104144d4804dSStefan Eßer  * Parses an if statement.
104244d4804dSStefan Eßer  * @param p  The parser.
104344d4804dSStefan Eßer  */
104450696a6eSStefan Eßer static void bc_parse_if(BcParse *p) {
104550696a6eSStefan Eßer 
104644d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
104750696a6eSStefan Eßer 	size_t idx;
104850696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
104950696a6eSStefan Eßer 
105044d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
105150696a6eSStefan Eßer 	bc_lex_next(&p->l);
105250696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
105350696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
105450696a6eSStefan Eßer 
105544d4804dSStefan Eßer 	// Parse the condition.
105650696a6eSStefan Eßer 	bc_lex_next(&p->l);
105750696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
105844d4804dSStefan Eßer 
105944d4804dSStefan Eßer 	// Must have a right paren.
106050696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
106150696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
106250696a6eSStefan Eßer 
106350696a6eSStefan Eßer 	bc_lex_next(&p->l);
106444d4804dSStefan Eßer 
106544d4804dSStefan Eßer 	// Insert the conditional jump instruction.
106650696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
106750696a6eSStefan Eßer 
106850696a6eSStefan Eßer 	idx = p->func->labels.len;
106950696a6eSStefan Eßer 
107044d4804dSStefan Eßer 	// Push the index for the instruction and create an exit label for an else
107144d4804dSStefan Eßer 	// statement.
107250696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
107350696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
107444d4804dSStefan Eßer 
107550696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_IF);
107650696a6eSStefan Eßer }
107750696a6eSStefan Eßer 
107844d4804dSStefan Eßer /**
107944d4804dSStefan Eßer  * Parses an else statement.
108044d4804dSStefan Eßer  * @param p  The parser.
108144d4804dSStefan Eßer  */
108250696a6eSStefan Eßer static void bc_parse_else(BcParse *p) {
108350696a6eSStefan Eßer 
108450696a6eSStefan Eßer 	size_t idx = p->func->labels.len;
108550696a6eSStefan Eßer 
108644d4804dSStefan Eßer 	// We must be at the end of an if statement.
108750696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_IF_END(p)))
108850696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
108950696a6eSStefan Eßer 
109044d4804dSStefan Eßer 	// Push an unconditional jump to make bc jump over the else statement if it
109144d4804dSStefan Eßer 	// executed the original if statement.
109250696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
109350696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
109450696a6eSStefan Eßer 
109544d4804dSStefan Eßer 	// Clear the else stuff. Yes, that function is misnamed for its use here,
109644d4804dSStefan Eßer 	// but deal with it.
109750696a6eSStefan Eßer 	bc_parse_noElse(p);
109850696a6eSStefan Eßer 
109944d4804dSStefan Eßer 	// Create the exit label and parse the body.
110050696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, false);
110150696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_ELSE);
110250696a6eSStefan Eßer 
110350696a6eSStefan Eßer 	bc_lex_next(&p->l);
110450696a6eSStefan Eßer }
110550696a6eSStefan Eßer 
110644d4804dSStefan Eßer /**
110744d4804dSStefan Eßer  * Parse a while loop.
110844d4804dSStefan Eßer  * @param p  The parser.
110944d4804dSStefan Eßer  */
111050696a6eSStefan Eßer static void bc_parse_while(BcParse *p) {
111150696a6eSStefan Eßer 
111244d4804dSStefan Eßer 	// We are allowed relational operators, and we must have a value.
111350696a6eSStefan Eßer 	size_t idx;
111450696a6eSStefan Eßer 	uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
111550696a6eSStefan Eßer 
111644d4804dSStefan Eßer 	// Get the left paren and barf if necessary.
111750696a6eSStefan Eßer 	bc_lex_next(&p->l);
111850696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
111950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
112050696a6eSStefan Eßer 	bc_lex_next(&p->l);
112150696a6eSStefan Eßer 
112244d4804dSStefan Eßer 	// Create the labels. Loops need both.
112350696a6eSStefan Eßer 	bc_parse_createCondLabel(p, p->func->labels.len);
112450696a6eSStefan Eßer 	idx = p->func->labels.len;
112550696a6eSStefan Eßer 	bc_parse_createExitLabel(p, idx, true);
112650696a6eSStefan Eßer 
112744d4804dSStefan Eßer 	// Parse the actual condition and barf on non-right paren.
112850696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_rel);
112950696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
113050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
113150696a6eSStefan Eßer 	bc_lex_next(&p->l);
113250696a6eSStefan Eßer 
113344d4804dSStefan Eßer 	// Now we can push the conditional jump and start the body.
113450696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
113550696a6eSStefan Eßer 	bc_parse_pushIndex(p, idx);
113650696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
113750696a6eSStefan Eßer }
113850696a6eSStefan Eßer 
113944d4804dSStefan Eßer /**
114044d4804dSStefan Eßer  * Parse a for loop.
114144d4804dSStefan Eßer  * @param p  The parser.
114244d4804dSStefan Eßer  */
114350696a6eSStefan Eßer static void bc_parse_for(BcParse *p) {
114450696a6eSStefan Eßer 
114550696a6eSStefan Eßer 	size_t cond_idx, exit_idx, body_idx, update_idx;
114650696a6eSStefan Eßer 
114744d4804dSStefan Eßer 	// Barf on the missing left paren.
114850696a6eSStefan Eßer 	bc_lex_next(&p->l);
114950696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
115050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
115150696a6eSStefan Eßer 	bc_lex_next(&p->l);
115250696a6eSStefan Eßer 
115344d4804dSStefan Eßer 	// The first statement can be empty, but if it is, check for error in POSIX
115444d4804dSStefan Eßer 	// mode. Otherwise, parse it.
115550696a6eSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON)
115650696a6eSStefan Eßer 		bc_parse_expr_status(p, 0, bc_parse_next_for);
115750696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
115850696a6eSStefan Eßer 
115944d4804dSStefan Eßer 	// Must have a semicolon.
116044d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
116150696a6eSStefan Eßer 	bc_lex_next(&p->l);
116250696a6eSStefan Eßer 
116344d4804dSStefan Eßer 	// These are indices for labels. There are so many of them because the end
116444d4804dSStefan Eßer 	// of the loop must unconditionally jump to the update code. Then the update
116544d4804dSStefan Eßer 	// code must unconditionally jump to the condition code. Then the condition
116644d4804dSStefan Eßer 	// code must *conditionally* jump to the exit.
116750696a6eSStefan Eßer 	cond_idx = p->func->labels.len;
116850696a6eSStefan Eßer 	update_idx = cond_idx + 1;
116950696a6eSStefan Eßer 	body_idx = update_idx + 1;
117050696a6eSStefan Eßer 	exit_idx = body_idx + 1;
117150696a6eSStefan Eßer 
117244d4804dSStefan Eßer 	// This creates the condition label.
117350696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
117450696a6eSStefan Eßer 
117544d4804dSStefan Eßer 	// Parse an expression if it exists.
117650696a6eSStefan Eßer 	if (p->l.t != BC_LEX_SCOLON) {
117750696a6eSStefan Eßer 		uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL);
117850696a6eSStefan Eßer 		bc_parse_expr_status(p, flags, bc_parse_next_for);
117950696a6eSStefan Eßer 	}
118050696a6eSStefan Eßer 	else {
118150696a6eSStefan Eßer 
118244d4804dSStefan Eßer 		// Set this for the next call to bc_parse_number because an empty
118344d4804dSStefan Eßer 		// condition means that it is an infinite loop, so the condition must be
118444d4804dSStefan Eßer 		// non-zero. This is safe to set because the current token is a
118544d4804dSStefan Eßer 		// semicolon, which has no string requirement.
118650696a6eSStefan Eßer 		bc_vec_string(&p->l.str, sizeof(bc_parse_one) - 1, bc_parse_one);
118750696a6eSStefan Eßer 		bc_parse_number(p);
118850696a6eSStefan Eßer 
118944d4804dSStefan Eßer 		// An empty condition makes POSIX mad.
119050696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_FOR);
119150696a6eSStefan Eßer 	}
119250696a6eSStefan Eßer 
119344d4804dSStefan Eßer 	// Must have a semicolon.
119450696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_SCOLON))
119550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
119650696a6eSStefan Eßer 	bc_lex_next(&p->l);
119750696a6eSStefan Eßer 
119844d4804dSStefan Eßer 	// Now we can set up the conditional jump to the exit and an unconditional
119944d4804dSStefan Eßer 	// jump to the body right after. The unconditional jump to the body is
120044d4804dSStefan Eßer 	// because there is update code coming right after the condition, so we need
120144d4804dSStefan Eßer 	// to skip it to get to the body.
120250696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP_ZERO);
120350696a6eSStefan Eßer 	bc_parse_pushIndex(p, exit_idx);
120450696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
120550696a6eSStefan Eßer 	bc_parse_pushIndex(p, body_idx);
120650696a6eSStefan Eßer 
120744d4804dSStefan Eßer 	// Now create the label for the update code.
120850696a6eSStefan Eßer 	bc_parse_createCondLabel(p, update_idx);
120950696a6eSStefan Eßer 
121044d4804dSStefan Eßer 	// Parse if not empty, and if it is, let POSIX yell if necessary.
121150696a6eSStefan Eßer 	if (p->l.t != BC_LEX_RPAREN)
121250696a6eSStefan Eßer 		bc_parse_expr_status(p, 0, bc_parse_next_rel);
121350696a6eSStefan Eßer 	else bc_parse_err(p, BC_ERR_POSIX_FOR);
121450696a6eSStefan Eßer 
121544d4804dSStefan Eßer 	// Must have a right paren.
121650696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_RPAREN))
121750696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
121844d4804dSStefan Eßer 
121944d4804dSStefan Eßer 	// Set up a jump to the condition right after the update code.
122050696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
122150696a6eSStefan Eßer 	bc_parse_pushIndex(p, cond_idx);
122250696a6eSStefan Eßer 	bc_parse_createLabel(p, p->func->code.len);
122350696a6eSStefan Eßer 
122444d4804dSStefan Eßer 	// Create an exit label for the body and start the body.
122550696a6eSStefan Eßer 	bc_parse_createExitLabel(p, exit_idx, true);
122650696a6eSStefan Eßer 	bc_lex_next(&p->l);
122750696a6eSStefan Eßer 	bc_parse_startBody(p, BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER);
122850696a6eSStefan Eßer }
122950696a6eSStefan Eßer 
123044d4804dSStefan Eßer /**
123144d4804dSStefan Eßer  * Parse a statement or token that indicates a loop exit. This includes an
123244d4804dSStefan Eßer  * actual loop exit, the break keyword, or the continue keyword.
123344d4804dSStefan Eßer  * @param p     The parser.
123444d4804dSStefan Eßer  * @param type  The type of exit.
123544d4804dSStefan Eßer  */
123650696a6eSStefan Eßer static void bc_parse_loopExit(BcParse *p, BcLexType type) {
123750696a6eSStefan Eßer 
123850696a6eSStefan Eßer 	size_t i;
123950696a6eSStefan Eßer 	BcInstPtr *ip;
124050696a6eSStefan Eßer 
124144d4804dSStefan Eßer 	// Must have a loop. If we don't, that's an error.
124250696a6eSStefan Eßer 	if (BC_ERR(!BC_PARSE_LOOP(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
124350696a6eSStefan Eßer 
124444d4804dSStefan Eßer 	// If we have a break statement...
124550696a6eSStefan Eßer 	if (type == BC_LEX_KW_BREAK) {
124650696a6eSStefan Eßer 
124744d4804dSStefan Eßer 		// If there are no exits, something went wrong somewhere.
124850696a6eSStefan Eßer 		if (BC_ERR(!p->exits.len)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
124950696a6eSStefan Eßer 
125044d4804dSStefan Eßer 		// Get the exit.
125150696a6eSStefan Eßer 		i = p->exits.len - 1;
125250696a6eSStefan Eßer 		ip = bc_vec_item(&p->exits, i);
125350696a6eSStefan Eßer 
125444d4804dSStefan Eßer 		// The condition !ip->func is true if the exit is not for a loop, so we
125544d4804dSStefan Eßer 		// need to find the first actual loop exit.
125650696a6eSStefan Eßer 		while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--);
125744d4804dSStefan Eßer 
125844d4804dSStefan Eßer 		// Make sure everything is hunky dory.
125950696a6eSStefan Eßer 		assert(ip != NULL && (i < p->exits.len || ip->func));
126044d4804dSStefan Eßer 
126144d4804dSStefan Eßer 		// Set the index for the exit.
126250696a6eSStefan Eßer 		i = ip->idx;
126350696a6eSStefan Eßer 	}
126444d4804dSStefan Eßer 	// If we have a continue statement or just the loop end, jump to the
126544d4804dSStefan Eßer 	// condition (or update for a foor loop).
126650696a6eSStefan Eßer 	else i = *((size_t*) bc_vec_top(&p->conds));
126750696a6eSStefan Eßer 
126844d4804dSStefan Eßer 	// Add the unconditional jump.
126950696a6eSStefan Eßer 	bc_parse_push(p, BC_INST_JUMP);
127050696a6eSStefan Eßer 	bc_parse_pushIndex(p, i);
127150696a6eSStefan Eßer 
127250696a6eSStefan Eßer 	bc_lex_next(&p->l);
127350696a6eSStefan Eßer }
127450696a6eSStefan Eßer 
127544d4804dSStefan Eßer /**
127644d4804dSStefan Eßer  * Parse a function (header).
127744d4804dSStefan Eßer  * @param p  The parser.
127844d4804dSStefan Eßer  */
127950696a6eSStefan Eßer static void bc_parse_func(BcParse *p) {
128050696a6eSStefan Eßer 
128150696a6eSStefan Eßer 	bool comma = false, voidfn;
128250696a6eSStefan Eßer 	uint16_t flags;
128350696a6eSStefan Eßer 	size_t idx;
128450696a6eSStefan Eßer 
128550696a6eSStefan Eßer 	bc_lex_next(&p->l);
128650696a6eSStefan Eßer 
128744d4804dSStefan Eßer 	// Must have a name.
128844d4804dSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
128950696a6eSStefan Eßer 
129044d4804dSStefan Eßer 	// If the name is "void", and POSIX is not on, mark as void.
129150696a6eSStefan Eßer 	voidfn = (!BC_IS_POSIX && p->l.t == BC_LEX_NAME &&
129250696a6eSStefan Eßer 	          !strcmp(p->l.str.v, "void"));
129350696a6eSStefan Eßer 
129444d4804dSStefan Eßer 	// We can safely do this because the expected token should not overwrite the
129544d4804dSStefan Eßer 	// function name.
129650696a6eSStefan Eßer 	bc_lex_next(&p->l);
129750696a6eSStefan Eßer 
129844d4804dSStefan Eßer 	// If we *don't* have another name, then void is the name of the function.
129950696a6eSStefan Eßer 	voidfn = (voidfn && p->l.t == BC_LEX_NAME);
130050696a6eSStefan Eßer 
130144d4804dSStefan Eßer 	// With a void function, allow POSIX to complain and get a new token.
130250696a6eSStefan Eßer 	if (voidfn) {
130344d4804dSStefan Eßer 
130450696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_VOID);
130544d4804dSStefan Eßer 
130644d4804dSStefan Eßer 		// We can safely do this because the expected token should not overwrite
130744d4804dSStefan Eßer 		// the function name.
130850696a6eSStefan Eßer 		bc_lex_next(&p->l);
130950696a6eSStefan Eßer 	}
131050696a6eSStefan Eßer 
131144d4804dSStefan Eßer 	// Must have a left paren.
131250696a6eSStefan Eßer 	if (BC_ERR(p->l.t != BC_LEX_LPAREN))
131350696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_FUNC);
131450696a6eSStefan Eßer 
131544d4804dSStefan Eßer 	// Make sure the functions map and vector are synchronized.
131650696a6eSStefan Eßer 	assert(p->prog->fns.len == p->prog->fn_map.len);
131750696a6eSStefan Eßer 
131844d4804dSStefan Eßer 	// Must lock signals because vectors are changed, and the vector functions
131944d4804dSStefan Eßer 	// expect signals to be locked.
132050696a6eSStefan Eßer 	BC_SIG_LOCK;
132150696a6eSStefan Eßer 
132244d4804dSStefan Eßer 	// Insert the function by name into the map and vector.
132350696a6eSStefan Eßer 	idx = bc_program_insertFunc(p->prog, p->l.str.v);
132450696a6eSStefan Eßer 
132550696a6eSStefan Eßer 	BC_SIG_UNLOCK;
132650696a6eSStefan Eßer 
132744d4804dSStefan Eßer 	// Make sure the insert worked.
132850696a6eSStefan Eßer 	assert(idx);
132944d4804dSStefan Eßer 
133044d4804dSStefan Eßer 	// Update the function pointer and stuff in the parser and set its void.
133150696a6eSStefan Eßer 	bc_parse_updateFunc(p, idx);
133250696a6eSStefan Eßer 	p->func->voidfn = voidfn;
133350696a6eSStefan Eßer 
133450696a6eSStefan Eßer 	bc_lex_next(&p->l);
133550696a6eSStefan Eßer 
133644d4804dSStefan Eßer 	// While we do not have a right paren, we are still parsing arguments.
133750696a6eSStefan Eßer 	while (p->l.t != BC_LEX_RPAREN) {
133850696a6eSStefan Eßer 
133950696a6eSStefan Eßer 		BcType t = BC_TYPE_VAR;
134050696a6eSStefan Eßer 
134144d4804dSStefan Eßer 		// If we have an asterisk, we are parsing a reference argument.
134250696a6eSStefan Eßer 		if (p->l.t == BC_LEX_OP_MULTIPLY) {
134344d4804dSStefan Eßer 
134450696a6eSStefan Eßer 			t = BC_TYPE_REF;
134550696a6eSStefan Eßer 			bc_lex_next(&p->l);
134644d4804dSStefan Eßer 
134744d4804dSStefan Eßer 			// Let POSIX complain if necessary.
134850696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_POSIX_REF);
134950696a6eSStefan Eßer 		}
135050696a6eSStefan Eßer 
135144d4804dSStefan Eßer 		// If we don't have a name, the argument will not have a name. Barf.
135250696a6eSStefan Eßer 		if (BC_ERR(p->l.t != BC_LEX_NAME))
135350696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_FUNC);
135450696a6eSStefan Eßer 
135544d4804dSStefan Eßer 		// Increment the number of parameters.
135650696a6eSStefan Eßer 		p->func->nparams += 1;
135750696a6eSStefan Eßer 
135844d4804dSStefan Eßer 		// Copy the string in the lexer so that we can use the lexer again.
135950696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len, p->l.str.v);
136050696a6eSStefan Eßer 
136150696a6eSStefan Eßer 		bc_lex_next(&p->l);
136250696a6eSStefan Eßer 
136344d4804dSStefan Eßer 		// We are parsing an array parameter if this is true.
136450696a6eSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET) {
136550696a6eSStefan Eßer 
136644d4804dSStefan Eßer 			// Set the array type, unless we are already parsing a reference.
136750696a6eSStefan Eßer 			if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY;
136850696a6eSStefan Eßer 
136950696a6eSStefan Eßer 			bc_lex_next(&p->l);
137050696a6eSStefan Eßer 
137144d4804dSStefan Eßer 			// The brackets *must* be empty.
137250696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
137350696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
137450696a6eSStefan Eßer 
137550696a6eSStefan Eßer 			bc_lex_next(&p->l);
137650696a6eSStefan Eßer 		}
137744d4804dSStefan Eßer 		// If we did *not* get a bracket, but we are expecting a reference, we
137844d4804dSStefan Eßer 		// have a problem.
137950696a6eSStefan Eßer 		else if (BC_ERR(t == BC_TYPE_REF))
138050696a6eSStefan Eßer 			bc_parse_verr(p, BC_ERR_PARSE_REF_VAR, p->buf.v);
138150696a6eSStefan Eßer 
138244d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
138350696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
138444d4804dSStefan Eßer 		if (comma) bc_lex_next(&p->l);
138550696a6eSStefan Eßer 
138644d4804dSStefan Eßer 		// Insert the parameter into the function.
138750696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
138850696a6eSStefan Eßer 	}
138950696a6eSStefan Eßer 
139044d4804dSStefan Eßer 	// If we have a comma, but no parameter, barf.
139150696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
139250696a6eSStefan Eßer 
139344d4804dSStefan Eßer 	// Start the body.
139450696a6eSStefan Eßer 	flags = BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_FUNC_INNER;
139550696a6eSStefan Eßer 	bc_parse_startBody(p, flags);
139650696a6eSStefan Eßer 
139750696a6eSStefan Eßer 	bc_lex_next(&p->l);
139850696a6eSStefan Eßer 
139944d4804dSStefan Eßer 	// POSIX requires that a brace be on the same line as the function header.
140044d4804dSStefan Eßer 	// If we don't have a brace, let POSIX throw an error.
140150696a6eSStefan Eßer 	if (p->l.t != BC_LEX_LBRACE) bc_parse_err(p, BC_ERR_POSIX_BRACE);
140250696a6eSStefan Eßer }
140350696a6eSStefan Eßer 
140444d4804dSStefan Eßer /**
140544d4804dSStefan Eßer  * Parse an auto list.
140644d4804dSStefan Eßer  * @param p  The parser.
140744d4804dSStefan Eßer  */
140850696a6eSStefan Eßer static void bc_parse_auto(BcParse *p) {
140950696a6eSStefan Eßer 
141050696a6eSStefan Eßer 	bool comma, one;
141150696a6eSStefan Eßer 
141244d4804dSStefan Eßer 	// Error if the auto keyword appeared in the wrong place.
141350696a6eSStefan Eßer 	if (BC_ERR(!p->auto_part)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
141450696a6eSStefan Eßer 	bc_lex_next(&p->l);
141550696a6eSStefan Eßer 
141650696a6eSStefan Eßer 	p->auto_part = comma = false;
141750696a6eSStefan Eßer 
141844d4804dSStefan Eßer 	// We need at least one variable or array.
141944d4804dSStefan Eßer 	one = (p->l.t == BC_LEX_NAME);
142044d4804dSStefan Eßer 
142144d4804dSStefan Eßer 	// While we have a variable or array.
142250696a6eSStefan Eßer 	while (p->l.t == BC_LEX_NAME) {
142350696a6eSStefan Eßer 
142450696a6eSStefan Eßer 		BcType t;
142550696a6eSStefan Eßer 
142644d4804dSStefan Eßer 		// Copy the name from the lexer, so we can use it again.
142750696a6eSStefan Eßer 		bc_vec_string(&p->buf, p->l.str.len - 1, p->l.str.v);
142850696a6eSStefan Eßer 
142950696a6eSStefan Eßer 		bc_lex_next(&p->l);
143050696a6eSStefan Eßer 
143144d4804dSStefan Eßer 		// If we are parsing an array...
143250696a6eSStefan Eßer 		if (p->l.t == BC_LEX_LBRACKET) {
143350696a6eSStefan Eßer 
143450696a6eSStefan Eßer 			t = BC_TYPE_ARRAY;
143550696a6eSStefan Eßer 
143650696a6eSStefan Eßer 			bc_lex_next(&p->l);
143750696a6eSStefan Eßer 
143844d4804dSStefan Eßer 			// The brackets *must* be empty.
143950696a6eSStefan Eßer 			if (BC_ERR(p->l.t != BC_LEX_RBRACKET))
144050696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_FUNC);
144150696a6eSStefan Eßer 
144250696a6eSStefan Eßer 			bc_lex_next(&p->l);
144350696a6eSStefan Eßer 		}
144450696a6eSStefan Eßer 		else t = BC_TYPE_VAR;
144550696a6eSStefan Eßer 
144644d4804dSStefan Eßer 		// Test for comma and get the next token if it exists.
144750696a6eSStefan Eßer 		comma = (p->l.t == BC_LEX_COMMA);
144850696a6eSStefan Eßer 		if (comma) bc_lex_next(&p->l);
144950696a6eSStefan Eßer 
145044d4804dSStefan Eßer 		// Insert the auto into the function.
145150696a6eSStefan Eßer 		bc_func_insert(p->func, p->prog, p->buf.v, t, p->l.line);
145250696a6eSStefan Eßer 	}
145350696a6eSStefan Eßer 
145444d4804dSStefan Eßer 	// If we have a comma, but no auto, barf.
145550696a6eSStefan Eßer 	if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_FUNC);
145644d4804dSStefan Eßer 
145744d4804dSStefan Eßer 	// If we don't have any variables or arrays, barf.
145850696a6eSStefan Eßer 	if (BC_ERR(!one)) bc_parse_err(p, BC_ERR_PARSE_NO_AUTO);
145944d4804dSStefan Eßer 
146044d4804dSStefan Eßer 	// The auto statement should be all that's in the statement.
146150696a6eSStefan Eßer 	if (BC_ERR(!bc_parse_isDelimiter(p)))
146250696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_TOKEN);
146350696a6eSStefan Eßer }
146450696a6eSStefan Eßer 
146544d4804dSStefan Eßer /**
146644d4804dSStefan Eßer  * Parses a body.
146744d4804dSStefan Eßer  * @param p      The parser.
146844d4804dSStefan Eßer  * @param brace  True if a brace was encountered, false otherwise.
146944d4804dSStefan Eßer  */
147050696a6eSStefan Eßer static void bc_parse_body(BcParse *p, bool brace) {
147150696a6eSStefan Eßer 
147250696a6eSStefan Eßer 	uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p);
147350696a6eSStefan Eßer 
147450696a6eSStefan Eßer 	assert(flag_ptr != NULL);
147550696a6eSStefan Eßer 	assert(p->flags.len >= 2);
147650696a6eSStefan Eßer 
147744d4804dSStefan Eßer 	// The body flag is for when we expect a body. We got a body, so clear the
147844d4804dSStefan Eßer 	// flag.
147950696a6eSStefan Eßer 	*flag_ptr &= ~(BC_PARSE_FLAG_BODY);
148050696a6eSStefan Eßer 
148144d4804dSStefan Eßer 	// If we are inside a function, that means we just barely entered it, and
148244d4804dSStefan Eßer 	// we can expect an auto list.
148350696a6eSStefan Eßer 	if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) {
148450696a6eSStefan Eßer 
148544d4804dSStefan Eßer 		// We *must* have a brace in this case.
148650696a6eSStefan Eßer 		if (BC_ERR(!brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN);
148750696a6eSStefan Eßer 
148850696a6eSStefan Eßer 		p->auto_part = (p->l.t != BC_LEX_KW_AUTO);
148950696a6eSStefan Eßer 
149050696a6eSStefan Eßer 		if (!p->auto_part) {
149150696a6eSStefan Eßer 
149250696a6eSStefan Eßer 			// Make sure this is true to not get a parse error.
149350696a6eSStefan Eßer 			p->auto_part = true;
149450696a6eSStefan Eßer 
149544d4804dSStefan Eßer 			// Since we already have the auto keyword, parse.
149650696a6eSStefan Eßer 			bc_parse_auto(p);
149750696a6eSStefan Eßer 		}
149850696a6eSStefan Eßer 
149944d4804dSStefan Eßer 		// Eat a newline.
150050696a6eSStefan Eßer 		if (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
150150696a6eSStefan Eßer 	}
150250696a6eSStefan Eßer 	else {
150350696a6eSStefan Eßer 
150444d4804dSStefan Eßer 		// This is the easy part.
150550696a6eSStefan Eßer 		size_t len = p->flags.len;
150650696a6eSStefan Eßer 
150750696a6eSStefan Eßer 		assert(*flag_ptr);
150850696a6eSStefan Eßer 
150944d4804dSStefan Eßer 		// Parse a statement.
151050696a6eSStefan Eßer 		bc_parse_stmt(p);
151150696a6eSStefan Eßer 
151244d4804dSStefan Eßer 		// This is a very important condition to get right. If there is no
151344d4804dSStefan Eßer 		// brace, and no body flag, and the flags len hasn't shrunk, then we
151444d4804dSStefan Eßer 		// have a body that was not delimited by braces, so we need to end it
151544d4804dSStefan Eßer 		// now, after just one statement.
151650696a6eSStefan Eßer 		if (!brace && !BC_PARSE_BODY(p) && len <= p->flags.len)
151750696a6eSStefan Eßer 			bc_parse_endBody(p, false);
151850696a6eSStefan Eßer 	}
151950696a6eSStefan Eßer }
152050696a6eSStefan Eßer 
152144d4804dSStefan Eßer /**
152244d4804dSStefan Eßer  * Parses a statement. This is the entry point for just about everything, except
152344d4804dSStefan Eßer  * function definitions.
152444d4804dSStefan Eßer  * @param p  The parser.
152544d4804dSStefan Eßer  */
152650696a6eSStefan Eßer static void bc_parse_stmt(BcParse *p) {
152750696a6eSStefan Eßer 
152850696a6eSStefan Eßer 	size_t len;
152950696a6eSStefan Eßer 	uint16_t flags;
153050696a6eSStefan Eßer 	BcLexType type = p->l.t;
153150696a6eSStefan Eßer 
153244d4804dSStefan Eßer 	// Eat newline.
153350696a6eSStefan Eßer 	if (type == BC_LEX_NLINE) {
153450696a6eSStefan Eßer 		bc_lex_next(&p->l);
153550696a6eSStefan Eßer 		return;
153650696a6eSStefan Eßer 	}
153744d4804dSStefan Eßer 
153844d4804dSStefan Eßer 	// Eat auto list.
153950696a6eSStefan Eßer 	if (type == BC_LEX_KW_AUTO) {
154050696a6eSStefan Eßer 		bc_parse_auto(p);
154150696a6eSStefan Eßer 		return;
154250696a6eSStefan Eßer 	}
154350696a6eSStefan Eßer 
154444d4804dSStefan Eßer 	// If we reach this point, no auto list is allowed.
154550696a6eSStefan Eßer 	p->auto_part = false;
154650696a6eSStefan Eßer 
154744d4804dSStefan Eßer 	// Everything but an else needs to be taken care of here, but else is
154844d4804dSStefan Eßer 	// special.
154950696a6eSStefan Eßer 	if (type != BC_LEX_KW_ELSE) {
155050696a6eSStefan Eßer 
155144d4804dSStefan Eßer 		// After an if, no else found.
155250696a6eSStefan Eßer 		if (BC_PARSE_IF_END(p)) {
155344d4804dSStefan Eßer 
155444d4804dSStefan Eßer 			// Clear the expectation for else, end body, and return. Returning
155544d4804dSStefan Eßer 			// gives us a clean slate for parsing again.
155650696a6eSStefan Eßer 			bc_parse_noElse(p);
155750696a6eSStefan Eßer 			if (p->flags.len > 1 && !BC_PARSE_BRACE(p))
155850696a6eSStefan Eßer 				bc_parse_endBody(p, false);
155950696a6eSStefan Eßer 			return;
156050696a6eSStefan Eßer 		}
156144d4804dSStefan Eßer 		// With a left brace, we are parsing a body.
156250696a6eSStefan Eßer 		else if (type == BC_LEX_LBRACE) {
156350696a6eSStefan Eßer 
156444d4804dSStefan Eßer 			// We need to start a body if we are not expecting one yet.
156550696a6eSStefan Eßer 			if (!BC_PARSE_BODY(p)) {
156650696a6eSStefan Eßer 				bc_parse_startBody(p, BC_PARSE_FLAG_BRACE);
156750696a6eSStefan Eßer 				bc_lex_next(&p->l);
156850696a6eSStefan Eßer 			}
156944d4804dSStefan Eßer 			// If we *are* expecting a body, that body should get a brace. This
157044d4804dSStefan Eßer 			// takes care of braces being on a different line than if and loop
157144d4804dSStefan Eßer 			// headers.
157250696a6eSStefan Eßer 			else {
157350696a6eSStefan Eßer 				*(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE;
157450696a6eSStefan Eßer 				bc_lex_next(&p->l);
157550696a6eSStefan Eßer 				bc_parse_body(p, true);
157650696a6eSStefan Eßer 			}
157750696a6eSStefan Eßer 
157844d4804dSStefan Eßer 			// If we have reached this point, we need to return for a clean
157944d4804dSStefan Eßer 			// slate.
158050696a6eSStefan Eßer 			return;
158150696a6eSStefan Eßer 		}
158244d4804dSStefan Eßer 		// This happens when we are expecting a body and get a single statement,
158344d4804dSStefan Eßer 		// i.e., a body with no braces surrounding it. Returns after for a clean
158444d4804dSStefan Eßer 		// slate.
158550696a6eSStefan Eßer 		else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p)) {
158650696a6eSStefan Eßer 			bc_parse_body(p, false);
158750696a6eSStefan Eßer 			return;
158850696a6eSStefan Eßer 		}
158950696a6eSStefan Eßer 	}
159050696a6eSStefan Eßer 
159150696a6eSStefan Eßer 	len = p->flags.len;
159250696a6eSStefan Eßer 	flags = BC_PARSE_TOP_FLAG(p);
159350696a6eSStefan Eßer 
159450696a6eSStefan Eßer 	switch (type) {
159550696a6eSStefan Eßer 
159644d4804dSStefan Eßer 		// All of these are valid for expressions.
159750696a6eSStefan Eßer 		case BC_LEX_OP_INC:
159850696a6eSStefan Eßer 		case BC_LEX_OP_DEC:
159950696a6eSStefan Eßer 		case BC_LEX_OP_MINUS:
160050696a6eSStefan Eßer 		case BC_LEX_OP_BOOL_NOT:
160150696a6eSStefan Eßer 		case BC_LEX_LPAREN:
160250696a6eSStefan Eßer 		case BC_LEX_NAME:
160350696a6eSStefan Eßer 		case BC_LEX_NUMBER:
160450696a6eSStefan Eßer 		case BC_LEX_KW_IBASE:
160550696a6eSStefan Eßer 		case BC_LEX_KW_LAST:
160650696a6eSStefan Eßer 		case BC_LEX_KW_LENGTH:
160750696a6eSStefan Eßer 		case BC_LEX_KW_OBASE:
160850696a6eSStefan Eßer 		case BC_LEX_KW_SCALE:
160944d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
161050696a6eSStefan Eßer 		case BC_LEX_KW_SEED:
161144d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
161250696a6eSStefan Eßer 		case BC_LEX_KW_SQRT:
161350696a6eSStefan Eßer 		case BC_LEX_KW_ABS:
161444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
161550696a6eSStefan Eßer 		case BC_LEX_KW_IRAND:
161644d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
161744d4804dSStefan Eßer 		case BC_LEX_KW_ASCIIFY:
161844d4804dSStefan Eßer 		case BC_LEX_KW_MODEXP:
161944d4804dSStefan Eßer 		case BC_LEX_KW_DIVMOD:
162050696a6eSStefan Eßer 		case BC_LEX_KW_READ:
162144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
162250696a6eSStefan Eßer 		case BC_LEX_KW_RAND:
162344d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
162450696a6eSStefan Eßer 		case BC_LEX_KW_MAXIBASE:
162550696a6eSStefan Eßer 		case BC_LEX_KW_MAXOBASE:
162650696a6eSStefan Eßer 		case BC_LEX_KW_MAXSCALE:
162744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
162850696a6eSStefan Eßer 		case BC_LEX_KW_MAXRAND:
162944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
1630d43fa8efSStefan Eßer 		case BC_LEX_KW_LINE_LENGTH:
1631d43fa8efSStefan Eßer 		case BC_LEX_KW_GLOBAL_STACKS:
1632d43fa8efSStefan Eßer 		case BC_LEX_KW_LEADING_ZERO:
163350696a6eSStefan Eßer 		{
163450696a6eSStefan Eßer 			bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr);
163550696a6eSStefan Eßer 			break;
163650696a6eSStefan Eßer 		}
163750696a6eSStefan Eßer 
163850696a6eSStefan Eßer 		case BC_LEX_KW_ELSE:
163950696a6eSStefan Eßer 		{
164050696a6eSStefan Eßer 			bc_parse_else(p);
164150696a6eSStefan Eßer 			break;
164250696a6eSStefan Eßer 		}
164350696a6eSStefan Eßer 
164444d4804dSStefan Eßer 		// Just eat.
164550696a6eSStefan Eßer 		case BC_LEX_SCOLON:
164650696a6eSStefan Eßer 		{
164750696a6eSStefan Eßer 			// Do nothing.
164850696a6eSStefan Eßer 			break;
164950696a6eSStefan Eßer 		}
165050696a6eSStefan Eßer 
165150696a6eSStefan Eßer 		case BC_LEX_RBRACE:
165250696a6eSStefan Eßer 		{
165350696a6eSStefan Eßer 			bc_parse_endBody(p, true);
165450696a6eSStefan Eßer 			break;
165550696a6eSStefan Eßer 		}
165650696a6eSStefan Eßer 
165750696a6eSStefan Eßer 		case BC_LEX_STR:
165850696a6eSStefan Eßer 		{
165950696a6eSStefan Eßer 			bc_parse_str(p, BC_INST_PRINT_STR);
166050696a6eSStefan Eßer 			break;
166150696a6eSStefan Eßer 		}
166250696a6eSStefan Eßer 
166350696a6eSStefan Eßer 		case BC_LEX_KW_BREAK:
166450696a6eSStefan Eßer 		case BC_LEX_KW_CONTINUE:
166550696a6eSStefan Eßer 		{
166650696a6eSStefan Eßer 			bc_parse_loopExit(p, p->l.t);
166750696a6eSStefan Eßer 			break;
166850696a6eSStefan Eßer 		}
166950696a6eSStefan Eßer 
167050696a6eSStefan Eßer 		case BC_LEX_KW_FOR:
167150696a6eSStefan Eßer 		{
167250696a6eSStefan Eßer 			bc_parse_for(p);
167350696a6eSStefan Eßer 			break;
167450696a6eSStefan Eßer 		}
167550696a6eSStefan Eßer 
167650696a6eSStefan Eßer 		case BC_LEX_KW_HALT:
167750696a6eSStefan Eßer 		{
167850696a6eSStefan Eßer 			bc_parse_push(p, BC_INST_HALT);
167950696a6eSStefan Eßer 			bc_lex_next(&p->l);
168050696a6eSStefan Eßer 			break;
168150696a6eSStefan Eßer 		}
168250696a6eSStefan Eßer 
168350696a6eSStefan Eßer 		case BC_LEX_KW_IF:
168450696a6eSStefan Eßer 		{
168550696a6eSStefan Eßer 			bc_parse_if(p);
168650696a6eSStefan Eßer 			break;
168750696a6eSStefan Eßer 		}
168850696a6eSStefan Eßer 
168950696a6eSStefan Eßer 		case BC_LEX_KW_LIMITS:
169050696a6eSStefan Eßer 		{
169144d4804dSStefan Eßer 			// `limits` is a compile-time command, so execute it right away.
169250696a6eSStefan Eßer 			bc_vm_printf("BC_LONG_BIT      = %lu\n", (ulong) BC_LONG_BIT);
169350696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_DIGS     = %lu\n", (ulong) BC_BASE_DIGS);
169450696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_POW      = %lu\n", (ulong) BC_BASE_POW);
169550696a6eSStefan Eßer 			bc_vm_printf("BC_OVERFLOW_MAX  = %lu\n", (ulong) BC_NUM_BIGDIG_MAX);
169650696a6eSStefan Eßer 			bc_vm_printf("\n");
169750696a6eSStefan Eßer 			bc_vm_printf("BC_BASE_MAX      = %lu\n", BC_MAX_OBASE);
169850696a6eSStefan Eßer 			bc_vm_printf("BC_DIM_MAX       = %lu\n", BC_MAX_DIM);
169950696a6eSStefan Eßer 			bc_vm_printf("BC_SCALE_MAX     = %lu\n", BC_MAX_SCALE);
170050696a6eSStefan Eßer 			bc_vm_printf("BC_STRING_MAX    = %lu\n", BC_MAX_STRING);
170150696a6eSStefan Eßer 			bc_vm_printf("BC_NAME_MAX      = %lu\n", BC_MAX_NAME);
170250696a6eSStefan Eßer 			bc_vm_printf("BC_NUM_MAX       = %lu\n", BC_MAX_NUM);
170344d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
170450696a6eSStefan Eßer 			bc_vm_printf("BC_RAND_MAX      = %lu\n", BC_MAX_RAND);
170544d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
170650696a6eSStefan Eßer 			bc_vm_printf("MAX Exponent     = %lu\n", BC_MAX_EXP);
170750696a6eSStefan Eßer 			bc_vm_printf("Number of vars   = %lu\n", BC_MAX_VARS);
170850696a6eSStefan Eßer 
170950696a6eSStefan Eßer 			bc_lex_next(&p->l);
171050696a6eSStefan Eßer 
171150696a6eSStefan Eßer 			break;
171250696a6eSStefan Eßer 		}
171350696a6eSStefan Eßer 
171444d4804dSStefan Eßer 		case BC_LEX_KW_STREAM:
171550696a6eSStefan Eßer 		case BC_LEX_KW_PRINT:
171650696a6eSStefan Eßer 		{
171744d4804dSStefan Eßer 			bc_parse_print(p, type);
171850696a6eSStefan Eßer 			break;
171950696a6eSStefan Eßer 		}
172050696a6eSStefan Eßer 
172150696a6eSStefan Eßer 		case BC_LEX_KW_QUIT:
172250696a6eSStefan Eßer 		{
172344d4804dSStefan Eßer 			// Quit is a compile-time command. We don't exit directly, so the vm
172444d4804dSStefan Eßer 			// can clean up.
172550696a6eSStefan Eßer 			vm.status = BC_STATUS_QUIT;
172644d4804dSStefan Eßer 			BC_JMP;
172750696a6eSStefan Eßer 			break;
172850696a6eSStefan Eßer 		}
172950696a6eSStefan Eßer 
173050696a6eSStefan Eßer 		case BC_LEX_KW_RETURN:
173150696a6eSStefan Eßer 		{
173250696a6eSStefan Eßer 			bc_parse_return(p);
173350696a6eSStefan Eßer 			break;
173450696a6eSStefan Eßer 		}
173550696a6eSStefan Eßer 
173650696a6eSStefan Eßer 		case BC_LEX_KW_WHILE:
173750696a6eSStefan Eßer 		{
173850696a6eSStefan Eßer 			bc_parse_while(p);
173950696a6eSStefan Eßer 			break;
174050696a6eSStefan Eßer 		}
174150696a6eSStefan Eßer 
174250696a6eSStefan Eßer 		default:
174350696a6eSStefan Eßer 		{
174450696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
174550696a6eSStefan Eßer 		}
174650696a6eSStefan Eßer 	}
174750696a6eSStefan Eßer 
174844d4804dSStefan Eßer 	// If the flags did not change, we expect a delimiter.
174950696a6eSStefan Eßer 	if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) {
175050696a6eSStefan Eßer 		if (BC_ERR(!bc_parse_isDelimiter(p)))
175150696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_TOKEN);
175250696a6eSStefan Eßer 	}
175350696a6eSStefan Eßer 
175450696a6eSStefan Eßer 	// Make sure semicolons are eaten.
175550696a6eSStefan Eßer 	while (p->l.t == BC_LEX_SCOLON) bc_lex_next(&p->l);
175650696a6eSStefan Eßer }
175750696a6eSStefan Eßer 
175850696a6eSStefan Eßer void bc_parse_parse(BcParse *p) {
175950696a6eSStefan Eßer 
176050696a6eSStefan Eßer 	assert(p);
176150696a6eSStefan Eßer 
176250696a6eSStefan Eßer 	BC_SETJMP(exit);
176350696a6eSStefan Eßer 
176444d4804dSStefan Eßer 	// We should not let an EOF get here unless some partial parse was not
176544d4804dSStefan Eßer 	// completed, in which case, it's the user's fault.
176650696a6eSStefan Eßer 	if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF);
176744d4804dSStefan Eßer 
176844d4804dSStefan Eßer 	// Functions need special parsing.
176950696a6eSStefan Eßer 	else if (p->l.t == BC_LEX_KW_DEFINE) {
1770d43fa8efSStefan Eßer 		if (BC_ERR(BC_PARSE_NO_EXEC(p))) {
1771*a30efc5cSStefan Eßer 			bc_parse_endif(p);
1772*a30efc5cSStefan Eßer 			if (BC_ERR(BC_PARSE_NO_EXEC(p)))
1773*a30efc5cSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
1774d43fa8efSStefan Eßer 		}
177550696a6eSStefan Eßer 		bc_parse_func(p);
177650696a6eSStefan Eßer 	}
177744d4804dSStefan Eßer 
177844d4804dSStefan Eßer 	// Otherwise, parse a normal statement.
177950696a6eSStefan Eßer 	else bc_parse_stmt(p);
178050696a6eSStefan Eßer 
178150696a6eSStefan Eßer exit:
178244d4804dSStefan Eßer 
178350696a6eSStefan Eßer 	BC_SIG_MAYLOCK;
178444d4804dSStefan Eßer 
178544d4804dSStefan Eßer 	// We need to reset on error.
178650696a6eSStefan Eßer 	if (BC_ERR(((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig)))
178750696a6eSStefan Eßer 		bc_parse_reset(p);
178844d4804dSStefan Eßer 
178950696a6eSStefan Eßer 	BC_LONGJMP_CONT;
179050696a6eSStefan Eßer }
179150696a6eSStefan Eßer 
179244d4804dSStefan Eßer /**
179344d4804dSStefan Eßer  * Parse an expression. This is the actual implementation of the Shunting-Yard
179444d4804dSStefan Eßer  * Algorithm.
179544d4804dSStefan Eßer  * @param p      The parser.
179644d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
179744d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
179844d4804dSStefan Eßer  * @return       A parse status. In some places, an empty expression is an
179944d4804dSStefan Eßer  *               error, and sometimes, it is required. This allows this function
180044d4804dSStefan Eßer  *               to tell the caller if the expression was empty and let the
180144d4804dSStefan Eßer  *               caller handle it.
180244d4804dSStefan Eßer  */
180350696a6eSStefan Eßer static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags,
180450696a6eSStefan Eßer                                        BcParseNext next)
180550696a6eSStefan Eßer {
180650696a6eSStefan Eßer 	BcInst prev = BC_INST_PRINT;
180750696a6eSStefan Eßer 	uchar inst = BC_INST_INVALID;
180844d4804dSStefan Eßer 	BcLexType top, t;
180944d4804dSStefan Eßer 	size_t nexprs, ops_bgn;
181050696a6eSStefan Eßer 	uint32_t i, nparens, nrelops;
181150696a6eSStefan Eßer 	bool pfirst, rprn, done, get_token, assign, bin_last, incdec, can_assign;
181250696a6eSStefan Eßer 
181344d4804dSStefan Eßer 	// One of these *must* be true.
181450696a6eSStefan Eßer 	assert(!(flags & BC_PARSE_PRINT) || !(flags & BC_PARSE_NEEDVAL));
181550696a6eSStefan Eßer 
181644d4804dSStefan Eßer 	// These are set very carefully. In fact, controlling the values of these
181744d4804dSStefan Eßer 	// locals is the biggest part of making this work. ops_bgn especially is
181844d4804dSStefan Eßer 	// important because it marks where the operator stack begins for *this*
181944d4804dSStefan Eßer 	// invocation of this function. That's because bc_parse_expr_err() is
182044d4804dSStefan Eßer 	// recursive (the Shunting-Yard Algorithm is most easily expressed
182144d4804dSStefan Eßer 	// recursively when parsing subexpressions), and each invocation needs to
182244d4804dSStefan Eßer 	// know where to stop.
182344d4804dSStefan Eßer 	//
182444d4804dSStefan Eßer 	// - nparens is the number of left parens without matches.
182544d4804dSStefan Eßer 	// - nrelops is the number of relational operators that appear in the expr.
182644d4804dSStefan Eßer 	// - nexprs is the number of unused expressions.
182744d4804dSStefan Eßer 	// - rprn is a right paren encountered last.
182844d4804dSStefan Eßer 	// - done means the expression has been fully parsed.
182944d4804dSStefan Eßer 	// - get_token is true when a token is needed at the end of an iteration.
183044d4804dSStefan Eßer 	// - assign is true when an assignment statement was parsed last.
183144d4804dSStefan Eßer 	// - incdec is true when the previous operator was an inc or dec operator.
183244d4804dSStefan Eßer 	// - can_assign is true when an assignemnt is valid.
183344d4804dSStefan Eßer 	// - bin_last is true when the previous instruction was a binary operator.
183444d4804dSStefan Eßer 	t = p->l.t;
183550696a6eSStefan Eßer 	pfirst = (p->l.t == BC_LEX_LPAREN);
183650696a6eSStefan Eßer 	nparens = nrelops = 0;
183744d4804dSStefan Eßer 	nexprs = 0;
183844d4804dSStefan Eßer 	ops_bgn = p->ops.len;
183950696a6eSStefan Eßer 	rprn = done = get_token = assign = incdec = can_assign = false;
184050696a6eSStefan Eßer 	bin_last = true;
184150696a6eSStefan Eßer 
184250696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
184350696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
184450696a6eSStefan Eßer 	if (!(flags & BC_PARSE_NOREAD)) {
184550696a6eSStefan Eßer 		while ((t = p->l.t) == BC_LEX_NLINE) bc_lex_next(&p->l);
184650696a6eSStefan Eßer 	}
184750696a6eSStefan Eßer 
184844d4804dSStefan Eßer 	// This is the Shunting-Yard algorithm loop.
184950696a6eSStefan Eßer 	for (; !done && BC_PARSE_EXPR(t); t = p->l.t)
185050696a6eSStefan Eßer 	{
185150696a6eSStefan Eßer 		switch (t) {
185250696a6eSStefan Eßer 
185350696a6eSStefan Eßer 			case BC_LEX_OP_INC:
185450696a6eSStefan Eßer 			case BC_LEX_OP_DEC:
185550696a6eSStefan Eßer 			{
185644d4804dSStefan Eßer 				// These operators can only be used with items that can be
185744d4804dSStefan Eßer 				// assigned to.
185850696a6eSStefan Eßer 				if (BC_ERR(incdec)) bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
185944d4804dSStefan Eßer 
186050696a6eSStefan Eßer 				bc_parse_incdec(p, &prev, &can_assign, &nexprs, flags);
186144d4804dSStefan Eßer 
186250696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
186350696a6eSStefan Eßer 				incdec = true;
186450696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
186544d4804dSStefan Eßer 
186650696a6eSStefan Eßer 				break;
186750696a6eSStefan Eßer 			}
186850696a6eSStefan Eßer 
186950696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
187050696a6eSStefan Eßer 			case BC_LEX_OP_TRUNC:
187150696a6eSStefan Eßer 			{
187244d4804dSStefan Eßer 				// The previous token must have been a leaf expression, or the
187344d4804dSStefan Eßer 				// operator is in the wrong place.
187450696a6eSStefan Eßer 				if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn)))
187550696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_TOKEN);
187650696a6eSStefan Eßer 
187750696a6eSStefan Eßer 				// I can just add the instruction because
187850696a6eSStefan Eßer 				// negative will already be taken care of.
187950696a6eSStefan Eßer 				bc_parse_push(p, BC_INST_TRUNC);
188044d4804dSStefan Eßer 
188150696a6eSStefan Eßer 				rprn = can_assign = incdec = false;
188250696a6eSStefan Eßer 				get_token = true;
188350696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
188444d4804dSStefan Eßer 
188550696a6eSStefan Eßer 				break;
188650696a6eSStefan Eßer 			}
188750696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
188850696a6eSStefan Eßer 
188950696a6eSStefan Eßer 			case BC_LEX_OP_MINUS:
189050696a6eSStefan Eßer 			{
189150696a6eSStefan Eßer 				bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs);
189244d4804dSStefan Eßer 
189350696a6eSStefan Eßer 				rprn = get_token = can_assign = false;
189444d4804dSStefan Eßer 
189544d4804dSStefan Eßer 				// This is true if it was a binary operator last.
189650696a6eSStefan Eßer 				bin_last = (prev == BC_INST_MINUS);
189750696a6eSStefan Eßer 				if (bin_last) incdec = false;
189844d4804dSStefan Eßer 
189950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
190044d4804dSStefan Eßer 
190150696a6eSStefan Eßer 				break;
190250696a6eSStefan Eßer 			}
190350696a6eSStefan Eßer 
190444d4804dSStefan Eßer 			// All of this group, including the fallthrough, is to parse binary
190544d4804dSStefan Eßer 			// operators.
190650696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_POWER:
190750696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MULTIPLY:
190850696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_DIVIDE:
190950696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MODULUS:
191050696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLUS:
191150696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_MINUS:
191250696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
191350696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_PLACES:
191450696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_LSHIFT:
191550696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN_RSHIFT:
191650696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
191750696a6eSStefan Eßer 			case BC_LEX_OP_ASSIGN:
191850696a6eSStefan Eßer 			{
191944d4804dSStefan Eßer 				// We need to make sure the assignment is valid.
192050696a6eSStefan Eßer 				if (!BC_PARSE_INST_VAR(prev))
192150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_ASSIGN);
192250696a6eSStefan Eßer 			}
192350696a6eSStefan Eßer 			// Fallthrough.
192450696a6eSStefan Eßer 			BC_FALLTHROUGH
192550696a6eSStefan Eßer 
192650696a6eSStefan Eßer 			case BC_LEX_OP_POWER:
192750696a6eSStefan Eßer 			case BC_LEX_OP_MULTIPLY:
192850696a6eSStefan Eßer 			case BC_LEX_OP_DIVIDE:
192950696a6eSStefan Eßer 			case BC_LEX_OP_MODULUS:
193050696a6eSStefan Eßer 			case BC_LEX_OP_PLUS:
193150696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH
193250696a6eSStefan Eßer 			case BC_LEX_OP_PLACES:
193350696a6eSStefan Eßer 			case BC_LEX_OP_LSHIFT:
193450696a6eSStefan Eßer 			case BC_LEX_OP_RSHIFT:
193550696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
193650696a6eSStefan Eßer 			case BC_LEX_OP_REL_EQ:
193750696a6eSStefan Eßer 			case BC_LEX_OP_REL_LE:
193850696a6eSStefan Eßer 			case BC_LEX_OP_REL_GE:
193950696a6eSStefan Eßer 			case BC_LEX_OP_REL_NE:
194050696a6eSStefan Eßer 			case BC_LEX_OP_REL_LT:
194150696a6eSStefan Eßer 			case BC_LEX_OP_REL_GT:
194250696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_NOT:
194350696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_OR:
194450696a6eSStefan Eßer 			case BC_LEX_OP_BOOL_AND:
194550696a6eSStefan Eßer 			{
194644d4804dSStefan Eßer 				// This is true if the operator if the token is a prefix
194744d4804dSStefan Eßer 				// operator. This is only for boolean not.
194850696a6eSStefan Eßer 				if (BC_PARSE_OP_PREFIX(t)) {
194944d4804dSStefan Eßer 
195044d4804dSStefan Eßer 					// Prefix operators are only allowed after binary operators
195144d4804dSStefan Eßer 					// or prefix operators.
195250696a6eSStefan Eßer 					if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last)))
195350696a6eSStefan Eßer 						bc_parse_err(p, BC_ERR_PARSE_EXPR);
195450696a6eSStefan Eßer 				}
195544d4804dSStefan Eßer 				// If we execute the else, that means we have a binary operator.
195644d4804dSStefan Eßer 				// If the previous operator was a prefix or a binary operator,
195744d4804dSStefan Eßer 				// then a binary operator is not allowed.
195850696a6eSStefan Eßer 				else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last))
195950696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
196050696a6eSStefan Eßer 
196150696a6eSStefan Eßer 				nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT);
196250696a6eSStefan Eßer 				prev = BC_PARSE_TOKEN_INST(t);
196344d4804dSStefan Eßer 
196450696a6eSStefan Eßer 				bc_parse_operator(p, t, ops_bgn, &nexprs);
196544d4804dSStefan Eßer 
196650696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
196750696a6eSStefan Eßer 				get_token = true;
196850696a6eSStefan Eßer 				bin_last = !BC_PARSE_OP_PREFIX(t);
196950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
197050696a6eSStefan Eßer 
197150696a6eSStefan Eßer 				break;
197250696a6eSStefan Eßer 			}
197350696a6eSStefan Eßer 
197450696a6eSStefan Eßer 			case BC_LEX_LPAREN:
197550696a6eSStefan Eßer 			{
197644d4804dSStefan Eßer 				// A left paren is *not* allowed right after a leaf expr.
197750696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
197850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
197950696a6eSStefan Eßer 
198050696a6eSStefan Eßer 				nparens += 1;
198150696a6eSStefan Eßer 				rprn = incdec = can_assign = false;
198250696a6eSStefan Eßer 				get_token = true;
198344d4804dSStefan Eßer 
198444d4804dSStefan Eßer 				// Push the paren onto the operator stack.
198550696a6eSStefan Eßer 				bc_vec_push(&p->ops, &t);
198650696a6eSStefan Eßer 
198750696a6eSStefan Eßer 				break;
198850696a6eSStefan Eßer 			}
198950696a6eSStefan Eßer 
199050696a6eSStefan Eßer 			case BC_LEX_RPAREN:
199150696a6eSStefan Eßer 			{
199244d4804dSStefan Eßer 				// This needs to be a status. The error is handled in
199344d4804dSStefan Eßer 				// bc_parse_expr_status().
199450696a6eSStefan Eßer 				if (BC_ERR(p->l.last == BC_LEX_LPAREN))
199550696a6eSStefan Eßer 					return BC_PARSE_STATUS_EMPTY_EXPR;
199650696a6eSStefan Eßer 
199744d4804dSStefan Eßer 				// The right paren must not come after a prefix or binary
199844d4804dSStefan Eßer 				// operator.
199950696a6eSStefan Eßer 				if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev)))
200050696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
200150696a6eSStefan Eßer 
200244d4804dSStefan Eßer 				// If there are no parens left, we are done, but we need another
200344d4804dSStefan Eßer 				// token.
200450696a6eSStefan Eßer 				if (!nparens) {
200550696a6eSStefan Eßer 					done = true;
200650696a6eSStefan Eßer 					get_token = false;
200750696a6eSStefan Eßer 					break;
200850696a6eSStefan Eßer 				}
200950696a6eSStefan Eßer 
201050696a6eSStefan Eßer 				nparens -= 1;
201150696a6eSStefan Eßer 				rprn = true;
201250696a6eSStefan Eßer 				get_token = bin_last = incdec = false;
201350696a6eSStefan Eßer 
201450696a6eSStefan Eßer 				bc_parse_rightParen(p, &nexprs);
201550696a6eSStefan Eßer 
201650696a6eSStefan Eßer 				break;
201750696a6eSStefan Eßer 			}
201850696a6eSStefan Eßer 
201944d4804dSStefan Eßer 			case BC_LEX_STR:
202044d4804dSStefan Eßer 			{
202144d4804dSStefan Eßer 				// POSIX only allows strings alone.
202244d4804dSStefan Eßer 				if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_EXPR_STRING);
202344d4804dSStefan Eßer 
202444d4804dSStefan Eßer 				// A string is a leaf and cannot come right after a leaf.
202544d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
202644d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
202744d4804dSStefan Eßer 
202844d4804dSStefan Eßer 				bc_parse_addString(p);
202944d4804dSStefan Eßer 
203044d4804dSStefan Eßer 				get_token = true;
203144d4804dSStefan Eßer 				bin_last = rprn = false;
203244d4804dSStefan Eßer 				nexprs += 1;
203344d4804dSStefan Eßer 
203444d4804dSStefan Eßer 				break;
203544d4804dSStefan Eßer 			}
203644d4804dSStefan Eßer 
203750696a6eSStefan Eßer 			case BC_LEX_NAME:
203850696a6eSStefan Eßer 			{
203944d4804dSStefan Eßer 				// A name is a leaf and cannot come right after a leaf.
204050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
204150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
204250696a6eSStefan Eßer 
204350696a6eSStefan Eßer 				get_token = bin_last = false;
204444d4804dSStefan Eßer 
204544d4804dSStefan Eßer 				bc_parse_name(p, &prev, &can_assign, flags & ~BC_PARSE_NOCALL);
204644d4804dSStefan Eßer 
204750696a6eSStefan Eßer 				rprn = (prev == BC_INST_CALL);
204850696a6eSStefan Eßer 				nexprs += 1;
204950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
205050696a6eSStefan Eßer 
205150696a6eSStefan Eßer 				break;
205250696a6eSStefan Eßer 			}
205350696a6eSStefan Eßer 
205450696a6eSStefan Eßer 			case BC_LEX_NUMBER:
205550696a6eSStefan Eßer 			{
205644d4804dSStefan Eßer 				// A number is a leaf and cannot come right after a leaf.
205750696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
205850696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
205950696a6eSStefan Eßer 
206044d4804dSStefan Eßer 				// The number instruction is pushed in here.
206150696a6eSStefan Eßer 				bc_parse_number(p);
206244d4804dSStefan Eßer 
206350696a6eSStefan Eßer 				nexprs += 1;
206450696a6eSStefan Eßer 				prev = BC_INST_NUM;
206550696a6eSStefan Eßer 				get_token = true;
206650696a6eSStefan Eßer 				rprn = bin_last = can_assign = false;
206750696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
206850696a6eSStefan Eßer 
206950696a6eSStefan Eßer 				break;
207050696a6eSStefan Eßer 			}
207150696a6eSStefan Eßer 
207250696a6eSStefan Eßer 			case BC_LEX_KW_IBASE:
207350696a6eSStefan Eßer 			case BC_LEX_KW_LAST:
207450696a6eSStefan Eßer 			case BC_LEX_KW_OBASE:
207544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
207650696a6eSStefan Eßer 			case BC_LEX_KW_SEED:
207744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
207850696a6eSStefan Eßer 			{
207944d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
208050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
208150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
208250696a6eSStefan Eßer 
208350696a6eSStefan Eßer 				prev = t - BC_LEX_KW_LAST + BC_INST_LAST;
208450696a6eSStefan Eßer 				bc_parse_push(p, prev);
208550696a6eSStefan Eßer 
208650696a6eSStefan Eßer 				get_token = can_assign = true;
208750696a6eSStefan Eßer 				rprn = bin_last = false;
208850696a6eSStefan Eßer 				nexprs += 1;
208950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
209050696a6eSStefan Eßer 
209150696a6eSStefan Eßer 				break;
209250696a6eSStefan Eßer 			}
209350696a6eSStefan Eßer 
209450696a6eSStefan Eßer 			case BC_LEX_KW_LENGTH:
209550696a6eSStefan Eßer 			case BC_LEX_KW_SQRT:
209650696a6eSStefan Eßer 			case BC_LEX_KW_ABS:
209744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
209850696a6eSStefan Eßer 			case BC_LEX_KW_IRAND:
209944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
210044d4804dSStefan Eßer 			case BC_LEX_KW_ASCIIFY:
210150696a6eSStefan Eßer 			{
210244d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
210350696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
210450696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
210550696a6eSStefan Eßer 
210650696a6eSStefan Eßer 				bc_parse_builtin(p, t, flags, &prev);
210744d4804dSStefan Eßer 
210850696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
210950696a6eSStefan Eßer 				nexprs += 1;
211050696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
211150696a6eSStefan Eßer 
211250696a6eSStefan Eßer 				break;
211350696a6eSStefan Eßer 			}
211450696a6eSStefan Eßer 
211550696a6eSStefan Eßer 			case BC_LEX_KW_READ:
211644d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
211750696a6eSStefan Eßer 			case BC_LEX_KW_RAND:
211844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
211950696a6eSStefan Eßer 			case BC_LEX_KW_MAXIBASE:
212050696a6eSStefan Eßer 			case BC_LEX_KW_MAXOBASE:
212150696a6eSStefan Eßer 			case BC_LEX_KW_MAXSCALE:
212244d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
212350696a6eSStefan Eßer 			case BC_LEX_KW_MAXRAND:
212444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
2125d43fa8efSStefan Eßer 			case BC_LEX_KW_LINE_LENGTH:
2126d43fa8efSStefan Eßer 			case BC_LEX_KW_GLOBAL_STACKS:
2127d43fa8efSStefan Eßer 			case BC_LEX_KW_LEADING_ZERO:
212850696a6eSStefan Eßer 			{
212944d4804dSStefan Eßer 				// All of these are leaves and cannot come right after a leaf.
213050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
213150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
213244d4804dSStefan Eßer 
213344d4804dSStefan Eßer 				// Error if we have read and it's not allowed.
213450696a6eSStefan Eßer 				else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD))
213550696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_EXEC_REC_READ);
213644d4804dSStefan Eßer 
213750696a6eSStefan Eßer 				prev = t - BC_LEX_KW_READ + BC_INST_READ;
213850696a6eSStefan Eßer 				bc_parse_noArgBuiltin(p, prev);
213950696a6eSStefan Eßer 
214050696a6eSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
214150696a6eSStefan Eßer 				nexprs += 1;
214250696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
214350696a6eSStefan Eßer 
214450696a6eSStefan Eßer 				break;
214550696a6eSStefan Eßer 			}
214650696a6eSStefan Eßer 
214750696a6eSStefan Eßer 			case BC_LEX_KW_SCALE:
214850696a6eSStefan Eßer 			{
214944d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
215050696a6eSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
215150696a6eSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
215250696a6eSStefan Eßer 
215344d4804dSStefan Eßer 				// Scale needs special work because it can be a variable *or* a
215444d4804dSStefan Eßer 				// function.
215550696a6eSStefan Eßer 				bc_parse_scale(p, &prev, &can_assign, flags);
215644d4804dSStefan Eßer 
215750696a6eSStefan Eßer 				rprn = get_token = bin_last = false;
215850696a6eSStefan Eßer 				nexprs += 1;
215950696a6eSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
216050696a6eSStefan Eßer 
216150696a6eSStefan Eßer 				break;
216250696a6eSStefan Eßer 			}
216350696a6eSStefan Eßer 
216444d4804dSStefan Eßer 			case BC_LEX_KW_MODEXP:
216544d4804dSStefan Eßer 			case BC_LEX_KW_DIVMOD:
216644d4804dSStefan Eßer 			{
216744d4804dSStefan Eßer 				// This is a leaf and cannot come right after a leaf.
216844d4804dSStefan Eßer 				if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn)))
216944d4804dSStefan Eßer 					bc_parse_err(p, BC_ERR_PARSE_EXPR);
217044d4804dSStefan Eßer 
217144d4804dSStefan Eßer 				bc_parse_builtin3(p, t, flags, &prev);
217244d4804dSStefan Eßer 
217344d4804dSStefan Eßer 				rprn = get_token = bin_last = incdec = can_assign = false;
217444d4804dSStefan Eßer 				nexprs += 1;
217544d4804dSStefan Eßer 				flags &= ~(BC_PARSE_ARRAY);
217644d4804dSStefan Eßer 
217744d4804dSStefan Eßer 				break;
217844d4804dSStefan Eßer 			}
217944d4804dSStefan Eßer 
218050696a6eSStefan Eßer 			default:
218150696a6eSStefan Eßer 			{
218250696a6eSStefan Eßer #ifndef NDEBUG
218344d4804dSStefan Eßer 				// We should never get here, even in debug builds.
218450696a6eSStefan Eßer 				bc_parse_err(p, BC_ERR_PARSE_TOKEN);
218550696a6eSStefan Eßer 				break;
218650696a6eSStefan Eßer #endif // NDEBUG
218750696a6eSStefan Eßer 			}
218850696a6eSStefan Eßer 		}
218950696a6eSStefan Eßer 
219050696a6eSStefan Eßer 		if (get_token) bc_lex_next(&p->l);
219150696a6eSStefan Eßer 	}
219250696a6eSStefan Eßer 
219344d4804dSStefan Eßer 	// Now that we have parsed the expression, we need to empty the operator
219444d4804dSStefan Eßer 	// stack.
219550696a6eSStefan Eßer 	while (p->ops.len > ops_bgn) {
219650696a6eSStefan Eßer 
219750696a6eSStefan Eßer 		top = BC_PARSE_TOP_OP(p);
219850696a6eSStefan Eßer 		assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN;
219950696a6eSStefan Eßer 
220044d4804dSStefan Eßer 		// There should not be *any* parens on the stack anymore.
220150696a6eSStefan Eßer 		if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN))
220250696a6eSStefan Eßer 			bc_parse_err(p, BC_ERR_PARSE_EXPR);
220350696a6eSStefan Eßer 
220450696a6eSStefan Eßer 		bc_parse_push(p, BC_PARSE_TOKEN_INST(top));
220550696a6eSStefan Eßer 
220644d4804dSStefan Eßer 		// Adjust the number of unused expressions.
220750696a6eSStefan Eßer 		nexprs -= !BC_PARSE_OP_PREFIX(top);
220850696a6eSStefan Eßer 		bc_vec_pop(&p->ops);
220950696a6eSStefan Eßer 
221050696a6eSStefan Eßer 		incdec = false;
221150696a6eSStefan Eßer 	}
221250696a6eSStefan Eßer 
221344d4804dSStefan Eßer 	// There must be only one expression at the top.
221450696a6eSStefan Eßer 	if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR);
221550696a6eSStefan Eßer 
221644d4804dSStefan Eßer 	// Check that the next token is correct.
221750696a6eSStefan Eßer 	for (i = 0; i < next.len && t != next.tokens[i]; ++i);
221850696a6eSStefan Eßer 	if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p)))
221950696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EXPR);
222050696a6eSStefan Eßer 
222144d4804dSStefan Eßer 	// Check that POSIX would be happy with the number of relational operators.
222250696a6eSStefan Eßer 	if (!(flags & BC_PARSE_REL) && nrelops)
222350696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_REL_POS);
222450696a6eSStefan Eßer 	else if ((flags & BC_PARSE_REL) && nrelops > 1)
222550696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_POSIX_MULTIREL);
222650696a6eSStefan Eßer 
222744d4804dSStefan Eßer 	// If this is true, then we might be in a situation where we don't print.
222844d4804dSStefan Eßer 	// We would want to have the increment/decrement operator not make an extra
222944d4804dSStefan Eßer 	// copy if it's not necessary.
223050696a6eSStefan Eßer 	if (!(flags & BC_PARSE_NEEDVAL) && !pfirst) {
223150696a6eSStefan Eßer 
223244d4804dSStefan Eßer 		// We have the easy case if the last operator was an assignment
223344d4804dSStefan Eßer 		// operator.
223450696a6eSStefan Eßer 		if (assign) {
223550696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
223650696a6eSStefan Eßer 			inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER);
223750696a6eSStefan Eßer 			incdec = false;
223850696a6eSStefan Eßer 		}
223944d4804dSStefan Eßer 		// If we have an inc/dec operator and we are *not* printing, implement
224044d4804dSStefan Eßer 		// the optimization to get rid of the extra copy.
224150696a6eSStefan Eßer 		else if (incdec && !(flags & BC_PARSE_PRINT)) {
224250696a6eSStefan Eßer 			inst = *((uchar*) bc_vec_top(&p->func->code));
224350696a6eSStefan Eßer 			incdec = (inst <= BC_INST_DEC);
224450696a6eSStefan Eßer 			inst = BC_INST_ASSIGN_PLUS_NO_VAL + (inst != BC_INST_INC &&
224550696a6eSStefan Eßer 			                                     inst != BC_INST_ASSIGN_PLUS);
224650696a6eSStefan Eßer 		}
224750696a6eSStefan Eßer 
224844d4804dSStefan Eßer 		// This condition allows us to change the previous assignment
224944d4804dSStefan Eßer 		// instruction (which does a copy) for a NO_VAL version, which does not.
225044d4804dSStefan Eßer 		// This condition is set if either of the above if statements ends up
225144d4804dSStefan Eßer 		// being true.
225250696a6eSStefan Eßer 		if (inst >= BC_INST_ASSIGN_POWER_NO_VAL &&
225350696a6eSStefan Eßer 		    inst <= BC_INST_ASSIGN_NO_VAL)
225450696a6eSStefan Eßer 		{
225544d4804dSStefan Eßer 			// Pop the previous assignment instruction and push a new one.
225644d4804dSStefan Eßer 			// Inc/dec needs the extra instruction because it is now a binary
225744d4804dSStefan Eßer 			// operator and needs a second operand.
225850696a6eSStefan Eßer 			bc_vec_pop(&p->func->code);
225950696a6eSStefan Eßer 			if (incdec) bc_parse_push(p, BC_INST_ONE);
226050696a6eSStefan Eßer 			bc_parse_push(p, inst);
226150696a6eSStefan Eßer 		}
226250696a6eSStefan Eßer 	}
226350696a6eSStefan Eßer 
226444d4804dSStefan Eßer 	// If we might have to print...
226550696a6eSStefan Eßer 	if ((flags & BC_PARSE_PRINT)) {
226644d4804dSStefan Eßer 
226744d4804dSStefan Eßer 		// With a paren first or the last operator not being an assignment, we
226844d4804dSStefan Eßer 		// *do* want to print.
226950696a6eSStefan Eßer 		if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT);
227050696a6eSStefan Eßer 	}
227144d4804dSStefan Eßer 	// We need to make sure to push a pop instruction for assignment statements
227244d4804dSStefan Eßer 	// that will not print. The print will pop, but without it, we need to pop.
227350696a6eSStefan Eßer 	else if (!(flags & BC_PARSE_NEEDVAL) &&
227450696a6eSStefan Eßer 	         (inst < BC_INST_ASSIGN_POWER_NO_VAL ||
227550696a6eSStefan Eßer 	          inst > BC_INST_ASSIGN_NO_VAL))
227650696a6eSStefan Eßer 	{
227750696a6eSStefan Eßer 		bc_parse_push(p, BC_INST_POP);
227850696a6eSStefan Eßer 	}
227950696a6eSStefan Eßer 
228050696a6eSStefan Eßer 	// We want to eat newlines if newlines are not a valid ending token.
228150696a6eSStefan Eßer 	// This is for spacing in things like for loop headers.
228244d4804dSStefan Eßer 	//
228344d4804dSStefan Eßer 	// Yes, this is one case where I reuse a variable for a different purpose;
228444d4804dSStefan Eßer 	// in this case, incdec being true now means that newlines are not valid.
228550696a6eSStefan Eßer 	for (incdec = true, i = 0; i < next.len && incdec; ++i)
228650696a6eSStefan Eßer 		incdec = (next.tokens[i] != BC_LEX_NLINE);
228750696a6eSStefan Eßer 	if (incdec) {
228850696a6eSStefan Eßer 		while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l);
228950696a6eSStefan Eßer 	}
229050696a6eSStefan Eßer 
229150696a6eSStefan Eßer 	return BC_PARSE_STATUS_SUCCESS;
229250696a6eSStefan Eßer }
229350696a6eSStefan Eßer 
229444d4804dSStefan Eßer /**
229544d4804dSStefan Eßer  * Parses an expression with bc_parse_expr_err(), but throws an error if it gets
229644d4804dSStefan Eßer  * an empty expression.
229744d4804dSStefan Eßer  * @param p      The parser.
229844d4804dSStefan Eßer  * @param flags  The flags for what is valid in the expression.
229944d4804dSStefan Eßer  * @param next   A set of tokens for what is valid *after* the expression.
230044d4804dSStefan Eßer  */
230144d4804dSStefan Eßer static void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) {
230250696a6eSStefan Eßer 
230350696a6eSStefan Eßer 	BcParseStatus s = bc_parse_expr_err(p, flags, next);
230450696a6eSStefan Eßer 
230550696a6eSStefan Eßer 	if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR))
230650696a6eSStefan Eßer 		bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR);
230750696a6eSStefan Eßer }
230850696a6eSStefan Eßer 
230950696a6eSStefan Eßer void bc_parse_expr(BcParse *p, uint8_t flags) {
231050696a6eSStefan Eßer 	assert(p);
231150696a6eSStefan Eßer 	bc_parse_expr_status(p, flags, bc_parse_next_read);
231250696a6eSStefan Eßer }
231350696a6eSStefan Eßer #endif // BC_ENABLED
2314