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