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