150696a6eSStefan Eßer /* 250696a6eSStefan Eßer * ***************************************************************************** 350696a6eSStefan Eßer * 450696a6eSStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 550696a6eSStefan Eßer * 6*d101cdd6SStefan Eßer * Copyright (c) 2018-2023 Gavin D. Howard and contributors. 750696a6eSStefan Eßer * 850696a6eSStefan Eßer * Redistribution and use in source and binary forms, with or without 950696a6eSStefan Eßer * modification, are permitted provided that the following conditions are met: 1050696a6eSStefan Eßer * 1150696a6eSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 1250696a6eSStefan Eßer * list of conditions and the following disclaimer. 1350696a6eSStefan Eßer * 1450696a6eSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 1550696a6eSStefan Eßer * this list of conditions and the following disclaimer in the documentation 1650696a6eSStefan Eßer * and/or other materials provided with the distribution. 1750696a6eSStefan Eßer * 1850696a6eSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1950696a6eSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2050696a6eSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2150696a6eSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2250696a6eSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2350696a6eSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2450696a6eSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2550696a6eSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2650696a6eSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2750696a6eSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2850696a6eSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 2950696a6eSStefan Eßer * 3050696a6eSStefan Eßer * ***************************************************************************** 3150696a6eSStefan Eßer * 3250696a6eSStefan Eßer * The parser for bc. 3350696a6eSStefan Eßer * 3450696a6eSStefan Eßer */ 3550696a6eSStefan Eßer 3650696a6eSStefan Eßer #if BC_ENABLED 3750696a6eSStefan Eßer 3850696a6eSStefan Eßer #include <assert.h> 3950696a6eSStefan Eßer #include <stdbool.h> 4050696a6eSStefan Eßer #include <stdlib.h> 4150696a6eSStefan Eßer #include <string.h> 4250696a6eSStefan Eßer 4350696a6eSStefan Eßer #include <setjmp.h> 4450696a6eSStefan Eßer 4550696a6eSStefan Eßer #include <bc.h> 4650696a6eSStefan Eßer #include <num.h> 4750696a6eSStefan Eßer #include <vm.h> 4850696a6eSStefan Eßer 4944d4804dSStefan Eßer // Before you embark on trying to understand this code, have you read the 5044d4804dSStefan Eßer // Development manual (manuals/development.md) and the comment in include/bc.h 5144d4804dSStefan Eßer // yet? No? Do that first. I'm serious. 5244d4804dSStefan Eßer // 5344d4804dSStefan Eßer // The reason is because this file holds the most sensitive and finicky code in 5444d4804dSStefan Eßer // the entire codebase. Even getting history to work on Windows was nothing 5544d4804dSStefan Eßer // compared to this. This is where dreams go to die, where dragons live, and 5644d4804dSStefan Eßer // from which Ken Thompson himself would flee. 5744d4804dSStefan Eßer 5878bc019dSStefan Eßer static void 5978bc019dSStefan Eßer bc_parse_else(BcParse* p); 6078bc019dSStefan Eßer 6178bc019dSStefan Eßer static void 6278bc019dSStefan Eßer bc_parse_stmt(BcParse* p); 6378bc019dSStefan Eßer 6478bc019dSStefan Eßer static BcParseStatus 6578bc019dSStefan Eßer bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next); 6678bc019dSStefan Eßer 6778bc019dSStefan Eßer static void 6878bc019dSStefan Eßer bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next); 6950696a6eSStefan Eßer 7044d4804dSStefan Eßer /** 7144d4804dSStefan Eßer * Returns true if an instruction could only have come from a "leaf" expression. 7244d4804dSStefan Eßer * For more on what leaf expressions are, read the comment for BC_PARSE_LEAF(). 7344d4804dSStefan Eßer * @param t The instruction to test. 74*d101cdd6SStefan 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 { 79*d101cdd6SStefan 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 210*d101cdd6SStefan 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 258*d101cdd6SStefan 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 264*d101cdd6SStefan Eßer // If it's a left paren, we have reached the end of whatever expression 265*d101cdd6SStefan Eßer // this is no matter what. We also don't pop the left paren because it 266*d101cdd6SStefan 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. 273*d101cdd6SStefan Eßer // 274*d101cdd6SStefan 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 279*d101cdd6SStefan Eßer // expression was consumed (well, two were, but another was added) if 280*d101cdd6SStefan Eßer // the operator was not a prefix operator. (Postfix operators are not 281*d101cdd6SStefan 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. 398*d101cdd6SStefan Eßer * @param p The parser. 399*d101cdd6SStefan Eßer * @param type A pointer to return the resulting instruction. 400*d101cdd6SStefan Eßer * @param can_assign A pointer to return true if the name can be assigned to, 401*d101cdd6SStefan Eßer * false otherwise. 402*d101cdd6SStefan 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 414*d101cdd6SStefan 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); 487*d101cdd6SStefan 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. 535*d101cdd6SStefan Eßer if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY) 536*d101cdd6SStefan Eßer { 537*d101cdd6SStefan Eßer flags |= BC_PARSE_ARRAY; 538*d101cdd6SStefan Eßer } 539*d101cdd6SStefan Eßer 540*d101cdd6SStefan Eßer // Otherwise, we need to clear it because it could be set. 541*d101cdd6SStefan 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(). 558*d101cdd6SStefan Eßer * @param p The parser. 559*d101cdd6SStefan Eßer * @param type The lex token. 560*d101cdd6SStefan Eßer * @param flags The expression parsing flags for parsing the argument. 561*d101cdd6SStefan 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. 750*d101cdd6SStefan 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. 1113*d101cdd6SStefan Eßer BcMode mode = vm->mode; 1114a30efc5cSStefan Eßer 1115*d101cdd6SStefan 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 1124*d101cdd6SStefan 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. 1127*d101cdd6SStefan 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: 1715*d101cdd6SStefan Eßer case BC_LEX_KW_IS_NUMBER: 1716*d101cdd6SStefan 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. 1828*d101cdd6SStefan 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 1845*d101cdd6SStefan Eßer case BC_LEX_EOF: 1846*d101cdd6SStefan Eßer case BC_LEX_INVALID: 1847*d101cdd6SStefan Eßer case BC_LEX_NEG: 1848*d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH 1849*d101cdd6SStefan Eßer case BC_LEX_OP_TRUNC: 1850*d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1851*d101cdd6SStefan Eßer case BC_LEX_OP_POWER: 1852*d101cdd6SStefan Eßer case BC_LEX_OP_MULTIPLY: 1853*d101cdd6SStefan Eßer case BC_LEX_OP_DIVIDE: 1854*d101cdd6SStefan Eßer case BC_LEX_OP_MODULUS: 1855*d101cdd6SStefan Eßer case BC_LEX_OP_PLUS: 1856*d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH 1857*d101cdd6SStefan Eßer case BC_LEX_OP_PLACES: 1858*d101cdd6SStefan Eßer case BC_LEX_OP_LSHIFT: 1859*d101cdd6SStefan Eßer case BC_LEX_OP_RSHIFT: 1860*d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1861*d101cdd6SStefan Eßer case BC_LEX_OP_REL_EQ: 1862*d101cdd6SStefan Eßer case BC_LEX_OP_REL_LE: 1863*d101cdd6SStefan Eßer case BC_LEX_OP_REL_GE: 1864*d101cdd6SStefan Eßer case BC_LEX_OP_REL_NE: 1865*d101cdd6SStefan Eßer case BC_LEX_OP_REL_LT: 1866*d101cdd6SStefan Eßer case BC_LEX_OP_REL_GT: 1867*d101cdd6SStefan Eßer case BC_LEX_OP_BOOL_OR: 1868*d101cdd6SStefan Eßer case BC_LEX_OP_BOOL_AND: 1869*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_POWER: 1870*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_MULTIPLY: 1871*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_DIVIDE: 1872*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_MODULUS: 1873*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_PLUS: 1874*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_MINUS: 1875*d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH 1876*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_PLACES: 1877*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_LSHIFT: 1878*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN_RSHIFT: 1879*d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1880*d101cdd6SStefan Eßer case BC_LEX_OP_ASSIGN: 1881*d101cdd6SStefan Eßer case BC_LEX_NLINE: 1882*d101cdd6SStefan Eßer case BC_LEX_WHITESPACE: 1883*d101cdd6SStefan Eßer case BC_LEX_RPAREN: 1884*d101cdd6SStefan Eßer case BC_LEX_LBRACKET: 1885*d101cdd6SStefan Eßer case BC_LEX_COMMA: 1886*d101cdd6SStefan Eßer case BC_LEX_RBRACKET: 1887*d101cdd6SStefan Eßer case BC_LEX_LBRACE: 1888*d101cdd6SStefan Eßer case BC_LEX_KW_AUTO: 1889*d101cdd6SStefan Eßer case BC_LEX_KW_DEFINE: 1890*d101cdd6SStefan Eßer #if DC_ENABLED 1891*d101cdd6SStefan Eßer case BC_LEX_EQ_NO_REG: 1892*d101cdd6SStefan Eßer case BC_LEX_COLON: 1893*d101cdd6SStefan Eßer case BC_LEX_EXECUTE: 1894*d101cdd6SStefan Eßer case BC_LEX_PRINT_STACK: 1895*d101cdd6SStefan Eßer case BC_LEX_CLEAR_STACK: 1896*d101cdd6SStefan Eßer case BC_LEX_REG_STACK_LEVEL: 1897*d101cdd6SStefan Eßer case BC_LEX_STACK_LEVEL: 1898*d101cdd6SStefan Eßer case BC_LEX_DUPLICATE: 1899*d101cdd6SStefan Eßer case BC_LEX_SWAP: 1900*d101cdd6SStefan Eßer case BC_LEX_POP: 1901*d101cdd6SStefan Eßer case BC_LEX_STORE_IBASE: 1902*d101cdd6SStefan Eßer case BC_LEX_STORE_OBASE: 1903*d101cdd6SStefan Eßer case BC_LEX_STORE_SCALE: 1904*d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH 1905*d101cdd6SStefan Eßer case BC_LEX_STORE_SEED: 1906*d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 1907*d101cdd6SStefan Eßer case BC_LEX_LOAD: 1908*d101cdd6SStefan Eßer case BC_LEX_LOAD_POP: 1909*d101cdd6SStefan Eßer case BC_LEX_STORE_PUSH: 1910*d101cdd6SStefan Eßer case BC_LEX_PRINT_POP: 1911*d101cdd6SStefan Eßer case BC_LEX_NQUIT: 1912*d101cdd6SStefan Eßer case BC_LEX_EXEC_STACK_LENGTH: 1913*d101cdd6SStefan Eßer case BC_LEX_SCALE_FACTOR: 1914*d101cdd6SStefan Eßer case BC_LEX_ARRAY_LENGTH: 1915*d101cdd6SStefan Eßer #endif // DC_ENABLED 191650696a6eSStefan Eßer { 191750696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_TOKEN); 191850696a6eSStefan Eßer } 191950696a6eSStefan Eßer } 192050696a6eSStefan Eßer 192144d4804dSStefan Eßer // If the flags did not change, we expect a delimiter. 192278bc019dSStefan Eßer if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) 192378bc019dSStefan Eßer { 192450696a6eSStefan Eßer if (BC_ERR(!bc_parse_isDelimiter(p))) 192578bc019dSStefan Eßer { 192650696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_TOKEN); 192750696a6eSStefan Eßer } 192878bc019dSStefan Eßer } 192950696a6eSStefan Eßer 193050696a6eSStefan Eßer // Make sure semicolons are eaten. 1931*d101cdd6SStefan Eßer while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE) 193278bc019dSStefan Eßer { 193378bc019dSStefan Eßer bc_lex_next(&p->l); 193478bc019dSStefan Eßer } 193510041e99SStefan Eßer 193610041e99SStefan Eßer // POSIX's grammar does not allow a function definition after a semicolon 193710041e99SStefan Eßer // without a newline, so check specifically for that case and error if 193810041e99SStefan Eßer // the POSIX standard flag is set. 193910041e99SStefan Eßer if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX) 194010041e99SStefan Eßer { 194110041e99SStefan Eßer bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON); 194210041e99SStefan Eßer } 194350696a6eSStefan Eßer } 194450696a6eSStefan Eßer 194578bc019dSStefan Eßer void 194678bc019dSStefan Eßer bc_parse_parse(BcParse* p) 194778bc019dSStefan Eßer { 194850696a6eSStefan Eßer assert(p); 194950696a6eSStefan Eßer 1950*d101cdd6SStefan Eßer BC_SETJMP_LOCKED(vm, exit); 195150696a6eSStefan Eßer 195244d4804dSStefan Eßer // We should not let an EOF get here unless some partial parse was not 195344d4804dSStefan Eßer // completed, in which case, it's the user's fault. 195450696a6eSStefan Eßer if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF); 195544d4804dSStefan Eßer 195644d4804dSStefan Eßer // Functions need special parsing. 195778bc019dSStefan Eßer else if (p->l.t == BC_LEX_KW_DEFINE) 195878bc019dSStefan Eßer { 195978bc019dSStefan Eßer if (BC_ERR(BC_PARSE_NO_EXEC(p))) 196078bc019dSStefan Eßer { 1961a30efc5cSStefan Eßer bc_parse_endif(p); 1962a30efc5cSStefan Eßer if (BC_ERR(BC_PARSE_NO_EXEC(p))) 196378bc019dSStefan Eßer { 1964a30efc5cSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_TOKEN); 1965d43fa8efSStefan Eßer } 196678bc019dSStefan Eßer } 196750696a6eSStefan Eßer bc_parse_func(p); 196850696a6eSStefan Eßer } 196944d4804dSStefan Eßer 197044d4804dSStefan Eßer // Otherwise, parse a normal statement. 197150696a6eSStefan Eßer else bc_parse_stmt(p); 197250696a6eSStefan Eßer 197350696a6eSStefan Eßer exit: 197444d4804dSStefan Eßer 197544d4804dSStefan Eßer // We need to reset on error. 1976*d101cdd6SStefan Eßer if (BC_ERR(((vm->status && vm->status != BC_STATUS_QUIT) || vm->sig != 0))) 197778bc019dSStefan Eßer { 197850696a6eSStefan Eßer bc_parse_reset(p); 197978bc019dSStefan Eßer } 198044d4804dSStefan Eßer 1981*d101cdd6SStefan Eßer BC_LONGJMP_CONT(vm); 198210041e99SStefan Eßer BC_SIG_MAYLOCK; 198350696a6eSStefan Eßer } 198450696a6eSStefan Eßer 198544d4804dSStefan Eßer /** 198644d4804dSStefan Eßer * Parse an expression. This is the actual implementation of the Shunting-Yard 198744d4804dSStefan Eßer * Algorithm. 198844d4804dSStefan Eßer * @param p The parser. 198944d4804dSStefan Eßer * @param flags The flags for what is valid in the expression. 199044d4804dSStefan Eßer * @param next A set of tokens for what is valid *after* the expression. 199144d4804dSStefan Eßer * @return A parse status. In some places, an empty expression is an 199244d4804dSStefan Eßer * error, and sometimes, it is required. This allows this function 199344d4804dSStefan Eßer * to tell the caller if the expression was empty and let the 199444d4804dSStefan Eßer * caller handle it. 199544d4804dSStefan Eßer */ 199678bc019dSStefan Eßer static BcParseStatus 199778bc019dSStefan Eßer bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next) 199850696a6eSStefan Eßer { 199950696a6eSStefan Eßer BcInst prev = BC_INST_PRINT; 200050696a6eSStefan Eßer uchar inst = BC_INST_INVALID; 200144d4804dSStefan Eßer BcLexType top, t; 200244d4804dSStefan Eßer size_t nexprs, ops_bgn; 200350696a6eSStefan Eßer uint32_t i, nparens, nrelops; 200450696a6eSStefan Eßer bool pfirst, rprn, done, get_token, assign, bin_last, incdec, can_assign; 200550696a6eSStefan Eßer 200644d4804dSStefan Eßer // One of these *must* be true. 200750696a6eSStefan Eßer assert(!(flags & BC_PARSE_PRINT) || !(flags & BC_PARSE_NEEDVAL)); 200850696a6eSStefan Eßer 200944d4804dSStefan Eßer // These are set very carefully. In fact, controlling the values of these 201044d4804dSStefan Eßer // locals is the biggest part of making this work. ops_bgn especially is 201144d4804dSStefan Eßer // important because it marks where the operator stack begins for *this* 201244d4804dSStefan Eßer // invocation of this function. That's because bc_parse_expr_err() is 201344d4804dSStefan Eßer // recursive (the Shunting-Yard Algorithm is most easily expressed 201444d4804dSStefan Eßer // recursively when parsing subexpressions), and each invocation needs to 201544d4804dSStefan Eßer // know where to stop. 201644d4804dSStefan Eßer // 201744d4804dSStefan Eßer // - nparens is the number of left parens without matches. 201844d4804dSStefan Eßer // - nrelops is the number of relational operators that appear in the expr. 201944d4804dSStefan Eßer // - nexprs is the number of unused expressions. 202044d4804dSStefan Eßer // - rprn is a right paren encountered last. 202144d4804dSStefan Eßer // - done means the expression has been fully parsed. 202244d4804dSStefan Eßer // - get_token is true when a token is needed at the end of an iteration. 202344d4804dSStefan Eßer // - assign is true when an assignment statement was parsed last. 202444d4804dSStefan Eßer // - incdec is true when the previous operator was an inc or dec operator. 202544d4804dSStefan Eßer // - can_assign is true when an assignemnt is valid. 202644d4804dSStefan Eßer // - bin_last is true when the previous instruction was a binary operator. 202744d4804dSStefan Eßer t = p->l.t; 202850696a6eSStefan Eßer pfirst = (p->l.t == BC_LEX_LPAREN); 202950696a6eSStefan Eßer nparens = nrelops = 0; 203044d4804dSStefan Eßer nexprs = 0; 203144d4804dSStefan Eßer ops_bgn = p->ops.len; 203250696a6eSStefan Eßer rprn = done = get_token = assign = incdec = can_assign = false; 203350696a6eSStefan Eßer bin_last = true; 203450696a6eSStefan Eßer 203550696a6eSStefan Eßer // We want to eat newlines if newlines are not a valid ending token. 203650696a6eSStefan Eßer // This is for spacing in things like for loop headers. 203778bc019dSStefan Eßer if (!(flags & BC_PARSE_NOREAD)) 203878bc019dSStefan Eßer { 203978bc019dSStefan Eßer while ((t = p->l.t) == BC_LEX_NLINE) 204078bc019dSStefan Eßer { 204178bc019dSStefan Eßer bc_lex_next(&p->l); 204278bc019dSStefan Eßer } 204350696a6eSStefan Eßer } 204450696a6eSStefan Eßer 204544d4804dSStefan Eßer // This is the Shunting-Yard algorithm loop. 204650696a6eSStefan Eßer for (; !done && BC_PARSE_EXPR(t); t = p->l.t) 204750696a6eSStefan Eßer { 204878bc019dSStefan Eßer switch (t) 204978bc019dSStefan Eßer { 205050696a6eSStefan Eßer case BC_LEX_OP_INC: 205150696a6eSStefan Eßer case BC_LEX_OP_DEC: 205250696a6eSStefan Eßer { 205344d4804dSStefan Eßer // These operators can only be used with items that can be 205444d4804dSStefan Eßer // assigned to. 205550696a6eSStefan Eßer if (BC_ERR(incdec)) bc_parse_err(p, BC_ERR_PARSE_ASSIGN); 205644d4804dSStefan Eßer 205750696a6eSStefan Eßer bc_parse_incdec(p, &prev, &can_assign, &nexprs, flags); 205844d4804dSStefan Eßer 205950696a6eSStefan Eßer rprn = get_token = bin_last = false; 206050696a6eSStefan Eßer incdec = true; 206150696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 206244d4804dSStefan Eßer 206350696a6eSStefan Eßer break; 206450696a6eSStefan Eßer } 206550696a6eSStefan Eßer 206650696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 206750696a6eSStefan Eßer case BC_LEX_OP_TRUNC: 206850696a6eSStefan Eßer { 206944d4804dSStefan Eßer // The previous token must have been a leaf expression, or the 207044d4804dSStefan Eßer // operator is in the wrong place. 207150696a6eSStefan Eßer if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn))) 207278bc019dSStefan Eßer { 207350696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_TOKEN); 207478bc019dSStefan Eßer } 207550696a6eSStefan Eßer 207650696a6eSStefan Eßer // I can just add the instruction because 207750696a6eSStefan Eßer // negative will already be taken care of. 207850696a6eSStefan Eßer bc_parse_push(p, BC_INST_TRUNC); 207944d4804dSStefan Eßer 208050696a6eSStefan Eßer rprn = can_assign = incdec = false; 208150696a6eSStefan Eßer get_token = true; 208250696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 208344d4804dSStefan Eßer 208450696a6eSStefan Eßer break; 208550696a6eSStefan Eßer } 208650696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 208750696a6eSStefan Eßer 208850696a6eSStefan Eßer case BC_LEX_OP_MINUS: 208950696a6eSStefan Eßer { 209050696a6eSStefan Eßer bc_parse_minus(p, &prev, ops_bgn, rprn, bin_last, &nexprs); 209144d4804dSStefan Eßer 209250696a6eSStefan Eßer rprn = get_token = can_assign = false; 209344d4804dSStefan Eßer 209444d4804dSStefan Eßer // This is true if it was a binary operator last. 209550696a6eSStefan Eßer bin_last = (prev == BC_INST_MINUS); 209650696a6eSStefan Eßer if (bin_last) incdec = false; 209744d4804dSStefan Eßer 209850696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 209944d4804dSStefan Eßer 210050696a6eSStefan Eßer break; 210150696a6eSStefan Eßer } 210250696a6eSStefan Eßer 210344d4804dSStefan Eßer // All of this group, including the fallthrough, is to parse binary 210444d4804dSStefan Eßer // operators. 210550696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_POWER: 210650696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_MULTIPLY: 210750696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_DIVIDE: 210850696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_MODULUS: 210950696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_PLUS: 211050696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_MINUS: 211150696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 211250696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_PLACES: 211350696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_LSHIFT: 211450696a6eSStefan Eßer case BC_LEX_OP_ASSIGN_RSHIFT: 211550696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 211650696a6eSStefan Eßer case BC_LEX_OP_ASSIGN: 211750696a6eSStefan Eßer { 211844d4804dSStefan Eßer // We need to make sure the assignment is valid. 211950696a6eSStefan Eßer if (!BC_PARSE_INST_VAR(prev)) 212078bc019dSStefan Eßer { 212150696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_ASSIGN); 212250696a6eSStefan Eßer } 212378bc019dSStefan Eßer 212450696a6eSStefan Eßer // Fallthrough. 212550696a6eSStefan Eßer BC_FALLTHROUGH 212678bc019dSStefan Eßer } 212750696a6eSStefan Eßer 212850696a6eSStefan Eßer case BC_LEX_OP_POWER: 212950696a6eSStefan Eßer case BC_LEX_OP_MULTIPLY: 213050696a6eSStefan Eßer case BC_LEX_OP_DIVIDE: 213150696a6eSStefan Eßer case BC_LEX_OP_MODULUS: 213250696a6eSStefan Eßer case BC_LEX_OP_PLUS: 213350696a6eSStefan Eßer #if BC_ENABLE_EXTRA_MATH 213450696a6eSStefan Eßer case BC_LEX_OP_PLACES: 213550696a6eSStefan Eßer case BC_LEX_OP_LSHIFT: 213650696a6eSStefan Eßer case BC_LEX_OP_RSHIFT: 213750696a6eSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 213850696a6eSStefan Eßer case BC_LEX_OP_REL_EQ: 213950696a6eSStefan Eßer case BC_LEX_OP_REL_LE: 214050696a6eSStefan Eßer case BC_LEX_OP_REL_GE: 214150696a6eSStefan Eßer case BC_LEX_OP_REL_NE: 214250696a6eSStefan Eßer case BC_LEX_OP_REL_LT: 214350696a6eSStefan Eßer case BC_LEX_OP_REL_GT: 214450696a6eSStefan Eßer case BC_LEX_OP_BOOL_NOT: 214550696a6eSStefan Eßer case BC_LEX_OP_BOOL_OR: 214650696a6eSStefan Eßer case BC_LEX_OP_BOOL_AND: 214750696a6eSStefan Eßer { 214844d4804dSStefan Eßer // This is true if the operator if the token is a prefix 214944d4804dSStefan Eßer // operator. This is only for boolean not. 215078bc019dSStefan Eßer if (BC_PARSE_OP_PREFIX(t)) 215178bc019dSStefan Eßer { 215244d4804dSStefan Eßer // Prefix operators are only allowed after binary operators 215344d4804dSStefan Eßer // or prefix operators. 215450696a6eSStefan Eßer if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last))) 215578bc019dSStefan Eßer { 215650696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 215750696a6eSStefan Eßer } 215878bc019dSStefan Eßer } 215944d4804dSStefan Eßer // If we execute the else, that means we have a binary operator. 216044d4804dSStefan Eßer // If the previous operator was a prefix or a binary operator, 216144d4804dSStefan Eßer // then a binary operator is not allowed. 216250696a6eSStefan Eßer else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last)) 216378bc019dSStefan Eßer { 216450696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 216578bc019dSStefan Eßer } 216650696a6eSStefan Eßer 216750696a6eSStefan Eßer nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT); 216850696a6eSStefan Eßer prev = BC_PARSE_TOKEN_INST(t); 216944d4804dSStefan Eßer 217050696a6eSStefan Eßer bc_parse_operator(p, t, ops_bgn, &nexprs); 217144d4804dSStefan Eßer 217250696a6eSStefan Eßer rprn = incdec = can_assign = false; 217350696a6eSStefan Eßer get_token = true; 217450696a6eSStefan Eßer bin_last = !BC_PARSE_OP_PREFIX(t); 217550696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 217650696a6eSStefan Eßer 217750696a6eSStefan Eßer break; 217850696a6eSStefan Eßer } 217950696a6eSStefan Eßer 218050696a6eSStefan Eßer case BC_LEX_LPAREN: 218150696a6eSStefan Eßer { 218244d4804dSStefan Eßer // A left paren is *not* allowed right after a leaf expr. 218350696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 218478bc019dSStefan Eßer { 218550696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 218678bc019dSStefan Eßer } 218750696a6eSStefan Eßer 218850696a6eSStefan Eßer nparens += 1; 218950696a6eSStefan Eßer rprn = incdec = can_assign = false; 219050696a6eSStefan Eßer get_token = true; 219144d4804dSStefan Eßer 219244d4804dSStefan Eßer // Push the paren onto the operator stack. 219350696a6eSStefan Eßer bc_vec_push(&p->ops, &t); 219450696a6eSStefan Eßer 219550696a6eSStefan Eßer break; 219650696a6eSStefan Eßer } 219750696a6eSStefan Eßer 219850696a6eSStefan Eßer case BC_LEX_RPAREN: 219950696a6eSStefan Eßer { 220044d4804dSStefan Eßer // This needs to be a status. The error is handled in 220144d4804dSStefan Eßer // bc_parse_expr_status(). 220250696a6eSStefan Eßer if (BC_ERR(p->l.last == BC_LEX_LPAREN)) 220378bc019dSStefan Eßer { 220450696a6eSStefan Eßer return BC_PARSE_STATUS_EMPTY_EXPR; 220578bc019dSStefan Eßer } 220650696a6eSStefan Eßer 220744d4804dSStefan Eßer // The right paren must not come after a prefix or binary 220844d4804dSStefan Eßer // operator. 220950696a6eSStefan Eßer if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev))) 221078bc019dSStefan Eßer { 221150696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 221278bc019dSStefan Eßer } 221350696a6eSStefan Eßer 221444d4804dSStefan Eßer // If there are no parens left, we are done, but we need another 221544d4804dSStefan Eßer // token. 221678bc019dSStefan Eßer if (!nparens) 221778bc019dSStefan Eßer { 221850696a6eSStefan Eßer done = true; 221950696a6eSStefan Eßer get_token = false; 222050696a6eSStefan Eßer break; 222150696a6eSStefan Eßer } 222250696a6eSStefan Eßer 222350696a6eSStefan Eßer nparens -= 1; 222450696a6eSStefan Eßer rprn = true; 222550696a6eSStefan Eßer get_token = bin_last = incdec = false; 222650696a6eSStefan Eßer 222750696a6eSStefan Eßer bc_parse_rightParen(p, &nexprs); 222850696a6eSStefan Eßer 222950696a6eSStefan Eßer break; 223050696a6eSStefan Eßer } 223150696a6eSStefan Eßer 223244d4804dSStefan Eßer case BC_LEX_STR: 223344d4804dSStefan Eßer { 223444d4804dSStefan Eßer // POSIX only allows strings alone. 223544d4804dSStefan Eßer if (BC_IS_POSIX) bc_parse_err(p, BC_ERR_POSIX_EXPR_STRING); 223644d4804dSStefan Eßer 223744d4804dSStefan Eßer // A string is a leaf and cannot come right after a leaf. 223844d4804dSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 223978bc019dSStefan Eßer { 224044d4804dSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 224178bc019dSStefan Eßer } 224244d4804dSStefan Eßer 224344d4804dSStefan Eßer bc_parse_addString(p); 224444d4804dSStefan Eßer 224544d4804dSStefan Eßer get_token = true; 224644d4804dSStefan Eßer bin_last = rprn = false; 224744d4804dSStefan Eßer nexprs += 1; 224844d4804dSStefan Eßer 224944d4804dSStefan Eßer break; 225044d4804dSStefan Eßer } 225144d4804dSStefan Eßer 225250696a6eSStefan Eßer case BC_LEX_NAME: 225350696a6eSStefan Eßer { 225444d4804dSStefan Eßer // A name is a leaf and cannot come right after a leaf. 225550696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 225678bc019dSStefan Eßer { 225750696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 225878bc019dSStefan Eßer } 225950696a6eSStefan Eßer 226050696a6eSStefan Eßer get_token = bin_last = false; 226144d4804dSStefan Eßer 226244d4804dSStefan Eßer bc_parse_name(p, &prev, &can_assign, flags & ~BC_PARSE_NOCALL); 226344d4804dSStefan Eßer 226450696a6eSStefan Eßer rprn = (prev == BC_INST_CALL); 226550696a6eSStefan Eßer nexprs += 1; 226650696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 226750696a6eSStefan Eßer 226850696a6eSStefan Eßer break; 226950696a6eSStefan Eßer } 227050696a6eSStefan Eßer 227150696a6eSStefan Eßer case BC_LEX_NUMBER: 227250696a6eSStefan Eßer { 227344d4804dSStefan Eßer // A number 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 227944d4804dSStefan Eßer // The number instruction is pushed in here. 228050696a6eSStefan Eßer bc_parse_number(p); 228144d4804dSStefan Eßer 228250696a6eSStefan Eßer nexprs += 1; 228350696a6eSStefan Eßer prev = BC_INST_NUM; 228450696a6eSStefan Eßer get_token = true; 228550696a6eSStefan Eßer rprn = bin_last = can_assign = false; 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_KW_IBASE: 229250696a6eSStefan Eßer case BC_LEX_KW_LAST: 229350696a6eSStefan Eßer case BC_LEX_KW_OBASE: 229444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 229550696a6eSStefan Eßer case BC_LEX_KW_SEED: 229644d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 229750696a6eSStefan Eßer { 229844d4804dSStefan Eßer // All of these are leaves and cannot come right after a leaf. 229950696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 230078bc019dSStefan Eßer { 230150696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 230278bc019dSStefan Eßer } 230350696a6eSStefan Eßer 230450696a6eSStefan Eßer prev = t - BC_LEX_KW_LAST + BC_INST_LAST; 230550696a6eSStefan Eßer bc_parse_push(p, prev); 230650696a6eSStefan Eßer 230750696a6eSStefan Eßer get_token = can_assign = true; 230850696a6eSStefan Eßer rprn = bin_last = false; 230950696a6eSStefan Eßer nexprs += 1; 231050696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 231150696a6eSStefan Eßer 231250696a6eSStefan Eßer break; 231350696a6eSStefan Eßer } 231450696a6eSStefan Eßer 231550696a6eSStefan Eßer case BC_LEX_KW_LENGTH: 231650696a6eSStefan Eßer case BC_LEX_KW_SQRT: 231750696a6eSStefan Eßer case BC_LEX_KW_ABS: 2318*d101cdd6SStefan Eßer case BC_LEX_KW_IS_NUMBER: 2319*d101cdd6SStefan Eßer case BC_LEX_KW_IS_STRING: 232044d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 232150696a6eSStefan Eßer case BC_LEX_KW_IRAND: 232244d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 232344d4804dSStefan Eßer case BC_LEX_KW_ASCIIFY: 232450696a6eSStefan Eßer { 232544d4804dSStefan Eßer // All of these are leaves and cannot come right after a leaf. 232650696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 232778bc019dSStefan Eßer { 232850696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 232978bc019dSStefan Eßer } 233050696a6eSStefan Eßer 233150696a6eSStefan Eßer bc_parse_builtin(p, t, flags, &prev); 233244d4804dSStefan Eßer 233350696a6eSStefan Eßer rprn = get_token = bin_last = incdec = can_assign = false; 233450696a6eSStefan Eßer nexprs += 1; 233550696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 233650696a6eSStefan Eßer 233750696a6eSStefan Eßer break; 233850696a6eSStefan Eßer } 233950696a6eSStefan Eßer 234050696a6eSStefan Eßer case BC_LEX_KW_READ: 234144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 234250696a6eSStefan Eßer case BC_LEX_KW_RAND: 234344d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 234450696a6eSStefan Eßer case BC_LEX_KW_MAXIBASE: 234550696a6eSStefan Eßer case BC_LEX_KW_MAXOBASE: 234650696a6eSStefan Eßer case BC_LEX_KW_MAXSCALE: 234744d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 234850696a6eSStefan Eßer case BC_LEX_KW_MAXRAND: 234944d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 2350d43fa8efSStefan Eßer case BC_LEX_KW_LINE_LENGTH: 2351d43fa8efSStefan Eßer case BC_LEX_KW_GLOBAL_STACKS: 2352d43fa8efSStefan Eßer case BC_LEX_KW_LEADING_ZERO: 235350696a6eSStefan Eßer { 235444d4804dSStefan Eßer // All of these are leaves and cannot come right after a leaf. 235550696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 235678bc019dSStefan Eßer { 235750696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 235878bc019dSStefan Eßer } 235944d4804dSStefan Eßer 236044d4804dSStefan Eßer // Error if we have read and it's not allowed. 236150696a6eSStefan Eßer else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD)) 236278bc019dSStefan Eßer { 236350696a6eSStefan Eßer bc_parse_err(p, BC_ERR_EXEC_REC_READ); 236478bc019dSStefan Eßer } 236544d4804dSStefan Eßer 236650696a6eSStefan Eßer prev = t - BC_LEX_KW_READ + BC_INST_READ; 236750696a6eSStefan Eßer bc_parse_noArgBuiltin(p, prev); 236850696a6eSStefan Eßer 236950696a6eSStefan Eßer rprn = get_token = bin_last = incdec = can_assign = false; 237050696a6eSStefan Eßer nexprs += 1; 237150696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 237250696a6eSStefan Eßer 237350696a6eSStefan Eßer break; 237450696a6eSStefan Eßer } 237550696a6eSStefan Eßer 237650696a6eSStefan Eßer case BC_LEX_KW_SCALE: 237750696a6eSStefan Eßer { 237844d4804dSStefan Eßer // This is a leaf and cannot come right after a leaf. 237950696a6eSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 238078bc019dSStefan Eßer { 238150696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 238278bc019dSStefan Eßer } 238350696a6eSStefan Eßer 238444d4804dSStefan Eßer // Scale needs special work because it can be a variable *or* a 238544d4804dSStefan Eßer // function. 238650696a6eSStefan Eßer bc_parse_scale(p, &prev, &can_assign, flags); 238744d4804dSStefan Eßer 238850696a6eSStefan Eßer rprn = get_token = bin_last = false; 238950696a6eSStefan Eßer nexprs += 1; 239050696a6eSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 239150696a6eSStefan Eßer 239250696a6eSStefan Eßer break; 239350696a6eSStefan Eßer } 239450696a6eSStefan Eßer 239544d4804dSStefan Eßer case BC_LEX_KW_MODEXP: 239644d4804dSStefan Eßer case BC_LEX_KW_DIVMOD: 239744d4804dSStefan Eßer { 239844d4804dSStefan Eßer // This is a leaf and cannot come right after a leaf. 239944d4804dSStefan Eßer if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) 240078bc019dSStefan Eßer { 240144d4804dSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 240278bc019dSStefan Eßer } 240344d4804dSStefan Eßer 240444d4804dSStefan Eßer bc_parse_builtin3(p, t, flags, &prev); 240544d4804dSStefan Eßer 240644d4804dSStefan Eßer rprn = get_token = bin_last = incdec = can_assign = false; 240744d4804dSStefan Eßer nexprs += 1; 240844d4804dSStefan Eßer flags &= ~(BC_PARSE_ARRAY); 240944d4804dSStefan Eßer 241044d4804dSStefan Eßer break; 241144d4804dSStefan Eßer } 241244d4804dSStefan Eßer 2413*d101cdd6SStefan Eßer case BC_LEX_EOF: 2414*d101cdd6SStefan Eßer case BC_LEX_INVALID: 2415*d101cdd6SStefan Eßer case BC_LEX_NEG: 2416*d101cdd6SStefan Eßer case BC_LEX_NLINE: 2417*d101cdd6SStefan Eßer case BC_LEX_WHITESPACE: 2418*d101cdd6SStefan Eßer case BC_LEX_LBRACKET: 2419*d101cdd6SStefan Eßer case BC_LEX_COMMA: 2420*d101cdd6SStefan Eßer case BC_LEX_RBRACKET: 2421*d101cdd6SStefan Eßer case BC_LEX_LBRACE: 2422*d101cdd6SStefan Eßer case BC_LEX_SCOLON: 2423*d101cdd6SStefan Eßer case BC_LEX_RBRACE: 2424*d101cdd6SStefan Eßer case BC_LEX_KW_AUTO: 2425*d101cdd6SStefan Eßer case BC_LEX_KW_BREAK: 2426*d101cdd6SStefan Eßer case BC_LEX_KW_CONTINUE: 2427*d101cdd6SStefan Eßer case BC_LEX_KW_DEFINE: 2428*d101cdd6SStefan Eßer case BC_LEX_KW_FOR: 2429*d101cdd6SStefan Eßer case BC_LEX_KW_IF: 2430*d101cdd6SStefan Eßer case BC_LEX_KW_LIMITS: 2431*d101cdd6SStefan Eßer case BC_LEX_KW_RETURN: 2432*d101cdd6SStefan Eßer case BC_LEX_KW_WHILE: 2433*d101cdd6SStefan Eßer case BC_LEX_KW_HALT: 2434*d101cdd6SStefan Eßer case BC_LEX_KW_PRINT: 2435*d101cdd6SStefan Eßer case BC_LEX_KW_QUIT: 2436*d101cdd6SStefan Eßer case BC_LEX_KW_STREAM: 2437*d101cdd6SStefan Eßer case BC_LEX_KW_ELSE: 2438*d101cdd6SStefan Eßer #if DC_ENABLED 2439*d101cdd6SStefan Eßer case BC_LEX_EQ_NO_REG: 2440*d101cdd6SStefan Eßer case BC_LEX_COLON: 2441*d101cdd6SStefan Eßer case BC_LEX_EXECUTE: 2442*d101cdd6SStefan Eßer case BC_LEX_PRINT_STACK: 2443*d101cdd6SStefan Eßer case BC_LEX_CLEAR_STACK: 2444*d101cdd6SStefan Eßer case BC_LEX_REG_STACK_LEVEL: 2445*d101cdd6SStefan Eßer case BC_LEX_STACK_LEVEL: 2446*d101cdd6SStefan Eßer case BC_LEX_DUPLICATE: 2447*d101cdd6SStefan Eßer case BC_LEX_SWAP: 2448*d101cdd6SStefan Eßer case BC_LEX_POP: 2449*d101cdd6SStefan Eßer case BC_LEX_STORE_IBASE: 2450*d101cdd6SStefan Eßer case BC_LEX_STORE_OBASE: 2451*d101cdd6SStefan Eßer case BC_LEX_STORE_SCALE: 2452*d101cdd6SStefan Eßer #if BC_ENABLE_EXTRA_MATH 2453*d101cdd6SStefan Eßer case BC_LEX_STORE_SEED: 2454*d101cdd6SStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 2455*d101cdd6SStefan Eßer case BC_LEX_LOAD: 2456*d101cdd6SStefan Eßer case BC_LEX_LOAD_POP: 2457*d101cdd6SStefan Eßer case BC_LEX_STORE_PUSH: 2458*d101cdd6SStefan Eßer case BC_LEX_PRINT_POP: 2459*d101cdd6SStefan Eßer case BC_LEX_NQUIT: 2460*d101cdd6SStefan Eßer case BC_LEX_EXEC_STACK_LENGTH: 2461*d101cdd6SStefan Eßer case BC_LEX_SCALE_FACTOR: 2462*d101cdd6SStefan Eßer case BC_LEX_ARRAY_LENGTH: 2463*d101cdd6SStefan Eßer #endif // DC_ENABLED 246450696a6eSStefan Eßer { 246550696a6eSStefan Eßer #ifndef NDEBUG 246644d4804dSStefan Eßer // We should never get here, even in debug builds. 246750696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_TOKEN); 246850696a6eSStefan Eßer break; 246950696a6eSStefan Eßer #endif // NDEBUG 247050696a6eSStefan Eßer } 247150696a6eSStefan Eßer } 247250696a6eSStefan Eßer 247350696a6eSStefan Eßer if (get_token) bc_lex_next(&p->l); 247450696a6eSStefan Eßer } 247550696a6eSStefan Eßer 247644d4804dSStefan Eßer // Now that we have parsed the expression, we need to empty the operator 247744d4804dSStefan Eßer // stack. 247878bc019dSStefan Eßer while (p->ops.len > ops_bgn) 247978bc019dSStefan Eßer { 248050696a6eSStefan Eßer top = BC_PARSE_TOP_OP(p); 248150696a6eSStefan Eßer assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN; 248250696a6eSStefan Eßer 248344d4804dSStefan Eßer // There should not be *any* parens on the stack anymore. 248450696a6eSStefan Eßer if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)) 248578bc019dSStefan Eßer { 248650696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 248778bc019dSStefan Eßer } 248850696a6eSStefan Eßer 248950696a6eSStefan Eßer bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); 249050696a6eSStefan Eßer 249144d4804dSStefan Eßer // Adjust the number of unused expressions. 249250696a6eSStefan Eßer nexprs -= !BC_PARSE_OP_PREFIX(top); 249350696a6eSStefan Eßer bc_vec_pop(&p->ops); 249450696a6eSStefan Eßer 249550696a6eSStefan Eßer incdec = false; 249650696a6eSStefan Eßer } 249750696a6eSStefan Eßer 249844d4804dSStefan Eßer // There must be only one expression at the top. 249950696a6eSStefan Eßer if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR); 250050696a6eSStefan Eßer 250144d4804dSStefan Eßer // Check that the next token is correct. 250278bc019dSStefan Eßer for (i = 0; i < next.len && t != next.tokens[i]; ++i) 250378bc019dSStefan Eßer { 250478bc019dSStefan Eßer continue; 250578bc019dSStefan Eßer } 250650696a6eSStefan Eßer if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p))) 250778bc019dSStefan Eßer { 250850696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EXPR); 250978bc019dSStefan Eßer } 251050696a6eSStefan Eßer 251144d4804dSStefan Eßer // Check that POSIX would be happy with the number of relational operators. 251250696a6eSStefan Eßer if (!(flags & BC_PARSE_REL) && nrelops) 251378bc019dSStefan Eßer { 251450696a6eSStefan Eßer bc_parse_err(p, BC_ERR_POSIX_REL_POS); 251578bc019dSStefan Eßer } 251650696a6eSStefan Eßer else if ((flags & BC_PARSE_REL) && nrelops > 1) 251778bc019dSStefan Eßer { 251850696a6eSStefan Eßer bc_parse_err(p, BC_ERR_POSIX_MULTIREL); 251978bc019dSStefan Eßer } 252050696a6eSStefan Eßer 252144d4804dSStefan Eßer // If this is true, then we might be in a situation where we don't print. 252244d4804dSStefan Eßer // We would want to have the increment/decrement operator not make an extra 252344d4804dSStefan Eßer // copy if it's not necessary. 252478bc019dSStefan Eßer if (!(flags & BC_PARSE_NEEDVAL) && !pfirst) 252578bc019dSStefan Eßer { 252644d4804dSStefan Eßer // We have the easy case if the last operator was an assignment 252744d4804dSStefan Eßer // operator. 252878bc019dSStefan Eßer if (assign) 252978bc019dSStefan Eßer { 253050696a6eSStefan Eßer inst = *((uchar*) bc_vec_top(&p->func->code)); 253150696a6eSStefan Eßer inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER); 253250696a6eSStefan Eßer incdec = false; 253350696a6eSStefan Eßer } 253444d4804dSStefan Eßer // If we have an inc/dec operator and we are *not* printing, implement 253544d4804dSStefan Eßer // the optimization to get rid of the extra copy. 253678bc019dSStefan Eßer else if (incdec && !(flags & BC_PARSE_PRINT)) 253778bc019dSStefan Eßer { 253850696a6eSStefan Eßer inst = *((uchar*) bc_vec_top(&p->func->code)); 253950696a6eSStefan Eßer incdec = (inst <= BC_INST_DEC); 254078bc019dSStefan Eßer inst = BC_INST_ASSIGN_PLUS_NO_VAL + 254178bc019dSStefan Eßer (inst != BC_INST_INC && inst != BC_INST_ASSIGN_PLUS); 254250696a6eSStefan Eßer } 254350696a6eSStefan Eßer 254444d4804dSStefan Eßer // This condition allows us to change the previous assignment 254544d4804dSStefan Eßer // instruction (which does a copy) for a NO_VAL version, which does not. 254644d4804dSStefan Eßer // This condition is set if either of the above if statements ends up 254744d4804dSStefan Eßer // being true. 254850696a6eSStefan Eßer if (inst >= BC_INST_ASSIGN_POWER_NO_VAL && 254950696a6eSStefan Eßer inst <= BC_INST_ASSIGN_NO_VAL) 255050696a6eSStefan Eßer { 255144d4804dSStefan Eßer // Pop the previous assignment instruction and push a new one. 255244d4804dSStefan Eßer // Inc/dec needs the extra instruction because it is now a binary 255344d4804dSStefan Eßer // operator and needs a second operand. 255450696a6eSStefan Eßer bc_vec_pop(&p->func->code); 255550696a6eSStefan Eßer if (incdec) bc_parse_push(p, BC_INST_ONE); 255650696a6eSStefan Eßer bc_parse_push(p, inst); 255750696a6eSStefan Eßer } 255850696a6eSStefan Eßer } 255950696a6eSStefan Eßer 256044d4804dSStefan Eßer // If we might have to print... 256178bc019dSStefan Eßer if ((flags & BC_PARSE_PRINT)) 256278bc019dSStefan Eßer { 256344d4804dSStefan Eßer // With a paren first or the last operator not being an assignment, we 256444d4804dSStefan Eßer // *do* want to print. 256550696a6eSStefan Eßer if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT); 256650696a6eSStefan Eßer } 256744d4804dSStefan Eßer // We need to make sure to push a pop instruction for assignment statements 256844d4804dSStefan Eßer // that will not print. The print will pop, but without it, we need to pop. 256950696a6eSStefan Eßer else if (!(flags & BC_PARSE_NEEDVAL) && 257050696a6eSStefan Eßer (inst < BC_INST_ASSIGN_POWER_NO_VAL || 257150696a6eSStefan Eßer inst > BC_INST_ASSIGN_NO_VAL)) 257250696a6eSStefan Eßer { 257350696a6eSStefan Eßer bc_parse_push(p, BC_INST_POP); 257450696a6eSStefan Eßer } 257550696a6eSStefan Eßer 257650696a6eSStefan Eßer // We want to eat newlines if newlines are not a valid ending token. 257750696a6eSStefan Eßer // This is for spacing in things like for loop headers. 257844d4804dSStefan Eßer // 257944d4804dSStefan Eßer // Yes, this is one case where I reuse a variable for a different purpose; 258044d4804dSStefan Eßer // in this case, incdec being true now means that newlines are not valid. 258150696a6eSStefan Eßer for (incdec = true, i = 0; i < next.len && incdec; ++i) 258278bc019dSStefan Eßer { 258350696a6eSStefan Eßer incdec = (next.tokens[i] != BC_LEX_NLINE); 258478bc019dSStefan Eßer } 258578bc019dSStefan Eßer if (incdec) 258678bc019dSStefan Eßer { 258778bc019dSStefan Eßer while (p->l.t == BC_LEX_NLINE) 258878bc019dSStefan Eßer { 258978bc019dSStefan Eßer bc_lex_next(&p->l); 259078bc019dSStefan Eßer } 259150696a6eSStefan Eßer } 259250696a6eSStefan Eßer 259350696a6eSStefan Eßer return BC_PARSE_STATUS_SUCCESS; 259450696a6eSStefan Eßer } 259550696a6eSStefan Eßer 259644d4804dSStefan Eßer /** 259744d4804dSStefan Eßer * Parses an expression with bc_parse_expr_err(), but throws an error if it gets 259844d4804dSStefan Eßer * an empty expression. 259944d4804dSStefan Eßer * @param p The parser. 260044d4804dSStefan Eßer * @param flags The flags for what is valid in the expression. 260144d4804dSStefan Eßer * @param next A set of tokens for what is valid *after* the expression. 260244d4804dSStefan Eßer */ 260378bc019dSStefan Eßer static void 260478bc019dSStefan Eßer bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next) 260578bc019dSStefan Eßer { 260650696a6eSStefan Eßer BcParseStatus s = bc_parse_expr_err(p, flags, next); 260750696a6eSStefan Eßer 260850696a6eSStefan Eßer if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR)) 260978bc019dSStefan Eßer { 261050696a6eSStefan Eßer bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR); 261150696a6eSStefan Eßer } 261278bc019dSStefan Eßer } 261350696a6eSStefan Eßer 261478bc019dSStefan Eßer void 261578bc019dSStefan Eßer bc_parse_expr(BcParse* p, uint8_t flags) 261678bc019dSStefan Eßer { 261750696a6eSStefan Eßer assert(p); 261850696a6eSStefan Eßer bc_parse_expr_status(p, flags, bc_parse_next_read); 261950696a6eSStefan Eßer } 262050696a6eSStefan Eßer #endif // BC_ENABLED 2621