1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 6a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 3244d4804dSStefan Eßer * Definitions for bc only. 33252884aeSStefan Eßer * 34252884aeSStefan Eßer */ 35252884aeSStefan Eßer 36252884aeSStefan Eßer #ifndef BC_BC_H 37252884aeSStefan Eßer #define BC_BC_H 38252884aeSStefan Eßer 39252884aeSStefan Eßer #if BC_ENABLED 40252884aeSStefan Eßer 41252884aeSStefan Eßer #include <limits.h> 42252884aeSStefan Eßer #include <stdbool.h> 43252884aeSStefan Eßer 44252884aeSStefan Eßer #include <status.h> 45252884aeSStefan Eßer #include <lex.h> 46252884aeSStefan Eßer #include <parse.h> 47252884aeSStefan Eßer 4844d4804dSStefan Eßer /** 4944d4804dSStefan Eßer * The main function for bc. It just sets variables and passes its arguments 5044d4804dSStefan Eßer * through to @a bc_vm_boot(). 51a970610aSStefan Eßer * @return A status. 5244d4804dSStefan Eßer */ 53a970610aSStefan Eßer BcStatus 54*12e0d316SStefan Eßer bc_main(int argc, const char* argv[]); 55252884aeSStefan Eßer 5644d4804dSStefan Eßer // These are references to the help text, the library text, and the "filename" 5744d4804dSStefan Eßer // for the library. 58252884aeSStefan Eßer extern const char bc_help[]; 59252884aeSStefan Eßer extern const char bc_lib[]; 60252884aeSStefan Eßer extern const char* bc_lib_name; 61252884aeSStefan Eßer 6244d4804dSStefan Eßer // These are references to the second math library and its "filename." 63252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 64252884aeSStefan Eßer extern const char bc_lib2[]; 65252884aeSStefan Eßer extern const char* bc_lib2_name; 66252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 67252884aeSStefan Eßer 6844d4804dSStefan Eßer /** 6944d4804dSStefan Eßer * A struct containing information about a bc keyword. 7044d4804dSStefan Eßer */ 7178bc019dSStefan Eßer typedef struct BcLexKeyword 7278bc019dSStefan Eßer { 7344d4804dSStefan Eßer /// Holds the length of the keyword along with a bit that, if set, means the 7444d4804dSStefan Eßer /// keyword is used in POSIX bc. 75252884aeSStefan Eßer uchar data; 7644d4804dSStefan Eßer 7744d4804dSStefan Eßer /// The keyword text. 78d43fa8efSStefan Eßer const char name[14]; 79252884aeSStefan Eßer } BcLexKeyword; 80252884aeSStefan Eßer 8144d4804dSStefan Eßer /// Sets the most significant bit. Used for setting the POSIX bit in 8244d4804dSStefan Eßer /// BcLexKeyword's data field. 83252884aeSStefan Eßer #define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1)) 84252884aeSStefan Eßer 8544d4804dSStefan Eßer /// Returns non-zero if the keyword is POSIX, zero otherwise. 86252884aeSStefan Eßer #define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1))) 8744d4804dSStefan Eßer 8844d4804dSStefan Eßer /// Returns the length of the keyword. 89252884aeSStefan Eßer #define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1)))) 90252884aeSStefan Eßer 9144d4804dSStefan Eßer /// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c. 92252884aeSStefan Eßer #define BC_LEX_KW_ENTRY(a, b, c) \ 93a970610aSStefan Eßer { .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a } 94252884aeSStefan Eßer 9544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 9644d4804dSStefan Eßer 9744d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are 9844d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct. 99d101cdd6SStefan Eßer #define BC_LEX_NKWS (37) 10044d4804dSStefan Eßer 10144d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH 10244d4804dSStefan Eßer 10344d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are 10444d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct. 105d101cdd6SStefan Eßer #define BC_LEX_NKWS (33) 10644d4804dSStefan Eßer 10744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 10844d4804dSStefan Eßer 10944d4804dSStefan Eßer // The array of keywords and its length. 110252884aeSStefan Eßer extern const BcLexKeyword bc_lex_kws[]; 111252884aeSStefan Eßer extern const size_t bc_lex_kws_len; 112252884aeSStefan Eßer 11344d4804dSStefan Eßer /** 11444d4804dSStefan Eßer * The @a BcLexNext function for bc. (See include/lex.h for a definition of 11544d4804dSStefan Eßer * @a BcLexNext.) 11644d4804dSStefan Eßer * @param l The lexer. 11744d4804dSStefan Eßer */ 11878bc019dSStefan Eßer void 11978bc019dSStefan Eßer bc_lex_token(BcLex* l); 120252884aeSStefan Eßer 12144d4804dSStefan Eßer // The following section is for flags needed when parsing bc code. These flags 12244d4804dSStefan Eßer // are complicated, but necessary. Why you ask? Because bc's standard is awful. 12344d4804dSStefan Eßer // 12444d4804dSStefan Eßer // If you don't believe me, go read the bc Parsing section of the Development 12544d4804dSStefan Eßer // manual (manuals/development.md). Then come back. 12644d4804dSStefan Eßer // 12744d4804dSStefan Eßer // In other words, these flags are the sign declaring, "Here be dragons." 12844d4804dSStefan Eßer 12944d4804dSStefan Eßer /** 13044d4804dSStefan Eßer * This returns a pointer to the set of flags at the top of the flag stack. 13144d4804dSStefan Eßer * @a p is expected to be a BcParse pointer. 13244d4804dSStefan Eßer * @param p The parser. 13344d4804dSStefan Eßer * @return A pointer to the top flag set. 13444d4804dSStefan Eßer */ 135252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags)) 13644d4804dSStefan Eßer 13744d4804dSStefan Eßer /** 13844d4804dSStefan Eßer * This returns the flag set at the top of the flag stack. @a p is expected to 13944d4804dSStefan Eßer * be a BcParse pointer. 14044d4804dSStefan Eßer * @param p The parser. 14144d4804dSStefan Eßer * @return The top flag set. 14244d4804dSStefan Eßer */ 143252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p))) 144252884aeSStefan Eßer 14544d4804dSStefan Eßer // After this point, all flag #defines are in sets of 2: one to define the flag, 14644d4804dSStefan Eßer // and one to define a way to grab the flag from the flag set at the top of the 14744d4804dSStefan Eßer // flag stack. All `p` arguments are pointers to a BcParse. 14844d4804dSStefan Eßer 14944d4804dSStefan Eßer // This flag is set if the parser has seen a left brace. 150252884aeSStefan Eßer #define BC_PARSE_FLAG_BRACE (UINTMAX_C(1) << 0) 151252884aeSStefan Eßer #define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE) 152252884aeSStefan Eßer 15344d4804dSStefan Eßer // This flag is set if the parser is parsing inside of the braces of a function 15444d4804dSStefan Eßer // body. 155252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1) << 1) 156252884aeSStefan Eßer #define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER) 157252884aeSStefan Eßer 15844d4804dSStefan Eßer // This flag is set if the parser is parsing a function. It is different from 15944d4804dSStefan Eßer // the one above because it is set if it is parsing a function body *or* header, 16044d4804dSStefan Eßer // not just if it's parsing a function body. 161252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC (UINTMAX_C(1) << 2) 162252884aeSStefan Eßer #define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC) 163252884aeSStefan Eßer 16444d4804dSStefan Eßer // This flag is set if the parser is expecting to parse a body, whether of a 16544d4804dSStefan Eßer // function, an if statement, or a loop. 166252884aeSStefan Eßer #define BC_PARSE_FLAG_BODY (UINTMAX_C(1) << 3) 167252884aeSStefan Eßer #define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY) 168252884aeSStefan Eßer 16944d4804dSStefan Eßer // This flag is set if bc is parsing a loop. This is important because the break 17044d4804dSStefan Eßer // and continue keywords are only valid inside of a loop. 171252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP (UINTMAX_C(1) << 4) 172252884aeSStefan Eßer #define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP) 173252884aeSStefan Eßer 17444d4804dSStefan Eßer // This flag is set if bc is parsing the body of a loop. It is different from 17544d4804dSStefan Eßer // the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from 17644d4804dSStefan Eßer // @a BC_PARSE_FLAG_FUNC. 177252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1) << 5) 178252884aeSStefan Eßer #define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER) 179252884aeSStefan Eßer 18044d4804dSStefan Eßer // This flag is set if bc is parsing an if statement. 181252884aeSStefan Eßer #define BC_PARSE_FLAG_IF (UINTMAX_C(1) << 6) 182252884aeSStefan Eßer #define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF) 183252884aeSStefan Eßer 18444d4804dSStefan Eßer // This flag is set if bc is parsing an else statement. This is important 18544d4804dSStefan Eßer // because of "else if" constructions, among other things. 186252884aeSStefan Eßer #define BC_PARSE_FLAG_ELSE (UINTMAX_C(1) << 7) 187252884aeSStefan Eßer #define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE) 188252884aeSStefan Eßer 18944d4804dSStefan Eßer // This flag is set if bc just finished parsing an if statement and its body. 19044d4804dSStefan Eßer // It tells the parser that it can probably expect an else statement next. This 19144d4804dSStefan Eßer // flag is, thus, one of the most subtle. 192252884aeSStefan Eßer #define BC_PARSE_FLAG_IF_END (UINTMAX_C(1) << 8) 193252884aeSStefan Eßer #define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END) 194252884aeSStefan Eßer 19544d4804dSStefan Eßer /** 19644d4804dSStefan Eßer * This returns true if bc is in a state where it should not execute any code 19744d4804dSStefan Eßer * at all. 19844d4804dSStefan Eßer * @param p The parser. 19944d4804dSStefan Eßer * @return True if execution cannot proceed, false otherwise. 20044d4804dSStefan Eßer */ 201252884aeSStefan Eßer #define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0) 202252884aeSStefan Eßer 20344d4804dSStefan Eßer /** 20444d4804dSStefan Eßer * This returns true if the token @a t is a statement delimiter, which is 20544d4804dSStefan Eßer * either a newline or a semicolon. 20644d4804dSStefan Eßer * @param t The token to check. 20744d4804dSStefan Eßer * @return True if t is a statement delimiter token; false otherwise. 20844d4804dSStefan Eßer */ 209252884aeSStefan Eßer #define BC_PARSE_DELIMITER(t) \ 210252884aeSStefan Eßer ((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF) 211252884aeSStefan Eßer 21244d4804dSStefan Eßer /** 21344d4804dSStefan Eßer * This is poorly named, but it basically returns whether or not the current 21444d4804dSStefan Eßer * state is valid for the end of an else statement. 21544d4804dSStefan Eßer * @param f The flag set to be checked. 21644d4804dSStefan Eßer * @return True if the state is valid for the end of an else statement. 21744d4804dSStefan Eßer */ 218252884aeSStefan Eßer #define BC_PARSE_BLOCK_STMT(f) \ 219252884aeSStefan Eßer ((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER)) 220252884aeSStefan Eßer 22144d4804dSStefan Eßer /** 22244d4804dSStefan Eßer * This returns the value of the data for an operator with precedence @a p and 22344d4804dSStefan Eßer * associativity @a l (true if left associative, false otherwise). This is used 22444d4804dSStefan Eßer * to construct an array of operators, bc_parse_ops, in src/data.c. 22544d4804dSStefan Eßer * @param p The precedence. 22644d4804dSStefan Eßer * @param l True if the operator is left associative, false otherwise. 22744d4804dSStefan Eßer * @return The data for the operator. 22844d4804dSStefan Eßer */ 229252884aeSStefan Eßer #define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l))) 230252884aeSStefan Eßer 23144d4804dSStefan Eßer /** 23244d4804dSStefan Eßer * Returns the operator data for the lex token @a t. 23344d4804dSStefan Eßer * @param t The token to return operator data for. 23444d4804dSStefan Eßer * @return The operator data for @a t. 23544d4804dSStefan Eßer */ 236252884aeSStefan Eßer #define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)] 23744d4804dSStefan Eßer 23844d4804dSStefan Eßer /** 23944d4804dSStefan Eßer * Returns non-zero if operator @a op is left associative, zero otherwise. 24044d4804dSStefan Eßer * @param op The operator to test for associativity. 24144d4804dSStefan Eßer * @return Non-zero if the operator is left associative, zero otherwise. 24244d4804dSStefan Eßer */ 243252884aeSStefan Eßer #define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1)) 24444d4804dSStefan Eßer 24544d4804dSStefan Eßer /** 24644d4804dSStefan Eßer * Returns the precedence of operator @a op. Lower number means higher 24744d4804dSStefan Eßer * precedence. 24844d4804dSStefan Eßer * @param op The operator to return the precedence of. 24944d4804dSStefan Eßer * @return The precedence of @a op. 25044d4804dSStefan Eßer */ 251252884aeSStefan Eßer #define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1))) 252252884aeSStefan Eßer 25344d4804dSStefan Eßer /** 25444d4804dSStefan Eßer * A macro to easily define a series of bits for whether a lex token is an 25544d4804dSStefan Eßer * expression token or not. It takes 8 expression bits, corresponding to the 8 25644d4804dSStefan Eßer * bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c. 25744d4804dSStefan Eßer * @param e1 The first bit. 25844d4804dSStefan Eßer * @param e2 The second bit. 25944d4804dSStefan Eßer * @param e3 The third bit. 26044d4804dSStefan Eßer * @param e4 The fourth bit. 26144d4804dSStefan Eßer * @param e5 The fifth bit. 26244d4804dSStefan Eßer * @param e6 The sixth bit. 26344d4804dSStefan Eßer * @param e7 The seventh bit. 26444d4804dSStefan Eßer * @param e8 The eighth bit. 26544d4804dSStefan Eßer * @return An expression entry for bc_parse_exprs[]. 26644d4804dSStefan Eßer */ 267252884aeSStefan Eßer #define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \ 268252884aeSStefan Eßer ((UINTMAX_C(e1) << 7) | (UINTMAX_C(e2) << 6) | (UINTMAX_C(e3) << 5) | \ 269252884aeSStefan Eßer (UINTMAX_C(e4) << 4) | (UINTMAX_C(e5) << 3) | (UINTMAX_C(e6) << 2) | \ 270252884aeSStefan Eßer (UINTMAX_C(e7) << 1) | (UINTMAX_C(e8) << 0)) 271252884aeSStefan Eßer 27244d4804dSStefan Eßer /** 27344d4804dSStefan Eßer * Returns true if token @a i is a token that belongs in an expression. 27444d4804dSStefan Eßer * @param i The token to test. 27544d4804dSStefan Eßer * @return True if i is an expression token, false otherwise. 27644d4804dSStefan Eßer */ 277252884aeSStefan Eßer #define BC_PARSE_EXPR(i) \ 278252884aeSStefan Eßer (bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07)))) 279252884aeSStefan Eßer 28044d4804dSStefan Eßer /** 28144d4804dSStefan Eßer * Returns the operator (by lex token) that is at the top of the operator 28244d4804dSStefan Eßer * stack. 28344d4804dSStefan Eßer * @param p The parser. 28444d4804dSStefan Eßer * @return The operator that is at the top of the operator stack, as a lex 28544d4804dSStefan Eßer * token. 28644d4804dSStefan Eßer */ 287252884aeSStefan Eßer #define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops))) 28844d4804dSStefan Eßer 28944d4804dSStefan Eßer /** 29044d4804dSStefan Eßer * Returns true if bc has a "leaf" token. A "leaf" token is one that can stand 29144d4804dSStefan Eßer * alone in an expression. For example, a number by itself can be an expression, 29244d4804dSStefan Eßer * but a binary operator, while valid for an expression, cannot be alone in the 29344d4804dSStefan Eßer * expression. It must have an expression to the left and right of itself. See 29444d4804dSStefan Eßer * the documentation for @a bc_parse_expr_err() in src/bc_parse.c. 29544d4804dSStefan Eßer * @param prev The previous token as an instruction. 29644d4804dSStefan Eßer * @param bin_last True if that last operator was a binary operator, false 29744d4804dSStefan Eßer * otherwise. 29844d4804dSStefan Eßer * @param rparen True if the last operator was a right paren. 29944d4804dSStefan Eßer * return True if the last token was a leaf token, false otherwise. 30044d4804dSStefan Eßer */ 301252884aeSStefan Eßer #define BC_PARSE_LEAF(prev, bin_last, rparen) \ 302252884aeSStefan Eßer (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev))) 303252884aeSStefan Eßer 30444d4804dSStefan Eßer /** 30544d4804dSStefan Eßer * This returns true if the token @a t should be treated as though it's a 30644d4804dSStefan Eßer * variable. This goes for actual variables, array elements, and globals. 30744d4804dSStefan Eßer * @param t The token to test. 30844d4804dSStefan Eßer * @return True if @a t should be treated as though it's a variable, false 30944d4804dSStefan Eßer * otherwise. 31044d4804dSStefan Eßer */ 31144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 312252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \ 313252884aeSStefan Eßer ((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY) 31444d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH 315252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \ 316252884aeSStefan Eßer ((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY) 31744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 318252884aeSStefan Eßer 31944d4804dSStefan Eßer /** 32044d4804dSStefan Eßer * Returns true if the previous token @a p (in the form of a bytecode 32144d4804dSStefan Eßer * instruction) is a prefix operator. The fact that it is for bytecode 32244d4804dSStefan Eßer * instructions is what makes it different from @a BC_PARSE_OP_PREFIX below. 32344d4804dSStefan Eßer * @param p The previous token. 32444d4804dSStefan Eßer * @return True if @a p is a prefix operator. 32544d4804dSStefan Eßer */ 32644d4804dSStefan Eßer #define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT) 32744d4804dSStefan Eßer 32844d4804dSStefan Eßer /** 32944d4804dSStefan Eßer * Returns true if token @a t is a prefix operator. 33044d4804dSStefan Eßer * @param t The token to test. 33144d4804dSStefan Eßer * @return True if @a t is a prefix operator, false otherwise. 33244d4804dSStefan Eßer */ 333252884aeSStefan Eßer #define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG) 334252884aeSStefan Eßer 33544d4804dSStefan Eßer /** 33644d4804dSStefan Eßer * We can calculate the conversion between tokens and bytecode instructions by 33744d4804dSStefan Eßer * subtracting the position of the first operator in the lex enum and adding the 33844d4804dSStefan Eßer * position of the first in the instruction enum. Note: This only works for 33944d4804dSStefan Eßer * binary operators. 34044d4804dSStefan Eßer * @param t The token to turn into an instruction. 34144d4804dSStefan Eßer * @return The token as an instruction. 34244d4804dSStefan Eßer */ 343252884aeSStefan Eßer #define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG)) 344252884aeSStefan Eßer 34544d4804dSStefan Eßer /** 34644d4804dSStefan Eßer * Returns true if the token is a bc keyword. 34744d4804dSStefan Eßer * @param t The token to check. 34844d4804dSStefan Eßer * @return True if @a t is a bc keyword, false otherwise. 34944d4804dSStefan Eßer */ 35044d4804dSStefan Eßer #define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE) 35144d4804dSStefan Eßer 35244d4804dSStefan Eßer /// A struct that holds data about what tokens should be expected next. There 35344d4804dSStefan Eßer /// are a few instances of these, all named because they are used in specific 35444d4804dSStefan Eßer /// cases. Basically, in certain situations, it's useful to use the same code, 35544d4804dSStefan Eßer /// but have a list of valid tokens. 35644d4804dSStefan Eßer /// 35744d4804dSStefan Eßer /// Obviously, @a len is the number of tokens in the @a tokens array. If more 35844d4804dSStefan Eßer /// than 4 is needed in the future, @a tokens will have to be changed. 35978bc019dSStefan Eßer typedef struct BcParseNext 36078bc019dSStefan Eßer { 36144d4804dSStefan Eßer /// The number of tokens in the tokens array. 36244d4804dSStefan Eßer uchar len; 36344d4804dSStefan Eßer 36444d4804dSStefan Eßer /// The tokens that can be expected next. 36544d4804dSStefan Eßer uchar tokens[4]; 36644d4804dSStefan Eßer 36744d4804dSStefan Eßer } BcParseNext; 36844d4804dSStefan Eßer 36944d4804dSStefan Eßer /// A macro to construct an array literal of tokens from a parameter list. 37044d4804dSStefan Eßer #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ } 37144d4804dSStefan Eßer 37244d4804dSStefan Eßer /// A macro to generate a BcParseNext literal from BcParseNext data. See 37344d4804dSStefan Eßer /// src/data.c for examples. 37444d4804dSStefan Eßer #define BC_PARSE_NEXT(a, ...) \ 375a970610aSStefan Eßer { .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) } 37644d4804dSStefan Eßer 37744d4804dSStefan Eßer /// A status returned by @a bc_parse_expr_err(). It can either return success or 37844d4804dSStefan Eßer /// an error indicating an empty expression. 37978bc019dSStefan Eßer typedef enum BcParseStatus 38078bc019dSStefan Eßer { 381252884aeSStefan Eßer BC_PARSE_STATUS_SUCCESS, 382252884aeSStefan Eßer BC_PARSE_STATUS_EMPTY_EXPR, 383252884aeSStefan Eßer 384252884aeSStefan Eßer } BcParseStatus; 385252884aeSStefan Eßer 38644d4804dSStefan Eßer /** 38744d4804dSStefan Eßer * The @a BcParseExpr function for bc. (See include/parse.h for a definition of 38844d4804dSStefan Eßer * @a BcParseExpr.) 38944d4804dSStefan Eßer * @param p The parser. 39044d4804dSStefan Eßer * @param flags Flags that define the requirements that the parsed code must 39144d4804dSStefan Eßer * meet or an error will result. See @a BcParseExpr for more info. 39244d4804dSStefan Eßer */ 39378bc019dSStefan Eßer void 39478bc019dSStefan Eßer bc_parse_expr(BcParse* p, uint8_t flags); 395252884aeSStefan Eßer 39644d4804dSStefan Eßer /** 39744d4804dSStefan Eßer * The @a BcParseParse function for bc. (See include/parse.h for a definition of 39844d4804dSStefan Eßer * @a BcParseParse.) 39944d4804dSStefan Eßer * @param p The parser. 40044d4804dSStefan Eßer */ 40178bc019dSStefan Eßer void 40278bc019dSStefan Eßer bc_parse_parse(BcParse* p); 403252884aeSStefan Eßer 404a30efc5cSStefan Eßer /** 405a30efc5cSStefan Eßer * Ends a series of if statements. This is to ensure that full parses happen 406a30efc5cSStefan Eßer * when a file finishes or before defining a function. Without this, bc thinks 407a30efc5cSStefan Eßer * that it cannot parse any further. But if we reach the end of a file or a 408a30efc5cSStefan Eßer * function definition, we know we can add an empty else clause. 409a30efc5cSStefan Eßer * @param p The parser. 410a30efc5cSStefan Eßer */ 41178bc019dSStefan Eßer void 41278bc019dSStefan Eßer bc_parse_endif(BcParse* p); 413a30efc5cSStefan Eßer 41444d4804dSStefan Eßer /// References to the signal message and its length. 415252884aeSStefan Eßer extern const char bc_sig_msg[]; 416252884aeSStefan Eßer extern const uchar bc_sig_msg_len; 417252884aeSStefan Eßer 41844d4804dSStefan Eßer /// A reference to an array of bits that are set if the corresponding lex token 41944d4804dSStefan Eßer /// is valid in an expression. 420252884aeSStefan Eßer extern const uint8_t bc_parse_exprs[]; 42144d4804dSStefan Eßer 42244d4804dSStefan Eßer /// A reference to an array of bc operators. 423252884aeSStefan Eßer extern const uchar bc_parse_ops[]; 42444d4804dSStefan Eßer 42544d4804dSStefan Eßer // References to the various instances of BcParseNext's. 42644d4804dSStefan Eßer 42744d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing normal 42844d4804dSStefan Eßer /// expressions. More accurately. these are the tokens that are valid for 42944d4804dSStefan Eßer /// *ending* the expression. 430252884aeSStefan Eßer extern const BcParseNext bc_parse_next_expr; 43144d4804dSStefan Eßer 43244d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing function 43344d4804dSStefan Eßer /// parameters (well, actually arguments). 43444d4804dSStefan Eßer extern const BcParseNext bc_parse_next_arg; 43544d4804dSStefan Eßer 43644d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a print 43744d4804dSStefan Eßer /// statement. 438252884aeSStefan Eßer extern const BcParseNext bc_parse_next_print; 43944d4804dSStefan Eßer 44044d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing things like 44144d4804dSStefan Eßer /// loop headers and builtin functions where the only thing expected is a right 44244d4804dSStefan Eßer /// paren. 44344d4804dSStefan Eßer /// 44444d4804dSStefan Eßer /// The name is an artifact of history, and is related to @a BC_PARSE_REL (see 44544d4804dSStefan Eßer /// include/parse.h). It refers to how POSIX only allows some operators as part 44644d4804dSStefan Eßer /// of the conditional of for loops, while loops, and if statements. 447252884aeSStefan Eßer extern const BcParseNext bc_parse_next_rel; 44844d4804dSStefan Eßer 44944d4804dSStefan Eßer // What tokens are valid as next tokens when parsing an array element 45044d4804dSStefan Eßer // expression. 451252884aeSStefan Eßer extern const BcParseNext bc_parse_next_elem; 45244d4804dSStefan Eßer 45344d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing the first 45444d4804dSStefan Eßer /// two parts of a for loop header. 455252884aeSStefan Eßer extern const BcParseNext bc_parse_next_for; 45644d4804dSStefan Eßer 45744d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a read 45844d4804dSStefan Eßer /// expression. 459252884aeSStefan Eßer extern const BcParseNext bc_parse_next_read; 460252884aeSStefan Eßer 46144d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a builtin 46244d4804dSStefan Eßer /// function with multiple arguments. 46344d4804dSStefan Eßer extern const BcParseNext bc_parse_next_builtin; 46444d4804dSStefan Eßer 465d213476dSStefan Eßer #else // BC_ENABLED 466d213476dSStefan Eßer 46744d4804dSStefan Eßer // If bc is not enabled, execution is always possible because dc has strict 46844d4804dSStefan Eßer // rules that ensure execution can always proceed safely. 469d213476dSStefan Eßer #define BC_PARSE_NO_EXEC(p) (0) 470d213476dSStefan Eßer 471252884aeSStefan Eßer #endif // BC_ENABLED 472252884aeSStefan Eßer 473252884aeSStefan Eßer #endif // BC_BC_H 474