diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/args.h | 31 | ||||
| -rw-r--r-- | include/bcl.h | 55 | ||||
| -rw-r--r-- | include/file.h | 18 | ||||
| -rw-r--r-- | include/history.h | 28 | ||||
| -rw-r--r-- | include/lang.h | 12 | ||||
| -rw-r--r-- | include/lex.h | 7 | ||||
| -rw-r--r-- | include/library.h | 136 | ||||
| -rw-r--r-- | include/num.h | 12 | ||||
| -rw-r--r-- | include/program.h | 50 | ||||
| -rw-r--r-- | include/status.h | 417 | ||||
| -rw-r--r-- | include/vector.h | 30 | ||||
| -rw-r--r-- | include/version.h | 2 | ||||
| -rw-r--r-- | include/vm.h | 237 |
13 files changed, 667 insertions, 368 deletions
diff --git a/include/args.h b/include/args.h index cf6bcbef621c..515e53b1e891 100644 --- a/include/args.h +++ b/include/args.h @@ -46,10 +46,37 @@ * @param argv The array of arguments. * @param exit_exprs True if bc/dc should exit when there are expressions, * false otherwise. - * @param scale The current scale. + * @param scale A pointer to return the scale that the arguments set, if + * any. + * @param ibase A pointer to return the ibase that the arguments set, if + * any. + * @param obase A pointer to return the obase that the arguments set, if + * any. */ void -bc_args(int argc, char* argv[], bool exit_exprs, BcBigDig scale); +bc_args(int argc, char* argv[], bool exit_exprs, BcBigDig* scale, + BcBigDig* ibase, BcBigDig* obase); + +#if BC_ENABLED + +#if DC_ENABLED + +/// Returns true if the banner should be quieted. +#define BC_ARGS_SHOULD_BE_QUIET (BC_IS_DC || vm->exprs.len > 1) + +#else // DC_ENABLED + +/// Returns true if the banner should be quieted. +#define BC_ARGS_SHOULD_BE_QUIET (vm->exprs.len > 1) + +#endif // DC_ENABLED + +#else // BC_ENABLED + +/// Returns true if the banner should be quieted. +#define BC_ARGS_SHOULD_BE_QUIET (BC_IS_DC) + +#endif // BC_ENABLED // A reference to the list of long options. extern const BcOptLong bc_args_lopt[]; diff --git a/include/bcl.h b/include/bcl.h index 54be3239d241..0a6f43700797 100644 --- a/include/bcl.h +++ b/include/bcl.h @@ -36,6 +36,11 @@ #ifndef BC_BCL_H #define BC_BCL_H +#include <stdbool.h> +#include <stdlib.h> +#include <limits.h> +#include <stdint.h> + #ifdef _WIN32 #include <Windows.h> #include <BaseTsd.h> @@ -43,44 +48,8 @@ #include <io.h> #endif // _WIN32 -#include <stdbool.h> -#include <stdlib.h> -#include <limits.h> -#include <stdint.h> -#include <sys/types.h> - -// Windows has deprecated isatty() and the rest of these. Or doesn't have them. -// So these are just fixes for Windows. #ifdef _WIN32 - -// This one is special. Windows did not like me defining an -// inline function that was not given a definition in a header -// file. This suppresses that by making inline functions non-inline. -#define inline - -#define restrict __restrict -#define strdup _strdup -#define write(f, b, s) _write((f), (b), (unsigned int) (s)) -#define read(f, b, s) _read((f), (b), (unsigned int) (s)) -#define close _close -#define open(f, n, m) \ - _sopen_s((f), (n), (m) | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) -#define sigjmp_buf jmp_buf -#define sigsetjmp(j, s) setjmp(j) -#define siglongjmp longjmp -#define isatty _isatty -#define STDIN_FILENO _fileno(stdin) -#define STDOUT_FILENO _fileno(stdout) -#define STDERR_FILENO _fileno(stderr) #define ssize_t SSIZE_T -#define S_ISDIR(m) ((m) & (_S_IFDIR)) -#define O_RDONLY _O_RDONLY -#define stat _stat -#define fstat _fstat -#define BC_FILE_SEP '\\' - -#else // _WIN32 -#define BC_FILE_SEP '/' #endif // _WIN32 #define BCL_SEED_ULONGS (4) @@ -161,11 +130,11 @@ struct BclCtxt; typedef struct BclCtxt* BclContext; -void -bcl_handleSignal(void); +BclError +bcl_start(void); -bool -bcl_running(void); +void +bcl_end(void); BclError bcl_init(void); @@ -185,6 +154,12 @@ bcl_leadingZeroes(void); void bcl_setLeadingZeroes(bool leadingZeroes); +bool +bcl_digitClamp(void); + +void +bcl_setDigitClamp(bool digitClamp); + void bcl_gc(void); diff --git a/include/file.h b/include/file.h index 30a0d9011c00..d6b7c4e56f85 100644 --- a/include/file.h +++ b/include/file.h @@ -98,16 +98,24 @@ typedef enum BcFlushType } BcFlushType; +// These are here to satisfy a clang warning about recursive macros. + +#define bc_file_putchar(f, t, c) bc_file_putchar_impl(f, t, c) +#define bc_file_flushErr(f, t) bc_file_flushErr_impl(f, t) +#define bc_file_flush(f, t) bc_file_flush_impl(f, t) +#define bc_file_write(f, t, b, n) bc_file_write_impl(f, t, b, n) +#define bc_file_puts(f, t, s) bc_file_puts_impl(f, t, s) + #else // BC_ENABLE_HISTORY && !BC_ENABLE_LINE_LIB // These make sure that the BcFlushType parameter disappears if history is not // used, editline is used, or readline is used. -#define bc_file_putchar(f, t, c) bc_file_putchar(f, c) -#define bc_file_flushErr(f, t) bc_file_flushErr(f) -#define bc_file_flush(f, t) bc_file_flush(f) -#define bc_file_write(f, t, b, n) bc_file_write(f, b, n) -#define bc_file_puts(f, t, s) bc_file_puts(f, s) +#define bc_file_putchar(f, t, c) bc_file_putchar_impl(f, c) +#define bc_file_flushErr(f, t) bc_file_flushErr_impl(f) +#define bc_file_flush(f, t) bc_file_flush_impl(f) +#define bc_file_write(f, t, b, n) bc_file_write_impl(f, b, n) +#define bc_file_puts(f, t, s) bc_file_puts_impl(f, s) #endif // BC_ENABLE_HISTORY && !BC_ENABLE_LINE_LIB diff --git a/include/history.h b/include/history.h index 1e9962ded1eb..495b315cc311 100644 --- a/include/history.h +++ b/include/history.h @@ -79,27 +79,10 @@ #ifndef BC_HISTORY_H #define BC_HISTORY_H -#ifndef BC_ENABLE_HISTORY -#define BC_ENABLE_HISTORY (1) -#endif // BC_ENABLE_HISTORY - -#ifndef BC_ENABLE_EDITLINE -#define BC_ENABLE_EDITLINE (0) -#endif // BC_ENABLE_EDITLINE - -#ifndef BC_ENABLE_READLINE -#define BC_ENABLE_READLINE (0) -#endif // BC_ENABLE_READLINE - -#if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE -#error Must enable only one of editline or readline, not both. -#endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE - -#if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE -#define BC_ENABLE_LINE_LIB (1) -#else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE -#define BC_ENABLE_LINE_LIB (0) -#endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE +// These must come before the #if BC_ENABLE_LINE_LIB below because status.h +// defines it. +#include <status.h> +#include <vector.h> #if BC_ENABLE_LINE_LIB @@ -107,9 +90,6 @@ #include <setjmp.h> #include <signal.h> -#include <status.h> -#include <vector.h> - extern sigjmp_buf bc_history_jmpbuf; extern volatile sig_atomic_t bc_history_inlinelib; diff --git a/include/lang.h b/include/lang.h index 6b8ebabf6a95..f7356c412396 100644 --- a/include/lang.h +++ b/include/lang.h @@ -38,19 +38,19 @@ #include <stdbool.h> -#if BC_C11 -#include <assert.h> -#endif // BC_C11 - +// These have to come first to silence a warning on BC_C11 below. #include <status.h> #include <vector.h> #include <num.h> +#if BC_C11 +#include <assert.h> +#endif // BC_C11 + /// The instructions for bytecode. typedef enum BcInst { #if BC_ENABLED - /// Postfix increment and decrement. Prefix are translated into /// BC_INST_ONE with either BC_INST_ASSIGN_PLUS or BC_INST_ASSIGN_MINUS. BC_INST_INC = 0, @@ -62,6 +62,7 @@ typedef enum BcInst /// Boolean not. BC_INST_BOOL_NOT, + #if BC_ENABLE_EXTRA_MATH /// Truncation operator. BC_INST_TRUNC, @@ -76,7 +77,6 @@ typedef enum BcInst BC_INST_MINUS, #if BC_ENABLE_EXTRA_MATH - /// Places operator. BC_INST_PLACES, diff --git a/include/lex.h b/include/lex.h index 20be6efa9cde..4f08b45d623f 100644 --- a/include/lex.h +++ b/include/lex.h @@ -136,6 +136,7 @@ typedef enum BcLexType BC_LEX_OP_MINUS, #if BC_ENABLE_EXTRA_MATH + /// Places (truncate or extend) operator. BC_LEX_OP_PLACES, @@ -144,6 +145,7 @@ typedef enum BcLexType /// Right (decimal) shift operator. BC_LEX_OP_RSHIFT, + #endif // BC_ENABLE_EXTRA_MATH /// Equal operator. @@ -171,6 +173,7 @@ typedef enum BcLexType BC_LEX_OP_BOOL_AND, #if BC_ENABLED + /// Power assignment operator. BC_LEX_OP_ASSIGN_POWER, @@ -353,8 +356,10 @@ typedef enum BcLexType BC_LEX_KW_MAXSCALE, #if BC_ENABLE_EXTRA_MATH + /// bc maxrand keyword. BC_LEX_KW_MAXRAND, + #endif // BC_ENABLE_EXTRA_MATH /// bc line_length keyword. @@ -418,8 +423,10 @@ typedef enum BcLexType BC_LEX_STORE_SCALE, #if BC_ENABLE_EXTRA_MATH + /// Store seed command. BC_LEX_STORE_SEED, + #endif // BC_ENABLE_EXTRA_MATH /// Load variable onto stack command. diff --git a/include/library.h b/include/library.h index 63d24ee5f7a9..94c62923062a 100644 --- a/include/library.h +++ b/include/library.h @@ -39,91 +39,42 @@ #include <bcl.h> #include <num.h> +#include <vm.h> /** - * A header for functions that need to lock and setjmp(). It also sets the - * variable that tells bcl that it is running. - * @param l The label to jump to on error. + * A header that sets a jump. + * @param vm The thread data. + * @param l The label to jump to on error. */ -#define BC_FUNC_HEADER_LOCK(l) \ - do \ - { \ - BC_SIG_LOCK; \ - BC_SETJMP_LOCKED(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } \ +#define BC_FUNC_HEADER(vm, l) \ + do \ + { \ + BC_SETJMP(vm, l); \ + vm->err = BCL_ERROR_NONE; \ + } \ while (0) /** - * A footer to unlock and stop the jumping if an error happened. It also sets - * the variable that tells bcl that it is running. - * @param e The error variable to set. + * A footer for functions that do not return an error code. */ -#define BC_FUNC_FOOTER_UNLOCK(e) \ - do \ - { \ - BC_SIG_ASSERT_LOCKED; \ - e = vm.err; \ - vm.running = 0; \ - BC_UNSETJMP; \ - BC_LONGJMP_STOP; \ - vm.sig_lock = 0; \ - } \ +#define BC_FUNC_FOOTER_NO_ERR(vm) \ + do \ + { \ + BC_UNSETJMP(vm); \ + } \ while (0) /** - * A header that sets a jump and sets running. - * @param l The label to jump to on error. + * A footer for functions that *do* return an error code. + * @param vm The thread data. + * @param e The error variable to set. */ -#define BC_FUNC_HEADER(l) \ - do \ - { \ - BC_SETJMP(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } \ - while (0) - -/** - * A header that assumes that signals are already locked. It sets a jump and - * running. - * @param l The label to jump to on error. - */ -#define BC_FUNC_HEADER_INIT(l) \ - do \ - { \ - BC_SETJMP_LOCKED(l); \ - vm.err = BCL_ERROR_NONE; \ - vm.running = 1; \ - } \ - while (0) - -/** - * A footer for functions that do not return an error code. It clears running - * and unlocks the signals. It also stops the jumping. - */ -#define BC_FUNC_FOOTER_NO_ERR \ - do \ - { \ - vm.running = 0; \ - BC_UNSETJMP; \ - BC_LONGJMP_STOP; \ - vm.sig_lock = 0; \ - } \ - while (0) - -/** - * A footer for functions that *do* return an error code. It clears running and - * unlocks the signals. It also stops the jumping. - * @param e The error variable to set. - */ -#define BC_FUNC_FOOTER(e) \ - do \ - { \ - e = vm.err; \ - BC_FUNC_FOOTER_NO_ERR; \ - } \ +#define BC_FUNC_FOOTER(vm, e) \ + do \ + { \ + e = vm->err; \ + BC_FUNC_FOOTER_NO_ERR(vm); \ + } \ while (0) /** @@ -151,10 +102,10 @@ * is bad. * @param c The context. */ -#define BC_CHECK_CTXT(c) \ +#define BC_CHECK_CTXT(vm, c) \ do \ { \ - c = bcl_context(); \ + c = bcl_contextHelper(vm); \ if (BC_ERR(c == NULL)) \ { \ BclNumber n_num; \ @@ -168,10 +119,10 @@ * A header to check the context and return an error directly if it is bad. * @param c The context. */ -#define BC_CHECK_CTXT_ERR(c) \ +#define BC_CHECK_CTXT_ERR(vm, c) \ do \ { \ - c = bcl_context(); \ + c = bcl_contextHelper(vm); \ if (BC_ERR(c == NULL)) \ { \ return BCL_ERROR_INVALID_CONTEXT; \ @@ -183,12 +134,12 @@ * A header to check the context and abort if it is bad. * @param c The context. */ -#define BC_CHECK_CTXT_ASSERT(c) \ - do \ - { \ - c = bcl_context(); \ - assert(c != NULL); \ - } \ +#define BC_CHECK_CTXT_ASSERT(vm, c) \ + do \ + { \ + c = bcl_contextHelper(vm); \ + assert(c != NULL); \ + } \ while (0) /** @@ -272,4 +223,21 @@ typedef struct BclCtxt } BclCtxt; +/** + * Returns the @a BcVm for the current thread. + * @return The vm for the current thread. + */ +BcVm* +bcl_getspecific(void); + +#ifndef _WIN32 + +typedef pthread_key_t BclTls; + +#else // _WIN32 + +typedef DWORD BclTls; + +#endif // _WIN32 + #endif // LIBBC_PRIVATE_H diff --git a/include/num.h b/include/num.h index 4a4dc5bc54fa..835dd8e97478 100644 --- a/include/num.h +++ b/include/num.h @@ -47,10 +47,6 @@ #include <vector.h> #include <bcl.h> -#ifndef BC_ENABLE_EXTRA_MATH -#define BC_ENABLE_EXTRA_MATH (1) -#endif // BC_ENABLE_EXTRA_MATH - /// Everything in bc is base 10.. #define BC_BASE (10) @@ -829,6 +825,14 @@ bc_num_parse(BcNum* restrict n, const char* restrict val, BcBigDig base); void bc_num_print(BcNum* restrict n, BcBigDig base, bool newline); +/** + * Invert @a into @a b at the current scale. + * @param a The number to invert. + * @param b The return parameter. This must be preallocated. + * @param scale The current scale. + */ +#define bc_num_inv(a, b, scale) bc_num_div(&vm->one, (a), (b), (scale)) + #if !BC_ENABLE_LIBRARY /** diff --git a/include/program.h b/include/program.h index 1a87aa612c90..3eaf568d66ac 100644 --- a/include/program.h +++ b/include/program.h @@ -69,8 +69,10 @@ 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 @@ -122,6 +124,10 @@ typedef struct BcProgram /// 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. @@ -206,16 +212,36 @@ typedef struct BcProgram /// 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(p, name, t) +#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. +// 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(p, code, bgn) + 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 @@ -438,14 +464,14 @@ extern const char bc_program_esc_seqs[]; #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]; \ - } \ +#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 diff --git a/include/status.h b/include/status.h index d038944d40c9..f478beb1a2d5 100644 --- a/include/status.h +++ b/include/status.h @@ -36,7 +36,15 @@ #ifndef BC_STATUS_H #define BC_STATUS_H +#ifdef _WIN32 +#include <Windows.h> +#include <BaseTsd.h> +#include <stdio.h> +#include <io.h> +#endif // _WIN32 + #include <stdint.h> +#include <sys/types.h> // This is used by configure.sh to test for OpenBSD. #ifdef BC_TEST_OPENBSD @@ -52,6 +60,39 @@ #endif // __FreeBSD__ #endif // BC_TEST_FREEBSD +// Windows has deprecated isatty() and the rest of these. Or doesn't have them. +// So these are just fixes for Windows. +#ifdef _WIN32 + +// This one is special. Windows did not like me defining an +// inline function that was not given a definition in a header +// file. This suppresses that by making inline functions non-inline. +#define inline + +#define restrict __restrict +#define strdup _strdup +#define write(f, b, s) _write((f), (b), (unsigned int) (s)) +#define read(f, b, s) _read((f), (b), (unsigned int) (s)) +#define close _close +#define open(f, n, m) \ + _sopen_s((f), (n), (m) | _O_BINARY, _SH_DENYNO, _S_IREAD | _S_IWRITE) +#define sigjmp_buf jmp_buf +#define sigsetjmp(j, s) setjmp(j) +#define siglongjmp longjmp +#define isatty _isatty +#define STDIN_FILENO _fileno(stdin) +#define STDOUT_FILENO _fileno(stdout) +#define STDERR_FILENO _fileno(stderr) +#define S_ISDIR(m) ((m) & (_S_IFDIR)) +#define O_RDONLY _O_RDONLY +#define stat _stat +#define fstat _fstat +#define BC_FILE_SEP '\\' + +#else // _WIN32 +#define BC_FILE_SEP '/' +#endif // _WIN32 + #ifndef BC_ENABLED #define BC_ENABLED (1) #endif // BC_ENABLED @@ -60,10 +101,46 @@ #define DC_ENABLED (1) #endif // DC_ENABLED +#ifndef BC_ENABLE_EXTRA_MATH +#define BC_ENABLE_EXTRA_MATH (1) +#endif // BC_ENABLE_EXTRA_MATH + #ifndef BC_ENABLE_LIBRARY #define BC_ENABLE_LIBRARY (0) #endif // BC_ENABLE_LIBRARY +#ifndef BC_ENABLE_HISTORY +#define BC_ENABLE_HISTORY (1) +#endif // BC_ENABLE_HISTORY + +#ifndef BC_ENABLE_EDITLINE +#define BC_ENABLE_EDITLINE (0) +#endif // BC_ENABLE_EDITLINE + +#ifndef BC_ENABLE_READLINE +#define BC_ENABLE_READLINE (0) +#endif // BC_ENABLE_READLINE + +#ifndef BC_ENABLE_NLS +#define BC_ENABLE_NLS (0) +#endif // BC_ENABLE_NLS + +#ifdef __OpenBSD__ +#if BC_ENABLE_READLINE +#error Cannot use readline on OpenBSD +#endif // BC_ENABLE_READLINE +#endif // __OpenBSD__ + +#if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE +#error Must enable only one of editline or readline, not both. +#endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE + +#if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE +#define BC_ENABLE_LINE_LIB (1) +#else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE +#define BC_ENABLE_LINE_LIB (0) +#endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE + // This is error checking for fuzz builds. #if BC_ENABLE_AFL #ifndef __AFL_HAVE_MANUAL_CONTROL @@ -122,6 +199,18 @@ #define BC_DEBUG_CODE (0) #endif // BC_DEBUG_CODE +#if defined(__clang__) +#define BC_CLANG (1) +#else // defined(__clang__) +#define BC_CLANG (0) +#endif // defined(__clang__) + +#if defined(__GNUC__) && !BC_CLANG +#define BC_GCC (1) +#else // defined(__GNUC__) && !BC_CLANG +#define BC_GCC (0) +#endif // defined(__GNUC__) && !BC_CLANG + // We want to be able to use _Noreturn on C11 compilers. #if __STDC_VERSION__ >= 201112L @@ -131,7 +220,19 @@ #else // __STDC_VERSION__ +#if BC_CLANG +#if __has_attribute(noreturn) +#define BC_NORETURN __attribute((noreturn)) +#else // __has_attribute(noreturn) #define BC_NORETURN +#endif // __has_attribute(noreturn) + +#else // BC_CLANG + +#define BC_NORETURN + +#endif // BC_CLANG + #define BC_MUST_RETURN #define BC_C11 (0) @@ -143,7 +244,7 @@ // GCC and Clang complain if fallthroughs are not marked with their special // attribute. Jerks. This creates a define for marking the fallthroughs that is // nothing on other compilers. -#if defined(__clang__) || defined(__GNUC__) +#if BC_CLANG || BC_GCC #if defined(__has_attribute) @@ -153,28 +254,28 @@ #define BC_FALLTHROUGH #endif // __has_attribute(fallthrough) -#ifdef __GNUC__ +#if BC_GCC #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #undef BC_HAS_UNREACHABLE #define BC_HAS_UNREACHABLE (1) #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -#else // __GNUC__ +#else // BC_GCC #if __clang_major__ >= 4 #undef BC_HAS_UNREACHABLE #define BC_HAS_UNREACHABLE (1) #endif // __clang_major__ >= 4 -#endif // __GNUC__ +#endif // BC_GCC #else // defined(__has_attribute) #define BC_FALLTHROUGH #endif // defined(__has_attribute) -#else // defined(__clang__) || defined(__GNUC__) +#else // BC_CLANG || BC_GCC #define BC_FALLTHROUGH -#endif // defined(__clang__) || defined(__GNUC__) +#endif // BC_CLANG || BC_GCC #if BC_HAS_UNREACHABLE @@ -194,7 +295,7 @@ #endif // BC_HAS_UNREACHABLE -#ifdef __GNUC__ +#if BC_GCC #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) @@ -203,9 +304,9 @@ #endif // __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) -#endif // __GNUC__ +#endif // BC_GCC -#ifdef __clang__ +#if BC_CLANG #if __clang_major__ >= 4 @@ -214,7 +315,7 @@ #endif // __clang_major__ >= 4 -#endif // __GNUC__ +#endif // BC_CLANG #ifdef BC_NO_COMPUTED_GOTO @@ -223,12 +324,12 @@ #endif // BC_NO_COMPUTED_GOTO -#ifdef __GNUC__ +#if BC_GCC #ifdef __OpenBSD__ // The OpenBSD GCC doesn't like inline. #define inline #endif // __OpenBSD__ -#endif // __GNUC__ +#endif // BC_GCC // Workarounds for AIX's POSIX incompatibility. #ifndef SIZE_MAX @@ -279,6 +380,10 @@ #define BC_DEFAULT_EXPR_EXIT (1) #endif // BC_DEFAULT_EXPR_EXIT +#ifndef BC_DEFAULT_DIGIT_CLAMP +#define BC_DEFAULT_DIGIT_CLAMP (0) +#endif // BC_DEFAULT_DIGIT_CLAMP + // All of these set defaults for settings. #ifndef DC_DEFAULT_SIGINT_RESET #define DC_DEFAULT_SIGINT_RESET (1) @@ -300,6 +405,10 @@ #define DC_DEFAULT_EXPR_EXIT (1) #endif // DC_DEFAULT_EXPR_EXIT +#ifndef DC_DEFAULT_DIGIT_CLAMP +#define DC_DEFAULT_DIGIT_CLAMP (0) +#endif // DC_DEFAULT_DIGIT_CLAMP + /// Statuses, which mark either which category of error happened, or some other /// status that matters. typedef enum BcStatus @@ -558,13 +667,15 @@ typedef enum BcErr #define BC_JMP bc_vm_jmp() #endif // BC_DEBUG_CODE +#if !BC_ENABLE_LIBRARY + /// Returns true if an exception is in flight, false otherwise. -#define BC_SIG_EXC \ - BC_UNLIKELY(vm.status != (sig_atomic_t) BC_STATUS_SUCCESS || vm.sig) +#define BC_SIG_EXC(vm) \ + BC_UNLIKELY(vm->status != (sig_atomic_t) BC_STATUS_SUCCESS || vm->sig) /// Returns true if there is *no* exception in flight, false otherwise. -#define BC_NO_SIG_EXC \ - BC_LIKELY(vm.status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm.sig) +#define BC_NO_SIG_EXC(vm) \ + BC_LIKELY(vm->status == (sig_atomic_t) BC_STATUS_SUCCESS && !vm->sig) #ifndef NDEBUG @@ -572,22 +683,22 @@ typedef enum BcErr /// bc, and they *must* have signals locked. Other functions are expected to /// *not* have signals locked, for reasons. So this is a pre-built assert /// (no-op in non-debug mode) that check that signals are locked. -#define BC_SIG_ASSERT_LOCKED \ - do \ - { \ - assert(vm.sig_lock); \ - } \ +#define BC_SIG_ASSERT_LOCKED \ + do \ + { \ + assert(vm->sig_lock); \ + } \ while (0) /// Assert that signals are unlocked. There are non-async-signal-safe functions /// in bc, and they *must* have signals locked. Other functions are expected to /// *not* have signals locked, for reasons. So this is a pre-built assert /// (no-op in non-debug mode) that check that signals are unlocked. -#define BC_SIG_ASSERT_NOT_LOCKED \ - do \ - { \ - assert(vm.sig_lock == 0); \ - } \ +#define BC_SIG_ASSERT_NOT_LOCKED \ + do \ + { \ + assert(vm->sig_lock == 0); \ + } \ while (0) #else // NDEBUG @@ -611,7 +722,7 @@ typedef enum BcErr do \ { \ BC_SIG_ASSERT_NOT_LOCKED; \ - vm.sig_lock = 1; \ + vm->sig_lock = 1; \ } \ while (0) @@ -620,8 +731,8 @@ typedef enum BcErr do \ { \ BC_SIG_ASSERT_LOCKED; \ - vm.sig_lock = 0; \ - if (vm.sig) BC_JMP; \ + vm->sig_lock = 0; \ + if (vm->sig) BC_JMP; \ } \ while (0) @@ -629,21 +740,21 @@ typedef enum BcErr /// used after labels that longjmp() goes to after the jump because the cleanup /// code must have signals locked, and BC_LONGJMP_CONT will unlock signals if it /// doesn't jump. -#define BC_SIG_MAYLOCK \ - do \ - { \ - vm.sig_lock = 1; \ - } \ +#define BC_SIG_MAYLOCK \ + do \ + { \ + vm->sig_lock = 1; \ + } \ while (0) /// Unlocks signals, regardless of if they were already unlocked. If a signal /// happened, then this will cause a jump. -#define BC_SIG_MAYUNLOCK \ - do \ - { \ - vm.sig_lock = 0; \ - if (vm.sig) BC_JMP; \ - } \ +#define BC_SIG_MAYUNLOCK \ + do \ + { \ + vm->sig_lock = 0; \ + if (vm->sig) BC_JMP; \ + } \ while (0) /* @@ -654,8 +765,8 @@ typedef enum BcErr #define BC_SIG_TRYLOCK(v) \ do \ { \ - v = vm.sig_lock; \ - vm.sig_lock = 1; \ + v = vm->sig_lock; \ + vm->sig_lock = 1; \ } \ while (0) @@ -663,38 +774,23 @@ typedef enum BcErr * initiates an exception/jump. * @param v The old lock state. */ -#define BC_SIG_TRYUNLOCK(v) \ - do \ - { \ - vm.sig_lock = (v); \ - if (!(v) && vm.sig) BC_JMP; \ - } \ +#define BC_SIG_TRYUNLOCK(v) \ + do \ + { \ + vm->sig_lock = (v); \ + if (!(v) && vm->sig) BC_JMP; \ + } \ while (0) -/** - * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will - * immediately goto a label where some cleanup code is. This one assumes that - * signals are not locked and will lock them, set the jump, and unlock them. - * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. - * This grows the jmp_bufs vector first to prevent a fatal error from happening - * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used - * *before* the actual initialization calls that need the setjmp(). - * param l The label to jump to on a longjmp(). - */ -#define BC_SETJMP(l) \ - do \ - { \ - sigjmp_buf sjb; \ - BC_SIG_LOCK; \ - bc_vec_grow(&vm.jmp_bufs, 1); \ - if (sigsetjmp(sjb, 0)) \ - { \ - assert(BC_SIG_EXC); \ - goto l; \ - } \ - bc_vec_push(&vm.jmp_bufs, &sjb); \ - BC_SIG_UNLOCK; \ - } \ +/// Stops a stack unwinding. Technically, a stack unwinding needs to be done +/// manually, but it will always be done unless certain flags are cleared. This +/// clears the flags. +#define BC_LONGJMP_STOP \ + do \ + { \ + vm->sig_pop = 0; \ + vm->sig = 0; \ + } \ while (0) /** @@ -704,59 +800,108 @@ typedef enum BcErr * the initializations that need the setjmp(). * param l The label to jump to on a longjmp(). */ -#define BC_SETJMP_LOCKED(l) \ - do \ - { \ - sigjmp_buf sjb; \ - BC_SIG_ASSERT_LOCKED; \ - if (sigsetjmp(sjb, 0)) \ - { \ - assert(BC_SIG_EXC); \ - goto l; \ - } \ - bc_vec_push(&vm.jmp_bufs, &sjb); \ - } \ +#define BC_SETJMP_LOCKED(vm, l) \ + do \ + { \ + sigjmp_buf sjb; \ + BC_SIG_ASSERT_LOCKED; \ + if (sigsetjmp(sjb, 0)) \ + { \ + assert(BC_SIG_EXC(vm)); \ + goto l; \ + } \ + bc_vec_push(&vm->jmp_bufs, &sjb); \ + } \ while (0) /// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to /// the next place. This is what continues the stack unwinding. This basically /// copies BC_SIG_UNLOCK into itself, but that is because its condition for /// jumping is BC_SIG_EXC, not just that a signal happened. -#define BC_LONGJMP_CONT \ - do \ - { \ - BC_SIG_ASSERT_LOCKED; \ - if (!vm.sig_pop) bc_vec_pop(&vm.jmp_bufs); \ - vm.sig_lock = 0; \ - if (BC_SIG_EXC) BC_JMP; \ - } \ +#define BC_LONGJMP_CONT(vm) \ + do \ + { \ + BC_SIG_ASSERT_LOCKED; \ + if (!vm->sig_pop) bc_vec_pop(&vm->jmp_bufs); \ + vm->sig_lock = 0; \ + if (BC_SIG_EXC(vm)) BC_JMP; \ + } \ + while (0) + +#else // !BC_ENABLE_LIBRARY + +#define BC_SIG_LOCK +#define BC_SIG_UNLOCK +#define BC_SIG_MAYLOCK +#define BC_SIG_TRYLOCK(lock) +#define BC_SIG_TRYUNLOCK(lock) +#define BC_SIG_ASSERT_LOCKED + +/// Returns true if an exception is in flight, false otherwise. +#define BC_SIG_EXC(vm) \ + BC_UNLIKELY(vm->status != (sig_atomic_t) BC_STATUS_SUCCESS) + +/// Returns true if there is *no* exception in flight, false otherwise. +#define BC_NO_SIG_EXC(vm) \ + BC_LIKELY(vm->status == (sig_atomic_t) BC_STATUS_SUCCESS) + +/// Used after cleanup labels set by BC_SETJMP and BC_SETJMP_LOCKED to jump to +/// the next place. This is what continues the stack unwinding. This basically +/// copies BC_SIG_UNLOCK into itself, but that is because its condition for +/// jumping is BC_SIG_EXC, not just that a signal happened. +#define BC_LONGJMP_CONT(vm) \ + do \ + { \ + bc_vec_pop(&vm->jmp_bufs); \ + if (BC_SIG_EXC(vm)) BC_JMP; \ + } \ + while (0) + +#endif // !BC_ENABLE_LIBRARY + +/** + * Sets a jump, and sets it up as well so that if a longjmp() happens, bc will + * immediately goto a label where some cleanup code is. This one assumes that + * signals are not locked and will lock them, set the jump, and unlock them. + * Setting the jump also includes pushing the jmp_buf onto the jmp_buf stack. + * This grows the jmp_bufs vector first to prevent a fatal error from happening + * after the setjmp(). This is done because BC_SETJMP(l) is assumed to be used + * *before* the actual initialization calls that need the setjmp(). + * param l The label to jump to on a longjmp(). + */ +#define BC_SETJMP(vm, l) \ + do \ + { \ + sigjmp_buf sjb; \ + BC_SIG_LOCK; \ + bc_vec_grow(&vm->jmp_bufs, 1); \ + if (sigsetjmp(sjb, 0)) \ + { \ + assert(BC_SIG_EXC(vm)); \ + goto l; \ + } \ + bc_vec_push(&vm->jmp_bufs, &sjb); \ + BC_SIG_UNLOCK; \ + } \ while (0) /// Unsets a jump. It always assumes signals are locked. This basically just /// pops a jmp_buf off of the stack of jmp_bufs, and since the jump mechanism /// always jumps to the location at the top of the stack, this effectively /// undoes a setjmp(). -#define BC_UNSETJMP \ - do \ - { \ - BC_SIG_ASSERT_LOCKED; \ - bc_vec_pop(&vm.jmp_bufs); \ - } \ +#define BC_UNSETJMP(vm) \ + do \ + { \ + BC_SIG_ASSERT_LOCKED; \ + bc_vec_pop(&vm->jmp_bufs); \ + } \ while (0) -/// Stops a stack unwinding. Technically, a stack unwinding needs to be done -/// manually, but it will always be done unless certain flags are cleared. This -/// clears the flags. -#define BC_LONGJMP_STOP \ - do \ - { \ - vm.sig_pop = 0; \ - vm.sig = 0; \ - } \ - while (0) +#if BC_ENABLE_LIBRARY + +#define BC_SETJMP_LOCKED(vm, l) BC_SETJMP(vm, l) // Various convenience macros for calling the bc's error handling routine. -#if BC_ENABLE_LIBRARY /** * Call bc's error handling routine. @@ -780,6 +925,8 @@ typedef enum BcErr #else // BC_ENABLE_LIBRARY +// Various convenience macros for calling the bc's error handling routine. + /** * Call bc's error handling routine. * @param e The error. @@ -813,34 +960,34 @@ typedef enum BcErr // Convenience macros that can be placed at the beginning and exits of functions // for easy marking of where functions are entered and exited. #if BC_DEBUG_CODE -#define BC_FUNC_ENTER \ - do \ - { \ - size_t bc_func_enter_i; \ - for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \ - ++bc_func_enter_i) \ - { \ - bc_file_puts(&vm.ferr, bc_flush_none, " "); \ - } \ - vm.func_depth += 1; \ - bc_file_printf(&vm.ferr, "Entering %s\n", __func__); \ - bc_file_flush(&vm.ferr, bc_flush_none); \ - } \ +#define BC_FUNC_ENTER \ + do \ + { \ + size_t bc_func_enter_i; \ + for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ + ++bc_func_enter_i) \ + { \ + bc_file_puts(&vm->ferr, bc_flush_none, " "); \ + } \ + vm->func_depth += 1; \ + bc_file_printf(&vm->ferr, "Entering %s\n", __func__); \ + bc_file_flush(&vm->ferr, bc_flush_none); \ + } \ while (0); -#define BC_FUNC_EXIT \ - do \ - { \ - size_t bc_func_enter_i; \ - vm.func_depth -= 1; \ - for (bc_func_enter_i = 0; bc_func_enter_i < vm.func_depth; \ - ++bc_func_enter_i) \ - { \ - bc_file_puts(&vm.ferr, bc_flush_none, " "); \ - } \ - bc_file_printf(&vm.ferr, "Leaving %s\n", __func__); \ - bc_file_flush(&vm.ferr, bc_flush_none); \ - } \ +#define BC_FUNC_EXIT \ + do \ + { \ + size_t bc_func_enter_i; \ + vm->func_depth -= 1; \ + for (bc_func_enter_i = 0; bc_func_enter_i < vm->func_depth; \ + ++bc_func_enter_i) \ + { \ + bc_file_puts(&vm->ferr, bc_flush_none, " "); \ + } \ + bc_file_printf(&vm->ferr, "Leaving %s\n", __func__); \ + bc_file_flush(&vm->ferr, bc_flush_none); \ + } \ while (0); #else // BC_DEBUG_CODE #define BC_FUNC_ENTER diff --git a/include/vector.h b/include/vector.h index 43158ef4ba63..539b8a1ac292 100644 --- a/include/vector.h +++ b/include/vector.h @@ -427,17 +427,6 @@ bc_slabvec_init(BcVec* restrict v); char* bc_slabvec_strdup(BcVec* restrict v, const char* str); -#if BC_ENABLED - -/** - * Undoes the last allocation on the slab vector. This allows bc to have a - * heap-based stacks for strings. This is used by the bc parser. - */ -void -bc_slabvec_undo(BcVec* restrict v, size_t len); - -#endif // BC_ENABLED - /** * Clears a slab vector. This deallocates all but the first slab and clears the * first slab. @@ -460,6 +449,25 @@ bc_slabvec_print(BcVec* v, const char* func); /// A convenience macro for freeing a vector of slabs. #define bc_slabvec_free bc_vec_free +#if BC_ENABLED +#if DC_ENABLED + +/// Returns the set of slabs for the maps and the current calculator. +#define BC_VEC_MAP_SLABS (BC_IS_DC ? &vm->main_slabs : &vm->other_slabs) + +#else // DC_ENABLED + +/// Returns the set of slabs for the maps and the current calculator. +#define BC_VEC_MAP_SLABS (&vm->other_slabs) + +#endif // DC_ENABLED +#else // BC_ENABLED + +/// Returns the set of slabs for the maps and the current calculator. +#define BC_VEC_MAP_SLABS (&vm->main_slabs) + +#endif // BC_ENABLED + #ifndef _WIN32 /** diff --git a/include/version.h b/include/version.h index 4400e4f59ccd..74b1dc72bd0c 100644 --- a/include/version.h +++ b/include/version.h @@ -37,6 +37,6 @@ #define BC_VERSION_H /// The current version. -#define VERSION 5.3.3 +#define VERSION 6.0.2 #endif // BC_VERSION_H diff --git a/include/vm.h b/include/vm.h index dd4577489467..c800e476e228 100644 --- a/include/vm.h +++ b/include/vm.h @@ -78,10 +78,6 @@ #endif // Set defaults. -// -#ifndef BC_ENABLE_NLS -#define BC_ENABLE_NLS (0) -#endif // BC_ENABLE_NLS #ifndef MAINEXEC #define MAINEXEC bc @@ -179,52 +175,58 @@ /// The flag for exiting with expressions. #define BC_FLAG_EXPR_EXIT (UINTMAX_C(1) << 13) +/// The flag for digit clamping. +#define BC_FLAG_DIGIT_CLAMP (UINTMAX_C(1) << 14) + /// A convenience macro for getting the TTYIN flag. -#define BC_TTYIN (vm.flags & BC_FLAG_TTYIN) +#define BC_TTYIN (vm->flags & BC_FLAG_TTYIN) /// A convenience macro for getting the TTY flag. -#define BC_TTY (vm.flags & BC_FLAG_TTY) +#define BC_TTY (vm->flags & BC_FLAG_TTY) /// A convenience macro for getting the SIGINT flag. -#define BC_SIGINT (vm.flags & BC_FLAG_SIGINT) +#define BC_SIGINT (vm->flags & BC_FLAG_SIGINT) #if BC_ENABLED /// A convenience macro for getting the POSIX error flag. -#define BC_S (vm.flags & BC_FLAG_S) +#define BC_S (vm->flags & BC_FLAG_S) /// A convenience macro for getting the POSIX warning flag. -#define BC_W (vm.flags & BC_FLAG_W) +#define BC_W (vm->flags & BC_FLAG_W) /// A convenience macro for getting the math library flag. -#define BC_L (vm.flags & BC_FLAG_L) +#define BC_L (vm->flags & BC_FLAG_L) /// A convenience macro for getting the global stacks flag. -#define BC_G (vm.flags & BC_FLAG_G) +#define BC_G (vm->flags & BC_FLAG_G) #endif // BC_ENABLED #if DC_ENABLED /// A convenience macro for getting the extended register flag. -#define DC_X (vm.flags & DC_FLAG_X) +#define DC_X (vm->flags & DC_FLAG_X) #endif // DC_ENABLED /// A convenience macro for getting the interactive flag. -#define BC_I (vm.flags & BC_FLAG_I) +#define BC_I (vm->flags & BC_FLAG_I) /// A convenience macro for getting the prompt flag. -#define BC_P (vm.flags & BC_FLAG_P) +#define BC_P (vm->flags & BC_FLAG_P) /// A convenience macro for getting the read prompt flag. -#define BC_R (vm.flags & BC_FLAG_R) +#define BC_R (vm->flags & BC_FLAG_R) /// A convenience macro for getting the leading zero flag. -#define BC_Z (vm.flags & BC_FLAG_Z) +#define BC_Z (vm->flags & BC_FLAG_Z) /// A convenience macro for getting the expression exit flag. -#define BC_EXPR_EXIT (vm.flags & BC_FLAG_EXPR_EXIT) +#define BC_EXPR_EXIT (vm->flags & BC_FLAG_EXPR_EXIT) + +/// A convenience macro for getting the digit clamp flag. +#define BC_DIGIT_CLAMP (vm->flags & BC_FLAG_DIGIT_CLAMP) #if BC_ENABLED @@ -234,10 +236,57 @@ #if DC_ENABLED /// Returns true if bc is running. -#define BC_IS_BC (vm.name[0] != 'd') +#define BC_IS_BC (vm->name[0] != 'd') /// Returns true if dc is running. -#define BC_IS_DC (vm.name[0] == 'd') +#define BC_IS_DC (vm->name[0] == 'd') + +/// Returns the correct read prompt. +#define BC_VM_READ_PROMPT (BC_IS_BC ? "read> " : "?> ") + +/// Returns the string for the line length environment variable. +#define BC_VM_LINE_LENGTH_STR (BC_IS_BC ? "BC_LINE_LENGTH" : "DC_LINE_LENGTH") + +/// Returns the string for the environment args environment variable. +#define BC_VM_ENV_ARGS_STR (BC_IS_BC ? "BC_ENV_ARGS" : "DC_ENV_ARGS") + +/// Returns the string for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_STR (BC_IS_BC ? "BC_EXPR_EXIT" : "DC_EXPR_EXIT") + +/// Returns the default for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_DEF \ + (BC_IS_BC ? BC_DEFAULT_EXPR_EXIT : DC_DEFAULT_EXPR_EXIT) + +/// Returns the string for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_STR (BC_IS_BC ? "BC_DIGIT_CLAMP" : "DC_DIGIT_CLAMP") + +/// Returns the default for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_DEF \ + (BC_IS_BC ? BC_DEFAULT_DIGIT_CLAMP : DC_DEFAULT_DIGIT_CLAMP) + +/// Returns the string for the TTY mode environment variable. +#define BC_VM_TTY_MODE_STR (BC_IS_BC ? "BC_TTY_MODE" : "DC_TTY_MODE") + +/// Returns the default for the TTY mode environment variable. +#define BC_VM_TTY_MODE_DEF \ + (BC_IS_BC ? BC_DEFAULT_TTY_MODE : DC_DEFAULT_TTY_MODE) + +/// Returns the string for the prompt environment variable. +#define BC_VM_PROMPT_STR (BC_IS_BC ? "BC_PROMPT" : "DC_PROMPT") + +/// Returns the default for the prompt environment variable. +#define BC_VM_PROMPT_DEF (BC_IS_BC ? BC_DEFAULT_PROMPT : DC_DEFAULT_PROMPT) + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_STR \ + (BC_IS_BC ? "BC_SIGINT_RESET" : "DC_SIGINT_RESET") + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_DEF \ + (BC_IS_BC ? BC_DEFAULT_SIGINT_RESET : DC_DEFAULT_SIGINT_RESET) + +/// Returns true if the calculator should run stdin. +#define BC_VM_RUN_STDIN(has_file) (BC_IS_BC || !(has_file)) #else // DC_ENABLED @@ -247,6 +296,48 @@ /// Returns true if dc is running. #define BC_IS_DC (0) +/// Returns the correct read prompt. +#define BC_VM_READ_PROMPT ("read> ") + +/// Returns the string for the line length environment variable. +#define BC_VM_LINE_LENGTH_STR ("BC_LINE_LENGTH") + +/// Returns the string for the environment args environment variable. +#define BC_VM_ENV_ARGS_STR ("BC_ENV_ARGS") + +/// Returns the string for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_STR ("BC_EXPR_EXIT") + +/// Returns the default for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_DEF (BC_DEFAULT_EXPR_EXIT) + +/// Returns the string for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_STR ("BC_DIGIT_CLAMP") + +/// Returns the default for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_DEF (BC_DEFAULT_DIGIT_CLAMP) + +/// Returns the string for the TTY mode environment variable. +#define BC_VM_TTY_MODE_STR ("BC_TTY_MODE") + +/// Returns the default for the TTY mode environment variable. +#define BC_VM_TTY_MODE_DEF (BC_DEFAULT_TTY_MODE) + +/// Returns the string for the prompt environment variable. +#define BC_VM_PROMPT_STR ("BC_PROMPT") + +/// Returns the default for the SIGINT reset environment variable. +#define BC_VM_PROMPT_DEF (BC_DEFAULT_PROMPT) + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_STR ("BC_SIGINT_RESET") + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_DEF (BC_DEFAULT_SIGINT_RESET) + +/// Returns true if the calculator should run stdin. +#define BC_VM_RUN_STDIN(has_file) (BC_IS_BC) + #endif // DC_ENABLED #else // BC_ENABLED @@ -260,6 +351,48 @@ /// Returns true if dc is running. #define BC_IS_DC (1) +/// Returns the correct read prompt. +#define BC_VM_READ_PROMPT ("?> ") + +/// Returns the string for the line length environment variable. +#define BC_VM_LINE_LENGTH_STR ("DC_LINE_LENGTH") + +/// Returns the string for the environment args environment variable. +#define BC_VM_ENV_ARGS_STR ("DC_ENV_ARGS") + +/// Returns the string for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_STR ("DC_EXPR_EXIT") + +/// Returns the default for the expression exit environment variable. +#define BC_VM_EXPR_EXIT_DEF (DC_DEFAULT_EXPR_EXIT) + +/// Returns the string for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_STR ("DC_DIGIT_CLAMP") + +/// Returns the default for the digit clamp environment variable. +#define BC_VM_DIGIT_CLAMP_DEF (DC_DEFAULT_DIGIT_CLAMP) + +/// Returns the string for the TTY mode environment variable. +#define BC_VM_TTY_MODE_STR ("DC_TTY_MODE") + +/// Returns the default for the TTY mode environment variable. +#define BC_VM_TTY_MODE_DEF (DC_DEFAULT_TTY_MODE) + +/// Returns the string for the prompt environment variable. +#define BC_VM_PROMPT_STR ("DC_PROMPT") + +/// Returns the default for the SIGINT reset environment variable. +#define BC_VM_PROMPT_DEF (DC_DEFAULT_PROMPT) + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_STR ("DC_SIGINT_RESET") + +/// Returns the string for the SIGINT reset environment variable. +#define BC_VM_SIGINT_RESET_DEF (DC_DEFAULT_SIGINT_RESET) + +/// Returns true if the calculator should run stdin. +#define BC_VM_RUN_STDIN(has_file) (!(has_file)) + #endif // BC_ENABLED /// A convenience macro for checking if the prompt is enabled. @@ -267,7 +400,9 @@ #else // !BC_ENABLE_LIBRARY -#define BC_Z (vm.leading_zeroes) +#define BC_Z (vm->leading_zeroes) + +#define BC_DIGIT_CLAMP (vm->digit_clamp) #endif // !BC_ENABLE_LIBRARY @@ -437,18 +572,14 @@ typedef struct BcVm /// Whether or not to print leading zeros. bool leading_zeroes; + /// Whether or not to clamp digits that are greater than or equal to the + /// current ibase. + bool digit_clamp; + /// The number of "references," or times that the library was initialized. unsigned int refs; - /// Non-zero if bcl is running. This is volatile sig_atomic_t because it is - /// also used in the signal handler. See the development manual - /// (manuals/development.md#async-signal-safe-signal-handling) for more - /// information. - volatile sig_atomic_t running; - -#endif // BC_ENABLE_LIBRARY - -#if !BC_ENABLE_LIBRARY +#else // BC_ENABLE_LIBRARY /// A pointer to the filename of the current file. This is not owned by the /// BcVm struct. @@ -457,8 +588,6 @@ typedef struct BcVm /// The message printed when SIGINT happens. const char* sigmsg; -#endif // !BC_ENABLE_LIBRARY - /// Non-zero when signals are "locked." This is volatile sig_atomic_t /// because it is also used in the signal handler. See the development /// manual (manuals/development.md#async-signal-safe-signal-handling) for @@ -472,8 +601,6 @@ typedef struct BcVm /// information. volatile sig_atomic_t sig; -#if !BC_ENABLE_LIBRARY - /// The length of sigmsg. uchar siglen; @@ -504,6 +631,10 @@ typedef struct BcVm /// True if bc is currently reading from stdin. bool is_stdin; + /// True if bc should clear its buffers. This is BcVm to fill a hole and + /// also to avoid clobber warnings from GCC. + bool clear; + #if BC_ENABLED /// True if keywords should not be redefined. This is only true for the @@ -512,13 +643,6 @@ typedef struct BcVm #endif // BC_ENABLED -#endif // !BC_ENABLE_LIBRARY - - /// An array of maxes for the globals. - BcBigDig maxes[BC_PROG_GLOBALS_LEN + BC_ENABLE_EXTRA_MATH]; - -#if !BC_ENABLE_LIBRARY - /// A vector of filenames to process. BcVec files; @@ -562,7 +686,10 @@ typedef struct BcVm const char* locale; #endif // BC_ENABLE_NLS -#endif // !BC_ENABLE_LIBRARY +#endif // BC_ENABLE_LIBRARY + + /// An array of maxes for the globals. + BcBigDig maxes[BC_PROG_GLOBALS_LEN + BC_ENABLE_EXTRA_MATH]; /// The last base used to parse. BcBigDig last_base; @@ -652,6 +779,8 @@ typedef struct BcVm #endif // BC_ENABLED #endif // !BC_ENABLE_LIBRARY + BcDig* temps_buf[BC_VM_MAX_TEMPS]; + #if BC_DEBUG_CODE /// The depth for BC_FUNC_ENTER and BC_FUNC_EXIT. @@ -697,13 +826,21 @@ void bc_vm_addTemp(BcDig* num); /** - * Dish out a temp, or NULL if there are none. + * Return the temp on the top of the temp stack, or NULL if there are none. * @return A temp, or NULL if none exist. */ BcDig* bc_vm_takeTemp(void); /** + * Gets the top temp of the temp stack. This is separate from bc_vm_takeTemp() + * to quiet a GCC warning about longjmp() clobbering in bc_num_init(). + * @return A temp, or NULL if none exist. + */ +BcDig* +bc_vm_getTemp(void); + +/** * Frees all temporaries. */ void @@ -715,7 +852,12 @@ bc_vm_freeTemps(void); * Erases the flush argument if history does not exist because it does not * matter if history does not exist. */ -#define bc_vm_putchar(c, t) bc_vm_putchar(c) +#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c) + +#else // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB + +// This is here to satisfy a clang warning about recursive macros. +#define bc_vm_putchar(c, t) bc_vm_putchar_impl(c, t) #endif // !BC_ENABLE_HISTORY || BC_ENABLE_LINE_LIB @@ -921,10 +1063,17 @@ extern const char bc_pledge_end_history[]; /// A reference to the end pledge() promises when *not* using history. extern const char bc_pledge_end[]; +#if !BC_ENABLE_LIBRARY + /// A reference to the global data. -extern BcVm vm; +extern BcVm* vm; + +/// The global data. +extern BcVm vm_data; /// A reference to the global output buffers. extern char output_bufs[BC_VM_BUF_SIZE]; +#endif // !BC_ENABLE_LIBRARY + #endif // BC_VM_H |
