diff options
Diffstat (limited to 'src/bc_parse.c')
-rw-r--r-- | src/bc_parse.c | 956 |
1 files changed, 656 insertions, 300 deletions
diff --git a/src/bc_parse.c b/src/bc_parse.c index d0635a3b..4cf886ef 100644 --- a/src/bc_parse.c +++ b/src/bc_parse.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. + * Copyright (c) 2018-2023 Gavin D. Howard and contributors. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -55,23 +55,32 @@ // compared to this. This is where dreams go to die, where dragons live, and // from which Ken Thompson himself would flee. -static void bc_parse_else(BcParse *p); -static void bc_parse_stmt(BcParse *p); -static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, - BcParseNext next); -static void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next); +static void +bc_parse_else(BcParse* p); + +static void +bc_parse_stmt(BcParse* p); + +static BcParseStatus +bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next); + +static void +bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next); /** * Returns true if an instruction could only have come from a "leaf" expression. * For more on what leaf expressions are, read the comment for BC_PARSE_LEAF(). * @param t The instruction to test. + * @return True if the instruction is a from a leaf expression. */ -static bool bc_parse_inst_isLeaf(BcInst t) { - return (t >= BC_INST_NUM && t <= BC_INST_MAXSCALE) || +static bool +bc_parse_inst_isLeaf(BcInst t) +{ + return (t >= BC_INST_NUM && t <= BC_INST_LEADING_ZERO) || #if BC_ENABLE_EXTRA_MATH - t == BC_INST_TRUNC || + t == BC_INST_TRUNC || #endif // BC_ENABLE_EXTRA_MATH - t <= BC_INST_DEC; + t <= BC_INST_DEC; } /** @@ -79,9 +88,11 @@ static bool bc_parse_inst_isLeaf(BcInst t) { * that can legally end a statement. In bc's case, it could be a newline, a * semicolon, and a brace in certain cases. * @param p The parser. + * @return True if the token is a legal delimiter. */ -static bool bc_parse_isDelimiter(const BcParse *p) { - +static bool +bc_parse_isDelimiter(const BcParse* p) +{ BcLexType t = p->l.t; bool good; @@ -93,33 +104,36 @@ static bool bc_parse_isDelimiter(const BcParse *p) { // If the current token is a keyword, then...beware. That means that we need // to check for a "dangling" else, where there was no brace-delimited block // on the previous if. - if (t == BC_LEX_KW_ELSE) { - + if (t == BC_LEX_KW_ELSE) + { size_t i; uint16_t *fptr = NULL, flags = BC_PARSE_FLAG_ELSE; // As long as going up the stack is valid for a dangling else, keep on. - for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) { - + for (i = 0; i < p->flags.len && BC_PARSE_BLOCK_STMT(flags); ++i) + { fptr = bc_vec_item_rev(&p->flags, i); flags = *fptr; // If we need a brace and don't have one, then we don't have a // delimiter. if ((flags & BC_PARSE_FLAG_BRACE) && p->l.last != BC_LEX_RBRACE) + { return false; + } } // Oh, and we had also better have an if statement somewhere. good = ((flags & BC_PARSE_FLAG_IF) != 0); } - else if (t == BC_LEX_RBRACE) { - + else if (t == BC_LEX_RBRACE) + { size_t i; // Since we have a brace, we need to just check if a brace was needed. - for (i = 0; !good && i < p->flags.len; ++i) { - uint16_t *fptr = bc_vec_item_rev(&p->flags, i); + for (i = 0; !good && i < p->flags.len; ++i) + { + uint16_t* fptr = bc_vec_item_rev(&p->flags, i); good = (((*fptr) & BC_PARSE_FLAG_BRACE) != 0); } } @@ -128,15 +142,34 @@ static bool bc_parse_isDelimiter(const BcParse *p) { } /** + * Returns true if we are in top level of a function body. The POSIX grammar + * is defined such that anything is allowed after a function body, so we must + * use this function to detect that case when ending a function body. + * @param p The parser. + * @return True if we are in the top level of parsing a function body. + */ +static bool +bc_parse_TopFunc(const BcParse* p) +{ + bool good = p->flags.len == 2; + + uint16_t val = BC_PARSE_FLAG_BRACE | BC_PARSE_FLAG_FUNC_INNER; + val |= BC_PARSE_FLAG_FUNC; + + return good && BC_PARSE_TOP_FLAG(p) == val; +} + +/** * Sets a previously defined exit label. What are labels? See the bc Parsing * section of the Development manual (manuals/development.md). * @param p The parser. */ -static void bc_parse_setLabel(BcParse *p) { - - BcFunc *func = p->func; - BcInstPtr *ip = bc_vec_top(&p->exits); - size_t *label; +static void +bc_parse_setLabel(BcParse* p) +{ + BcFunc* func = p->func; + BcInstPtr* ip = bc_vec_top(&p->exits); + size_t* label; assert(func == bc_vec_item(&p->prog->fns, p->fidx)); @@ -155,7 +188,9 @@ static void bc_parse_setLabel(BcParse *p) { * @param p The parser. * @param idx The index of the label. */ -static void bc_parse_createLabel(BcParse *p, size_t idx) { +static void +bc_parse_createLabel(BcParse* p, size_t idx) +{ bc_vec_push(&p->func->labels, &idx); } @@ -165,12 +200,14 @@ static void bc_parse_createLabel(BcParse *p, size_t idx) { * @param p The parser. * @param idx The index of the label. */ -static void bc_parse_createCondLabel(BcParse *p, size_t idx) { +static void +bc_parse_createCondLabel(BcParse* p, size_t idx) +{ bc_parse_createLabel(p, p->func->code.len); bc_vec_push(&p->conds, &idx); } -/* +/** * Creates an exit label to be filled in later by bc_parse_setLabel(). Also, why * create a label to be filled in later? Because exit labels are meant to be * targeted by code that comes *before* the label. Since we have to parse that @@ -184,8 +221,9 @@ static void bc_parse_createCondLabel(BcParse *p, size_t idx) { * @param idx The index of the label's position. * @param loop True if the exit label is for a loop or not. */ -static void bc_parse_createExitLabel(BcParse *p, size_t idx, bool loop) { - +static void +bc_parse_createExitLabel(BcParse* p, size_t idx, bool loop) +{ BcInstPtr ip; assert(p->func == bc_vec_item(&p->prog->fns, p->fidx)); @@ -210,32 +248,37 @@ static void bc_parse_createExitLabel(BcParse *p, size_t idx, bool loop) { * @param nexprs A pointer to the current number of expressions that have not * been consumed yet. This is an IN and OUT parameter. */ -static void bc_parse_operator(BcParse *p, BcLexType type, - size_t start, size_t *nexprs) +static void +bc_parse_operator(BcParse* p, BcLexType type, size_t start, size_t* nexprs) { BcLexType t; uchar l, r = BC_PARSE_OP_PREC(type); uchar left = BC_PARSE_OP_LEFT(type); - // While we haven't hit the stop point yet. - while (p->ops.len > start) { - + // While we haven't hit the stop point yet... + while (p->ops.len > start) + { // Get the top operator. t = BC_PARSE_TOP_OP(p); - // If it's a right paren, we have reached the end of whatever expression - // this is no matter what. + // If it's a left paren, we have reached the end of whatever expression + // this is no matter what. We also don't pop the left paren because it + // will need to stay for the rest of the subexpression. if (t == BC_LEX_LPAREN) break; // Break for precedence. Precedence operates differently on left and // right associativity, by the way. A left associative operator that // matches the current precedence should take priority, but a right // associative operator should not. + // + // Also, a lower precedence value means a higher precedence. l = BC_PARSE_OP_PREC(t); if (l >= r && (l != r || !left)) break; // Do the housekeeping. In particular, make sure to note that one - // expression was consumed. (Two were, but another was added.) + // expression was consumed (well, two were, but another was added) if + // the operator was not a prefix operator. (Postfix operators are not + // handled by this function at all.) bc_parse_push(p, BC_PARSE_TOKEN_INST(t)); bc_vec_pop(&p->ops); *nexprs -= !BC_PARSE_OP_PREFIX(t); @@ -252,12 +295,14 @@ static void bc_parse_operator(BcParse *p, BcLexType type, * @param nexprs A pointer to the current number of expressions that have not * been consumed yet. This is an IN and OUT parameter. */ -static void bc_parse_rightParen(BcParse *p, size_t *nexprs) { - +static void +bc_parse_rightParen(BcParse* p, size_t* nexprs) +{ BcLexType top; // Consume operators until a left paren. - while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) { + while ((top = BC_PARSE_TOP_OP(p)) != BC_LEX_LPAREN) + { bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); bc_vec_pop(&p->ops); *nexprs -= !BC_PARSE_OP_PREFIX(top); @@ -276,8 +321,9 @@ static void bc_parse_rightParen(BcParse *p, size_t *nexprs) { * @param flags Flags restricting what kind of expressions the arguments can * be. */ -static void bc_parse_args(BcParse *p, uint8_t flags) { - +static void +bc_parse_args(BcParse* p, uint8_t flags) +{ bool comma = false; size_t nargs; @@ -289,8 +335,8 @@ static void bc_parse_args(BcParse *p, uint8_t flags) { flags |= (BC_PARSE_ARRAY | BC_PARSE_NEEDVAL); // Count the arguments and parse them. - for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs) { - + for (nargs = 0; p->l.t != BC_LEX_RPAREN; ++nargs) + { bc_parse_expr_status(p, flags, bc_parse_next_arg); comma = (p->l.t == BC_LEX_COMMA); @@ -311,8 +357,9 @@ static void bc_parse_args(BcParse *p, uint8_t flags) { * @param flags Flags restricting what kind of expressions the arguments can * be. */ -static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) { - +static void +bc_parse_call(BcParse* p, const char* name, uint8_t flags) +{ size_t idx; bc_parse_args(p, flags); @@ -327,14 +374,10 @@ static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) { // The function does not exist yet. Create a space for it. If the user does // not define it, it's a *runtime* error, not a parse error. - if (idx == BC_VEC_INVALID_IDX) { - - BC_SIG_LOCK; - + if (idx == BC_VEC_INVALID_IDX) + { idx = bc_program_insertFunc(p->prog, name); - BC_SIG_UNLOCK; - assert(idx != BC_VEC_INVALID_IDX); // Make sure that this pointer was not invalidated. @@ -352,42 +395,46 @@ static void bc_parse_call(BcParse *p, const char *name, uint8_t flags) { /** * Parses a name/identifier-based expression. It could be a variable, an array * element, an array itself (for function arguments), a function call, etc. - * + * @param p The parser. + * @param type A pointer to return the resulting instruction. + * @param can_assign A pointer to return true if the name can be assigned to, + * false otherwise. + * @param flags Flags restricting what kind of expression the name can be. */ -static void bc_parse_name(BcParse *p, BcInst *type, - bool *can_assign, uint8_t flags) +static void +bc_parse_name(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags) { - char *name; + char* name; - BC_SIG_LOCK; + BC_SIG_ASSERT_LOCKED; // We want a copy of the name since the lexer might overwrite its copy. name = bc_vm_strdup(p->l.str.v); - BC_SETJMP_LOCKED(err); - - BC_SIG_UNLOCK; + BC_SETJMP_LOCKED(vm, err); // We need the next token to see if it's just a variable or something more. bc_lex_next(&p->l); // Array element or array. - if (p->l.t == BC_LEX_LBRACKET) { - + if (p->l.t == BC_LEX_LBRACKET) + { bc_lex_next(&p->l); // Array only. This has to be a function parameter. - if (p->l.t == BC_LEX_RBRACKET) { - + if (p->l.t == BC_LEX_RBRACKET) + { // Error if arrays are not allowed. if (BC_ERR(!(flags & BC_PARSE_ARRAY))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } *type = BC_INST_ARRAY; *can_assign = false; } - else { - + else + { // If we are here, we have an array element. We need to set the // expression parsing flags. uint8_t flags2 = (flags & ~(BC_PARSE_PRINT | BC_PARSE_REL)) | @@ -397,7 +444,9 @@ static void bc_parse_name(BcParse *p, BcInst *type, // The next token *must* be a right bracket. if (BC_ERR(p->l.t != BC_LEX_RBRACKET)) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } *type = BC_INST_ARRAY_ELEM; *can_assign = true; @@ -410,18 +459,21 @@ static void bc_parse_name(BcParse *p, BcInst *type, bc_parse_push(p, *type); bc_parse_pushName(p, name, false); } - else if (p->l.t == BC_LEX_LPAREN) { - + else if (p->l.t == BC_LEX_LPAREN) + { // We are parsing a function call; error if not allowed. if (BC_ERR(flags & BC_PARSE_NOCALL)) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } *type = BC_INST_CALL; *can_assign = false; bc_parse_call(p, name, flags); } - else { + else + { // Just a variable. *type = BC_INST_VAR; *can_assign = true; @@ -431,9 +483,9 @@ static void bc_parse_name(BcParse *p, BcInst *type, err: // Need to make sure to unallocate the name. - BC_SIG_MAYLOCK; free(name); - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); + BC_SIG_MAYLOCK; } /** @@ -442,8 +494,9 @@ err: * @param p The parser. * @param inst The instruction corresponding to the builtin. */ -static void bc_parse_noArgBuiltin(BcParse *p, BcInst inst) { - +static void +bc_parse_noArgBuiltin(BcParse* p, BcInst inst) +{ // Must have a left paren. bc_lex_next(&p->l); if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); @@ -465,13 +518,12 @@ static void bc_parse_noArgBuiltin(BcParse *p, BcInst inst) { * @param flags The expression parsing flags for parsing the argument. * @param prev An out parameter; the previous instruction pointer. */ -static void bc_parse_builtin(BcParse *p, BcLexType type, - uint8_t flags, BcInst *prev) +static void +bc_parse_builtin(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev) { // Must have a left paren. bc_lex_next(&p->l); - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); @@ -480,13 +532,18 @@ static void bc_parse_builtin(BcParse *p, BcLexType type, flags |= BC_PARSE_NEEDVAL; // Since length can take arrays, we need to specially add that flag. - if (type == BC_LEX_KW_LENGTH) flags |= BC_PARSE_ARRAY; + if (type == BC_LEX_KW_LENGTH || type == BC_LEX_KW_ASCIIFY) + { + flags |= BC_PARSE_ARRAY; + } + + // Otherwise, we need to clear it because it could be set. + else flags &= ~(BC_PARSE_ARRAY); bc_parse_expr_status(p, flags, bc_parse_next_rel); // Must have a right paren. - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // Adjust previous based on the token and push it. *prev = type - BC_LEX_KW_LENGTH + BC_INST_LENGTH; @@ -498,16 +555,19 @@ static void bc_parse_builtin(BcParse *p, BcLexType type, /** * Parses a builtin function that takes 3 arguments. This includes modexp() and * divmod(). + * @param p The parser. + * @param type The lex token. + * @param flags The expression parsing flags for parsing the argument. + * @param prev An out parameter; the previous instruction pointer. */ -static void bc_parse_builtin3(BcParse *p, BcLexType type, - uint8_t flags, BcInst *prev) +static void +bc_parse_builtin3(BcParse* p, BcLexType type, uint8_t flags, BcInst* prev) { assert(type == BC_LEX_KW_MODEXP || type == BC_LEX_KW_DIVMOD); // Must have a left paren. bc_lex_next(&p->l); - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); @@ -518,23 +578,21 @@ static void bc_parse_builtin3(BcParse *p, BcLexType type, bc_parse_expr_status(p, flags, bc_parse_next_builtin); // Must have a comma. - if (BC_ERR(p->l.t != BC_LEX_COMMA)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); bc_parse_expr_status(p, flags, bc_parse_next_builtin); // Must have a comma. - if (BC_ERR(p->l.t != BC_LEX_COMMA)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_COMMA)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); // If it is a divmod, parse an array name. Otherwise, just parse another // expression. - if (type == BC_LEX_KW_DIVMOD) { - + if (type == BC_LEX_KW_DIVMOD) + { // Must have a name. if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); @@ -543,14 +601,18 @@ static void bc_parse_builtin3(BcParse *p, BcLexType type, // Must have a left bracket. if (BC_ERR(p->l.t != BC_LEX_LBRACKET)) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } // This is safe because the next token should not overwrite the name. bc_lex_next(&p->l); // Must have a right bracket. if (BC_ERR(p->l.t != BC_LEX_RBRACKET)) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } // This is safe because the next token should not overwrite the name. bc_lex_next(&p->l); @@ -558,8 +620,7 @@ static void bc_parse_builtin3(BcParse *p, BcLexType type, else bc_parse_expr_status(p, flags, bc_parse_next_rel); // Must have a right paren. - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // Adjust previous based on the token and push it. *prev = type - BC_LEX_KW_MODEXP + BC_INST_MODEXP; @@ -567,8 +628,8 @@ static void bc_parse_builtin3(BcParse *p, BcLexType type, // If we have divmod, we need to assign the modulus to the array element, so // we need to push the instructions for doing so. - if (type == BC_LEX_KW_DIVMOD) { - + if (type == BC_LEX_KW_DIVMOD) + { // The zeroth element. bc_parse_push(p, BC_INST_ZERO); bc_parse_push(p, BC_INST_ARRAY_ELEM); @@ -594,14 +655,14 @@ static void bc_parse_builtin3(BcParse *p, BcLexType type, * to. * @param flags The expression parsing flags for parsing a scale() arg. */ -static void bc_parse_scale(BcParse *p, BcInst *type, - bool *can_assign, uint8_t flags) +static void +bc_parse_scale(BcParse* p, BcInst* type, bool* can_assign, uint8_t flags) { bc_lex_next(&p->l); // Without the left paren, it's just the keyword. - if (p->l.t != BC_LEX_LPAREN) { - + if (p->l.t != BC_LEX_LPAREN) + { // Set, push, and return. *type = BC_INST_SCALE; *can_assign = true; @@ -622,8 +683,7 @@ static void bc_parse_scale(BcParse *p, BcInst *type, bc_parse_expr_status(p, flags, bc_parse_next_rel); // Must have a right paren. - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_parse_push(p, BC_INST_SCALE_FUNC); @@ -640,8 +700,9 @@ static void bc_parse_scale(BcParse *p, BcInst *type, * parse tree that are not used. * @param flags The expression parsing flags for parsing a scale() arg. */ -static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign, - size_t *nexs, uint8_t flags) +static void +bc_parse_incdec(BcParse* p, BcInst* prev, bool* can_assign, size_t* nexs, + uint8_t flags) { BcLexType type; uchar inst; @@ -658,8 +719,8 @@ static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign, } // Is the previous instruction for a variable? - if (BC_PARSE_INST_VAR(etype)) { - + if (BC_PARSE_INST_VAR(etype)) + { // If so, this is a postfix operator. if (!*can_assign) bc_parse_err(p, BC_ERR_PARSE_ASSIGN); @@ -669,8 +730,8 @@ static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign, bc_lex_next(&p->l); *can_assign = false; } - else { - + else + { // This is a prefix operator. In that case, we just convert it to // an assignment instruction. *prev = inst = BC_INST_ASSIGN_PLUS + (p->l.t != BC_LEX_OP_INC); @@ -683,25 +744,28 @@ static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign, *nexs = *nexs + 1; // Is the next token a normal identifier? - if (type == BC_LEX_NAME) { - + if (type == BC_LEX_NAME) + { // Parse the name. - uint8_t flags2 = flags & ~BC_PARSE_ARRAY; + uint8_t flags2 = flags & ~(BC_PARSE_ARRAY); bc_parse_name(p, prev, can_assign, flags2 | BC_PARSE_NOCALL); } // Is the next token a global? - else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE) { + else if (type >= BC_LEX_KW_LAST && type <= BC_LEX_KW_OBASE) + { bc_parse_push(p, type - BC_LEX_KW_LAST + BC_INST_LAST); bc_lex_next(&p->l); } // Is the next token specifically scale, which needs special treatment? - else if (BC_NO_ERR(type == BC_LEX_KW_SCALE)) { - + else if (BC_NO_ERR(type == BC_LEX_KW_SCALE)) + { bc_lex_next(&p->l); // Check that scale() was not used. if (BC_ERR(p->l.t == BC_LEX_LPAREN)) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } else bc_parse_push(p, BC_INST_SCALE); } // Now we know we have an error. @@ -724,8 +788,9 @@ static void bc_parse_incdec(BcParse *p, BcInst *prev, bool *can_assign, * @param binlast True if the last token was a binary operator. * @param nexprs An in/out parameter; the number of unused expressions. */ -static void bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn, - bool rparen, bool binlast, size_t *nexprs) +static void +bc_parse_minus(BcParse* p, BcInst* prev, size_t ops_bgn, bool rparen, + bool binlast, size_t* nexprs) { BcLexType type; @@ -747,7 +812,9 @@ static void bc_parse_minus(BcParse *p, BcInst *prev, size_t ops_bgn, * @param inst The instruction corresponding to how the string was found and * how it should be printed. */ -static void bc_parse_str(BcParse *p, BcInst inst) { +static void +bc_parse_str(BcParse* p, BcInst inst) +{ bc_parse_addString(p); bc_parse_push(p, inst); bc_lex_next(&p->l); @@ -757,12 +824,13 @@ static void bc_parse_str(BcParse *p, BcInst inst) { * Parses a print statement. * @param p The parser. */ -static void bc_parse_print(BcParse *p, BcLexType type) { - +static void +bc_parse_print(BcParse* p, BcLexType type) +{ BcLexType t; bool comma = false; - BcInst inst = type == BC_LEX_KW_STREAM ? - BC_INST_PRINT_STREAM : BC_INST_PRINT_POP; + BcInst inst = type == BC_LEX_KW_STREAM ? BC_INST_PRINT_STREAM : + BC_INST_PRINT_POP; bc_lex_next(&p->l); @@ -771,12 +839,13 @@ static void bc_parse_print(BcParse *p, BcLexType type) { // A print or stream statement has to have *something*. if (bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_PRINT); - do { - + do + { // If the token is a string, then print it with escapes. // BC_INST_PRINT_POP plays that role for bc. if (t == BC_LEX_STR) bc_parse_str(p, inst); - else { + else + { // We have an actual number; parse and add a print instruction. bc_parse_expr_status(p, BC_PARSE_NEEDVAL, bc_parse_next_print); bc_parse_push(p, inst); @@ -787,17 +856,16 @@ static void bc_parse_print(BcParse *p, BcLexType type) { // Get the next token if we have a comma. if (comma) bc_lex_next(&p->l); - else { - + else + { // If we don't have a comma, the statement needs to end. - if (!bc_parse_isDelimiter(p)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (!bc_parse_isDelimiter(p)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); else break; } t = p->l.t; - - } while (true); + } + while (true); // If we have a comma but no token, that's bad. if (BC_ERR(comma)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); @@ -807,8 +875,9 @@ static void bc_parse_print(BcParse *p, BcLexType type) { * Parses a return statement. * @param p The parser. */ -static void bc_parse_return(BcParse *p) { - +static void +bc_parse_return(BcParse* p) +{ BcLexType t; bool paren; uchar inst = BC_INST_RET0; @@ -826,28 +895,33 @@ static void bc_parse_return(BcParse *p) { // An empty return statement just needs to push the selected instruction. if (bc_parse_isDelimiter(p)) bc_parse_push(p, inst); - else { - + else + { BcParseStatus s; // Need to parse the expression whose value will be returned. s = bc_parse_expr_err(p, BC_PARSE_NEEDVAL, bc_parse_next_expr); // If the expression was empty, just push the selected instruction. - if (s == BC_PARSE_STATUS_EMPTY_EXPR) { + if (s == BC_PARSE_STATUS_EMPTY_EXPR) + { bc_parse_push(p, inst); bc_lex_next(&p->l); } // POSIX requires parentheses. - if (!paren || p->l.last != BC_LEX_RPAREN) { + if (!paren || p->l.last != BC_LEX_RPAREN) + { bc_parse_err(p, BC_ERR_POSIX_RET); } // Void functions require an empty expression. - if (BC_ERR(p->func->voidfn)) { + if (BC_ERR(p->func->voidfn)) + { if (s != BC_PARSE_STATUS_EMPTY_EXPR) + { bc_parse_verr(p, BC_ERR_PARSE_RET_VOID, p->func->name); + } } // If we got here, we want to be sure to end the function with a real // return instruction, just in case. @@ -860,8 +934,10 @@ static void bc_parse_return(BcParse *p) { * the jump location. * @param p The parser. */ -static void bc_parse_noElse(BcParse *p) { - uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); +static void +bc_parse_noElse(BcParse* p) +{ + uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); *flag_ptr = (*flag_ptr & ~(BC_PARSE_FLAG_IF_END)); bc_parse_setLabel(p); } @@ -871,15 +947,16 @@ static void bc_parse_noElse(BcParse *p) { * @param p The parser. * @param brace True if the body was ended by a brace, false otherwise. */ -static void bc_parse_endBody(BcParse *p, bool brace) { - +static void +bc_parse_endBody(BcParse* p, bool brace) +{ bool has_brace, new_else = false; // We cannot be ending a body if there are no bodies to end. if (BC_ERR(p->flags.len <= 1)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); - if (brace) { - + if (brace) + { // The brace was already gotten; make sure that the caller did not lie. // We check for the requirement of braces later. assert(p->l.t == BC_LEX_RBRACE); @@ -887,14 +964,17 @@ static void bc_parse_endBody(BcParse *p, bool brace) { bc_lex_next(&p->l); // If the next token is not a delimiter, that is a problem. - if (BC_ERR(!bc_parse_isDelimiter(p))) + if (BC_ERR(!bc_parse_isDelimiter(p) && !bc_parse_TopFunc(p))) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } } // Do we have a brace flag? has_brace = (BC_PARSE_BRACE(p) != 0); - do { + do + { size_t len = p->flags.len; bool loop; @@ -905,12 +985,12 @@ static void bc_parse_endBody(BcParse *p, bool brace) { loop = (BC_PARSE_LOOP_INNER(p) != 0); // If we are ending a loop or an else... - if (loop || BC_PARSE_ELSE(p)) { - + if (loop || BC_PARSE_ELSE(p)) + { // Loops have condition labels that we have to take care of as well. - if (loop) { - - size_t *label = bc_vec_top(&p->conds); + if (loop) + { + size_t* label = bc_vec_top(&p->conds); bc_parse_push(p, BC_INST_JUMP); bc_parse_pushIndex(p, *label); @@ -922,7 +1002,8 @@ static void bc_parse_endBody(BcParse *p, bool brace) { bc_vec_pop(&p->flags); } // If we are ending a function... - else if (BC_PARSE_FUNC_INNER(p)) { + else if (BC_PARSE_FUNC_INNER(p)) + { BcInst inst = (p->func->voidfn ? BC_INST_RET_VOID : BC_INST_RET0); bc_parse_push(p, inst); bc_parse_updateFunc(p, BC_PROG_MAIN); @@ -933,17 +1014,20 @@ static void bc_parse_endBody(BcParse *p, bool brace) { else if (has_brace && !BC_PARSE_IF(p)) bc_vec_pop(&p->flags); // This needs to be last to parse nested if's properly. - if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) { - + if (BC_PARSE_IF(p) && (len == p->flags.len || !BC_PARSE_BRACE(p))) + { // Eat newlines. - while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l); + while (p->l.t == BC_LEX_NLINE) + { + bc_lex_next(&p->l); + } // *Now* we can pop the flags. bc_vec_pop(&p->flags); // If we are allowed non-POSIX stuff... - if (!BC_S) { - + if (!BC_S) + { // Have we found yet another dangling else? *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_IF_END; new_else = (p->l.t == BC_LEX_KW_ELSE); @@ -951,7 +1035,9 @@ static void bc_parse_endBody(BcParse *p, bool brace) { // Parse the else or end the if statement body. if (new_else) bc_parse_else(p); else if (!has_brace && (!BC_PARSE_IF_END(p) || brace)) + { bc_parse_noElse(p); + } } // POSIX requires us to do the bare minimum only. else bc_parse_noElse(p); @@ -959,20 +1045,19 @@ static void bc_parse_endBody(BcParse *p, bool brace) { // If these are both true, we have "used" the braces that we found. if (brace && has_brace) brace = false; - - // This condition was perhaps the hardest single part of the parser. If the - // flags stack does not have enough, we should stop. If we have a new else - // statement, we should stop. If we do have the end of an if statement and - // we have eaten the brace, we should stop. If we do have a brace flag, we - // should stop. - } while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) && - !(has_brace = (BC_PARSE_BRACE(p) != 0))); + } + // This condition was perhaps the hardest single part of the parser. If + // the flags stack does not have enough, we should stop. If we have a + // new else statement, we should stop. If we do have the end of an if + // statement and we have eaten the brace, we should stop. If we do have + // a brace flag, we should stop. + while (p->flags.len > 1 && !new_else && (!BC_PARSE_IF_END(p) || brace) && + !(has_brace = (BC_PARSE_BRACE(p) != 0))); // If we have a brace, yet no body for it, that's a problem. - if (BC_ERR(p->flags.len == 1 && brace)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); - else if (brace && BC_PARSE_BRACE(p)) { - + if (BC_ERR(p->flags.len == 1 && brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); + else if (brace && BC_PARSE_BRACE(p)) + { // If we make it here, we have a brace and a flag for it. uint16_t flags = BC_PARSE_TOP_FLAG(p); @@ -992,35 +1077,77 @@ static void bc_parse_endBody(BcParse *p, bool brace) { * @param p The parser. * @param flags The current flags (will be edited). */ -static void bc_parse_startBody(BcParse *p, uint16_t flags) { +static void +bc_parse_startBody(BcParse* p, uint16_t flags) +{ assert(flags); flags |= (BC_PARSE_TOP_FLAG(p) & (BC_PARSE_FLAG_FUNC | BC_PARSE_FLAG_LOOP)); flags |= BC_PARSE_FLAG_BODY; bc_vec_push(&p->flags, &flags); } +void +bc_parse_endif(BcParse* p) +{ + size_t i; + bool good; + + // Not a problem if this is true. + if (BC_NO_ERR(!BC_PARSE_NO_EXEC(p))) return; + + good = true; + + // Find an instance of a body that needs closing, i.e., a statement that did + // not have a right brace when it should have. + for (i = 0; good && i < p->flags.len; ++i) + { + uint16_t flag = *((uint16_t*) bc_vec_item(&p->flags, i)); + good = ((flag & BC_PARSE_FLAG_BRACE) != BC_PARSE_FLAG_BRACE); + } + + // If we did not find such an instance... + if (good) + { + // We set this to restore it later. We don't want the parser thinking + // that we are on stdin for this one because it will want more. + BcMode mode = vm->mode; + + vm->mode = BC_MODE_FILE; + + // End all of the if statements and loops. + while (p->flags.len > 1 || BC_PARSE_IF_END(p)) + { + if (BC_PARSE_IF_END(p)) bc_parse_noElse(p); + if (p->flags.len > 1) bc_parse_endBody(p, false); + } + + vm->mode = (uchar) mode; + } + // If we reach here, a block was not properly closed, and we should error. + else bc_parse_err(&vm->prs, BC_ERR_PARSE_BLOCK); +} + /** * Parses an if statement. * @param p The parser. */ -static void bc_parse_if(BcParse *p) { - +static void +bc_parse_if(BcParse* p) +{ // We are allowed relational operators, and we must have a value. size_t idx; uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL); // Get the left paren and barf if necessary. bc_lex_next(&p->l); - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // Parse the condition. bc_lex_next(&p->l); bc_parse_expr_status(p, flags, bc_parse_next_rel); // Must have a right paren. - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); @@ -1041,13 +1168,13 @@ static void bc_parse_if(BcParse *p) { * Parses an else statement. * @param p The parser. */ -static void bc_parse_else(BcParse *p) { - +static void +bc_parse_else(BcParse* p) +{ size_t idx = p->func->labels.len; // We must be at the end of an if statement. - if (BC_ERR(!BC_PARSE_IF_END(p))) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(!BC_PARSE_IF_END(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // Push an unconditional jump to make bc jump over the else statement if it // executed the original if statement. @@ -1069,16 +1196,16 @@ static void bc_parse_else(BcParse *p) { * Parse a while loop. * @param p The parser. */ -static void bc_parse_while(BcParse *p) { - +static void +bc_parse_while(BcParse* p) +{ // We are allowed relational operators, and we must have a value. size_t idx; uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL); // Get the left paren and barf if necessary. bc_lex_next(&p->l); - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); // Create the labels. Loops need both. @@ -1088,8 +1215,7 @@ static void bc_parse_while(BcParse *p) { // Parse the actual condition and barf on non-right paren. bc_parse_expr_status(p, flags, bc_parse_next_rel); - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); // Now we can push the conditional jump and start the body. @@ -1102,20 +1228,19 @@ static void bc_parse_while(BcParse *p) { * Parse a for loop. * @param p The parser. */ -static void bc_parse_for(BcParse *p) { - +static void +bc_parse_for(BcParse* p) +{ size_t cond_idx, exit_idx, body_idx, update_idx; // Barf on the missing left paren. bc_lex_next(&p->l); - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); // The first statement can be empty, but if it is, check for error in POSIX // mode. Otherwise, parse it. - if (p->l.t != BC_LEX_SCOLON) - bc_parse_expr_status(p, 0, bc_parse_next_for); + if (p->l.t != BC_LEX_SCOLON) bc_parse_expr_status(p, 0, bc_parse_next_for); else bc_parse_err(p, BC_ERR_POSIX_FOR); // Must have a semicolon. @@ -1135,12 +1260,13 @@ static void bc_parse_for(BcParse *p) { bc_parse_createLabel(p, p->func->code.len); // Parse an expression if it exists. - if (p->l.t != BC_LEX_SCOLON) { + if (p->l.t != BC_LEX_SCOLON) + { uint8_t flags = (BC_PARSE_REL | BC_PARSE_NEEDVAL); bc_parse_expr_status(p, flags, bc_parse_next_for); } - else { - + else + { // Set this for the next call to bc_parse_number because an empty // condition means that it is an infinite loop, so the condition must be // non-zero. This is safe to set because the current token is a @@ -1153,8 +1279,7 @@ static void bc_parse_for(BcParse *p) { } // Must have a semicolon. - if (BC_ERR(p->l.t != BC_LEX_SCOLON)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_SCOLON)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); bc_lex_next(&p->l); // Now we can set up the conditional jump to the exit and an unconditional @@ -1170,13 +1295,11 @@ static void bc_parse_for(BcParse *p) { bc_parse_createCondLabel(p, update_idx); // Parse if not empty, and if it is, let POSIX yell if necessary. - if (p->l.t != BC_LEX_RPAREN) - bc_parse_expr_status(p, 0, bc_parse_next_rel); + if (p->l.t != BC_LEX_RPAREN) bc_parse_expr_status(p, 0, bc_parse_next_rel); else bc_parse_err(p, BC_ERR_POSIX_FOR); // Must have a right paren. - if (BC_ERR(p->l.t != BC_LEX_RPAREN)) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(p->l.t != BC_LEX_RPAREN)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // Set up a jump to the condition right after the update code. bc_parse_push(p, BC_INST_JUMP); @@ -1195,17 +1318,18 @@ static void bc_parse_for(BcParse *p) { * @param p The parser. * @param type The type of exit. */ -static void bc_parse_loopExit(BcParse *p, BcLexType type) { - +static void +bc_parse_loopExit(BcParse* p, BcLexType type) +{ size_t i; - BcInstPtr *ip; + BcInstPtr* ip; // Must have a loop. If we don't, that's an error. if (BC_ERR(!BC_PARSE_LOOP(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN); // If we have a break statement... - if (type == BC_LEX_KW_BREAK) { - + if (type == BC_LEX_KW_BREAK) + { // If there are no exits, something went wrong somewhere. if (BC_ERR(!p->exits.len)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); @@ -1215,7 +1339,11 @@ static void bc_parse_loopExit(BcParse *p, BcLexType type) { // The condition !ip->func is true if the exit is not for a loop, so we // need to find the first actual loop exit. - while (!ip->func && i < p->exits.len) ip = bc_vec_item(&p->exits, i--); + while (!ip->func && i < p->exits.len) + { + ip = bc_vec_item(&p->exits, i); + i -= 1; + } // Make sure everything is hunky dory. assert(ip != NULL && (i < p->exits.len || ip->func)); @@ -1238,8 +1366,9 @@ static void bc_parse_loopExit(BcParse *p, BcLexType type) { * Parse a function (header). * @param p The parser. */ -static void bc_parse_func(BcParse *p) { - +static void +bc_parse_func(BcParse* p) +{ bool comma = false, voidfn; uint16_t flags; size_t idx; @@ -1261,8 +1390,8 @@ static void bc_parse_func(BcParse *p) { voidfn = (voidfn && p->l.t == BC_LEX_NAME); // With a void function, allow POSIX to complain and get a new token. - if (voidfn) { - + if (voidfn) + { bc_parse_err(p, BC_ERR_POSIX_VOID); // We can safely do this because the expected token should not overwrite @@ -1271,21 +1400,14 @@ static void bc_parse_func(BcParse *p) { } // Must have a left paren. - if (BC_ERR(p->l.t != BC_LEX_LPAREN)) - bc_parse_err(p, BC_ERR_PARSE_FUNC); + if (BC_ERR(p->l.t != BC_LEX_LPAREN)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // Make sure the functions map and vector are synchronized. assert(p->prog->fns.len == p->prog->fn_map.len); - // Must lock signals because vectors are changed, and the vector functions - // expect signals to be locked. - BC_SIG_LOCK; - // Insert the function by name into the map and vector. idx = bc_program_insertFunc(p->prog, p->l.str.v); - BC_SIG_UNLOCK; - // Make sure the insert worked. assert(idx); @@ -1296,13 +1418,13 @@ static void bc_parse_func(BcParse *p) { bc_lex_next(&p->l); // While we do not have a right paren, we are still parsing arguments. - while (p->l.t != BC_LEX_RPAREN) { - + while (p->l.t != BC_LEX_RPAREN) + { BcType t = BC_TYPE_VAR; // If we have an asterisk, we are parsing a reference argument. - if (p->l.t == BC_LEX_OP_MULTIPLY) { - + if (p->l.t == BC_LEX_OP_MULTIPLY) + { t = BC_TYPE_REF; bc_lex_next(&p->l); @@ -1311,8 +1433,7 @@ static void bc_parse_func(BcParse *p) { } // If we don't have a name, the argument will not have a name. Barf. - if (BC_ERR(p->l.t != BC_LEX_NAME)) - bc_parse_err(p, BC_ERR_PARSE_FUNC); + if (BC_ERR(p->l.t != BC_LEX_NAME)) bc_parse_err(p, BC_ERR_PARSE_FUNC); // Increment the number of parameters. p->func->nparams += 1; @@ -1323,8 +1444,8 @@ static void bc_parse_func(BcParse *p) { bc_lex_next(&p->l); // We are parsing an array parameter if this is true. - if (p->l.t == BC_LEX_LBRACKET) { - + if (p->l.t == BC_LEX_LBRACKET) + { // Set the array type, unless we are already parsing a reference. if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY; @@ -1332,14 +1453,18 @@ static void bc_parse_func(BcParse *p) { // The brackets *must* be empty. if (BC_ERR(p->l.t != BC_LEX_RBRACKET)) + { bc_parse_err(p, BC_ERR_PARSE_FUNC); + } bc_lex_next(&p->l); } // If we did *not* get a bracket, but we are expecting a reference, we // have a problem. else if (BC_ERR(t == BC_TYPE_REF)) + { bc_parse_verr(p, BC_ERR_PARSE_REF_VAR, p->buf.v); + } // Test for comma and get the next token if it exists. comma = (p->l.t == BC_LEX_COMMA); @@ -1367,8 +1492,9 @@ static void bc_parse_func(BcParse *p) { * Parse an auto list. * @param p The parser. */ -static void bc_parse_auto(BcParse *p) { - +static void +bc_parse_auto(BcParse* p) +{ bool comma, one; // Error if the auto keyword appeared in the wrong place. @@ -1381,8 +1507,8 @@ static void bc_parse_auto(BcParse *p) { one = (p->l.t == BC_LEX_NAME); // While we have a variable or array. - while (p->l.t == BC_LEX_NAME) { - + while (p->l.t == BC_LEX_NAME) + { BcType t; // Copy the name from the lexer, so we can use it again. @@ -1391,15 +1517,17 @@ static void bc_parse_auto(BcParse *p) { bc_lex_next(&p->l); // If we are parsing an array... - if (p->l.t == BC_LEX_LBRACKET) { - + if (p->l.t == BC_LEX_LBRACKET) + { t = BC_TYPE_ARRAY; bc_lex_next(&p->l); // The brackets *must* be empty. if (BC_ERR(p->l.t != BC_LEX_RBRACKET)) + { bc_parse_err(p, BC_ERR_PARSE_FUNC); + } bc_lex_next(&p->l); } @@ -1420,8 +1548,7 @@ static void bc_parse_auto(BcParse *p) { if (BC_ERR(!one)) bc_parse_err(p, BC_ERR_PARSE_NO_AUTO); // The auto statement should be all that's in the statement. - if (BC_ERR(!bc_parse_isDelimiter(p))) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + if (BC_ERR(!bc_parse_isDelimiter(p))) bc_parse_err(p, BC_ERR_PARSE_TOKEN); } /** @@ -1429,9 +1556,10 @@ static void bc_parse_auto(BcParse *p) { * @param p The parser. * @param brace True if a brace was encountered, false otherwise. */ -static void bc_parse_body(BcParse *p, bool brace) { - - uint16_t *flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); +static void +bc_parse_body(BcParse* p, bool brace) +{ + uint16_t* flag_ptr = BC_PARSE_TOP_FLAG_PTR(p); assert(flag_ptr != NULL); assert(p->flags.len >= 2); @@ -1442,15 +1570,15 @@ static void bc_parse_body(BcParse *p, bool brace) { // If we are inside a function, that means we just barely entered it, and // we can expect an auto list. - if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) { - + if (*flag_ptr & BC_PARSE_FLAG_FUNC_INNER) + { // We *must* have a brace in this case. if (BC_ERR(!brace)) bc_parse_err(p, BC_ERR_PARSE_TOKEN); p->auto_part = (p->l.t != BC_LEX_KW_AUTO); - if (!p->auto_part) { - + if (!p->auto_part) + { // Make sure this is true to not get a parse error. p->auto_part = true; @@ -1461,8 +1589,8 @@ static void bc_parse_body(BcParse *p, bool brace) { // Eat a newline. if (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l); } - else { - + else + { // This is the easy part. size_t len = p->flags.len; @@ -1476,7 +1604,9 @@ static void bc_parse_body(BcParse *p, bool brace) { // have a body that was not delimited by braces, so we need to end it // now, after just one statement. if (!brace && !BC_PARSE_BODY(p) && len <= p->flags.len) + { bc_parse_endBody(p, false); + } } } @@ -1485,20 +1615,23 @@ static void bc_parse_body(BcParse *p, bool brace) { * function definitions. * @param p The parser. */ -static void bc_parse_stmt(BcParse *p) { - +static void +bc_parse_stmt(BcParse* p) +{ size_t len; uint16_t flags; BcLexType type = p->l.t; // Eat newline. - if (type == BC_LEX_NLINE) { + if (type == BC_LEX_NLINE) + { bc_lex_next(&p->l); return; } // Eat auto list. - if (type == BC_LEX_KW_AUTO) { + if (type == BC_LEX_KW_AUTO) + { bc_parse_auto(p); return; } @@ -1508,30 +1641,35 @@ static void bc_parse_stmt(BcParse *p) { // Everything but an else needs to be taken care of here, but else is // special. - if (type != BC_LEX_KW_ELSE) { - + if (type != BC_LEX_KW_ELSE) + { // After an if, no else found. - if (BC_PARSE_IF_END(p)) { - + if (BC_PARSE_IF_END(p)) + { // Clear the expectation for else, end body, and return. Returning // gives us a clean slate for parsing again. bc_parse_noElse(p); if (p->flags.len > 1 && !BC_PARSE_BRACE(p)) + { bc_parse_endBody(p, false); + } + return; } // With a left brace, we are parsing a body. - else if (type == BC_LEX_LBRACE) { - + else if (type == BC_LEX_LBRACE) + { // We need to start a body if we are not expecting one yet. - if (!BC_PARSE_BODY(p)) { + if (!BC_PARSE_BODY(p)) + { bc_parse_startBody(p, BC_PARSE_FLAG_BRACE); bc_lex_next(&p->l); } // If we *are* expecting a body, that body should get a brace. This // takes care of braces being on a different line than if and loop // headers. - else { + else + { *(BC_PARSE_TOP_FLAG_PTR(p)) |= BC_PARSE_FLAG_BRACE; bc_lex_next(&p->l); bc_parse_body(p, true); @@ -1544,7 +1682,8 @@ static void bc_parse_stmt(BcParse *p) { // This happens when we are expecting a body and get a single statement, // i.e., a body with no braces surrounding it. Returns after for a clean // slate. - else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p)) { + else if (BC_PARSE_BODY(p) && !BC_PARSE_BRACE(p)) + { bc_parse_body(p, false); return; } @@ -1553,8 +1692,8 @@ static void bc_parse_stmt(BcParse *p) { len = p->flags.len; flags = BC_PARSE_TOP_FLAG(p); - switch (type) { - + switch (type) + { // All of these are valid for expressions. case BC_LEX_OP_INC: case BC_LEX_OP_DEC: @@ -1573,6 +1712,8 @@ static void bc_parse_stmt(BcParse *p) { #endif // BC_ENABLE_EXTRA_MATH case BC_LEX_KW_SQRT: case BC_LEX_KW_ABS: + case BC_LEX_KW_IS_NUMBER: + case BC_LEX_KW_IS_STRING: #if BC_ENABLE_EXTRA_MATH case BC_LEX_KW_IRAND: #endif // BC_ENABLE_EXTRA_MATH @@ -1589,6 +1730,9 @@ static void bc_parse_stmt(BcParse *p) { #if BC_ENABLE_EXTRA_MATH case BC_LEX_KW_MAXRAND: #endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_KW_LINE_LENGTH: + case BC_LEX_KW_GLOBAL_STACKS: + case BC_LEX_KW_LEADING_ZERO: { bc_parse_expr_status(p, BC_PARSE_PRINT, bc_parse_next_expr); break; @@ -1681,7 +1825,7 @@ static void bc_parse_stmt(BcParse *p) { { // Quit is a compile-time command. We don't exit directly, so the vm // can clean up. - vm.status = BC_STATUS_QUIT; + vm->status = BC_STATUS_QUIT; BC_JMP; break; } @@ -1698,36 +1842,129 @@ static void bc_parse_stmt(BcParse *p) { break; } - default: + case BC_LEX_EOF: + case BC_LEX_INVALID: + case BC_LEX_NEG: +#if BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_TRUNC: +#endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_POWER: + case BC_LEX_OP_MULTIPLY: + case BC_LEX_OP_DIVIDE: + case BC_LEX_OP_MODULUS: + case BC_LEX_OP_PLUS: +#if BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_PLACES: + case BC_LEX_OP_LSHIFT: + case BC_LEX_OP_RSHIFT: +#endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_REL_EQ: + case BC_LEX_OP_REL_LE: + case BC_LEX_OP_REL_GE: + case BC_LEX_OP_REL_NE: + case BC_LEX_OP_REL_LT: + case BC_LEX_OP_REL_GT: + case BC_LEX_OP_BOOL_OR: + case BC_LEX_OP_BOOL_AND: + case BC_LEX_OP_ASSIGN_POWER: + case BC_LEX_OP_ASSIGN_MULTIPLY: + case BC_LEX_OP_ASSIGN_DIVIDE: + case BC_LEX_OP_ASSIGN_MODULUS: + case BC_LEX_OP_ASSIGN_PLUS: + case BC_LEX_OP_ASSIGN_MINUS: +#if BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_ASSIGN_PLACES: + case BC_LEX_OP_ASSIGN_LSHIFT: + case BC_LEX_OP_ASSIGN_RSHIFT: +#endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_OP_ASSIGN: + case BC_LEX_NLINE: + case BC_LEX_WHITESPACE: + case BC_LEX_RPAREN: + case BC_LEX_LBRACKET: + case BC_LEX_COMMA: + case BC_LEX_RBRACKET: + case BC_LEX_LBRACE: + case BC_LEX_KW_AUTO: + case BC_LEX_KW_DEFINE: +#if DC_ENABLED + case BC_LEX_EXTENDED_REGISTERS: + case BC_LEX_EQ_NO_REG: + case BC_LEX_COLON: + case BC_LEX_EXECUTE: + case BC_LEX_PRINT_STACK: + case BC_LEX_CLEAR_STACK: + case BC_LEX_REG_STACK_LEVEL: + case BC_LEX_STACK_LEVEL: + case BC_LEX_DUPLICATE: + case BC_LEX_SWAP: + case BC_LEX_POP: + case BC_LEX_STORE_IBASE: + case BC_LEX_STORE_OBASE: + case BC_LEX_STORE_SCALE: +#if BC_ENABLE_EXTRA_MATH + case BC_LEX_STORE_SEED: +#endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_LOAD: + case BC_LEX_LOAD_POP: + case BC_LEX_STORE_PUSH: + case BC_LEX_PRINT_POP: + case BC_LEX_NQUIT: + case BC_LEX_EXEC_STACK_LENGTH: + case BC_LEX_SCALE_FACTOR: + case BC_LEX_ARRAY_LENGTH: +#endif // DC_ENABLED { bc_parse_err(p, BC_ERR_PARSE_TOKEN); } } // If the flags did not change, we expect a delimiter. - if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) { + if (len == p->flags.len && flags == BC_PARSE_TOP_FLAG(p)) + { if (BC_ERR(!bc_parse_isDelimiter(p))) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } } // Make sure semicolons are eaten. - while (p->l.t == BC_LEX_SCOLON) bc_lex_next(&p->l); -} + while (p->l.t == BC_LEX_SCOLON || p->l.t == BC_LEX_NLINE) + { + bc_lex_next(&p->l); + } -void bc_parse_parse(BcParse *p) { + // POSIX's grammar does not allow a function definition after a semicolon + // without a newline, so check specifically for that case and error if + // the POSIX standard flag is set. + if (p->l.last == BC_LEX_SCOLON && p->l.t == BC_LEX_KW_DEFINE && BC_IS_POSIX) + { + bc_parse_err(p, BC_ERR_POSIX_FUNC_AFTER_SEMICOLON); + } +} +void +bc_parse_parse(BcParse* p) +{ assert(p); - BC_SETJMP(exit); + BC_SETJMP_LOCKED(vm, exit); // We should not let an EOF get here unless some partial parse was not // completed, in which case, it's the user's fault. if (BC_ERR(p->l.t == BC_LEX_EOF)) bc_parse_err(p, BC_ERR_PARSE_EOF); // Functions need special parsing. - else if (p->l.t == BC_LEX_KW_DEFINE) { + else if (p->l.t == BC_LEX_KW_DEFINE) + { if (BC_ERR(BC_PARSE_NO_EXEC(p))) - bc_parse_err(p, BC_ERR_PARSE_TOKEN); + { + bc_parse_endif(p); + if (BC_ERR(BC_PARSE_NO_EXEC(p))) + { + bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } + } bc_parse_func(p); } @@ -1736,13 +1973,14 @@ void bc_parse_parse(BcParse *p) { exit: - BC_SIG_MAYLOCK; - // We need to reset on error. - if (BC_ERR(((vm.status && vm.status != BC_STATUS_QUIT) || vm.sig))) + if (BC_ERR(((vm->status && vm->status != BC_STATUS_QUIT) || vm->sig != 0))) + { bc_parse_reset(p); + } - BC_LONGJMP_CONT; + BC_LONGJMP_CONT(vm); + BC_SIG_MAYLOCK; } /** @@ -1756,8 +1994,8 @@ exit: * to tell the caller if the expression was empty and let the * caller handle it. */ -static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, - BcParseNext next) +static BcParseStatus +bc_parse_expr_err(BcParse* p, uint8_t flags, BcParseNext next) { BcInst prev = BC_INST_PRINT; uchar inst = BC_INST_INVALID; @@ -1797,15 +2035,19 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // We want to eat newlines if newlines are not a valid ending token. // This is for spacing in things like for loop headers. - if (!(flags & BC_PARSE_NOREAD)) { - while ((t = p->l.t) == BC_LEX_NLINE) bc_lex_next(&p->l); + if (!(flags & BC_PARSE_NOREAD)) + { + while ((t = p->l.t) == BC_LEX_NLINE) + { + bc_lex_next(&p->l); + } } // This is the Shunting-Yard algorithm loop. for (; !done && BC_PARSE_EXPR(t); t = p->l.t) { - switch (t) { - + switch (t) + { case BC_LEX_OP_INC: case BC_LEX_OP_DEC: { @@ -1828,7 +2070,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // The previous token must have been a leaf expression, or the // operator is in the wrong place. if (BC_ERR(!BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_TOKEN); + } // I can just add the instruction because // negative will already be taken care of. @@ -1874,10 +2118,13 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // We need to make sure the assignment is valid. if (!BC_PARSE_INST_VAR(prev)) + { bc_parse_err(p, BC_ERR_PARSE_ASSIGN); + } + + // Fallthrough. + BC_FALLTHROUGH } - // Fallthrough. - BC_FALLTHROUGH case BC_LEX_OP_POWER: case BC_LEX_OP_MULTIPLY: @@ -1901,18 +2148,22 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // This is true if the operator if the token is a prefix // operator. This is only for boolean not. - if (BC_PARSE_OP_PREFIX(t)) { - + if (BC_PARSE_OP_PREFIX(t)) + { // Prefix operators are only allowed after binary operators // or prefix operators. if (BC_ERR(!bin_last && !BC_PARSE_OP_PREFIX(p->l.last))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } } // If we execute the else, that means we have a binary operator. // If the previous operator was a prefix or a binary operator, // then a binary operator is not allowed. else if (BC_ERR(BC_PARSE_PREV_PREFIX(prev) || bin_last)) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } nrelops += (t >= BC_LEX_OP_REL_EQ && t <= BC_LEX_OP_REL_GT); prev = BC_PARSE_TOKEN_INST(t); @@ -1931,7 +2182,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // A left paren is *not* allowed right after a leaf expr. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } nparens += 1; rprn = incdec = can_assign = false; @@ -1948,16 +2201,21 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // This needs to be a status. The error is handled in // bc_parse_expr_status(). if (BC_ERR(p->l.last == BC_LEX_LPAREN)) + { return BC_PARSE_STATUS_EMPTY_EXPR; + } // The right paren must not come after a prefix or binary // operator. if (BC_ERR(bin_last || BC_PARSE_PREV_PREFIX(prev))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } // If there are no parens left, we are done, but we need another // token. - if (!nparens) { + if (!nparens) + { done = true; get_token = false; break; @@ -1979,7 +2237,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // A string is a leaf and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } bc_parse_addString(p); @@ -1994,7 +2254,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // A name is a leaf and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } get_token = bin_last = false; @@ -2011,7 +2273,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // A number is a leaf and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } // The number instruction is pushed in here. bc_parse_number(p); @@ -2034,7 +2298,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // All of these are leaves and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } prev = t - BC_LEX_KW_LAST + BC_INST_LAST; bc_parse_push(p, prev); @@ -2050,6 +2316,8 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, case BC_LEX_KW_LENGTH: case BC_LEX_KW_SQRT: case BC_LEX_KW_ABS: + case BC_LEX_KW_IS_NUMBER: + case BC_LEX_KW_IS_STRING: #if BC_ENABLE_EXTRA_MATH case BC_LEX_KW_IRAND: #endif // BC_ENABLE_EXTRA_MATH @@ -2057,7 +2325,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // All of these are leaves and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } bc_parse_builtin(p, t, flags, &prev); @@ -2078,14 +2348,21 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, #if BC_ENABLE_EXTRA_MATH case BC_LEX_KW_MAXRAND: #endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_KW_LINE_LENGTH: + case BC_LEX_KW_GLOBAL_STACKS: + case BC_LEX_KW_LEADING_ZERO: { // All of these are leaves and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } // Error if we have read and it's not allowed. else if (t == BC_LEX_KW_READ && BC_ERR(flags & BC_PARSE_NOREAD)) + { bc_parse_err(p, BC_ERR_EXEC_REC_READ); + } prev = t - BC_LEX_KW_READ + BC_INST_READ; bc_parse_noArgBuiltin(p, prev); @@ -2101,7 +2378,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // This is a leaf and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } // Scale needs special work because it can be a variable *or* a // function. @@ -2119,7 +2398,9 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, { // This is a leaf and cannot come right after a leaf. if (BC_ERR(BC_PARSE_LEAF(prev, bin_last, rprn))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } bc_parse_builtin3(p, t, flags, &prev); @@ -2130,13 +2411,64 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, break; } - default: + case BC_LEX_EOF: + case BC_LEX_INVALID: + case BC_LEX_NEG: + case BC_LEX_NLINE: + case BC_LEX_WHITESPACE: + case BC_LEX_LBRACKET: + case BC_LEX_COMMA: + case BC_LEX_RBRACKET: + case BC_LEX_LBRACE: + case BC_LEX_SCOLON: + case BC_LEX_RBRACE: + case BC_LEX_KW_AUTO: + case BC_LEX_KW_BREAK: + case BC_LEX_KW_CONTINUE: + case BC_LEX_KW_DEFINE: + case BC_LEX_KW_FOR: + case BC_LEX_KW_IF: + case BC_LEX_KW_LIMITS: + case BC_LEX_KW_RETURN: + case BC_LEX_KW_WHILE: + case BC_LEX_KW_HALT: + case BC_LEX_KW_PRINT: + case BC_LEX_KW_QUIT: + case BC_LEX_KW_STREAM: + case BC_LEX_KW_ELSE: +#if DC_ENABLED + case BC_LEX_EXTENDED_REGISTERS: + case BC_LEX_EQ_NO_REG: + case BC_LEX_COLON: + case BC_LEX_EXECUTE: + case BC_LEX_PRINT_STACK: + case BC_LEX_CLEAR_STACK: + case BC_LEX_REG_STACK_LEVEL: + case BC_LEX_STACK_LEVEL: + case BC_LEX_DUPLICATE: + case BC_LEX_SWAP: + case BC_LEX_POP: + case BC_LEX_STORE_IBASE: + case BC_LEX_STORE_OBASE: + case BC_LEX_STORE_SCALE: +#if BC_ENABLE_EXTRA_MATH + case BC_LEX_STORE_SEED: +#endif // BC_ENABLE_EXTRA_MATH + case BC_LEX_LOAD: + case BC_LEX_LOAD_POP: + case BC_LEX_STORE_PUSH: + case BC_LEX_PRINT_POP: + case BC_LEX_NQUIT: + case BC_LEX_EXEC_STACK_LENGTH: + case BC_LEX_SCALE_FACTOR: + case BC_LEX_ARRAY_LENGTH: +#endif // DC_ENABLED { -#ifndef NDEBUG +#if BC_DEBUG // We should never get here, even in debug builds. bc_parse_err(p, BC_ERR_PARSE_TOKEN); break; -#endif // NDEBUG +#endif // BC_DEBUG } } @@ -2145,14 +2477,16 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // Now that we have parsed the expression, we need to empty the operator // stack. - while (p->ops.len > ops_bgn) { - + while (p->ops.len > ops_bgn) + { top = BC_PARSE_TOP_OP(p); assign = top >= BC_LEX_OP_ASSIGN_POWER && top <= BC_LEX_OP_ASSIGN; // There should not be *any* parens on the stack anymore. if (BC_ERR(top == BC_LEX_LPAREN || top == BC_LEX_RPAREN)) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } bc_parse_push(p, BC_PARSE_TOKEN_INST(top)); @@ -2167,35 +2501,46 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, if (BC_ERR(nexprs != 1)) bc_parse_err(p, BC_ERR_PARSE_EXPR); // Check that the next token is correct. - for (i = 0; i < next.len && t != next.tokens[i]; ++i); + for (i = 0; i < next.len && t != next.tokens[i]; ++i) + { + continue; + } if (BC_ERR(i == next.len && !bc_parse_isDelimiter(p))) + { bc_parse_err(p, BC_ERR_PARSE_EXPR); + } // Check that POSIX would be happy with the number of relational operators. if (!(flags & BC_PARSE_REL) && nrelops) + { bc_parse_err(p, BC_ERR_POSIX_REL_POS); + } else if ((flags & BC_PARSE_REL) && nrelops > 1) + { bc_parse_err(p, BC_ERR_POSIX_MULTIREL); + } // If this is true, then we might be in a situation where we don't print. // We would want to have the increment/decrement operator not make an extra // copy if it's not necessary. - if (!(flags & BC_PARSE_NEEDVAL) && !pfirst) { - + if (!(flags & BC_PARSE_NEEDVAL) && !pfirst) + { // We have the easy case if the last operator was an assignment // operator. - if (assign) { + if (assign) + { inst = *((uchar*) bc_vec_top(&p->func->code)); inst += (BC_INST_ASSIGN_POWER_NO_VAL - BC_INST_ASSIGN_POWER); incdec = false; } // If we have an inc/dec operator and we are *not* printing, implement // the optimization to get rid of the extra copy. - else if (incdec && !(flags & BC_PARSE_PRINT)) { + else if (incdec && !(flags & BC_PARSE_PRINT)) + { inst = *((uchar*) bc_vec_top(&p->func->code)); incdec = (inst <= BC_INST_DEC); - inst = BC_INST_ASSIGN_PLUS_NO_VAL + (inst != BC_INST_INC && - inst != BC_INST_ASSIGN_PLUS); + inst = BC_INST_ASSIGN_PLUS_NO_VAL + + (inst != BC_INST_INC && inst != BC_INST_ASSIGN_PLUS); } // This condition allows us to change the previous assignment @@ -2215,8 +2560,8 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, } // If we might have to print... - if ((flags & BC_PARSE_PRINT)) { - + if ((flags & BC_PARSE_PRINT)) + { // With a paren first or the last operator not being an assignment, we // *do* want to print. if (pfirst || !assign) bc_parse_push(p, BC_INST_PRINT); @@ -2236,9 +2581,15 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, // Yes, this is one case where I reuse a variable for a different purpose; // in this case, incdec being true now means that newlines are not valid. for (incdec = true, i = 0; i < next.len && incdec; ++i) + { incdec = (next.tokens[i] != BC_LEX_NLINE); - if (incdec) { - while (p->l.t == BC_LEX_NLINE) bc_lex_next(&p->l); + } + if (incdec) + { + while (p->l.t == BC_LEX_NLINE) + { + bc_lex_next(&p->l); + } } return BC_PARSE_STATUS_SUCCESS; @@ -2251,15 +2602,20 @@ static BcParseStatus bc_parse_expr_err(BcParse *p, uint8_t flags, * @param flags The flags for what is valid in the expression. * @param next A set of tokens for what is valid *after* the expression. */ -static void bc_parse_expr_status(BcParse *p, uint8_t flags, BcParseNext next) { - +static void +bc_parse_expr_status(BcParse* p, uint8_t flags, BcParseNext next) +{ BcParseStatus s = bc_parse_expr_err(p, flags, next); if (BC_ERR(s == BC_PARSE_STATUS_EMPTY_EXPR)) + { bc_parse_err(p, BC_ERR_PARSE_EMPTY_EXPR); + } } -void bc_parse_expr(BcParse *p, uint8_t flags) { +void +bc_parse_expr(BcParse* p, uint8_t flags) +{ assert(p); bc_parse_expr_status(p, flags, bc_parse_next_read); } |