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