freebsd-src/contrib/bc/include/bc.h
Stefan Eßer f4fbc49d20 vendor/bc: upgrade to version 6.7.5
This update fixes a bug that line breaks in printed numbers may not
match the line length set by the user. The value is printed correctly,
just not split as specified in some situations.

(cherry picked from commit 52a5ec1b178fd07651446c7e31b1512794a04dbf)
2024-01-10 17:36:29 +01:00

477 lines
18 KiB
C

/*
* *****************************************************************************
*
* SPDX-License-Identifier: BSD-2-Clause
*
* 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:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* *****************************************************************************
*
* Definitions for bc only.
*
*/
#ifndef BC_BC_H
#define BC_BC_H
#if BC_ENABLED
#include <limits.h>
#include <stdbool.h>
#include <status.h>
#include <lex.h>
#include <parse.h>
/**
* The main function for bc. It just sets variables and passes its arguments
* through to @a bc_vm_boot().
*/
void
bc_main(int argc, char* argv[]);
// These are references to the help text, the library text, and the "filename"
// for the library.
extern const char bc_help[];
extern const char bc_lib[];
extern const char* bc_lib_name;
// These are references to the second math library and its "filename."
#if BC_ENABLE_EXTRA_MATH
extern const char bc_lib2[];
extern const char* bc_lib2_name;
#endif // BC_ENABLE_EXTRA_MATH
/**
* A struct containing information about a bc keyword.
*/
typedef struct BcLexKeyword
{
/// Holds the length of the keyword along with a bit that, if set, means the
/// keyword is used in POSIX bc.
uchar data;
/// The keyword text.
const char name[14];
} BcLexKeyword;
/// Sets the most significant bit. Used for setting the POSIX bit in
/// BcLexKeyword's data field.
#define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))
/// Returns non-zero if the keyword is POSIX, zero otherwise.
#define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))
/// Returns the length of the keyword.
#define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))
/// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c.
#define BC_LEX_KW_ENTRY(a, b, c) \
{ \
.data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a \
}
#if BC_ENABLE_EXTRA_MATH
/// A macro for the number of keywords bc has. This has to be updated if any are
/// added. This is for the redefined_kws field of the BcVm struct.
#define BC_LEX_NKWS (37)
#else // BC_ENABLE_EXTRA_MATH
/// A macro for the number of keywords bc has. This has to be updated if any are
/// added. This is for the redefined_kws field of the BcVm struct.
#define BC_LEX_NKWS (33)
#endif // BC_ENABLE_EXTRA_MATH
// The array of keywords and its length.
extern const BcLexKeyword bc_lex_kws[];
extern const size_t bc_lex_kws_len;
/**
* The @a BcLexNext function for bc. (See include/lex.h for a definition of
* @a BcLexNext.)
* @param l The lexer.
*/
void
bc_lex_token(BcLex* l);
// The following section is for flags needed when parsing bc code. These flags
// are complicated, but necessary. Why you ask? Because bc's standard is awful.
//
// If you don't believe me, go read the bc Parsing section of the Development
// manual (manuals/development.md). Then come back.
//
// In other words, these flags are the sign declaring, "Here be dragons."
/**
* This returns a pointer to the set of flags at the top of the flag stack.
* @a p is expected to be a BcParse pointer.
* @param p The parser.
* @return A pointer to the top flag set.
*/
#define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))
/**
* This returns the flag set at the top of the flag stack. @a p is expected to
* be a BcParse pointer.
* @param p The parser.
* @return The top flag set.
*/
#define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))
// After this point, all flag #defines are in sets of 2: one to define the flag,
// and one to define a way to grab the flag from the flag set at the top of the
// flag stack. All `p` arguments are pointers to a BcParse.
// This flag is set if the parser has seen a left brace.
#define BC_PARSE_FLAG_BRACE (UINTMAX_C(1) << 0)
#define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)
// This flag is set if the parser is parsing inside of the braces of a function
// body.
#define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1) << 1)
#define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)
// This flag is set if the parser is parsing a function. It is different from
// the one above because it is set if it is parsing a function body *or* header,
// not just if it's parsing a function body.
#define BC_PARSE_FLAG_FUNC (UINTMAX_C(1) << 2)
#define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)
// This flag is set if the parser is expecting to parse a body, whether of a
// function, an if statement, or a loop.
#define BC_PARSE_FLAG_BODY (UINTMAX_C(1) << 3)
#define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)
// This flag is set if bc is parsing a loop. This is important because the break
// and continue keywords are only valid inside of a loop.
#define BC_PARSE_FLAG_LOOP (UINTMAX_C(1) << 4)
#define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)
// This flag is set if bc is parsing the body of a loop. It is different from
// the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from
// @a BC_PARSE_FLAG_FUNC.
#define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1) << 5)
#define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)
// This flag is set if bc is parsing an if statement.
#define BC_PARSE_FLAG_IF (UINTMAX_C(1) << 6)
#define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)
// This flag is set if bc is parsing an else statement. This is important
// because of "else if" constructions, among other things.
#define BC_PARSE_FLAG_ELSE (UINTMAX_C(1) << 7)
#define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)
// This flag is set if bc just finished parsing an if statement and its body.
// It tells the parser that it can probably expect an else statement next. This
// flag is, thus, one of the most subtle.
#define BC_PARSE_FLAG_IF_END (UINTMAX_C(1) << 8)
#define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)
/**
* This returns true if bc is in a state where it should not execute any code
* at all.
* @param p The parser.
* @return True if execution cannot proceed, false otherwise.
*/
#define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)
/**
* This returns true if the token @a t is a statement delimiter, which is
* either a newline or a semicolon.
* @param t The token to check.
* @return True if t is a statement delimiter token; false otherwise.
*/
#define BC_PARSE_DELIMITER(t) \
((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)
/**
* This is poorly named, but it basically returns whether or not the current
* state is valid for the end of an else statement.
* @param f The flag set to be checked.
* @return True if the state is valid for the end of an else statement.
*/
#define BC_PARSE_BLOCK_STMT(f) \
((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))
/**
* This returns the value of the data for an operator with precedence @a p and
* associativity @a l (true if left associative, false otherwise). This is used
* to construct an array of operators, bc_parse_ops, in src/data.c.
* @param p The precedence.
* @param l True if the operator is left associative, false otherwise.
* @return The data for the operator.
*/
#define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))
/**
* Returns the operator data for the lex token @a t.
* @param t The token to return operator data for.
* @return The operator data for @a t.
*/
#define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) -BC_LEX_OP_INC)]
/**
* Returns non-zero if operator @a op is left associative, zero otherwise.
* @param op The operator to test for associativity.
* @return Non-zero if the operator is left associative, zero otherwise.
*/
#define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))
/**
* Returns the precedence of operator @a op. Lower number means higher
* precedence.
* @param op The operator to return the precedence of.
* @return The precedence of @a op.
*/
#define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))
/**
* A macro to easily define a series of bits for whether a lex token is an
* expression token or not. It takes 8 expression bits, corresponding to the 8
* bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c.
* @param e1 The first bit.
* @param e2 The second bit.
* @param e3 The third bit.
* @param e4 The fourth bit.
* @param e5 The fifth bit.
* @param e6 The sixth bit.
* @param e7 The seventh bit.
* @param e8 The eighth bit.
* @return An expression entry for bc_parse_exprs[].
*/
#define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8) \
((UINTMAX_C(e1) << 7) | (UINTMAX_C(e2) << 6) | (UINTMAX_C(e3) << 5) | \
(UINTMAX_C(e4) << 4) | (UINTMAX_C(e5) << 3) | (UINTMAX_C(e6) << 2) | \
(UINTMAX_C(e7) << 1) | (UINTMAX_C(e8) << 0))
/**
* Returns true if token @a i is a token that belongs in an expression.
* @param i The token to test.
* @return True if i is an expression token, false otherwise.
*/
#define BC_PARSE_EXPR(i) \
(bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07))))
/**
* Returns the operator (by lex token) that is at the top of the operator
* stack.
* @param p The parser.
* @return The operator that is at the top of the operator stack, as a lex
* token.
*/
#define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))
/**
* Returns true if bc has a "leaf" token. A "leaf" token is one that can stand
* alone in an expression. For example, a number by itself can be an expression,
* but a binary operator, while valid for an expression, cannot be alone in the
* expression. It must have an expression to the left and right of itself. See
* the documentation for @a bc_parse_expr_err() in src/bc_parse.c.
* @param prev The previous token as an instruction.
* @param bin_last True if that last operator was a binary operator, false
* otherwise.
* @param rparen True if the last operator was a right paren.
* return True if the last token was a leaf token, false otherwise.
*/
#define BC_PARSE_LEAF(prev, bin_last, rparen) \
(!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
/**
* This returns true if the token @a t should be treated as though it's a
* variable. This goes for actual variables, array elements, and globals.
* @param t The token to test.
* @return True if @a t should be treated as though it's a variable, false
* otherwise.
*/
#if BC_ENABLE_EXTRA_MATH
#define BC_PARSE_INST_VAR(t) \
((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY)
#else // BC_ENABLE_EXTRA_MATH
#define BC_PARSE_INST_VAR(t) \
((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)
#endif // BC_ENABLE_EXTRA_MATH
/**
* Returns true if the previous token @a p (in the form of a bytecode
* instruction) is a prefix operator. The fact that it is for bytecode
* instructions is what makes it different from @a BC_PARSE_OP_PREFIX below.
* @param p The previous token.
* @return True if @a p is a prefix operator.
*/
#define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT)
/**
* Returns true if token @a t is a prefix operator.
* @param t The token to test.
* @return True if @a t is a prefix operator, false otherwise.
*/
#define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)
/**
* We can calculate the conversion between tokens and bytecode instructions by
* subtracting the position of the first operator in the lex enum and adding the
* position of the first in the instruction enum. Note: This only works for
* binary operators.
* @param t The token to turn into an instruction.
* @return The token as an instruction.
*/
#define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) -BC_LEX_NEG + BC_INST_NEG))
/**
* Returns true if the token is a bc keyword.
* @param t The token to check.
* @return True if @a t is a bc keyword, false otherwise.
*/
#define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE)
/// A struct that holds data about what tokens should be expected next. There
/// are a few instances of these, all named because they are used in specific
/// cases. Basically, in certain situations, it's useful to use the same code,
/// but have a list of valid tokens.
///
/// Obviously, @a len is the number of tokens in the @a tokens array. If more
/// than 4 is needed in the future, @a tokens will have to be changed.
typedef struct BcParseNext
{
/// The number of tokens in the tokens array.
uchar len;
/// The tokens that can be expected next.
uchar tokens[4];
} BcParseNext;
/// A macro to construct an array literal of tokens from a parameter list.
#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
/// A macro to generate a BcParseNext literal from BcParseNext data. See
/// src/data.c for examples.
#define BC_PARSE_NEXT(a, ...) \
{ \
.len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
}
/// A status returned by @a bc_parse_expr_err(). It can either return success or
/// an error indicating an empty expression.
typedef enum BcParseStatus
{
BC_PARSE_STATUS_SUCCESS,
BC_PARSE_STATUS_EMPTY_EXPR,
} BcParseStatus;
/**
* The @a BcParseExpr function for bc. (See include/parse.h for a definition of
* @a BcParseExpr.)
* @param p The parser.
* @param flags Flags that define the requirements that the parsed code must
* meet or an error will result. See @a BcParseExpr for more info.
*/
void
bc_parse_expr(BcParse* p, uint8_t flags);
/**
* The @a BcParseParse function for bc. (See include/parse.h for a definition of
* @a BcParseParse.)
* @param p The parser.
*/
void
bc_parse_parse(BcParse* p);
/**
* Ends a series of if statements. This is to ensure that full parses happen
* when a file finishes or before defining a function. Without this, bc thinks
* that it cannot parse any further. But if we reach the end of a file or a
* function definition, we know we can add an empty else clause.
* @param p The parser.
*/
void
bc_parse_endif(BcParse* p);
/// References to the signal message and its length.
extern const char bc_sig_msg[];
extern const uchar bc_sig_msg_len;
/// A reference to an array of bits that are set if the corresponding lex token
/// is valid in an expression.
extern const uint8_t bc_parse_exprs[];
/// A reference to an array of bc operators.
extern const uchar bc_parse_ops[];
// References to the various instances of BcParseNext's.
/// A reference to what tokens are valid as next tokens when parsing normal
/// expressions. More accurately. these are the tokens that are valid for
/// *ending* the expression.
extern const BcParseNext bc_parse_next_expr;
/// A reference to what tokens are valid as next tokens when parsing function
/// parameters (well, actually arguments).
extern const BcParseNext bc_parse_next_arg;
/// A reference to what tokens are valid as next tokens when parsing a print
/// statement.
extern const BcParseNext bc_parse_next_print;
/// A reference to what tokens are valid as next tokens when parsing things like
/// loop headers and builtin functions where the only thing expected is a right
/// paren.
///
/// The name is an artifact of history, and is related to @a BC_PARSE_REL (see
/// include/parse.h). It refers to how POSIX only allows some operators as part
/// of the conditional of for loops, while loops, and if statements.
extern const BcParseNext bc_parse_next_rel;
// What tokens are valid as next tokens when parsing an array element
// expression.
extern const BcParseNext bc_parse_next_elem;
/// A reference to what tokens are valid as next tokens when parsing the first
/// two parts of a for loop header.
extern const BcParseNext bc_parse_next_for;
/// A reference to what tokens are valid as next tokens when parsing a read
/// expression.
extern const BcParseNext bc_parse_next_read;
/// A reference to what tokens are valid as next tokens when parsing a builtin
/// function with multiple arguments.
extern const BcParseNext bc_parse_next_builtin;
#else // BC_ENABLED
// If bc is not enabled, execution is always possible because dc has strict
// rules that ensure execution can always proceed safely.
#define BC_PARSE_NO_EXEC(p) (0)
#endif // BC_ENABLED
#endif // BC_BC_H