/*1* *****************************************************************************2*3* SPDX-License-Identifier: BSD-2-Clause4*5* Copyright (c) 2018-2025 Gavin D. Howard and contributors.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions are met:9*10* * Redistributions of source code must retain the above copyright notice, this11* list of conditions and the following disclaimer.12*13* * Redistributions in binary form must reproduce the above copyright notice,14* this list of conditions and the following disclaimer in the documentation15* and/or other materials provided with the distribution.16*17* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"18* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE19* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE20* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE21* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS24* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN25* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)26* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE27* POSSIBILITY OF SUCH DAMAGE.28*29* *****************************************************************************30*31* Definitions for bc only.32*33*/3435#ifndef BC_BC_H36#define BC_BC_H3738#if BC_ENABLED3940#include <limits.h>41#include <stdbool.h>4243#include <status.h>44#include <lex.h>45#include <parse.h>4647/**48* The main function for bc. It just sets variables and passes its arguments49* through to @a bc_vm_boot().50* @return A status.51*/52BcStatus53bc_main(int argc, const char* argv[]);5455// These are references to the help text, the library text, and the "filename"56// for the library.57extern const char bc_help[];58extern const char bc_lib[];59extern const char* bc_lib_name;6061// These are references to the second math library and its "filename."62#if BC_ENABLE_EXTRA_MATH63extern const char bc_lib2[];64extern const char* bc_lib2_name;65#endif // BC_ENABLE_EXTRA_MATH6667/**68* A struct containing information about a bc keyword.69*/70typedef struct BcLexKeyword71{72/// Holds the length of the keyword along with a bit that, if set, means the73/// keyword is used in POSIX bc.74uchar data;7576/// The keyword text.77const char name[14];78} BcLexKeyword;7980/// Sets the most significant bit. Used for setting the POSIX bit in81/// BcLexKeyword's data field.82#define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))8384/// Returns non-zero if the keyword is POSIX, zero otherwise.85#define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))8687/// Returns the length of the keyword.88#define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))8990/// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c.91#define BC_LEX_KW_ENTRY(a, b, c) \92{ .data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a }9394#if BC_ENABLE_EXTRA_MATH9596/// A macro for the number of keywords bc has. This has to be updated if any are97/// added. This is for the redefined_kws field of the BcVm struct.98#define BC_LEX_NKWS (37)99100#else // BC_ENABLE_EXTRA_MATH101102/// A macro for the number of keywords bc has. This has to be updated if any are103/// added. This is for the redefined_kws field of the BcVm struct.104#define BC_LEX_NKWS (33)105106#endif // BC_ENABLE_EXTRA_MATH107108// The array of keywords and its length.109extern const BcLexKeyword bc_lex_kws[];110extern const size_t bc_lex_kws_len;111112/**113* The @a BcLexNext function for bc. (See include/lex.h for a definition of114* @a BcLexNext.)115* @param l The lexer.116*/117void118bc_lex_token(BcLex* l);119120// The following section is for flags needed when parsing bc code. These flags121// are complicated, but necessary. Why you ask? Because bc's standard is awful.122//123// If you don't believe me, go read the bc Parsing section of the Development124// manual (manuals/development.md). Then come back.125//126// In other words, these flags are the sign declaring, "Here be dragons."127128/**129* This returns a pointer to the set of flags at the top of the flag stack.130* @a p is expected to be a BcParse pointer.131* @param p The parser.132* @return A pointer to the top flag set.133*/134#define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))135136/**137* This returns the flag set at the top of the flag stack. @a p is expected to138* be a BcParse pointer.139* @param p The parser.140* @return The top flag set.141*/142#define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))143144// After this point, all flag #defines are in sets of 2: one to define the flag,145// and one to define a way to grab the flag from the flag set at the top of the146// flag stack. All `p` arguments are pointers to a BcParse.147148// This flag is set if the parser has seen a left brace.149#define BC_PARSE_FLAG_BRACE (UINTMAX_C(1) << 0)150#define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)151152// This flag is set if the parser is parsing inside of the braces of a function153// body.154#define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1) << 1)155#define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)156157// This flag is set if the parser is parsing a function. It is different from158// the one above because it is set if it is parsing a function body *or* header,159// not just if it's parsing a function body.160#define BC_PARSE_FLAG_FUNC (UINTMAX_C(1) << 2)161#define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)162163// This flag is set if the parser is expecting to parse a body, whether of a164// function, an if statement, or a loop.165#define BC_PARSE_FLAG_BODY (UINTMAX_C(1) << 3)166#define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)167168// This flag is set if bc is parsing a loop. This is important because the break169// and continue keywords are only valid inside of a loop.170#define BC_PARSE_FLAG_LOOP (UINTMAX_C(1) << 4)171#define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)172173// This flag is set if bc is parsing the body of a loop. It is different from174// the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from175// @a BC_PARSE_FLAG_FUNC.176#define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1) << 5)177#define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)178179// This flag is set if bc is parsing an if statement.180#define BC_PARSE_FLAG_IF (UINTMAX_C(1) << 6)181#define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)182183// This flag is set if bc is parsing an else statement. This is important184// because of "else if" constructions, among other things.185#define BC_PARSE_FLAG_ELSE (UINTMAX_C(1) << 7)186#define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)187188// This flag is set if bc just finished parsing an if statement and its body.189// It tells the parser that it can probably expect an else statement next. This190// flag is, thus, one of the most subtle.191#define BC_PARSE_FLAG_IF_END (UINTMAX_C(1) << 8)192#define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)193194/**195* This returns true if bc is in a state where it should not execute any code196* at all.197* @param p The parser.198* @return True if execution cannot proceed, false otherwise.199*/200#define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)201202/**203* This returns true if the token @a t is a statement delimiter, which is204* either a newline or a semicolon.205* @param t The token to check.206* @return True if t is a statement delimiter token; false otherwise.207*/208#define BC_PARSE_DELIMITER(t) \209((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)210211/**212* This is poorly named, but it basically returns whether or not the current213* state is valid for the end of an else statement.214* @param f The flag set to be checked.215* @return True if the state is valid for the end of an else statement.216*/217#define BC_PARSE_BLOCK_STMT(f) \218((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))219220/**221* This returns the value of the data for an operator with precedence @a p and222* associativity @a l (true if left associative, false otherwise). This is used223* to construct an array of operators, bc_parse_ops, in src/data.c.224* @param p The precedence.225* @param l True if the operator is left associative, false otherwise.226* @return The data for the operator.227*/228#define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))229230/**231* Returns the operator data for the lex token @a t.232* @param t The token to return operator data for.233* @return The operator data for @a t.234*/235#define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) - BC_LEX_OP_INC)]236237/**238* Returns non-zero if operator @a op is left associative, zero otherwise.239* @param op The operator to test for associativity.240* @return Non-zero if the operator is left associative, zero otherwise.241*/242#define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))243244/**245* Returns the precedence of operator @a op. Lower number means higher246* precedence.247* @param op The operator to return the precedence of.248* @return The precedence of @a op.249*/250#define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))251252/**253* A macro to easily define a series of bits for whether a lex token is an254* expression token or not. It takes 8 expression bits, corresponding to the 8255* bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c.256* @param e1 The first bit.257* @param e2 The second bit.258* @param e3 The third bit.259* @param e4 The fourth bit.260* @param e5 The fifth bit.261* @param e6 The sixth bit.262* @param e7 The seventh bit.263* @param e8 The eighth bit.264* @return An expression entry for bc_parse_exprs[].265*/266#define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \267((UINT8_C(e1) << 7) | (UINT8_C(e2) << 6) | (UINT8_C(e3) << 5) | \268(UINT8_C(e4) << 4) | (UINT8_C(e5) << 3) | (UINT8_C(e6) << 2) | \269(UINT8_C(e7) << 1) | (UINT8_C(e8) << 0))270271/**272* Returns true if token @a i is a token that belongs in an expression.273* @param i The token to test.274* @return True if i is an expression token, false otherwise.275*/276#define BC_PARSE_EXPR(i) \277(bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07))))278279/**280* Returns the operator (by lex token) that is at the top of the operator281* stack.282* @param p The parser.283* @return The operator that is at the top of the operator stack, as a lex284* token.285*/286#define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))287288/**289* Returns true if bc has a "leaf" token. A "leaf" token is one that can stand290* alone in an expression. For example, a number by itself can be an expression,291* but a binary operator, while valid for an expression, cannot be alone in the292* expression. It must have an expression to the left and right of itself. See293* the documentation for @a bc_parse_expr_err() in src/bc_parse.c.294* @param prev The previous token as an instruction.295* @param bin_last True if that last operator was a binary operator, false296* otherwise.297* @param rparen True if the last operator was a right paren.298* return True if the last token was a leaf token, false otherwise.299*/300#define BC_PARSE_LEAF(prev, bin_last, rparen) \301(!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))302303/**304* This returns true if the token @a t should be treated as though it's a305* variable. This goes for actual variables, array elements, and globals.306* @param t The token to test.307* @return True if @a t should be treated as though it's a variable, false308* otherwise.309*/310#if BC_ENABLE_EXTRA_MATH311#define BC_PARSE_INST_VAR(t) \312((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY)313#else // BC_ENABLE_EXTRA_MATH314#define BC_PARSE_INST_VAR(t) \315((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)316#endif // BC_ENABLE_EXTRA_MATH317318/**319* Returns true if the previous token @a p (in the form of a bytecode320* instruction) is a prefix operator. The fact that it is for bytecode321* instructions is what makes it different from @a BC_PARSE_OP_PREFIX below.322* @param p The previous token.323* @return True if @a p is a prefix operator.324*/325#define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT)326327/**328* Returns true if token @a t is a prefix operator.329* @param t The token to test.330* @return True if @a t is a prefix operator, false otherwise.331*/332#define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)333334/**335* We can calculate the conversion between tokens and bytecode instructions by336* subtracting the position of the first operator in the lex enum and adding the337* position of the first in the instruction enum. Note: This only works for338* binary operators.339* @param t The token to turn into an instruction.340* @return The token as an instruction.341*/342#define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) - BC_LEX_NEG + BC_INST_NEG))343344/**345* Returns true if the token is a bc keyword.346* @param t The token to check.347* @return True if @a t is a bc keyword, false otherwise.348*/349#define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE)350351/// A struct that holds data about what tokens should be expected next. There352/// are a few instances of these, all named because they are used in specific353/// cases. Basically, in certain situations, it's useful to use the same code,354/// but have a list of valid tokens.355///356/// Obviously, @a len is the number of tokens in the @a tokens array. If more357/// than 4 is needed in the future, @a tokens will have to be changed.358typedef struct BcParseNext359{360/// The number of tokens in the tokens array.361uchar len;362363/// The tokens that can be expected next.364uchar tokens[4];365366} BcParseNext;367368/// A macro to construct an array literal of tokens from a parameter list.369#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }370371/// A macro to generate a BcParseNext literal from BcParseNext data. See372/// src/data.c for examples.373#define BC_PARSE_NEXT(a, ...) \374{ .len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) }375376/// A status returned by @a bc_parse_expr_err(). It can either return success or377/// an error indicating an empty expression.378typedef enum BcParseStatus379{380BC_PARSE_STATUS_SUCCESS,381BC_PARSE_STATUS_EMPTY_EXPR,382383} BcParseStatus;384385/**386* The @a BcParseExpr function for bc. (See include/parse.h for a definition of387* @a BcParseExpr.)388* @param p The parser.389* @param flags Flags that define the requirements that the parsed code must390* meet or an error will result. See @a BcParseExpr for more info.391*/392void393bc_parse_expr(BcParse* p, uint8_t flags);394395/**396* The @a BcParseParse function for bc. (See include/parse.h for a definition of397* @a BcParseParse.)398* @param p The parser.399*/400void401bc_parse_parse(BcParse* p);402403/**404* Ends a series of if statements. This is to ensure that full parses happen405* when a file finishes or before defining a function. Without this, bc thinks406* that it cannot parse any further. But if we reach the end of a file or a407* function definition, we know we can add an empty else clause.408* @param p The parser.409*/410void411bc_parse_endif(BcParse* p);412413/// References to the signal message and its length.414extern const char bc_sig_msg[];415extern const uchar bc_sig_msg_len;416417/// A reference to an array of bits that are set if the corresponding lex token418/// is valid in an expression.419extern const uint8_t bc_parse_exprs[];420421/// A reference to an array of bc operators.422extern const uchar bc_parse_ops[];423424// References to the various instances of BcParseNext's.425426/// A reference to what tokens are valid as next tokens when parsing normal427/// expressions. More accurately. these are the tokens that are valid for428/// *ending* the expression.429extern const BcParseNext bc_parse_next_expr;430431/// A reference to what tokens are valid as next tokens when parsing function432/// parameters (well, actually arguments).433extern const BcParseNext bc_parse_next_arg;434435/// A reference to what tokens are valid as next tokens when parsing a print436/// statement.437extern const BcParseNext bc_parse_next_print;438439/// A reference to what tokens are valid as next tokens when parsing things like440/// loop headers and builtin functions where the only thing expected is a right441/// paren.442///443/// The name is an artifact of history, and is related to @a BC_PARSE_REL (see444/// include/parse.h). It refers to how POSIX only allows some operators as part445/// of the conditional of for loops, while loops, and if statements.446extern const BcParseNext bc_parse_next_rel;447448// What tokens are valid as next tokens when parsing an array element449// expression.450extern const BcParseNext bc_parse_next_elem;451452/// A reference to what tokens are valid as next tokens when parsing the first453/// two parts of a for loop header.454extern const BcParseNext bc_parse_next_for;455456/// A reference to what tokens are valid as next tokens when parsing a read457/// expression.458extern const BcParseNext bc_parse_next_read;459460/// A reference to what tokens are valid as next tokens when parsing a builtin461/// function with multiple arguments.462extern const BcParseNext bc_parse_next_builtin;463464#else // BC_ENABLED465466// If bc is not enabled, execution is always possible because dc has strict467// rules that ensure execution can always proceed safely.468#define BC_PARSE_NO_EXEC(p) (0)469470#endif // BC_ENABLED471472#endif // BC_BC_H473474475