An implementation of Unix dc and POSIX bc with GNU and BSD extensions. Finished, but well-maintained.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1043 lines
39 KiB

/*
* *****************************************************************************
*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018-2021 Gavin D. Howard and contributors.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* *****************************************************************************
*
* Definitions for bc programs.
*
*/
#ifndef BC_PROGRAM_H
#define BC_PROGRAM_H
#include <assert.h>
#include <stddef.h>
#include <status.h>
#include <parse.h>
#include <lang.h>
#include <num.h>
#include <rand.h>
/// The index of ibase in the globals array.
#define BC_PROG_GLOBALS_IBASE (0)
/// The index of obase in the globals array.
#define BC_PROG_GLOBALS_OBASE (1)
/// The index of scale in the globals array.
#define BC_PROG_GLOBALS_SCALE (2)
2 years ago
#if BC_ENABLE_EXTRA_MATH
/// The index of the rand max in the maxes array.
#define BC_PROG_MAX_RAND (3)
#endif // BC_ENABLE_EXTRA_MATH
2 years ago
/// The length of the globals array.
#define BC_PROG_GLOBALS_LEN (3 + BC_ENABLE_EXTRA_MATH)
typedef struct BcProgram
{
/// The array of globals values.
BcBigDig globals[BC_PROG_GLOBALS_LEN];
#if BC_ENABLED
/// The array of globals stacks.
BcVec globals_v[BC_PROG_GLOBALS_LEN];
#endif // BC_ENABLED
#if BC_ENABLE_EXTRA_MATH
/// The pseudo-random number generator.
BcRNG rng;
#endif // BC_ENABLE_EXTRA_MATH
/// The results stack.
BcVec results;
/// The execution stack.
BcVec stack;
/// A pointer to the current function's constants.
BcVec* consts;
/// A pointer to the current function's strings.
BcVec* strs;
/// The array of functions.
BcVec fns;
/// The map of functions to go with fns.
BcVec fn_map;
/// The array of variables.
BcVec vars;
/// The map of variables to go with vars.
BcVec var_map;
/// The array of arrays.
BcVec arrs;
/// The map of arrays to go with arrs.
BcVec arr_map;
#if DC_ENABLED
/// A vector of tail calls. These are just integers, which are the number of
/// tail calls that have been executed for each function (string) on the
/// stack for dc. This is to prevent dc from constantly growing memory use
/// because of pushing more and more string executions on the stack.
BcVec tail_calls;
#endif // DC_ENABLED
/// A BcNum that has the proper base for asciify.
BcNum strmb;
// A BcNum to run asciify. This is to prevent GCC longjmp() clobbering
// warnings.
BcNum asciify;
#if BC_ENABLED
/// The last printed value for bc.
BcNum last;
#endif // BC_ENABLED
// The BcDig array for strmb. This uses BC_NUM_LONG_LOG10 because it is used
// in bc_num_ulong2num(), which attempts to realloc, unless it is big
// enough. This is big enough.
BcDig strmb_num[BC_NUM_BIGDIG_LOG10];
} BcProgram;
/**
* Returns true if the stack @a s has at least @a n items, false otherwise.
* @param s The stack to check.
* @param n The number of items the stack must have.
* @return True if @a s has at least @a n items, false otherwise.
*/
4 years ago
#define BC_PROG_STACK(s, n) ((s)->len >= ((size_t) (n)))
/**
* Get a pointer to the top value in a global value stack.
* @param v The global value stack.
* @return A pointer to the top value in @a v.
*/
#define BC_PROG_GLOBAL_PTR(v) (bc_vec_top(v))
/**
* Get the top value in a global value stack.
* @param v The global value stack.
* @return The top value in @a v.
*/
#define BC_PROG_GLOBAL(v) (*((BcBigDig*) BC_PROG_GLOBAL_PTR(v)))
/**
* Returns the current value of ibase.
* @param p The program.
* @return The current ibase.
*/
#define BC_PROG_IBASE(p) ((p)->globals[BC_PROG_GLOBALS_IBASE])
/**
* Returns the current value of obase.
* @param p The program.
* @return The current obase.
*/
#define BC_PROG_OBASE(p) ((p)->globals[BC_PROG_GLOBALS_OBASE])
/**
* Returns the current value of scale.
* @param p The program.
* @return The current scale.
*/
#define BC_PROG_SCALE(p) ((p)->globals[BC_PROG_GLOBALS_SCALE])
/// The index for the main function in the functions array.//
#define BC_PROG_MAIN (0)
/// The index for the read function in the functions array.
#define BC_PROG_READ (1)
/**
* Retires (completes the execution of) an instruction. Some instructions
* require special retirement, but most can use this. This basically pops the
* operands while preserving the result (which we assumed was pushed before the
* actual operation).
* @param p The program.
* @param nres The number of results returned by the instruction.
* @param nops The number of operands used by the instruction.
*/
#define bc_program_retire(p, nres, nops) \
(bc_vec_npopAt(&(p)->results, (nops), (p)->results.len - (nres + nops)))
#if DC_ENABLED
/// A constant that tells how many functions are required in dc.
#define BC_PROG_REQ_FUNCS (2)
#if !BC_ENABLED
/// This define disappears the parameter last because for dc only, last is
/// always true.
#define bc_program_copyToVar(p, name, t, last) \
bc_program_copyToVar_impl(p, name, t)
/// Returns true if the calculator should pop after printing.
#define BC_PROGRAM_POP(pop) (pop)
#else // !BC_ENABLED
// This is here to quiet a compiler warning.
#define bc_program_copyToVar(p, name, t, last) \
bc_program_copyToVar_impl(p, name, t, last)
/// Returns true if the calculator should pop after printing.
#define BC_PROGRAM_POP(pop) (BC_IS_BC || (pop))
#endif // !BC_ENABLED
// This is here to satisfy a clang warning about recursive macros.
#define bc_program_pushVar(p, code, bgn, pop, copy) \
bc_program_pushVar_impl(p, code, bgn, pop, copy)
#else // DC_ENABLED
// This define disappears pop and copy because for bc, 'pop' and 'copy' are
// always false.
#define bc_program_pushVar(p, code, bgn, pop, copy) \
bc_program_pushVar_impl(p, code, bgn)
/// Returns true if the calculator should pop after printing.
#define BC_PROGRAM_POP(pop) (BC_IS_BC)
// In debug mode, we want bc to check the stack, but otherwise, we don't because
// the bc language implicitly mandates that the stack should always have enough
// items.
#ifdef NDEBUG
#define BC_PROG_NO_STACK_CHECK
#endif // NDEBUG
#endif // DC_ENABLED
/**
* Returns true if the BcNum @a n is acting as a string.
* @param n The BcNum to test.
* @return True if @a n is acting as a string, false otherwise.
*/
#define BC_PROG_STR(n) ((n)->num == NULL && !(n)->cap)
#if BC_ENABLED
/**
* Returns true if the result @a r and @a n is a number.
* @param r The result.
* @param n The number corresponding to the result.
* @return True if the result holds a number, false otherwise.
*/
#define BC_PROG_NUM(r, n) \
((r)->t != BC_RESULT_ARRAY && (r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
#else // BC_ENABLED
/**
* Returns true if the result @a r and @a n is a number.
* @param r The result.
* @param n The number corresponding to the result.
* @return True if the result holds a number, false otherwise.
*/
#define BC_PROG_NUM(r, n) ((r)->t != BC_RESULT_STR && !BC_PROG_STR(n))
#endif // BC_ENABLED
/**
* This is a function type for unary operations. Currently, these include
* boolean not, negation, and truncation with extra math.
* @param r The BcResult to store the result into.
* @param n The parameter to the unary operation.
*/
typedef void (*BcProgramUnary)(BcResult* r, BcNum* n);
/**
* Initializes the BcProgram.
* @param p The program to initialize.
*/
void
bc_program_init(BcProgram* p);
#ifndef NDEBUG
/**
* Frees a BcProgram. This is only used in debug builds because a BcProgram is
* only freed on program exit, and we don't care about freeing resources on
* exit.
* @param p The program to initialize.
*/
void
bc_program_free(BcProgram* p);
#endif // NDEBUG
#if BC_DEBUG_CODE
#if BC_ENABLED && DC_ENABLED
/**
* Prints the bytecode in a function. This is a debug-only function.
* @param p The program.
*/
void
bc_program_code(const BcProgram* p);
/**
* Prints an instruction. This is a debug-only function.
* @param p The program.
* @param code The bytecode array.
* @param bgn A pointer to the current index. It is also updated to the next
* index.
*/
void
bc_program_printInst(const BcProgram* p, const char* code,
size_t* restrict bgn);
/**
* Prints the stack. This is a debug-only function.
* @param p The program.
*/
void
bc_program_printStackDebug(BcProgram* p);
4 years ago
#endif // BC_ENABLED && DC_ENABLED
#endif // BC_DEBUG_CODE
/**
* Returns the index of the variable or array in their respective arrays.
* @param p The program.
* @param id The BcId of the variable or array.
* @param var True if the search should be for a variable, false for an array.
* @return The index of the variable or array in the correct array.
*/
size_t
bc_program_search(BcProgram* p, const char* id, bool var);
/**
* Adds a string to a function and returns the string's index in the function.
* @param p The program.
* @param str The string to add.
* @param fidx The index of the function to add to.
*/
size_t
bc_program_addString(BcProgram* p, const char* str, size_t fidx);
/**
* Inserts a function into the program and returns the index of the function in
* the fns array.
* @param p The program.
* @param name The name of the function.
* @return The index of the function after insertion.
*/
size_t
bc_program_insertFunc(BcProgram* p, const char* name);
/**
* Resets a program, usually because of resetting after an error.
* @param p The program to reset.
*/
void
bc_program_reset(BcProgram* p);
/**
* Executes bc or dc code in the BcProgram.
* @param p The program.
*/
void
bc_program_exec(BcProgram* p);
/**
* Negates a copy of a BcNum. This is a BcProgramUnary function.
* @param r The BcResult to store the result into.
* @param n The parameter to the unary operation.
*/
void
bc_program_negate(BcResult* r, BcNum* n);
/**
* Returns a boolean not of a BcNum. This is a BcProgramUnary function.
* @param r The BcResult to store the result into.
* @param n The parameter to the unary operation.
*/
void
bc_program_not(BcResult* r, BcNum* n);
#if BC_ENABLE_EXTRA_MATH
/**
* Truncates a copy of a BcNum. This is a BcProgramUnary function.
* @param r The BcResult to store the result into.
* @param n The parameter to the unary operation.
*/
void
bc_program_trunc(BcResult* r, BcNum* n);
/**
* Assigns a value to the seed builtin variable.
* @param p The program.
* @param val The value to assign to the seed.
*/
void
bc_program_assignSeed(BcProgram* p, BcNum* val);
#endif // BC_ENABLE_EXTRA_MATH
/**
* Assigns a value to a builtin value that is not seed.
* @param p The program.
* @param scale True if the builtin is scale.
* @param obase True if the builtin is obase. This cannot be true at the same
* time @a scale is.
* @param val The value to assign to the builtin.
*/
void
bc_program_assignBuiltin(BcProgram* p, bool scale, bool obase, BcBigDig val);
/// A reference to an array of binary operator functions.
extern const BcNumBinaryOp bc_program_ops[];
/// A reference to an array of binary operator allocation request functions.
extern const BcNumBinaryOpReq bc_program_opReqs[];
/// A reference to an array of unary operator functions.
extern const BcProgramUnary bc_program_unarys[];
/// A reference to a filename for command-line expressions.
extern const char bc_program_exprs_name[];
/// A reference to a filename for stdin.
extern const char bc_program_stdin_name[];
/// A reference to the ready message printed on SIGINT.
extern const char bc_program_ready_msg[];
/// A reference to the length of the ready message.
extern const size_t bc_program_ready_msg_len;
/// A reference to an array of escape characters for the print statement.
extern const char bc_program_esc_chars[];
/// A reference to an array of the characters corresponding to the escape
/// characters in bc_program_esc_chars.
extern const char bc_program_esc_seqs[];
#if BC_HAS_COMPUTED_GOTO
#if BC_DEBUG_CODE
// clang-format off
#define BC_PROG_JUMP(inst, code, ip) \
do \
{ \
inst = (uchar) (code)[(ip)->idx++]; \
bc_file_printf(&vm->ferr, "inst: %s\n", bc_inst_names[inst]); \
bc_file_flush(&vm->ferr, bc_flush_none); \
goto *bc_program_inst_lbls[inst]; \
} \
while (0)
// clang-format on
#else // BC_DEBUG_CODE
// clang-format off
#define BC_PROG_JUMP(inst, code, ip) \
do \
{ \
inst = (uchar) (code)[(ip)->idx++]; \
goto *bc_program_inst_lbls[inst]; \
} \
while (0)
// clang-format on
#endif // BC_DEBUG_CODE
#define BC_PROG_DIRECT_JUMP(l) goto lbl_##l;
#define BC_PROG_LBL(l) lbl_##l
#define BC_PROG_FALLTHROUGH
#if BC_C11
#define BC_PROG_LBLS_SIZE (sizeof(bc_program_inst_lbls) / sizeof(void*))
#define BC_PROG_LBLS_ASSERT \
_Static_assert(BC_PROG_LBLS_SIZE == BC_INST_INVALID + 1, \
"bc_program_inst_lbls[] mismatches the instructions")
#else // BC_C11
#define BC_PROG_LBLS_ASSERT
#endif // BC_C11
#if BC_ENABLED
#if DC_ENABLED
#if BC_ENABLE_EXTRA_MATH
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_INC, \
&&lbl_BC_INST_DEC, \
&&lbl_BC_INST_NEG, \
&&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_TRUNC, \
&&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_PLACES, \
&&lbl_BC_INST_LSHIFT, \
&&lbl_BC_INST_RSHIFT, \
&&lbl_BC_INST_REL_EQ, \
&&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, \
&&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, \
&&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, \
&&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_POWER, \
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
&&lbl_BC_INST_ASSIGN_DIVIDE, \
&&lbl_BC_INST_ASSIGN_MODULUS, \
&&lbl_BC_INST_ASSIGN_PLUS, \
&&lbl_BC_INST_ASSIGN_MINUS, \
&&lbl_BC_INST_ASSIGN_PLACES, \
&&lbl_BC_INST_ASSIGN_LSHIFT, \
&&lbl_BC_INST_ASSIGN_RSHIFT, \
&&lbl_BC_INST_ASSIGN, \
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_PLACES_NO_VAL, \
&&lbl_BC_INST_ASSIGN_LSHIFT_NO_VAL, \
&&lbl_BC_INST_ASSIGN_RSHIFT_NO_VAL, \
&&lbl_BC_INST_ASSIGN_NO_VAL, \
&&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, \
&&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, \
&&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, \
&&lbl_BC_INST_LAST, \
&&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, \
&&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_SEED, \
&&lbl_BC_INST_LENGTH, \
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_IRAND, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_RAND, \
&&lbl_BC_INST_MAXIBASE, \
&&lbl_BC_INST_MAXOBASE, \
&&lbl_BC_INST_MAXSCALE, \
&&lbl_BC_INST_MAXRAND, \
&&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_GLOBAL_STACKS, \
&&lbl_BC_INST_LEADING_ZERO, \
&&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, \
&&lbl_BC_INST_STR, \
&&lbl_BC_INST_PRINT_STR, \
&&lbl_BC_INST_JUMP, \
&&lbl_BC_INST_JUMP_ZERO, \
&&lbl_BC_INST_CALL, \
&&lbl_BC_INST_RET, \
&&lbl_BC_INST_RET0, \
&&lbl_BC_INST_RET_VOID, \
&&lbl_BC_INST_HALT, \
&&lbl_BC_INST_POP, \
&&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, \
&&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, \
&&lbl_BC_INST_POP_EXEC, \
&&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, \
&&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, \
&&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, \
&&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, \
&&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, \
&&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, \
&&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
}
#else // BC_ENABLE_EXTRA_MATH
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_INC, \
&&lbl_BC_INST_DEC, \
&&lbl_BC_INST_NEG, \
&&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_REL_EQ, \
&&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, \
&&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, \
&&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, \
&&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_POWER, \
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
&&lbl_BC_INST_ASSIGN_DIVIDE, \
&&lbl_BC_INST_ASSIGN_MODULUS, \
&&lbl_BC_INST_ASSIGN_PLUS, \
&&lbl_BC_INST_ASSIGN_MINUS, \
&&lbl_BC_INST_ASSIGN, \
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_NO_VAL, \
&&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, \
&&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, \
&&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, \
&&lbl_BC_INST_LAST, \
&&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, \
&&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_LENGTH, \
&&lbl_BC_INST_SCALE_FUNC, \
&&lbl_BC_INST_SQRT, \
&&lbl_BC_INST_ABS, \
&&lbl_BC_INST_ASCIIFY, \
&&lbl_BC_INST_READ, \
&&lbl_BC_INST_MAXIBASE, \
&&lbl_BC_INST_MAXOBASE, \
&&lbl_BC_INST_MAXSCALE, \
&&lbl_BC_INST_LINE_LENGTH, \
&&lbl_BC_INST_GLOBAL_STACKS, \
&&lbl_BC_INST_LEADING_ZERO, \
&&lbl_BC_INST_PRINT, \
&&lbl_BC_INST_PRINT_POP, \
&&lbl_BC_INST_STR, \
&&lbl_BC_INST_PRINT_STR, \
&&lbl_BC_INST_JUMP, \
&&lbl_BC_INST_JUMP_ZERO, \
&&lbl_BC_INST_CALL, \
&&lbl_BC_INST_RET, \
&&lbl_BC_INST_RET0, \
&&lbl_BC_INST_RET_VOID, \
&&lbl_BC_INST_HALT, \
&&lbl_BC_INST_POP, \
&&lbl_BC_INST_SWAP, \
&&lbl_BC_INST_MODEXP, \
&&lbl_BC_INST_DIVMOD, \
&&lbl_BC_INST_PRINT_STREAM, \
&&lbl_BC_INST_POP_EXEC, \
&&lbl_BC_INST_EXECUTE, \
&&lbl_BC_INST_EXEC_COND, \
&&lbl_BC_INST_PRINT_STACK, \
&&lbl_BC_INST_CLEAR_STACK, \
&&lbl_BC_INST_REG_STACK_LEN, \
&&lbl_BC_INST_STACK_LEN, \
&&lbl_BC_INST_DUPLICATE, \
&&lbl_BC_INST_LOAD, \
&&lbl_BC_INST_PUSH_VAR, \
&&lbl_BC_INST_PUSH_TO_VAR, \
&&lbl_BC_INST_QUIT, \
&&lbl_BC_INST_NQUIT, \
&&lbl_BC_INST_EXEC_STACK_LEN, \
&&lbl_BC_INST_INVALID, \
}
#endif // BC_ENABLE_EXTRA_MATH
#else // DC_ENABLED
#if BC_ENABLE_EXTRA_MATH
#define BC_PROG_LBLS \
static const void* const bc_program_inst_lbls[] = { \
&&lbl_BC_INST_INC, \
&&lbl_BC_INST_DEC, \
&&lbl_BC_INST_NEG, \
&&lbl_BC_INST_BOOL_NOT, \
&&lbl_BC_INST_TRUNC, \
&&lbl_BC_INST_POWER, \
&&lbl_BC_INST_MULTIPLY, \
&&lbl_BC_INST_DIVIDE, \
&&lbl_BC_INST_MODULUS, \
&&lbl_BC_INST_PLUS, \
&&lbl_BC_INST_MINUS, \
&&lbl_BC_INST_PLACES, \
&&lbl_BC_INST_LSHIFT, \
&&lbl_BC_INST_RSHIFT, \
&&lbl_BC_INST_REL_EQ, \
&&lbl_BC_INST_REL_LE, \
&&lbl_BC_INST_REL_GE, \
&&lbl_BC_INST_REL_NE, \
&&lbl_BC_INST_REL_LT, \
&&lbl_BC_INST_REL_GT, \
&&lbl_BC_INST_BOOL_OR, \
&&lbl_BC_INST_BOOL_AND, \
&&lbl_BC_INST_ASSIGN_POWER, \
&&lbl_BC_INST_ASSIGN_MULTIPLY, \
&&lbl_BC_INST_ASSIGN_DIVIDE, \
&&lbl_BC_INST_ASSIGN_MODULUS, \
&&lbl_BC_INST_ASSIGN_PLUS, \
&&lbl_BC_INST_ASSIGN_MINUS, \
&&lbl_BC_INST_ASSIGN_PLACES, \
&&lbl_BC_INST_ASSIGN_LSHIFT, \
&&lbl_BC_INST_ASSIGN_RSHIFT, \
&&lbl_BC_INST_ASSIGN, \
&&lbl_BC_INST_ASSIGN_POWER_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MULTIPLY_NO_VAL, \
&&lbl_BC_INST_ASSIGN_DIVIDE_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MODULUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_PLUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_MINUS_NO_VAL, \
&&lbl_BC_INST_ASSIGN_PLACES_NO_VAL, \
&&lbl_BC_INST_ASSIGN_LSHIFT_NO_VAL, \
&&lbl_BC_INST_ASSIGN_RSHIFT_NO_VAL, \
&&lbl_BC_INST_ASSIGN_NO_VAL, \
&&lbl_BC_INST_NUM, \
&&lbl_BC_INST_VAR, \
&&lbl_BC_INST_ARRAY_ELEM, \
&&lbl_BC_INST_ARRAY, \
&&lbl_BC_INST_ZERO, \
&&lbl_BC_INST_ONE, \
&&lbl_BC_INST_LAST, \
&&lbl_BC_INST_IBASE, \
&&lbl_BC_INST_OBASE, \
&&lbl_BC_INST_SCALE, \
&&lbl_BC_INST_SEED, \
&&lbl_BC_INST_LENGTH, \