xref: /freebsd/contrib/bc/include/bc.h (revision 12e0d316644a4f80f5f1f78cf07bd93def43b1ca)
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