diff options
Diffstat (limited to 'src/mcpp-predefined.c')
| -rw-r--r-- | src/mcpp-predefined.c | 627 |
1 files changed, 627 insertions, 0 deletions
diff --git a/src/mcpp-predefined.c b/src/mcpp-predefined.c new file mode 100644 index 0000000..556232c --- /dev/null +++ b/src/mcpp-predefined.c @@ -0,0 +1,627 @@ +#include <defs.h> + + +static int +define_utf8( mcpu_macro_table *table, const char *name, + const char *replacement ) +{ + mcpu_text n; + mcpu_text r; + int rc = -1; + + mcpu_text_init( &n ); + mcpu_text_init( &r ); + + if( mcpu_text_from_utf8(&n, name) != 0 || + mcpu_text_from_utf8(&r, replacement ? replacement : "") != 0 ) + goto done; + + rc = mcpu_macro_define_object( table, n.data, n.length, + r.data, r.length, + MCPU_MACRO_ORIGIN_BUILTIN ); + +done: + mcpu_text_free( &n ); + mcpu_text_free( &r ); + return( rc ); +} + + +static int +define_unsigned( mcpu_macro_table *table, const char *name, + unsigned long value ) +{ + char text[64]; + + snprintf( text, sizeof(text), "%lu", value ); + return( define_utf8(table, name, text) ); +} + + +static int +define_quoted( mcpu_macro_table *table, const char *name, + const char *value ) +{ + size_t n; + char *text; + size_t i; + size_t o = 0; + int rc; + + if( value == NULL ) + value = ""; + + n = strlen( value ); + if( n > (SIZE_MAX - 3) / 2 ) + { + errno = EOVERFLOW; + return( -1 ); + } + + text = (char *)malloc( n * 2 + 3 ); + if( text == NULL ) + return( -1 ); + + text[o++] = '"'; + for( i = 0; i < n; ++i ) + { + if( value[i] == '\\' || value[i] == '"' ) + text[o++] = '\\'; + text[o++] = value[i]; + } + text[o++] = '"'; + text[o] = 0; + + rc = define_utf8( table, name, text ); + free( text ); + return( rc ); +} + + +static int +define_from_macro( mcpu_macro_table *table, const char *name, + const char *source_name ) +{ + mcpu_text source; + mcpu_text target; + mcpu_macro *macro; + int rc = -1; + + mcpu_text_init( &source ); + mcpu_text_init( &target ); + + if( mcpu_text_from_utf8(&source, source_name) != 0 || + mcpu_text_from_utf8(&target, name) != 0 ) + goto done; + + macro = mcpu_macro_find( table, source.data, source.length ); + if( macro == NULL || macro->builtin != MCPU_MACRO_BUILTIN_NONE ) + { + errno = EINVAL; + goto done; + } + + rc = mcpu_macro_define_object( table, target.data, target.length, + macro->replacement, + macro->replacement_length, + MCPU_MACRO_ORIGIN_BUILTIN ); + +done: + mcpu_text_free( &source ); + mcpu_text_free( &target ); + return( rc ); +} + + +static int +define_sized_builtin_utf8( mcpu_macro_table *table, const char *name, + enum mcpu_macro_builtin builtin, unsigned bits ) +{ + mcpu_text n; + int rc; + + mcpu_text_init( &n ); + if( mcpu_text_from_utf8(&n, name) != 0 ) + return( -1 ); + + rc = mcpu_macro_define_sized_builtin( table, n.data, n.length, + builtin, bits ); + mcpu_text_free( &n ); + return( rc ); +} + + +static unsigned long +mcpp_uint_decimal_digs( unsigned bits ) +{ + uint64_t n; + + if( bits < 1 ) + return( 0 ); + + /* + * Number of decimal digits in 2^bits - 1. This follows the integer-only + * scheme used by LibMPU _int_digs(), but does not include a terminating + * NUL. The tighter upper approximation keeps the result exact for every + * integer width supported by the current LibMPU family through 65536 bits. + * + * log10(2) < 301029995664 / 1000000000000 + */ + n = ((uint64_t)bits * UINT64_C(301029995664) + + UINT64_C(999999999999)) / UINT64_C(1000000000000); + + return( (unsigned long)n ); +} + + +static unsigned long +mcpp_int_decimal_digs( unsigned bits ) +{ + if( bits < 2 ) + return( 0 ); + + /* Signed maximum is 2^(bits - 1) - 1; sign is not part of DECIMAL_DIG. */ + return( mcpp_uint_decimal_digs(bits - 1) ); +} + + +static int +define_fixed_integer_family( mcpu_macro_table *table, unsigned bits ) +{ + size_t nb = (size_t)bits / 8; + mpu_int *value = NULL; + char *text = NULL; + char name[96]; + size_t text_size; + unsigned long int_digs; + unsigned long uint_digs; + int rc = -1; + + if( bits == 0 || (bits % 8) != 0 ) + { + errno = EINVAL; + return( -1 ); + } + + snprintf( name, sizeof(name), "__INT%u_TYPE__", bits ); + { + char type[64]; + snprintf( type, sizeof(type), "int%u", bits ); + if( define_utf8(table, name, type) != 0 ) + return( -1 ); + } + + snprintf( name, sizeof(name), "__UINT%u_TYPE__", bits ); + { + char type[64]; + snprintf( type, sizeof(type), "uint%u", bits ); + if( define_utf8(table, name, type) != 0 ) + return( -1 ); + } + + snprintf( name, sizeof(name), "__INT%u_WIDTH__", bits ); + if( define_unsigned(table, name, bits) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__UINT%u_WIDTH__", bits ); + if( define_unsigned(table, name, bits) != 0 ) + return( -1 ); + + /* + * TYPE/WIDTH/SIZEOF and decimal-digit metadata remain available for the + * complete LibMPU integer family through NB_I_MAX * 8. Only textual MAX + * values are capped at 256 bits so -dMP stays compact and useful. + */ + snprintf( name, sizeof(name), "__SIZEOF_INT%u__", bits ); + if( define_unsigned(table, name, bits / 8) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__SIZEOF_UINT%u__", bits ); + if( define_unsigned(table, name, bits / 8) != 0 ) + return( -1 ); + + int_digs = mcpp_int_decimal_digs( bits ); + uint_digs = mcpp_uint_decimal_digs( bits ); + if( int_digs == 0 || uint_digs == 0 ) + { + errno = EINVAL; + return( -1 ); + } + snprintf( name, sizeof(name), "__INT%u_DECIMAL_DIG__", bits ); + if( define_unsigned(table, name, int_digs) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__UINT%u_DECIMAL_DIG__", bits ); + if( define_unsigned(table, name, uint_digs) != 0 ) + return( -1 ); + + if( bits > 256 ) + return( 0 ); + + value = (mpu_int *)malloc( nb ); + if( value == NULL ) + return( -1 ); + + text_size = (size_t)bits + 3; + text = (char *)calloc( text_size, 1 ); + if( text == NULL ) + goto done; + + memset( value, 0xff, nb ); + iuitoa( (__mpu_char8_t *)text, value, RADIX_HEX, LOWERCASE, (int)nb ); + + snprintf( name, sizeof(name), "__UINT%u_MAX__", bits ); + if( define_utf8(table, name, text) != 0 ) + goto done; + + /* + * iuitoa() is the canonical LibMPU conversion. For the signed maximum + * the all-ones unsigned bit pattern has only its top bit cleared. + */ + if( strlen(text) < 3 || text[0] != '0' || text[1] != 'x' ) + { + errno = EINVAL; + goto done; + } + text[2] = '7'; + + snprintf( name, sizeof(name), "__INT%u_MAX__", bits ); + if( define_utf8(table, name, text) != 0 ) + goto done; + + rc = 0; + +done: + free( text ); + free( value ); + return( rc ); +} + +typedef void (*real_value_fn)( mpu_real *, unsigned int, int ); + +static int +append_real_value( mcpu_text *output, unsigned bits, real_value_fn fn ) +{ + int nb = (int)(bits / 8); + int max_string; + mpu_real *value; + char *text; + int rc = -1; + + max_string = _real_max_string( nb ); + if( max_string <= 0 ) + { + errno = EINVAL; + return( -1 ); + } + + value = (mpu_real *)calloc( (size_t)nb, 1 ); + text = (char *)calloc( (size_t)max_string + 4096, 1 ); + if( value == NULL || text == NULL ) + goto done; + + fn( value, 0, nb ); + real_to_ascii( (__mpu_char8_t *)text, value, + _real_mant_digs(nb), 'e', 0, 0, nb ); + if( text[0] == 0 ) + { + errno = EINVAL; + goto done; + } + + rc = mcpu_text_append_ascii( output, text ); + +done: + free( text ); + free( value ); + return( rc ); +} + + +static void +real_epsilon_wrapper( mpu_real *value, unsigned int sign, int nb ) +{ + (void)sign; + _real_epsilon( value, nb ); +} + + +static int +append_real_exponent( mcpu_text *output, unsigned bits, + void (*fn)(mpu_int *, int, int) ) +{ + int nb_r = (int)(bits / 8); + int nb_e = _sizeof_exp( nb_r ); + mpu_int *value; + char *text; + size_t text_size; + int rc = -1; + + if( nb_e <= 0 ) + { + errno = EINVAL; + return( -1 ); + } + + value = (mpu_int *)calloc( (size_t)nb_e, 1 ); + text_size = (size_t)nb_e * 8 + 3; + text = (char *)calloc( text_size, 1 ); + if( value == NULL || text == NULL ) + goto done; + + fn( value, nb_e, nb_r ); + iitoa( (__mpu_char8_t *)text, value, RADIX_DEC, LOWERCASE, nb_e ); + if( text[0] == 0 ) + { + errno = EINVAL; + goto done; + } + + rc = mcpu_text_append_ascii( output, text ); + +done: + free( text ); + free( value ); + return( rc ); +} + + +static int +define_real_family( mcpu_macro_table *table, unsigned bits ) +{ + char name[96]; + char type[64]; + int nb = (int)(bits / 8); + + /* + * Real and Complex language types exist only through the configured + * MPU_REAL_IO_LIMIT. Complex WIDTH is the width parameter in the language + * type name (complex128 -> 128), while SIZEOF is twice the Real storage. + */ + if( bits > MCPU_CPP_MPU_REAL_IO_LIMIT ) + return( 0 ); + + snprintf( name, sizeof(name), "__REAL%u_TYPE__", bits ); + snprintf( type, sizeof(type), "real%u", bits ); + if( define_utf8(table, name, type) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__COMPLEX%u_TYPE__", bits ); + snprintf( type, sizeof(type), "complex%u", bits ); + if( define_utf8(table, name, type) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_WIDTH__", bits ); + if( define_unsigned(table, name, bits) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__COMPLEX%u_WIDTH__", bits ); + if( define_unsigned(table, name, bits) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__SIZEOF_REAL%u__", bits ); + if( define_unsigned(table, name, bits / 8) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__SIZEOF_COMPLEX%u__", bits ); + if( define_unsigned(table, name, bits / 4) != 0 ) + return( -1 ); + + /* + * These are compact structural/text-conversion properties. They are + * available for every configured Real type through MPU_REAL_IO_LIMIT. + * _real_max_string() returns a character count, not a byte count. + */ + { + int exp_size = _sizeof_exp( nb ); + int max_strlen = _real_max_string( nb ); + + if( exp_size <= 0 || max_strlen <= 0 ) + { + errno = EINVAL; + return( -1 ); + } + + snprintf( name, sizeof(name), "__SIZEOF_REAL%u_EXP__", bits ); + if( define_unsigned(table, name, (unsigned long)exp_size) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_MAX_STRLEN__", bits ); + if( define_unsigned(table, name, (unsigned long)max_strlen) != 0 ) + return( -1 ); + } + + /* + * Precision metadata is compact and is useful for every configured Real + * width. Only large textual numeric values are capped at 256 bits. + */ + snprintf( name, sizeof(name), "__REAL%u_MANT_DIG__", bits ); + if( define_unsigned(table, name, (unsigned long)_real_mant_digs(nb)) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_DECIMAL_DIG__", bits ); + if( define_unsigned(table, name, (unsigned long)_real_digs(nb)) != 0 ) + return( -1 ); + + if( bits > 256 ) + return( 0 ); + + snprintf( name, sizeof(name), "__REAL%u_MAX__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MAX, bits) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_MIN__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MIN, bits) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_EPSILON__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_EPSILON, bits) != 0 ) + return( -1 ); + + snprintf( name, sizeof(name), "__REAL%u_MAX_EXP__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MAX_EXP, bits) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__REAL%u_MIN_EXP__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MIN_EXP, bits) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__REAL%u_MAX_10_EXP__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MAX_10_EXP, bits) != 0 ) + return( -1 ); + snprintf( name, sizeof(name), "__REAL%u_MIN_10_EXP__", bits ); + if( define_sized_builtin_utf8(table, name, + MCPU_MACRO_BUILTIN_REAL_MIN_10_EXP, bits) != 0 ) + return( -1 ); + + return( 0 ); +} + +int +mcpu_predefined_expand_builtin( enum mcpu_macro_builtin builtin, + unsigned bits, + mcpu_text *output ) +{ + if( output == NULL || bits == 0 || bits > 256 || + bits > MCPU_CPP_MPU_REAL_IO_LIMIT ) + { + errno = EINVAL; + return( -1 ); + } + + switch( builtin ) + { + case MCPU_MACRO_BUILTIN_REAL_MAX: + return( append_real_value(output, bits, _real_max) ); + case MCPU_MACRO_BUILTIN_REAL_MIN: + return( append_real_value(output, bits, _real_min) ); + case MCPU_MACRO_BUILTIN_REAL_EPSILON: + return( append_real_value(output, bits, real_epsilon_wrapper) ); + case MCPU_MACRO_BUILTIN_REAL_MAX_EXP: + return( append_real_exponent(output, bits, _real_max_exp) ); + case MCPU_MACRO_BUILTIN_REAL_MIN_EXP: + return( append_real_exponent(output, bits, _real_min_exp) ); + case MCPU_MACRO_BUILTIN_REAL_MAX_10_EXP: + return( append_real_exponent(output, bits, _real_max_10_exp) ); + case MCPU_MACRO_BUILTIN_REAL_MIN_10_EXP: + return( append_real_exponent(output, bits, _real_min_10_exp) ); + default: + errno = EINVAL; + return( -1 ); + } +} + + +int +mcpu_predefined_install( mcpu_macro_table *table ) +{ + unsigned bits; + char type[64]; + char ref[96]; + + if( table == NULL ) + { + errno = EINVAL; + return( -1 ); + } + + if( define_utf8(table, "_ARCH_MCPU", "1") != 0 || + define_quoted(table, "__MCPU_CPP_VERSION__", PACKAGE_VERSION) != 0 || + define_utf8(table, "__REGISTER_PREFIX__", "") != 0 || + define_utf8(table, "__LOCAL_LABEL_PREFIX__", "") != 0 || + define_utf8(table, "__USER_LABEL_PREFIX__", "") != 0 || + define_utf8(table, "__IMMEDIATE_PREFIX__", "") != 0 || + define_utf8(table, "__ORDER_LITTLE_ENDIAN__", "1234") != 0 || + define_utf8(table, "__ORDER_BIG_ENDIAN__", "4321") != 0 || + define_utf8(table, "__ORDER_PDP_ENDIAN__", "3412") != 0 ) + return( -1 ); + +#if MCPU_CPP_MPU_BYTE_ORDER == 1234 + if( define_utf8(table, "__MCPU_BYTE_ORDER__", "__ORDER_LITTLE_ENDIAN__") != 0 ) + return( -1 ); +#else + if( define_utf8(table, "__MCPU_BYTE_ORDER__", "__ORDER_BIG_ENDIAN__") != 0 ) + return( -1 ); +#endif + if( define_utf8(table, "__BYTE_ORDER__", "__MCPU_BYTE_ORDER__") != 0 ) + return( -1 ); + +#if MCPU_CPP_MPU_WORD_ORDER == 1234 + if( define_utf8(table, "__MCPU_WORD_ORDER__", "__ORDER_LITTLE_ENDIAN__") != 0 ) + return( -1 ); +#else + if( define_utf8(table, "__MCPU_WORD_ORDER__", "__ORDER_BIG_ENDIAN__") != 0 ) + return( -1 ); +#endif + + if( define_unsigned(table, "__MCPU_MACHINE_REGISTER_WIDTH__", + MCPU_CPP_MPU_REGISTER_WIDTH) != 0 || + define_unsigned(table, "__MCPU_REAL_IO_LIMIT__", + MCPU_CPP_MPU_REAL_IO_LIMIT) != 0 || + define_unsigned(table, "__MCPU_MATH_FN_LIMIT__", + MCPU_CPP_MPU_MATH_FN_LIMIT) != 0 || + define_unsigned(table, "__MCPU_INT_MAX_WIDTH__", + MCPU_CPP_MPU_INT_MAX_WIDTH) != 0 || + define_unsigned(table, "__MCPU_REAL_MAX_WIDTH__", + MCPU_CPP_MPU_REAL_IO_LIMIT) != 0 || + define_unsigned(table, "__MCPU_COMPLEX_MAX_WIDTH__", + MCPU_CPP_MPU_REAL_IO_LIMIT) != 0 || + define_unsigned(table, "__SIZEOF_POINTER__", 8) != 0 || + define_unsigned(table, "__MCPU_POINTER_WIDTH__", 64) != 0 || + define_unsigned(table, "__MCPU_SIZEOF_SIZE__", MCPU_CPP_SIZEOF_SIZE_T) != 0 || + define_unsigned(table, "__MCPU_SIZE_WIDTH__", MCPU_CPP_SIZE_WIDTH) != 0 || + define_unsigned(table, "__SIZEOF_PTRDIFF__", 8) != 0 || + define_unsigned(table, "__PTRDIFF_WIDTH__", 64) != 0 || + define_utf8(table, "__CHAR8_TYPE__", "char8") != 0 || + define_utf8(table, "__CHAR16_TYPE__", "char16") != 0 || + define_unsigned(table, "__CHAR8_WIDTH__", 8) != 0 || + define_unsigned(table, "__CHAR16_WIDTH__", 16) != 0 || + define_unsigned(table, "__SIZEOF_CHAR8__", 1) != 0 || + define_unsigned(table, "__SIZEOF_CHAR16__", 2) != 0 || + define_utf8(table, "__CHAR8_MAX__", "0xff") != 0 || + define_utf8(table, "__CHAR16_MAX__", "0xffff") != 0 ) + return( -1 ); + + for( bits = 8; bits != 0 && bits <= MCPU_CPP_MPU_INT_MAX_WIDTH; bits *= 2 ) + { + if( define_fixed_integer_family(table, bits) != 0 ) + return( -1 ); + } + + snprintf( type, sizeof(type), "uint%u", (unsigned)MCPU_CPP_SIZE_WIDTH ); + if( define_utf8(table, "__MCPU_SIZE_TYPE__", type) != 0 ) + return( -1 ); + snprintf( ref, sizeof(ref), "__UINT%u_MAX__", (unsigned)MCPU_CPP_SIZE_WIDTH ); + if( define_from_macro(table, "__MCPU_SIZE_MAX__", ref) != 0 ) + return( -1 ); + + snprintf( type, sizeof(type), "int%u", (unsigned)MCPU_CPP_SSIZE_WIDTH ); + if( define_utf8(table, "__MCPU_SSIZE_TYPE__", type) != 0 || + define_unsigned(table, "__MCPU_SSIZE_WIDTH__", MCPU_CPP_SSIZE_WIDTH) != 0 || + define_unsigned(table, "__MCPU_SIZEOF_SSIZE__", MCPU_CPP_SIZEOF_SSIZE_T) != 0 ) + return( -1 ); + if( MCPU_CPP_SSIZE_WIDTH <= 256 ) + { + snprintf( ref, sizeof(ref), "__INT%u_MAX__", (unsigned)MCPU_CPP_SSIZE_WIDTH ); + if( define_from_macro(table, "__MCPU_SSIZE_MAX__", ref) != 0 ) + return( -1 ); + } + + if( define_utf8(table, "__PTRDIFF_TYPE__", "int64") != 0 || + define_unsigned(table, "__PTRDIFF_WIDTH__", 64) != 0 || + define_utf8(table, "__PTRDIFF_MAX__", "0x7fffffffffffffff") != 0 || + define_utf8(table, "__INTPTR_TYPE__", "int64") != 0 || + define_utf8(table, "__UINTPTR_TYPE__", "uint64") != 0 || + define_unsigned(table, "__INTPTR_WIDTH__", 64) != 0 || + define_unsigned(table, "__UINTPTR_WIDTH__", 64) != 0 || + define_utf8(table, "__INTPTR_MAX__", "0x7fffffffffffffff") != 0 || + define_utf8(table, "__UINTPTR_MAX__", "0xffffffffffffffff") != 0 ) + return( -1 ); + + for( bits = 32; bits != 0 && bits <= MCPU_CPP_MPU_REAL_IO_LIMIT; bits *= 2 ) + { + if( define_real_family(table, bits) != 0 ) + return( -1 ); + } + + return( 0 ); +} |
