1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 610328f8bSStefan Eßer * Copyright (c) 2018-2021 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(). 5144d4804dSStefan Eßer */ 5244d4804dSStefan Eßer void bc_main(int argc, char *argv[]); 53252884aeSStefan Eßer 5444d4804dSStefan Eßer // These are references to the help text, the library text, and the "filename" 5544d4804dSStefan Eßer // for the library. 56252884aeSStefan Eßer extern const char bc_help[]; 57252884aeSStefan Eßer extern const char bc_lib[]; 58252884aeSStefan Eßer extern const char* bc_lib_name; 59252884aeSStefan Eßer 6044d4804dSStefan Eßer // These are references to the second math library and its "filename." 61252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH 62252884aeSStefan Eßer extern const char bc_lib2[]; 63252884aeSStefan Eßer extern const char* bc_lib2_name; 64252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 65252884aeSStefan Eßer 6644d4804dSStefan Eßer /** 6744d4804dSStefan Eßer * A struct containing information about a bc keyword. 6844d4804dSStefan Eßer */ 69252884aeSStefan Eßer typedef struct BcLexKeyword { 7044d4804dSStefan Eßer 7144d4804dSStefan Eßer /// Holds the length of the keyword along with a bit that, if set, means the 7244d4804dSStefan Eßer /// keyword is used in POSIX bc. 73252884aeSStefan Eßer uchar data; 7444d4804dSStefan Eßer 7544d4804dSStefan Eßer /// The keyword text. 76d43fa8efSStefan Eßer const char name[14]; 77252884aeSStefan Eßer } BcLexKeyword; 78252884aeSStefan Eßer 7944d4804dSStefan Eßer /// Sets the most significant bit. Used for setting the POSIX bit in 8044d4804dSStefan Eßer /// BcLexKeyword's data field. 81252884aeSStefan Eßer #define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1)) 82252884aeSStefan Eßer 8344d4804dSStefan Eßer /// Returns non-zero if the keyword is POSIX, zero otherwise. 84252884aeSStefan Eßer #define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1))) 8544d4804dSStefan Eßer 8644d4804dSStefan Eßer /// Returns the length of the keyword. 87252884aeSStefan Eßer #define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1)))) 88252884aeSStefan Eßer 8944d4804dSStefan Eßer /// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c. 90252884aeSStefan Eßer #define BC_LEX_KW_ENTRY(a, b, c) \ 91252884aeSStefan Eßer { .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a } 92252884aeSStefan Eßer 9344d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 9444d4804dSStefan Eßer 9544d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are 9644d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct. 97d43fa8efSStefan Eßer #define BC_LEX_NKWS (35) 9844d4804dSStefan Eßer 9944d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH 10044d4804dSStefan Eßer 10144d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are 10244d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct. 103d43fa8efSStefan Eßer #define BC_LEX_NKWS (31) 10444d4804dSStefan Eßer 10544d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 10644d4804dSStefan Eßer 10744d4804dSStefan Eßer // The array of keywords and its length. 108252884aeSStefan Eßer extern const BcLexKeyword bc_lex_kws[]; 109252884aeSStefan Eßer extern const size_t bc_lex_kws_len; 110252884aeSStefan Eßer 11144d4804dSStefan Eßer /** 11244d4804dSStefan Eßer * The @a BcLexNext function for bc. (See include/lex.h for a definition of 11344d4804dSStefan Eßer * @a BcLexNext.) 11444d4804dSStefan Eßer * @param l The lexer. 11544d4804dSStefan Eßer */ 116252884aeSStefan Eßer void bc_lex_token(BcLex *l); 117252884aeSStefan Eßer 11844d4804dSStefan Eßer // The following section is for flags needed when parsing bc code. These flags 11944d4804dSStefan Eßer // are complicated, but necessary. Why you ask? Because bc's standard is awful. 12044d4804dSStefan Eßer // 12144d4804dSStefan Eßer // If you don't believe me, go read the bc Parsing section of the Development 12244d4804dSStefan Eßer // manual (manuals/development.md). Then come back. 12344d4804dSStefan Eßer // 12444d4804dSStefan Eßer // In other words, these flags are the sign declaring, "Here be dragons." 12544d4804dSStefan Eßer 12644d4804dSStefan Eßer /** 12744d4804dSStefan Eßer * This returns a pointer to the set of flags at the top of the flag stack. 12844d4804dSStefan Eßer * @a p is expected to be a BcParse pointer. 12944d4804dSStefan Eßer * @param p The parser. 13044d4804dSStefan Eßer * @return A pointer to the top flag set. 13144d4804dSStefan Eßer */ 132252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags)) 13344d4804dSStefan Eßer 13444d4804dSStefan Eßer /** 13544d4804dSStefan Eßer * This returns the flag set at the top of the flag stack. @a p is expected to 13644d4804dSStefan Eßer * be a BcParse pointer. 13744d4804dSStefan Eßer * @param p The parser. 13844d4804dSStefan Eßer * @return The top flag set. 13944d4804dSStefan Eßer */ 140252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p))) 141252884aeSStefan Eßer 14244d4804dSStefan Eßer // After this point, all flag #defines are in sets of 2: one to define the flag, 14344d4804dSStefan Eßer // and one to define a way to grab the flag from the flag set at the top of the 14444d4804dSStefan Eßer // flag stack. All `p` arguments are pointers to a BcParse. 14544d4804dSStefan Eßer 14644d4804dSStefan Eßer // This flag is set if the parser has seen a left brace. 147252884aeSStefan Eßer #define BC_PARSE_FLAG_BRACE (UINTMAX_C(1)<<0) 148252884aeSStefan Eßer #define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE) 149252884aeSStefan Eßer 15044d4804dSStefan Eßer // This flag is set if the parser is parsing inside of the braces of a function 15144d4804dSStefan Eßer // body. 152252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1)<<1) 153252884aeSStefan Eßer #define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER) 154252884aeSStefan Eßer 15544d4804dSStefan Eßer // This flag is set if the parser is parsing a function. It is different from 15644d4804dSStefan Eßer // the one above because it is set if it is parsing a function body *or* header, 15744d4804dSStefan Eßer // not just if it's parsing a function body. 158252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC (UINTMAX_C(1)<<2) 159252884aeSStefan Eßer #define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC) 160252884aeSStefan Eßer 16144d4804dSStefan Eßer // This flag is set if the parser is expecting to parse a body, whether of a 16244d4804dSStefan Eßer // function, an if statement, or a loop. 163252884aeSStefan Eßer #define BC_PARSE_FLAG_BODY (UINTMAX_C(1)<<3) 164252884aeSStefan Eßer #define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY) 165252884aeSStefan Eßer 16644d4804dSStefan Eßer // This flag is set if bc is parsing a loop. This is important because the break 16744d4804dSStefan Eßer // and continue keywords are only valid inside of a loop. 168252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP (UINTMAX_C(1)<<4) 169252884aeSStefan Eßer #define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP) 170252884aeSStefan Eßer 17144d4804dSStefan Eßer // This flag is set if bc is parsing the body of a loop. It is different from 17244d4804dSStefan Eßer // the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from 17344d4804dSStefan Eßer // @a BC_PARSE_FLAG_FUNC. 174252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1)<<5) 175252884aeSStefan Eßer #define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER) 176252884aeSStefan Eßer 17744d4804dSStefan Eßer // This flag is set if bc is parsing an if statement. 178252884aeSStefan Eßer #define BC_PARSE_FLAG_IF (UINTMAX_C(1)<<6) 179252884aeSStefan Eßer #define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF) 180252884aeSStefan Eßer 18144d4804dSStefan Eßer // This flag is set if bc is parsing an else statement. This is important 18244d4804dSStefan Eßer // because of "else if" constructions, among other things. 183252884aeSStefan Eßer #define BC_PARSE_FLAG_ELSE (UINTMAX_C(1)<<7) 184252884aeSStefan Eßer #define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE) 185252884aeSStefan Eßer 18644d4804dSStefan Eßer // This flag is set if bc just finished parsing an if statement and its body. 18744d4804dSStefan Eßer // It tells the parser that it can probably expect an else statement next. This 18844d4804dSStefan Eßer // flag is, thus, one of the most subtle. 189252884aeSStefan Eßer #define BC_PARSE_FLAG_IF_END (UINTMAX_C(1)<<8) 190252884aeSStefan Eßer #define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END) 191252884aeSStefan Eßer 19244d4804dSStefan Eßer /** 19344d4804dSStefan Eßer * This returns true if bc is in a state where it should not execute any code 19444d4804dSStefan Eßer * at all. 19544d4804dSStefan Eßer * @param p The parser. 19644d4804dSStefan Eßer * @return True if execution cannot proceed, false otherwise. 19744d4804dSStefan Eßer */ 198252884aeSStefan Eßer #define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0) 199252884aeSStefan Eßer 20044d4804dSStefan Eßer /** 20144d4804dSStefan Eßer * This returns true if the token @a t is a statement delimiter, which is 20244d4804dSStefan Eßer * either a newline or a semicolon. 20344d4804dSStefan Eßer * @param t The token to check. 20444d4804dSStefan Eßer * @return True if t is a statement delimiter token; false otherwise. 20544d4804dSStefan Eßer */ 206252884aeSStefan Eßer #define BC_PARSE_DELIMITER(t) \ 207252884aeSStefan Eßer ((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF) 208252884aeSStefan Eßer 20944d4804dSStefan Eßer /** 21044d4804dSStefan Eßer * This is poorly named, but it basically returns whether or not the current 21144d4804dSStefan Eßer * state is valid for the end of an else statement. 21244d4804dSStefan Eßer * @param f The flag set to be checked. 21344d4804dSStefan Eßer * @return True if the state is valid for the end of an else statement. 21444d4804dSStefan Eßer */ 215252884aeSStefan Eßer #define BC_PARSE_BLOCK_STMT(f) \ 216252884aeSStefan Eßer ((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER)) 217252884aeSStefan Eßer 21844d4804dSStefan Eßer /** 21944d4804dSStefan Eßer * This returns the value of the data for an operator with precedence @a p and 22044d4804dSStefan Eßer * associativity @a l (true if left associative, false otherwise). This is used 22144d4804dSStefan Eßer * to construct an array of operators, bc_parse_ops, in src/data.c. 22244d4804dSStefan Eßer * @param p The precedence. 22344d4804dSStefan Eßer * @param l True if the operator is left associative, false otherwise. 22444d4804dSStefan Eßer * @return The data for the operator. 22544d4804dSStefan Eßer */ 226252884aeSStefan Eßer #define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l))) 227252884aeSStefan Eßer 22844d4804dSStefan Eßer /** 22944d4804dSStefan Eßer * Returns the operator data for the lex token @a t. 23044d4804dSStefan Eßer * @param t The token to return operator data for. 23144d4804dSStefan Eßer * @return The operator data for @a t. 23244d4804dSStefan Eßer */ 233252884aeSStefan Eßer #define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)] 23444d4804dSStefan Eßer 23544d4804dSStefan Eßer /** 23644d4804dSStefan Eßer * Returns non-zero if operator @a op is left associative, zero otherwise. 23744d4804dSStefan Eßer * @param op The operator to test for associativity. 23844d4804dSStefan Eßer * @return Non-zero if the operator is left associative, zero otherwise. 23944d4804dSStefan Eßer */ 240252884aeSStefan Eßer #define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1)) 24144d4804dSStefan Eßer 24244d4804dSStefan Eßer /** 24344d4804dSStefan Eßer * Returns the precedence of operator @a op. Lower number means higher 24444d4804dSStefan Eßer * precedence. 24544d4804dSStefan Eßer * @param op The operator to return the precedence of. 24644d4804dSStefan Eßer * @return The precedence of @a op. 24744d4804dSStefan Eßer */ 248252884aeSStefan Eßer #define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1))) 249252884aeSStefan Eßer 25044d4804dSStefan Eßer /** 25144d4804dSStefan Eßer * A macro to easily define a series of bits for whether a lex token is an 25244d4804dSStefan Eßer * expression token or not. It takes 8 expression bits, corresponding to the 8 25344d4804dSStefan Eßer * bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c. 25444d4804dSStefan Eßer * @param e1 The first bit. 25544d4804dSStefan Eßer * @param e2 The second bit. 25644d4804dSStefan Eßer * @param e3 The third bit. 25744d4804dSStefan Eßer * @param e4 The fourth bit. 25844d4804dSStefan Eßer * @param e5 The fifth bit. 25944d4804dSStefan Eßer * @param e6 The sixth bit. 26044d4804dSStefan Eßer * @param e7 The seventh bit. 26144d4804dSStefan Eßer * @param e8 The eighth bit. 26244d4804dSStefan Eßer * @return An expression entry for bc_parse_exprs[]. 26344d4804dSStefan Eßer */ 264252884aeSStefan Eßer #define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \ 265252884aeSStefan Eßer ((UINTMAX_C(e1) << 7) | (UINTMAX_C(e2) << 6) | (UINTMAX_C(e3) << 5) | \ 266252884aeSStefan Eßer (UINTMAX_C(e4) << 4) | (UINTMAX_C(e5) << 3) | (UINTMAX_C(e6) << 2) | \ 267252884aeSStefan Eßer (UINTMAX_C(e7) << 1) | (UINTMAX_C(e8) << 0)) 268252884aeSStefan Eßer 26944d4804dSStefan Eßer /** 27044d4804dSStefan Eßer * Returns true if token @a i is a token that belongs in an expression. 27144d4804dSStefan Eßer * @param i The token to test. 27244d4804dSStefan Eßer * @return True if i is an expression token, false otherwise. 27344d4804dSStefan Eßer */ 274252884aeSStefan Eßer #define BC_PARSE_EXPR(i) \ 275252884aeSStefan Eßer (bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07)))) 276252884aeSStefan Eßer 27744d4804dSStefan Eßer /** 27844d4804dSStefan Eßer * Returns the operator (by lex token) that is at the top of the operator 27944d4804dSStefan Eßer * stack. 28044d4804dSStefan Eßer * @param p The parser. 28144d4804dSStefan Eßer * @return The operator that is at the top of the operator stack, as a lex 28244d4804dSStefan Eßer * token. 28344d4804dSStefan Eßer */ 284252884aeSStefan Eßer #define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops))) 28544d4804dSStefan Eßer 28644d4804dSStefan Eßer /** 28744d4804dSStefan Eßer * Returns true if bc has a "leaf" token. A "leaf" token is one that can stand 28844d4804dSStefan Eßer * alone in an expression. For example, a number by itself can be an expression, 28944d4804dSStefan Eßer * but a binary operator, while valid for an expression, cannot be alone in the 29044d4804dSStefan Eßer * expression. It must have an expression to the left and right of itself. See 29144d4804dSStefan Eßer * the documentation for @a bc_parse_expr_err() in src/bc_parse.c. 29244d4804dSStefan Eßer * @param prev The previous token as an instruction. 29344d4804dSStefan Eßer * @param bin_last True if that last operator was a binary operator, false 29444d4804dSStefan Eßer * otherwise. 29544d4804dSStefan Eßer * @param rparen True if the last operator was a right paren. 29644d4804dSStefan Eßer * return True if the last token was a leaf token, false otherwise. 29744d4804dSStefan Eßer */ 298252884aeSStefan Eßer #define BC_PARSE_LEAF(prev, bin_last, rparen) \ 299252884aeSStefan Eßer (!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev))) 300252884aeSStefan Eßer 30144d4804dSStefan Eßer /** 30244d4804dSStefan Eßer * This returns true if the token @a t should be treated as though it's a 30344d4804dSStefan Eßer * variable. This goes for actual variables, array elements, and globals. 30444d4804dSStefan Eßer * @param t The token to test. 30544d4804dSStefan Eßer * @return True if @a t should be treated as though it's a variable, false 30644d4804dSStefan Eßer * otherwise. 30744d4804dSStefan Eßer */ 30844d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH 309252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \ 310252884aeSStefan Eßer ((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY) 31144d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH 312252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \ 313252884aeSStefan Eßer ((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY) 31444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH 315252884aeSStefan Eßer 31644d4804dSStefan Eßer /** 31744d4804dSStefan Eßer * Returns true if the previous token @a p (in the form of a bytecode 31844d4804dSStefan Eßer * instruction) is a prefix operator. The fact that it is for bytecode 31944d4804dSStefan Eßer * instructions is what makes it different from @a BC_PARSE_OP_PREFIX below. 32044d4804dSStefan Eßer * @param p The previous token. 32144d4804dSStefan Eßer * @return True if @a p is a prefix operator. 32244d4804dSStefan Eßer */ 32344d4804dSStefan Eßer #define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT) 32444d4804dSStefan Eßer 32544d4804dSStefan Eßer /** 32644d4804dSStefan Eßer * Returns true if token @a t is a prefix operator. 32744d4804dSStefan Eßer * @param t The token to test. 32844d4804dSStefan Eßer * @return True if @a t is a prefix operator, false otherwise. 32944d4804dSStefan Eßer */ 330252884aeSStefan Eßer #define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG) 331252884aeSStefan Eßer 33244d4804dSStefan Eßer /** 33344d4804dSStefan Eßer * We can calculate the conversion between tokens and bytecode instructions by 33444d4804dSStefan Eßer * subtracting the position of the first operator in the lex enum and adding the 33544d4804dSStefan Eßer * position of the first in the instruction enum. Note: This only works for 33644d4804dSStefan Eßer * binary operators. 33744d4804dSStefan Eßer * @param t The token to turn into an instruction. 33844d4804dSStefan Eßer * @return The token as an instruction. 33944d4804dSStefan Eßer */ 340252884aeSStefan Eßer #define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG)) 341252884aeSStefan Eßer 34244d4804dSStefan Eßer /** 34344d4804dSStefan Eßer * Returns true if the token is a bc keyword. 34444d4804dSStefan Eßer * @param t The token to check. 34544d4804dSStefan Eßer * @return True if @a t is a bc keyword, false otherwise. 34644d4804dSStefan Eßer */ 34744d4804dSStefan Eßer #define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE) 34844d4804dSStefan Eßer 34944d4804dSStefan Eßer /// A struct that holds data about what tokens should be expected next. There 35044d4804dSStefan Eßer /// are a few instances of these, all named because they are used in specific 35144d4804dSStefan Eßer /// cases. Basically, in certain situations, it's useful to use the same code, 35244d4804dSStefan Eßer /// but have a list of valid tokens. 35344d4804dSStefan Eßer /// 35444d4804dSStefan Eßer /// Obviously, @a len is the number of tokens in the @a tokens array. If more 35544d4804dSStefan Eßer /// than 4 is needed in the future, @a tokens will have to be changed. 35644d4804dSStefan Eßer typedef struct BcParseNext { 35744d4804dSStefan Eßer 35844d4804dSStefan Eßer /// The number of tokens in the tokens array. 35944d4804dSStefan Eßer uchar len; 36044d4804dSStefan Eßer 36144d4804dSStefan Eßer /// The tokens that can be expected next. 36244d4804dSStefan Eßer uchar tokens[4]; 36344d4804dSStefan Eßer 36444d4804dSStefan Eßer } BcParseNext; 36544d4804dSStefan Eßer 36644d4804dSStefan Eßer /// A macro to construct an array literal of tokens from a parameter list. 36744d4804dSStefan Eßer #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ } 36844d4804dSStefan Eßer 36944d4804dSStefan Eßer /// A macro to generate a BcParseNext literal from BcParseNext data. See 37044d4804dSStefan Eßer /// src/data.c for examples. 37144d4804dSStefan Eßer #define BC_PARSE_NEXT(a, ...) \ 37244d4804dSStefan Eßer { .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) } 37344d4804dSStefan Eßer 37444d4804dSStefan Eßer /// A status returned by @a bc_parse_expr_err(). It can either return success or 37544d4804dSStefan Eßer /// an error indicating an empty expression. 376252884aeSStefan Eßer typedef enum BcParseStatus { 377252884aeSStefan Eßer 378252884aeSStefan Eßer BC_PARSE_STATUS_SUCCESS, 379252884aeSStefan Eßer BC_PARSE_STATUS_EMPTY_EXPR, 380252884aeSStefan Eßer 381252884aeSStefan Eßer } BcParseStatus; 382252884aeSStefan Eßer 38344d4804dSStefan Eßer /** 38444d4804dSStefan Eßer * The @a BcParseExpr function for bc. (See include/parse.h for a definition of 38544d4804dSStefan Eßer * @a BcParseExpr.) 38644d4804dSStefan Eßer * @param p The parser. 38744d4804dSStefan Eßer * @param flags Flags that define the requirements that the parsed code must 38844d4804dSStefan Eßer * meet or an error will result. See @a BcParseExpr for more info. 38944d4804dSStefan Eßer */ 390252884aeSStefan Eßer void bc_parse_expr(BcParse *p, uint8_t flags); 391252884aeSStefan Eßer 39244d4804dSStefan Eßer /** 39344d4804dSStefan Eßer * The @a BcParseParse function for bc. (See include/parse.h for a definition of 39444d4804dSStefan Eßer * @a BcParseParse.) 39544d4804dSStefan Eßer * @param p The parser. 39644d4804dSStefan Eßer */ 397252884aeSStefan Eßer void bc_parse_parse(BcParse *p); 398252884aeSStefan Eßer 399*a30efc5cSStefan Eßer /** 400*a30efc5cSStefan Eßer * Ends a series of if statements. This is to ensure that full parses happen 401*a30efc5cSStefan Eßer * when a file finishes or before defining a function. Without this, bc thinks 402*a30efc5cSStefan Eßer * that it cannot parse any further. But if we reach the end of a file or a 403*a30efc5cSStefan Eßer * function definition, we know we can add an empty else clause. 404*a30efc5cSStefan Eßer * @param p The parser. 405*a30efc5cSStefan Eßer */ 406*a30efc5cSStefan Eßer void bc_parse_endif(BcParse *p); 407*a30efc5cSStefan Eßer 40844d4804dSStefan Eßer /// References to the signal message and its length. 409252884aeSStefan Eßer extern const char bc_sig_msg[]; 410252884aeSStefan Eßer extern const uchar bc_sig_msg_len; 411252884aeSStefan Eßer 41244d4804dSStefan Eßer /// A reference to an array of bits that are set if the corresponding lex token 41344d4804dSStefan Eßer /// is valid in an expression. 414252884aeSStefan Eßer extern const uint8_t bc_parse_exprs[]; 41544d4804dSStefan Eßer 41644d4804dSStefan Eßer /// A reference to an array of bc operators. 417252884aeSStefan Eßer extern const uchar bc_parse_ops[]; 41844d4804dSStefan Eßer 41944d4804dSStefan Eßer // References to the various instances of BcParseNext's. 42044d4804dSStefan Eßer 42144d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing normal 42244d4804dSStefan Eßer /// expressions. More accurately. these are the tokens that are valid for 42344d4804dSStefan Eßer /// *ending* the expression. 424252884aeSStefan Eßer extern const BcParseNext bc_parse_next_expr; 42544d4804dSStefan Eßer 42644d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing function 42744d4804dSStefan Eßer /// parameters (well, actually arguments). 42844d4804dSStefan Eßer extern const BcParseNext bc_parse_next_arg; 42944d4804dSStefan Eßer 43044d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a print 43144d4804dSStefan Eßer /// statement. 432252884aeSStefan Eßer extern const BcParseNext bc_parse_next_print; 43344d4804dSStefan Eßer 43444d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing things like 43544d4804dSStefan Eßer /// loop headers and builtin functions where the only thing expected is a right 43644d4804dSStefan Eßer /// paren. 43744d4804dSStefan Eßer /// 43844d4804dSStefan Eßer /// The name is an artifact of history, and is related to @a BC_PARSE_REL (see 43944d4804dSStefan Eßer /// include/parse.h). It refers to how POSIX only allows some operators as part 44044d4804dSStefan Eßer /// of the conditional of for loops, while loops, and if statements. 441252884aeSStefan Eßer extern const BcParseNext bc_parse_next_rel; 44244d4804dSStefan Eßer 44344d4804dSStefan Eßer // What tokens are valid as next tokens when parsing an array element 44444d4804dSStefan Eßer // expression. 445252884aeSStefan Eßer extern const BcParseNext bc_parse_next_elem; 44644d4804dSStefan Eßer 44744d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing the first 44844d4804dSStefan Eßer /// two parts of a for loop header. 449252884aeSStefan Eßer extern const BcParseNext bc_parse_next_for; 45044d4804dSStefan Eßer 45144d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a read 45244d4804dSStefan Eßer /// expression. 453252884aeSStefan Eßer extern const BcParseNext bc_parse_next_read; 454252884aeSStefan Eßer 45544d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a builtin 45644d4804dSStefan Eßer /// function with multiple arguments. 45744d4804dSStefan Eßer extern const BcParseNext bc_parse_next_builtin; 45844d4804dSStefan Eßer 459d213476dSStefan Eßer #else // BC_ENABLED 460d213476dSStefan Eßer 46144d4804dSStefan Eßer // If bc is not enabled, execution is always possible because dc has strict 46244d4804dSStefan Eßer // rules that ensure execution can always proceed safely. 463d213476dSStefan Eßer #define BC_PARSE_NO_EXEC(p) (0) 464d213476dSStefan Eßer 465252884aeSStefan Eßer #endif // BC_ENABLED 466252884aeSStefan Eßer 467252884aeSStefan Eßer #endif // BC_BC_H 468