xref: /freebsd/contrib/bc/include/bc.h (revision f4fbc49d)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6d101cdd6SStefan Eßer  * Copyright (c) 2018-2023 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  */
5278bc019dSStefan Eßer void
5378bc019dSStefan Eßer bc_main(int argc, char* argv[]);
54252884aeSStefan Eßer 
5544d4804dSStefan Eßer // These are references to the help text, the library text, and the "filename"
5644d4804dSStefan Eßer // for the library.
57252884aeSStefan Eßer extern const char bc_help[];
58252884aeSStefan Eßer extern const char bc_lib[];
59252884aeSStefan Eßer extern const char* bc_lib_name;
60252884aeSStefan Eßer 
6144d4804dSStefan Eßer // These are references to the second math library and its "filename."
62252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
63252884aeSStefan Eßer extern const char bc_lib2[];
64252884aeSStefan Eßer extern const char* bc_lib2_name;
65252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
66252884aeSStefan Eßer 
6744d4804dSStefan Eßer /**
6844d4804dSStefan Eßer  * A struct containing information about a bc keyword.
6944d4804dSStefan Eßer  */
7078bc019dSStefan Eßer typedef struct BcLexKeyword
7178bc019dSStefan Eßer {
7244d4804dSStefan Eßer 	/// Holds the length of the keyword along with a bit that, if set, means the
7344d4804dSStefan Eßer 	/// keyword is used in POSIX bc.
74252884aeSStefan Eßer 	uchar data;
7544d4804dSStefan Eßer 
7644d4804dSStefan Eßer 	/// The keyword text.
77d43fa8efSStefan Eßer 	const char name[14];
78252884aeSStefan Eßer } BcLexKeyword;
79252884aeSStefan Eßer 
8044d4804dSStefan Eßer /// Sets the most significant bit. Used for setting the POSIX bit in
8144d4804dSStefan Eßer /// BcLexKeyword's data field.
82252884aeSStefan Eßer #define BC_LEX_CHAR_MSB(bit) ((bit) << (CHAR_BIT - 1))
83252884aeSStefan Eßer 
8444d4804dSStefan Eßer /// Returns non-zero if the keyword is POSIX, zero otherwise.
85252884aeSStefan Eßer #define BC_LEX_KW_POSIX(kw) ((kw)->data & (BC_LEX_CHAR_MSB(1)))
8644d4804dSStefan Eßer 
8744d4804dSStefan Eßer /// Returns the length of the keyword.
88252884aeSStefan Eßer #define BC_LEX_KW_LEN(kw) ((size_t) ((kw)->data & ~(BC_LEX_CHAR_MSB(1))))
89252884aeSStefan Eßer 
9044d4804dSStefan Eßer /// A macro to easily build a keyword entry. See bc_lex_kws in src/data.c.
91252884aeSStefan Eßer #define BC_LEX_KW_ENTRY(a, b, c)                                              \
9278bc019dSStefan Eßer 	{                                                                         \
9378bc019dSStefan Eßer 		.data = ((b) & ~(BC_LEX_CHAR_MSB(1))) | BC_LEX_CHAR_MSB(c), .name = a \
9478bc019dSStefan Eßer 	}
95252884aeSStefan Eßer 
9644d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
9744d4804dSStefan Eßer 
9844d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are
9944d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct.
100d101cdd6SStefan Eßer #define BC_LEX_NKWS (37)
10144d4804dSStefan Eßer 
10244d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH
10344d4804dSStefan Eßer 
10444d4804dSStefan Eßer /// A macro for the number of keywords bc has. This has to be updated if any are
10544d4804dSStefan Eßer /// added. This is for the redefined_kws field of the BcVm struct.
106d101cdd6SStefan Eßer #define BC_LEX_NKWS (33)
10744d4804dSStefan Eßer 
10844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
10944d4804dSStefan Eßer 
11044d4804dSStefan Eßer // The array of keywords and its length.
111252884aeSStefan Eßer extern const BcLexKeyword bc_lex_kws[];
112252884aeSStefan Eßer extern const size_t bc_lex_kws_len;
113252884aeSStefan Eßer 
11444d4804dSStefan Eßer /**
11544d4804dSStefan Eßer  * The @a BcLexNext function for bc. (See include/lex.h for a definition of
11644d4804dSStefan Eßer  * @a BcLexNext.)
11744d4804dSStefan Eßer  * @param l  The lexer.
11844d4804dSStefan Eßer  */
11978bc019dSStefan Eßer void
12078bc019dSStefan Eßer bc_lex_token(BcLex* l);
121252884aeSStefan Eßer 
12244d4804dSStefan Eßer // The following section is for flags needed when parsing bc code. These flags
12344d4804dSStefan Eßer // are complicated, but necessary. Why you ask? Because bc's standard is awful.
12444d4804dSStefan Eßer //
12544d4804dSStefan Eßer // If you don't believe me, go read the bc Parsing section of the Development
12644d4804dSStefan Eßer // manual (manuals/development.md). Then come back.
12744d4804dSStefan Eßer //
12844d4804dSStefan Eßer // In other words, these flags are the sign declaring, "Here be dragons."
12944d4804dSStefan Eßer 
13044d4804dSStefan Eßer /**
13144d4804dSStefan Eßer  * This returns a pointer to the set of flags at the top of the flag stack.
13244d4804dSStefan Eßer  * @a p is expected to be a BcParse pointer.
13344d4804dSStefan Eßer  * @param p  The parser.
13444d4804dSStefan Eßer  * @return   A pointer to the top flag set.
13544d4804dSStefan Eßer  */
136252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG_PTR(p) ((uint16_t*) bc_vec_top(&(p)->flags))
13744d4804dSStefan Eßer 
13844d4804dSStefan Eßer /**
13944d4804dSStefan Eßer  * This returns the flag set at the top of the flag stack. @a p is expected to
14044d4804dSStefan Eßer  * be a BcParse pointer.
14144d4804dSStefan Eßer  * @param p  The parser.
14244d4804dSStefan Eßer  * @return   The top flag set.
14344d4804dSStefan Eßer  */
144252884aeSStefan Eßer #define BC_PARSE_TOP_FLAG(p) (*(BC_PARSE_TOP_FLAG_PTR(p)))
145252884aeSStefan Eßer 
14644d4804dSStefan Eßer // After this point, all flag #defines are in sets of 2: one to define the flag,
14744d4804dSStefan Eßer // and one to define a way to grab the flag from the flag set at the top of the
14844d4804dSStefan Eßer // flag stack. All `p` arguments are pointers to a BcParse.
14944d4804dSStefan Eßer 
15044d4804dSStefan Eßer // This flag is set if the parser has seen a left brace.
151252884aeSStefan Eßer #define BC_PARSE_FLAG_BRACE (UINTMAX_C(1) << 0)
152252884aeSStefan Eßer #define BC_PARSE_BRACE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BRACE)
153252884aeSStefan Eßer 
15444d4804dSStefan Eßer // This flag is set if the parser is parsing inside of the braces of a function
15544d4804dSStefan Eßer // body.
156252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC_INNER (UINTMAX_C(1) << 1)
157252884aeSStefan Eßer #define BC_PARSE_FUNC_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC_INNER)
158252884aeSStefan Eßer 
15944d4804dSStefan Eßer // This flag is set if the parser is parsing a function. It is different from
16044d4804dSStefan Eßer // the one above because it is set if it is parsing a function body *or* header,
16144d4804dSStefan Eßer // not just if it's parsing a function body.
162252884aeSStefan Eßer #define BC_PARSE_FLAG_FUNC (UINTMAX_C(1) << 2)
163252884aeSStefan Eßer #define BC_PARSE_FUNC(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_FUNC)
164252884aeSStefan Eßer 
16544d4804dSStefan Eßer // This flag is set if the parser is expecting to parse a body, whether of a
16644d4804dSStefan Eßer // function, an if statement, or a loop.
167252884aeSStefan Eßer #define BC_PARSE_FLAG_BODY (UINTMAX_C(1) << 3)
168252884aeSStefan Eßer #define BC_PARSE_BODY(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_BODY)
169252884aeSStefan Eßer 
17044d4804dSStefan Eßer // This flag is set if bc is parsing a loop. This is important because the break
17144d4804dSStefan Eßer // and continue keywords are only valid inside of a loop.
172252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP (UINTMAX_C(1) << 4)
173252884aeSStefan Eßer #define BC_PARSE_LOOP(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP)
174252884aeSStefan Eßer 
17544d4804dSStefan Eßer // This flag is set if bc is parsing the body of a loop. It is different from
17644d4804dSStefan Eßer // the one above the same way @a BC_PARSE_FLAG_FUNC_INNER is different from
17744d4804dSStefan Eßer // @a BC_PARSE_FLAG_FUNC.
178252884aeSStefan Eßer #define BC_PARSE_FLAG_LOOP_INNER (UINTMAX_C(1) << 5)
179252884aeSStefan Eßer #define BC_PARSE_LOOP_INNER(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_LOOP_INNER)
180252884aeSStefan Eßer 
18144d4804dSStefan Eßer // This flag is set if bc is parsing an if statement.
182252884aeSStefan Eßer #define BC_PARSE_FLAG_IF (UINTMAX_C(1) << 6)
183252884aeSStefan Eßer #define BC_PARSE_IF(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF)
184252884aeSStefan Eßer 
18544d4804dSStefan Eßer // This flag is set if bc is parsing an else statement. This is important
18644d4804dSStefan Eßer // because of "else if" constructions, among other things.
187252884aeSStefan Eßer #define BC_PARSE_FLAG_ELSE (UINTMAX_C(1) << 7)
188252884aeSStefan Eßer #define BC_PARSE_ELSE(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_ELSE)
189252884aeSStefan Eßer 
19044d4804dSStefan Eßer // This flag is set if bc just finished parsing an if statement and its body.
19144d4804dSStefan Eßer // It tells the parser that it can probably expect an else statement next. This
19244d4804dSStefan Eßer // flag is, thus, one of the most subtle.
193252884aeSStefan Eßer #define BC_PARSE_FLAG_IF_END (UINTMAX_C(1) << 8)
194252884aeSStefan Eßer #define BC_PARSE_IF_END(p) (BC_PARSE_TOP_FLAG(p) & BC_PARSE_FLAG_IF_END)
195252884aeSStefan Eßer 
19644d4804dSStefan Eßer /**
19744d4804dSStefan Eßer  * This returns true if bc is in a state where it should not execute any code
19844d4804dSStefan Eßer  * at all.
19944d4804dSStefan Eßer  * @param p  The parser.
20044d4804dSStefan Eßer  * @return   True if execution cannot proceed, false otherwise.
20144d4804dSStefan Eßer  */
202252884aeSStefan Eßer #define BC_PARSE_NO_EXEC(p) ((p)->flags.len != 1 || BC_PARSE_TOP_FLAG(p) != 0)
203252884aeSStefan Eßer 
20444d4804dSStefan Eßer /**
20544d4804dSStefan Eßer  * This returns true if the token @a t is a statement delimiter, which is
20644d4804dSStefan Eßer  * either a newline or a semicolon.
20744d4804dSStefan Eßer  * @param t  The token to check.
20844d4804dSStefan Eßer  * @return   True if t is a statement delimiter token; false otherwise.
20944d4804dSStefan Eßer  */
210252884aeSStefan Eßer #define BC_PARSE_DELIMITER(t) \
211252884aeSStefan Eßer 	((t) == BC_LEX_SCOLON || (t) == BC_LEX_NLINE || (t) == BC_LEX_EOF)
212252884aeSStefan Eßer 
21344d4804dSStefan Eßer /**
21444d4804dSStefan Eßer  * This is poorly named, but it basically returns whether or not the current
21544d4804dSStefan Eßer  * state is valid for the end of an else statement.
21644d4804dSStefan Eßer  * @param f  The flag set to be checked.
21744d4804dSStefan Eßer  * @return   True if the state is valid for the end of an else statement.
21844d4804dSStefan Eßer  */
219252884aeSStefan Eßer #define BC_PARSE_BLOCK_STMT(f) \
220252884aeSStefan Eßer 	((f) & (BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_LOOP_INNER))
221252884aeSStefan Eßer 
22244d4804dSStefan Eßer /**
22344d4804dSStefan Eßer  * This returns the value of the data for an operator with precedence @a p and
22444d4804dSStefan Eßer  * associativity @a l (true if left associative, false otherwise). This is used
22544d4804dSStefan Eßer  * to construct an array of operators, bc_parse_ops, in src/data.c.
22644d4804dSStefan Eßer  * @param p  The precedence.
22744d4804dSStefan Eßer  * @param l  True if the operator is left associative, false otherwise.
22844d4804dSStefan Eßer  * @return   The data for the operator.
22944d4804dSStefan Eßer  */
230252884aeSStefan Eßer #define BC_PARSE_OP(p, l) (((p) & ~(BC_LEX_CHAR_MSB(1))) | (BC_LEX_CHAR_MSB(l)))
231252884aeSStefan Eßer 
23244d4804dSStefan Eßer /**
23344d4804dSStefan Eßer  * Returns the operator data for the lex token @a t.
23444d4804dSStefan Eßer  * @param t  The token to return operator data for.
23544d4804dSStefan Eßer  * @return   The operator data for @a t.
23644d4804dSStefan Eßer  */
237252884aeSStefan Eßer #define BC_PARSE_OP_DATA(t) bc_parse_ops[((t) -BC_LEX_OP_INC)]
23844d4804dSStefan Eßer 
23944d4804dSStefan Eßer /**
24044d4804dSStefan Eßer  * Returns non-zero if operator @a op is left associative, zero otherwise.
24144d4804dSStefan Eßer  * @param op  The operator to test for associativity.
24244d4804dSStefan Eßer  * @return    Non-zero if the operator is left associative, zero otherwise.
24344d4804dSStefan Eßer  */
244252884aeSStefan Eßer #define BC_PARSE_OP_LEFT(op) (BC_PARSE_OP_DATA(op) & BC_LEX_CHAR_MSB(1))
24544d4804dSStefan Eßer 
24644d4804dSStefan Eßer /**
24744d4804dSStefan Eßer  * Returns the precedence of operator @a op. Lower number means higher
24844d4804dSStefan Eßer  * precedence.
24944d4804dSStefan Eßer  * @param op  The operator to return the precedence of.
25044d4804dSStefan Eßer  * @return    The precedence of @a op.
25144d4804dSStefan Eßer  */
252252884aeSStefan Eßer #define BC_PARSE_OP_PREC(op) (BC_PARSE_OP_DATA(op) & ~(BC_LEX_CHAR_MSB(1)))
253252884aeSStefan Eßer 
25444d4804dSStefan Eßer /**
25544d4804dSStefan Eßer  * A macro to easily define a series of bits for whether a lex token is an
25644d4804dSStefan Eßer  * expression token or not. It takes 8 expression bits, corresponding to the 8
25744d4804dSStefan Eßer  * bits in a uint8_t. You can see this in use for bc_parse_exprs in src/data.c.
25844d4804dSStefan Eßer  * @param e1  The first bit.
25944d4804dSStefan Eßer  * @param e2  The second bit.
26044d4804dSStefan Eßer  * @param e3  The third bit.
26144d4804dSStefan Eßer  * @param e4  The fourth bit.
26244d4804dSStefan Eßer  * @param e5  The fifth bit.
26344d4804dSStefan Eßer  * @param e6  The sixth bit.
26444d4804dSStefan Eßer  * @param e7  The seventh bit.
26544d4804dSStefan Eßer  * @param e8  The eighth bit.
26644d4804dSStefan Eßer  * @return    An expression entry for bc_parse_exprs[].
26744d4804dSStefan Eßer  */
268252884aeSStefan Eßer #define BC_PARSE_EXPR_ENTRY(e1, e2, e3, e4, e5, e6, e7, e8)               \
269252884aeSStefan Eßer 	((UINTMAX_C(e1) << 7) | (UINTMAX_C(e2) << 6) | (UINTMAX_C(e3) << 5) | \
270252884aeSStefan Eßer 	 (UINTMAX_C(e4) << 4) | (UINTMAX_C(e5) << 3) | (UINTMAX_C(e6) << 2) | \
271252884aeSStefan Eßer 	 (UINTMAX_C(e7) << 1) | (UINTMAX_C(e8) << 0))
272252884aeSStefan Eßer 
27344d4804dSStefan Eßer /**
27444d4804dSStefan Eßer  * Returns true if token @a i is a token that belongs in an expression.
27544d4804dSStefan Eßer  * @param i  The token to test.
27644d4804dSStefan Eßer  * @return   True if i is an expression token, false otherwise.
27744d4804dSStefan Eßer  */
278252884aeSStefan Eßer #define BC_PARSE_EXPR(i) \
279252884aeSStefan Eßer 	(bc_parse_exprs[(((i) & (uchar) ~(0x07)) >> 3)] & (1 << (7 - ((i) & 0x07))))
280252884aeSStefan Eßer 
28144d4804dSStefan Eßer /**
28244d4804dSStefan Eßer  * Returns the operator (by lex token) that is at the top of the operator
28344d4804dSStefan Eßer  * stack.
28444d4804dSStefan Eßer  * @param p  The parser.
28544d4804dSStefan Eßer  * @return   The operator that is at the top of the operator stack, as a lex
28644d4804dSStefan Eßer  *           token.
28744d4804dSStefan Eßer  */
288252884aeSStefan Eßer #define BC_PARSE_TOP_OP(p) (*((BcLexType*) bc_vec_top(&(p)->ops)))
28944d4804dSStefan Eßer 
29044d4804dSStefan Eßer /**
29144d4804dSStefan Eßer  * Returns true if bc has a "leaf" token. A "leaf" token is one that can stand
29244d4804dSStefan Eßer  * alone in an expression. For example, a number by itself can be an expression,
29344d4804dSStefan Eßer  * but a binary operator, while valid for an expression, cannot be alone in the
29444d4804dSStefan Eßer  * expression. It must have an expression to the left and right of itself. See
29544d4804dSStefan Eßer  * the documentation for @a bc_parse_expr_err() in src/bc_parse.c.
29644d4804dSStefan Eßer  * @param prev      The previous token as an instruction.
29744d4804dSStefan Eßer  * @param bin_last  True if that last operator was a binary operator, false
29844d4804dSStefan Eßer  *                  otherwise.
29944d4804dSStefan Eßer  * @param rparen    True if the last operator was a right paren.
30044d4804dSStefan Eßer  * return           True if the last token was a leaf token, false otherwise.
30144d4804dSStefan Eßer  */
302252884aeSStefan Eßer #define BC_PARSE_LEAF(prev, bin_last, rparen) \
303252884aeSStefan Eßer 	(!(bin_last) && ((rparen) || bc_parse_inst_isLeaf(prev)))
304252884aeSStefan Eßer 
30544d4804dSStefan Eßer /**
30644d4804dSStefan Eßer  * This returns true if the token @a t should be treated as though it's a
30744d4804dSStefan Eßer  * variable. This goes for actual variables, array elements, and globals.
30844d4804dSStefan Eßer  * @param t  The token to test.
30944d4804dSStefan Eßer  * @return   True if @a t should be treated as though it's a variable, false
31044d4804dSStefan Eßer  *           otherwise.
31144d4804dSStefan Eßer  */
31244d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
313252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \
314252884aeSStefan Eßer 	((t) >= BC_INST_VAR && (t) <= BC_INST_SEED && (t) != BC_INST_ARRAY)
31544d4804dSStefan Eßer #else // BC_ENABLE_EXTRA_MATH
316252884aeSStefan Eßer #define BC_PARSE_INST_VAR(t) \
317252884aeSStefan Eßer 	((t) >= BC_INST_VAR && (t) <= BC_INST_SCALE && (t) != BC_INST_ARRAY)
31844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
319252884aeSStefan Eßer 
32044d4804dSStefan Eßer /**
32144d4804dSStefan Eßer  * Returns true if the previous token @a p (in the form of a bytecode
32244d4804dSStefan Eßer  * instruction) is a prefix operator. The fact that it is for bytecode
32344d4804dSStefan Eßer  * instructions is what makes it different from @a BC_PARSE_OP_PREFIX below.
32444d4804dSStefan Eßer  * @param p  The previous token.
32544d4804dSStefan Eßer  * @return   True if @a p is a prefix operator.
32644d4804dSStefan Eßer  */
32744d4804dSStefan Eßer #define BC_PARSE_PREV_PREFIX(p) ((p) >= BC_INST_NEG && (p) <= BC_INST_BOOL_NOT)
32844d4804dSStefan Eßer 
32944d4804dSStefan Eßer /**
33044d4804dSStefan Eßer  * Returns true if token @a t is a prefix operator.
33144d4804dSStefan Eßer  * @param t  The token to test.
33244d4804dSStefan Eßer  * @return   True if @a t is a prefix operator, false otherwise.
33344d4804dSStefan Eßer  */
334252884aeSStefan Eßer #define BC_PARSE_OP_PREFIX(t) ((t) == BC_LEX_OP_BOOL_NOT || (t) == BC_LEX_NEG)
335252884aeSStefan Eßer 
33644d4804dSStefan Eßer /**
33744d4804dSStefan Eßer  * We can calculate the conversion between tokens and bytecode instructions by
33844d4804dSStefan Eßer  * subtracting the position of the first operator in the lex enum and adding the
33944d4804dSStefan Eßer  * position of the first in the instruction enum. Note: This only works for
34044d4804dSStefan Eßer  * binary operators.
34144d4804dSStefan Eßer  * @param t  The token to turn into an instruction.
34244d4804dSStefan Eßer  * @return   The token as an instruction.
34344d4804dSStefan Eßer  */
344252884aeSStefan Eßer #define BC_PARSE_TOKEN_INST(t) ((uchar) ((t) -BC_LEX_NEG + BC_INST_NEG))
345252884aeSStefan Eßer 
34644d4804dSStefan Eßer /**
34744d4804dSStefan Eßer  * Returns true if the token is a bc keyword.
34844d4804dSStefan Eßer  * @param t  The token to check.
34944d4804dSStefan Eßer  * @return   True if @a t is a bc keyword, false otherwise.
35044d4804dSStefan Eßer  */
35144d4804dSStefan Eßer #define BC_PARSE_IS_KEYWORD(t) ((t) >= BC_LEX_KW_AUTO && (t) <= BC_LEX_KW_ELSE)
35244d4804dSStefan Eßer 
35344d4804dSStefan Eßer /// A struct that holds data about what tokens should be expected next. There
35444d4804dSStefan Eßer /// are a few instances of these, all named because they are used in specific
35544d4804dSStefan Eßer /// cases. Basically, in certain situations, it's useful to use the same code,
35644d4804dSStefan Eßer /// but have a list of valid tokens.
35744d4804dSStefan Eßer ///
35844d4804dSStefan Eßer /// Obviously, @a len is the number of tokens in the @a tokens array. If more
35944d4804dSStefan Eßer /// than 4 is needed in the future, @a tokens will have to be changed.
36078bc019dSStefan Eßer typedef struct BcParseNext
36178bc019dSStefan Eßer {
36244d4804dSStefan Eßer 	/// The number of tokens in the tokens array.
36344d4804dSStefan Eßer 	uchar len;
36444d4804dSStefan Eßer 
36544d4804dSStefan Eßer 	/// The tokens that can be expected next.
36644d4804dSStefan Eßer 	uchar tokens[4];
36744d4804dSStefan Eßer 
36844d4804dSStefan Eßer } BcParseNext;
36944d4804dSStefan Eßer 
37044d4804dSStefan Eßer /// A macro to construct an array literal of tokens from a parameter list.
37144d4804dSStefan Eßer #define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
37244d4804dSStefan Eßer 
37344d4804dSStefan Eßer /// A macro to generate a BcParseNext literal from BcParseNext data. See
37444d4804dSStefan Eßer /// src/data.c for examples.
37544d4804dSStefan Eßer #define BC_PARSE_NEXT(a, ...)                                 \
37678bc019dSStefan Eßer 	{                                                         \
37778bc019dSStefan Eßer 		.len = (uchar) (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
37878bc019dSStefan Eßer 	}
37944d4804dSStefan Eßer 
38044d4804dSStefan Eßer /// A status returned by @a bc_parse_expr_err(). It can either return success or
38144d4804dSStefan Eßer /// an error indicating an empty expression.
38278bc019dSStefan Eßer typedef enum BcParseStatus
38378bc019dSStefan Eßer {
384252884aeSStefan Eßer 	BC_PARSE_STATUS_SUCCESS,
385252884aeSStefan Eßer 	BC_PARSE_STATUS_EMPTY_EXPR,
386252884aeSStefan Eßer 
387252884aeSStefan Eßer } BcParseStatus;
388252884aeSStefan Eßer 
38944d4804dSStefan Eßer /**
39044d4804dSStefan Eßer  * The @a BcParseExpr function for bc. (See include/parse.h for a definition of
39144d4804dSStefan Eßer  * @a BcParseExpr.)
39244d4804dSStefan Eßer  * @param p      The parser.
39344d4804dSStefan Eßer  * @param flags  Flags that define the requirements that the parsed code must
39444d4804dSStefan Eßer  *               meet or an error will result. See @a BcParseExpr for more info.
39544d4804dSStefan Eßer  */
39678bc019dSStefan Eßer void
39778bc019dSStefan Eßer bc_parse_expr(BcParse* p, uint8_t flags);
398252884aeSStefan Eßer 
39944d4804dSStefan Eßer /**
40044d4804dSStefan Eßer  * The @a BcParseParse function for bc. (See include/parse.h for a definition of
40144d4804dSStefan Eßer  * @a BcParseParse.)
40244d4804dSStefan Eßer  * @param p  The parser.
40344d4804dSStefan Eßer  */
40478bc019dSStefan Eßer void
40578bc019dSStefan Eßer bc_parse_parse(BcParse* p);
406252884aeSStefan Eßer 
407a30efc5cSStefan Eßer /**
408a30efc5cSStefan Eßer  * Ends a series of if statements. This is to ensure that full parses happen
409a30efc5cSStefan Eßer  * when a file finishes or before defining a function. Without this, bc thinks
410a30efc5cSStefan Eßer  * that it cannot parse any further. But if we reach the end of a file or a
411a30efc5cSStefan Eßer  * function definition, we know we can add an empty else clause.
412a30efc5cSStefan Eßer  * @param p  The parser.
413a30efc5cSStefan Eßer  */
41478bc019dSStefan Eßer void
41578bc019dSStefan Eßer bc_parse_endif(BcParse* p);
416a30efc5cSStefan Eßer 
41744d4804dSStefan Eßer /// References to the signal message and its length.
418252884aeSStefan Eßer extern const char bc_sig_msg[];
419252884aeSStefan Eßer extern const uchar bc_sig_msg_len;
420252884aeSStefan Eßer 
42144d4804dSStefan Eßer /// A reference to an array of bits that are set if the corresponding lex token
42244d4804dSStefan Eßer /// is valid in an expression.
423252884aeSStefan Eßer extern const uint8_t bc_parse_exprs[];
42444d4804dSStefan Eßer 
42544d4804dSStefan Eßer /// A reference to an array of bc operators.
426252884aeSStefan Eßer extern const uchar bc_parse_ops[];
42744d4804dSStefan Eßer 
42844d4804dSStefan Eßer // References to the various instances of BcParseNext's.
42944d4804dSStefan Eßer 
43044d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing normal
43144d4804dSStefan Eßer /// expressions. More accurately. these are the tokens that are valid for
43244d4804dSStefan Eßer /// *ending* the expression.
433252884aeSStefan Eßer extern const BcParseNext bc_parse_next_expr;
43444d4804dSStefan Eßer 
43544d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing function
43644d4804dSStefan Eßer /// parameters (well, actually arguments).
43744d4804dSStefan Eßer extern const BcParseNext bc_parse_next_arg;
43844d4804dSStefan Eßer 
43944d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a print
44044d4804dSStefan Eßer /// statement.
441252884aeSStefan Eßer extern const BcParseNext bc_parse_next_print;
44244d4804dSStefan Eßer 
44344d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing things like
44444d4804dSStefan Eßer /// loop headers and builtin functions where the only thing expected is a right
44544d4804dSStefan Eßer /// paren.
44644d4804dSStefan Eßer ///
44744d4804dSStefan Eßer /// The name is an artifact of history, and is related to @a BC_PARSE_REL (see
44844d4804dSStefan Eßer /// include/parse.h). It refers to how POSIX only allows some operators as part
44944d4804dSStefan Eßer /// of the conditional of for loops, while loops, and if statements.
450252884aeSStefan Eßer extern const BcParseNext bc_parse_next_rel;
45144d4804dSStefan Eßer 
45244d4804dSStefan Eßer // What tokens are valid as next tokens when parsing an array element
45344d4804dSStefan Eßer // expression.
454252884aeSStefan Eßer extern const BcParseNext bc_parse_next_elem;
45544d4804dSStefan Eßer 
45644d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing the first
45744d4804dSStefan Eßer /// two parts of a for loop header.
458252884aeSStefan Eßer extern const BcParseNext bc_parse_next_for;
45944d4804dSStefan Eßer 
46044d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a read
46144d4804dSStefan Eßer /// expression.
462252884aeSStefan Eßer extern const BcParseNext bc_parse_next_read;
463252884aeSStefan Eßer 
46444d4804dSStefan Eßer /// A reference to what tokens are valid as next tokens when parsing a builtin
46544d4804dSStefan Eßer /// function with multiple arguments.
46644d4804dSStefan Eßer extern const BcParseNext bc_parse_next_builtin;
46744d4804dSStefan Eßer 
468d213476dSStefan Eßer #else // BC_ENABLED
469d213476dSStefan Eßer 
47044d4804dSStefan Eßer // If bc is not enabled, execution is always possible because dc has strict
47144d4804dSStefan Eßer // rules that ensure execution can always proceed safely.
472d213476dSStefan Eßer #define BC_PARSE_NO_EXEC(p) (0)
473d213476dSStefan Eßer 
474252884aeSStefan Eßer #endif // BC_ENABLED
475252884aeSStefan Eßer 
476252884aeSStefan Eßer #endif // BC_BC_H
477