xref: /freebsd/contrib/bc/include/lang.h (revision a970610a3af63b3f4df5b69d91c6b4093a00ed8f)
1252884aeSStefan Eßer /*
2252884aeSStefan Eßer  * *****************************************************************************
3252884aeSStefan Eßer  *
43aa99676SStefan Eßer  * SPDX-License-Identifier: BSD-2-Clause
5252884aeSStefan Eßer  *
6*a970610aSStefan 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  *
32252884aeSStefan Eßer  * Definitions for program data.
33252884aeSStefan Eßer  *
34252884aeSStefan Eßer  */
35252884aeSStefan Eßer 
36252884aeSStefan Eßer #ifndef BC_LANG_H
37252884aeSStefan Eßer #define BC_LANG_H
38252884aeSStefan Eßer 
39252884aeSStefan Eßer #include <stdbool.h>
40252884aeSStefan Eßer 
41d101cdd6SStefan Eßer // These have to come first to silence a warning on BC_C11 below.
42252884aeSStefan Eßer #include <status.h>
43252884aeSStefan Eßer #include <vector.h>
44252884aeSStefan Eßer #include <num.h>
45252884aeSStefan Eßer 
46d101cdd6SStefan Eßer #if BC_C11
47d101cdd6SStefan Eßer #include <assert.h>
48d101cdd6SStefan Eßer #endif // BC_C11
49d101cdd6SStefan Eßer 
5044d4804dSStefan Eßer /// The instructions for bytecode.
5178bc019dSStefan Eßer typedef enum BcInst
5278bc019dSStefan Eßer {
53252884aeSStefan Eßer #if BC_ENABLED
5444d4804dSStefan Eßer 	/// Postfix increment and decrement. Prefix are translated into
5544d4804dSStefan Eßer 	/// BC_INST_ONE with either BC_INST_ASSIGN_PLUS or BC_INST_ASSIGN_MINUS.
56252884aeSStefan Eßer 	BC_INST_INC = 0,
57252884aeSStefan Eßer 	BC_INST_DEC,
58252884aeSStefan Eßer #endif // BC_ENABLED
59252884aeSStefan Eßer 
6044d4804dSStefan Eßer 	/// Unary negation.
61252884aeSStefan Eßer 	BC_INST_NEG,
6244d4804dSStefan Eßer 
6344d4804dSStefan Eßer 	/// Boolean not.
64252884aeSStefan Eßer 	BC_INST_BOOL_NOT,
65d101cdd6SStefan Eßer 
66252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
6744d4804dSStefan Eßer 	/// Truncation operator.
68252884aeSStefan Eßer 	BC_INST_TRUNC,
69252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
70252884aeSStefan Eßer 
7144d4804dSStefan Eßer 	/// These should be self-explanatory.
72252884aeSStefan Eßer 	BC_INST_POWER,
73252884aeSStefan Eßer 	BC_INST_MULTIPLY,
74252884aeSStefan Eßer 	BC_INST_DIVIDE,
75252884aeSStefan Eßer 	BC_INST_MODULUS,
76252884aeSStefan Eßer 	BC_INST_PLUS,
77252884aeSStefan Eßer 	BC_INST_MINUS,
78252884aeSStefan Eßer 
79252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
8044d4804dSStefan Eßer 	/// Places operator.
81252884aeSStefan Eßer 	BC_INST_PLACES,
82252884aeSStefan Eßer 
8344d4804dSStefan Eßer 	/// Shift operators.
84252884aeSStefan Eßer 	BC_INST_LSHIFT,
85252884aeSStefan Eßer 	BC_INST_RSHIFT,
86252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
87252884aeSStefan Eßer 
8844d4804dSStefan Eßer 	/// Comparison operators.
89252884aeSStefan Eßer 	BC_INST_REL_EQ,
90252884aeSStefan Eßer 	BC_INST_REL_LE,
91252884aeSStefan Eßer 	BC_INST_REL_GE,
92252884aeSStefan Eßer 	BC_INST_REL_NE,
93252884aeSStefan Eßer 	BC_INST_REL_LT,
94252884aeSStefan Eßer 	BC_INST_REL_GT,
95252884aeSStefan Eßer 
9644d4804dSStefan Eßer 	/// Boolean or and and.
97252884aeSStefan Eßer 	BC_INST_BOOL_OR,
98252884aeSStefan Eßer 	BC_INST_BOOL_AND,
99252884aeSStefan Eßer 
100252884aeSStefan Eßer #if BC_ENABLED
10144d4804dSStefan Eßer 	/// Same as the normal operators, but assigment. So ^=, *=, /=, etc.
102252884aeSStefan Eßer 	BC_INST_ASSIGN_POWER,
103252884aeSStefan Eßer 	BC_INST_ASSIGN_MULTIPLY,
104252884aeSStefan Eßer 	BC_INST_ASSIGN_DIVIDE,
105252884aeSStefan Eßer 	BC_INST_ASSIGN_MODULUS,
106252884aeSStefan Eßer 	BC_INST_ASSIGN_PLUS,
107252884aeSStefan Eßer 	BC_INST_ASSIGN_MINUS,
108252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
10944d4804dSStefan Eßer 	/// Places and shift assignment operators.
110252884aeSStefan Eßer 	BC_INST_ASSIGN_PLACES,
111252884aeSStefan Eßer 	BC_INST_ASSIGN_LSHIFT,
112252884aeSStefan Eßer 	BC_INST_ASSIGN_RSHIFT,
113252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
11444d4804dSStefan Eßer 
11544d4804dSStefan Eßer 	/// Normal assignment.
116252884aeSStefan Eßer 	BC_INST_ASSIGN,
117252884aeSStefan Eßer 
11844d4804dSStefan Eßer 	/// bc and dc detect when the value from an assignment is not necessary.
11944d4804dSStefan Eßer 	/// For example, a plain assignment statement means the value is never used.
12044d4804dSStefan Eßer 	/// In those cases, we can get lots of performance back by not even creating
12144d4804dSStefan Eßer 	/// a copy at all. In fact, it saves a copy, a push onto the results stack,
12244d4804dSStefan Eßer 	/// a pop from the results stack, and a free. Definitely worth it to detect.
123252884aeSStefan Eßer 	BC_INST_ASSIGN_POWER_NO_VAL,
124252884aeSStefan Eßer 	BC_INST_ASSIGN_MULTIPLY_NO_VAL,
125252884aeSStefan Eßer 	BC_INST_ASSIGN_DIVIDE_NO_VAL,
126252884aeSStefan Eßer 	BC_INST_ASSIGN_MODULUS_NO_VAL,
127252884aeSStefan Eßer 	BC_INST_ASSIGN_PLUS_NO_VAL,
128252884aeSStefan Eßer 	BC_INST_ASSIGN_MINUS_NO_VAL,
129252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
13044d4804dSStefan Eßer 	/// Same as above.
131252884aeSStefan Eßer 	BC_INST_ASSIGN_PLACES_NO_VAL,
132252884aeSStefan Eßer 	BC_INST_ASSIGN_LSHIFT_NO_VAL,
133252884aeSStefan Eßer 	BC_INST_ASSIGN_RSHIFT_NO_VAL,
134252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
135252884aeSStefan Eßer #endif // BC_ENABLED
13644d4804dSStefan Eßer 
13744d4804dSStefan Eßer 	/// Normal assignment that pushes no value on the stack.
138252884aeSStefan Eßer 	BC_INST_ASSIGN_NO_VAL,
139252884aeSStefan Eßer 
14044d4804dSStefan Eßer 	/// Push a constant onto the results stack.
141252884aeSStefan Eßer 	BC_INST_NUM,
142252884aeSStefan Eßer 
14344d4804dSStefan Eßer 	/// Push a variable onto the results stack.
14444d4804dSStefan Eßer 	BC_INST_VAR,
14544d4804dSStefan Eßer 
14644d4804dSStefan Eßer 	/// Push an array element onto the results stack.
14744d4804dSStefan Eßer 	BC_INST_ARRAY_ELEM,
14844d4804dSStefan Eßer 
14944d4804dSStefan Eßer 	/// Push an array onto the results stack. This is different from pushing an
15044d4804dSStefan Eßer 	/// array *element* onto the results stack; it pushes a reference to the
15144d4804dSStefan Eßer 	/// whole array. This is needed in bc for function arguments that are
15244d4804dSStefan Eßer 	/// arrays. It is also needed for returning the length of an array.
15344d4804dSStefan Eßer 	BC_INST_ARRAY,
15444d4804dSStefan Eßer 
15544d4804dSStefan Eßer 	/// Push a zero or a one onto the stack. These are special cased because it
15644d4804dSStefan Eßer 	/// does help performance, particularly for one since inc/dec operators
15744d4804dSStefan Eßer 	/// use it.
1583aa99676SStefan Eßer 	BC_INST_ZERO,
159252884aeSStefan Eßer 	BC_INST_ONE,
160252884aeSStefan Eßer 
161252884aeSStefan Eßer #if BC_ENABLED
16244d4804dSStefan Eßer 	/// Push the last printed value onto the stack.
163252884aeSStefan Eßer 	BC_INST_LAST,
164252884aeSStefan Eßer #endif // BC_ENABLED
16544d4804dSStefan Eßer 
16644d4804dSStefan Eßer 	/// Push the value of any of the globals onto the stack.
167252884aeSStefan Eßer 	BC_INST_IBASE,
168252884aeSStefan Eßer 	BC_INST_OBASE,
169252884aeSStefan Eßer 	BC_INST_SCALE,
17044d4804dSStefan Eßer 
17144d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
17244d4804dSStefan Eßer 	/// Push the value of the seed global onto the stack.
173252884aeSStefan Eßer 	BC_INST_SEED,
17444d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
17544d4804dSStefan Eßer 
17644d4804dSStefan Eßer 	/// These are builtin functions.
177252884aeSStefan Eßer 	BC_INST_LENGTH,
178252884aeSStefan Eßer 	BC_INST_SCALE_FUNC,
179252884aeSStefan Eßer 	BC_INST_SQRT,
180252884aeSStefan Eßer 	BC_INST_ABS,
181d101cdd6SStefan Eßer 	BC_INST_IS_NUMBER,
182d101cdd6SStefan Eßer 	BC_INST_IS_STRING,
18344d4804dSStefan Eßer 
18444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
18544d4804dSStefan Eßer 	/// Another builtin function.
186252884aeSStefan Eßer 	BC_INST_IRAND,
18744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
18844d4804dSStefan Eßer 
18944d4804dSStefan Eßer 	/// Asciify.
19044d4804dSStefan Eßer 	BC_INST_ASCIIFY,
19144d4804dSStefan Eßer 
19244d4804dSStefan Eßer 	/// Another builtin function.
193252884aeSStefan Eßer 	BC_INST_READ,
19444d4804dSStefan Eßer 
19544d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
19644d4804dSStefan Eßer 	/// Another builtin function.
197252884aeSStefan Eßer 	BC_INST_RAND,
19844d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
19944d4804dSStefan Eßer 
20044d4804dSStefan Eßer 	/// Return the max for the various globals.
201252884aeSStefan Eßer 	BC_INST_MAXIBASE,
202252884aeSStefan Eßer 	BC_INST_MAXOBASE,
203252884aeSStefan Eßer 	BC_INST_MAXSCALE,
20444d4804dSStefan Eßer #if BC_ENABLE_EXTRA_MATH
20544d4804dSStefan Eßer 	/// Return the max value returned by rand().
206252884aeSStefan Eßer 	BC_INST_MAXRAND,
20744d4804dSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
208252884aeSStefan Eßer 
209d43fa8efSStefan Eßer 	/// bc line_length() builtin function.
210d43fa8efSStefan Eßer 	BC_INST_LINE_LENGTH,
211d43fa8efSStefan Eßer 
212d43fa8efSStefan Eßer #if BC_ENABLED
213d43fa8efSStefan Eßer 
214d43fa8efSStefan Eßer 	/// bc global_stacks() builtin function.
215d43fa8efSStefan Eßer 	BC_INST_GLOBAL_STACKS,
216d43fa8efSStefan Eßer 
217d43fa8efSStefan Eßer #endif // BC_ENABLED
218d43fa8efSStefan Eßer 
219d43fa8efSStefan Eßer 	/// bc leading_zero() builtin function.
220d43fa8efSStefan Eßer 	BC_INST_LEADING_ZERO,
221d43fa8efSStefan Eßer 
22244d4804dSStefan Eßer 	/// This is slightly misnamed versus BC_INST_PRINT_POP. Well, it is in bc.
22344d4804dSStefan Eßer 	/// dc uses this instruction to print, but not pop. That's valid in dc.
22444d4804dSStefan Eßer 	/// However, in bc, it is *never* valid to print without popping. In bc,
22544d4804dSStefan Eßer 	/// BC_INST_PRINT_POP is used to indicate when a string should be printed
22644d4804dSStefan Eßer 	/// because of a print statement or whether it should be printed raw. The
22744d4804dSStefan Eßer 	/// reason for this is because a print statement handles escaped characters.
22844d4804dSStefan Eßer 	/// So BC_INST_PRINT_POP is for printing a string from a print statement,
22944d4804dSStefan Eßer 	/// BC_INST_PRINT_STR is for printing a string by itself.
23044d4804dSStefan Eßer 	///
23144d4804dSStefan Eßer 	/// In dc, BC_INST_PRINT_POP prints and pops, and BC_INST_PRINT just prints.
23244d4804dSStefan Eßer 	///
23344d4804dSStefan Eßer 	/// Oh, and BC_INST_STR pushes a string onto the results stack.
234252884aeSStefan Eßer 	BC_INST_PRINT,
235252884aeSStefan Eßer 	BC_INST_PRINT_POP,
236252884aeSStefan Eßer 	BC_INST_STR,
23744d4804dSStefan Eßer #if BC_ENABLED
238252884aeSStefan Eßer 	BC_INST_PRINT_STR,
239252884aeSStefan Eßer 
24044d4804dSStefan Eßer 	/// Jumps unconditionally.
241252884aeSStefan Eßer 	BC_INST_JUMP,
24244d4804dSStefan Eßer 
24344d4804dSStefan Eßer 	/// Jumps if the top of the results stack is zero (condition failed). It
24444d4804dSStefan Eßer 	/// turns out that we only want to jump when conditions fail to "skip" code.
245252884aeSStefan Eßer 	BC_INST_JUMP_ZERO,
246252884aeSStefan Eßer 
24744d4804dSStefan Eßer 	/// Call a function.
248252884aeSStefan Eßer 	BC_INST_CALL,
249252884aeSStefan Eßer 
25044d4804dSStefan Eßer 	/// Return the top of the stack to the caller.
251252884aeSStefan Eßer 	BC_INST_RET,
25244d4804dSStefan Eßer 
25344d4804dSStefan Eßer 	/// Return 0 to the caller.
254252884aeSStefan Eßer 	BC_INST_RET0,
25544d4804dSStefan Eßer 
25644d4804dSStefan Eßer 	/// Special return instruction for void functions.
257252884aeSStefan Eßer 	BC_INST_RET_VOID,
258252884aeSStefan Eßer 
25944d4804dSStefan Eßer 	/// Special halt instruction.
260252884aeSStefan Eßer 	BC_INST_HALT,
261252884aeSStefan Eßer #endif // BC_ENABLED
262252884aeSStefan Eßer 
26344d4804dSStefan Eßer 	/// Pop an item off of the results stack.
264252884aeSStefan Eßer 	BC_INST_POP,
265252884aeSStefan Eßer 
26644d4804dSStefan Eßer 	/// Swaps the top two items on the results stack.
267252884aeSStefan Eßer 	BC_INST_SWAP,
268252884aeSStefan Eßer 
26944d4804dSStefan Eßer 	/// Modular exponentiation.
27044d4804dSStefan Eßer 	BC_INST_MODEXP,
27144d4804dSStefan Eßer 
27244d4804dSStefan Eßer 	/// Do divide and modulus at the same time.
27344d4804dSStefan Eßer 	BC_INST_DIVMOD,
27444d4804dSStefan Eßer 
27544d4804dSStefan Eßer 	/// Turns a number into a string and prints it.
27644d4804dSStefan Eßer 	BC_INST_PRINT_STREAM,
27744d4804dSStefan Eßer 
27844d4804dSStefan Eßer #if DC_ENABLED
27944d4804dSStefan Eßer 
280103d7cdfSStefan Eßer 	/// dc extended registers command.
281103d7cdfSStefan Eßer 	BC_INST_EXTENDED_REGISTERS,
282103d7cdfSStefan Eßer 
28344d4804dSStefan Eßer 	/// dc's return; it pops an executing string off of the stack.
28444d4804dSStefan Eßer 	BC_INST_POP_EXEC,
28544d4804dSStefan Eßer 
28644d4804dSStefan Eßer 	/// Unconditionally execute a string.
28744d4804dSStefan Eßer 	BC_INST_EXECUTE,
28844d4804dSStefan Eßer 
28944d4804dSStefan Eßer 	/// Conditionally execute a string.
29044d4804dSStefan Eßer 	BC_INST_EXEC_COND,
29144d4804dSStefan Eßer 
29244d4804dSStefan Eßer 	/// Prints each item on the results stack, separated by newlines.
29344d4804dSStefan Eßer 	BC_INST_PRINT_STACK,
29444d4804dSStefan Eßer 
29544d4804dSStefan Eßer 	/// Pops everything off of the results stack.
29644d4804dSStefan Eßer 	BC_INST_CLEAR_STACK,
29744d4804dSStefan Eßer 
29844d4804dSStefan Eßer 	/// Pushes the current length of a register stack onto the results stack.
29944d4804dSStefan Eßer 	BC_INST_REG_STACK_LEN,
30044d4804dSStefan Eßer 
30144d4804dSStefan Eßer 	/// Pushes the current length of the results stack onto the results stack.
30244d4804dSStefan Eßer 	BC_INST_STACK_LEN,
30344d4804dSStefan Eßer 
30444d4804dSStefan Eßer 	/// Pushes a copy of the item on the top of the results stack onto the
30544d4804dSStefan Eßer 	/// results stack.
30644d4804dSStefan Eßer 	BC_INST_DUPLICATE,
30744d4804dSStefan Eßer 
30844d4804dSStefan Eßer 	/// Copies the value in a register and pushes the copy onto the results
30944d4804dSStefan Eßer 	/// stack.
310252884aeSStefan Eßer 	BC_INST_LOAD,
31144d4804dSStefan Eßer 
31244d4804dSStefan Eßer 	/// Pops an item off of a register stack and pushes it onto the results
31344d4804dSStefan Eßer 	/// stack.
314252884aeSStefan Eßer 	BC_INST_PUSH_VAR,
31544d4804dSStefan Eßer 
31644d4804dSStefan Eßer 	/// Pops an item off of the results stack and pushes it onto a register's
31744d4804dSStefan Eßer 	/// stack.
318252884aeSStefan Eßer 	BC_INST_PUSH_TO_VAR,
319252884aeSStefan Eßer 
32044d4804dSStefan Eßer 	/// Quit.
321252884aeSStefan Eßer 	BC_INST_QUIT,
32244d4804dSStefan Eßer 
32344d4804dSStefan Eßer 	/// Quit executing some number of strings.
324252884aeSStefan Eßer 	BC_INST_NQUIT,
32544d4804dSStefan Eßer 
32644d4804dSStefan Eßer 	/// Push the depth of the execution stack onto the stack.
32744d4804dSStefan Eßer 	BC_INST_EXEC_STACK_LEN,
32844d4804dSStefan Eßer 
329252884aeSStefan Eßer #endif // DC_ENABLED
330252884aeSStefan Eßer 
33144d4804dSStefan Eßer 	/// Invalid instruction.
33244d4804dSStefan Eßer 	BC_INST_INVALID,
333252884aeSStefan Eßer 
334252884aeSStefan Eßer } BcInst;
335252884aeSStefan Eßer 
33600698711SStefan Eßer #if BC_C11
33778bc019dSStefan Eßer _Static_assert(BC_INST_INVALID <= UCHAR_MAX,
33800698711SStefan Eßer                "Too many instructions to fit into an unsigned char");
33900698711SStefan Eßer #endif // BC_C11
34000698711SStefan Eßer 
34144d4804dSStefan Eßer /// Used by maps to identify where items are in the array.
34278bc019dSStefan Eßer typedef struct BcId
34378bc019dSStefan Eßer {
34444d4804dSStefan Eßer 	/// The name of the item.
345252884aeSStefan Eßer 	char* name;
34644d4804dSStefan Eßer 
34744d4804dSStefan Eßer 	/// The index into the array where the item is.
348252884aeSStefan Eßer 	size_t idx;
34944d4804dSStefan Eßer 
350252884aeSStefan Eßer } BcId;
351252884aeSStefan Eßer 
35244d4804dSStefan Eßer /// The location of a var, array, or array element.
35378bc019dSStefan Eßer typedef struct BcLoc
35478bc019dSStefan Eßer {
35544d4804dSStefan Eßer 	/// The index of the var or array.
356252884aeSStefan Eßer 	size_t loc;
35744d4804dSStefan Eßer 
358d101cdd6SStefan Eßer 	/// The index of the array or variable in the array stack. This is to
359d101cdd6SStefan Eßer 	/// prevent a bug with getting the wrong array element or variable after a
360d101cdd6SStefan Eßer 	/// function call. See the tests/bc/scripts/array.bc test for the array
361d101cdd6SStefan Eßer 	/// case; the variable case is in various variable tests.
362d101cdd6SStefan Eßer 	size_t stack_idx;
363d101cdd6SStefan Eßer 
36444d4804dSStefan Eßer 	/// The index of the array element. Only used for array elements.
365252884aeSStefan Eßer 	size_t idx;
36644d4804dSStefan Eßer 
367252884aeSStefan Eßer } BcLoc;
368252884aeSStefan Eßer 
36944d4804dSStefan Eßer /// An entry for a constant.
37078bc019dSStefan Eßer typedef struct BcConst
37178bc019dSStefan Eßer {
37244d4804dSStefan Eßer 	/// The original string as parsed from the source code.
373252884aeSStefan Eßer 	char* val;
37444d4804dSStefan Eßer 
37544d4804dSStefan Eßer 	/// The last base that the constant was parsed in.
376252884aeSStefan Eßer 	BcBigDig base;
37744d4804dSStefan Eßer 
37844d4804dSStefan Eßer 	/// The parsed constant.
379252884aeSStefan Eßer 	BcNum num;
38044d4804dSStefan Eßer 
381252884aeSStefan Eßer } BcConst;
382252884aeSStefan Eßer 
38344d4804dSStefan Eßer /// A function. This is also used in dc, not just bc. The reason is that strings
38444d4804dSStefan Eßer /// are executed in dc, and they are converted to functions in order to be
38544d4804dSStefan Eßer /// executed.
38678bc019dSStefan Eßer typedef struct BcFunc
38778bc019dSStefan Eßer {
38844d4804dSStefan Eßer 	/// The bytecode instructions.
389252884aeSStefan Eßer 	BcVec code;
39044d4804dSStefan Eßer 
391252884aeSStefan Eßer #if BC_ENABLED
39244d4804dSStefan Eßer 
39344d4804dSStefan Eßer 	/// The labels. This is a vector of indices. The index is the index into
39444d4804dSStefan Eßer 	/// the bytecode vector where the label is.
395252884aeSStefan Eßer 	BcVec labels;
39644d4804dSStefan Eßer 
39744d4804dSStefan Eßer 	/// The autos for the function. The first items are the parameters, and the
39844d4804dSStefan Eßer 	/// arguments to the parameters must match the types in this vector.
399252884aeSStefan Eßer 	BcVec autos;
40044d4804dSStefan Eßer 
40144d4804dSStefan Eßer 	/// The number of parameters the function takes.
402252884aeSStefan Eßer 	size_t nparams;
40344d4804dSStefan Eßer 
404252884aeSStefan Eßer #endif // BC_ENABLED
405252884aeSStefan Eßer 
40644d4804dSStefan Eßer 	/// The function's name.
407252884aeSStefan Eßer 	const char* name;
40844d4804dSStefan Eßer 
409252884aeSStefan Eßer #if BC_ENABLED
41044d4804dSStefan Eßer 	/// True if the function is a void function.
411252884aeSStefan Eßer 	bool voidfn;
412252884aeSStefan Eßer #endif // BC_ENABLED
413252884aeSStefan Eßer 
414252884aeSStefan Eßer } BcFunc;
415252884aeSStefan Eßer 
41644d4804dSStefan Eßer /// Types of results that can be pushed onto the results stack.
41778bc019dSStefan Eßer typedef enum BcResultType
41878bc019dSStefan Eßer {
41944d4804dSStefan Eßer 	/// Result is a variable.
420252884aeSStefan Eßer 	BC_RESULT_VAR,
421252884aeSStefan Eßer 
42244d4804dSStefan Eßer 	/// Result is an array element.
42344d4804dSStefan Eßer 	BC_RESULT_ARRAY_ELEM,
42444d4804dSStefan Eßer 
42544d4804dSStefan Eßer 	/// Result is an array. This is only allowed for function arguments or
42644d4804dSStefan Eßer 	/// returning the length of the array.
42744d4804dSStefan Eßer 	BC_RESULT_ARRAY,
42844d4804dSStefan Eßer 
42944d4804dSStefan Eßer 	/// Result is a string.
430252884aeSStefan Eßer 	BC_RESULT_STR,
431252884aeSStefan Eßer 
43244d4804dSStefan Eßer 	/// Result is a temporary. This is used for the result of almost all
43344d4804dSStefan Eßer 	/// expressions.
434252884aeSStefan Eßer 	BC_RESULT_TEMP,
435252884aeSStefan Eßer 
43644d4804dSStefan Eßer 	/// Special casing the two below gave performance improvements.
43744d4804dSStefan Eßer 
43844d4804dSStefan Eßer 	/// Result is a 0.
4393aa99676SStefan Eßer 	BC_RESULT_ZERO,
44044d4804dSStefan Eßer 
44144d4804dSStefan Eßer 	/// Result is a 1. Useful for inc/dec operators.
442252884aeSStefan Eßer 	BC_RESULT_ONE,
443252884aeSStefan Eßer 
444252884aeSStefan Eßer #if BC_ENABLED
44544d4804dSStefan Eßer 
44644d4804dSStefan Eßer 	/// Result is the special "last" variable.
447252884aeSStefan Eßer 	BC_RESULT_LAST,
44844d4804dSStefan Eßer 
44944d4804dSStefan Eßer 	/// Result is the return value of a void function.
450252884aeSStefan Eßer 	BC_RESULT_VOID,
451252884aeSStefan Eßer #endif // BC_ENABLED
45244d4804dSStefan Eßer 
45344d4804dSStefan Eßer 	/// Result is the value of ibase.
454252884aeSStefan Eßer 	BC_RESULT_IBASE,
45544d4804dSStefan Eßer 
45644d4804dSStefan Eßer 	/// Result is the value of obase.
457252884aeSStefan Eßer 	BC_RESULT_OBASE,
45844d4804dSStefan Eßer 
45944d4804dSStefan Eßer 	/// Result is the value of scale.
460252884aeSStefan Eßer 	BC_RESULT_SCALE,
46144d4804dSStefan Eßer 
462252884aeSStefan Eßer #if BC_ENABLE_EXTRA_MATH
46344d4804dSStefan Eßer 
46444d4804dSStefan Eßer 	/// Result is the value of seed.
465252884aeSStefan Eßer 	BC_RESULT_SEED,
46644d4804dSStefan Eßer 
467252884aeSStefan Eßer #endif // BC_ENABLE_EXTRA_MATH
468252884aeSStefan Eßer 
469252884aeSStefan Eßer } BcResultType;
470252884aeSStefan Eßer 
47144d4804dSStefan Eßer /// A union to store data for various result types.
47278bc019dSStefan Eßer typedef union BcResultData
47378bc019dSStefan Eßer {
47444d4804dSStefan Eßer 	/// A number. Strings are stored here too; they are numbers with
47544d4804dSStefan Eßer 	/// cap == 0 && num == NULL. The string's index into the strings vector is
47644d4804dSStefan Eßer 	/// stored in the scale field. But this is only used for strings stored in
47744d4804dSStefan Eßer 	/// variables.
478252884aeSStefan Eßer 	BcNum n;
47944d4804dSStefan Eßer 
48044d4804dSStefan Eßer 	/// A vector.
481252884aeSStefan Eßer 	BcVec v;
48244d4804dSStefan Eßer 
48344d4804dSStefan Eßer 	/// A variable, array, or array element reference. This could also be a
48444d4804dSStefan Eßer 	/// string if a string is not stored in a variable (dc only).
485252884aeSStefan Eßer 	BcLoc loc;
48644d4804dSStefan Eßer 
487252884aeSStefan Eßer } BcResultData;
488252884aeSStefan Eßer 
48944d4804dSStefan Eßer /// A tagged union for results.
49078bc019dSStefan Eßer typedef struct BcResult
49178bc019dSStefan Eßer {
49244d4804dSStefan Eßer 	/// The tag. The type of the result.
493252884aeSStefan Eßer 	BcResultType t;
49444d4804dSStefan Eßer 
49544d4804dSStefan Eßer 	/// The data. The data for the result.
496252884aeSStefan Eßer 	BcResultData d;
49744d4804dSStefan Eßer 
498252884aeSStefan Eßer } BcResult;
499252884aeSStefan Eßer 
50044d4804dSStefan Eßer /// An instruction pointer. This is how bc knows where in the bytecode vector,
50144d4804dSStefan Eßer /// and which function, the current execution is.
50278bc019dSStefan Eßer typedef struct BcInstPtr
50378bc019dSStefan Eßer {
50444d4804dSStefan Eßer 	/// The index of the currently executing function in the fns vector.
505252884aeSStefan Eßer 	size_t func;
50644d4804dSStefan Eßer 
50744d4804dSStefan Eßer 	/// The index into the bytecode vector of the *next* instruction.
508252884aeSStefan Eßer 	size_t idx;
50944d4804dSStefan Eßer 
51044d4804dSStefan Eßer 	/// The length of the results vector when this function started executing.
51144d4804dSStefan Eßer 	/// This is mostly used for bc where functions should not affect the results
51244d4804dSStefan Eßer 	/// of their callers.
513252884aeSStefan Eßer 	size_t len;
51444d4804dSStefan Eßer 
515252884aeSStefan Eßer } BcInstPtr;
516252884aeSStefan Eßer 
51744d4804dSStefan Eßer /// Types of identifiers.
51878bc019dSStefan Eßer typedef enum BcType
51978bc019dSStefan Eßer {
52044d4804dSStefan Eßer 	/// Variable.
521252884aeSStefan Eßer 	BC_TYPE_VAR,
52244d4804dSStefan Eßer 
52344d4804dSStefan Eßer 	/// Array.
524252884aeSStefan Eßer 	BC_TYPE_ARRAY,
52544d4804dSStefan Eßer 
526252884aeSStefan Eßer #if BC_ENABLED
52744d4804dSStefan Eßer 
52844d4804dSStefan Eßer 	/// Array reference.
529252884aeSStefan Eßer 	BC_TYPE_REF,
53044d4804dSStefan Eßer 
531252884aeSStefan Eßer #endif // BC_ENABLED
53244d4804dSStefan Eßer 
533252884aeSStefan Eßer } BcType;
534252884aeSStefan Eßer 
53544d4804dSStefan Eßer #if BC_ENABLED
53644d4804dSStefan Eßer /// An auto variable in bc.
53778bc019dSStefan Eßer typedef struct BcAuto
53878bc019dSStefan Eßer {
53944d4804dSStefan Eßer 	/// The index of the variable in the vars or arrs vectors.
54044d4804dSStefan Eßer 	size_t idx;
54144d4804dSStefan Eßer 
54244d4804dSStefan Eßer 	/// The type of the variable.
54344d4804dSStefan Eßer 	BcType type;
54444d4804dSStefan Eßer 
54544d4804dSStefan Eßer } BcAuto;
54644d4804dSStefan Eßer #endif // BC_ENABLED
54744d4804dSStefan Eßer 
54844d4804dSStefan Eßer /// Forward declaration.
549252884aeSStefan Eßer struct BcProgram;
550252884aeSStefan Eßer 
55144d4804dSStefan Eßer /**
55244d4804dSStefan Eßer  * Initializes a function.
55344d4804dSStefan Eßer  * @param f     The function to initialize.
55444d4804dSStefan Eßer  * @param name  The name of the function. The string is assumed to be owned by
55544d4804dSStefan Eßer  *              some other entity.
55644d4804dSStefan Eßer  */
55778bc019dSStefan Eßer void
55878bc019dSStefan Eßer bc_func_init(BcFunc* f, const char* name);
55944d4804dSStefan Eßer 
56044d4804dSStefan Eßer /**
56144d4804dSStefan Eßer  * Inserts an auto into the function.
56244d4804dSStefan Eßer  * @param f     The function to insert into.
56344d4804dSStefan Eßer  * @param p     The program. This is to search for the variable or array name.
56444d4804dSStefan Eßer  * @param name  The name of the auto to insert.
56544d4804dSStefan Eßer  * @param type  The type of the auto.
56644d4804dSStefan Eßer  * @param line  The line in the source code where the insert happened. This is
56744d4804dSStefan Eßer  *              solely for error reporting.
56844d4804dSStefan Eßer  */
56978bc019dSStefan Eßer void
57078bc019dSStefan Eßer bc_func_insert(BcFunc* f, struct BcProgram* p, char* name, BcType type,
57178bc019dSStefan Eßer                size_t line);
572252884aeSStefan Eßer 
57344d4804dSStefan Eßer /**
57444d4804dSStefan Eßer  * Resets a function in preparation for it to be reused. This can happen in bc
57544d4804dSStefan Eßer  * because it is a dynamic language and functions can be redefined.
57644d4804dSStefan Eßer  * @param f  The functio to reset.
57744d4804dSStefan Eßer  */
57878bc019dSStefan Eßer void
57978bc019dSStefan Eßer bc_func_reset(BcFunc* f);
58044d4804dSStefan Eßer 
581103d7cdfSStefan Eßer #if BC_DEBUG
58244d4804dSStefan Eßer /**
58344d4804dSStefan Eßer  * Frees a function. This is a destructor. This is only used in debug builds
58444d4804dSStefan Eßer  * because all functions are freed at exit. We free them in debug builds to
58544d4804dSStefan Eßer  * check for memory leaks.
58644d4804dSStefan Eßer  * @param func  The function to free as a void pointer.
58744d4804dSStefan Eßer  */
58878bc019dSStefan Eßer void
58978bc019dSStefan Eßer bc_func_free(void* func);
590103d7cdfSStefan Eßer #endif // BC_DEBUG
59144d4804dSStefan Eßer 
59244d4804dSStefan Eßer /**
59344d4804dSStefan Eßer  * Initializes an array, which is the array type in bc and dc source code. Since
59444d4804dSStefan Eßer  * variables and arrays are both arrays (see the development manual,
59544d4804dSStefan Eßer  * manuals/development.md#execution, for more information), the @a nums
59644d4804dSStefan Eßer  * parameter tells bc whether to initialize an array of numbers or an array of
59744d4804dSStefan Eßer  * arrays of numbers. If the latter, it does a recursive call with nums set to
59844d4804dSStefan Eßer  * true.
59944d4804dSStefan Eßer  * @param a     The array to initialize.
60044d4804dSStefan Eßer  * @param nums  True if the array should be for numbers, false if it should be
60144d4804dSStefan Eßer  *              for vectors.
60244d4804dSStefan Eßer  */
60378bc019dSStefan Eßer void
60478bc019dSStefan Eßer bc_array_init(BcVec* a, bool nums);
60544d4804dSStefan Eßer 
60644d4804dSStefan Eßer /**
60744d4804dSStefan Eßer  * Copies an array to another array. This is used to do pass arrays to functions
60844d4804dSStefan Eßer  * that do not take references to arrays. The arrays are passed entirely by
60944d4804dSStefan Eßer  * value, which means that they need to be copied.
61044d4804dSStefan Eßer  * @param d  The destination array.
61144d4804dSStefan Eßer  * @param s  The source array.
61244d4804dSStefan Eßer  */
61378bc019dSStefan Eßer void
61478bc019dSStefan Eßer bc_array_copy(BcVec* d, const BcVec* s);
615252884aeSStefan Eßer 
61644d4804dSStefan Eßer /**
61744d4804dSStefan Eßer  * Frees a string stored in a function. This is a destructor.
61844d4804dSStefan Eßer  * @param string  The string to free as a void pointer.
61944d4804dSStefan Eßer  */
62078bc019dSStefan Eßer void
62178bc019dSStefan Eßer bc_string_free(void* string);
62244d4804dSStefan Eßer 
62344d4804dSStefan Eßer /**
62444d4804dSStefan Eßer  * Frees a constant stored in a function. This is a destructor.
62544d4804dSStefan Eßer  * @param constant  The constant to free as a void pointer.
62644d4804dSStefan Eßer  */
62778bc019dSStefan Eßer void
62878bc019dSStefan Eßer bc_const_free(void* constant);
62944d4804dSStefan Eßer 
63044d4804dSStefan Eßer /**
63144d4804dSStefan Eßer  * Clears a result. It sets the type to BC_RESULT_TEMP and clears the union by
63244d4804dSStefan Eßer  * clearing the BcNum in the union. This is to ensure that bc does not use
63344d4804dSStefan Eßer  * uninitialized data.
63444d4804dSStefan Eßer  * @param r  The result to clear.
63544d4804dSStefan Eßer  */
63678bc019dSStefan Eßer void
63778bc019dSStefan Eßer bc_result_clear(BcResult* r);
63844d4804dSStefan Eßer 
63944d4804dSStefan Eßer /**
64044d4804dSStefan Eßer  * Copies a result into another. This is done for things like duplicating the
64144d4804dSStefan Eßer  * top of the results stack or copying the result of an assignment to put back
64244d4804dSStefan Eßer  * on the results stack.
64344d4804dSStefan Eßer  * @param d    The destination result.
64444d4804dSStefan Eßer  * @param src  The source result.
64544d4804dSStefan Eßer  */
64678bc019dSStefan Eßer void
64778bc019dSStefan Eßer bc_result_copy(BcResult* d, BcResult* src);
64844d4804dSStefan Eßer 
64944d4804dSStefan Eßer /**
65044d4804dSStefan Eßer  * Frees a result. This is a destructor.
65144d4804dSStefan Eßer  * @param result  The result to free as a void pointer.
65244d4804dSStefan Eßer  */
65378bc019dSStefan Eßer void
65478bc019dSStefan Eßer bc_result_free(void* result);
655252884aeSStefan Eßer 
65644d4804dSStefan Eßer /**
65744d4804dSStefan Eßer  * Expands an array to @a len. This can happen because in bc, you do not have to
65844d4804dSStefan Eßer  * explicitly initialize elements of an array. If you access an element that is
65944d4804dSStefan Eßer  * not initialized, the array is expanded to fit it, and all missing elements
66044d4804dSStefan Eßer  * are initialized to 0 if they are numbers, or arrays with one element of 0.
66144d4804dSStefan Eßer  * This function does that expansion.
66244d4804dSStefan Eßer  * @param a    The array to expand.
66344d4804dSStefan Eßer  * @param len  The length to expand to.
66444d4804dSStefan Eßer  */
66578bc019dSStefan Eßer void
66678bc019dSStefan Eßer bc_array_expand(BcVec* a, size_t len);
66744d4804dSStefan Eßer 
66844d4804dSStefan Eßer #if BC_ENABLED
66944d4804dSStefan Eßer 
67044d4804dSStefan Eßer /**
67144d4804dSStefan Eßer  * Returns non-zero if the bytecode instruction i is an assignment instruction.
67244d4804dSStefan Eßer  * @param i  The instruction to test.
67344d4804dSStefan Eßer  * @return   Non-zero if i is an assignment instruction, zero otherwise.
67444d4804dSStefan Eßer  */
67544d4804dSStefan Eßer #define BC_INST_IS_ASSIGN(i) \
67644d4804dSStefan Eßer 	((i) == BC_INST_ASSIGN || (i) == BC_INST_ASSIGN_NO_VAL)
67744d4804dSStefan Eßer 
67844d4804dSStefan Eßer /**
67944d4804dSStefan Eßer  * Returns true if the bytecode instruction @a i requires the value to be
68044d4804dSStefan Eßer  * returned for use.
68144d4804dSStefan Eßer  * @param i  The instruction to test.
68244d4804dSStefan Eßer  * @return   True if @a i requires the value to be returned for use, false
68344d4804dSStefan Eßer  *           otherwise.
68444d4804dSStefan Eßer  */
68544d4804dSStefan Eßer #define BC_INST_USE_VAL(i) ((i) <= BC_INST_ASSIGN)
68644d4804dSStefan Eßer 
68744d4804dSStefan Eßer #else // BC_ENABLED
68844d4804dSStefan Eßer 
68944d4804dSStefan Eßer /**
69044d4804dSStefan Eßer  * Returns non-zero if the bytecode instruction i is an assignment instruction.
69144d4804dSStefan Eßer  * @param i  The instruction to test.
69244d4804dSStefan Eßer  * @return   Non-zero if i is an assignment instruction, zero otherwise.
69344d4804dSStefan Eßer  */
69444d4804dSStefan Eßer #define BC_INST_IS_ASSIGN(i) ((i) == BC_INST_ASSIGN_NO_VAL)
69544d4804dSStefan Eßer 
69644d4804dSStefan Eßer /**
69744d4804dSStefan Eßer  * Returns true if the bytecode instruction @a i requires the value to be
69844d4804dSStefan Eßer  * returned for use.
69944d4804dSStefan Eßer  * @param i  The instruction to test.
70044d4804dSStefan Eßer  * @return   True if @a i requires the value to be returned for use, false
70144d4804dSStefan Eßer  *           otherwise.
70244d4804dSStefan Eßer  */
70344d4804dSStefan Eßer #define BC_INST_USE_VAL(i) (false)
70444d4804dSStefan Eßer 
70544d4804dSStefan Eßer #endif // BC_ENABLED
70644d4804dSStefan Eßer 
707252884aeSStefan Eßer #if BC_DEBUG_CODE
70844d4804dSStefan Eßer /// Reference to string names for all of the instructions. For debugging.
709252884aeSStefan Eßer extern const char* bc_inst_names[];
710252884aeSStefan Eßer #endif // BC_DEBUG_CODE
711252884aeSStefan Eßer 
71244d4804dSStefan Eßer /// References to the names of the main and read functions.
713252884aeSStefan Eßer extern const char bc_func_main[];
714252884aeSStefan Eßer extern const char bc_func_read[];
715252884aeSStefan Eßer 
716252884aeSStefan Eßer #endif // BC_LANG_H
717