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