From: Thomas Walker Lynch Date: Mon, 13 Oct 2025 03:27:22 +0000 (+0000) Subject: no more pencils X-Git-Url: https://git.reasoningtechnology.com/style/rt_dark_doc.css?a=commitdiff_plain;h=c434dbe0995b4976b1e64f2456f5e7f94a20d710;p=N no more pencils --- diff --git a/developer/Python/fill_template b/developer/Python/fill_template new file mode 100755 index 0000000..67e57ec --- /dev/null +++ b/developer/Python/fill_template @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 + +import sys +from template_N import N + +def write(code ,basename): + filepath = "../cc/" + basename + ".lib.c" + with open(filepath, "w") as f: + f.write(code) + print("Generated " + filepath) + + +def main(): + """ + generates `.c` source code from templates + """ + + #---------------------------------------- + # N32 made from 1 digit, of 32 bits. + + type_name = "N32_1x32" + digit_type = "uint32_t" + digit_array_extent_type = "uint32_t" + digit_array_extent = 0 + address_type = "uint64_t" + + code = N( + type_name + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ) + write(code ,type_name); + + #---------------------------------------- + # N32 made from 4 digits, each 8 bits. + + type_name = "N32_1x32" + digit_type = "uint32_t" + digit_array_extent_type = "uint8_t" + digit_array_extent = 3 + address_type = "uint64_t" + + code = N( + type_name + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ) + write(code ,type_name); + +if __name__ == "__main__": + main() + diff --git a/developer/Python/make_N_constants.py b/developer/Python/make_N_constants.py new file mode 100755 index 0000000..6a51113 --- /dev/null +++ b/developer/Python/make_N_constants.py @@ -0,0 +1,59 @@ + +def make_N_constants( + namespace: str, + digit_type: str, + digit_array_extent: int +) -> str: + """ + Returns a block of code defining static compile-time constants: + static {namespace}T {namespace}constant[4] = { + { { ...zero... } }, + { { ...one... } }, + { { ...allbits... } }, + { { ...msb... } } + }; + + The total digit count is digit_array_extent + 1. + """ + digit_count = digit_array_extent + 1 + + def digits_zero(): + return ", ".join("0" for _ in range(digit_count)) + + def digits_one(): + # index 0 => 1, rest => 0 + return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) + + def digits_allbits(): + # each digit => (digit_type)(-1) + return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) + + def digits_msb(): + # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) + items = [] + for i in range(digit_count): + if i == digit_count - 1: + items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") + else: + items.append("0") + return ", ".join(items) + + return f''' +static {namespace}T {namespace}constant[4] = {{ + {{ + // zero + {{ {digits_zero()} }} + }}, + {{ + // one + {{ {digits_one()} }} + }}, + {{ + // all one bits + {{ {digits_allbits()} }} + }}, + {{ + // msb + {{ {digits_msb()} }} + }} +}};''' diff --git a/developer/Python/template_N.py b/developer/Python/template_N.py new file mode 100644 index 0000000..0d51033 --- /dev/null +++ b/developer/Python/template_N.py @@ -0,0 +1,574 @@ +from template_conversion import conversion +from make_N_constants import make_N_constants + +def N( + namespace + ,digit_type + ,digit_array_extent_type + ,digit_array_extent + ,address_type + ): + """ + Returns a source code file for cc to munch on. + """ + + template = template_N() + code = ( + template + .replace("NS" ,namespace) + .replace("DIGIT_TYPE" ,digit_type) + .replace("DIGIT_ARRAY_EXTENT_TYPE" ,str(digit_array_extent_type)) + .replace("DIGIT_ARRAY_EXTENT" ,str(digit_array_extent)) + .replace("ADDRESS_TYPE" ,address_type) + .replace("CONSTANTS_BLOCK" + ,make_N_constants(namespace ,digit_type ,digit_array_extent)) + .replace("CONV_8" ,conversion("uint8_t")) + .replace("CONV_16" ,conversion("uint16_t")) + .replace("CONV_32" ,conversion("uint32_t")) + .replace("CONV_64" ,conversion("uint64_t")) + .replace("CONV_128" ,conversion("__uint128_t")) + ) + + return code + +def template_N(): + return r''' +/* + M - The type for the function dictionary (manifold). + m - a manifold instance, there can be many, m0, m1 ... + T - Is the type for the tableau. + +*/ +#define NS·DEBUG + +#ifndef FACE +#define NS·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef NS·FACE +#define NS·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef ADDRESS_TYPE Address; + + // tableau type, encapsulated data is unavailable to user code + typedef struct NS·T NS·T; + + extern NS·T *NS·zero; + extern NS·T *NS·one; + extern NS·T *NS·all_one_bit; + extern NS·T *NS·lsb; + extern NS·T *NS·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + NS·Status·ok = 0 + ,NS·Status·overflow + ,NS·Status·accumulator_overflow + ,NS·Status·carry + ,NS·Status·borrow + ,NS·Status·undefined_divide_by_zero + ,NS·Status·undefined_modulus_zero + ,NS·Status·gt_max_shift_count + ,NS·Status·spill_eq_operand // not currently signaled, result will be spill value + ,NS·Status·one_word_product + ,NS·Status·two_word_product + } NS·Status; + + typedef enum{ + NS·Order_lt = -1 + ,NS·Order_eq = 0 + ,NS·Order_gt = 1 + } NS·Order; + + // when alloc runs out of memory + typedef NS·T *( *NS·Allocate_MemoryFault )(Address); + + //---------------------------------------- + // Interface + + // Incomplete conversion NS·T -> PNT, NS·T leftovers + typedef struct { + size_t scale; // this is in bytes + NS·T *d; // digits, programmer must point this to a register + } NS·Leftover_N; + + // Incomplete conversion PNT -> NS·T, PNT leftovers + #define NS·LEFTOVER_PNT(PNT)\ + typedef struct {\ + size_t scale; // this is in bytes\ + PNT leftover; // Residual value in PNT format\ + } NS·Leftover_##PNT; + + #define NS·WRITE(PNT) NS·Status (*write_##PNT)(const NS·T *, PNT *, NS·Leftover_N *) + #define NS·READ(PNT) NS·Status (*read_##PNT)(const PNT *, NS·T * ,NS·Leftover_##PNT *) + + typedef struct{ + + // memory allocation + NS·T *(*allocate_array_zero)(Address, NS·Allocate_MemoryFault); + NS·T *(*allocate_array)(Address, NS·Allocate_MemoryFault); + void (*deallocate)(NS·T*); + NS·T* (*access)(NS·T*, Address); + + // results fits in operand type functions + void (*copy)(NS·T*, NS·T*); + void (*bit_and)(NS·T*, NS·T*, NS·T*); + void (*bit_or)(NS·T*, NS·T*, NS·T*); + void (*bit_complement)(NS·T*, NS·T*); + void (*bit_twos_complement)(NS·T*, NS·T*); + + // tests + NS·Order (*compare)(NS·T*, NS·T*); + bool (*lt)(NS·T*, NS·T*); + bool (*gt)(NS·T*, NS·T*); + bool (*eq)(NS·T*, NS·T*); + bool (*eq_zero)(NS·T*); + + // arithmetic + NS·Status (*accumulate)(NS·T *accumulator1 ,NS·T *accumulator0 ,...); + NS·Status (*add)(NS·T*, NS·T*, NS·T*); + bool (*increment)(NS·T *a); + NS·Status (*subtract)(NS·T*, NS·T*, NS·T*); + NS·Status (*multiply)(NS·T*, NS·T*, NS·T*, NS·T*); + NS·Status (*divide)(NS·T*, NS·T*, NS·T*, NS·T*); + NS·Status (*modulus)(NS·T*, NS·T*, NS·T*); + + // shift + NS·Status (*shift_left)(Address, NS·T*, NS·T*, NS·T*); + NS·Status (*shift_right)(Address, NS·T*, NS·T*, NS·T*); + NS·Status (*arithmetic_shift_right)(Address, NS·T*, NS·T*); + + // import/export + char *(*to_hex)(NS·T *); + + #ifdef UINT8_MAX + NS·TO_TYPE(uint8_t) + NS·FROM_TYPE(uint8_t) + #endif + #ifdef UINT16_MAX + NS·TO_TYPE(uint16_t) + NS·FROM_TYPE(uint16_t) + #endif + #ifdef UINT32_MAX + NS·TO_TYPE(uint32_t) + NS·FROM_TYPE(uint32_t) + #endif + #ifdef UINT64_MAX + NS·TO_TYPE(uint64_t) + NS·FROM_TYPE(uint64_t) + #endif + #ifdef __UINT128_MAX + NS·TO_TYPE(__uint128_t) + NS·FROM_TYPE(__uint128_t) + #endif + + } NS·M; + + Local const NS·M NS·m; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef NS·IMPLEMENTATION + + typedef DIGIT_TYPE Digit; + const DIGIT_ARRAY_EXTENT_TYPE digit_array_extent = {DIGIT_ARRAY_EXTENT}; + + // full type definition for Tableau + struct NS·T{ + Digit d[digit_array_extent + 1]; + }; + + // this part goes into Nlib.a + #ifndef LOCAL + + #include + #include + #include + + // the allocate an array of N32 + NS·T *NS·allocate_array(Address extent ,NS·Allocate_MemoryFault memory_fault){ + NS·T *instance = malloc((extent + 1) * sizeof(NS·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + NS·T *NS·allocate_array_zero(Address extent ,NS·Allocate_MemoryFault memory_fault){ + NS·T *instance = calloc( extent + 1 ,sizeof(NS·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void NS·deallocate(NS·T *unencumbered){ + free(unencumbered); + } + + char *to_hex(NS·T *n) { + // Each byte requires two hex characters, plus "0x" prefix and null terminator + const Address string_length = (sizeof(Digit) * (digit_array_extent + 1) * 2) + 3; + char *buffer = malloc(string_length); + if (!buffer) { + return NULL; // Handle allocation failure + } + + strcpy(buffer, "0x"); // Prefix the hex representation + char *ps = buffer + 2; // Pointer to string buffer (after "0x") + + // Pointer to the most significant digit + Digit *pd = n->d + digit_array_extent; + + for (; pd >= n->d; pd--) { + sprintf(ps, "%0*X", (int)(sizeof(Digit) * 2), *pd); + ps += sizeof(Digit) * 2; // Move forward in buffer + } + + return buffer; // Caller must free the allocated buffer + } + + #endif + + // This part is included after the user's code. If the code at top is a 'header, then this is a 'tailer'. + #ifdef LOCAL + + #include "Copy.lib.c" + + CONSTANTS_BLOCK + + NS·T *NS·zero = NS·constant + 0; + NS·T *NS·one = NS·constant + 1; + NS·T *NS·all_one_bit = NS·constant + 2; + NS·T *NS·msb = &NS·constant + 3; + NS·T *NS·lsb = &NS·constant + 1; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local NS·T NS·t[4]; + + + // allocation + + extern NS·T *NS·allocate_array(Address, NS·Allocate_MemoryFault); + extern NS·T *NS·allocate_array_zero(Address, NS·Allocate_MemoryFault); + extern void NS·deallocate(NS·T *); + + // so the user can access numbers in an array allocation + Local NS·T* NS·access(NS·T *array ,Address index){ + return array + index; + } + + // copy, convenience copy + + Local void NS·copy(NS·T *destination ,NS·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void NS·set_to_zero(NS·T *instance){ + instance->d0 = 0; + } + + Local void NS·set_to_one(NS·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void NS·bit_and(NS·T *result, NS·T *a, NS·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void NS·bit_or(NS·T *result, NS·T *a, NS·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void NS·bit_complement(NS·T *result, NS·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void NS·bit_twos_complement(NS·T *result ,NS·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local NS·Order NS·compare(NS·T *a, NS·T *b){ + if(a->d0 < b->d0) return NS·Order_lt; + if(a->d0 > b->d0) return NS·Order_gt; + return NS·Order_eq; + } + + Local bool NS·lt(NS·T *a ,NS·T *b){ + return a->d0 < b->d0; + } + + Local bool NS·gt(NS·T *a ,NS·T *b){ + return a->d0 > b->d0; + } + + Local bool NS·eq(NS·T *a ,NS·T *b){ + return a->d0 == b->d0; + } + + Local bool NS·eq_zero(NS·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return NS·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local NS·Status NS·accumulate(NS·T *accumulator1 ,NS·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + NS·T *current; + + while( (current = va_arg(args ,NS·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return NS·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return NS·Status·ok; + } + + Local NS·Status NS·add(NS·T *sum ,NS·T *a ,NS·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? NS·Status·carry : NS·Status·ok; + } + + Local bool NS·increment(NS·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local NS·Status NS·subtract(NS·T *difference ,NS·T *a ,NS·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? NS·Status·borrow : NS·Status·ok; + } + + Local NS·Status NS·multiply(NS·T *product1 ,NS·T *product0 ,NS·T *a ,NS·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return NS·Status·one_word_product; + return NS·Status·two_word_product; + } + + Local NS·Status NS·divide(NS·T *remainder ,NS·T *quotient ,NS·T *a ,NS·T *b){ + if(b->d0 == 0) return NS·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return NS·Status·ok; + } + + Local NS·Status NS·modulus(NS·T *remainder ,NS·T *a ,NS·T *b){ + if(b->d0 == 0) return NS·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return NS·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local NS·Status NS·shift + ( + uint32_t shift_count + ,NS·T *spill + ,NS·T *operand + ,NS·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return NS·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &NS·t[0]; + NS·copy(operand, NS·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return NS·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + NS·T *given_operand = &NS·t[1]; + NS·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + NS·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return NS·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local NS·Status + NS·shift_left(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ + return NS·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local NS·Status + NS·shift_right(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ + return NS·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local NS·Status + NS·arithmetic_shift_right(uint32_t shift_count, NS·T *operand, NS·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return NS·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &NS·t[0]; + NS·copy(operand, NS·zero); + } + + // Pick the fill value based on the sign bit + NS·T *fill = (operand->d0 & 0x80000000) ? NS·all_one_bit : NS·zero; + + // Call shift_right with the appropriate fill + return NS·shift_right(shift_count, spill, operand, fill); + } + + #ifdef UINT8_MAX + #endif + #ifdef UINT16_MAX + #endif + #ifdef UINT32_MAX + #endif + #ifdef UINT64_MAX + #endif + #ifdef __UINT128_MAX + #endif + + Local const NS·M NS·m = { + + .allocate_array = NS·allocate_array + ,.allocate_array_zero = NS·allocate_array_zero + ,.deallocate = NS·deallocate + + ,.copy = NS·copy + ,.bit_and = NS·bit_and + ,.bit_or = NS·bit_or + ,.bit_complement = NS·bit_complement + ,.bit_twos_complement = NS·bit_twos_complement + ,.compare = NS·compare + ,.lt = NS·lt + ,.gt = NS·gt + ,.eq = NS·eq + ,.eq_zero = NS·eq_zero + ,.accumulate = NS·accumulate + ,.add = NS·add + ,.increment = NS·increment + ,.subtract = NS·subtract + ,.multiply = NS·multiply + ,.divide = NS·divide + ,.modulus = NS·modulus + ,.shift_left = NS·shift_left + ,.shift_right = NS·shift_right + ,.arithmetic_shift_right = NS·arithmetic_shift_right + + ,.access = NS·access + ,.from_uint32 = NS·from_uint32 + + #ifdef UINT8_MAX + ,.to_uint8_t = NS·to_uint8_t + ,.from_uint8_t = NS·from_uint8_t + #endif + #ifdef UINT16_MAX + ,.to_uint16_t = NS·to_uint16_t + ,.from_uint16_t = NS·from_uint16_t + #endif + #ifdef UINT32_MAX + ,.to_uint32_t = NS·to_uint32_t + ,.from_uint32_t = NS·from_uint32_t + #endif + #ifdef UINT64_MAX + ,.to_uint64_t = NS·to_uint64_t + ,.from_uint64_t = NS·from_uint64_t + #endif + #ifdef __UINT128_MAX + ,.to___uint128_t = NS·to___uint128_t + ,.from___uint128_t = NS·from___uint128_t + #endif + + }; + + #undef FACE + #include "Copy.lib.c" + + #endif // LOCAL + +#endif // IMPLEMENTATION +''' + + + + diff --git a/developer/Python/template_conversion.py b/developer/Python/template_conversion.py new file mode 100644 index 0000000..d751cdd --- /dev/null +++ b/developer/Python/template_conversion.py @@ -0,0 +1,94 @@ + +# gt_extent_type is large enough to hold a sizeof(NS·T)-1 or sizeof(TYPE)-1 +def conversion(type: str): + """ + Returns a source code file for cc to munch on + """ + template = template_conversion() + code = template.replace("TYPE", type) + return code + +# The Digit array is always least significant digit at d[0] +def template_conversion(): + return r''' + +// NS·T -> PNT, possible NS·T leftovers +NS·Status NS·to_TYPE + ( + const NS·T *source + ,TYPE *destination + ,NS·Leftover_N *leftover + ){ + + uint8_t *s = (uint8_t *)source; + uint8_t *d = (uint8_t *)destination; + + if( sizeof(NS·T) <= sizeof(TYPE) ){ + *destination = 0; + memcpy( d, s, sizeof(NS·T) ); + return NS·Status·ok; + } + + memcpy( destination ,s ,sizeof(TYPE) ); + s += sizeof(TYPE); + const size_t δ = sizeof(NS·T) - sizeof(TYPE); + + if( memcmp(NS·constant + 0 ,s ,δ) == 0 ){ + return NS·Status·ok; + } + // else there are leftovers + + if( leftover == NULL || leftover->d == NULL){ // then nowhere to put the leftovers + return NS·Status·ConversionOverflow; + } + + // copy the part leftover into the leftover struct + leftover->scale = sizeof(TYPE); + uint8_t *lod = (uint8_t *)(leftover->d); + memcpy(lod ,s ,δ); + + // zero out the upper bytes of the leftover struct + lod += δ; + memset(lod, 0, sizeof(NS·T) - δ); // Zero remaining bytes safely + + return NS·Status·ConversionOverflow; +} + +// PNT -> NS·T, possible PNT leftovers +NS·Status NS·from_TYPE + ( + const TYPE *s // source + ,NS·T *destination + ,NS·Leftover_PNT *leftover + ){ + + uint8_t *d = (uint8_t *)destination; // NS·T + + // source allocation smaller: copy then zero out the top of destination + if( sizeof(TYPE) <= sizeof(NS·T) ){ + memcpy( d, s, sizeof(TYPE) ); + d += sizeof(TYPE); + memset( d, 0, sizeof(NS·T) - sizeof(TYPE) ); // Zero out remaining bytes + return NS·Status·ok; + } + + // The source allocation is larger: copy then potentially spill to leftovers + + memcpy( d, s, sizeof(NS·T) ); + + TYPE mask = ~(TYPE)0 << (sizeof(NS·T) << 3); + TYPE unscaled_leftover = *source & mask; + + if(unscaled_leftover == 0) return NS·Status·ok; + + if(leftover == NULL){ // then nowhere to put the leftovers + return NS·Status·ConversionOverflow; + } + + leftover->scale = sizeof(NS·T); + leftover->leftover = unscaled_leftover >> (sizeof(NS·T) << 3); + + return NS·Status·ConversionOverflow; + +} +''' diff --git "a/developer/Python\360\237\226\211/fill_template" "b/developer/Python\360\237\226\211/fill_template" deleted file mode 100755 index 67e57ec..0000000 --- "a/developer/Python\360\237\226\211/fill_template" +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 - -import sys -from template_N import N - -def write(code ,basename): - filepath = "../cc/" + basename + ".lib.c" - with open(filepath, "w") as f: - f.write(code) - print("Generated " + filepath) - - -def main(): - """ - generates `.c` source code from templates - """ - - #---------------------------------------- - # N32 made from 1 digit, of 32 bits. - - type_name = "N32_1x32" - digit_type = "uint32_t" - digit_array_extent_type = "uint32_t" - digit_array_extent = 0 - address_type = "uint64_t" - - code = N( - type_name - ,digit_type - ,digit_array_extent_type - ,digit_array_extent - ,address_type - ) - write(code ,type_name); - - #---------------------------------------- - # N32 made from 4 digits, each 8 bits. - - type_name = "N32_1x32" - digit_type = "uint32_t" - digit_array_extent_type = "uint8_t" - digit_array_extent = 3 - address_type = "uint64_t" - - code = N( - type_name - ,digit_type - ,digit_array_extent_type - ,digit_array_extent - ,address_type - ) - write(code ,type_name); - -if __name__ == "__main__": - main() - diff --git "a/developer/Python\360\237\226\211/make_N_constants.py" "b/developer/Python\360\237\226\211/make_N_constants.py" deleted file mode 100755 index 6a51113..0000000 --- "a/developer/Python\360\237\226\211/make_N_constants.py" +++ /dev/null @@ -1,59 +0,0 @@ - -def make_N_constants( - namespace: str, - digit_type: str, - digit_array_extent: int -) -> str: - """ - Returns a block of code defining static compile-time constants: - static {namespace}T {namespace}constant[4] = { - { { ...zero... } }, - { { ...one... } }, - { { ...allbits... } }, - { { ...msb... } } - }; - - The total digit count is digit_array_extent + 1. - """ - digit_count = digit_array_extent + 1 - - def digits_zero(): - return ", ".join("0" for _ in range(digit_count)) - - def digits_one(): - # index 0 => 1, rest => 0 - return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) - - def digits_allbits(): - # each digit => (digit_type)(-1) - return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) - - def digits_msb(): - # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) - items = [] - for i in range(digit_count): - if i == digit_count - 1: - items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") - else: - items.append("0") - return ", ".join(items) - - return f''' -static {namespace}T {namespace}constant[4] = {{ - {{ - // zero - {{ {digits_zero()} }} - }}, - {{ - // one - {{ {digits_one()} }} - }}, - {{ - // all one bits - {{ {digits_allbits()} }} - }}, - {{ - // msb - {{ {digits_msb()} }} - }} -}};''' diff --git "a/developer/Python\360\237\226\211/template_N.py" "b/developer/Python\360\237\226\211/template_N.py" deleted file mode 100644 index 0d51033..0000000 --- "a/developer/Python\360\237\226\211/template_N.py" +++ /dev/null @@ -1,574 +0,0 @@ -from template_conversion import conversion -from make_N_constants import make_N_constants - -def N( - namespace - ,digit_type - ,digit_array_extent_type - ,digit_array_extent - ,address_type - ): - """ - Returns a source code file for cc to munch on. - """ - - template = template_N() - code = ( - template - .replace("NS" ,namespace) - .replace("DIGIT_TYPE" ,digit_type) - .replace("DIGIT_ARRAY_EXTENT_TYPE" ,str(digit_array_extent_type)) - .replace("DIGIT_ARRAY_EXTENT" ,str(digit_array_extent)) - .replace("ADDRESS_TYPE" ,address_type) - .replace("CONSTANTS_BLOCK" - ,make_N_constants(namespace ,digit_type ,digit_array_extent)) - .replace("CONV_8" ,conversion("uint8_t")) - .replace("CONV_16" ,conversion("uint16_t")) - .replace("CONV_32" ,conversion("uint32_t")) - .replace("CONV_64" ,conversion("uint64_t")) - .replace("CONV_128" ,conversion("__uint128_t")) - ) - - return code - -def template_N(): - return r''' -/* - M - The type for the function dictionary (manifold). - m - a manifold instance, there can be many, m0, m1 ... - T - Is the type for the tableau. - -*/ -#define NS·DEBUG - -#ifndef FACE -#define NS·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef NS·FACE -#define NS·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef ADDRESS_TYPE Address; - - // tableau type, encapsulated data is unavailable to user code - typedef struct NS·T NS·T; - - extern NS·T *NS·zero; - extern NS·T *NS·one; - extern NS·T *NS·all_one_bit; - extern NS·T *NS·lsb; - extern NS·T *NS·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum{ - NS·Status·ok = 0 - ,NS·Status·overflow - ,NS·Status·accumulator_overflow - ,NS·Status·carry - ,NS·Status·borrow - ,NS·Status·undefined_divide_by_zero - ,NS·Status·undefined_modulus_zero - ,NS·Status·gt_max_shift_count - ,NS·Status·spill_eq_operand // not currently signaled, result will be spill value - ,NS·Status·one_word_product - ,NS·Status·two_word_product - } NS·Status; - - typedef enum{ - NS·Order_lt = -1 - ,NS·Order_eq = 0 - ,NS·Order_gt = 1 - } NS·Order; - - // when alloc runs out of memory - typedef NS·T *( *NS·Allocate_MemoryFault )(Address); - - //---------------------------------------- - // Interface - - // Incomplete conversion NS·T -> PNT, NS·T leftovers - typedef struct { - size_t scale; // this is in bytes - NS·T *d; // digits, programmer must point this to a register - } NS·Leftover_N; - - // Incomplete conversion PNT -> NS·T, PNT leftovers - #define NS·LEFTOVER_PNT(PNT)\ - typedef struct {\ - size_t scale; // this is in bytes\ - PNT leftover; // Residual value in PNT format\ - } NS·Leftover_##PNT; - - #define NS·WRITE(PNT) NS·Status (*write_##PNT)(const NS·T *, PNT *, NS·Leftover_N *) - #define NS·READ(PNT) NS·Status (*read_##PNT)(const PNT *, NS·T * ,NS·Leftover_##PNT *) - - typedef struct{ - - // memory allocation - NS·T *(*allocate_array_zero)(Address, NS·Allocate_MemoryFault); - NS·T *(*allocate_array)(Address, NS·Allocate_MemoryFault); - void (*deallocate)(NS·T*); - NS·T* (*access)(NS·T*, Address); - - // results fits in operand type functions - void (*copy)(NS·T*, NS·T*); - void (*bit_and)(NS·T*, NS·T*, NS·T*); - void (*bit_or)(NS·T*, NS·T*, NS·T*); - void (*bit_complement)(NS·T*, NS·T*); - void (*bit_twos_complement)(NS·T*, NS·T*); - - // tests - NS·Order (*compare)(NS·T*, NS·T*); - bool (*lt)(NS·T*, NS·T*); - bool (*gt)(NS·T*, NS·T*); - bool (*eq)(NS·T*, NS·T*); - bool (*eq_zero)(NS·T*); - - // arithmetic - NS·Status (*accumulate)(NS·T *accumulator1 ,NS·T *accumulator0 ,...); - NS·Status (*add)(NS·T*, NS·T*, NS·T*); - bool (*increment)(NS·T *a); - NS·Status (*subtract)(NS·T*, NS·T*, NS·T*); - NS·Status (*multiply)(NS·T*, NS·T*, NS·T*, NS·T*); - NS·Status (*divide)(NS·T*, NS·T*, NS·T*, NS·T*); - NS·Status (*modulus)(NS·T*, NS·T*, NS·T*); - - // shift - NS·Status (*shift_left)(Address, NS·T*, NS·T*, NS·T*); - NS·Status (*shift_right)(Address, NS·T*, NS·T*, NS·T*); - NS·Status (*arithmetic_shift_right)(Address, NS·T*, NS·T*); - - // import/export - char *(*to_hex)(NS·T *); - - #ifdef UINT8_MAX - NS·TO_TYPE(uint8_t) - NS·FROM_TYPE(uint8_t) - #endif - #ifdef UINT16_MAX - NS·TO_TYPE(uint16_t) - NS·FROM_TYPE(uint16_t) - #endif - #ifdef UINT32_MAX - NS·TO_TYPE(uint32_t) - NS·FROM_TYPE(uint32_t) - #endif - #ifdef UINT64_MAX - NS·TO_TYPE(uint64_t) - NS·FROM_TYPE(uint64_t) - #endif - #ifdef __UINT128_MAX - NS·TO_TYPE(__uint128_t) - NS·FROM_TYPE(__uint128_t) - #endif - - } NS·M; - - Local const NS·M NS·m; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef NS·IMPLEMENTATION - - typedef DIGIT_TYPE Digit; - const DIGIT_ARRAY_EXTENT_TYPE digit_array_extent = {DIGIT_ARRAY_EXTENT}; - - // full type definition for Tableau - struct NS·T{ - Digit d[digit_array_extent + 1]; - }; - - // this part goes into Nlib.a - #ifndef LOCAL - - #include - #include - #include - - // the allocate an array of N32 - NS·T *NS·allocate_array(Address extent ,NS·Allocate_MemoryFault memory_fault){ - NS·T *instance = malloc((extent + 1) * sizeof(NS·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - NS·T *NS·allocate_array_zero(Address extent ,NS·Allocate_MemoryFault memory_fault){ - NS·T *instance = calloc( extent + 1 ,sizeof(NS·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void NS·deallocate(NS·T *unencumbered){ - free(unencumbered); - } - - char *to_hex(NS·T *n) { - // Each byte requires two hex characters, plus "0x" prefix and null terminator - const Address string_length = (sizeof(Digit) * (digit_array_extent + 1) * 2) + 3; - char *buffer = malloc(string_length); - if (!buffer) { - return NULL; // Handle allocation failure - } - - strcpy(buffer, "0x"); // Prefix the hex representation - char *ps = buffer + 2; // Pointer to string buffer (after "0x") - - // Pointer to the most significant digit - Digit *pd = n->d + digit_array_extent; - - for (; pd >= n->d; pd--) { - sprintf(ps, "%0*X", (int)(sizeof(Digit) * 2), *pd); - ps += sizeof(Digit) * 2; // Move forward in buffer - } - - return buffer; // Caller must free the allocated buffer - } - - #endif - - // This part is included after the user's code. If the code at top is a 'header, then this is a 'tailer'. - #ifdef LOCAL - - #include "Copy.lib.c" - - CONSTANTS_BLOCK - - NS·T *NS·zero = NS·constant + 0; - NS·T *NS·one = NS·constant + 1; - NS·T *NS·all_one_bit = NS·constant + 2; - NS·T *NS·msb = &NS·constant + 3; - NS·T *NS·lsb = &NS·constant + 1; - - // temporary variables - // making these LOCAL rather than reserving one block in the library is thread safe - // allocating a block once is more efficient - // library code writes these, they are not on the interface - - Local NS·T NS·t[4]; - - - // allocation - - extern NS·T *NS·allocate_array(Address, NS·Allocate_MemoryFault); - extern NS·T *NS·allocate_array_zero(Address, NS·Allocate_MemoryFault); - extern void NS·deallocate(NS·T *); - - // so the user can access numbers in an array allocation - Local NS·T* NS·access(NS·T *array ,Address index){ - return array + index; - } - - // copy, convenience copy - - Local void NS·copy(NS·T *destination ,NS·T *source){ - if(source == destination) return; // that was easy! - *destination = *source; - } - - Local void NS·set_to_zero(NS·T *instance){ - instance->d0 = 0; - } - - Local void NS·set_to_one(NS·T *instance){ - instance->d0 = 1; - } - - // bit operations - - Local void NS·bit_and(NS·T *result, NS·T *a, NS·T *b){ - result->d0 = a->d0 & b->d0; - } - - // result can be one of the operands - Local void NS·bit_or(NS·T *result, NS·T *a, NS·T *b){ - result->d0 = a->d0 | b->d0; - } - - // result can the same as the operand - Local void NS·bit_complement(NS·T *result, NS·T *a){ - result->d0 = ~a->d0; - } - - // result can the same as the operand - Local void NS·bit_twos_complement(NS·T *result ,NS·T *a){ - result->d0 = ~a->d0 + 1; - } - - // test functions - - Local NS·Order NS·compare(NS·T *a, NS·T *b){ - if(a->d0 < b->d0) return NS·Order_lt; - if(a->d0 > b->d0) return NS·Order_gt; - return NS·Order_eq; - } - - Local bool NS·lt(NS·T *a ,NS·T *b){ - return a->d0 < b->d0; - } - - Local bool NS·gt(NS·T *a ,NS·T *b){ - return a->d0 > b->d0; - } - - Local bool NS·eq(NS·T *a ,NS·T *b){ - return a->d0 == b->d0; - } - - Local bool NS·eq_zero(NS·T *a){ - return a->d0 == 0; - } - - - // arithmetic operations - - // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return NS·Status·accumulator1_overflow - // - // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. - Local NS·Status NS·accumulate(NS·T *accumulator1 ,NS·T *accumulator0 ,...){ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - NS·T *current; - - while( (current = va_arg(args ,NS·T *)) ){ - sum += current->d0; - if(sum < current->d0){ // Accumulator1 into carry - (carry)++; - if(carry == 0){ - va_end(args); - return NS·Status·accumulator1_overflow; - } - } - } - va_end(args); - - // wipes out prior value of accumulator1 - accumulator1->d0 = carry; - - return NS·Status·ok; - } - - Local NS·Status NS·add(NS·T *sum ,NS·T *a ,NS·T *b){ - uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; - sum->d0 = (uint32_t)result; - return (result >> 32) ? NS·Status·carry : NS·Status·ok; - } - - Local bool NS·increment(NS·T *a){ - a->d0++; - return a->d0 == 0; - } - - Local NS·Status NS·subtract(NS·T *difference ,NS·T *a ,NS·T *b){ - uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; - difference->d0 = (uint32_t)diff; - return (diff > a->d0) ? NS·Status·borrow : NS·Status·ok; - } - - Local NS·Status NS·multiply(NS·T *product1 ,NS·T *product0 ,NS·T *a ,NS·T *b){ - uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; - product0->d0 = (uint32_t)product; - product1->d0 = (uint32_t)(product >> 32); - - if(product1->d0 == 0) return NS·Status·one_word_product; - return NS·Status·two_word_product; - } - - Local NS·Status NS·divide(NS·T *remainder ,NS·T *quotient ,NS·T *a ,NS·T *b){ - if(b->d0 == 0) return NS·Status·undefined_divide_by_zero; - - quotient->d0 = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient->d0 * b->d0); - - return NS·Status·ok; - } - - Local NS·Status NS·modulus(NS·T *remainder ,NS·T *a ,NS·T *b){ - if(b->d0 == 0) return NS·Status·undefined_modulus_zero; - uint32_t quotient = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient * b->d0); - return NS·Status·ok; - } - - // bit motion - - typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); - - Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ - return value << amount; - } - - Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ - return value >> amount; - } - - // modifies all three of its operands - // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, - Local NS·Status NS·shift - ( - uint32_t shift_count - ,NS·T *spill - ,NS·T *operand - ,NS·T *fill - ,ShiftOp shift_op - ,ShiftOp complement_shift_op - ){ - - // If no result is needed, return immediately. - if(operand == NULL && spill == NULL) return NS·Status·ok; - - // Treat NULL operand as zero. - if(operand == NULL){ - operand = &NS·t[0]; - NS·copy(operand, NS·zero); - } - - // Shifting more than one word breaks our fill/spill model. - if(shift_count > 31) return NS·Status·gt_max_shift_count; - - // The given operand is still required after it is modified, so we copy it. - NS·T *given_operand = &NS·t[1]; - NS·copy(given_operand, operand); - - // Perform the shift - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); - NS·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); - } - - return NS·Status·ok; - } - - // Define concrete shift functions using valid C function pointers - Local NS·Status - NS·shift_left(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ - return NS·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local NS·Status - NS·shift_right(uint32_t shift_count, NS·T *spill, NS·T *operand, NS·T *fill){ - return NS·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local NS·Status - NS·arithmetic_shift_right(uint32_t shift_count, NS·T *operand, NS·T *spill){ - - // Guard against excessive shift counts - if(shift_count > 31) return NS·Status·gt_max_shift_count; - - // A NULL operand is treated as zero - if(operand == NULL){ - operand = &NS·t[0]; - NS·copy(operand, NS·zero); - } - - // Pick the fill value based on the sign bit - NS·T *fill = (operand->d0 & 0x80000000) ? NS·all_one_bit : NS·zero; - - // Call shift_right with the appropriate fill - return NS·shift_right(shift_count, spill, operand, fill); - } - - #ifdef UINT8_MAX - #endif - #ifdef UINT16_MAX - #endif - #ifdef UINT32_MAX - #endif - #ifdef UINT64_MAX - #endif - #ifdef __UINT128_MAX - #endif - - Local const NS·M NS·m = { - - .allocate_array = NS·allocate_array - ,.allocate_array_zero = NS·allocate_array_zero - ,.deallocate = NS·deallocate - - ,.copy = NS·copy - ,.bit_and = NS·bit_and - ,.bit_or = NS·bit_or - ,.bit_complement = NS·bit_complement - ,.bit_twos_complement = NS·bit_twos_complement - ,.compare = NS·compare - ,.lt = NS·lt - ,.gt = NS·gt - ,.eq = NS·eq - ,.eq_zero = NS·eq_zero - ,.accumulate = NS·accumulate - ,.add = NS·add - ,.increment = NS·increment - ,.subtract = NS·subtract - ,.multiply = NS·multiply - ,.divide = NS·divide - ,.modulus = NS·modulus - ,.shift_left = NS·shift_left - ,.shift_right = NS·shift_right - ,.arithmetic_shift_right = NS·arithmetic_shift_right - - ,.access = NS·access - ,.from_uint32 = NS·from_uint32 - - #ifdef UINT8_MAX - ,.to_uint8_t = NS·to_uint8_t - ,.from_uint8_t = NS·from_uint8_t - #endif - #ifdef UINT16_MAX - ,.to_uint16_t = NS·to_uint16_t - ,.from_uint16_t = NS·from_uint16_t - #endif - #ifdef UINT32_MAX - ,.to_uint32_t = NS·to_uint32_t - ,.from_uint32_t = NS·from_uint32_t - #endif - #ifdef UINT64_MAX - ,.to_uint64_t = NS·to_uint64_t - ,.from_uint64_t = NS·from_uint64_t - #endif - #ifdef __UINT128_MAX - ,.to___uint128_t = NS·to___uint128_t - ,.from___uint128_t = NS·from___uint128_t - #endif - - }; - - #undef FACE - #include "Copy.lib.c" - - #endif // LOCAL - -#endif // IMPLEMENTATION -''' - - - - diff --git "a/developer/Python\360\237\226\211/template_conversion.py" "b/developer/Python\360\237\226\211/template_conversion.py" deleted file mode 100644 index d751cdd..0000000 --- "a/developer/Python\360\237\226\211/template_conversion.py" +++ /dev/null @@ -1,94 +0,0 @@ - -# gt_extent_type is large enough to hold a sizeof(NS·T)-1 or sizeof(TYPE)-1 -def conversion(type: str): - """ - Returns a source code file for cc to munch on - """ - template = template_conversion() - code = template.replace("TYPE", type) - return code - -# The Digit array is always least significant digit at d[0] -def template_conversion(): - return r''' - -// NS·T -> PNT, possible NS·T leftovers -NS·Status NS·to_TYPE - ( - const NS·T *source - ,TYPE *destination - ,NS·Leftover_N *leftover - ){ - - uint8_t *s = (uint8_t *)source; - uint8_t *d = (uint8_t *)destination; - - if( sizeof(NS·T) <= sizeof(TYPE) ){ - *destination = 0; - memcpy( d, s, sizeof(NS·T) ); - return NS·Status·ok; - } - - memcpy( destination ,s ,sizeof(TYPE) ); - s += sizeof(TYPE); - const size_t δ = sizeof(NS·T) - sizeof(TYPE); - - if( memcmp(NS·constant + 0 ,s ,δ) == 0 ){ - return NS·Status·ok; - } - // else there are leftovers - - if( leftover == NULL || leftover->d == NULL){ // then nowhere to put the leftovers - return NS·Status·ConversionOverflow; - } - - // copy the part leftover into the leftover struct - leftover->scale = sizeof(TYPE); - uint8_t *lod = (uint8_t *)(leftover->d); - memcpy(lod ,s ,δ); - - // zero out the upper bytes of the leftover struct - lod += δ; - memset(lod, 0, sizeof(NS·T) - δ); // Zero remaining bytes safely - - return NS·Status·ConversionOverflow; -} - -// PNT -> NS·T, possible PNT leftovers -NS·Status NS·from_TYPE - ( - const TYPE *s // source - ,NS·T *destination - ,NS·Leftover_PNT *leftover - ){ - - uint8_t *d = (uint8_t *)destination; // NS·T - - // source allocation smaller: copy then zero out the top of destination - if( sizeof(TYPE) <= sizeof(NS·T) ){ - memcpy( d, s, sizeof(TYPE) ); - d += sizeof(TYPE); - memset( d, 0, sizeof(NS·T) - sizeof(TYPE) ); // Zero out remaining bytes - return NS·Status·ok; - } - - // The source allocation is larger: copy then potentially spill to leftovers - - memcpy( d, s, sizeof(NS·T) ); - - TYPE mask = ~(TYPE)0 << (sizeof(NS·T) << 3); - TYPE unscaled_leftover = *source & mask; - - if(unscaled_leftover == 0) return NS·Status·ok; - - if(leftover == NULL){ // then nowhere to put the leftovers - return NS·Status·ConversionOverflow; - } - - leftover->scale = sizeof(NS·T); - leftover->leftover = unscaled_leftover >> (sizeof(NS·T) << 3); - - return NS·Status·ConversionOverflow; - -} -''' diff --git "a/developer/cc\360\237\226\211/Core.lib.c" "b/developer/cc\360\237\226\211/Core.lib.c" deleted file mode 100644 index ec6a658..0000000 --- "a/developer/cc\360\237\226\211/Core.lib.c" +++ /dev/null @@ -1,241 +0,0 @@ -/* - Core - core memory operations. - - Abbreviations used in comments: - - 'ATP' `At This Point' in the code. Acronym used in comments usually before pointing - out certain values variables must have. - - 'AToW' - At Time of Writing ,also used in comments. - - Abbreviations used in identifiers: - - `AU` `Addressable Unit for the machine`. The C standard leaves this open to definition by the architecture and calls it `char`. On most all machines today it is uint8_t; - - We use structs to group functions into a namespace. When all the functions that have a specific type of given argument are group together ,we call the table a 'Functions Given Type X table' ,or 'PFT table' for short. A specific instance of an PFT table is an `pft` table. - -*/ - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ -#ifndef Core·FACE -#define Core·FACE - - #define Core·DEBUG - #ifdef PFT·DEBUG - #include - #endif - - #include - #include - #include - #include - #include "cpp_ext.c" - - //---------------------------------------- - // memory interface - - // extent is the maximum index in an address space ,tape or area ,the doted - // unit is the cell type. - typedef size_t extent_t·AU; - #define extent_of·AU(x) (sizeof(x) - 1) - // Funny ,we seldom check for this ,perhaps that matters on some tiny machine. - #define extent_of·AU_address_space ~(uintptr)0; - - // addressable unit for the machine - // C language standard left this undefined. AToW industry uses uint8_t. - typedef uint8_t AU ; - typedef uint16_t AU2; - typedef uint32_t AU4; - typedef uint64_t AU8; - - const AU AU_MAX = (~(AU)0); - const AU2 AU2_MAX = (~(AU2)0); - const AU4 AU4_MAX = (~(AU4)0); - const AU8 AU8_MAX = (~(AU8)0); - - // ask the compiler what this is - // when using enums we get this whether we want it or not - typedef unsigned int WU; - const WU WU_MAX = (~(WU)0); - - //---------------------------------------- - // flag facility ,argument guard facility - - typedef enum{ - Core·Status·mu = 0 - ,Core·Status·on_track - ,Core·Status·derailed - }Core·Status; - - typedef void (*Core·Flag·Fn)(WU *flag ,WU err); - - void Core·Flag·count(WU *flag ,WU err){ - if(err == WU_MAX){ *flag = WU_MAX; return;} - - //*flag + err > WU_MAX - if(*flag > WU_MAX - err){ *flag = WU_MAX; return;} - - (*flag) += err; - } - - void Core·Flag·collect(WU *flag ,WU err){ - (*flag) |= err; - } - - typedef struct { - const char *name; - Core·Flag·Fn flag_function; - WU flag; - } Core·Guard; - - typedef struct { - void (*init)(Core·Guard *chk ,const char *name ,Core·Flag·Fn af); - void (*reset)(Core·Guard *chk); - void (*check)( - Core·Guard *chk - ,WU err - ,bool condition - ,char *message - ); - } Core·Guard·PFT; - - // Default guard function table - // initialized in the implementation section below - Local Core·Guard·PFT Core·Guard·pft; - - #define Core·Guard·init_count(chk) \ - Core·Guard chk; \ - Core·Guard·pft.init(&chk ,__func__ ,Core·Flag·count); - - #define Core·Guard·init_collect(chk) \ - Core·Guard chk; \ - Core·Guard·pft.init(&chk ,__func__ ,Core·Flag·collect); - - #define Core·Guard·if_return(chk) if( chk.flag ) return Core·Status·derailed; - #define Core·Guard·return(chk)\ - if( chk.flag ) return Core·Status·derailed;\ - else return Core·Status·on_track; - #define Core·Guard·assert(chk) assert(!chk.flag); - - //---------------------------------------- - // functions interface - - // no state ,this is merely a namespace - - typedef struct{ - Core·Status (*on_track)(); - Core·Status (*derailed)(); - Core·Status (*is_aligned)(AU *p ,extent_t·AU alignment ,bool *flag); - Core·Status (*round_down)(AU *p ,extent_t·AU alignment ,AU **result); - Core·Status (*round_up)(AU *p ,extent_t·AU alignment ,AU **result); - } Core·F; - Local Core·F Core·f; - -#endif // #if CORE·FACE - - -/*-------------------------------------------------------------------------------- - Local - at bottom of translation unit, to keep some functions private - --------------------------------------------------------------------------------*/ -#ifdef LOCAL - -// once per translation unit -#ifndef Core·LOCAL -#define Core·LOCAL - - //---------------------------------------- - // argument guard implementation - - Local void Core·Guard·init(Core·Guard *chk ,const char *name ,Core·Flag·Fn af){ - if(!chk) return; - chk->name = name; - chk->flag_function = af; - chk->flag = 0; - } - - Local void Core·Guard·reset(Core·Guard *chk){ - if( !chk ) return; - chk->flag = 0; - } - - Local void Core·Guard·check( - Core·Guard *chk - ,WU err - ,bool condition - ,char *message - ){ - if( !chk || !chk->flag_function ) return; - if( condition ) return; - fprintf(stderr ,"%s\n" ,message); - chk->flag_function(&chk->flag ,err); - } - - Local Core·Guard·PFT Core·Guard·pft = { - .init = Core·Guard·init - ,.reset = Core·Guard·reset - ,.check = Core·Guard·check - }; - - //---------------------------------------- - // Functions implementation - - Core·Status Core·on_track(){ return Core·Status·on_track; } - Core·Status Core·derailed(){ return Core·Status·derailed; } - - Local Core·Status Core·is_aligned(AU *p ,extent_t·AU alignment ,bool *flag){ - #ifdef Core·DEBUG - Core·Guard·init_count(chk); - Core·Guard·pft.check(&chk ,1 ,p ,"given NULL p"); - Core·Guard·pft.check(&chk ,1 ,flag ,"flag is NULL, so nowhere to write result"); - Core·Guard·if_return(chk); - #endif - *flag = ( (uintptr_t)p & alignment ) == 0; - return Core·Status·on_track; - } - - Local Core·Status Core·round_down(AU *p ,extent_t·AU alignment ,AU **result){ - #ifdef Core·DEBUG - Core·Guard·init_count(chk); - Core·Guard·pft.check(&chk ,1 ,p ,"given NULL p to round"); - Core·Guard·pft.check(&chk ,1 ,result ,"result is NULL, so nowhere to write result"); - Core·Guard·if_return(chk); - #endif - *result = (AU *)( (uintptr_t)p & ~(uintptr_t)alignment ); - return Core·Status·on_track; - } - - Local Core·Status Core·round_up(AU *p ,extent_t·AU alignment ,AU **result){ - #ifdef Core·DEBUG - Core·Guard·init_count(chk); - Core·Guard·pft.check(&chk ,1 ,p ,"given NULL p to round"); - Core·Guard·pft.check(&chk ,1 ,result ,"result is NULL, so nowhere to write result"); - Core·Guard·if_return(chk); - #endif - *result = (AU *)( ( (uintptr_t)p + alignment ) & ~(uintptr_t)alignment ); - return Core·Status·on_track; - } - - Local Core·F Core·f = { - .on_track = Core·on_track - ,.derailed = Core·derailed - ,.is_aligned = Core·is_aligned - ,.round_down = Core·round_down // Add `Core` - ,.round_up = Core·round_up // Add `Core` - }; - -#endif // Core·LOCAL -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif - -/*-------------------------------------------------------------------------------- - undef the template parameters - Core currently has not template parameters ---------------------------------------------------------------------------------*/ diff --git "a/developer/cc\360\237\226\211/ParameterConnector.lib.c" "b/developer/cc\360\237\226\211/ParameterConnector.lib.c" deleted file mode 100644 index f0db395..0000000 --- "a/developer/cc\360\237\226\211/ParameterConnector.lib.c" +++ /dev/null @@ -1,77 +0,0 @@ -/* -Namespace: ParameterConnector - -Defines a macro for declaring parameter connectors, and for calling a parameterized function. - -Declares a parameter connector, does not initialize it. - -*/ - -/*-------------------------------------------------------------------------------- - Interface --------------------------------------------------------------------------------*/ - - -// once per translation unit -#ifndef ParameterConnector·FACE -#define ParameterConnector·FACE - - #define ParameterConnector·DEBUG - #ifdef ParameterConnector·DEBUG - #include - #pragma message( "ParameterConnector·FACE" ) - #endif - - #include "cpp_ext.c" - #include "Core.lib.c" - - /* - usage e.g.: ParameterConnector·call(tm, function_name, arg1, arg2, ...) - Expands to: (tm.pft->function_name)(tm ,arg1 ,arg2, ...) - - note the use of the comma operator to return the result from the b.pft->fn call - - pc - parameter connector - PC - generic parameter connector type, though as the parameter connector is the entry point for dispatch, we give it the name of Model/Machine type. - */ - #ifdef ParameterConnector·DEBUG - #include - #define ParameterConnector·call(pc ,fn ,...) ( \ - assert((pc).pft != NULL) \ - ,assert((pc).state_parameter != NULL) \ - ,(pc).pft->fn(pc __VA_OPT__(,) __VA_ARGS__) \ - ) - #else - #define ParameterConnector·call(pc ,fn ,...) \ - (pc).pft->fn(pc __VA_OPT__(,) __VA_ARGS__) - #endif - - #define ParameterConnector·DECLARE(type) \ - typedef struct ·(type ,PFT) ·(type ,PFT); \ - typedef struct ·(type ,StateParameter) ·(type ,StateParameter); \ - typedef struct type { \ - ·(type ,StateParameter) *state_parameter; \ - ·(type ,PFT) *pft; \ - } type; - -#endif - - - -/*-------------------------------------------------------------------------------- - Local - at bottom of translation unit, to keep some functions private - ParameterConnector currently has no local component ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - -#endif - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - ParameterConnector has no library component ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY - -#endif - - diff --git "a/developer/cc\360\237\226\211/TM.lib.c" "b/developer/cc\360\237\226\211/TM.lib.c" deleted file mode 100644 index ac59356..0000000 --- "a/developer/cc\360\237\226\211/TM.lib.c" +++ /dev/null @@ -1,143 +0,0 @@ -/* - Namespace: TM - Template parameters: - - `_TM·CVT_` Cell Value Type`. - - TM - Tape Machine Model - - Caller must declare TM set members: - #define SET_Binding__TM· // replacing with the actual value of CVT - -*/ - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ - -// once per translation unit -#ifndef TM·FACE -#define TM·FACE - - #include - #include - #include "cpp_ext.c" - - #include "Core.lib.c" - #include "Binding.lib.c" - - #define TM·DEBUG - #ifdef TM·DEBUG - #include - #endif - - typedef enum{ - TM·Topo·mu = 0 - ,TM·Topo·zero_length = 1 - ,TM·Topo·singleton = 1 << 1 - ,TM·Topo·segment = 1 << 2 - ,TM·Topo·circle = 1 << 3 - ,TM·Topo·tail_cyclic = 1 << 4 - ,TM·Topo·infinite = 1 << 5 - }TM·Topo; - const TM·Topo TM·Topo·bounded = - TM·Topo·singleton - | TM·Topo·segment - ; - - typedef enum{ - TM·Status·mu = 0 - ,TM·Status·dismounted = 1 - ,TM·Status·out_of_area = 1 << 1 - ,TM·Status·leftmost = 1 << 2 - ,TM·Status·interim = 1 << 3 - ,TM·Status·rightmost = 1 << 4 - } TM·Status; - - const TM·Status TM·Status·on_tape = - TM·Status·leftmost - | TM·Status·interim - | TM·Status·rightmost - ; - -#endif //#ifndef TM·FACE - -// once per _TM·CVT_ value -// Caller must #define SET_Binding__TM·, after inclusion, to prevent re-inclusion -#ifdef _TM·CVT_ -#if BOOLEAN( NOT_IN(TM ,_TM·CVT_) ) -#ifdef TM·DEBUG - #pragma message( "Creating TM type with a CVT of:" STR_VAL(_TM·CVT_) ) -#endif - - typedef size_t ·(extent_t,_TM·CVT_); - - ParameterConnector·DECLARE( ·(TM,_TM·CVT_) ) - - typedef struct ·(TM,_TM·CVT_,PFT){ - - TM·Topo (*topo) ( ·(TM,_TM·CVT_) tm ); - bool (*bounded) ( ·(TM,_TM·CVT_) tm ); - ·(extent_t,_TM·CVT_) (*extent) ( ·(TM,_TM·CVT_) tm ); - - TM·Status (*status) ( ·(TM,_TM·CVT_) tm ); - bool (*dismounted) ( ·(TM,_TM·CVT_) tm ); - bool (*on_tape) ( ·(TM,_TM·CVT_) tm ); - bool (*on_leftmost)( ·(TM,_TM·CVT_) tm ); - bool (*on_rightmost)( ·(TM,_TM·CVT_) tm ); - - // tape machine functions - void (*mount) ( ·(TM,_TM·CVT_) tm ); - void (*dismount) ( ·(TM,_TM·CVT_) tm ); - - void (*step) ( ·(TM,_TM·CVT_) tm ); - void (*step_left) ( ·(TM,_TM·CVT_) tm ); - void (*rewind) ( ·(TM,_TM·CVT_) tm ); - - _TM·CVT_ (*read) ( ·(TM,_TM·CVT_) tm ); - void (*write) ( ·(TM,_TM·CVT_) tm ,_TM·CVT_ *remote_pt ); - - } ·(TM,_TM·CVT_,PFT); - - -#endif -#endif - -/*-------------------------------------------------------------------------------- - Local ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - - // once per translation unit - #ifndef TM·LOCAL - #define TM·LOCAL - - #include "Core.lib.c" - #include "Binding.lib.c" - - const char *TM·Msg·tm = "given NULL tm"; - const char *TM·Msg·flag = "given NULL flag pointer"; - const char *TM·Msg·result = "given NULL result pointer"; - const char *TM·Msg·status = "bad head status"; - - #endif - - // once per _TM·CVT_ value - // Caller must #define SET_TM·LOCAL__TM·, after inclusion, to prevent re-inclusion - #ifdef _TM·CVT_ - #if BOOLEAN(NOT_IN(TM·LOCAL ,·(TM,_TM·CVT_))) - #ifdef TM·DEBUG - #pragma message( "Including TM LOCAL code for:" STR_VAL(_TM·CVT_) ) - #endif - - #endif // #if BOOLEAN(NOT_IN(TM·LOCAL ,TM)) - #endif // #ifdef _TM·CVT_ - -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif diff --git "a/developer/cc\360\237\226\211/TM\302\267Array.lib.c" "b/developer/cc\360\237\226\211/TM\302\267Array.lib.c" deleted file mode 100644 index f9ce008..0000000 --- "a/developer/cc\360\237\226\211/TM\302\267Array.lib.c" +++ /dev/null @@ -1,244 +0,0 @@ -/* - Namespace: TM·Array - - Template parameters: - - `_TM·CVT_` Cell Value Type`. - -*/ -#include "TM.lib.c" - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ - -// once per translation unit -#ifndef TM·Array·FACE -#define TM·Array·FACE - - #define TM·Array·DEBUG - #ifdef TM·Array·DEBUG - #include - #endif - -#endif - -// only include this file once per _TM·CVT_ value -#ifdef _TM·CVT_ - - #if BOOLEAN( NOT_IN(TM ,_TM·CVT_) ) - #include "TM.Lib.c" - #define SET__ - #endif - - #pragma push(T) - #pragma push(TA) - #pragma push(TE) - - #define T ·(TM,_TM·CVT_) - #define TA ·(TM,Array,_TM·CVT_) - #define TE ·(extent_t,_TM·CVT_) - - #ifdef TM·Array·DEBUG - #pragma message( "Declaring:" STR_VAL(TA) ) - #endif - - typedef struct{ - _TM·CVT_ *hd; - _TM·CVT_ *position; - TE extent; - } ·(TA,StateParameter); - - // call signatures for the initialization functions - // - T ·(TA,init_pe)( - ·(TA,StateParameter) *t ,_TM·CVT_ position[] ,TE extent - ); - - T ·(TA,init_pp)( - ·(TA,StateParameter) *t ,_TM·CVT_ *position_left ,_TM·CVT_ *position_right - ); - - #pragma pop(T) - #pragma pop(TA) - #pragma pop(TE) - -#endif -#endif - -/*-------------------------------------------------------------------------------- - Local ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - - // once per translation unit - #ifndef TM·Array·LOCAL - #define TM·Array·LOCAL - - #endif - - // once per _TM·CVT_ value - #ifdef _TM·CVT_ - #if BOOLEAN( NOT_IN(TM·Array·LOCAL ,_TM·CVT_) ) - - #include "TM.Lib.c" - - #pragma push(T) - #pragma push(TA) - #pragma push(TE) - - #define T ·(TM,_TM·CVT_) - #define TA ·(TM,Array,_TM·CVT_) - #define TE ·(extent_t,_TM·CVT_) - - #ifdef TM·Array·DEBUG - #pragma message( "LOCAL:" STR_VAL(TA) ) - #endif - - Local TM·Topo ·(TA,topo)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - if( t->extent == 0 ) return TM·Topo·singleton; - return TM·Topo·segment; - } - Local bool ·(TA,bounded)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - return ·(TA,topo)(tm) & TM·Topo·bounded; - } - Local TE ·(TA,extent)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - return t->extent; - } - - Local TM·Status ·(TA,status)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - if( !t->hd ) return TM·Status·dismounted; - if( t->hd == t->position ) return TM·Status·leftmost; - - _TM·CVT_ *rightmost_pt = t->position + t->extent; - if( t->hd == rightmost_pt ) return TM·Status·rightmost; - if( t->hd < t->position || t->hd > rightmost_pt ) - return TM·Status·out_of_area; - - return TM·Status·interim; - } - - Local bool ·(TA,dismounted)(T tm){ - return ·(TA,status)( tm ) & TM·Status·dismounted; - } - - Local bool ·(TA,on_tape)(T tm){ - return ·(TA,status)( tm ) & TM·Status·on_tape; - } - - Local bool ·(TA,on_leftmost)(T tm){ - return ·(TA,status)( tm ) & TM·Status·leftmost; - } - - Local bool ·(TA,on_rightmost)(T tm){ - return ·(TA,status)( tm ) & TM·Status·rightmost; - } - - // does nothing if tape is already mounted - Local void ·(TA,mount)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - if( !t->hd ) t->hd = t->position; - } - - Local void ·(TA,dismount)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - t->hd = NULL; - } - - Local void ·(TA,step)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - t->hd++; - } - - Local void ·(TA,step_left)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - t->hd--; - } - - // rewind does nothing if the tape is dismounted - Local void ·(TA,rewind)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - if( ·(TA,dismounted)( tm ) ) return; - t->hd = t->position; - } - - Local _TM·CVT_ ·(TA,read)(T tm){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - return *t->hd; - } - - Local void ·(TA,write)(T tm ,_TM·CVT_ *remote_pt){ - ·(TA,StateParameter) *t = (·(TA,StateParameter) *) tm.state_parameter; - *t->hd = *remote_pt; - } - - Local ·(TM,_TM·CVT_,PFT) ·(TA,pft) = { - - .topo = ·(TA,topo) - ,.bounded = ·(TA,bounded) - ,.extent = ·(TA,extent) - - ,.status = ·(TA,status) - ,.dismounted = ·(TA,dismounted) - ,.on_tape = ·(TA,on_tape) - ,.on_leftmost = ·(TA,on_leftmost) - ,.on_rightmost = ·(TA,on_rightmost) - - ,.mount = ·(TA,mount) - ,.dismount = ·(TA,dismount) - - ,.step = ·(TA,step) - ,.step_left = ·(TA,step_left) - ,.rewind = ·(TA,rewind) - - ,.read = ·(TA,read) - ,.write = ·(TA,write) - - }; - - /* - tm is up casted from being array specific, to being generic. Later it is downcasted within the array code before being used. This can be seen at the top of each of the array specific function. This is the only loss of static type safety, and it is embedded in the library code. - */ - ·(TM,_TM·CVT_) ·(TA,init_pe)( - ·(TA,StateParameter) *t - ,_TM·CVT_ *position - ,TE extent - ){ - t->hd = position; - t->position = position; - t->extent = extent; - - T tm = { - .state_parameter = (·(TM,_TM·CVT_,StateParameter) *)t - ,.pft = &·(TA,pft) - }; - - return tm; - } - - ·(TM,_TM·CVT_) ·(TA,init_pp)( - ·(TA,StateParameter) *t - ,_TM·CVT_ *position_left - ,_TM·CVT_ *position_right - ){ - return ·(TA,init_pe)( - t ,position_left ,position_right - position_left - ); - } - - - #endif // #if BOOLEAN(NOT_IN(TM·LOCAL ,TM)) - #endif // #ifdef _TM·CVT_ - -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif diff --git "a/developer/cc\360\237\226\211/TM\302\267SingletonCircle.lib.c" "b/developer/cc\360\237\226\211/TM\302\267SingletonCircle.lib.c" deleted file mode 100644 index 6e375ea..0000000 --- "a/developer/cc\360\237\226\211/TM\302\267SingletonCircle.lib.c" +++ /dev/null @@ -1,182 +0,0 @@ -/* - Namespace: TM - Template parameters: - - `_TM·CVT_` Cell Value Type`. - - TM - Tape Machine Model - - Caller must declare TM set members: - #define SET_Binding__TM· // replacing with the actual value of CVT - -*/ - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ - -// once per translation unit -#ifndef TM·FACE -#define TM·FACE - - #define TM·SingletonCircle·DEBUG - #ifdef TM·SingletonCircle·DEBUG - #include - #endif - -#endif //#ifndef TM·FACE - -// once per _TM·CVT_ value -// Caller must #define SET_Binding__TM·SingletonCircle·, after inclusion, to prevent re-inclusion -#ifdef _TM·CVT_ -#if BOOLEAN( NOT_IN(Binding ,·(TM·SingletonCircle,_TM·CVT_)) ) -#ifdef TM·DEBUG - #pragma message( "Creating TM·SingletonCircle type with a CVT of:" STR_VAL(_TM·CVT_) ) -#endif - - typedef struct{ - bool hd; - _TM·CVT_ value; - } ·(TM,_TM·CVT_,SingletonCircle,StateParameter); - - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,SingletonCircle,init)( - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t - ,_TM·CVT_ initial_value - ); - -#endif // #if BOOLEAN( NOT_IN(Binding ,TM) ) -#endif // #ifdef _TM·CVT_ - -/*-------------------------------------------------------------------------------- - Local ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - - // once per translation unit - #ifndef TM·SingletonCircle·LOCAL - #define TM·SingletonCircle·LOCAL - - #endif - - // once per _TM·CVT_ value - // Caller must #define SET_TM·LOCAL__TM·, after inclusion, to prevent re-inclusion - #ifdef _TM·CVT_ - #if BOOLEAN(NOT_IN(TM·SingletonCircle·LOCAL ,·(TM,_TM·CVT_))) - #ifdef TM·SingletonCircle·DEBUG - #pragma message( "Including TM·SingletonCircle LOCAL code for:" STR_VAL(_TM·CVT_) ) - #endif - - Local TM·Topo ·(TM,_TM·CVT_,SingletonCircle,topo)( ·(TM,_TM·CVT_) tm ){ - return TM·Topo·circle; - } - Local bool ·(TM,_TM·CVT_,SingletonCircle,bounded)( ·(TM,_TM·CVT_) tm ){ - return false; - } - Local ·(extent_t,_TM·CVT_) ·(TM,_TM·CVT_,SingletonCircle,extent)( ·(TM,_TM·CVT_) tm ){ - return 0; - } - Local TM·Status ·(TM,_TM·CVT_,SingletonCircle,status)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - if( !t->hd ) return TM·Status·dismounted; - return TM·Status·interim; - } - Local bool ·(TM,_TM·CVT_,SingletonCircle,dismounted)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - return !t->hd; - } - - // these could be pulled from the tm.pft table, and defined once - Local bool ·(TM,_TM·CVT_,SingletonCircle,on_tape)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - return t->hd; - } - Local bool ·(TM,_TM·CVT_,SingletonCircle,on_leftmost)( ·(TM,_TM·CVT_) tm ){ - return false; - } - Local bool ·(TM,_TM·CVT_,SingletonCircle,on_rightmost)( ·(TM,_TM·CVT_) tm ){ - return false; - } - - // does nothing if tape is already mounted - Local void ·(TM,_TM·CVT_,SingletonCircle,mount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - t->hd = true; - } - Local void ·(TM,_TM·CVT_,SingletonCircle,dismount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - t->hd = false; - } - - Local void ·(TM,_TM·CVT_,SingletonCircle,s)( ·(TM,_TM·CVT_) tm ){ - return; - } - Local void ·(TM,_TM·CVT_,SingletonCircle,step_left)( ·(TM,_TM·CVT_) tm ){ - return; - } - Local void ·(TM,_TM·CVT_,SingletonCircle,rewind)( ·(TM,_TM·CVT_) tm ){ - return; - } - - Local _TM·CVT_ ·(TM,_TM·CVT_,SingletonCircle,r)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - return t->value; - } - Local void ·(TM,_TM·CVT_,SingletonCircle,w)( ·(TM,_TM·CVT_) tm ,_TM·CVT_ *remote_pt ){ - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t = (·(TM,_TM·CVT_,SingletonCircle,StateParameter) *) tm.state_parameter; - t->value = *remote_pt; - } - - Local ·(TM,_TM·CVT_,PFT) ·(TM,_TM·CVT_,SingletonCircle,pft) = { - - .topo = ·(TM,_TM·CVT_,SingletonCircle,topo) - ,.bounded = ·(TM,_TM·CVT_,SingletonCircle,bounded) - ,.extent = ·(TM,_TM·CVT_,SingletonCircle,extent) - - ,.status = ·(TM,_TM·CVT_,SingletonCircle,status) - ,.dismounted = ·(TM,_TM·CVT_,SingletonCircle,dismounted) - ,.on_tape = ·(TM,_TM·CVT_,SingletonCircle,on_tape) - ,.on_leftmost = ·(TM,_TM·CVT_,SingletonCircle,on_leftmost) - ,.on_rightmost = ·(TM,_TM·CVT_,SingletonCircle,on_rightmost) - - ,.mount = ·(TM,_TM·CVT_,SingletonCircle,mount) - ,.dismount = ·(TM,_TM·CVT_,SingletonCircle,dismount) - - ,.step = ·(TM,_TM·CVT_,SingletonCircle,s) - ,.step_left = ·(TM,_TM·CVT_,SingletonCircle,step_left) - ,.rewind = ·(TM,_TM·CVT_,SingletonCircle,rewind) - - ,.r = ·(TM,_TM·CVT_,SingletonCircle,r) - ,.w = ·(TM,_TM·CVT_,SingletonCircle,w) - - }; - - /* - tm is up casted from being array specific, to being generic. Later it is downcasted within the array code before being used. This can be seen at the top of each of the array specific function. This is the only loss of static type safety, and it is embedded in the library code. - */ - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,SingletonCircle,init)( - ·(TM,_TM·CVT_,SingletonCircle,StateParameter) *t - ,_TM·CVT_ initial_value - ){ - t->hd = true; - t->value = initial_value; - - ·(TM,_TM·CVT_) tm = { - .state_parameter = (·(TM,_TM·CVT_,StateParameter) *)t - ,.pft = &·(TM,_TM·CVT_,SingletonCircle,pft) - }; - - return tm; - } - - #endif // #if BOOLEAN(NOT_IN(TM·LOCAL ,TM)) - #endif // #ifdef _TM·CVT_ - -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif - diff --git "a/developer/cc\360\237\226\211/TM\302\267SingletonSegment.lib.c" "b/developer/cc\360\237\226\211/TM\302\267SingletonSegment.lib.c" deleted file mode 100644 index 1dff957..0000000 --- "a/developer/cc\360\237\226\211/TM\302\267SingletonSegment.lib.c" +++ /dev/null @@ -1,178 +0,0 @@ -/* - Namespace: TM·SingletonSegment - - Template parameters: - - `_TM·CVT_` Cell Value Type`. - -*/ -#include "TM.lib.c" - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ - -// once per translation unit -#ifndef TM·FACE -#define TM·FACE - - #define TM·SingletonSegment·DEBUG - #ifdef TM·SingletonSegment·DEBUG - #include - #endif - -#endif //#ifndef TM·FACE - -// once per _TM·CVT_ value -// Caller must #define SET_Binding__TM·SingletonSegment·, after inclusion, to prevent re-inclusion -#ifdef _TM·CVT_ -#if BOOLEAN( NOT_IN(Binding ,·(TM·SingletonSegment,_TM·CVT_)) ) -#ifdef TM·SingletonSegment·DEBUG - #pragma message( "Creating TM·SingletonSegment type with a CVT of:" STR_VAL(_TM·CVT_) ) -#endif - - typedef struct{ - bool hd; - _TM·CVT_ value; - } ·(TM,_TM·CVT_,SingletonSegment,StateParameter); - - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,SingletonSegment,init)( - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t - ,_TM·CVT_ initial_value - ); - -#endif -#endif - -/*-------------------------------------------------------------------------------- - Local ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - - // once per translation unit - #ifndef TM·SingletonSegment·LOCAL - #define TM·SingletonSegment·LOCAL - - #endif - - // once per _TM·CVT_ value - // Caller must #define SET_TM·LOCAL__TM·, after inclusion, to prevent re-inclusion - #ifdef _TM·CVT_ - #if BOOLEAN(NOT_IN(TM·LOCAL ,·(TM·SingletonSegment,_TM·CVT_))) - #ifdef TM·SingletonSegment·DEBUG - #pragma message( "Including TM·SingletonSegment LOCAL code for:" STR_VAL(_TM·CVT_) ) - #endif - - Local TM·Topo ·(TM,_TM·CVT_,SingletonSegment,topo)( ·(TM,_TM·CVT_) tm ){ - return TM·Topo·singleton; - } - Local bool ·(TM,_TM·CVT_,SingletonSegment,bounded)( ·(TM,_TM·CVT_) tm ){ - return true; - } - Local ·(extent_t,_TM·CVT_) ·(TM,_TM·CVT_,SingletonSegment,extent)( ·(TM,_TM·CVT_) tm ){ - return 0; - } - Local TM·Status ·(TM,_TM·CVT_,SingletonSegment,status)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - if( !t->hd ) return TM·Status·dismounted; - return TM·Status·leftmost | TM·Status·rightmost; - } - Local bool ·(TM,_TM·CVT_,SingletonSegment,dismounted)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - return !t->hd; - } - - // these could be pulled from the tm.pft table, and defined once - Local bool ·(TM,_TM·CVT_,SingletonSegment,on_tape)( ·(TM,_TM·CVT_) tm ){ - return ·(TM,_TM·CVT_,SingletonSegment,status)( tm ) & TM·Status·on_tape; - } - Local bool ·(TM,_TM·CVT_,SingletonSegment,on_leftmost)( ·(TM,_TM·CVT_) tm ){ - return ·(TM,_TM·CVT_,SingletonSegment,status)( tm ) & TM·Status·leftmost; - } - Local bool ·(TM,_TM·CVT_,SingletonSegment,on_rightmost)( ·(TM,_TM·CVT_) tm ){ - return ·(TM,_TM·CVT_,SingletonSegment,status)( tm ) & TM·Status·rightmost; - } - - // does nothing if tape is already mounted - Local void ·(TM,_TM·CVT_,SingletonSegment,mount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - t->hd = true; - } - Local void ·(TM,_TM·CVT_,SingletonSegment,dismount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - t->hd = false; - } - - Local void ·(TM,_TM·CVT_,SingletonSegment,s)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - Local void ·(TM,_TM·CVT_,SingletonSegment,step_left)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - Local void ·(TM,_TM·CVT_,SingletonSegment,rewind)( ·(TM,_TM·CVT_) tm ){ - return; - } - - Local _TM·CVT_ ·(TM,_TM·CVT_,SingletonSegment,r)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - return t->value; - } - Local void ·(TM,_TM·CVT_,SingletonSegment,w)( ·(TM,_TM·CVT_) tm ,_TM·CVT_ *remote_pt ){ - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t = (·(TM,_TM·CVT_,SingletonSegment,StateParameter) *) tm.state_parameter; - t->value = *remote_pt; - } - - Local ·(TM,_TM·CVT_,PFT) ·(TM,_TM·CVT_,SingletonSegment,pft) = { - - .topo = ·(TM,_TM·CVT_,SingletonSegment,topo) - ,.bounded = ·(TM,_TM·CVT_,SingletonSegment,bounded) - ,.extent = ·(TM,_TM·CVT_,SingletonSegment,extent) - - ,.status = ·(TM,_TM·CVT_,SingletonSegment,status) - ,.dismounted = ·(TM,_TM·CVT_,SingletonSegment,dismounted) - ,.on_tape = ·(TM,_TM·CVT_,SingletonSegment,on_tape) - ,.on_leftmost = ·(TM,_TM·CVT_,SingletonSegment,on_leftmost) - ,.on_rightmost = ·(TM,_TM·CVT_,SingletonSegment,on_rightmost) - - ,.mount = ·(TM,_TM·CVT_,SingletonSegment,mount) - ,.dismount = ·(TM,_TM·CVT_,SingletonSegment,dismount) - - ,.step = ·(TM,_TM·CVT_,SingletonSegment,s) - ,.step_left = ·(TM,_TM·CVT_,SingletonSegment,step_left) - ,.rewind = ·(TM,_TM·CVT_,SingletonSegment,rewind) - - ,.r = ·(TM,_TM·CVT_,SingletonSegment,r) - ,.w = ·(TM,_TM·CVT_,SingletonSegment,w) - - }; - - /* - tm is up casted from being array specific, to being generic. Later it is downcasted within the array code before being used. This can be seen at the top of each of the array specific function. This is the only loss of static type safety, and it is embedded in the library code. - */ - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,SingletonSegment,init)( - ·(TM,_TM·CVT_,SingletonSegment,StateParameter) *t - ,_TM·CVT_ initial_value - ){ - t->hd = true; - t->value = initial_value; - - ·(TM,_TM·CVT_) tm = { - .state_parameter = (·(TM,_TM·CVT_,StateParameter) *)t - ,.pft = &·(TM,_TM·CVT_,SingletonSegment,pft) - }; - - return tm; - } - - #endif // #if BOOLEAN(NOT_IN(TM·LOCAL ,TM)) - #endif // #ifdef _TM·CVT_ - -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif - diff --git "a/developer/cc\360\237\226\211/TM\302\267ZeroLength.lib.c" "b/developer/cc\360\237\226\211/TM\302\267ZeroLength.lib.c" deleted file mode 100644 index 4506cc6..0000000 --- "a/developer/cc\360\237\226\211/TM\302\267ZeroLength.lib.c" +++ /dev/null @@ -1,180 +0,0 @@ -/* - Namespace: TM·ZeroLength - - Template parameters: - - `_TM·CVT_` Cell Value Type`. - -*/ -#include "TM.lib.c" - -/*-------------------------------------------------------------------------------- - Interface ---------------------------------------------------------------------------------*/ - -// once per translation unit -#ifndef TM·ZeroLength·FACE -#define TM·ZeroLength·FACE - - #define TM·ZeroLength·DEBUG - #ifdef TM·ZeroLength·DEBUG - #include - #endif - -#endif //#ifndef TM·FACE - -// once per _TM·CVT_ value -// Caller must #define SET_Binding__TM·ZeroLength·, after inclusion, to prevent re-inclusion -#ifdef _TM·CVT_ -#if BOOLEAN( NOT_IN(Binding ,·(TM·ZeroLength,_TM·CVT_)) ) -#ifdef TM·ZeroLength·DEBUG - #pragma message( "Creating TM·ZeroLength type with a CVT of:" STR_VAL(_TM·CVT_) ) -#endif - - typedef struct{ - bool hd; - } ·(TM,_TM·CVT_,ZeroLength,StateParameter); - - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,ZeroLength,init)( - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t - ); - -#endif -#endif - -/*-------------------------------------------------------------------------------- - Local ---------------------------------------------------------------------------------*/ -#ifdef LOCAL - - // once per translation unit - #ifndef TM·ZeroLength·LOCAL - #define TM·ZeroLength·LOCAL - - #endif - - // once per _TM·CVT_ value - // Caller must #define SET_TM·ZeroLength·LOCAL__TM·, after inclusion, to prevent re-inclusion - #ifdef _TM·CVT_ - #if BOOLEAN(NOT_IN(TM·LOCAL ,·(TM·ZeroLength,_TM·CVT_))) - #ifdef TM·ZeroLength·DEBUG - #pragma message( "Including TM·ZeroLength LOCAL code for:" STR_VAL(_TM·CVT_) ) - #endif - - Local TM·Topo ·(TM,_TM·CVT_,ZeroLength,topo)( ·(TM,_TM·CVT_) tm ){ - return TM·Topo·zero_length; - } - - Local bool ·(TM,_TM·CVT_,ZeroLength,bounded)( ·(TM,_TM·CVT_) tm ){ - return true; - } - - Local ·(extent_t,_TM·CVT_) ·(TM,_TM·CVT_,ZeroLength,extent)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - - Local TM·Status ·(TM,_TM·CVT_,ZeroLength,status)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t = (·(TM,_TM·CVT_,ZeroLength,StateParameter) *) tm.state_parameter; - if( !t->hd ) return TM·Status·dismounted; - return TM·Status·out_of_area; - } - - Local bool ·(TM,_TM·CVT_,ZeroLength,dismounted)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t = (·(TM,_TM·CVT_,ZeroLength,StateParameter) *) tm.state_parameter; - return !t->hd; - } - - Local bool ·(TM,_TM·CVT_,ZeroLength,on_tape)( ·(TM,_TM·CVT_) tm ){ - return false; - } - - Local bool ·(TM,_TM·CVT_,ZeroLength,on_leftmost)( ·(TM,_TM·CVT_) tm ){ - return false; - } - - Local bool ·(TM,_TM·CVT_,ZeroLength,on_rightmost)( ·(TM,_TM·CVT_) tm ){ - return false; - } - - // does nothing if tape is already mounted - Local void ·(TM,_TM·CVT_,ZeroLength,mount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t = (·(TM,_TM·CVT_,ZeroLength,StateParameter) *) tm.state_parameter; - if( !t->hd ) t->hd = true; - } - - Local void ·(TM,_TM·CVT_,ZeroLength,dismount)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t = (·(TM,_TM·CVT_,ZeroLength,StateParameter) *) tm.state_parameter; - t->hd = false; - } - - Local void ·(TM,_TM·CVT_,ZeroLength,s)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - - Local void ·(TM,_TM·CVT_,ZeroLength,step_left)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - - // rewind does nothing if the tape is dismounted - Local void ·(TM,_TM·CVT_,ZeroLength,rewind)( ·(TM,_TM·CVT_) tm ){ - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t = (·(TM,_TM·CVT_,ZeroLength,StateParameter) *) tm.state_parameter; - if( ·(TM,_TM·CVT_,ZeroLength,dismounted)( tm ) ) return; - assert(0); - } - - Local _TM·CVT_ ·(TM,_TM·CVT_,ZeroLength,r)( ·(TM,_TM·CVT_) tm ){ - assert(0); - } - - Local void ·(TM,_TM·CVT_,ZeroLength,w)( ·(TM,_TM·CVT_) tm ,_TM·CVT_ *remote_pt ){ - assert(0); - } - - Local ·(TM,_TM·CVT_,PFT) ·(TM,_TM·CVT_,ZeroLength,pft) = { - - .topo = ·(TM,_TM·CVT_,ZeroLength,topo) - ,.bounded = ·(TM,_TM·CVT_,ZeroLength,bounded) - ,.extent = ·(TM,_TM·CVT_,ZeroLength,extent) - - ,.status = ·(TM,_TM·CVT_,ZeroLength,status) - ,.dismounted = ·(TM,_TM·CVT_,ZeroLength,dismounted) - ,.on_tape = ·(TM,_TM·CVT_,ZeroLength,on_tape) - ,.on_leftmost = ·(TM,_TM·CVT_,ZeroLength,on_leftmost) - ,.on_rightmost = ·(TM,_TM·CVT_,ZeroLength,on_rightmost) - - ,.mount = ·(TM,_TM·CVT_,ZeroLength,mount) - ,.dismount = ·(TM,_TM·CVT_,ZeroLength,dismount) - - ,.step = ·(TM,_TM·CVT_,ZeroLength,s) - ,.step_left = ·(TM,_TM·CVT_,ZeroLength,step_left) - ,.rewind = ·(TM,_TM·CVT_,ZeroLength,rewind) - - ,.r = ·(TM,_TM·CVT_,ZeroLength,r) - ,.w = ·(TM,_TM·CVT_,ZeroLength,w) - - }; - - ·(TM,_TM·CVT_) ·(TM,_TM·CVT_,ZeroLength,init)( - ·(TM,_TM·CVT_,ZeroLength,StateParameter) *t - ){ - t->hd = true; - ·(TM,_TM·CVT_) tm = { - .state_parameter = (·(TM,_TM·CVT_,StateParameter) *)t - ,.pft = &·(TM,_TM·CVT_,ZeroLength,pft) - }; - return tm; - } - - - #endif // #if BOOLEAN(NOT_IN(TM·LOCAL ,TM)) - #endif // #ifdef _TM·CVT_ - -#endif // LOCAL - -/*-------------------------------------------------------------------------------- - Library - compiled into a lib.a file by the current make - Core currently has no library components ---------------------------------------------------------------------------------*/ -#ifdef LIBRARY -#endif - diff --git "a/developer/cc\360\237\226\211/cpp_ext.c" "b/developer/cc\360\237\226\211/cpp_ext.c" deleted file mode 100644 index 6cff205..0000000 --- "a/developer/cc\360\237\226\211/cpp_ext.c" +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef CPP_EXT -#define CPP_EXT - - #include "cpp_ext_0.c" - #include "cpp_ext_1.c" - - /* - CONTAINS requires registration of pattern, as examples: - - #define EQ__int__oo__int - #define EQ__float__oo__float - #define EQ__char__oo__char - #define EQ__void__oo__void - - */ - - #define ·(...) CAT(· ,__VA_ARGS__) - -#endif diff --git "a/developer/cc\360\237\226\211/cpp_ext_0.c" "b/developer/cc\360\237\226\211/cpp_ext_0.c" deleted file mode 100644 index a04d08d..0000000 --- "a/developer/cc\360\237\226\211/cpp_ext_0.c" +++ /dev/null @@ -1,290 +0,0 @@ -/* - See also - https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h - and tutorial at: http://jhnet.co.uk/articles/cpp_magic - - documents in $REPO_HOME/developer/document🖉 - -1. We use a truth of existence - - An empty value is false. Anything else is true. Hence, even the token '0' is true. - -2. todo - -- cpp_ext as separate project -- make the try into tests -- cpp_ext macros put into a namespace to prevent aliasing - -*/ - -#ifndef CPP_EXT_0 -#define CPP_EXT_0 - -/*--------------------------------------------------------------------------- - DEBUG ----------------------------------------------------------------------------*/ - -#include -#define DEBUG_CPP - -// print the macro and the evaluation of the macro at compile time: -// #pragma message( STR_VAL() ) - -#define STR(...) #__VA_ARGS__ -#define VAL(...) STR(__VA_ARGS__) -#define STR_VAL(...) #__VA_ARGS__ " -> " VAL(__VA_ARGS__) - -// print the macro and the evaluation of the macro at run time: -#define SHOW(expr) printf("%s -> %s\n", #expr, STR(expr)); - -/*--------------------------------------------------------------------------- -Constants ----------------------------------------------------------------------------*/ - -#define NOTHING - -#define COMMA , -#define SEMICOLON ; - -// 'twion' is a two component object that masquerades as a single object -#define _TWION_0 ~,0 -#define _TWION_1 ~,1 - -/*--------------------------------------------------------------------------- -Fixed arg count concatenation - - Not implemented for elegance, rather CAT is used to force evaluation of arguments before `##`. -*/ - -#define _CAT2(a ,b) a ## b -#define CAT2(a ,b) _CAT2(a ,b) - -#define _CAT3(a ,b ,c) a ## b ## c -#define CAT3(a ,b ,c) _CAT3(a ,b ,c) - -#define _CAT4(a ,b ,c ,d) a ## b ## c ## d -#define CAT4(a ,b ,c ,d) _CAT4(a ,b ,c ,d) - -/*--------------------------------------------------------------------------- -LOGIC - - empty - false - NOT() - not empty, is true -*/ - - //---------------------------------------- - // primitive access - - // _FIRST with zero arguments returns nothing, otherwise returns first token - // in the list, which can also be nothing. e.g. _FIRST(,2,3) returns nothing. - #define _FIRST(a ,...) a - - // _SECOND must be given a list of length 2, though no tokens need be given - #define _SECOND(a ,b ,...) b - - //---------------------------------------- - // given one or zero arguments, returns nothing - // - #define RETURN_NOTHING() - - //---------------------------------------- - // given a list returns a token - // given an token returns a token - // given nothing, returns nothing - // - #define _OR(...) _FIRST(RETURN_NOTHING __VA_ARGS__ ()) - - /*---------------------------------------- - given a token returns nothing - given nothing returns 1 - - `##` prevents rewrite of _TWION_ in the _EXISTS_TOKEN_1 macro, don't - replace that with CAT! - */ - #define _NOT_TOKEN_ss(x_token) _SECOND(x_token ,) - #define _NOT_TOKEN_s(x_token) _NOT_TOKEN_ss(_TWION_1##x_token) - #define _NOT_TOKEN(x_token) _NOT_TOKEN_s(x_token) - - /*---------------------------------------- - given a token or a list, returns nothing - given nothing, returns 1 - */ - #define NOT(...) _NOT_TOKEN( _OR(__VA_ARGS__) ) - - /*---------------------------------------- - given argument is empty returns empty - given argument is not empty, returns 1 - */ - #define EXISTS(...) NOT( NOT(__VA_ARGS__) ) - - // useful synonym - #define MATCH_RWR(x) NOT(x) - -/*--------------------------------------------------------------------------- - IF-ELSE construct. - Usage: IF_ELSE(condition)()() - - A most amazing little macro. It has no dependencies on the other macros - in this file, though many of those will be useful in predicates -*/ - - #define IF(...) CAT2(_IF_ ,EXISTS(__VA_ARGS__)) - #define _IF_1(...) __VA_ARGS__ _IF_1_ELSE - #define _IF_(...) _IF__ELSE - #define _IF_1_ELSE(...) - #define _IF__ELSE(...) __VA_ARGS__ - -/*--------------------------------------------------------------------------- - - In cpp_ext logic: - ε is false and anything else is true - - In BOOLEAN logic - ε is an error, 0 is false, anything else is true - - USE this operator to convert something in cpp_ext logic to something for - the built-in operators. - - Note the output of BOOLEAN is always an existing token, so it will - aways be 'true' in cpp_ext logic. - -*/ - #define BOOLEAN(...) IF(__VA_ARGS__) (1) (0) - - -/*--------------------------------------------------------------------------- - Logic connectors -*/ - #define LEQ2(x ,y) IF(x) (y) (NOT(y)) - #define XOR2(x ,y) IF(x) (NOT(y)) (y) - #define AND2(x ,y) IF(x) (y) () - #define OR2(x ,y) IF(x) (1) (y) - -/*--------------------------------------------------------------------------- - Set - User must define set members manually: - - #define __ - - For example a set named TRIP with 1 ,2 ,3 in it: - - #define SET_TRIP__1 - #define SET_TRIP__2 - #define SET_TRIP__3 - -*/ - -#define IN(name ,x) NOT(CAT4(SET_ ,name ,__ ,x)) -#define NOT_IN(name ,x) CAT4(SET_ ,name ,__ ,x) - - -/*--------------------------------------------------------------------------- - Registered Equivalence - - Checks if x and y have been paired in a rewrite rule. - - Logic values can not be paired, as anything except an empty argument is taken as true. - - each pairing rule has the form - EQ____oo__ - - for example: - #define EQ__APPLE__oo__APPLE - #define EQ__PEAR__oo__PEAR - - SHOW( EQ(APPLE ,APPLE) ); -> 1 - SHOW( EQ(APPLE ,PEAR) ); -> ε - - // if empty should be EQ to empty, add this - // without this, EQ(,) -> ε - #define EQ____oo__ - ----------------------------------------------------------------------------*/ - - // if empty should be EQ to empty, keep this - // without this, EQ(,) -> ε - #define EQ____oo__ - - #define EQ__0__oo__0 - #define EQ__1__oo__1 - - #define EQ(x_token ,y_token) MATCH_RWR( CAT4(EQ__ ,x_token ,__oo__ ,y_token) ) - -/*--------------------------------------------------------------------------- -Remainder of list ----------------------------------------------------------------------------*/ - - #define _REST(a ,...) __VA_ARGS__ - #define REST(...)\ - IF \ - (__VA_ARGS__) \ - ( _REST(__VA_ARGS__) ) \ - () - -#endif -/* - _FIRST(1) -> 1 - _FIRST() -> - _SECOND(1,2) -> 2 - _SECOND(1,) -> - - RETURN_NOTHING() -> - - _OR() -> - _OR(1) -> RETURN_NOTHING 1 () - _OR(1,2,3) -> RETURN_NOTHING 1 - - T(x) -> 7 - _NOT_ITEM() -> _NOT_ITEM() - _NOT_ITEM(1) -> _NOT_ITEM(1) - _NOT_ITEM(T(x)) -> _NOT_ITEM(7) - - NOT() -> 1 - NOT(1) -> - NOT(T(x)) -> - NOT(1,2,3) -> - - BOOL() -> BOOL() - CAT2(_IF_ ,BOOL()) -> _IF_BOOL() - - TO_1_OR_0() -> TO_1_OR_0() - TO_1_OR_0(1) -> TO_1_OR_0(1) - TO_1_OR_0(x) -> TO_1_OR_0(x) - TO_1_OR_0(1.2.3) -> TO_1_OR_0(1.2.3) - - EXISTS() -> - EXISTS(0) -> 1 - EXISTS(x,y,z) -> 1 - - LEQ2( , ) -> 1 - LEQ2( , 1 ) -> - LEQ2( 1, ) -> - LEQ2( 1, 0 ) -> 0 - - XOR2( , ) -> - XOR2( , 0 ) -> 0 - XOR2( 0, 0 ) -> - - AND2( , 0 ) -> - AND2( 0, 1 ) -> 1 - - OR2( , ) -> - OR2( , 0 ) -> 0 - - EQ(APPLE ,APPLE) -> 1 - EQ(APPLE ,PEAR) -> - EQ(PEAR ,PEAR) -> 1 - EQ(,) -> 1 - EQ(,PEAR) -> - EQ(PEAR ,) -> - - BOOLEAN() -> 0 - BOOLEAN(0) -> 1 - BOOLEAN(foo) -> 1 - BOOLEAN(1,2,3) -> 1 - - REST() -> - REST(1) -> - REST(1,2) -> 2 - REST(1,2,3) -> 2,3 -*/ diff --git "a/developer/cc\360\237\226\211/cpp_ext_1.c" "b/developer/cc\360\237\226\211/cpp_ext_1.c" deleted file mode 100644 index 788c57a..0000000 --- "a/developer/cc\360\237\226\211/cpp_ext_1.c" +++ /dev/null @@ -1,195 +0,0 @@ -/* -These are the recursive extension. - -Simple errors can lead to very long error outputs, which might be why -the cpp designers had obviously intended that recursion would not be possible. - -To be added: - -LIST_TOO_LONG - -cleanup list -DROP_EMPTY_ALL -DROP_EMPTY_LEFT -DROPE_EMPTY_RIGHT - -#define CAT(sep,first,...) \ - -Instead of comma separated lists consider instead to make a list with #define: -``` -#define LIST_1 -#define LIST_2 - -#ifdef LIST_2 - ... -`` - -*/ - -#ifndef CPP_EXT_1 -#define CPP_EXT_1 - -/*--------------------------------------------------------------------------- - Force extra macro expansion (the EVAL trick) - This chain of EVAL macros forces the preprocessor to perform many rescans, - which is necessary to “unroll” recursive macros. ----------------------------------------------------------------------------*/ - //#define EVAL(...) EVAL1024(__VA_ARGS__) - #define EVAL(...) EVAL32(__VA_ARGS__) - #define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__)) - #define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__)) - #define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__)) - #define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__)) - #define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__)) - #define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__)) - #define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__)) - #define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__)) - #define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__)) - #define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__)) - #define EVAL1(...) __VA_ARGS__ - -/*--------------------------------------------------------------------------- - Defer macros: these help “hide” recursive calls for additional expansion passes. ----------------------------------------------------------------------------*/ -// defined in cpp_ext_0: RETURN_NOTHING() - - #define DEFER1(m) \ - m RETURN_NOTHING() - #define DEFER2(m) \ - m RETURN_NOTHING RETURN_NOTHING()() - #define DEFER3(m) \ - m RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING()()() - #define DEFER4(m) \ - m RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING()()()() - #define DEFER5(m) \ - m RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING RETURN_NOTHING()()()()() - -/*--------------------------------------------------------------------------- - List operations - - number of EVALs required depends upon length list that is processed - - REST will return nothing on one of two conditions: that the list has - been exhausted, or that the list is about to be exhausted and it has nothing - after the last comma. To assure that a tailing item always gets sent - to the predicate, even when empty, we append an empty item. - ----------------------------------------------------------------------------*/ - // defined in cpp_ext_0: _FIRST(a ,...) a - - // returns found item or EOL() - #define _FIND(predicate ,...) \ - IF \ - (__VA_ARGS__) \ - (IF \ - ( predicate(_FIRST(__VA_ARGS__)) ) \ - ( _FIRST(__VA_ARGS__) ) \ - ( DEFER3(_FIND_CONFEDERATE)()(predicate ,REST(__VA_ARGS__)) ) \ - ) \ - (EOL()) - #define _FIND_CONFEDERATE() _FIND - #define FIND(predicate ,...) EVAL( _FIND(predicate ,__VA_ARGS__ ,) ) - - // true if list exhausted, false otherwise - #define _WHILE(predicate ,...) \ - IF \ - (__VA_ARGS__) \ - (IF \ - ( predicate(_FIRST(__VA_ARGS__)) ) \ - ( DEFER3(_WHILE_CONFEDERATE)()(predicate ,REST(__VA_ARGS__)) ) \ - () \ - ) \ - (1) - #define _WHILE_CONFEDERATE() _WHILE - #define WHILE(predicate ,...) EVAL( _WHILE(predicate ,__VA_ARGS__ ,) ) - - // returns true or false - #define _CONTAINS(item ,...) \ - IF \ - (__VA_ARGS__) \ - (IF \ - ( EQ(item ,_FIRST(__VA_ARGS__)) ) \ - ( 1 ) \ - ( DEFER3(_CONTAINS_CONFEDERATE)()(item ,REST(__VA_ARGS__)) ) \ - ) \ - () - #define _CONTAINS_CONFEDERATE() _CONTAINS - #define CONTAINS(predicate ,...) EVAL( _CONTAINS(predicate ,__VA_ARGS__ ,) ) - - // if no list, returns EOL(), else returns last item in the list - #define _LAST(...) \ - IF \ - (__VA_ARGS__) \ - ( _LAST_s(_FIRST(__VA_ARGS__) ,REST(__VA_ARGS__)) ) \ - (EOL()) - #define _LAST_s(item, ...) \ - IF \ - (__VA_ARGS__) \ - ( DEFER3(_LAST_s_CONFEDERATE)()(_FIRST(__VA_ARGS__) ,REST(__VA_ARGS__)) ) \ - (item) - #define _LAST_s_CONFEDERATE() _LAST_s - #define LAST(...) EVAL( _LAST(__VA_ARGS__ ,) ) - - #define CAT(sep ,...) \ - IF \ - (__VA_ARGS__) \ - (_CAT_s( sep ,__VA_ARGS__)) \ - () - - #define _CAT_s(sep ,a ,...)\ - IF \ - (__VA_ARGS__) \ - ( EVAL(_CAT_ss(sep ,a ,__VA_ARGS__)) ) \ - (a) - - #define _CAT_ss(sep ,accumulator ,a ,...) \ - IF \ - (__VA_ARGS__) \ - ( DEFER2(_CAT_ss_CONFEDERATE)()(sep ,accumulator##sep##a ,__VA_ARGS__) ) \ - (accumulator##sep##a) - - #define _CAT_ss_CONFEDERATE() _CAT_ss - - // comma does not work with CAT so use this, though perhaps list ,a would be faster? - #define APPEND(...) \ - IF \ - (__VA_ARGS__) \ - (_APPEND_s(__VA_ARGS__)) \ - () - - #define _APPEND_s(a ,...)\ - IF \ - (__VA_ARGS__) \ - ( EVAL(_APPEND_ss(a ,__VA_ARGS__)) ) \ - (a) - - #define _APPEND_ss(accumulator ,a ,...) \ - IF \ - (__VA_ARGS__) \ - ( DEFER2(_APPEND_ss_CONFEDERATE)()(accumulator, a, ,__VA_ARGS__) ) \ - (accumulator,a) - - #define _APPEND_ss_CONFEDERATE() _APPEND_ss - - -/*--------------------------------------------------------------------------- - Quantifiers ----------------------------------------------------------------------------*/ - - // AKA all quantification, returns true or false - #define AND(...) WHILE(EXISTS ,__VA_ARGS__) - - // AKA existence quantification, returns true or false - #define OR(...) NOT( WHILE(NOT ,__VA_ARGS__) ) - -/*--------------------------------------------------------------------------- - Access ----------------------------------------------------------------------------*/ - - #define FIRST(...) \ - IF( __VA_ARGS__ ) \ - ( _FIRST(__VA_ARGS__) ) \ - (EOL()) - - -#endif diff --git "a/developer/cc\360\237\226\211/scratch.c" "b/developer/cc\360\237\226\211/scratch.c" deleted file mode 100644 index 1e39535..0000000 --- "a/developer/cc\360\237\226\211/scratch.c" +++ /dev/null @@ -1,7 +0,0 @@ -// #if BOOLEAN( NOT_IN(TM·Array ,_TM·CVT_) ) -// #include ... -// #define ... -// - - -#if BOOLEAN( NOT_IN(TM·Array ,_TM·CVT_) ) diff --git a/developer/deprecated/.githolder b/developer/deprecated/.githolder new file mode 100644 index 0000000..e69de29 diff --git a/developer/deprecated/2025-03-29/N16.lib.c b/developer/deprecated/2025-03-29/N16.lib.c new file mode 100644 index 0000000..561b43d --- /dev/null +++ b/developer/deprecated/2025-03-29/N16.lib.c @@ -0,0 +1,433 @@ +/* + N16 - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N16·DEBUG + +#ifndef FACE +#define N16·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N16·FACE +#define N16·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint16_t Extent; + typedef uint16_t Digit; + + typedef struct N16·T N16·T; + + extern N16·T *N16·zero; + extern N16·T *N16·one; + extern N16·T *N16·all_one_bit; + extern N16·T *N16·lsb; + extern N16·T *N16·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N16·Status·ok = 0 + ,N16·Status·overflow = 1 + ,N16·Status·accumulator1_overflow = 2 + ,N16·Status·carry = 3 + ,N16·Status·borrow = 4 + ,N16·Status·undefined_divide_by_zero = 5 + ,N16·Status·undefined_modulus_zero = 6 + ,N16·Status·gt_max_shift_count = 7 + ,N16·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N16·Status·one_word_product = 9 + ,N16·Status·two_word_product = 10 + } N16·Status; + + typedef enum{ + N16·Order_lt = -1 + ,N16·Order_eq = 0 + ,N16·Order_gt = 1 + } N16·Order; + + typedef N16·T *( *N16·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N16·T *(*allocate_array_zero)(Extent, N16·Allocate_MemoryFault); + N16·T *(*allocate_array)(Extent, N16·Allocate_MemoryFault); + void (*deallocate)(N16·T*); + + void (*copy)(N16·T*, N16·T*); + void (*bit_and)(N16·T*, N16·T*, N16·T*); + void (*bit_or)(N16·T*, N16·T*, N16·T*); + void (*bit_complement)(N16·T*, N16·T*); + void (*bit_twos_complement)(N16·T*, N16·T*); + N16·Order (*compare)(N16·T*, N16·T*); + bool (*lt)(N16·T*, N16·T*); + bool (*gt)(N16·T*, N16·T*); + bool (*eq)(N16·T*, N16·T*); + bool (*eq_zero)(N16·T*); + N16·Status (*accumulate)(N16·T *accumulator1 ,N16·T *accumulator0 ,...); + N16·Status (*add)(N16·T*, N16·T*, N16·T*); + bool (*increment)(N16·T *a); + N16·Status (*subtract)(N16·T*, N16·T*, N16·T*); + N16·Status (*multiply)(N16·T*, N16·T*, N16·T*, N16·T*); + N16·Status (*divide)(N16·T*, N16·T*, N16·T*, N16·T*); + N16·Status (*modulus)(N16·T*, N16·T*, N16·T*); + N16·Status (*shift_left)(Extent, N16·T*, N16·T*, N16·T*); + N16·Status (*shift_right)(Extent, N16·T*, N16·T*, N16·T*); + N16·Status (*arithmetic_shift_right)(Extent, N16·T*, N16·T*); + + N16·T* (*access)(N16·T*, Extent); + void (*from_uint32)(N16·T *destination ,uint32_t value); + } N16·M; + + Local const N16·M N16·m; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N16·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N16·T{ + Digit d0; + }; + + N16·T N16·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint16_t)0}, + {.d0 = 1 << 15} + }; + + N16·T *N16·zero = &N16·constant[0]; + N16·T *N16·one = &N16·constant[1]; + N16·T *N16·all_one_bit = &N16·constant[2]; + N16·T *N16·msb = &N16·constant[3]; + N16·T *N16·lsb = &N16·constant[1]; + + // the allocate an array of N16 + N16·T *N16·allocate_array(Extent extent ,N16·Allocate_MemoryFault memory_fault){ + N16·T *instance = malloc((extent + 1) * sizeof(N16·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N16·T *N16·allocate_array_zero(Extent extent ,N16·Allocate_MemoryFault memory_fault){ + N16·T *instance = calloc(extent + 1, sizeof(N16·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N16·deallocate(N16·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N16·T{ + Digit d0; + }; + + // temporary variables + Local N16·T N16·t[4]; + + // allocation + + extern N16·T *N16·allocate_array(Extent, N16·Allocate_MemoryFault); + extern N16·T *N16·allocate_array_zero(Extent, N16·Allocate_MemoryFault); + extern void N16·deallocate(N16·T *); + + // so the user can access numbers in an array allocation + Local N16·T* N16·access(N16·T *array ,Extent index){ + return &array[index]; + } + + Local void N16·from_uint32(N16·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint16_t)(value & 0xFFFF); + } + + // copy, convenience copy + + Local void N16·copy(N16·T *destination ,N16·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N16·set_to_zero(N16·T *instance){ + instance->d0 = 0; + } + + Local void N16·set_to_one(N16·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N16·bit_and(N16·T *result, N16·T *a, N16·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N16·bit_or(N16·T *result, N16·T *a, N16·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N16·bit_complement(N16·T *result, N16·T *a){ + result->d0 = ~a->d0; + } + + Local void N16·bit_twos_complement(N16·T *result ,N16·T *a){ + result->d0 = (uint16_t)(~a->d0 + 1); + } + + // test functions + + Local N16·Order N16·compare(N16·T *a, N16·T *b){ + if(a->d0 < b->d0) return N16·Order_lt; + if(a->d0 > b->d0) return N16·Order_gt; + return N16·Order_eq; + } + + Local bool N16·lt(N16·T *a ,N16·T *b){ + return a->d0 < b->d0; + } + + Local bool N16·gt(N16·T *a ,N16·T *b){ + return a->d0 > b->d0; + } + + Local bool N16·eq(N16·T *a ,N16·T *b){ + return a->d0 == b->d0; + } + + Local bool N16·eq_zero(N16·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N16·Status N16·accumulate(N16·T *accumulator1 ,N16·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N16·T *current; + + while( (current = va_arg(args ,N16·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N16·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint16_t)carry; + return N16·Status·ok; + } + + Local N16·Status N16·add(N16·T *sum ,N16·T *a ,N16·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint16_t)(result & 0xFFFF); + return (result >> 16) ? N16·Status·carry : N16·Status·ok; + } + + Local bool N16·increment(N16·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N16·Status N16·subtract(N16·T *difference ,N16·T *a ,N16·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint16_t)(diff & 0xFFFF); + return (diff > a->d0) ? N16·Status·borrow : N16·Status·ok; + } + + Local N16·Status N16·multiply(N16·T *product1 ,N16·T *product0 ,N16·T *a ,N16·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint16_t)(product & 0xFFFF); + product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); + + if(product1->d0 == 0) return N16·Status·one_word_product; + return N16·Status·two_word_product; + } + + Local N16·Status N16·divide(N16·T *remainder ,N16·T *quotient ,N16·T *a ,N16·T *b){ + if(b->d0 == 0) return N16·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint16_t)(dividend / divisor); + remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); + + return N16·Status·ok; + } + + Local N16·Status N16·modulus(N16·T *remainder ,N16·T *a ,N16·T *b){ + if(b->d0 == 0) return N16·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint16_t)(dividend - (q * divisor)); + return N16·Status·ok; + } + + // bit motion + + typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); + + Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ + return value << amount; + } + + Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ + return (uint16_t)(value >> amount); + } + + Local N16·Status N16·shift + ( + uint16_t shift_count + ,N16·T *spill + ,N16·T *operand + ,N16·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N16·Status·ok; + + if(operand == NULL){ + operand = &N16·t[0]; + N16·copy(operand, N16·zero); + } + + if(shift_count > 15) return N16·Status·gt_max_shift_count; + + N16·T *given_operand = &N16·t[1]; + N16·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); + N16·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); + } + + return N16·Status·ok; + } + + Local N16·Status + N16·shift_left(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ + return N16·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N16·Status + N16·shift_right(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ + return N16·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N16·Status + N16·arithmetic_shift_right(uint16_t shift_count, N16·T *operand, N16·T *spill){ + + if(shift_count > 15) return N16·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N16·t[0]; + N16·copy(operand, N16·zero); + } + + N16·T *fill = (operand->d0 & 0x8000) ? N16·all_one_bit : N16·zero; + return N16·shift_right(shift_count, spill, operand, fill); + } + + Local const N16·M N16·m = { + + .allocate_array = N16·allocate_array + ,.allocate_array_zero = N16·allocate_array_zero + ,.deallocate = N16·deallocate + + ,.copy = N16·copy + ,.bit_and = N16·bit_and + ,.bit_or = N16·bit_or + ,.bit_complement = N16·bit_complement + ,.bit_twos_complement = N16·bit_twos_complement + ,.compare = N16·compare + ,.lt = N16·lt + ,.gt = N16·gt + ,.eq = N16·eq + ,.eq_zero = N16·eq_zero + ,.accumulate = N16·accumulate + ,.add = N16·add + ,.increment = N16·increment + ,.subtract = N16·subtract + ,.multiply = N16·multiply + ,.divide = N16·divide + ,.modulus = N16·modulus + ,.shift_left = N16·shift_left + ,.shift_right = N16·shift_right + ,.arithmetic_shift_right = N16·arithmetic_shift_right + + ,.access = N16·access + ,.from_uint32 = N16·from_uint32 + }; + + #endif + +#endif diff --git a/developer/deprecated/2025-03-29/N32.lib.c b/developer/deprecated/2025-03-29/N32.lib.c new file mode 100644 index 0000000..ccb3411 --- /dev/null +++ b/developer/deprecated/2025-03-29/N32.lib.c @@ -0,0 +1,457 @@ +/* + N32 - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) + +*/ + +#define N32·DEBUG + +#ifndef FACE +#define N32·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N32·FACE +#define N32·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint32_t Extent; + typedef uint32_t Digit; + + typedef struct N32·T N32·T; + + extern N32·T *N32·zero; + extern N32·T *N32·one; + extern N32·T *N32·all_one_bit; + extern N32·T *N32·lsb; + extern N32·T *N32·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N32·Status·ok = 0 + ,N32·Status·overflow = 1 + ,N32·Status·accumulator1_overflow = 2 + ,N32·Status·carry = 3 + ,N32·Status·borrow = 4 + ,N32·Status·undefined_divide_by_zero = 5 + ,N32·Status·undefined_modulus_zero = 6 + ,N32·Status·gt_max_shift_count = 7 + ,N32·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N32·Status·one_word_product = 9 + ,N32·Status·two_word_product = 10 + } N32·Status; + + typedef enum{ + N32·Order_lt = -1 + ,N32·Order_eq = 0 + ,N32·Order_gt = 1 + } N32·Order; + + typedef N32·T *( *N32·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N32·T *(*allocate_array_zero)(Extent, N32·Allocate_MemoryFault); + N32·T *(*allocate_array)(Extent, N32·Allocate_MemoryFault); + void (*deallocate)(N32·T*); + + void (*copy)(N32·T*, N32·T*); + void (*bit_and)(N32·T*, N32·T*, N32·T*); + void (*bit_or)(N32·T*, N32·T*, N32·T*); + void (*bit_complement)(N32·T*, N32·T*); + void (*bit_twos_complement)(N32·T*, N32·T*); + N32·Order (*compare)(N32·T*, N32·T*); + bool (*lt)(N32·T*, N32·T*); + bool (*gt)(N32·T*, N32·T*); + bool (*eq)(N32·T*, N32·T*); + bool (*eq_zero)(N32·T*); + N32·Status (*accumulate)(N32·T *accumulator1 ,N32·T *accumulator0 ,...); + N32·Status (*add)(N32·T*, N32·T*, N32·T*); + bool (*increment)(N32·T *a); + N32·Status (*subtract)(N32·T*, N32·T*, N32·T*); + N32·Status (*multiply)(N32·T*, N32·T*, N32·T*, N32·T*); + N32·Status (*divide)(N32·T*, N32·T*, N32·T*, N32·T*); + N32·Status (*modulus)(N32·T*, N32·T*, N32·T*); + N32·Status (*shift_left)(Extent, N32·T*, N32·T*, N32·T*); + N32·Status (*shift_right)(Extent, N32·T*, N32·T*, N32·T*); + N32·Status (*arithmetic_shift_right)(Extent, N32·T*, N32·T*); + + N32·T* (*access)(N32·T*, Extent); + void (*from_uint32)(N32·T *destination ,uint32_t value); + } N32·M; + + Local const N32·M N32·m; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N32·T{ + Digit d0; + }; + + N32·T N32·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint32_t)0}, + {.d0 = 1 << 31} + }; + + N32·T *N32·zero = &N32·constant[0]; + N32·T *N32·one = &N32·constant[1]; + N32·T *N32·all_one_bit = &N32·constant[2]; + N32·T *N32·msb = &N32·constant[3]; + N32·T *N32·lsb = &N32·constant[1]; + + // the allocate an array of N32 + N32·T *N32·allocate_array(Extent extent ,N32·Allocate_MemoryFault memory_fault){ + N32·T *instance = malloc((extent + 1) * sizeof(N32·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N32·T *N32·allocate_array_zero(Extent extent ,N32·Allocate_MemoryFault memory_fault){ + N32·T *instance = calloc( extent + 1 ,sizeof(N32·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N32·deallocate(N32·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N32·T{ + Digit d0; + }; + + // temporary variables + // making these LOCAL rather than reserving one block in the library is thread safe + // allocating a block once is more efficient + // library code writes these, they are not on the interface + + Local N32·T N32·t[4]; + + + // allocation + + extern N32·T *N32·allocate_array(Extent, N32·Allocate_MemoryFault); + extern N32·T *N32·allocate_array_zero(Extent, N32·Allocate_MemoryFault); + extern void N32·deallocate(N32·T *); + + // so the user can access numbers in an array allocation + Local N32·T* N32·access(N32·T *array ,Extent index){ + return &array[index]; + } + + Local void N32·from_uint32(N32·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy, convenience copy + + Local void N32·copy(N32·T *destination ,N32·T *source){ + if(source == destination) return; // that was easy! + *destination = *source; + } + + Local void N32·set_to_zero(N32·T *instance){ + instance->d0 = 0; + } + + Local void N32·set_to_one(N32·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N32·bit_and(N32·T *result, N32·T *a, N32·T *b){ + result->d0 = a->d0 & b->d0; + } + + // result can be one of the operands + Local void N32·bit_or(N32·T *result, N32·T *a, N32·T *b){ + result->d0 = a->d0 | b->d0; + } + + // result can the same as the operand + Local void N32·bit_complement(N32·T *result, N32·T *a){ + result->d0 = ~a->d0; + } + + // result can the same as the operand + Local void N32·bit_twos_complement(N32·T *result ,N32·T *a){ + result->d0 = ~a->d0 + 1; + } + + // test functions + + Local N32·Order N32·compare(N32·T *a, N32·T *b){ + if(a->d0 < b->d0) return N32·Order_lt; + if(a->d0 > b->d0) return N32·Order_gt; + return N32·Order_eq; + } + + Local bool N32·lt(N32·T *a ,N32·T *b){ + return a->d0 < b->d0; + } + + Local bool N32·gt(N32·T *a ,N32·T *b){ + return a->d0 > b->d0; + } + + Local bool N32·eq(N32·T *a ,N32·T *b){ + return a->d0 == b->d0; + } + + Local bool N32·eq_zero(N32·T *a){ + return a->d0 == 0; + } + + + // arithmetic operations + + // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32·Status·accumulator1_overflow + // + // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. + Local N32·Status N32·accumulate(N32·T *accumulator1 ,N32·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N32·T *current; + + while( (current = va_arg(args ,N32·T *)) ){ + sum += current->d0; + if(sum < current->d0){ // Accumulator1 into carry + (carry)++; + if(carry == 0){ + va_end(args); + return N32·Status·accumulator1_overflow; + } + } + } + va_end(args); + + // wipes out prior value of accumulator1 + accumulator1->d0 = carry; + + return N32·Status·ok; + } + + Local N32·Status N32·add(N32·T *sum ,N32·T *a ,N32·T *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N32·Status·carry : N32·Status·ok; + } + + Local bool N32·increment(N32·T *a){ + a->d0++; + return a->d0 == 0; + } + + Local N32·Status N32·subtract(N32·T *difference ,N32·T *a ,N32·T *b){ + uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N32·Status·borrow : N32·Status·ok; + } + + + Local N32·Status N32·multiply(N32·T *product1 ,N32·T *product0 ,N32·T *a ,N32·T *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + product0->d0 = (uint32_t)product; + product1->d0 = (uint32_t)(product >> 32); + + if(product1->d0 == 0) return N32·Status·one_word_product; + return N32·Status·two_word_product; + } + + Local N32·Status N32·divide(N32·T *remainder ,N32·T *quotient ,N32·T *a ,N32·T *b){ + if(b->d0 == 0) return N32·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N32·Status·ok; + } + + Local N32·Status N32·modulus(N32·T *remainder ,N32·T *a ,N32·T *b){ + if(b->d0 == 0) return N32·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N32·Status·ok; + } + + // bit motion + + typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); + + Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ + return value << amount; + } + + Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ + return value >> amount; + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, + Local N32·Status N32·shift + ( + uint32_t shift_count + ,N32·T *spill + ,N32·T *operand + ,N32·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + // If no result is needed, return immediately. + if(operand == NULL && spill == NULL) return N32·Status·ok; + + // Treat NULL operand as zero. + if(operand == NULL){ + operand = &N32·t[0]; + N32·copy(operand, N32·zero); + } + + // Shifting more than one word breaks our fill/spill model. + if(shift_count > 31) return N32·Status·gt_max_shift_count; + + // The given operand is still required after it is modified, so we copy it. + N32·T *given_operand = &N32·t[1]; + N32·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); + N32·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); + } + + return N32·Status·ok; + } + + // Define concrete shift functions using valid C function pointers + Local N32·Status + N32·shift_left(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ + return N32·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N32·Status + N32·shift_right(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ + return N32·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N32·Status + N32·arithmetic_shift_right(uint32_t shift_count, N32·T *operand, N32·T *spill){ + + // Guard against excessive shift counts + if(shift_count > 31) return N32·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N32·t[0]; + N32·copy(operand, N32·zero); + } + + // Pick the fill value based on the sign bit + N32·T *fill = (operand->d0 & 0x80000000) ? N32·all_one_bit : N32·zero; + + // Call shift_right with the appropriate fill + return N32·shift_right(shift_count, spill, operand, fill); + } + + Local const N32·M N32·m = { + + .allocate_array = N32·allocate_array + ,.allocate_array_zero = N32·allocate_array_zero + ,.deallocate = N32·deallocate + + ,.copy = N32·copy + ,.bit_and = N32·bit_and + ,.bit_or = N32·bit_or + ,.bit_complement = N32·bit_complement + ,.bit_twos_complement = N32·bit_twos_complement + ,.compare = N32·compare + ,.lt = N32·lt + ,.gt = N32·gt + ,.eq = N32·eq + ,.eq_zero = N32·eq_zero + ,.accumulate = N32·accumulate + ,.add = N32·add + ,.increment = N32·increment + ,.subtract = N32·subtract + ,.multiply = N32·multiply + ,.divide = N32·divide + ,.modulus = N32·modulus + ,.shift_left = N32·shift_left + ,.shift_right = N32·shift_right + ,.arithmetic_shift_right = N32·arithmetic_shift_right + + ,.access = N32·access + ,.from_uint32 = N32·from_uint32 + }; + + #endif + +#endif diff --git a/developer/deprecated/2025-03-29/N64.lib.c b/developer/deprecated/2025-03-29/N64.lib.c new file mode 100644 index 0000000..6058e9b --- /dev/null +++ b/developer/deprecated/2025-03-29/N64.lib.c @@ -0,0 +1,477 @@ +/* + N64 - a 64-bit native type + + For binary operations: a op b -> c + + Similar to N32, but now each Digit is 64 bits. Where a 128-bit + intermediate is necessary (e.g. multiplication), we handle it + manually using two 64-bit parts. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N64·DEBUG + +#ifndef FACE +#define N64·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N64·FACE +#define N64·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint64_t Extent; + typedef uint64_t Digit; + + typedef struct N64·T N64·T; + + extern N64·T *N64·zero; + extern N64·T *N64·one; + extern N64·T *N64·all_one_bit; + extern N64·T *N64·lsb; + extern N64·T *N64·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum { + N64·Status·ok = 0 + ,N64·Status·overflow = 1 + ,N64·Status·accumulator1_overflow = 2 + ,N64·Status·carry = 3 + ,N64·Status·borrow = 4 + ,N64·Status·undefined_divide_by_zero = 5 + ,N64·Status·undefined_modulus_zero = 6 + ,N64·Status·gt_max_shift_count = 7 + ,N64·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value + ,N64·Status·one_word_product = 9 + ,N64·Status·two_word_product = 10 + } N64·Status; + + typedef enum { + N64·Order_lt = -1 + ,N64·Order_eq = 0 + ,N64·Order_gt = 1 + } N64·Order; + + typedef N64·T *(*N64·Allocate_MemoryFault)(Extent); + + //---------------------------------------- + // Interface + + typedef struct { + + N64·T *(*allocate_array_zero)(Extent, N64·Allocate_MemoryFault); + N64·T *(*allocate_array)(Extent, N64·Allocate_MemoryFault); + void (*deallocate)(N64·T*); + + void (*copy)(N64·T*, N64·T*); + void (*bit_and)(N64·T*, N64·T*, N64·T*); + void (*bit_or)(N64·T*, N64·T*, N64·T*); + void (*bit_complement)(N64·T*, N64·T*); + void (*bit_twos_complement)(N64·T*, N64·T*); + N64·Order (*compare)(N64·T*, N64·T*); + bool (*lt)(N64·T*, N64·T*); + bool (*gt)(N64·T*, N64·T*); + bool (*eq)(N64·T*, N64·T*); + bool (*eq_zero)(N64·T*); + N64·Status (*accumulate)(N64·T *accumulator1, N64·T *accumulator0, ...); + N64·Status (*add)(N64·T*, N64·T*, N64·T*); + bool (*increment)(N64·T *a); + N64·Status (*subtract)(N64·T*, N64·T*, N64·T*); + N64·Status (*multiply)(N64·T*, N64·T*, N64·T*, N64·T*); + N64·Status (*divide)(N64·T*, N64·T*, N64·T*, N64·T*); + N64·Status (*modulus)(N64·T*, N64·T*, N64·T*); + N64·Status (*shift_left)(Extent, N64·T*, N64·T*, N64·T*); + N64·Status (*shift_right)(Extent, N64·T*, N64·T*, N64·T*); + N64·Status (*arithmetic_shift_right)(Extent, N64·T*, N64·T*); + + N64·T* (*access)(N64·T*, Extent); + void (*from_uint64)(N64·T *destination, uint64_t value); + + } N64·M; + + Local const N64·M N64·m; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N64·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N64·T { + Digit d0; + }; + + // For constants, we store them in an array for convenience + // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) + N64·T N64·constant[4] = { + {.d0 = 0ULL}, + {.d0 = 1ULL}, + {.d0 = ~(uint64_t)0ULL}, + {.d0 = 1ULL << 63} + }; + + N64·T *N64·zero = &N64·constant[0]; + N64·T *N64·one = &N64·constant[1]; + N64·T *N64·all_one_bit = &N64·constant[2]; + N64·T *N64·msb = &N64·constant[3]; + N64·T *N64·lsb = &N64·constant[1]; + + // allocate an array of N64 + N64·T *N64·allocate_array(Extent extent, N64·Allocate_MemoryFault memory_fault){ + N64·T *instance = malloc( (extent + 1) * sizeof(N64·T) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N64·T *N64·allocate_array_zero(Extent extent, N64·Allocate_MemoryFault memory_fault){ + N64·T *instance = calloc(extent + 1, sizeof(N64·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N64·deallocate(N64·T *unencumbered){ + free(unencumbered); + } + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N64·T { + Digit d0; + }; + + // local temporary variables + Local N64·T N64·t[4]; + + // allocation references + extern N64·T *N64·allocate_array(Extent, N64·Allocate_MemoryFault); + extern N64·T *N64·allocate_array_zero(Extent, N64·Allocate_MemoryFault); + extern void N64·deallocate(N64·T *); + + // Access array + Local N64·T* N64·access(N64·T *array, Extent index){ + return &array[index]; + } + + Local void N64·from_uint64(N64·T *destination, uint64_t value){ + if(destination == NULL) return; + destination->d0 = value; + } + + // copy + Local void N64·copy(N64·T *destination, N64·T *source){ + if(source == destination) return; + *destination = *source; + } + + // bit operations + + Local void N64·bit_and(N64·T *result, N64·T *a, N64·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N64·bit_or(N64·T *result, N64·T *a, N64·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N64·bit_complement(N64·T *result, N64·T *a){ + result->d0 = ~a->d0; + } + + Local void N64·bit_twos_complement(N64·T *result, N64·T *a){ + result->d0 = ~a->d0 + 1ULL; + } + + // compare & test functions + + Local N64·Order N64·compare(N64·T *a, N64·T *b){ + if(a->d0 < b->d0) return N64·Order_lt; + if(a->d0 > b->d0) return N64·Order_gt; + return N64·Order_eq; + } + + Local bool N64·lt(N64·T *a, N64·T *b){ + return (a->d0 < b->d0); + } + + Local bool N64·gt(N64·T *a, N64·T *b){ + return (a->d0 > b->d0); + } + + Local bool N64·eq(N64·T *a, N64·T *b){ + return (a->d0 == b->d0); + } + + Local bool N64·eq_zero(N64·T *a){ + return (a->d0 == 0ULL); + } + + // arithmetic operations + + // accumulate + Local N64·Status N64·accumulate(N64·T *accumulator1, N64·T *accumulator0, ...){ + va_list args; + va_start(args, accumulator0); + + uint64_t sum = accumulator0->d0; + uint64_t carry = 0; + N64·T *current; + + while( (current = va_arg(args, N64·T*)) ){ + uint64_t prior = sum; + sum += current->d0; + if(sum < prior){ // indicates carry + carry++; + // if carry overflowed a 64-bit, that's an accumulator1 overflow + if(carry == 0ULL){ + va_end(args); + return N64·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = carry; + return N64·Status·ok; + } + + // add + Local N64·Status N64·add(N64·T *sum, N64·T *a, N64·T *b){ + __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; + // But to avoid using a GNU extension, we can do the simpler approach: + // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: + uint64_t temp = a->d0 + b->d0; + sum->d0 = temp; + if(temp < a->d0) return N64·Status·carry; // means we overflowed + return N64·Status·ok; + } + + Local bool N64·increment(N64·T *a){ + uint64_t old = a->d0; + a->d0++; + // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF + return (a->d0 < old); + } + + // subtract + Local N64·Status N64·subtract(N64·T *difference, N64·T *a, N64·T *b){ + uint64_t tmpA = a->d0; + uint64_t tmpB = b->d0; + uint64_t diff = tmpA - tmpB; + difference->d0 = diff; + if(diff > tmpA) return N64·Status·borrow; // indicates we borrowed + return N64·Status·ok; + } + + // multiply + // We'll do a 64x64->128 using two 64-bit accumulators + Local N64·Status N64·multiply(N64·T *product1, N64·T *product0, N64·T *a, N64·T *b){ + uint64_t A = a->d0; + uint64_t B = b->d0; + + // Break each operand into high & low 32 bits + uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); + uint64_t a_hi = A >> 32; + uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); + uint64_t b_hi = B >> 32; + + // partial products + uint64_t low = a_lo * b_lo; // 64-bit + uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits + uint64_t high = a_hi * b_hi; // up to 64 bits + + // incorporate cross into low, high + // cross is effectively the middle bits, so shift cross by 32 and add to low + uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part + uint64_t cross_high = cross >> 32; // upper part + + // add cross_low to low, capture carry + uint64_t old_low = low; + low += cross_low; + if(low < old_low) cross_high++; + + // final high + high += cross_high; + + // store results + product0->d0 = low; + product1->d0 = high; + + if(high == 0ULL) return N64·Status·one_word_product; + return N64·Status·two_word_product; + } + + // divide + Local N64·Status N64·divide(N64·T *remainder, N64·T *quotient, N64·T *a, N64·T *b){ + // we do not handle a > 64-bit, just the single 64-bit + if(b->d0 == 0ULL) return N64·Status·undefined_divide_by_zero; + + uint64_t divd = a->d0; // dividend + uint64_t divs = b->d0; // divisor + + quotient->d0 = divd / divs; + remainder->d0 = divd - (quotient->d0 * divs); + + return N64·Status·ok; + } + + // modulus + Local N64·Status N64·modulus(N64·T *remainder, N64·T *a, N64·T *b){ + if(b->d0 == 0ULL) return N64·Status·undefined_modulus_zero; + + uint64_t divd = a->d0; + uint64_t divs = b->d0; + uint64_t q = divd / divs; + remainder->d0 = divd - (q * divs); + + return N64·Status·ok; + } + + // bit motion + + typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); + + Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ + return (value << amount); + } + + Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ + return (value >> amount); + } + + // modifies all three of its operands + // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill + Local N64·Status N64·shift + ( + uint64_t shift_count, + N64·T *spill, + N64·T *operand, + N64·T *fill, + ShiftOp shift_op, + ShiftOp complement_shift_op + ){ + if(operand == NULL && spill == NULL) return N64·Status·ok; + + // Treat NULL operand as zero + if(operand == NULL){ + operand = &N64·t[0]; + N64·copy(operand, N64·zero); + } + + // Shifting more than 63 bits breaks fill/spill logic + if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; + + N64·T *given_operand = &N64·t[1]; + N64·copy(given_operand, operand); + + // Perform the shift + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); + N64·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); + } + + return N64·Status·ok; + } + + Local N64·Status N64·shift_left(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ + return N64·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N64·Status N64·shift_right(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ + return N64·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N64·Status N64·arithmetic_shift_right(uint64_t shift_count, N64·T *operand, N64·T *spill){ + if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; + + // A NULL operand is treated as zero + if(operand == NULL){ + operand = &N64·t[0]; + N64·copy(operand, N64·zero); + } + + // sign bit check + N64·T *fill = (operand->d0 & (1ULL << 63)) ? N64·all_one_bit : N64·zero; + return N64·shift_right(shift_count, spill, operand, fill); + } + + Local const N64·M N64·m = { + .allocate_array = N64·allocate_array + ,.allocate_array_zero = N64·allocate_array_zero + ,.deallocate = N64·deallocate + + ,.copy = N64·copy + ,.bit_and = N64·bit_and + ,.bit_or = N64·bit_or + ,.bit_complement = N64·bit_complement + ,.bit_twos_complement = N64·bit_twos_complement + ,.compare = N64·compare + ,.lt = N64·lt + ,.gt = N64·gt + ,.eq = N64·eq + ,.eq_zero = N64·eq_zero + ,.accumulate = N64·accumulate + ,.add = N64·add + ,.increment = N64·increment + ,.subtract = N64·subtract + ,.multiply = N64·multiply + ,.divide = N64·divide + ,.modulus = N64·modulus + ,.shift_left = N64·shift_left + ,.shift_right = N64·shift_right + ,.arithmetic_shift_right = N64·arithmetic_shift_right + + ,.access = N64·access + ,.from_uint64 = N64·from_uint64 + }; + + #endif + +#endif diff --git a/developer/deprecated/2025-03-29/N8.lib.c b/developer/deprecated/2025-03-29/N8.lib.c new file mode 100644 index 0000000..df6e01c --- /dev/null +++ b/developer/deprecated/2025-03-29/N8.lib.c @@ -0,0 +1,433 @@ +/* + N8 - PN = refers to the use of processor native accumulator + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) +*/ + +#define N8·DEBUG + +#ifndef FACE +#define N8·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef N8·FACE +#define N8·FACE + + #include + #include + #include + #include + + //---------------------------------------- + // Instance Data (Declaration Only) + + typedef uint8_t Extent; + typedef uint8_t Digit; + + typedef struct N8·T N8·T; + + extern N8·T *N8·zero; + extern N8·T *N8·one; + extern N8·T *N8·all_one_bit; + extern N8·T *N8·lsb; + extern N8·T *N8·msb; + + //---------------------------------------- + // Return/Error Status and handlers + + typedef enum{ + N8·Status·ok = 0 + ,N8·Status·overflow = 1 + ,N8·Status·accumulator1_overflow = 2 + ,N8·Status·carry = 3 + ,N8·Status·borrow = 4 + ,N8·Status·undefined_divide_by_zero = 5 + ,N8·Status·undefined_modulus_zero = 6 + ,N8·Status·gt_max_shift_count = 7 + ,N8·Status·spill_eq_operand = 8 + ,N8·Status·one_word_product = 9 + ,N8·Status·two_word_product = 10 + } N8·Status; + + typedef enum{ + N8·Order_lt = -1 + ,N8·Order_eq = 0 + ,N8·Order_gt = 1 + } N8·Order; + + typedef N8·T *( *N8·Allocate_MemoryFault )(Extent); + + //---------------------------------------- + // Interface + + typedef struct{ + + N8·T *(*allocate_array_zero)(Extent, N8·Allocate_MemoryFault); + N8·T *(*allocate_array)(Extent, N8·Allocate_MemoryFault); + void (*deallocate)(N8·T*); + + void (*copy)(N8·T*, N8·T*); + void (*bit_and)(N8·T*, N8·T*, N8·T*); + void (*bit_or)(N8·T*, N8·T*, N8·T*); + void (*bit_complement)(N8·T*, N8·T*); + void (*bit_twos_complement)(N8·T*, N8·T*); + N8·Order (*compare)(N8·T*, N8·T*); + bool (*lt)(N8·T*, N8·T*); + bool (*gt)(N8·T*, N8·T*); + bool (*eq)(N8·T*, N8·T*); + bool (*eq_zero)(N8·T*); + N8·Status (*accumulate)(N8·T *accumulator1 ,N8·T *accumulator0 ,...); + N8·Status (*add)(N8·T*, N8·T*, N8·T*); + bool (*increment)(N8·T *a); + N8·Status (*subtract)(N8·T*, N8·T*, N8·T*); + N8·Status (*multiply)(N8·T*, N8·T*, N8·T*, N8·T*); + N8·Status (*divide)(N8·T*, N8·T*, N8·T*, N8·T*); + N8·Status (*modulus)(N8·T*, N8·T*, N8·T*); + N8·Status (*shift_left)(Extent, N8·T*, N8·T*, N8·T*); + N8·Status (*shift_right)(Extent, N8·T*, N8·T*, N8·T*); + N8·Status (*arithmetic_shift_right)(Extent, N8·T*, N8·T*); + + N8·T* (*access)(N8·T*, Extent); + void (*from_uint32)(N8·T *destination ,uint32_t value); + } N8·M; + + Local const N8·M N8·m; // initialized in the LOCAL section + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N8·IMPLEMENTATION + + // this part goes into the library + #ifndef LOCAL + + #include + #include + + struct N8·T{ + Digit d0; + }; + + N8·T N8·constant[4] = { + {.d0 = 0}, + {.d0 = 1}, + {.d0 = ~(uint8_t)0}, + {.d0 = 1 << 7} + }; + + N8·T *N8·zero = &N8·constant[0]; + N8·T *N8·one = &N8·constant[1]; + N8·T *N8·all_one_bit = &N8·constant[2]; + N8·T *N8·msb = &N8·constant[3]; + N8·T *N8·lsb = &N8·constant[1]; + + // the allocate an array of N8 + N8·T *N8·allocate_array(Extent extent ,N8·Allocate_MemoryFault memory_fault){ + N8·T *instance = malloc((extent + 1) * sizeof(N8·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N8·T *N8·allocate_array_zero(Extent extent ,N8·Allocate_MemoryFault memory_fault){ + N8·T *instance = calloc(extent + 1, sizeof(N8·T)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + void N8·deallocate(N8·T *unencumbered){ + free(unencumbered); + } + + + #endif + + // This part is included after the library user's code + #ifdef LOCAL + + // instance + + struct N8·T{ + Digit d0; + }; + + // temporary variables + Local N8·T N8·t[4]; + + // allocation + + extern N8·T *N8·allocate_array(Extent, N8·Allocate_MemoryFault); + extern N8·T *N8·allocate_array_zero(Extent, N8·Allocate_MemoryFault); + extern void N8·deallocate(N8·T *); + + // so the user can access numbers in an array allocation + Local N8·T* N8·access(N8·T *array ,Extent index){ + return &array[index]; + } + + Local void N8·from_uint32(N8·T *destination ,uint32_t value){ + if(destination == NULL) return; + destination->d0 = (uint8_t)(value & 0xFF); + } + + // copy, convenience copy + + Local void N8·copy(N8·T *destination ,N8·T *source){ + if(source == destination) return; + *destination = *source; + } + + Local void N8·set_to_zero(N8·T *instance){ + instance->d0 = 0; + } + + Local void N8·set_to_one(N8·T *instance){ + instance->d0 = 1; + } + + // bit operations + + Local void N8·bit_and(N8·T *result, N8·T *a, N8·T *b){ + result->d0 = a->d0 & b->d0; + } + + Local void N8·bit_or(N8·T *result, N8·T *a, N8·T *b){ + result->d0 = a->d0 | b->d0; + } + + Local void N8·bit_complement(N8·T *result, N8·T *a){ + result->d0 = ~a->d0; + } + + Local void N8·bit_twos_complement(N8·T *result ,N8·T *a){ + result->d0 = (uint8_t)(~a->d0 + 1); + } + + // test functions + + Local N8·Order N8·compare(N8·T *a, N8·T *b){ + if(a->d0 < b->d0) return N8·Order_lt; + if(a->d0 > b->d0) return N8·Order_gt; + return N8·Order_eq; + } + + Local bool N8·lt(N8·T *a ,N8·T *b){ + return a->d0 < b->d0; + } + + Local bool N8·gt(N8·T *a ,N8·T *b){ + return a->d0 > b->d0; + } + + Local bool N8·eq(N8·T *a ,N8·T *b){ + return a->d0 == b->d0; + } + + Local bool N8·eq_zero(N8·T *a){ + return a->d0 == 0; + } + + // arithmetic operations + + Local N8·Status N8·accumulate(N8·T *accumulator1 ,N8·T *accumulator0 ,...){ + + va_list args; + va_start(args ,accumulator0); + uint32_t sum = accumulator0->d0; + uint32_t carry = 0; + N8·T *current; + + while( (current = va_arg(args ,N8·T*)) ){ + sum += current->d0; + if(sum < current->d0){ + (carry)++; + if(carry == 0){ + va_end(args); + return N8·Status·accumulator1_overflow; + } + } + } + va_end(args); + + accumulator1->d0 = (uint8_t)carry; + return N8·Status·ok; + } + + Local N8·Status N8·add(N8·T *sum ,N8·T *a ,N8·T *b){ + uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; + sum->d0 = (uint8_t)(result & 0xFF); + return (result >> 8) ? N8·Status·carry : N8·Status·ok; + } + + Local bool N8·increment(N8·T *a){ + a->d0++; + return (a->d0 == 0); + } + + Local N8·Status N8·subtract(N8·T *difference ,N8·T *a ,N8·T *b){ + uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; + difference->d0 = (uint8_t)(diff & 0xFF); + return (diff > a->d0) ? N8·Status·borrow : N8·Status·ok; + } + + Local N8·Status N8·multiply(N8·T *product1 ,N8·T *product0 ,N8·T *a ,N8·T *b){ + uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; + product0->d0 = (uint8_t)(product & 0xFF); + product1->d0 = (uint8_t)((product >> 8) & 0xFF); + + if(product1->d0 == 0) return N8·Status·one_word_product; + return N8·Status·two_word_product; + } + + Local N8·Status N8·divide(N8·T *remainder ,N8·T *quotient ,N8·T *a ,N8·T *b){ + if(b->d0 == 0) return N8·Status·undefined_divide_by_zero; + + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + quotient->d0 = (uint8_t)(dividend / divisor); + remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); + + return N8·Status·ok; + } + + Local N8·Status N8·modulus(N8·T *remainder ,N8·T *a ,N8·T *b){ + if(b->d0 == 0) return N8·Status·undefined_modulus_zero; + uint32_t dividend = a->d0; + uint32_t divisor = b->d0; + uint32_t q = dividend / divisor; + remainder->d0 = (uint8_t)(dividend - (q * divisor)); + return N8·Status·ok; + } + + // bit motion + + typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); + + Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value << amount); + } + + Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ + return (uint8_t)(value >> amount); + } + + Local N8·Status N8·shift + ( + uint8_t shift_count + ,N8·T *spill + ,N8·T *operand + ,N8·T *fill + ,ShiftOp shift_op + ,ShiftOp complement_shift_op + ){ + + if(operand == NULL && spill == NULL) return N8·Status·ok; + + if(operand == NULL){ + operand = &N8·t[0]; + N8·copy(operand, N8·zero); + } + + if(shift_count > 7) return N8·Status·gt_max_shift_count; + + N8·T *given_operand = &N8·t[1]; + N8·copy(given_operand, operand); + + operand->d0 = shift_op(given_operand->d0, shift_count); + if(fill != NULL){ + fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); + N8·bit_or(operand, operand, fill); + } + if(spill != NULL){ + spill->d0 = shift_op(spill->d0, shift_count); + spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); + } + + return N8·Status·ok; + } + + Local N8·Status + N8·shift_left(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ + return N8·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); + } + + Local N8·Status + N8·shift_right(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ + return N8·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); + } + + Local N8·Status + N8·arithmetic_shift_right(uint8_t shift_count, N8·T *operand, N8·T *spill){ + + if(shift_count > 7) return N8·Status·gt_max_shift_count; + + if(operand == NULL){ + operand = &N8·t[0]; + N8·copy(operand, N8·zero); + } + + N8·T *fill = (operand->d0 & 0x80) ? N8·all_one_bit : N8·zero; + return N8·shift_right(shift_count, spill, operand, fill); + } + + Local const N8·M N8·m = { + + .allocate_array = N8·allocate_array + ,.allocate_array_zero = N8·allocate_array_zero + ,.deallocate = N8·deallocate + + ,.copy = N8·copy + ,.bit_and = N8·bit_and + ,.bit_or = N8·bit_or + ,.bit_complement = N8·bit_complement + ,.bit_twos_complement = N8·bit_twos_complement + ,.compare = N8·compare + ,.lt = N8·lt + ,.gt = N8·gt + ,.eq = N8·eq + ,.eq_zero = N8·eq_zero + ,.accumulate = N8·accumulate + ,.add = N8·add + ,.increment = N8·increment + ,.subtract = N8·subtract + ,.multiply = N8·multiply + ,.divide = N8·divide + ,.modulus = N8·modulus + ,.shift_left = N8·shift_left + ,.shift_right = N8·shift_right + ,.arithmetic_shift_right = N8·arithmetic_shift_right + + ,.access = N8·access + ,.from_uint32 = N8·from_uint32 + }; + + #endif + +#endif diff --git a/developer/deprecated/2025-03-29/TM_scratch.c b/developer/deprecated/2025-03-29/TM_scratch.c new file mode 100644 index 0000000..13b2240 --- /dev/null +++ b/developer/deprecated/2025-03-29/TM_scratch.c @@ -0,0 +1,65 @@ + // This initializes 'inner'. + // `alignment` is an extent, e.g. extent_of·AU(uint64_t) = 0x7 + Local TM·Status Ξ(TM·NX ,CVT)·largest_aligned( + TM·NX·AU *outer ,Ξ(TM·NX ,CVT) *inner ,extent·AU alignment + ){ + uintptr_t p0 = (uintptr_t)outer->position; + uintptr_t p1 = (uintptr_t)outer->position + outer->extent; + + CVT *p0_aligned = (CVT *)( + (p0 + alignment) & ~( (uintptr_t)alignment ) + ); + CVT *p1_aligned = (CVT *)( + ( p1 - extent_of·AU(CVT) ) & ~( (uintptr_t)alignment ) + ); + + if( p1_aligned < p0_aligned ) return TM·Status·derailed; + + inner->position = p0_aligned; + inner->extent = (Ξ(extent_t ,CVT))(p1_aligned - p0_aligned}; + return TM·Status·on_track; + } + + + + + Local TM·Status TM·NX·topo(TM·NX *tm ,TM·Tape·Topo *topo){ + #ifdef TM·Debug + TM·Guard·init_count(chk); + TM·Guard·fg.check(&chk ,1 ,tm ,TM·NX_##CVT·Msg·tm); + TM·Guard·fg.check(&chk ,1 ,topo ,"topo ptr is NULL, so nowhere to put result"); + TM·Guard·if_return(chk); + #endif + if(tm->extent·AU == 0){ + *topo = TM·Tape·Topo·singleton; + }else{ + *topo = TM·Tape·Topo·segment; + } + return TM·Status·on_track; + } + + // extent·AU is an AU index + Local TM·Status TM·NX·extent·AU(TM·NX *tm ,extent·AU *extent·AU){ + TM·Tape·Topo topo; + TM·Status status = TM·NX_##CVT·topo(tm ,&topo); + boolean good_topo = + (status == TM·Status·on_track) && (topo & TM·Tape·Topo·finite_nz) + ; + + #ifdef TM·Debug + TM·Guard·init_count(chk); + TM·Guard·fg.check(&chk ,1 ,tm ,TM·NX·Msg·tm); + TM·Guard·fg.check(&chk ,1 ,extent·AU ,TM·NX·Msg·extent·AU); + TM·Guard·fg.check( + &chk ,0 ,good_topo + ,"Tape does not exist or topology does not have an extent·AU." + ); + TM·Guard·if_return(chk); + #endif + + if(!good_topo) return TM·Status·derailed; + *extent·AU = tm->array.extent·AU; + return TM·Status·on_track; + } + + #endif diff --git a/developer/deprecated/2025-03-29/environment.h b/developer/deprecated/2025-03-29/environment.h new file mode 100644 index 0000000..cdea83c --- /dev/null +++ b/developer/deprecated/2025-03-29/environment.h @@ -0,0 +1,5 @@ +#ifndef Mpblock·ENVIRONMENT_H +#define Mpblock·ENVIRONMENT_H + + +#endif diff --git a/developer/deprecated/2025-03-29/test_setup.cli.c b/developer/deprecated/2025-03-29/test_setup.cli.c new file mode 100644 index 0000000..f1c6e68 --- /dev/null +++ b/developer/deprecated/2025-03-29/test_setup.cli.c @@ -0,0 +1,22 @@ +/* + + A placeholder to see if make etc. is working. + +*/ + +#define IFACE +#include +#include + +// No need to define IMPLEMENTATION as `main` is one and done. + +int main(int argc ,char *argv[] ,char *envp[]){ + if(argc != 1){ + fprintf(stderr, "Usage: %s\n", argv[0]); + return EXIT_FAILURE; + } + + fprintf(stderr, "%s done\n", argv[0]); + + return 0; +} diff --git a/developer/deprecated/2025-03-29/update.lib.c b/developer/deprecated/2025-03-29/update.lib.c new file mode 100644 index 0000000..61c5cf4 --- /dev/null +++ b/developer/deprecated/2025-03-29/update.lib.c @@ -0,0 +1,107 @@ +/* + Copy - Memory copy operations with attention to alignment. + Provides optimized copy and byte order reversal functions. +*/ + +#define Copy·DEBUG + +#ifndef FACE +#define Copy·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Copy·FACE +#define Copy·FACE + + #include + #include + + typedef struct{ + void *read0 + ,size_t read_size + ,void *write0 + ,size_t write_size; + } Copy·it; + + typedef enum{ + Copy·Status·perfect_fit = 0 + ,Copy·Status·argument_guard + ,Copy·Status·read_surplus + ,Copy·Status·read_surplus_write_gap + ,Copy·Status·write_available + ,Copy·Status·write_gap; + } Copy·Status; + + typedef enum{ + Copy·WFIt·Mode·none = 0 + ,Copy·WFIt·Mode·bytes + ,Copy·WFIt·Mode·bytes_reverse + ,Copy·WFIt·Mode·write_hex + ,Copy·WFIt·Mode·read_hex; + } Copy·WFIt·Mode; + + typedef enum{ + Copy·WFIt·Status·valid = 0 + ,Copy·WFIt·Status·null_read + ,Copy·WFIt·Status·null_write + ,Copy·WFIt·Status·zero_buffer + ,Copy·WFIt·Status·overlap + ,Copy·WFIt·Status·write_too_small; + } Copy·WFIt·Status; + + typedef struct{ + void *region( void *read0 ,void *read1 ,void *write0 ) + ,void *reverse_byte_order( void *read0 ,void *read1 ,void *write0 ); + } Copy·M; + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef Copy·IMPLEMENTATION + + // this part goes into Nlib.a + #ifndef LOCAL + #endif + + #ifdef LOCAL + + Local Copy·WFIt·Status Copy·wellformed_it(Copy·it *it){ + char *this_name = "Copy·wellformed_it"; + Copy·WFIt·Status status = Copy·WFIt·Status·valid; + + if(it->read0 == NULL){ + fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); + status |= Copy·WFIt·Status·null_read; + } + + if(it->write0 == NULL){ + fprintf( stderr ,"%s: NULL write pointer\n" ,this_name ); + status |= Copy·WFIt·Status·null_write; + } + + if(it->read_size == 0){ + fprintf( stderr ,"%s: Zero-sized read buffer\n" ,this_name ); + status |= Copy·WFIt·Status·zero_read_buffer; + } + + if(it->write_size == 0){ + fprintf( stderr ,"%s: Zero-sized write buffer\n" ,this_name ); + status |= Copy·WFIt·Status·zero_write_buffer; + } + + if( Copy·overlap_size_interval(it->read0 ,it->read_size ,it->write0 ,it->write_size) ){ + fprintf( stderr ,"%s: Read and write buffers overlap!\n" ,this_name ); + status |= Copy·WFIt·Status·overlap; + } + + return status; + } + + #endif // LOCAL + +#endif // IMPLEMENTATION diff --git a/developer/deprecated/About_Python_templates.org b/developer/deprecated/About_Python_templates.org new file mode 100644 index 0000000..414366f --- /dev/null +++ b/developer/deprecated/About_Python_templates.org @@ -0,0 +1,232 @@ +#+TITLE: Python-Based Template Generation (Multi-Module Approach) +#+AUTHOR: Chat GPT + +Below is a single Org-mode document containing **four** separate Python modules +(or scripts). Each code block is top-level (not nested), ensuring they render +correctly. Together, they demonstrate how to generate a parametric `.lib.c` file +for an RT code format library. + +1. **get_template.py**: Returns a base template with `{named_blank}` placeholders. +2. **make_constants.py**: Creates the compile-time constants block for zero, one, etc. +3. **fill_template.py**: Combines the template and constants block, substituting parameters. +4. **A "Main" generator script** (for instance, `gen_n64_lib.py`) that writes out a final file (like `N64.lib.c`). + +You can create additional “main” scripts to produce different `.lib.c` files (e.g., `N128.lib.c`). + +--- + +*1. `get_template.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +def get_template(): + """ + Returns the base RT C code template, with placeholders like: + {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}. + + The final generated .lib.c will replace these with user-specified values. + """ + return r'''#define {NAMESPACE}DEBUG + +#ifndef FACE + #define {NAMESPACE}IMPLEMENTATION + #define FACE +#endif + +#ifndef {NAMESPACE}FACE +#define {NAMESPACE}FACE + + #include + #include + #include + #include + + typedef {EXTENT_TYPE} ExtentType; + typedef {DIGIT_TYPE} Digit; + + // Digit count is (DIGIT_EXTENT + 1) + #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 ) + + typedef struct {NAMESPACE}T{{ + Digit d[{NAMESPACE}DIGIT_COUNT]; + }} {NAMESPACE}T; + + // forward declarations for constants + extern {NAMESPACE}T *{NAMESPACE}zero; + extern {NAMESPACE}T *{NAMESPACE}one; + extern {NAMESPACE}T *{NAMESPACE}all_one_bit; + extern {NAMESPACE}T *{NAMESPACE}msb; + + // forward declarations for allocations, etc. + +#endif // {NAMESPACE}FACE + +#ifdef {NAMESPACE}IMPLEMENTATION + +#ifndef LOCAL + #include + #include + + // compile-time constants + {CONSTANTS_BLOCK} + + {NAMESPACE}T *{NAMESPACE}zero = &{NAMESPACE}constant[0]; + {NAMESPACE}T *{NAMESPACE}one = &{NAMESPACE}constant[1]; + {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2]; + {NAMESPACE}T *{NAMESPACE}msb = &{NAMESPACE}constant[3]; + + // memory allocation prototypes, etc. + +#endif // not LOCAL + +#ifdef LOCAL + // local code: actual function bodies, add, subtract, etc. +#endif // LOCAL + +#endif // {NAMESPACE}IMPLEMENTATION +''' +#+END_SRC + +--- + +*2. `make_constants.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +def make_constants_block(namespace: str, + digit_type: str, + digit_extent: int) -> str: + """ + Returns a block of code defining static compile-time constants: + static {namespace}T {namespace}constant[4] = { + { { ...zero... } }, + { { ...one... } }, + { { ...allbits... } }, + { { ...msb... } } + }; + + The total digit count is digit_extent + 1. + """ + digit_count = digit_extent + 1 + + def digits_zero(): + return ", ".join("0" for _ in range(digit_count)) + + def digits_one(): + # index 0 => 1, rest => 0 + return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) + + def digits_allbits(): + # each digit => (digit_type)(-1) + return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) + + def digits_msb(): + # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) + items = [] + for i in range(digit_count): + if i == digit_count - 1: + items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") + else: + items.append("0") + return ", ".join(items) + + return f'''\ +static {namespace}T {namespace}constant[4] = {{ + {{ + // zero + {{ {digits_zero()} }} + }}, + {{ + // one + {{ {digits_one()} }} + }}, + {{ + // all bits + {{ {digits_allbits()} }} + }}, + {{ + // msb + {{ {digits_msb()} }} + }} +}};''' + +#+END_SRC + +--- + +*3. `fill_template.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +from get_template import get_template +from make_constants import make_constants_block + +def fill_template(namespace: str, + digit_extent: int, + digit_type: str, + extent_type: str) -> str: + """ + Renders the final .lib.c code by merging: + - the base template from get_template() + - the compile-time constants block from make_constants_block() + - placeholders for namespace, digit_extent, digit_type, extent_type + """ + template = get_template() + constants_block = make_constants_block(namespace, digit_type, digit_extent) + + # Substitute placeholders + code = template.format( + NAMESPACE = namespace, + DIGIT_EXTENT = digit_extent, + DIGIT_TYPE = digit_type, + EXTENT_TYPE = extent_type, + CONSTANTS_BLOCK = constants_block + ) + return code +#+END_SRC + +--- + +*4. An Example “Main” Script, `gen_n64_lib.py`* + +#+BEGIN_SRC python +#!/usr/bin/env python3 + +import sys +from fill_template import fill_template + +def main(): + """ + Example: generate a .lib.c with an 'N64·' namespace, + digit_extent=0 => 1 digit total, + digit_type='uint32_t', + extent_type='uint64_t'. + """ + code = fill_template( + namespace = "N64·", + digit_extent = 0, # => digit_count = 1 => 32-bit + digit_type = "uint32_t", + extent_type = "uint64_t" + ) + + with open("N64.lib.c", "w") as f: + f.write(code) + print("Generated N64.lib.c") + +if __name__ == "__main__": + main() +#+END_SRC + +--- + +### Usage + +1. **Place** these four files side-by-side in your project (e.g., a `scripts/` directory). +2. **Mark** them as executable (`chmod +x`). +3. **Run** `./gen_n64_lib.py` to produce `N64.lib.c`. This file will appear in the same directory (or wherever you prefer). +4. **Compile** `N64.lib.c` using your RT C build system (`make -f tool🖉/makefile`, etc.). + +You can then create similar scripts like `gen_n128_lib.py` or unify them into a single driver that takes parameters for namespace, digit_extent, etc. The main advantage is that **Python code** for generating constants is much more readable than M4 macros, and you keep the RT code format in your template exactly as it should appear. diff --git a/developer/deprecated/Copy.lib.c b/developer/deprecated/Copy.lib.c new file mode 100644 index 0000000..f75a272 --- /dev/null +++ b/developer/deprecated/Copy.lib.c @@ -0,0 +1,431 @@ +/* + Copy - Memory copy operations with attention to alignment. + Provides optimized copy and byte order reversal functions. + +*/ + +#define Copy·DEBUG + +#ifndef FACE +#define Copy·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Copy·FACE +#define Copy·FACE + + #include + #include + + #define extentof(x) (sizeof(x)-1) + + typedef struct{ + void *read0; + size_t read_size; + void *write0; + size_t write_size; + } Copy·it; + + // returned from the `step_X` functions + typedef enum{ + Copy·Step·perfect_fit = 0 + ,Copy·Step·argument_guard + ,Copy·Step·read_surplus + ,Copy·Step·read_surplus_write_gap + ,Copy·Step·write_availableCopy·Status· + ,Copy·Step·write_gap; + } Copy·Status; + + typedef enum{ + Copy·WFIt·Status·valid = 0 + ,Copy·WFIt·Status·null_read + ,Copy·WFIt·Status·zero_size_read + ,Copy·WFIt·Status·null_write + ,Copy·WFIt·Status·zero_size_write + ,Copy·WFIt·Status·overlap + } Copy·WFIt·Status; + + // function dictionary + typedef struct{ + void *bytes(void *read0 ,void *read1 ,void *write0); + void *reverse_byte_order(void *read0 ,void *read1 ,void *write0); + Copy·WFIt·Status Copy·wellformed_it(Copy·it *it ,Copy·WFIt·Mode mode); + } Copy·M; + + Core·M m; // initialized in the LOCAL implementation, yes in C we can do this. + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef Copy·IMPLEMENTATION + + #ifdef Copy·DEBUG + #include // Only for debug prints, not used in production. + #endif + + + // this part goes into Copylib.a + // yes this is empty, so there is no Copylib.a + #ifndef LOCAL + #endif + + #ifdef LOCAL + + // Interval predicates. + // Intervals in Copy have an exclusive upper bound + + Local bool Copy·in_pt_interval(void *pt, void *pt0 ,void *pt1){ + return pt >= pt0 && pt < pt1; + } + Local bool Copy·in_size_interval(void *pt, void *pt0 ,size_t s){ + return Copy·in_pt_interval(pt ,pt0 ,pt0 + s); + } + + // interval 0 contains interval 1, overlap on boundaries allowed. + Local bool Copy·contains_pt_interval( + void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 + ){ + return + pt10 >= pt00 && pt11 <= pt01 + ; + } + + // Possible cases of overlap + // 1. interval 0 to the left of interval 1 + // 2. interval 0 to the right of interval 1 + // 3. interval 0 wholly contained in interval 1 + // 4. interval 0 wholly contains interval 1 + Local bool Copy·overlap_pt_interval(void *pt00 ,void *pt01, void *pt10 ,void *pt11){ + void *pt01_inclusive = pt01 - 1; + void *pt11_inclusive = pt11 - 1; + return + Copy·in_pt_interval(pt10 ,pt00 ,pt01) // #1, #4 + || + Copy·in_pt_interval(pt00 ,pt10 ,pt11) // #2, #3 + ; + } + Local bool Copy·overlap_size_interval(void *pt00 ,size_t s0, void *pt10 ,size_t s1){ + return Copy·overlap_pt_interval(pt00 ,pt00 + s0 ,pt10 ,pt10 + s1); + } + + Local Copy·WFIt·Status Copy·wellformed_it(Copy·it *it ,bool print){ + char *this_name = "Copy·wellformed_it"; + Copy·WFIt·Status status = Copy·WFIt·Status·valid; + + if(it == NULL){ + if(print) fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); + return Core·It·Status·null; + } + + if(it->read0 == NULL){ + if(print) fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); + status |= Copy·WFIt·Status·null_read; + } + + if(it->write0 == NULL){ + if(print) fprintf( stderr ,"%s: NULL write pointer\n" ,this_name ); + status |= Copy·WFIt·Status·null_write; + } + + if(it->read_size == 0){ + if(print) fprintf( stderr ,"%s: Zero-sized read buffer\n" ,this_name ); + status |= Copy·WFIt·Status·zero_read_buffer; + } + + if(it->write_size == 0){ + if(print) fprintf( stderr ,"%s: Zero-sized write buffer\n" ,this_name ); + status |= Copy·WFIt·Status·zero_write_buffer; + } + + if( Copy·overlap_size_interval(it->read0 ,it->read_size ,it->write0 ,it->write_size) ){ + if(print) fprintf( stderr ,"%s: Read and write buffers overlap!\n" ,this_name ); + status |= Copy·WFIt·Status·overlap; + } + + return status; + } + + /* + Identity function. read interval values are copied without modification of value + or order to the write allocation. + - Aligns reads for performance. + - Writes are assumed to be buffered and do not require alignment. + - Returns the updated write pointer. + - See doc 'Copy.org' for more details. + */ + Local void *Copy·identity(void *read0 ,void *read1 ,void *write0){ + + uint8_t *r = (uint8_t *)read0; + uint8_t *r1 = (uint8_t *)read1; + uint8_t *w = (uint8_t *)write0; + + //---------- + // The potentially unaligned initial part (align read pointer). + if( (uintptr_t)r & 0x7 ){ + + // at this point r == r0, the lower bound of the read interval + // r0 | `0x7` adds at most six bytes to r. + uint8_t *r01 = (uint8_t *)((uintptr_t)r | 0x7); + + // If the read interval is very small + if(r01 >= r1){ + while(r < r1){ + *w++ = *r++; + } + return w; + } + + // Copy up to alignment boundary + do{ + *w++ = *r++; + }while(r <= r01); + } + // r is now aligned, but *r has not yet been copied + + //---------- + // The bulk copy part (w is still possibly unaligned, but r is aligned) + uint8_t *r10 = (uint8_t *)((uintptr_t)r1 & ~(uintptr_t)0x7); + + while(r < r10){ + *(uint64_t *)w = *(uint64_t *)r; + w += 8; + r += 8; + } + + // If r1 was aligned then r10 == r1 and we are done + if(r == r1) return w; + + //---------- + // The ragged tail, up to 7 bytes + do{ + *w++ = *r++; + }while(r < r1); + + return w; + } + + /* + Copy·reverse_byte_order - Copies a memory region while reversing byte order. + - Reads from read1 down + - writes from write0 up + - Uses `__builtin_bswap64` for efficient 64-bit swaps. + - Returns the updated write pointer. + */ + Local void *Copy·bytes_reverse_order(void *read0 ,void *read1 ,void *write0){ + + uint8_t *r = (uint8_t *)read1; // Start from the last byte + uint8_t *r0 = (uint8_t *)read0; + uint8_t *w = (uint8_t *)write0; + + //---------- + // The potentially unaligned initial part (align read pointer). + if( (uintptr_t)r & 0x7 ){ + + // ANDing with `~0x7` moves it downward to the nearest lower alignment. + uint8_t *r10 = (uint8_t *)((uintptr_t)r & ~(uintptr_t)0x7); + + // If the read interval is very small + if(r10 < r0){ + while(r > r0){ + *w++ = *--r; + } + return w; + } + + // Copy down to alignment boundary + do{ + *w++ = *--r; + }while(r > r10); + } + // r is now aligned, and *r has been copied + + //---------- + // The bulk copy part + uint8_t *r01 = (uint8_t *)( ((uintptr_t)r0 + (uintptr_t)0x7) & ~(uintptr_t)0x7); + + while(r > r01){ + r -= 8; + *(uint64_t *)w = __builtin_bswap64(*(uint64_t *)r); + w += 8; + } + + // If r0 was aligned then r01 == r0 and we are done + if(r < r0) return w; + + //---------- + // The ragged tail, up to 7 bytes + do{ + *w++ = *--r; + }while(r >= r0); + + return w; + } + + /* + Read buffer is read from the lowest address, working toward higher addresses. + + Write buffer is written from the lowest address, working to higher addresses. + + To force data to be left in the read buffer, or for capacity to be left in the + write buffer, reduce sizes. + */ + Local Copy·Status Copy·step(Copy·it *it){ + uint8_t *r = (uint8_t *)it->read0; + uint8_t *w = (uint8_t *)it->write0; + + size_t rs = it->read_size; + size_t ws = it->write_size; + + if(ws >= rs){ + Copy·bytes(r ,r + rs ,w); + it->read0 += rs; + it->read_size = 0; + it->write0 += rs; + it->write_size -= rs; + if(ws == rs) return Copy·Step·perfect_fit; + return Copy·Step·write_available;; + } + + // ws < rs + Copy·bytes(r ,r + ws ,w); + it->read0 += ws; + it->read_size -= ws; + it->write_size = 0; + it->write0 += ws; + return Copy·Step·read_surplus; + } + + /* + Read buffer is read from top down. Start with the largest address + just above the read buffer. Continue into lower addresses. + + write buffer is written from bottom up. Start with the lowest address, + continue into higher addresses. + */ + Local Copy·Status Copy·step_reverse_order(Copy·it *it){ + // How many bytes remain to be read/written + if( it->read_size == 0) return Copy·Step·complete; + size_t rs = it->read_size; + uint8_t *r1 = (uint8_t *)it->read0 + rs; + size_t ws = it->write_size; + uint8_t *w0 = (uint8_t *)it->write0; + + if(ws >= rs){ + uint8_t *r0 = (uint8_t *)it->read0; + Copy·bytes_reverse_order(r0, r1, w0); + it->read_size = 0; + it->write0 += rs; + it->write_size -= rs; + if(it->write_size == 0) return Copy·Step·perfect_fit; + return Copy·Step·write_available; + } + + // ws < rs + uint8_t *r0 = r1 - ws; + Copy·bytes_reverse_order(r0, r1, w0); + it->read0 -= ws; + it->read_size -= ws; + it->write_size = 0; + it->write0 += ws; + return Copy·Step·read_surplus; + } + + /* + Read bytes, write hex pairs. + Read and write are low address to high address. + Each read byte value -> 2 write allocation bytes + */ + Local Copy·Status Copy·step_write_hex(Copy·it *it){ + + uint8_t *r = (uint8_t *)it->read0; + size_t rs = it->read_size; + + uint8_t *w = (uint8_t *)it->write0; + size_t ws = it->write_size & ~1; // even number write_size + size_t ews = it->write_size >> 1; // effective write size + + // If ews >= rs, read bytes all coped + if(ews >= rs){ + size_t ers = it->read_size << 1; // effective read size + it->write0 += ers; + it->write_size -= ers; + while(rs--){ + *(uint16_t *)w = Copy·byte_to_hex(*r++); + w += 2; + } + it->read0 = r; + it->read_size = 0; + + if(it->write_size == 0) return Copy·Step·perfect_fit; + if(it->write_size == 1) return Copy·Step·write_gap; + return Copy·Step·write_available; + } + + // ews < rs, write allocation all used, read bytes surplus + it->read0 += ews; + it->read_size -= ews; + while(ews--){ + *(uint16_t *)w = Copy·byte_to_hex(*r++); + w += 2; + } + it->write0 = w; + it->write_size -= ws; + + if(it->write_size == 1) return Copy·Step·read_surplus_write_gap; + return Copy·Step·read_surplus; + } + + /* + Read hex pairs, write bytes. + Read is low address to high address. + Write is low address to high address. + Each read hex pair -> 1 write byte. + */ + Local Copy·Status Copy·step_read_hex(Copy·it *it){ + uint8_t *r = (uint8_t *)it->read0; + size_t rs = it->read_size & ~1; // Must be even for hex pairs. + size_t ers = rs >> 1; // Effective read size: half the number of bytes. + + uint8_t *w = (uint8_t *)it->write0; + size_t ws = it->write_size; // Write size already in bytes. + + // If ws >= ers, all hex values are processed + if(ws >= ers){ + while(ers--){ + *w++ = Copy·hex_to_byte(*(uint16_t *)r); + r += 2; + } + + it->read0 = r; + it->read_size -= rs; + it->write0 = w; + it->write_size -= rs >> 1; // Each byte consumes two hex chars. + + if(it->write_size == 0) return Copy·Step·perfect_fit; + return Copy·Step·write_available; + } + + // ws < ers, read allocation surplus + while(ws--){ + *w++ = Copy·hex_to_byte(*(uint16_t *)r); + r += 2; + } + + it->read0 = r; + it->read_size -= ws << 1; // Each write byte consumes two hex chars. + it->write0 = w; + it->write_size = 0; + + return Copy·Step·read_surplus; + } + + + #endif // LOCAL + + +#endif // IMPLEMENTATION diff --git a/developer/deprecated/Copy.lib_2.c b/developer/deprecated/Copy.lib_2.c new file mode 100644 index 0000000..f93e599 --- /dev/null +++ b/developer/deprecated/Copy.lib_2.c @@ -0,0 +1,347 @@ +/* + CoreCopy - Memory copy operations with attention to alignment. + Provides optimized copy and byte order reversal functions. + + 'ATP' At This Point in the code. Assertions follow. +*/ + +#define CoreCopy·DEBUG + +#ifndef FACE +#define CoreCopy·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef CoreCopy·FACE +#define CoreCopy·FACE + + #include + #include + + #define extentof(x) (sizeof(x) - 1) + #define extent_t size_t + + typedef struct{ + void *read0; + extent_t read_extent; + void *write0; + extent_t write_extent; + } CoreCopy·It; + + typedef enum{ + CoreCopy·It·Status·valid = 0 + ,CoreCopy·It·Status·null_read + ,CoreCopy·It·Status·null_write + ,CoreCopy·It·Status·overlap + } CoreCopy·It·Status; + + typedef enum{ + CoreCopy·Step·perfect_fit = 0 + ,CoreCopy·Step·argument_guard + ,CoreCopy·Step·read_surplus + ,CoreCopy·Step·read_surplus_write_gap + ,CoreCopy·Step·write_available + ,CoreCopy·Step·write_gap + } CoreCopy·Status; + + typedef struct{ + bool CoreCopy·IntervalPts·in(void *pt, void *pt0 ,void *pt1); + bool CoreCopy·IntervalPts·contains(void *pt00 ,void *pt01 ,void *pt10 ,void *pt11); + bool CoreCopy·IntervalPts·overlap(void *pt00 ,void *pt01, void *pt10 ,void *pt11); + + bool CoreCopy·IntervalPtSize·in(void *pt, void *pt0 ,size_t s); + bool CoreCopy·IntervalPtSize·overlap(void *pt00 ,size_t s0, void *pt10 ,size_t s1); + + CoreCopy·It·Status CoreCopy·wellformed_it(CoreCopy·It *it) + + void *identity(void *read0 ,void *read1 ,void *write0); + void *reverse_byte_order(void *read0 ,void *read1 ,void *write0); + + CoreCopy·Status CoreCopy·Step·identity(CoreCopy·It *it); + CoreCopy·Status CoreCopy·Step·reverse_order(CoreCopy·It *it); + CoreCopy·Status CoreCopy·Step·write_hex(CoreCopy·It *it); + CoreCopy·Status CoreCopy·Step·read_hex(CoreCopy·It *it); + } CoreCopy·M; + +#endif + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef CoreCopy·IMPLEMENTATION + + #ifdef CoreCopy·DEBUG + #include + #endif + + // this part goes into Copylib.a + // yes this is empty, so there is no Copylib.a + #ifndef LOCAL + #endif + + #ifdef LOCAL + + // Interval predicates. + // Intervals in Copy have inclusive bounds + + Local bool CoreCopy·aligned64(void *p){ + return ((uintptr_t)p & 0x7) == 0; + } + + Local bool CoreCopy·IntervalPts·in(void *pt, void *pt0 ,void *pt1){ + return pt >= pt0 && pt <= pt1; // Inclusive bounds + } + + Local bool CoreCopy·in_extent_interval(void *pt, void *pt0 ,extent_t e){ + return CoreCopy·IntervalPts·in(pt ,pt0 ,pt0 + e); + } + + // interval 0 contains interval 1, overlap on boundaries allowed. + Local bool CoreCopy·IntervalPts·contains( + void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 + ){ + return pt10 >= pt00 && pt11 <= pt01; + } + + // interval 0 properly contains interval 1, overlap on boundaries not allowed. + Local bool CoreCopy·contains_proper_pt_interval( + void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 + ){ + return pt10 > pt00 && pt11 < pt01; + } + + // Possible cases of overlap, including just touching + // 1. interval 0 to the right of interval 1, just touching p00 == p11 + // 2. interval 0 to the left of interval 1, just touching p01 == p10 + // 3. interval 0 wholly contained in interval 1 + // 4. interval 0 wholly contains interval 1 + Local bool CoreCopy·IntervalPts·overlap(void *pt00 ,void *pt01, void *pt10 ,void *pt11){ + return + CoreCopy·IntervalPts·in(pt00 ,pt10 ,pt11) // #1, #3 + || CoreCopy·IntervalPts·in(pt10 ,pt00 ,pt01) // #2, #4 + ; + } + + Local bool CoreCopy·overlap_extent_interval(void *pt00 ,extent_t e0, void *pt10 ,extent_t e1){ + return CoreCopy·IntervalPts·overlap(pt00 ,pt00 + e0 ,pt10 ,pt10 + e1); + } + + Local CoreCopy·It·Status CoreCopy·It·wellformed(CoreCopy·It *it){ + char *this_name = "CoreCopy·It·wellformed"; + CoreCopy·It·Status status = CoreCopy·It·Status·valid; + + if(it->read0 == NULL){ + fprintf(stderr, "%s: NULL read pointer\n", this_name); + status |= CoreCopy·It·Status·null_read; + } + + if(it->write0 == NULL){ + fprintf(stderr, "%s: NULL write pointer\n", this_name); + status |= CoreCopy·It·Status·null_write; + } + + if( + CoreCopy·overlap_extent_interval(it->read0 ,it->read_extent ,it->write0 ,it->write_extent) + ){ + fprintf(stderr, "%s: Read and write buffers overlap!\n", this_name); + status |= CoreCopy·It·Status·overlap; + } + + return status; + } + + // consider an 8 byte window that is aligned + // returns the byte pointer to the least address byte in the window + Local void *CoreCopy·floor64(void *p){ + return (uintptr_t)p & ~(uintptr_t)0x7; + } + + // consider an 8 byte window that is aligned + // returns the byte pointer to the greatest address byte in the window + Local void *CoreCopy·ceiling64(void *p){ + return (uintptr_t)p | 0x7; + } + + // byte array greatest address byte at p1 (inclusive) + // byte array least address byte at p0 (inclusive) + // returns pointer to the greatest full 64-bit word-aligned address that is ≤ p1 + // by contract, p1 must be >= p0 + Local uint64_t *CoreCopy·greatest_full_64(void *p0 ,void *p1){ + + // If p1 - 0x7 moves into a prior word while p0 does not, a prefetch hazard can occur. + // If p1 and p0 are more than 0x7 apart, they cannot be in the same word, + // but this does not guarantee a full 64-bit word exists in the range. + if((uintptr_t)p1 < (uintptr_t)p0 + 0x7) return NULL; + + // Compute the last fully aligned word at or before p1. + uint64_t *p1_64 = (void *)( ((uintptr_t)p1 - 0x7) & ~(uintptr_t)0x7 ); + + // If alignment rounds p1_64 below p0, there is no full word available. + if(p1_64 < p0) return NULL; + + return p1_64; + } + + // byte array greatest address byte at p1 (inclusive) + // byte array least address byte at p0 (inclusive) + // returns pointer to the least full 64-bit word-aligned address that is ≥ p0 + Local uint64_t *CoreCopy·least_full_64(void *p0 ,void *p1){ + + // If p0 + 0x7 moves into the next word while p1 does not, a prefetch hazard can occur. + // If p1 and p0 are more than 0x7 apart, they cannot be in the same word, + // but this does not guarantee a full 64-bit word exists in the range. + if(p1 - p0 < 0x7) return NULL; + + // Compute the first fully aligned word at or after p0. + uint64_t *p0_64 = (void *)( ((uintptr_t)p0 + 0x7) & ~(uintptr_t)0x7 ); + + // If alignment rounds p0_64 beyond p1, there is no full word available. + if(p0_64 > p1) return NULL; + + return p0_64; + } + + Local void *CoreCopy·inc64(void *p ,size_t Δ){ + return (void *)((uint64_t *)p) + Δ; + } + + Local uint64_t CoreCopy·read_word_fwd(uint64_t *r){ + return *r; + } + + Local uint64_t CoreCopy·read_word_rev(uint64_t *r0, uint64_t *r1, uint64_t *r){ + return __builtin_bswap64(*(CoreCopy·floor64(r0 + (r1 - r)))); + } + + Local void *CoreCopy·byte( + uint8_t *r0 ,uint8_t *r1 ,uint8_t *w0 ,bool reverse + ){ + //---------------------------------------- + // Argument guard + // + + if(r1read0; + uint8_t *w = (uint8_t *)it->write0; + + extent_t re = it->read_extent; + extent_t we = it->write_extent; + + if(we >= re){ + CoreCopy·bytes(r ,r + re ,w); + it->read0 += re; // Fixed stepping logic + it->read_extent = 0; + it->write0 += re; + it->write_extent -= re; + if(we == re) return CoreCopy·Step·perfect_fit; + return CoreCopy·Step·write_available; + } + + CoreCopy·bytes(r ,r + we ,w); + it->read0 += we; // Fixed stepping logic + it->read_extent -= we; + it->write_extent = 0; + it->write0 += we; + return CoreCopy·Step·read_surplus; + } + + #endif // LOCAL + +#endif // IMPLEMENTATION diff --git a/developer/deprecated/Core_with_tableau.lib.c b/developer/deprecated/Core_with_tableau.lib.c new file mode 100644 index 0000000..eac2d40 --- /dev/null +++ b/developer/deprecated/Core_with_tableau.lib.c @@ -0,0 +1,1264 @@ + /* + Core - core memory operations. + + 'ATP' Used in comments. 'At This Point' in the code. + + 'Tape' refers to an tape (in contrast to a point) in the address space. + + A non-exist array is said to be non-existent. + An array with zero elements has 'length == 0' or is 'empty'. + + In contrast, an allocation does not exist if it has zero bytes. + + It is better to separate the tableau than have a union, and let the + optimizer figure out the memory life times, and what can be reused. + + Nodes include neighbor links, that makes traversal more efficient. + + +*/ + +#define Core·DEBUG + +#ifndef FACE +#define Core·IMPLEMENTATION +#define FAC +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Core·FACE +#define Core·FACE + + #include + #include + + //---------------------------------------- + // utility + + struct{ + void *offset(void *p ,size_t Δ); + void *offset_8AU(void *p ,size_t Δ); + + // given an 8AU window aligned on an 8AU boundary + bool is_aligned_on_8AU(void *p); + void *floor_within_aligned_8AU(void *p); + void *ceiling_within_aligned_8AU(void *p); + }Core·U; + Core·U Core·u; + + //---------------------------------------- + // memory + + #define extentof(x)(sizeof(x) - 1) + #define extent_t size_t + + // AU == Addressable Unit + // given an AU is an 8 bit byte, 4AU is 32 bits, and 8 AU is 64 bits. + #define AU uint8_t; + + //---------------------------------------- + // model + + typedef enum{ + Core·Status·mu = 0 + ,Core·Status·on_track + ,Core·Status·derailed + }Core·Status; + + typedef struct{ + }Core·Tableau; + + typedef struct{ + Core·Tableau tableau; + unint status; + }Core·Tableau·Face; + + typedef struct Core·Link; + + typedef struct{ + Core·ActionTable *action; + Core·Tableau *face; + Core·Tableau *state; + Core·NextTable *next_table; + }Core·Link; + + typedef enum { + Core·Link·Mode·none = 0 + ,Core·Link·Mode·action = 1 + ,Core·Link·Mode·face = 2 + ,Core·Link·Mode·state = 4 + ,Core·Link·Mode·next_table = 8 + ,Core·Link·Mode·bad_mode = 16 + ,Core·Link·Mode·bad_link = 32 + }Core·Link·Mode; + + Local uint Core·Link·check(Core·Link *l ,Core·Link·Mode m){ + Core·Link·Mode error = Core·Link·Mode·none; + + if(m == Core·Link·Mode·none){ + fprintf(stderr,"Core·Area·Array·read:: given zero mode"); + error |= Core·Link·Mode·bad_mode; + } + if(m >= Core·Link·Mode·bad_mode){ + fprintf(stderr,"Core·Area·Array·read:: illegal check mode"); + error |= Core·Link·Mode·bad_mode; + } + if(!l){ + fprintf(stderr,"Core·Area·Array·read:: given NULL link"); + error |= Core·Link·Mode·bad_link; + } + + if(error) return error; + + if( (m & Core·Link·Mode·action) && !l->action){ + fprintf(stderr,"Core·Area·Array·read:: given NULL action"); + error |= Core·Link·Mode·action; + } + if( (m & Core·Link·Mode·face) && !l->face){ + fprintf(stderr,"Core·Area·Array·read:: given NULL face"); + error |= Core·Link·Mode·face; + } + if( (m & Core·Link·Mode·state) && !l->state){ + fprintf(stderr,"Core·Area·Array·read:: given NULL state"); + error |= Core·Link·Mode·state; + } + if( (m & Core·Link·Mode·next_table) && !l->next_table){ + fprintf(stderr,"Core·Area·Array·read:: given NULL next_table"); + error |= Core·Link·Mode·next_table; + } + + return error; + } + + typedef struct{ + uint (*check)(Core·Link *l ,Core·Link·Mode m); + }Core·Link·ActionTable; + + + typedef Core·Link *(*Core·Action)(Core·Link *); + + typedef struct{ + Core·Action on_track; // -> status + Core·Action derailed; // -> status + }Core·ActionTable; + + Local Core·Link *Core·Action·on_track(Core·Link *lnk){ + lnk->face->status = Core·Status·on_track; + return NULL; + } + + Local Core·Link *Core·Action·derailed(Core·Link *lnk){ + lnk->face->status = Core·Status·derailed; + return NULL; + } + + // The most common continuations + typedef struct{ + Core·Link on_track; + Core·Link derailed; + }Core·NextTable; + + + Local void initiate(Core·Link *lnk){ + while(lnk) lnk = lnk->action(lnk); + } + + typedef struct Core·State; + + Local void call( + Core·Action action + ,Core·Face *face + ,Core·State *state + ){ + Core·Link link{ + .action = action + ,.face = face + ,.state = state + ,.next_table = NULL; + } + initiate(&link); + } + + Local Core·Tableau·Face Core·Tableau·face{ + .tableau = { + } + .status = Core·Status·mu + } + + Local Core·Link·ActionTable Core·Link·action_table = { + ,.check = Core·Link·check + }; + + Local Core·ActionTable Core·action_table = { + .on_track = Core·Action·on_track, + ,.derailed = Core·Action·derailed + ,.check = Core·Link·check + }; + + Local Core·NextTable Core·next_table{ + .on_track = Core·Action·on_track + ,.derailed = Core·Action·derailed + }; + + Local Core·Link Core·link{ + .action = NULL + ,.face = NULL + ,.state = NULL + ,.next_table = &Core·next_table + } + + //---------------------------------------- + // Tape model + + typedef struct Core·Tape; + typedef struct Core·Tape·Address; + typedef struct Core·Tape·Remote; + + typedef struct{ + Core·Tableau·Face; + Core·Tape *tape; + Core·Tape·Address *address; + Core·Tape·remote *remote; + extent_t extent; + }Core·Tape·Tableau·Face; + + typedef Local void (*Core·Tape·copy)( + Core·Tape·Address *address + ,Core·Tape·Remote *remote + ); + + typedef enum{ + Core·Area·Topo·mu + ,Core·Area·Topo·nonexistent // pointer to tape is NULL + ,Core·Area·Topo·empty // tape has no cells + ,Core·Area·Topo·singleton // extent is zero + ,Core·Area·Topo·segment // finite non-singleton tape + ,Core·Area·Topo·circle // initial location recurs + ,Core·Area·Topo·cyclic // a location recurs + ,Core·Area·Topo·infinite // exists, not empty, no cycle, no rightmost + }Core·Tape·Topo; + + typedef enum{ + Core·Status·mu = 0 + ,Core·Status·on_track + ,Core·Status·empty_tape + ,Core·Status·empty_tape + }Core·Tape·Extent·Next; + + typedef struct{ + Core·Action topo; + Core·Action copy; // *address -> *remote + Core·Action extent; + }Core·Tape·ActionTable; + + //---------------------------------------- + // Area model + + typedef struct Core·Area; // extends Tape + + typedef struct{ + Core·Tape·Tableau·Face tape; + Core·Area *area; + void *position; + void *position_right; + AU *pt; + AU *pt_complement; + Core·Area *a; + Core·Area *b; + bool q; // predicate -> q + }Core·Area·Tableau·Face; + + typedef struct{ + Core·Tape·ActionTable tape; + + Core·Action position_right; // sets position_right + + Core·Action complement; // AU *pt -> AU *pt_complement + + // area relationships + Core·Action address_valid; // a encloses pt + Core·Action encloses_pt_strictly_q; // " pt not on a bound + Core·Action encloses_area_q; // a encloses b + Core·Action encloses_area_strictly_q; // " no bounds touching + Core·Action overlap_q; // a overlaps b + // a is an outer byte array, b is an inner aligned word64 array + Core·Action largest_aligned_64_q; + } Core·Area·Action; + + //---------------------------------------- + // Tape Machine + + typedef struct Core·TM_NX; + + // if tape machine does not support step left, then Status·leftmost will be reported as Status·interim + typedef enum{ + Core·TM·Head·Status·mu + ,Core·TM·Head·Status·not_on_tape = 1 + ,Core·TM·Head·Status·on_leftmost = 1 << 1 + ,Core·TM·Head·Status·in_interim = 1 << 2 + ,Core·TM·Head·Status·on_rightmost = 1 << 3 + }Core·TM·Head·Status; + + const uint Core·TM·Head·Status·derailed = + Core·TM·Head·Status·mu + | Core·TM·Head·Status·not_on_tape + ; + + const uint Core·TM·Head·Status·can_step = + Core·TM·Head·Status·leftmost + | Core·TM·Head·Status·interim + ; + + typedef struct{ + Core·Tableau·Face face; + Core·Tape *tape; + Core·Tape·Topo topo; + void *read_pt; // various machines will have different read types + }Core·TM_NX·Tableau·Face; + + // default Tableau + Local Core·TM_NX·Tableau Core·TM_NX·t; + + typedef struct{ + Core·Action mount; + Core·Action rewind; + Core·Action can_step; + Core·Action step_right; + Core·Action step_left; + Core·Action read; // -> read_pt + Core·Action write; // writes data found at read_pt + Core·Action status; + Core·Action topo; + } Core·TM_NX·Action; + // default actions table + Local Core·TM_NX·Action Core·TM_NX·action; + + // default link + Core·Link Core·TM_NX·link; + + + //---------------------------------------- + // Map + + typedef enum{ + Core·Map·Status·mu = 0 + ,Core·Map·Status·no_tape + ,Core·Map·Status·not_computable + ,Core·Map·Status·complete + } Core·Map·Status; + + typedef enum{ + Core·Map·Completion·mu = 0 + ,Core·Map·Completion·no_tape + ,Core·Map·Completion·not_computable + ,Core·Map·Completion·failed + ,Core·Map·Completion·perfect_fit + ,Core·Map·Completion·read_surplus + ,Core·Map·Completion·read_surplus_write_gap + ,Core·Map·Completion·write_available + ,Core·Map·Completion·write_gap + } Core·Map·Completion; + + const uint Core·Map·Completion·derailed = + Core·Map·Completion·no_tape + | Core·Map·Completion·not_computable + | Core·Map·Completion·failed + ; + + const uint Core·Map·Completion·on_track = + Core·Map·Completion·perfect_fit + | Core·Map·Completion·read_surplus + | Core·Map·Completion·read_surplus_write_gap + | Core·Map·Completion·write_available + | Core·Map·Completion·write_gap + ; + + typedef Core·Map·Fn (*Core·Map·Fn)(); + + // Link for Map + typedef struct{ + Core·Link *domain; + Core·Link *range; + Core·Map·Fn *fn; + Core·Map·Status status; + } Core·Map·Tableau; + + void Core·map(Core·Map·Tableau t); + + // true if function enters the map loop, otherwise false. + void Core·map(Core·Map·Tableau *t){ + #ifdef Core·DEBUG + if(!t){ + fprintf(stderr, "Core·Map·Tableau:: given NULL t"); + return; + } + uint error = 0; + if( t->status & Core·Map·Completion·derailed != 0 ){ + fprintf(stderr, "Core·Map:: prior map completion status is derailed."); + } + call(status ,t->domain); + if(t->domain->tableau->status & Core·TM·Head·Status·on_track == 0){ + fprintf(stderr, "Core·Map:: domain is not on_track."); + error++; + } + call(status ,t->range); + if(t->range->tableau->status & Core·TM·Head·Status·on_track == 0){ + fprintf(stderr, "Core·Map:: range is not on_track."); + error++; + } + if(error > 0) return; + #endif + + + } + + //---------------------------------------- + // Copy + + typedef enum{ + Core·Copy·Status·mu = 0 + ,Core·Copy·Status·argument_guard = 1 + ,Core·Copy·Status·perfect_fit = 2 + ,Core·Copy·Status·read_surplus = 4 + ,Core·Copy·Status·read_surplus_write_gap = 8 + ,Core·Copy·Status·write_available = 16 + ,Core·Copy·Status·write_gap = 32 + } Core·Copy·Status; + + typedef struct{ + Core·TM read; + Core·TM write; + Core·Function init; + Core·Function copy_cell; + Core·Function step; + Core·Function status; + } Core·Copy·Link; + + typedef struct{ + + uint8AU_t Area·read_8AU_zero(Core·Area *area ,void *r); + uint8AU_t Area·read_8AU_fwd(Core·Area *area ,void *r); + uint8AU_t Area·read_8AU_rev(Core·Area *area_8AU ,void *r); + + // hex conversion + uint16_t byte_to_hex(uint8_t byte); + uint8_t hex_to_byte(uint16_t hex); + + // copy one area to another, possibly with a transformation + Map·Status Core·map(Core·Map·Fn fn); + Map·Fn Map·AU_by_AU; + Map·Fn Map·by_8AU; + Map·Fn Map·write_hex; + Map·Fn Map·read_hex; + + } Core·MapFn·Face; + + +#endif + +//-------------------------------------------------------------------------------- +// Implementation +#ifdef Core·IMPLEMENTATION + // declarations available to all of the IMPLEMENTATION go here + // + #ifdef Core·DEBUG + #include + #endif + + // this part goes into the library + #ifndef LOCAL + #endif + + #ifdef LOCAL + + //---------------------------------------- + // model + + Core·Status Core·on_track(){ return Core·Status·on_track; } + Core·Status Core·derailed(){ return Core·Status·derailed; } + + Local void *Core·offset(void *p ,size_t Δ){ + #ifdef Core·Debug + if( !p ){ + fprintf(stderr ,"Core·offset:: given NULL `p'"); + return NULL; + } + #endif + return (void *)( (AU *)p ) + Δ; + } + + Local void *Core·offset_8AU(void *p ,size_t Δ){ + #ifdef Core·Debug + if( !p ){ + fprintf(stderr ,"Core·offset_8AU:: given NULL `p'"); + return NULL; + } + #endif + return (void *)( (uint64_t *)p ) + Δ; + } + + Local bool Core·is_aligned_on_8AU(void *p){ + #ifdef Core·Debug + if( !p ){ + fprintf(stderr ,"Core·is_aligned_on_8AU:: given NULL `p'"); + return false; + } + #endif + return ( (uintptr_t)p & 0x7 ) == 0; + } + + // find the lowest address in an 8 byte aligned window + // returns the byte pointer to the least address byte in the window + Local void *Core·floor_within_aligned_8AU(void *p){ + #ifdef Core·Debug + if( !p ){ + fprintf(stderr ,"Core·floor_8AU:: given NULL `p'" ); + return NULL; + } + #endif + return (void *)( (uintptr_t)p & ~(uintptr_t)0x7 ); + } + + // find the largest address in an 8 byte aligned window + // returns the byte pointer to the greatest address byte in the window + Local void *Core·ceiling_within_aligned_8AU(void *p){ + #ifdef Core·Debug + if( !p ){ + fprintf(stderr ,"Core·ceiling_64:: given NULL `p'" ); + return NULL; + } + #endif + return (void *)( (uintptr_t)p | 0x7 ); + } + + // Struct instance initialization + Core·Action action_struct{ + .on_track = Core·on_track + ,.derailed = Core·derailed + ,.offset = Core·offset + ,.offset_8AU = Core·offset_8AU + ,.is_aligned_on_8AU = Core·is_aligned_on_8AU + ,.floor_within_aligned_8AU = Core·floor_within_aligned_8AU + ,.ceiling_within_aligned_8AU = Core·ceiling_within_aligned_8AU + }; + + //---------------------------------------- + // Tape Machine model, based on an array + + typedef struct{ + AU *position; + extent_t extent; + }Core·Tape; + +Core·Tape·Topo Core·Tape·Array·topo(Core·Tape *tape){ + +} + + + extent_t extent(Core·Area *area); + void read(Core·Tape·Address ,Core·Tape·Remote); + void write(Core·Tape·Address ,Core·Tape·Remote); + + + + + //---------------------------------------- + // Tape Machine Model based on array + + void Core·TM_NX·Array·mount(Core·TM_NX·Array *tm){ + // Mount the tape machine to its initial state + } + + void Core·TM_NX·Array·rewind(Core·TM_NX·Array *tm){ + // Reset the tape head position + } + + bool Core·TM_NX·Array·can_step(Core·TM_NX·Array *tm){ + // Determine if a step operation is possible + return true; + } + + void Core·TM_NX·Array·step(Core·TM_NX·Array *tm){ + // Perform a step operation + } + + void Core·TM_NX·Array·step_left(Core·TM_NX·Array *tm){ + // Perform a step operation to the left + } + + void Core·TM_NX·Array·topo(Core·TM_NX·Array *tm){ + // Handle topological considerations + } + + void Core·TM_NX·Array·head_status(Core·TM_NX·Array *tm){ + // Retrieve the current head status + } + + //---------------------------------------- + // Initialize Action Table + Core·TM_NX·Array·Action Core·TM_NX·Array·action = { + .mount = Core·mount + ,.rewind = Core·rewind + ,.can_step = Core·can_step + ,.step = Core·step + ,.step_left = Core·step_left + ,.topo = Core·topo + ,.head_status = Core·head_status + }; + + + // initialize an area + + Local void Core·Area·set_position(Core·Area *area ,void *new_position){ + area->position = new_position; + } + Local extent_t Core·Area·set_extent(Core·Area *area ,exent_t extent){ + return area->extent = extent; + } + Local void Core·Area·set_position_right(Core·Area *area ,void *new_position_right){ + Core·Area·set_extent(new_position_right - area->position); + } + Local void Core·Area·init_pe(Core·Area *area ,AU *position ,extent_t extent){ + Core·Area·set_position(position); + Core·Area·set_extent(extent); + } + Local void Core·Area·init_pp(Core·Area *area ,void *position_left ,void *position_right){ + Core·Area·set_position_left(position_left); + Core·Area·set_position_right(position_right); + } + + // read area properties + + Local bool Core·Area·empty(Core·Area *area){ + #ifdef Core·Debug + if(!area){ + fprintf(stderr,"Core·Area·empty:: given NULL area"); + return true; + } + #endif + return area->position == NULL; + } + + // Requesting a NULL position is a logical error, because a NULL position + // means the Area is empty and has no position. Instead, use the `empty` + // predicate. + Local AU *Core·Area·position(Core·Area *area){ + #ifdef Core·Debug + if(!area){ + fprintf(stderr,"Core·Area·position:: given NULL area"); + return NULL; + } + if(!area->position){ + fprintf(stderr,"Core·Area·position:: request for position when it is NULL"); + } + #endif + return area->position; + } + + + Local AU *Core·Area·position_right(Core·Area *area){ + #ifdef Core·Debug + if(!area){ + fprintf(stderr,"Core·Area·position_right:: given NULL area"); + return NULL; + } + #endif + return area->position + area->extent; + } + Local extent_t Core·Area·extent(Core·Area *area){ + #ifdef Core·Debug + if(!area){ + fprintf(stderr,"Core·Area·extent:: given NULL area"); + return 0; + } + #endif + return area->extent; + } + Local AU Core·Area·length_Kung(Core·Area *area){ + if(!Core·Area·position_left(area)) return 0; + if(Core·Area·extent(area) >= 2) return 3; + return Core·Area·extent(area) + 1; + } + + Local bool Core·Area·encloses_pt(Core·Area *area ,AU *pt){ + return + (pt >= Core·Area·position_left(area)) + && (pt <= Core·Area·position_right(area)); + } + Local bool Core·Area·encloses_pt_strictly(Core·Area *area ,AU *pt){ + return + (pt > Core·Area·position_left(area)) + && (pt < Core·Area·position_right(area)); + } + Local bool Core·Area·encloses_area(Core·Area *outer ,Core·Area *inner){ + return + (Core·Area·position_left(inner) >= Core·Area·position_left(outer)) + && (Core·Area·position_right(inner) <= Core·Area·position_right(outer)); + } + Local bool Core·Area·encloses_area_strictly(Core·Area *outer ,Core·Area *inner){ + return + (Core·Area·position_left(inner) > Core·Area·position_left(outer)) + && (Core·Area·position_right(inner) < Core·Area·position_right(outer)); + } + + // Possible cases of overlap ,including just touching + // 1. interval 0 to the right of interval 1 ,just touching p00 == p11 + // 2. interval 0 to the left of interval 1 ,just touching p01 == p10 + // 3. interval 0 wholly contained in interval 1 + // 4. interval 0 wholly contains interval 1 + Local bool Core·Area·overlap(Core·Area *area0 ,Core·Area *area1){ + return + Core·Area·position_right(area0) >= Core·Area·position_left(area1) + && Core·Area·position_left(area0) <= Core·Area·position_right(area1); + } + + // find the largest contained interval aligned on 64 bit boundaries + static void Core·Area·largest_aligned_64(Core·Area *outer ,Core·Area *inner_64){ + uintptr_t p0 = (uintptr_t)Core·Area·position_left(outer); + uintptr_t p1 = (uintptr_t)Core·Area·position_right(outer); + + AU *p0_64 = (AU *)( (p0 + 0x7) & ~(uintptr_t)0x7 ); + AU *p1_64 = (AU *)( (p1 - 0x7) & ~(uintptr_t)0x7 ); + + if(p1_64 < p0_64){ + Core·Area·set_position(inner_64 ,NULL); + }else{ + Core·Area·init_pp(inner_64 ,p0_64 ,p1_64); + } + } + + // complement against the extent of the area (reverse direction) + // works for byte pointer + // works for aligned word pointer + Local AU *Core·Area·complement(Core·Area *area ,AU *r){ + return Core·Area·position_left(area) + (Core·Area·position_right(area) - r); + } + + //---------------------------------------- + // read functions + + // consider instead using `copy_zero` + Local AU Core·Area·read_8_zero(Core·Area *area ,void *r){ + return 0; + } + Local uint64_t Core·Area·read_64_zero(Core·Area *area ,void *r){ + return 0; + } + + Local AU Core·Area·read_8_fwd(){ + Core·Area a = Core·tf.read; + AU **r = &Core·tf.read_pt; + + #ifdef Core·Debug + if(!a || !*r){ + fprintf(stderr ,"Core·Area·read_8_fwd:: read read_pt: %p %p\n" ,a ,*r); + return Core·Map·Read·Status·argument_guard; + } + if( !Core·Area·enclose_pt(area ,r) ){ + fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); + } + #endif + return *(AU *)r; + } + + Local AU Core·Area·read_8_fwd(Core·Area *area ,void *r){ + #ifdef Core·Debug + if(!area || !r){ + fprintf(stderr,"Core·Area·read_8_fwd:: area r: %p %p\n" ,area ,r); + return 0; + } + if( !Core·Area·enclose_pt(area ,r) ){ + fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); + } + #endif + return *(AU *)r; + } + + // Given a pointer to the least address byte of a uint64_t, return the value + Local uint64_t Core·Area·read_64_fwd(Core·Area *area ,void *r){ + #ifdef Core·Debug + if(!area || !r){ + fprintf(stderr,"Core·Area·read_8_fwd:: area r: %p %p\n" ,area ,r); + return 0; + } + if(!Core·Area·enclose_pt(area ,r) ){ + fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); + } + #endif + return *(uint64_t *)r; + } + + Local AU Core·Area·read_8_rev(Core·Area *area ,AU *r){ + return *(Core·complement(area ,r)); + } + + Local uint64_t Core·Area·read_64_rev(Core·Area *area_64 ,AU *r){ + return __builtin_bswap64( *(uint64_t *)Core·floor_64(Core·complement(area_64 ,r)) ); + } + + //---------------------------------------- + // Map + + // Map function using trampoline execution model + Local Core·Map·Status Core·map(Core·Map·Fn fn){ + #ifdef Core·Debug + if(!fn){ + fprintf(stderr,"Core·map:: given null function"); + return Core·Map·argument_guard; + } + if( + true + && fn != Core·Map·by_8AU + && fn != Core·Map·AU_by_AU + && fn != Core·write_hex + && fn != Core·read_hex + ){ + fprintf(stderr,"Core·map:: unrecognized copy function\n"); + return Core·Map·argument_guard; + ) + #endif + + while(fn) fn = fn(); + return tf.copy.status; + } + + //---------------------------------------- + // copy byte_by_byte + + Core·Map·Fn Core·Map·Map·ByteByByte·perfect_fit; + Core·Map·Fn Core·Map·Map·ByteByByte·read_surplus; + Core·Map·Fn Core·Map·Map·ByteByByte·write_available; + + Local Core·Map·Fn Core·Map·AU_by_AU(){ + if(Core·Area·extent(Core·tf.copy.read) == Core·Area·extent(Core·tf.copy.write)) + return Core·Map·ByteByByte·perfect_fit; + + if(Core·Area·extent(Core·tf.copy.read) > Core·Area·extent(Core·tf.copy.write)) + return Core·Map·ByteByByte·read_surplus; + + return Core·Map·ByteByByte·write_available; + } + + Local Core·Map·Fn Core·Map·ByteByByte·perfect_fit(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + + do{ + **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); + if(*r == r1) break; + (*r)++; + (*w)++; + }while(true); + + Core·tf.copy.status = Core·Map·Status·perfect_fit; + return NULL; + } + + Local Core·Map·Fn Core·Map·ByteByByte·read_surplus(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + AU *w1 = Core·Area·position_right(Core·tf.copy.write); + + do{ + **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); + if(*w == w1) break; + (*r)++; + (*w)++; + }while(true); + + Core·tf.copy.status = Core·Map·Status·write_available; + return NULL; + } + + Local Core·Map·Fn Core·Map·ByteByByte·write_avalable(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + + do{ + **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); + if(*r == r1) break; + (*r)++; + (*w)++; + }while(true); + + Core·tf.copy.status = Core·Map·Status·read_surplus; + return NULL; + } + + //---------------------------------------- + // copy copy_64 + + // 64-bit copy function with updated TableauFace terminology + Core·Map·Fn Core·Map·by_8AU; + Core·Map·Fn Core·Map·ByWord64·leadin; + Core·Map·Fn Core·Map·ByWord64·bulk; + Core·Map·Fn Core·Map·ByWord64·tail; + + // Initialize the copy_64 process + Local Core·Map·Fn Core·Map·by_8AU(){ + // Determine the largest 64-bit aligned region within the read area + Core·Area·largest_aligned_64(Core·tf.copy.read ,&Core·tl.copy_64.area_64); + + // Choose the correct function based on alignment + if(Core·Area·empty(&Core·tl.copy_64.area_64)) return Core·Map·ByWord64·tail; + if(Core·is_aligned_on_64(Core·Area·position(Core·tf.copy.read))) return Core·Map·ByWord64·bulk; + return Core·Map·ByWord64·leadin; + } + + // Lead-in byte copy (until alignment) + Local Core·Map·Fn Core·Map·ByWord64·leadin(){ + AU **r = &Core·tf.copy.read_pt; + AU *r0_64 = Core·Area·position(&Core·tl.copy_64.area_64); + AU **w = &Core·tf.copy.write_pt; + + do{ + **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,r0_64 ,*r); + if(*r == r0_64) break; + (*r)++; + (*w)++; + }while(true); + + return Core·Map·ByWord64·bulk; + } + + // Bulk word copy + Local Core·Map·Fn Core·Map·ByWord64·bulk(){ + uint64_t **r = (uint64_t **)&Core·tf.copy.read_pt; + uint64_t **w = (uint64_t **)&Core·tf.copy.write_pt; + uint64_t *r1_64 = Core·Area·position_right(&Core·tl.copy_64.area_64); + + do{ + **w = Core·tf.copy.read_fn_64(Core·tf.copy.read ,r1_64 ,*r); + if(*r == r1_64) break; + (*r)++; + (*w)++; + }while(true); + + return Core·Map·ByWord64·tail; + } + + // Tail byte copy (unaligned trailing bytes) + Local Core·Map·Fn Core·Map·ByWord64·tail(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(&Core·tl.copy_64.area_64); + AU **w = &Core·tf.copy.write_pt; + + do{ + **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,r1 ,*r); + if(*r == r1) break; + (*r)++; + (*w)++; + }while(true); + + Core·tf.copy.status = Core·Map·Status·perfect_fit; + return NULL; + } + + //---------------------------------------- + // copy write hex + + Local uint16_t Core·byte_to_hex(AU byte){ + static const char hex_digits[] = "0123456789ABCDEF"; + return + (hex_digits[byte >> 4] << 8) + | hex_digits[byte & 0x0F]; + } + + // Forward Declarations + Core·Map·Fn Core·Map·write_hex; + Core·Map·Fn Core·Map·WriteHex·perfect_fit; + Core·Map·Fn Core·Map·WriteHex·read_surplus; + Core·Map·Fn Core·Map·WriteHex·write_available; + + // Hex Encoding: Initialize Map + Local Core·Map·Fn Core·Map·write_hex(){ + if(Core·Area·extent(Core·tf.copy.read) == (Core·Area·extent(Core·tf.copy.write) >> 1)){ + return Core·Map·WriteHex·perfect_fit; + } + if(Core·Area·extent(Core·tf.copy.read) > (Core·Area·extent(Core·tf.copy.write) >> 1)){ + return Core·Map·WriteHex·read_surplus; + } + return Core·Map·WriteHex·write_available; + } + + Local Core·Map·Fn Core·Map·WriteHex·perfect_fit(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + + do { + *(uint16_t *)*w = Core·hex.byte_to_hex(**r); + if(*r == r1) break; + (*r)++; + (*w) += 2; + } while(true); + + Core·tf.copy.status = Core·Map·Status·perfect_fit; + return NULL; + } + + // Hex Encoding: Read Surplus + Local Core·Map·Fn Core·Map·WriteHex·read_surplus(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.write); + AU **w = &Core·tf.copy.write_pt; + + do { + *(uint16_t *)*w = Core·write_hex.byte_to_hex(**r); + if(*r == r1) break; + (*r)++; + (*w) += 2; + } while(true); + + Core·tf.copy.status = Core·Map·Status·read_surplus; + return NULL; + } + + // Hex Encoding: Write Available + Local Core·Map·Fn Core·Map·WriteHex·write_available(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + AU *w1 = Core·Area·position_right(Core·tf.copy.write); + + do { + *(uint16_t *)*w = Core·write_hex.byte_to_hex(**r); + if(*w == w1) break; + (*r)++; + (*w) += 2; + } while(true); + + Core·tf.copy.status = Core·Map·Status·write_available; + return NULL; + } + + //---------------------------------------- + // copy read hex + + Local AU Core·hex_to_byte(uint16_t hex){ + AU high = hex >> 8; + AU low = hex & 0xFF; + + high = + (high >= '0' && high <= '9') ? (high - '0') + : (high >= 'A' && high <= 'F') ? (high - 'A' + 10) + : (high >= 'a' && high <= 'f') ? (high - 'a' + 10) + : 0; + + low = + (low >= '0' && low <= '9') ? (low - '0') + : (low >= 'A' && low <= 'F') ? (low - 'A' + 10) + : (low >= 'a' && low <= 'f') ? (low - 'a' + 10) + : 0; + + return (high << 4) | low; + } + + Core·Map·Fn Core·Map·read_hex; + Core·Map·Fn Core·Map·ReadHex·perfect_fit; + Core·Map·Fn Core·Map·ReadHex·read_surplus; + Core·Map·Fn Core·Map·ReadHex·write_available; + + Local Core·Map·Fn Core·Map·read_hex(){ + if((Core·Area·extent(Core·tf.copy.read) >> 1) == Core·Area·extent(Core·tf.copy.write)){ + return Core·Map·ReadHex·perfect_fit; + } + if((Core·Area·extent(Core·tf.copy.read) >> 1) > Core·Area·extent(Core·tf.copy.write)){ + return Core·Map·ReadHex·read_surplus; + } + return Core·Map·ReadHex·write_available; + } + + Local Core·Map·Fn Core·Map·ReadHex·perfect_fit(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + + do { + **w = Core·hex_to_byte(*(uint16_t *)*r); + if(*r == r1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·perfect_fit; + return NULL; + } + + Local Core·Map·Fn Core·Map·ReadHex·read_surplus(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.write); + AU **w = &Core·tf.copy.write_pt; + + do { + **w = Core·tf.read_hex.hex_to_byte(*(uint16_t *)*r); + if(*r == r1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·read_surplus; + return NULL; + } + + Local Core·Map·Fn Core·Map·ReadHex·write_available(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + AU *w1 = Core·Area·position_right(Core·tf.copy.write); + + do { + **w = Core·tf.read_hex.hex_to_byte(*(uint16_t *)*r); + if(*w == w1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·write_available; + return NULL; + } + + //---------------------------------------- + // copy read hex + + Core·Map·Fn Core·Map·read_hex; + Core·Map·Fn Core·Map·ReadHex·perfect_fit; + Core·Map·Fn Core·Map·ReadHex·read_surplus; + Core·Map·Fn Core·Map·ReadHex·write_available; + + Local Core·Map·Fn Core·Map·read_hex(){ + if((Core·Area·extent(Core·tf.copy.read) >> 1) == Core·Area·extent(Core·tf.copy.write)){ + return Core·Map·ReadHex·perfect_fit; + } + if((Core·Area·extent(Core·tf.copy.read) >> 1) > Core·Area·extent(Core·tf.copy.write)){ + return Core·Map·ReadHex·read_surplus; + } + return Core·Map·ReadHex·write_available; + } + + Local Core·Map·Fn Core·Map·ReadHex·perfect_fit(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + + do { + **w = Core·hex_to_byte(*(uint16_t *)*r); + if(*r == r1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·perfect_fit; + return NULL; + } + + Local Core·Map·Fn Core·Map·ReadHex·read_surplus(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.write); + AU **w = &Core·tf.copy.write_pt; + + do { + **w = Core·hex_to_byte(*(uint16_t *)*r); + if(*r == r1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·read_surplus; + return NULL; + } + + Local Core·Map·Fn Core·Map·ReadHex·write_available(){ + AU **r = &Core·tf.copy.read_pt; + AU *r1 = Core·Area·position_right(Core·tf.copy.read); + AU **w = &Core·tf.copy.write_pt; + AU *w1 = Core·Area·position_right(Core·tf.copy.write); + + do { + **w = Core·hex_to_byte(*(uint16_t *)*r); + if(*w == w1) break; + (*r) += 2; + (*w)++; + } while(true); + + Core·tf.copy.status = Core·Map·Status·write_available; + return NULL; + } + + //---------------------------------------- + // Initialization Blocks + + //---------------------------------------- + // Tableaux + + Core·TableauFace tf = { + .copy = { + .read = NULL + ,.write = NULL + ,.read_fn_8 = Core·Area·read_8_fwd + ,.read_fn_64 = Core·Area·read_64_fwd + ,.read_pt = NULL + ,.write_pt = NULL + ,.status = Core·Map·Status·uninitialized + } + }; + + Core·TableauLocal tl = { + .copy_64 = { + .area_64 = {NULL ,0} + } + }; + + Core·M m = { + .Area·init_pe = Core·Area·init_pe + ,.Area·init_pp = Core·Area·init_pp + ,.Area·set_position = Core·Area·set_position + ,.Area·set_position_left = Core·Area·set_position + ,.Area·set_position_right = Core·Area·set_position_right + ,.Area·set_extent = Core·Area·set_extent + ,.Area·position = Core·Area·position + ,.Area·position_left = Core·Area·position + ,.Area·position_right = Core·Area·position_right + ,.Area·extent = Core·Area·extent + ,.Area·length_Kung = Core·Area·length_Kung + ,.Area·empty = Core·Area·empty + + ,.Area·encloses_pt = Core·Area·encloses_pt + ,.Area·encloses_pt_strictly = Core·Area·encloses_pt_strictly + ,.Area·encloses_area = Core·Area·encloses_area + ,.Area·encloses_area_strictly = Core·Area·encloses_area_strictly + ,.Area·overlap = Core·Area·overlap + ,.Area·largest_aligned_64 = Core·Area·largest_aligned_64 + ,.Area·complement = Core·Area·complement + + ,.Area·read_8_zero = Core·Area·read_8_zero + ,.Area·read_8_fwd = Core·Area·read_8_fwd + ,.Area·read_8_rev = Core·Area·read_8_rev + ,.Area·read_64_zero = Core·Area·read_64_zero + ,.Area·read_64_fwd = Core·Area·read_64_fwd + ,.Area·read_64_rev = Core·Area·read_64_rev + + ,.is_aligned_on_64 = Core·is_aligned_on_64 + ,.floor_64 = Core·floor_64 + ,.ceiling_64 = Core·ceiling_64 + ,.offset_8 = Core·offset_8 + ,.offset_64 = Core·offset_64 + + ,.byte_to_hex = Core·byte_to_hex + ,.hex_to_byte = Core·hex_to_byte + + ,.copy = Core·map + ,.Map·AU_by_AU = Core·Map·AU_by_AU + ,.Map·by_8AU = Core·Map·by_8AU + ,.Map·write_hex = Core·Map·write_hex + ,.Map·read_hex = Core·Map·read_hex + }; + + #endif // LOCAL + +#endif // IMPLEMENTATION diff --git a/developer/deprecated/Map.lib.c b/developer/deprecated/Map.lib.c new file mode 100644 index 0000000..2592129 --- /dev/null +++ b/developer/deprecated/Map.lib.c @@ -0,0 +1,154 @@ +/* Map - mapping functions between tape machines. + + This file has two template parameters: + `CVT_read` Cell Value Type for the source/read tape machine + `CVT_write` Cell Value Type for the destination/write tape machine + + By default (when the macros have no definition) the cell value types are taken as AU. + This file must be included with CVT_read and CVT_write undefined, before inclusions with them defined. + + 'Tape' is operated on by the Tape Machine. + 'Area' is subset of an address space that is used as a virtual Tape by a machine. + An Area with zero elements has 'length == 0' or is 'empty'. + In contrast, and area located (position specified) with a null pointer is said not to exist. +*/ + +#define Map·DEBUG + +#ifndef FACE + #define Map·IMPLEMENTATION + #define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Map·FACE + #define Map·FACE + + #include + #include + #include "Core.lib.c" + #include "TM.lib.c" + + // if only one template parameter is given, we will assume both are the same + + #if defined(CVT_read) && !defined(CVT_write) + #warning "Given CVT_read template value. Missing CVT_write template value, so setting it to CVT_read" + #define CVT_write CVT_read + #endif + + #if !defined(CVT_read) && defined(CVT_write) + #warning "Given CVT_write template value. Missing CVT_read template value, so setting it to CVT_write" + #define CVT_read CVT_write + #endif + + //---------------------------------------- + // Map status and completion enums + //---------------------------------------- + + #if !defined(CVT_read) && !defined(CVT_write) + + typedef enum { + Map·Completion·mu = 0 + ,Map·Completion·failed = 1 + ,Map·Completion·null_fn = 1 << 1 + ,Map·Completion·no_tape_access = 1 << 2 + ,Map·Completion·rightmost_read = 1 << 3 + ,Map·Completion·rightmost_write = 1 << 4 + } Map·Completion; + + // Masks for combinations + const uint Map·Completion·rightmost_both = + Map·Completion·rightmost_read + | Map·Completion·rightmost_write + ; + + const uint Map·Completion·derailed = + Map·Completion·failed + | Map·Completion·null_fn + | Map·Completion·no_tape_access + ; + + const uint Map·Completion·on_track = + Map·Completion·rightmost_read + | Map·Completion·rightmost_write + | Map·Completion·rightmost_both + ; + + #endif + + //---------------------------------------- + // Map interface + //---------------------------------------- + + #if !defined(CVT_read) || !defined(CVT_write) + + typedef struct { + Map·Completion (*copy_byte_to_byte)( + ·(TM·Array ,AU) *read_tm + ,·(TM·Array ,AU) *write_tm + ); + + Map·Completion (*copy_hex_to_byte)( + ·(TM·Array ,uint16_t) *read_tm + ,·(TM·Array ,AU) *write_tm + ); + + Map·Completion (*copy_byte_to_hex)( + ·(TM·Array ,AU) *read_tm + ,·(TM·Array ,uint16_t) *write_tm + ); + + // Terminate string function + Map·Completion (*terminate_string)( + ·(TM·Array ,AU) *write_tm + ); + } Map·FG; + + // a default function given table + Map·FG Map·fg; + + #endif + + + #if defined(CVT_read) && defined(CVT_write) + + // Function passed to map type signature must be this: + typedef Core·Status (*·(Map·fn ,CVT_read ,CVT_write))( + CVT_read *read_value + ,CVT_write *write_value + ); + + typedef struct { + // Map a function over all elements from read_tm to write_tm + Map·Completion (*map)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ); + + // Map a function over elements from read_tm to write_tm until a condition is met + Map·Completion (*map_while)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,bool (*condition)(·(TM·Array ,CVT_read) *read_tm) + ); + + // Map a function over n elements from read_tm to write_tm + Map·Completion (*map_extent)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,·(extent_t ,CVT_read) extent + ); + + } ·(Map·FG ,CVT_read ,CVT_write); + + // Default function given table + ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write); + + #endif + +#endif // #ifndef Map·FACE diff --git a/developer/deprecated/Map2.lib.c b/developer/deprecated/Map2.lib.c new file mode 100644 index 0000000..e58173e --- /dev/null +++ b/developer/deprecated/Map2.lib.c @@ -0,0 +1,500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* Map - mapping functions between tape machines. + + This file has two template parameters: + `CVT_read` Cell Value Type for the source/read tape machine + `CVT_write` Cell Value Type for the destination/write tape machine + + By default (when the macros have no definition) the cell value types are taken as AU. + This file must be included with CVT_read and CVT_write undefined, before inclusions with them defined. + + 'Tape' is operated on by the Tape Machine. + 'Area' is subset of an address space that is used as a virtual Tape by a machine. + An Area with zero elements has 'length == 0' or is 'empty'. + In contrast, and area located (position specified) with a null pointer is said not to exist. +*/ + +#define Map·DEBUG + +#ifndef FACE + #define Map·IMPLEMENTATION + #define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Map·FACE + #define Map·FACE + + #include + #include + #include "Core.lib.c" + #include "TM.lib.c" + + // if only one template parameter is given, we will assume both are the same + + #if defined(CVT_read) && !defined(CVT_write) + #warning "Given CVT_read template value. Missing CVT_write template value, so setting it to CVT_read" + #define CVT_write CVT_read + #endif + + #if !defined(CVT_read) && defined(CVT_write) + #warning "Given CVT_write template value. Missing CVT_read template value, so setting it to CVT_write" + #define CVT_read CVT_write + #endif + + //---------------------------------------- + // Map status and completion enums + //---------------------------------------- + + #if !defined(CVT_read) && !defined(CVT_write) + + typedef enum { + Map·Completion·mu = 0 + ,Map·Completion·failed = 1 + ,Map·Completion·null_fn = 1 << 1 + ,Map·Completion·no_tape_access = 1 << 2 + ,Map·Completion·rightmost_read = 1 << 3 + ,Map·Completion·rightmost_write = 1 << 4 + } Map·Completion; + + // Masks for combinations + const uint Map·Completion·rightmost_both = + Map·Completion·rightmost_read + | Map·Completion·rightmost_write + ; + + const uint Map·Completion·derailed = + Map·Completion·failed + | Map·Completion·null_fn + | Map·Completion·no_tape_access + ; + + const uint Map·Completion·on_track = + Map·Completion·rightmost_read + | Map·Completion·rightmost_write + | Map·Completion·rightmost_both + ; + + #endif + + //---------------------------------------- + // Map interface + //---------------------------------------- + + #if !defined(CVT_read) || !defined(CVT_write) + typedef struct { + Map·Completion (*copy_byte_to_byte)( + ·(TM·Array ,AU) *read_tm + ,·(TM·Array ,AU) *write_tm + ); + + Map·Completion (*copy_hex_to_byte)( + ·(TM·Array ,uint16_t) *read_tm + ,·(TM·Array ,AU) *write_tm + ); + + Map·Completion (*copy_byte_to_hex)( + ·(TM·Array ,AU) *read_tm + ,·(TM·Array ,uint16_t) *write_tm + ); + + // Terminate string function + Map·Completion (*terminate_string)( + ·(TM·Array ,AU) *write_tm + ); + } + #endif + + + #if defined(CVT_read) && defined(CVT_write) + + // Function passed to map type signature must be this: + typedef Core·Status (*·(Map·fn ,CVT_read ,CVT_write))( + CVT_read *read_value + ,CVT_write *write_value + ); + + typedef struct { + // Map a function over all elements from read_tm to write_tm + Map·Completion (*map)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ); + + // Map a function over elements from read_tm to write_tm until a condition is met + Map·Completion (*map_while)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,bool (*condition)(·(TM·Array ,CVT_read) *read_tm) + ); + + // Map a function over n elements from read_tm to write_tm + Map·Completion (*map_extent)( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,·(extent_t ,CVT_read) extent + ); + + } ·(Map·FG ,CVT_read ,CVT_write); + + // Default function given table + ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write); + #endif // !defined(CVT_read) && !defined(CVT_write) + +#endif // #ifndef Map·FACE + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef Map·IMPLEMENTATION + + // declarations available to all of the IMPLEMENTATION go here + #ifdef Map·DEBUG + #include + #endif + + // implementation to go into the lib.a file + #ifndef LOCAL + #endif + + #ifdef LOCAL + //---------------------------------------- + // Map implementation + //---------------------------------------- + + #if !defined(CVT_read) && !defined(CVT_write) + //----------------------------------- + // common error messages + const char *Map·Msg·read_tm = "given NULL read_tm"; + const char *Map·Msg·write_tm = "given NULL write_tm"; + const char *Map·Msg·map_fn = "given NULL map_fn"; + const char *Map·Msg·condition = "given NULL condition function"; + + //----------------------------------- + // Helper functions for copy operations + + // Byte to byte copy function + Local Core·Status Map·byte_to_byte_fn(AU *read_value, AU *write_value) { + *write_value = *read_value; + return Core·Status·on_track; + } + + // Hex to byte conversion function + Local Core·Status Map·hex_to_byte_fn(uint16_t *read_value, AU *write_value) { + // Convert hex value to byte + *write_value = (AU)(*read_value & 0xFF); + return Core·Status·on_track; + } + + // Byte to hex conversion function + Local Core·Status Map·byte_to_hex_fn(AU *read_value, uint16_t *write_value) { + // Convert byte to lowercase hex representation (no prefix) + static const char hex_chars[] = "0123456789abcdef"; + *write_value = hex_chars[(*read_value >> 4) & 0x0F]; + return Core·Status·on_track; + } + #endif // !defined(CVT_read) && !defined(CVT_write) + + #if defined(CVT_read) && defined(CVT_write) + //----------------------------------- + // Map implementation with specific types + + // Map a function over all elements from read_tm to write_tm + Local Core·Status ·(Map ,CVT_read ,CVT_write)·map( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ){ + #ifdef Map·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); + Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); + Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); + Core·Guard·if_return(chk); + #endif + + // Rewind both tape machines to ensure we start at the beginning + ·(TM·Array ,CVT_read)·fg.rewind(read_tm); + ·(TM·Array ,CVT_write)·fg.rewind(write_tm); + + // Initial check if can_read (not part of the loop) + if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; + + // Track completion status + uint completion = 0; + + // Following the first-rest pattern described in TTCA + while(1){ + // Read value from source + CVT_read read_value; + ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); + + // Apply mapping function to get write value + CVT_write write_value; + Core·Status status = map_fn(&read_value ,&write_value); + if(status != Core·gStatus·on_track) { + completion |= Core·Map·Completion·failed; + return status; + } + + // Write result to destination + ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); + + // Check if we're at the rightmost position for read + bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); + if(read_rightmost) { + completion |= Core·Map·Completion·rightmost_read; + } + + // Check if we're at the rightmost position for write + bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); + if(write_rightmost) { + completion |= Core·Map·Completion·rightmost_write; + } + + // Break if either machine is at rightmost + if(read_rightmost || write_rightmost) break; + + // Step both machines + ·(TM·Array ,CVT_read)·fg.step(read_tm); + ·(TM·Array ,CVT_write)·fg.step(write_tm); + } + + return Core·Status·on_track; + } + + // Map a function over elements from read_tm to write_tm until a condition is met + Local Core·Status ·(Map ,CVT_read ,CVT_write)·map_while( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,bool (*condition)(CVT_read *value) + ){ + #ifdef Map·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); + Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); + Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); + Core·Guard·fg.check(&chk ,1 ,condition ,Map·Msg·condition); + Core·Guard·if_return(chk); + #endif + + // Rewind both tape machines to ensure we start at the beginning + ·(TM·Array ,CVT_read)·fg.rewind(read_tm); + ·(TM·Array ,CVT_write)·fg.rewind(write_tm); + + // Initial check if can_read (not part of the loop) + if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; + + // Track completion status + uint completion = 0; + + // Following the first-rest pattern described in TTCA + while(1){ + // Read value from source + CVT_read read_value; + ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); + + // Check condition + if(!condition(&read_value)) break; + + // Apply mapping function to get write value + CVT_write write_value; + Core·Status status = map_fn(&read_value ,&write_value); + if(status != Core·Status·on_track) { + completion |= Core·Map·Completion·failed; + return status; + } + + // Write result to destination + ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); + + // Check if we're at the rightmost position for read + bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); + if(read_rightmost) { + completion |= Core·Map·Completion·rightmost_read; + } + + // Check if we're at the rightmost position for write + bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); + if(write_rightmost) { + completion |= Core·Map·Completion·rightmost_write; + } + + // Break if either machine is at rightmost + if(read_rightmost || write_rightmost) break; + + // Step both machines + ·(TM·Array ,CVT_read)·fg.step(read_tm); + ·(TM·Array ,CVT_write)·fg.step(write_tm); + } + + return Core·Status·on_track; + } + + // Map a function over n elements from read_tm to write_tm + Local Core·Status ·(Map ,CVT_read ,CVT_write)·map_n( + ·(TM·Array ,CVT_read) *read_tm + ,·(TM·Array ,CVT_write) *write_tm + ,·(Map·fn ,CVT_read ,CVT_write) map_fn + ,size_t n + ){ + #ifdef Map·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); + Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); + Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); + Core·Guard·if_return(chk); + #endif + + // Rewind both tape machines to ensure we start at the beginning + ·(TM·Array ,CVT_read)·fg.rewind(read_tm); + ·(TM·Array ,CVT_write)·fg.rewind(write_tm); + + // Initial check if can_read (not part of the loop) + if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; + + // Track completion status + uint completion = 0; + + // Following the first-rest pattern described in TTCA + size_t count = 0; + while(count < n){ + // Read value from source + CVT_read read_value; + ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); + + // Apply mapping function to get write value + CVT_write write_value; + Core·Status status = map_fn(&read_value ,&write_value); + if(status != Core·Status·on_track) { + completion |= Core·Map·Completion·failed; + return status; + } + + // Write result to destination + ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); + + // Increment count + count++; + + // Check if we're at the rightmost position for read + bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); + if(read_rightmost) { + completion |= Core·Map·Completion·rightmost_read; + } + + // Check if we're at the rightmost position for write + bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); + if(write_rightmost) { + completion |= Core·Map·Completion·rightmost_write; + } + + // Break if either machine is at rightmost + if(read_rightmost || write_rightmost) break; + + // Step both machines + ·(TM·Array ,CVT_read)·fg.step(read_tm); + ·(TM·Array ,CVT_write)·fg.step(write_tm); + } + + return Core·Status·on_track; + } + + // Initialize the function given table + ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write) = { + .map = ·(Map ,CVT_read ,CVT_write)·map + ,.map_while = ·(Map ,CVT_read ,CVT_write)·map_while + ,.map_n = ·(Map ,CVT_read ,CVT_write)·map_n + }; + #endif // defined(CVT_read) && defined(CVT_write) + + //---------------------------------------- + // Copy functions implementation + //---------------------------------------- + + // Byte to byte copy + Local Core·Status Map·copy_byte_to_byte( + ·(TM·Array ,AU) *read_tm + ,·(TM·Array ,AU) *write_tm + ){ + #ifdef Map·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); + Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); + Core·Guard·if_return(chk); + #endif + + return ·(Map ,AU ,AU)·fg.map(read_tm, write_tm, Map·byte_to_byte_fn); + } + + // Hex to byte copy + Local Core·Status Map·copy_hex_to_byte( + ·(TM·Array ,uint16_t) *read_tm + ,·(TM·Array ,AU) *write_tm + ){ + #ifdef Map·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); + Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); + Core·Guard·if_return(chk); + #endif + + return To save on context only part of this file has been shown to you. You should retry this tool after you have searched inside the file with `grep -n` in order to find the line numbers of what you are looking for. diff --git a/developer/deprecated/NN_Count_Digit.lib.c b/developer/deprecated/NN_Count_Digit.lib.c new file mode 100644 index 0000000..9d604a9 --- /dev/null +++ b/developer/deprecated/NN_Count_Digit.lib.c @@ -0,0 +1,118 @@ +/* + A digit count followed by that many digits. + + Extent_Digit_Instance: + - 'NN' stands for Natural Number representation. + - 'Extent' refers to the maximum array index. + - 'Digit' specifies that the representation involves digits. + - 'Instance' differentiates this from the interface struct, ensuring clarity in alternative representations. +*/ + +#ifndef IFACE +#define NN_Extent_Digit·IMPLEMENTATION +#define IFACE +#endif + +#ifndef NN_Extent_Digit·IFACE +#define NN_Extent_Digit·IFACE + + typedef uint32_t Extent; + + // interface function signatures + // + typedef NN_Extent_Digit *(*NN_Extent_Digit·Copy·MemoryFault) + ( + Extent extent + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Copy) + ( + NN_Extent_Digit *original + ,NN_Extent_Digit·Copy·MemoryFault memory_fault + ); + + typedef void (*NN_Extent_Digit·Accumulate) + ( + NN_Extent_Digit *accumulator ,... + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Add) + ( + NN_Extent_Digit *summand ,... + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Multiply) + ( + NN_Extent_Digit *factor ,... + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Rotate_Right_Digit) + ( + Extent count + ,NN_Extent_Digit *a + ,NN_Extent_Digit *b + ,NN_Extent_Digit *c + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Rotate_Left_Digit) + ( + Extent count + ,NN_Extent_Digit *a + ,NN_Extent_Digit *b + ,NN_Extent_Digit *c + ); + + typedef NN_Extent_Digit *(*NN_Extent_Digit·Allocate·MemoryFault) + ( + Extent extent + ); + + // interface struct definition + // + typedef struct { + NN_Extent_Digit·Copy copy; + NN_Extent_Digit·Accumulate accumulate; + NN_Extent_Digit·Add add; + NN_Extent_Digit·Multiply multiply; + NN_Extent_Digit·Rotate_Right_Digit rotate_right_digit; + NN_Extent_Digit·Rotate_Left_Digit rotate_left_digit; + } NN_Extent_Digit; + + // an extent is a maximum array index + NN_Extent_Digit *NN_Extent_Digit·allocate(Extent extent, NN_Extent_Digit·Allocate·MemoryFault memory_fault); + void NN_Extent_Digit·deallocate(NN_Extent_Digit *unencumbered); + +#endif + +#ifdef NN_Extent_Digit·IMPLEMENTATION + + #include + #include + typedef uint32_t Digit; + + typedef struct { + Extent extent; + Digit a[]; + } Instance; + + NN_Extent_Digit *allocate(Extent extent, NN_Extent_Digit·Allocate·MemoryFault memory_fault){ + Extent allocation_size = sizeof(NN_Extent_Digit_Instance) + extent * sizeof(Digit) + sizeof(Digit); + Instance *instance = malloc(allocation_size); + if (!instance) { + return memory_fault ? memory_fault(extent) : NULL; + } + instance->extent = extent; + + // nope-> need to allocate an interface signature struct and assign the method + // function pointers to it. It will also need a field for holding the instance, + // yes, declare a new interface struct that has an extra field on the bottom for + // the instance pointer .. but then what of interface inheritance? hmmm. Perhaps + // that is better done by composition anyway. + return (NN_Extent_Digit *)instance; + } + + void deallocate(NN_Extent_Digit *unencumbered){ + free(unencumbered); + } + +#endif diff --git a/developer/deprecated/N_32_test.cli.c b/developer/deprecated/N_32_test.cli.c new file mode 100644 index 0000000..5cb2d2e --- /dev/null +++ b/developer/deprecated/N_32_test.cli.c @@ -0,0 +1,118 @@ +#include +#include +#include "N_32.lib.h" // Include the module under test + +// Test function prototypes +bool test_copy(); +bool test_bitwise_operations(); +bool test_comparisons(); +bool test_arithmetic(); +bool test_shifts(); + +// Test array (null-terminated) +typedef bool (*TestFunction)(); +typedef struct { + TestFunction function; + const char *name; +} TestEntry; + +TestEntry test_list[] = { + { test_copy, "test_copy" }, + { test_bitwise_operations, "test_bitwise_operations" }, + { test_comparisons, "test_comparisons" }, + { test_arithmetic, "test_arithmetic" }, + { test_shifts, "test_shifts" }, + { NULL, NULL } // Null termination +}; + +// The test runner +int test_head() { + int pass_count = 0; + int fail_count = 0; + + for (TestEntry *entry = test_list; entry->function != NULL; entry++) { + if (!entry->function()) { + printf("Failed: %s\n", entry->name); + fail_count++; + } else { + pass_count++; + } + } + + printf("Tests passed: %d\n", pass_count); + printf("Tests failed: %d\n", fail_count); + return (fail_count == 0) ? 0 : 1; +} + +// Main function +int main(int argc, char **argv) { + return test_head(); +} + +//------------------------------------------------------------------------------ +// Test Implementations +//------------------------------------------------------------------------------ + +bool test_copy() { + N_32 a = { .d0 = 42 }; + N_32 b; + N_32·copy(&b, &a); + return b.d0 == 42; +} + +bool test_bitwise_operations() { + N_32 a = { .d0 = 0b101010 }; + N_32 b = { .d0 = 0b010101 }; + N_32 result; + + N_32·bit_and(&result, &a, &b); + if (result.d0 != 0b000000) return false; + + N_32·bit_or(&result, &a, &b); + if (result.d0 != 0b111111) return false; + + N_32·bit_complement(&result, &a); + if (result.d0 != ~0b101010) return false; + + return true; +} + +bool test_comparisons() { + N_32 a = { .d0 = 42 }; + N_32 b = { .d0 = 42 }; + N_32 c = { .d0 = 24 }; + + if (!N_32·eq(&a, &b)) return false; + if (N_32·eq(&a, &c)) return false; + if (!N_32·lt(&c, &a)) return false; + if (!N_32·gt(&a, &c)) return false; + + return true; +} + +bool test_arithmetic() { + N_32 a = { .d0 = 20 }; + N_32 b = { .d0 = 22 }; + N_32 result; + + if (N_32·add(&result, &a, &b) != N_32·Status·ok) return false; + if (result.d0 != 42) return false; + + if (N_32·subtract(&result, &b, &a) != N_32·Status·ok) return false; + if (result.d0 != 2) return false; + + return true; +} + +bool test_shifts() { + N_32 value = { .d0 = 1 }; + N_32 spill; + + if (N_32·shift_left(1, &spill, &value, NULL) != N_32·Status·ok) return false; + if (value.d0 != 2) return false; + + if (N_32·shift_right(1, &spill, &value, NULL) != N_32·Status·ok) return false; + if (value.d0 != 1) return false; + + return true; +} diff --git a/developer/deprecated/Natural_32.lib.c b/developer/deprecated/Natural_32.lib.c new file mode 100644 index 0000000..da30e8d --- /dev/null +++ b/developer/deprecated/Natural_32.lib.c @@ -0,0 +1,179 @@ +//---------------------------------------- +// Function Declarations + +void N_32_copy(N_32 *destination, N_32 *source); +void N_32_bit_and(N_32 *result, N_32 *a, N_32 *b); +void N_32_bit_or(N_32 *result, N_32 *a, N_32 *b); +void N_32_bit_complement(N_32 *result, N_32 *a); +N_32_Order N_32_compare(N_32 *a, N_32 *b); +bool N_32_lt(N_32 *a, N_32 *b); +bool N_32_gt(N_32 *a, N_32 *b); +bool N_32_eq(N_32 *a, N_32 *b); +N_32_Status N_32_add(N_32 *sum, N_32 *a, N_32 *b); +N_32_Status N_32_subtract(N_32 *difference, N_32 *a, N_32 *b); +N_32_Status N_32_multiply(N_32 *overflow, N_32 *result, N_32 *a, N_32 *b); +N_32_Status N_32_divide(N_32 *remainder, N_32 *quotient, N_32 *a, N_32 *b); +void N_32_shift_left(Extent shift, N_32 *sink, N_32 *result, N_32 *source); +void N_32_shift_right(Extent shift, N_32 *source, N_32 *result, N_32 *sink); + + +/* + N_32 - a processor native type + + For binary operations: a op b -> c + + To use N_32, first allocate a block of N_32. Do the arithmetic, + if any results need be kept, copy them to another block. Then deallocate + the block. Do not allocate numbers one at a time, or it would be slow. +*/ + +#ifndef IFACE +#define N_32_IMPLEMENTATION +#define IFACE +#endif + +#ifndef N_32_IFACE +#define N_32_IFACE + +#include +#include +#include +#include + +//---------------------------------------- +// Instance Data (Declaration Only) + +typedef uint32_t Extent; +typedef uint32_t Digit; + +typedef struct N_32 N_32; + +extern N_32 *N_32_zero; +extern N_32 *N_32_one; +extern N_32 *N_32_all_one_bit; +extern N_32 *N_32_lsb; +extern N_32 *N_32_msb; + +//---------------------------------------- +// Return Status + +typedef enum { + N_32_Status_ok = 0, + N_32_Status_overflow = 1, + N_32_Status_accumulator_overflow = 2, + N_32_Status_carry = 3, + N_32_Status_borrow = 4, + N_32_Status_undefined_divide_by_zero = 5, + N_32_Status_undefined_modulus_zero = 6 +} N_32_Status; + +typedef enum { + N_32_Order_lt = -1, + N_32_Order_eq = 0, + N_32_Order_gt = 1 +} N_32_Order; + +typedef N_32 *( *N_32_Allocate_MemoryFault )(Extent); + +//---------------------------------------- +// Interface + +typedef struct { + N_32 *( *allocate )(Extent, N_32_Allocate_MemoryFault); + void ( *deallocate )(N_32 *); + void ( *copy )(N_32 *, N_32 *); + void ( *bit_and )(N_32 *, N_32 *, N_32 *); + void ( *bit_or )(N_32 *, N_32 *, N_32 *); + void ( *bit_complement )(N_32 *, N_32 *); + N_32_Order ( *compare )(N_32 *, N_32 *); + bool ( *lt )(N_32 *, N_32 *); + bool ( *gt )(N_32 *, N_32 *); + bool ( *eq )(N_32 *, N_32 *); + N_32_Status ( *add )(N_32 *, N_32 *, N_32 *); + N_32_Status ( *subtract )(N_32 *, N_32 *, N_32 *); + N_32_Status ( *multiply )(N_32 *, N_32 *, N_32 *, N_32 *); + N_32_Status ( *divide )(N_32 *, N_32 *, N_32 *, N_32 *); + void ( *shift_left )(Extent, N_32 *, N_32 *, N_32 *); + void ( *shift_right )(Extent, N_32 *, N_32 *, N_32 *); +} N_32_Interface; + +extern const N_32_Interface N_32_interface; + +#endif + +#ifdef N_32_IMPLEMENTATION + +#ifndef LOCAL + +struct{ + Digit d0; +} N_32; + +N_32 N_32_constant[4] = { + { .d0 = 0 }, + { .d0 = 1 }, + { .d0 = ~(uint32_t)0 }, + { .d0 = 1 << 31 } +}; + +N_32 *N_32_zero = &N_32_constant[0]; +N_32 *N_32_one = &N_32_constant[1]; +N_32 *N_32_all_one_bit = &N_32_constant[2]; +N_32 *N_32_msb = &N_32_constant[3]; +N_32 *N_32_lsb = &N_32_constant[1]; + +#endif + +#ifdef LOCAL + +struct{ + Digit d0; +} N_32; + +Local void N_32_copy(N_32 *destination, N_32 *source) { + *destination = *source; +} + +Local void N_32_bit_and(N_32 *result, N_32 *a, N_32 *b) { + result->d0 = a->d0 & b->d0; +} + +Local void N_32_bit_or(N_32 *result, N_32 *a, N_32 *b) { + result->d0 = a->d0 | b->d0; +} + +Local void N_32_bit_complement(N_32 *result, N_32 *a) { + result->d0 = ~a->d0; +} + +Local N_32_Order N_32_compare(N_32 *a, N_32 *b) { + if (a->d0 < b->d0) return N_32_Order_lt; + if (a->d0 > b->d0) return N_32_Order_gt; + return N_32_Order_eq; +} + +Local void N_32_shift_left(Extent shift, N_32 *sink, N_32 *result, N_32 *source) { + *sink = *source; + result->d0 = source->d0 << shift; + sink->d0 = source->d0 >> (32 - shift); +} + +Local void N_32_shift_right(Extent shift, N_32 *source, N_32 *result, N_32 *sink) { + *sink = *source; + result->d0 = source->d0 >> shift; + sink->d0 = source->d0 << (32 - shift); +} + +Local const N_32_Interface N_32_interface = { + .copy = N_32_copy, + .bit_and = N_32_bit_and, + .bit_or = N_32_bit_or, + .bit_complement = N_32_bit_complement, + .compare = N_32_compare, + .shift_left = N_32_shift_left, + .shift_right = N_32_shift_right +}; + +#endif + +#endif diff --git a/developer/deprecated/Natural_32_0.lib.c b/developer/deprecated/Natural_32_0.lib.c new file mode 100644 index 0000000..335c402 --- /dev/null +++ b/developer/deprecated/Natural_32_0.lib.c @@ -0,0 +1,278 @@ +/* + N_32 - a processor native type + + For binary operations: a op b -> c + + To use N_32, first allocate a block of N_32. Do the arithmetic, + if any results need be kept, copy them to another block. Then deallocate + the block. Do not allocate numbers one at a time, or it would be slow. + +*/ + +#ifndef IFACE +#define N_32·IMPLEMENTATION +#define IFACE +#endif + +#ifndef N_32·IFACE +#define N_32·IFACE + + //---------------------------------------- + // The instance data + // no way to avoid adding this definition to the interface due to the use of inline functions + + typedef uint32_t Extent; + typedef uint32_t Digit;; + + struct N_32 { + Digit d0; + }; + + const N_32 N_32·zero; + const N_32 N_32·one; + const N_32 N_32·all_ones; + + + //---------------------------------------- + // error status return values, and error handlers + // + + typedef enum { + N_32·Status·ok = 0 + ,N_32·Status·overflow = 1 + ,N_32·Status·accumulator_overflow = 2 + ,N_32·Status·carry = 3 + ,N_32·Status·borrow = 4 + ,N_32·Status·undefined_divide_by_zero = 5 + ,N_32·Status·undefined_modulus_zero = 6 + } N_32·Status; + + typedef enum { + N_32·Order·lt = -1 // Less Than + ,N_32·Order·eq = 0 // Equal + ,N_32·Order·gt = 1 // Greater Than + } N_32·Order; + + typedef N_32 *( *N_32·Allocate·MemoryFault )(Extent); + + //---------------------------------------- + // inline interface + // + + // copy, convenience copy + + inline void N_32·copy(N_32 *destination ,N_32 *source){ + *destination = *source; + } + + inline void N_32·set_to_zero(N_32 *instance){ + instance->d0 = 0; + } + + inline void N_32·set_to_one(N_32 *instance){ + instance->d0 = 1; + } + + // bit operations + + inline void N_32·and(N_32 *result ,N_32 *a ,N_32 *b){ + result->d0 = a->d0 & b->d0; + } + + inline void N_32·or(N_32 *result ,N_32 *a ,N_32 *b){ + result->d0 = a->d0 | b->d0; + } + + inline void N_32·complement(N_32 *result ,N_32 *a){ + result->d0 = ~a->d0; + } + + inline void N_32·twos_complement(N_32 *result ,N_32 *a){ + result->d0 = ~a->d0 + 1; + } + + inline bool N_32·lsb_is_set(N_32 *a){ + return a->d0 & 0x0000001; + } + + inline bool N_32·msb_is_set(N_32 *a){ + return a->d0 & 0x8000000; + } + + // for low precision Natural, and large number of summands for accumulate/add/sub, overflow could overflow and thus this op would fail + inline N_32·Status N_32·accumulate(N_32 *overflow ,N_32 *accumulator ,...){ + va_list args; + va_start(args ,accumulator); + + uint64_t *sum = &accumulator->d0; + uint64_t *carry = &overflow->d0; + N_32 *current; + + while( (current = va_arg(args ,N_32 *)) ){ + *sum += current->d0; + if(*sum < current->d0){ // Overflow into carry + (*carry)++; + if(*carry == 0){ + va_end(args); + return N_32·Status·accumulator_overflow; + } + } + } + va_end(args); + + if(*carry == 0) return N_32·Status·ok; + return N_32·Status·OVERFLOW; + } + + inline N_32·Order N_32·compare(N_32 *a ,N_32 *b){ + if(a->d0 < b->d0) return N_32·order·lt; + if(a->d0 > b->d0) return N_32·order·gt; + return N_32·order·eq; + } + + inline bool N_32·lt(N_32 *a ,N_32 *b){ + return a->d0 < b->d0; + } + + inline bool N_32·gt(N_32 *a ,N_32 *b){ + return a->d0 > b->d0; + } + + inline bool N_32·eq(N_32 *a ,N_32 *b){ + return a->d0 == b->d0; + } + + // arithmetic operations + + inline N_32·Status N_32·add(N_32 *sum ,N_32 *a ,N_32 *b){ + uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; + sum->d0 = (uint32_t)result; + return (result >> 32) ? N_32·Status·carry : N_32·Status·ok; + } + + inline N_32·Status N_32·next(N_32 *overflow ,N_32 *result ,N_32 *a){ + uint64_t sum = (uint64_t)a->d0 + (uint64_t)1; + result->d0 = (uint32_t)sum; + overflow->d0 = (uint32_t)(sum >> 32); + + if(overflow->d0 == 0) return N_32·status·ok; + return N_32·status·overflow; + } + + inline N_32·Status N_32·subtract(N_32 *difference ,N_32 *a ,N_32 *b){ + uint64_t diff = (uint64_t)a->d0 - (uint64_t)b->d0; + difference->d0 = (uint32_t)diff; + return (diff > a->d0) ? N_32·Status·borrow : N_32·Status·ok; + } + + inline N_32·Status N_32·multiply(N_32 *overflow ,N_32 *result ,N_32 *a ,N_32 *b){ + uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; + result->d0 = (uint32_t)product; + overflow->d0 = (uint32_t)(product >> 32); + + if(overflow->d0 == 0) return N_32·status·ok; + return N_32·status·overflow; + } + + inline N_32·Status N_32·divide(N_32 *remainder ,N_32 *quotient ,N_32 *a ,N_32 *b){ + if(b->d0 == 0) return N_32·Status·undefined_divide_by_zero; + + quotient->d0 = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient->d0 * b->d0); + + return N_32·Status·ok; + } + + inline N_32·Status N_32·modulus(N_32 *remainder ,N_32 *a ,N_32 *b){ + if(b->d0 == 0) return N_32·Status·undefined_modulus_zero; + uint32_t quotient = a->d0 / b->d0; + remainder->d0 = a->d0 - (quotient * b->d0); + return N_32·Status·ok; + } + + // shift + inline void N_32·shift_left(Extent shift ,N_32 *sink ,N_32 *result ,N_32 *source){ + *sink = *source; + result->d0 = source->d0 << shift; + sink->d0 = source->d0 >> (32 - shift); + } + + inline void N_32·shift_right(Extent shift ,N_32 *source ,N_32 *result ,N_32 *sink){ + *sink = *source; + result->d0 = source->d0 >> shift; + sink->d0 = source->d0 << (32 - shift); + } + + inline void N_32·arithmetic_shift_right(Extent shift ,N_32 *result ,N_32 *sink){ + N_32 source; + N_32 source = msb_is_set(result) ? N_32·all_ones : N_32·zero; + N_32·shift_right(shift ,&source ,result ,sink); + } + + //---------------------------------------- + // compiled interface + + typedef struct { + N_32·Allocate allocate; + N_32·Zero zero; + N_32·One one; + N_32·Deallocate deallocate; + } N_32·Interface; + + extern const N_32·Interface N_32·interface; + + +#endif + +#ifdef N_32·IMPLEMENTATION + + #include + #include + + const N_32 N_32·zero = { .d0 = 0 }; + const N_32 N_32·one = { .d0 = 1 }; + const N_32 N_32·all_ones = { .d0 = ~(uint32_t)0 }; + + // the allocate an array of N_32 + N_32 *N_32·allocate( Extent extent ,N_32 *(*memory_fault)(Extent) ){ + N_32 *instance = malloc((extent + 1) * sizeof(N_32) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + N_32 *N_32·alloc_zero( Extent extent ,N_32 *(*memory_fault)(Extent) ){ + N_32 *instance = calloc( extent + 1 ,sizeof(N_32) ); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + return instance; + } + + // initialize all with x + N_32 *N_32·alloc_x(Extent extent ,N_32 *(*memory_fault)(Extent) ,N_32 *x){ + N_32 *instance = malloc((extent + 1) * sizeof(N_32)); + if(!instance){ + return memory_fault ? memory_fault(extent) : NULL; + } + N_32 *pt = instance; + while( pt <= instance + extent ){ + *pt = *x; + pt++; + } + return instance; + } + + const N_32·Interface N_32·interface = { + .allocate = N_32·allocate + ,.allocate_zero = N_32·alloc_zero + ,.allocate_all_x = N_32·alloc_x + ,.deallocate = N_32·deallocate + }; + + void N_32·deallocate(N_32 *unencumbered){ + free(unencumbered); + } + +#endif diff --git a/developer/deprecated/adding_new_N_types.org b/developer/deprecated/adding_new_N_types.org new file mode 100644 index 0000000..efb018b --- /dev/null +++ b/developer/deprecated/adding_new_N_types.org @@ -0,0 +1,23 @@ +#+TITLE: Adding new N types +#+AUTHOR: Thomas + +* Project Name + +N == Natural Number, aka 'unsigned int'. + +* Pencil directories / pencil suffix. + +The files in the pencil directory, e.g. cc🖉, are 'authored files'. The program 'rm_na' will not delete them. Use 'rm_na" in scripts. + +* Parameterized types + +The templated N type allows a user to specify a digit type, and number of digits. To generate a new multiple digit type, go into the `Python🖉/` directory, add a new write section to the `fill_template` file, and fill in the digit type and number of digits the new type will have. Run `fill_template` and the synthesized file will be written to the `cc/` directory. + + +* Custom types + +Some processors will have processor native types that the templating scheme does not take advantage of. + +Put custom `N_.lib.cc` files in the `cc🖉/` directory. Or new templates in the `Python🖉` directory. Be sure the file name is distinct from existing types, because the testing setup installs all the files. + + diff --git a/developer/deprecated/copy.lib.c b/developer/deprecated/copy.lib.c new file mode 100644 index 0000000..58ed27e --- /dev/null +++ b/developer/deprecated/copy.lib.c @@ -0,0 +1,117 @@ +/* +We pay attention to word alignment on the read side. Writes are probably +buffered so alignment is not as big of a performance issue. +*/ +void *Copy·region(void *read0 ,void *read1 ,void *write0){ + + uint8_t *r = (uint8_t *)read0; + uint8_t *r1 = (uint8_t *)read1; + uint8_t *w = (uint8_t *)write0; + + //---------- + // The potentially unaligned initial part (align read pointer). + if( (uintptr_t)r & 0x7 ){ + + // At this point r is known to be unaligned. + // ORing in `0x7` adds at most six + uint8_t *r01 = (uint8_t *)((uintptr_t)r | 0x7); + + // then the read interval is very small + if(r01 >= r1){ + while(r < r1){ + *w++ = *r++; + } + return w; + } + + // Copy up to alignment boundary + do{ + *w++ = *r++; + }while(r <= r01); + } + // r is now aligned, but *r has not yet been copied + + + //---------- + // The bulk copy part (w is still possibly unaligned, but r is aligned) + uint8_t *r10 = (uint8_t *)((uintptr_t)r1 & ~(uintptr_t)0x7); + + while(r < r10){ + *(uint64_t *)w = *(uint64_t *)r; + w += 8; + r += 8; + } + + // if r1 was aligned then r10 == r1 and we are done + if(r == r1) w; + + //---------- + // The ragged tail, up to 7 bytes + do{ + *w++ = *r++; + }while(r < r1); + + return w; + +} + +void *Copy·reverse_byte_order(void *read0 ,void *read1 ,void *write0){ + + uint8_t *r = (uint8_t *)read1; // Start from the last byte + uint8_t *r0 = (uint8_t *)read0; + uint8_t *w = (uint8_t *)write0; + + // For r to be aligned, means that it points to a 64 bit word, and the byte it + // points was the last copied coming out of the prior loop. This is due to going in + // leftward through the array, and the part to the rightward already having + // been done. + + //---------- + // The potentially unaligned initial part (align read pointer). + if( (uintptr_t)r & 0x7 != 0){ + + // At this point r is known to be unaligned. + // ANDing with `~0x7` moves it **downward** to the nearest lower alignment. + uint8_t *r10 = (uint8_t *)((uintptr_t)r & ~(uintptr_t)0x7); + + // If the read interval is very small + if(r10 < r0){ + while(r > r0){ + *w++ = *--r; + } + return w; + } + + // Copy down to alignment boundary + do{ + *w++ = *--r; + }while(r > r10); + } + // r is now aligned, and *r has been copied + + //---------- + // The bulk copy part + + // the first aligned address greater than or equal to r0 + uint8_t *r01 = (uint8_t *)( ((uintptr_t)r0 + (uintptr_t)0x7) & ~(uintptr_t)0x7); + + // as both r and r01 are aligned, r == r01 upon exit of this loop + while(r > r01){ + r -= 8; + *(uint64_t *)w = __builtin_bswap64(*(uint64_t *)r); + w += 8; + } + + // If r0 was aligned then r01 == r0 and we are done + if(r < r0) return w; + + //---------- + // The ragged tail, up to 7 bytes + do{ + *w++ = *--r; + }while(r >= r0); + + return w; +} + + diff --git a/developer/deprecated/scatch.c b/developer/deprecated/scatch.c new file mode 100644 index 0000000..abf9619 --- /dev/null +++ b/developer/deprecated/scatch.c @@ -0,0 +1,580 @@ + // some aliases to make things a little easier to read + #undef TM + #define TM ·(TM ,TM·CVT) + #undef EXTENT_T + #define EXTENT_T ·(extent_t ,TM·CVT) + + //---------------------------------------- + // TM Array implementation, not TM·CVT differentiated + + // some aliases to make things a little easier to read + #undef TM + #define TM ·(TM ,TM·CVT) + #undef EXTENT_T + #define EXTENT_T ·(extent_t ,TM·CVT) + #undef TM·ARRAY + #define TM·ARRAY ·(TM ,ARRAY) + + typedef struct ·(TM·ARRAY ,Tableau){ + TM·CVT *hd; + TM·CVT position[]; + EXTENT_T extent; + } ·(TM·ARRAY ,Tableau); + + Local TM·Tape·Topo ·(TM·ARRAY ,Tape·topo)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + if(t->extent == 0) return TM·Tape·Topo·singleton; + return TM·Tape·Topo·segment; + } + Local bool ·(TM·ARRAY ,Tape·bounded)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return ·(TM·ARRAY ,Tape·topo)(tm) & TM·Tape·Topo·bounded; + } + Local EXTENT_T ·(TM·ARRAY ,Tape·extent)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return t->extent; + } + + Local TM·Head·Status ·(TM·ARRAY ,Head·status)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + if(!t->hd) return TM·Head·Status·dismounted; + if(t->hd == tm->position) return TM·Head·Status·leftmost; + + TM·CVT *rightmost_pt = t->position + t->extent; + if(t->hd == rightmost_pt) TM·Head·Status·rightmost; + if(t->hd < tm->position || tm->hd > rightmost_pt) + return TM·Head·Status·out_of_area; + + return TM·Head·Status·interim; + } + Local bool ·(TM·ARRAY ,Head·dismounted)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·dismounted; + } + Local bool ·(TM·ARRAY ,Head·on_tape)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·on_tape; + } + Local bool ·(TM·ARRAY ,Head·on_leftmost)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·leftmost; + } + Local bool ·(TM·ARRAY ,Head·on_rightmost)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·rightmost; + } + + // does nothing if the hd is already mounted + Local void ·(TM·ARRAY ,mount)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + if( !t->hd ) t->hd = t->position; + } + + Local void dismount ·(TM·ARRAY ,dismount)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + t->hd = NULL; + } + + // does nothing if the hd is not mounted + Local void ·(TM·ARRAY ,step)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + t->hd++; + } + + Local void ·(TM·ARRAY ,step_left)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + t->hd--; + } + + Local void ·(TM·ARRAY ,rewind)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + ·(TM·ARRAY ,Head·dismounted)(tm) return; + t->hd = t->position; + } + + Local TM·CVT ·(TM·ARRAY ,read)(TM tm){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + return *t->hd; + } + + Local void ·(TM·ARRAY ,write)(TM tm ,TM·CVT *remote_pt){ + ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; + *remote_pt = *t->hd; + } + + Local TM·Binding TM·fg = { + + .Tape·topo = ·(TM·ARRAY ,Tape·topo) + ,.Tape·bounded = ·(TM·ARRAY ,Tape·bounded) + ,.Tape·extent = ·(TM·ARRAY ,Tape·extent) + + ,.Head·status = ·(TM·ARRAY ,Head·status) + ,.Head·dismounted = ·(TM·ARRAY ,Head·dismounted) + ,.Head·on_tape = ·(TM·ARRAY ,Head·on_tape) + ,.Head·on_leftmost = ·(TM·ARRAY ,Head·on_leftmost) + ,.Head·on_rightmost = ·(TM·ARRAY ,Head·on_rightmost) + + ,.mount = ·(TM·ARRAY ,mount) + ,.dismount = ·(TM·ARRAY ,dismount) + + ,.step = ·(TM·ARRAY ,step) + ,.step_right = ·(TM·ARRAY ,step) + ,.step_left = ·(TM·ARRAY ,step_left) + ,.rewind = ·(TM·ARRAY ,rewind) + + ,.read = ·(TM·ARRAY ,read) + ,.write = ·(TM·ARRAY ,write) + + }; + + + + + + + + +................................................................................ + + //----------------------------------- + // generic call wrappers + + Local TM·Tape·Topo TM·Tape·topo(TM *tm){ + return tm->fg.Tape·topo(tm); + } + Local TM·Tape·Topo TM·Tape·bounded(TM *tm){ + return TM·tape_top(tm) & TM·Tape·Topo·bounded); + } + + Local TM·Head·Status TM·head_status(TM *tm){ + return tm->fg.status(tm ,result); + } + Local TM·Head·Status TM·head_on_tape(TM *tm){ + return TM·status(tm) & TM·Head·Status·on_tape; + } + + // does nothing if the head is already mounted + Local Core·Status TM·mount(TM *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk, 1, tm, TM·Msg·tm); + Core·Guard·if_return(chk); + #endif + if( !TM·head_on_tape(tm) ) return Core·Status·on_track; + return tm->fg.mount(tm); + } + + // does nothing if the head is already dismounted + Local Core·Status TM·dismount(TM *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk, 1, tm, TM·Msg·tm); + Core·Guard·if_return(chk); + #endif + if( TM·head_status(TM *tm) & TM·Head·Status·dismounted) ) return Core·Status·on_track; + return tm->fg.dismount(tm); + } + + #define TM·macro·bool_tm(name) + Local bool name(TM *tm){ \ + #ifdef TM·DEBUG \ + Core·Guard·init_count(chk); \ + Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); \ + Core·Guard·assert(chk); \ + #endif \ + return tm->fg.name(tm); \ + } + + Local bool TM·macro·bool_tm(on_leftmost); + Local bool TM·macro·bool_tm(on_rightmost); + Local bool TM·macro·bool_tm(step); + Local bool TM·macro·bool_tm(step_left); + Local bool TM·macro·bool_tm(rewind); + + //---------------------------------------- + // Initialization for TM·fg + + + #endif // ifndef TM·CVT + + //----------------------------------- + // TM·CVT dependent functions + + #ifdef TM·CVT + + Local ·(extent_t ,TM·CVT) ·(TM ,TM·CVT)·extent(TM *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,TM·Tape·bounded(tm) ,"Tape is not bounded."); + Core·Guard·assert(chk); + #endif + return tm->fg.extent(tm); + } + + Local TM·CVT TM·read(TM *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); + Core·Guard·assert(chk); + #endif + return tm->fg.read(tm); + } + + Local void TM·write(TM *tm ,TM·CVT *write_pt){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); + Core·Guard·fg.check( &chk ,1 ,write_pt ,"Given NULL write_pt"); + Core·Guard·assert(chk); + #endif + return tm->fg.write(tm ,write_pt); + } + + Local ·(TM ,TM·CVT)·Binding ·(TM ,TM·CVT)·fg = { + .parent = TM·fg + ,.extent = ·(TM ,TM·CVT)·extent + ,.read = ·(TM ,TM·CVT)·read + ,.write = ·(TM ,TM·CVT)·write + }; + + #endif // ifdef TM·CVT + + + + #endif // ifdef TM·CVT + +#endif // LOCAL + +//-------------------------------------------------------------------------------- +// Library - compiled into a lib.a file by the current make +// TM currently has no library components +//-------------------------------------------------------------------------------- +#ifdef LIBRARY +#endif + +//-------------------------------------------------------------------------------- +// undef the template parameters +//-------------------------------------------------------------------------------- +#undef TM·CVT + + //---------------------------------------- + // TM·Array implementation + //---------------------------------------- + + /* + TM·Array is bound to a tape with head on the tape via mount_pe or mount_pp. + + Once a tape is bound, it remains so, though the head can be dismounted + and remounted. + + C lacks an allocation-bound initialization feature, so the library user is responsible + to make sure a TM·Array has been initialized before use. + + The TM·Array has no locking facility, so it is not possible to know if it is in use. + + Re-initializing a TM·Array while in use can lead to unspecified badness. Use `rewind` instead. + */ + + //---------------------------------------- + // TM·Array implementation + //---------------------------------------- + + #ifndef TM·CVT + + //----------------------------------- + // common error messages + + const char *TM·Array·Msg·tm="given NULL tm"; + const char *TM·Array·Msg·flag="given NULL flag pointer"; + const char *TM·Array·Msg·result="given NULL result pointer"; + const char *TM·Array·Msg·status="bad head status"; + + + #endif // #ifndef TM·CVT + + #ifdef TM·CVT + + + + + + // check the Tape·topo to make sure tape has extent before calling this + // `extent·TM·CVT` returns the index to the rightmost cell in the array. + Local ·(extent_t ,TM·CVT) ·(TM·Array ,TM·CVT)·extent(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Tape·Topo Tape·topo = Core·Tape·Topo·mu; + Core·Status status = ·(TM·Array ,TM·CVT)·Tape·topo(tm ,&Tape·topo); + bool good_Tape·topo = + (status == Core·Status·on_track) && (Tape·topo & Core·Tape·Topo·finite_nz) + ; + Core·Guard·fg.check(&chk ,1 ,good_Tape·topo ,"Tape does not have an extent."); + Core·Guard·assert(chk); + #endif + + *result = tm->extent; + return Core·Status·on_track; + } + + //----------------------------------- + // TM·Array.area implementation + + Local Core·Status ·(TM·Array ,TM·CVT)·mount_pe( + ·(TM·Array ,TM·CVT) *tm ,TM·CVT *position ,·(extent_t ,TM·CVT) extent + ){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); + Core·Guard·fg.check(&chk ,1 ,position ,"Given NULL position."); + Core·Guard·if_return(chk); + #endif + tm->position = position; + tm->extent = extent; + tm->hd = position; // mount the head on the origin cell + return Core·Status·on_track; + } + + // If size of TM·CVT is not a power of two this can perform a divide + Local Core·Status ·(TM·Array ,TM·CVT)·mount_pp( + ·(TM·Array ,TM·CVT) *tm ,TM·CVT *pos_leftmost ,TM·CVT *pos_rightmost + ){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,pos_leftmost ,"Null pos_leftmost."); + Core·Guard·fg.check(&chk ,1 ,pos_rightmost ,"Null pos_rightmost."); + if(pos_leftmost && pos_rightmost){ + Core·Guard·fg.check(&chk ,1 ,pos_rightmost >= pos_leftmost + ,"pos_rightmost < pos_leftmost" + ); + } + Core·Guard·if_return(chk); + #endif + + ·(extent_t ,TM·CVT) extent = pos_rightmost - pos_leftmost); + return ·(TM·Array ,TM·CVT)·mount_pe(tm ,pos_leftmost ,extent); + } + + //----------------------------------- + // base Tape Machine operations + + Local Core·Status ·(TM·Array ,TM·CVT)·mount(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); + if(tm) Core·Guard·fg.check(&chk ,1 ,tm->position ,TM·Array·Msg·position); + Core·Guard·if_return(chk); + #endif + + // mounting an already mounted head does nothing ,perhaps you meant `rewind`? + if(!tm->hd) tm->hd = tm->position; + return Core·Status·on_track; + } + + Local Core·Status ·(TM·Array ,TM·CVT)·dismount(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); + Core·Guard·if_return(chk); + #endif + + tm->hd = NULL; + return Core·Status·on_track; + } + + Local TM·Head·Status ·(TM·Array ,TM·CVT)·head_status(TM *tm){ + if(!tm || !tm->position) return TM·Head·Status·mu; + if(!tm->hd) return TM·Head·Status·dismounted; + if(tm->hd == tm->position) return TM·Head·Status·leftmost; + + TM·CVT *rightmost_pt = tm->position + tm->extent; + if(tm->hd == rightmost_pt) TM·Head·Status·rightmost; + if(tm->hd < tm->position || tm->hd > rightmost_pt) + return TM·Head·Status·out_of_area; + + return TM·Head·Status·interim; + } + + bool ·(TM·Array ,TM·CVT)·can_read(·(TM·Array ,TM·CVT) *tm){ + return tm && tm->position && tm->hd; + } + + // can_read was true + bool ·(TM·Array ,TM·CVT)·on_origin(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + return tm->hd == tm->position; + } + + // can_read was true + bool ·(TM·Array ,TM·CVT)·on_rightmost(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + return tm->hd == tm->position; + } + + void ·(TM·Array ,TM·CVT)·step(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + tm->hd++; + } + + void ·(TM·Array ,TM·CVT)·step_left(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + tm->hd--; + } + + void ·(TM·Array ,TM·CVT)·rewind(·(TM·Array ,TM·CVT) *tm){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + tm->hd = tm->position; + } + + // tm_can_read must be true for both machines. + void ·(TM·Array ,TM·CVT)·copy_datum(·(TM·Array ,TM·CVT) *tm_read ,·(TM·Array ,TM·CVT) *tm_write){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm_read ,flag) == Control·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"tm_read head off track"); + s = ·(TM·Array ,TM·CVT)·head_on_format(tm_write ,flag) == Control·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"tm_write head off track"); + Core·Guard·assert(chk); + #endif + + *(tm_write->hd) = *(tm_read->hd); + return Core·Status·on_track; + } + + void ·(TM·Array ,TM·CVT)·read(·(TM·Array ,TM·CVT) *tm ,TM·CVT *read_pt){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + + *read_pt = *(tm->hd); + } + + + // step_right is a synonym for step + + + //---------------------------------------- + // Initialization for ·(TM·Array ,TM·CVT)·fg + + Local ·(TM·Array ,TM·CVT)·Binding ·(TM·Array ,TM·CVT)·fg = { + .tape = { + .Tape·topo = ·(TM·Array ,TM·CVT)·Tape·topo + .extent = ·(TM·Array ,TM·CVT)·extent + } + + ,.area = { + .mount_pe = ·(TM·Array ,TM·CVT)·mount_pe + ,.mount_pp = ·(TM·Array ,TM·CVT)·mount_pp + } + + ,.mount = ·(TM·Array ,TM·CVT)·mount + ,.dismount = ·(TM·Array ,TM·CVT)·dismount + + ,.status = ·(TM·Array ,TM·CVT)·status + ,.head_on_format = ·(TM·Array ,TM·CVT)·head_on_format + + ,.can_read = ·(TM·Array ,TM·CVT)·can_read + ,.on_origin = ·(TM·Array ,TM·CVT)·on_origin + ,.on_rightmost = ·(TM·Array ,TM·CVT)·on_rightmost + + ,.step = ·(TM·Array ,TM·CVT)·step + ,.step_left = ·(TM·Array ,TM·CVT)·step_left + ,.step_right = ·(TM·Array ,TM·CVT)·step_right // Synonym for step + ,.rewind = ·(TM·Array ,TM·CVT)·rewind + + ,.copy_datum = ·(TM·Array ,TM·CVT)·copy_datum + ,.read = ·(TM·Array ,TM·CVT)·read + ,.write = ·(TM·Array ,TM·CVT)·write + + }; + + +//-------------------------------------------------------------------------------- + +// scrat + + +void ·(TM·Array ,TM·CVT)·write(·(TM·Array ,TM·CVT) *tm ,TM·CVT *write_pt){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + bool flag = true ,s; + s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; + Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); + Core·Guard·assert(chk); + #endif + + *(tm->hd) = *write_pt; +} + + //----------------------------------- + // TM struct initializers + + Local Core·Status TM·mount_pe( + TM *tm ,TM·CVT *position ,·(extent_t ,TM·CVT) extent + ){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,tm ,TM·Msg·tm); + Core·Guard·fg.check(&chk ,1 ,position ,"Given NULL position."); + Core·Guard·if_return(chk); + #endif + tm->position = position; + tm->extent = extent; + tm->hd = position; // mount the head on the origin cell + return Core·Status·on_track; + } + + // If size of TM·CVT is not a power of two this can perform a divide + Local Core·Status TM·mount_pp( + TM *tm ,TM·CVT *pos_leftmost ,TM·CVT *pos_rightmost + ){ + #ifdef TM·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk ,1 ,pos_leftmost ,"Null pos_leftmost."); + Core·Guard·fg.check(&chk ,1 ,pos_rightmost ,"Null pos_rightmost."); + if(pos_leftmost && pos_rightmost){ + Core·Guard·fg.check(&chk ,1 ,pos_rightmost >= pos_leftmost + ,"pos_rightmost < pos_leftmost" + ); + } + Core·Guard·if_return(chk); + #endif + + ·(extent_t ,TM·CVT) extent = pos_rightmost - pos_leftmost); + return TM·mount_pe(tm ,pos_leftmost ,extent); + } + diff --git a/developer/deprecated/test_Natural_32_0.cli.c b/developer/deprecated/test_Natural_32_0.cli.c new file mode 100644 index 0000000..2c344e7 --- /dev/null +++ b/developer/deprecated/test_Natural_32_0.cli.c @@ -0,0 +1,88 @@ + +#include "environment.h" +#include +#include +#include + +#define IFACE +#include "Natural_32.lib.c" + +#define TEST_COUNT 10 // Adjust as needed + +jmp_buf test_env; +const char *current_test = NULL; + +void signal_handler(int sig){ + printf("Failed due to Exception: %s (Signal %d)\n", current_test, sig); + longjmp(test_env, 1); +} + +int main(void){ + bool test_results[TEST_COUNT] = {false}; + const char *test_names[TEST_COUNT] = { + "Addition", + "Subtraction", + "Multiplication", + "Division", + "Modulus", + "Shift Left", + "Shift Right", + "Comparison", + "Complement", + "Two's Complement" + }; + + int pass_count = 0, fail_count = 0; + bool *test_ptr = test_results; + const char **name_ptr = test_names; + + // Install signal handler + signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGABRT, signal_handler); + + Natural_32 a, b, result, overflow; + Natural_32·set_to_zero(&a); + Natural_32·set_to_one(&b); + + // Macro to run tests with proper failure messaging + #define RUN_TEST(expr) \ + current_test = *name_ptr; \ + if(setjmp(test_env) == 0){ \ + if(expr){ \ + *test_ptr++ = true; \ + pass_count++; \ + } else { \ + printf("Failed due to Bad Return Value: %s\n", *name_ptr); \ + *test_ptr++ = false; \ + fail_count++; \ + } \ + } else { \ + *test_ptr++ = false; \ + fail_count++; \ + } \ + name_ptr++; + + RUN_TEST(Natural_32·add(&result, &a, &b) == Natural_32·Status·ok && result.d0 == 1); + RUN_TEST(Natural_32·subtract(&result, &b, &a) == Natural_32·Status·ok && result.d0 == 1); + RUN_TEST(Natural_32·multiply(&overflow, &result, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0); + RUN_TEST(Natural_32·divide(&result, &overflow, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0); + RUN_TEST(Natural_32·modulus(&result, &b, &b) == Natural_32·Status·ok && result.d0 == 0); + + Natural_32·shift_left(1, &overflow, &result, &b); + RUN_TEST(result.d0 == 2 && overflow.d0 == 0); + + Natural_32·shift_right(1, &b, &result, &overflow); + RUN_TEST(result.d0 == 0 && overflow.d0 == 1); + + RUN_TEST(Natural_32·compare(&a, &b) == Natural_32·Order·lt); + + Natural_32·complement(&result, &a); + RUN_TEST(result.d0 == ~0); + + Natural_32·twos_complement(&result, &b); + RUN_TEST(result.d0 == (uint32_t)(-1)); + + printf("Pass: %d, Fail: %d\n", pass_count, fail_count); + return fail_count > 0 ? 1 : 0; +} diff --git "a/developer/deprecated\360\237\226\211/.githolder" "b/developer/deprecated\360\237\226\211/.githolder" deleted file mode 100644 index e69de29..0000000 diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/N16.lib.c" "b/developer/deprecated\360\237\226\211/2025-03-29/N16.lib.c" deleted file mode 100644 index 561b43d..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/N16.lib.c" +++ /dev/null @@ -1,433 +0,0 @@ -/* - N16 - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define N16·DEBUG - -#ifndef FACE -#define N16·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N16·FACE -#define N16·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint16_t Extent; - typedef uint16_t Digit; - - typedef struct N16·T N16·T; - - extern N16·T *N16·zero; - extern N16·T *N16·one; - extern N16·T *N16·all_one_bit; - extern N16·T *N16·lsb; - extern N16·T *N16·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum{ - N16·Status·ok = 0 - ,N16·Status·overflow = 1 - ,N16·Status·accumulator1_overflow = 2 - ,N16·Status·carry = 3 - ,N16·Status·borrow = 4 - ,N16·Status·undefined_divide_by_zero = 5 - ,N16·Status·undefined_modulus_zero = 6 - ,N16·Status·gt_max_shift_count = 7 - ,N16·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value - ,N16·Status·one_word_product = 9 - ,N16·Status·two_word_product = 10 - } N16·Status; - - typedef enum{ - N16·Order_lt = -1 - ,N16·Order_eq = 0 - ,N16·Order_gt = 1 - } N16·Order; - - typedef N16·T *( *N16·Allocate_MemoryFault )(Extent); - - //---------------------------------------- - // Interface - - typedef struct{ - - N16·T *(*allocate_array_zero)(Extent, N16·Allocate_MemoryFault); - N16·T *(*allocate_array)(Extent, N16·Allocate_MemoryFault); - void (*deallocate)(N16·T*); - - void (*copy)(N16·T*, N16·T*); - void (*bit_and)(N16·T*, N16·T*, N16·T*); - void (*bit_or)(N16·T*, N16·T*, N16·T*); - void (*bit_complement)(N16·T*, N16·T*); - void (*bit_twos_complement)(N16·T*, N16·T*); - N16·Order (*compare)(N16·T*, N16·T*); - bool (*lt)(N16·T*, N16·T*); - bool (*gt)(N16·T*, N16·T*); - bool (*eq)(N16·T*, N16·T*); - bool (*eq_zero)(N16·T*); - N16·Status (*accumulate)(N16·T *accumulator1 ,N16·T *accumulator0 ,...); - N16·Status (*add)(N16·T*, N16·T*, N16·T*); - bool (*increment)(N16·T *a); - N16·Status (*subtract)(N16·T*, N16·T*, N16·T*); - N16·Status (*multiply)(N16·T*, N16·T*, N16·T*, N16·T*); - N16·Status (*divide)(N16·T*, N16·T*, N16·T*, N16·T*); - N16·Status (*modulus)(N16·T*, N16·T*, N16·T*); - N16·Status (*shift_left)(Extent, N16·T*, N16·T*, N16·T*); - N16·Status (*shift_right)(Extent, N16·T*, N16·T*, N16·T*); - N16·Status (*arithmetic_shift_right)(Extent, N16·T*, N16·T*); - - N16·T* (*access)(N16·T*, Extent); - void (*from_uint32)(N16·T *destination ,uint32_t value); - } N16·M; - - Local const N16·M N16·m; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N16·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct N16·T{ - Digit d0; - }; - - N16·T N16·constant[4] = { - {.d0 = 0}, - {.d0 = 1}, - {.d0 = ~(uint16_t)0}, - {.d0 = 1 << 15} - }; - - N16·T *N16·zero = &N16·constant[0]; - N16·T *N16·one = &N16·constant[1]; - N16·T *N16·all_one_bit = &N16·constant[2]; - N16·T *N16·msb = &N16·constant[3]; - N16·T *N16·lsb = &N16·constant[1]; - - // the allocate an array of N16 - N16·T *N16·allocate_array(Extent extent ,N16·Allocate_MemoryFault memory_fault){ - N16·T *instance = malloc((extent + 1) * sizeof(N16·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N16·T *N16·allocate_array_zero(Extent extent ,N16·Allocate_MemoryFault memory_fault){ - N16·T *instance = calloc(extent + 1, sizeof(N16·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void N16·deallocate(N16·T *unencumbered){ - free(unencumbered); - } - - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N16·T{ - Digit d0; - }; - - // temporary variables - Local N16·T N16·t[4]; - - // allocation - - extern N16·T *N16·allocate_array(Extent, N16·Allocate_MemoryFault); - extern N16·T *N16·allocate_array_zero(Extent, N16·Allocate_MemoryFault); - extern void N16·deallocate(N16·T *); - - // so the user can access numbers in an array allocation - Local N16·T* N16·access(N16·T *array ,Extent index){ - return &array[index]; - } - - Local void N16·from_uint32(N16·T *destination ,uint32_t value){ - if(destination == NULL) return; - destination->d0 = (uint16_t)(value & 0xFFFF); - } - - // copy, convenience copy - - Local void N16·copy(N16·T *destination ,N16·T *source){ - if(source == destination) return; - *destination = *source; - } - - Local void N16·set_to_zero(N16·T *instance){ - instance->d0 = 0; - } - - Local void N16·set_to_one(N16·T *instance){ - instance->d0 = 1; - } - - // bit operations - - Local void N16·bit_and(N16·T *result, N16·T *a, N16·T *b){ - result->d0 = a->d0 & b->d0; - } - - Local void N16·bit_or(N16·T *result, N16·T *a, N16·T *b){ - result->d0 = a->d0 | b->d0; - } - - Local void N16·bit_complement(N16·T *result, N16·T *a){ - result->d0 = ~a->d0; - } - - Local void N16·bit_twos_complement(N16·T *result ,N16·T *a){ - result->d0 = (uint16_t)(~a->d0 + 1); - } - - // test functions - - Local N16·Order N16·compare(N16·T *a, N16·T *b){ - if(a->d0 < b->d0) return N16·Order_lt; - if(a->d0 > b->d0) return N16·Order_gt; - return N16·Order_eq; - } - - Local bool N16·lt(N16·T *a ,N16·T *b){ - return a->d0 < b->d0; - } - - Local bool N16·gt(N16·T *a ,N16·T *b){ - return a->d0 > b->d0; - } - - Local bool N16·eq(N16·T *a ,N16·T *b){ - return a->d0 == b->d0; - } - - Local bool N16·eq_zero(N16·T *a){ - return a->d0 == 0; - } - - // arithmetic operations - - Local N16·Status N16·accumulate(N16·T *accumulator1 ,N16·T *accumulator0 ,...){ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - N16·T *current; - - while( (current = va_arg(args ,N16·T*)) ){ - sum += current->d0; - if(sum < current->d0){ - (carry)++; - if(carry == 0){ - va_end(args); - return N16·Status·accumulator1_overflow; - } - } - } - va_end(args); - - accumulator1->d0 = (uint16_t)carry; - return N16·Status·ok; - } - - Local N16·Status N16·add(N16·T *sum ,N16·T *a ,N16·T *b){ - uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; - sum->d0 = (uint16_t)(result & 0xFFFF); - return (result >> 16) ? N16·Status·carry : N16·Status·ok; - } - - Local bool N16·increment(N16·T *a){ - a->d0++; - return (a->d0 == 0); - } - - Local N16·Status N16·subtract(N16·T *difference ,N16·T *a ,N16·T *b){ - uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; - difference->d0 = (uint16_t)(diff & 0xFFFF); - return (diff > a->d0) ? N16·Status·borrow : N16·Status·ok; - } - - Local N16·Status N16·multiply(N16·T *product1 ,N16·T *product0 ,N16·T *a ,N16·T *b){ - uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; - product0->d0 = (uint16_t)(product & 0xFFFF); - product1->d0 = (uint16_t)((product >> 16) & 0xFFFF); - - if(product1->d0 == 0) return N16·Status·one_word_product; - return N16·Status·two_word_product; - } - - Local N16·Status N16·divide(N16·T *remainder ,N16·T *quotient ,N16·T *a ,N16·T *b){ - if(b->d0 == 0) return N16·Status·undefined_divide_by_zero; - - uint32_t dividend = a->d0; - uint32_t divisor = b->d0; - quotient->d0 = (uint16_t)(dividend / divisor); - remainder->d0 = (uint16_t)(dividend - (quotient->d0 * divisor)); - - return N16·Status·ok; - } - - Local N16·Status N16·modulus(N16·T *remainder ,N16·T *a ,N16·T *b){ - if(b->d0 == 0) return N16·Status·undefined_modulus_zero; - uint32_t dividend = a->d0; - uint32_t divisor = b->d0; - uint32_t q = dividend / divisor; - remainder->d0 = (uint16_t)(dividend - (q * divisor)); - return N16·Status·ok; - } - - // bit motion - - typedef uint16_t (*ShiftOp)(uint16_t, uint16_t); - - Local uint16_t shift_left_op(uint16_t value, uint16_t amount){ - return value << amount; - } - - Local uint16_t shift_right_op(uint16_t value, uint16_t amount){ - return (uint16_t)(value >> amount); - } - - Local N16·Status N16·shift - ( - uint16_t shift_count - ,N16·T *spill - ,N16·T *operand - ,N16·T *fill - ,ShiftOp shift_op - ,ShiftOp complement_shift_op - ){ - - if(operand == NULL && spill == NULL) return N16·Status·ok; - - if(operand == NULL){ - operand = &N16·t[0]; - N16·copy(operand, N16·zero); - } - - if(shift_count > 15) return N16·Status·gt_max_shift_count; - - N16·T *given_operand = &N16·t[1]; - N16·copy(given_operand, operand); - - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (16 - shift_count)); - N16·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (16 - shift_count)); - } - - return N16·Status·ok; - } - - Local N16·Status - N16·shift_left(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ - return N16·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N16·Status - N16·shift_right(uint16_t shift_count, N16·T *spill, N16·T *operand, N16·T *fill){ - return N16·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N16·Status - N16·arithmetic_shift_right(uint16_t shift_count, N16·T *operand, N16·T *spill){ - - if(shift_count > 15) return N16·Status·gt_max_shift_count; - - if(operand == NULL){ - operand = &N16·t[0]; - N16·copy(operand, N16·zero); - } - - N16·T *fill = (operand->d0 & 0x8000) ? N16·all_one_bit : N16·zero; - return N16·shift_right(shift_count, spill, operand, fill); - } - - Local const N16·M N16·m = { - - .allocate_array = N16·allocate_array - ,.allocate_array_zero = N16·allocate_array_zero - ,.deallocate = N16·deallocate - - ,.copy = N16·copy - ,.bit_and = N16·bit_and - ,.bit_or = N16·bit_or - ,.bit_complement = N16·bit_complement - ,.bit_twos_complement = N16·bit_twos_complement - ,.compare = N16·compare - ,.lt = N16·lt - ,.gt = N16·gt - ,.eq = N16·eq - ,.eq_zero = N16·eq_zero - ,.accumulate = N16·accumulate - ,.add = N16·add - ,.increment = N16·increment - ,.subtract = N16·subtract - ,.multiply = N16·multiply - ,.divide = N16·divide - ,.modulus = N16·modulus - ,.shift_left = N16·shift_left - ,.shift_right = N16·shift_right - ,.arithmetic_shift_right = N16·arithmetic_shift_right - - ,.access = N16·access - ,.from_uint32 = N16·from_uint32 - }; - - #endif - -#endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/N32.lib.c" "b/developer/deprecated\360\237\226\211/2025-03-29/N32.lib.c" deleted file mode 100644 index ccb3411..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/N32.lib.c" +++ /dev/null @@ -1,457 +0,0 @@ -/* - N32 - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) - -*/ - -#define N32·DEBUG - -#ifndef FACE -#define N32·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N32·FACE -#define N32·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint32_t Extent; - typedef uint32_t Digit; - - typedef struct N32·T N32·T; - - extern N32·T *N32·zero; - extern N32·T *N32·one; - extern N32·T *N32·all_one_bit; - extern N32·T *N32·lsb; - extern N32·T *N32·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum{ - N32·Status·ok = 0 - ,N32·Status·overflow = 1 - ,N32·Status·accumulator1_overflow = 2 - ,N32·Status·carry = 3 - ,N32·Status·borrow = 4 - ,N32·Status·undefined_divide_by_zero = 5 - ,N32·Status·undefined_modulus_zero = 6 - ,N32·Status·gt_max_shift_count = 7 - ,N32·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value - ,N32·Status·one_word_product = 9 - ,N32·Status·two_word_product = 10 - } N32·Status; - - typedef enum{ - N32·Order_lt = -1 - ,N32·Order_eq = 0 - ,N32·Order_gt = 1 - } N32·Order; - - typedef N32·T *( *N32·Allocate_MemoryFault )(Extent); - - //---------------------------------------- - // Interface - - typedef struct{ - - N32·T *(*allocate_array_zero)(Extent, N32·Allocate_MemoryFault); - N32·T *(*allocate_array)(Extent, N32·Allocate_MemoryFault); - void (*deallocate)(N32·T*); - - void (*copy)(N32·T*, N32·T*); - void (*bit_and)(N32·T*, N32·T*, N32·T*); - void (*bit_or)(N32·T*, N32·T*, N32·T*); - void (*bit_complement)(N32·T*, N32·T*); - void (*bit_twos_complement)(N32·T*, N32·T*); - N32·Order (*compare)(N32·T*, N32·T*); - bool (*lt)(N32·T*, N32·T*); - bool (*gt)(N32·T*, N32·T*); - bool (*eq)(N32·T*, N32·T*); - bool (*eq_zero)(N32·T*); - N32·Status (*accumulate)(N32·T *accumulator1 ,N32·T *accumulator0 ,...); - N32·Status (*add)(N32·T*, N32·T*, N32·T*); - bool (*increment)(N32·T *a); - N32·Status (*subtract)(N32·T*, N32·T*, N32·T*); - N32·Status (*multiply)(N32·T*, N32·T*, N32·T*, N32·T*); - N32·Status (*divide)(N32·T*, N32·T*, N32·T*, N32·T*); - N32·Status (*modulus)(N32·T*, N32·T*, N32·T*); - N32·Status (*shift_left)(Extent, N32·T*, N32·T*, N32·T*); - N32·Status (*shift_right)(Extent, N32·T*, N32·T*, N32·T*); - N32·Status (*arithmetic_shift_right)(Extent, N32·T*, N32·T*); - - N32·T* (*access)(N32·T*, Extent); - void (*from_uint32)(N32·T *destination ,uint32_t value); - } N32·M; - - Local const N32·M N32·m; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N32·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct N32·T{ - Digit d0; - }; - - N32·T N32·constant[4] = { - {.d0 = 0}, - {.d0 = 1}, - {.d0 = ~(uint32_t)0}, - {.d0 = 1 << 31} - }; - - N32·T *N32·zero = &N32·constant[0]; - N32·T *N32·one = &N32·constant[1]; - N32·T *N32·all_one_bit = &N32·constant[2]; - N32·T *N32·msb = &N32·constant[3]; - N32·T *N32·lsb = &N32·constant[1]; - - // the allocate an array of N32 - N32·T *N32·allocate_array(Extent extent ,N32·Allocate_MemoryFault memory_fault){ - N32·T *instance = malloc((extent + 1) * sizeof(N32·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N32·T *N32·allocate_array_zero(Extent extent ,N32·Allocate_MemoryFault memory_fault){ - N32·T *instance = calloc( extent + 1 ,sizeof(N32·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void N32·deallocate(N32·T *unencumbered){ - free(unencumbered); - } - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N32·T{ - Digit d0; - }; - - // temporary variables - // making these LOCAL rather than reserving one block in the library is thread safe - // allocating a block once is more efficient - // library code writes these, they are not on the interface - - Local N32·T N32·t[4]; - - - // allocation - - extern N32·T *N32·allocate_array(Extent, N32·Allocate_MemoryFault); - extern N32·T *N32·allocate_array_zero(Extent, N32·Allocate_MemoryFault); - extern void N32·deallocate(N32·T *); - - // so the user can access numbers in an array allocation - Local N32·T* N32·access(N32·T *array ,Extent index){ - return &array[index]; - } - - Local void N32·from_uint32(N32·T *destination ,uint32_t value){ - if(destination == NULL) return; - destination->d0 = value; - } - - // copy, convenience copy - - Local void N32·copy(N32·T *destination ,N32·T *source){ - if(source == destination) return; // that was easy! - *destination = *source; - } - - Local void N32·set_to_zero(N32·T *instance){ - instance->d0 = 0; - } - - Local void N32·set_to_one(N32·T *instance){ - instance->d0 = 1; - } - - // bit operations - - Local void N32·bit_and(N32·T *result, N32·T *a, N32·T *b){ - result->d0 = a->d0 & b->d0; - } - - // result can be one of the operands - Local void N32·bit_or(N32·T *result, N32·T *a, N32·T *b){ - result->d0 = a->d0 | b->d0; - } - - // result can the same as the operand - Local void N32·bit_complement(N32·T *result, N32·T *a){ - result->d0 = ~a->d0; - } - - // result can the same as the operand - Local void N32·bit_twos_complement(N32·T *result ,N32·T *a){ - result->d0 = ~a->d0 + 1; - } - - // test functions - - Local N32·Order N32·compare(N32·T *a, N32·T *b){ - if(a->d0 < b->d0) return N32·Order_lt; - if(a->d0 > b->d0) return N32·Order_gt; - return N32·Order_eq; - } - - Local bool N32·lt(N32·T *a ,N32·T *b){ - return a->d0 < b->d0; - } - - Local bool N32·gt(N32·T *a ,N32·T *b){ - return a->d0 > b->d0; - } - - Local bool N32·eq(N32·T *a ,N32·T *b){ - return a->d0 == b->d0; - } - - Local bool N32·eq_zero(N32·T *a){ - return a->d0 == 0; - } - - - // arithmetic operations - - // For a large number of summands for the lower precision Natural implementations, for accumulate/add/sub, the 'overflow' operand could overflow and thus this routine will halt and return N32·Status·accumulator1_overflow - // - // When accumulator1 and accumulator0 point to the same location, the result is the accumulator1 value. - Local N32·Status N32·accumulate(N32·T *accumulator1 ,N32·T *accumulator0 ,...){ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - N32·T *current; - - while( (current = va_arg(args ,N32·T *)) ){ - sum += current->d0; - if(sum < current->d0){ // Accumulator1 into carry - (carry)++; - if(carry == 0){ - va_end(args); - return N32·Status·accumulator1_overflow; - } - } - } - va_end(args); - - // wipes out prior value of accumulator1 - accumulator1->d0 = carry; - - return N32·Status·ok; - } - - Local N32·Status N32·add(N32·T *sum ,N32·T *a ,N32·T *b){ - uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; - sum->d0 = (uint32_t)result; - return (result >> 32) ? N32·Status·carry : N32·Status·ok; - } - - Local bool N32·increment(N32·T *a){ - a->d0++; - return a->d0 == 0; - } - - Local N32·Status N32·subtract(N32·T *difference ,N32·T *a ,N32·T *b){ - uint64_t diff = (uint64_t) a->d0 - (uint64_t) b->d0; - difference->d0 = (uint32_t)diff; - return (diff > a->d0) ? N32·Status·borrow : N32·Status·ok; - } - - - Local N32·Status N32·multiply(N32·T *product1 ,N32·T *product0 ,N32·T *a ,N32·T *b){ - uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; - product0->d0 = (uint32_t)product; - product1->d0 = (uint32_t)(product >> 32); - - if(product1->d0 == 0) return N32·Status·one_word_product; - return N32·Status·two_word_product; - } - - Local N32·Status N32·divide(N32·T *remainder ,N32·T *quotient ,N32·T *a ,N32·T *b){ - if(b->d0 == 0) return N32·Status·undefined_divide_by_zero; - - quotient->d0 = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient->d0 * b->d0); - - return N32·Status·ok; - } - - Local N32·Status N32·modulus(N32·T *remainder ,N32·T *a ,N32·T *b){ - if(b->d0 == 0) return N32·Status·undefined_modulus_zero; - uint32_t quotient = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient * b->d0); - return N32·Status·ok; - } - - // bit motion - - typedef uint32_t (*ShiftOp)(uint32_t, uint32_t); - - Local uint32_t shift_left_op(uint32_t value, uint32_t amount){ - return value << amount; - } - - Local uint32_t shift_right_op(uint32_t value, uint32_t amount){ - return value >> amount; - } - - // modifies all three of its operands - // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill, - Local N32·Status N32·shift - ( - uint32_t shift_count - ,N32·T *spill - ,N32·T *operand - ,N32·T *fill - ,ShiftOp shift_op - ,ShiftOp complement_shift_op - ){ - - // If no result is needed, return immediately. - if(operand == NULL && spill == NULL) return N32·Status·ok; - - // Treat NULL operand as zero. - if(operand == NULL){ - operand = &N32·t[0]; - N32·copy(operand, N32·zero); - } - - // Shifting more than one word breaks our fill/spill model. - if(shift_count > 31) return N32·Status·gt_max_shift_count; - - // The given operand is still required after it is modified, so we copy it. - N32·T *given_operand = &N32·t[1]; - N32·copy(given_operand, operand); - - // Perform the shift - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (32 - shift_count)); - N32·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (32 - shift_count)); - } - - return N32·Status·ok; - } - - // Define concrete shift functions using valid C function pointers - Local N32·Status - N32·shift_left(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ - return N32·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N32·Status - N32·shift_right(uint32_t shift_count, N32·T *spill, N32·T *operand, N32·T *fill){ - return N32·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N32·Status - N32·arithmetic_shift_right(uint32_t shift_count, N32·T *operand, N32·T *spill){ - - // Guard against excessive shift counts - if(shift_count > 31) return N32·Status·gt_max_shift_count; - - // A NULL operand is treated as zero - if(operand == NULL){ - operand = &N32·t[0]; - N32·copy(operand, N32·zero); - } - - // Pick the fill value based on the sign bit - N32·T *fill = (operand->d0 & 0x80000000) ? N32·all_one_bit : N32·zero; - - // Call shift_right with the appropriate fill - return N32·shift_right(shift_count, spill, operand, fill); - } - - Local const N32·M N32·m = { - - .allocate_array = N32·allocate_array - ,.allocate_array_zero = N32·allocate_array_zero - ,.deallocate = N32·deallocate - - ,.copy = N32·copy - ,.bit_and = N32·bit_and - ,.bit_or = N32·bit_or - ,.bit_complement = N32·bit_complement - ,.bit_twos_complement = N32·bit_twos_complement - ,.compare = N32·compare - ,.lt = N32·lt - ,.gt = N32·gt - ,.eq = N32·eq - ,.eq_zero = N32·eq_zero - ,.accumulate = N32·accumulate - ,.add = N32·add - ,.increment = N32·increment - ,.subtract = N32·subtract - ,.multiply = N32·multiply - ,.divide = N32·divide - ,.modulus = N32·modulus - ,.shift_left = N32·shift_left - ,.shift_right = N32·shift_right - ,.arithmetic_shift_right = N32·arithmetic_shift_right - - ,.access = N32·access - ,.from_uint32 = N32·from_uint32 - }; - - #endif - -#endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/N64.lib.c" "b/developer/deprecated\360\237\226\211/2025-03-29/N64.lib.c" deleted file mode 100644 index 6058e9b..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/N64.lib.c" +++ /dev/null @@ -1,477 +0,0 @@ -/* - N64 - a 64-bit native type - - For binary operations: a op b -> c - - Similar to N32, but now each Digit is 64 bits. Where a 128-bit - intermediate is necessary (e.g. multiplication), we handle it - manually using two 64-bit parts. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define N64·DEBUG - -#ifndef FACE -#define N64·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N64·FACE -#define N64·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint64_t Extent; - typedef uint64_t Digit; - - typedef struct N64·T N64·T; - - extern N64·T *N64·zero; - extern N64·T *N64·one; - extern N64·T *N64·all_one_bit; - extern N64·T *N64·lsb; - extern N64·T *N64·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum { - N64·Status·ok = 0 - ,N64·Status·overflow = 1 - ,N64·Status·accumulator1_overflow = 2 - ,N64·Status·carry = 3 - ,N64·Status·borrow = 4 - ,N64·Status·undefined_divide_by_zero = 5 - ,N64·Status·undefined_modulus_zero = 6 - ,N64·Status·gt_max_shift_count = 7 - ,N64·Status·spill_eq_operand = 8 // not currently signaled, result will be spill value - ,N64·Status·one_word_product = 9 - ,N64·Status·two_word_product = 10 - } N64·Status; - - typedef enum { - N64·Order_lt = -1 - ,N64·Order_eq = 0 - ,N64·Order_gt = 1 - } N64·Order; - - typedef N64·T *(*N64·Allocate_MemoryFault)(Extent); - - //---------------------------------------- - // Interface - - typedef struct { - - N64·T *(*allocate_array_zero)(Extent, N64·Allocate_MemoryFault); - N64·T *(*allocate_array)(Extent, N64·Allocate_MemoryFault); - void (*deallocate)(N64·T*); - - void (*copy)(N64·T*, N64·T*); - void (*bit_and)(N64·T*, N64·T*, N64·T*); - void (*bit_or)(N64·T*, N64·T*, N64·T*); - void (*bit_complement)(N64·T*, N64·T*); - void (*bit_twos_complement)(N64·T*, N64·T*); - N64·Order (*compare)(N64·T*, N64·T*); - bool (*lt)(N64·T*, N64·T*); - bool (*gt)(N64·T*, N64·T*); - bool (*eq)(N64·T*, N64·T*); - bool (*eq_zero)(N64·T*); - N64·Status (*accumulate)(N64·T *accumulator1, N64·T *accumulator0, ...); - N64·Status (*add)(N64·T*, N64·T*, N64·T*); - bool (*increment)(N64·T *a); - N64·Status (*subtract)(N64·T*, N64·T*, N64·T*); - N64·Status (*multiply)(N64·T*, N64·T*, N64·T*, N64·T*); - N64·Status (*divide)(N64·T*, N64·T*, N64·T*, N64·T*); - N64·Status (*modulus)(N64·T*, N64·T*, N64·T*); - N64·Status (*shift_left)(Extent, N64·T*, N64·T*, N64·T*); - N64·Status (*shift_right)(Extent, N64·T*, N64·T*, N64·T*); - N64·Status (*arithmetic_shift_right)(Extent, N64·T*, N64·T*); - - N64·T* (*access)(N64·T*, Extent); - void (*from_uint64)(N64·T *destination, uint64_t value); - - } N64·M; - - Local const N64·M N64·m; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N64·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct N64·T { - Digit d0; - }; - - // For constants, we store them in an array for convenience - // 0, 1, all bits set (~0ULL), and MSB set (1ULL<<63) - N64·T N64·constant[4] = { - {.d0 = 0ULL}, - {.d0 = 1ULL}, - {.d0 = ~(uint64_t)0ULL}, - {.d0 = 1ULL << 63} - }; - - N64·T *N64·zero = &N64·constant[0]; - N64·T *N64·one = &N64·constant[1]; - N64·T *N64·all_one_bit = &N64·constant[2]; - N64·T *N64·msb = &N64·constant[3]; - N64·T *N64·lsb = &N64·constant[1]; - - // allocate an array of N64 - N64·T *N64·allocate_array(Extent extent, N64·Allocate_MemoryFault memory_fault){ - N64·T *instance = malloc( (extent + 1) * sizeof(N64·T) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N64·T *N64·allocate_array_zero(Extent extent, N64·Allocate_MemoryFault memory_fault){ - N64·T *instance = calloc(extent + 1, sizeof(N64·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void N64·deallocate(N64·T *unencumbered){ - free(unencumbered); - } - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N64·T { - Digit d0; - }; - - // local temporary variables - Local N64·T N64·t[4]; - - // allocation references - extern N64·T *N64·allocate_array(Extent, N64·Allocate_MemoryFault); - extern N64·T *N64·allocate_array_zero(Extent, N64·Allocate_MemoryFault); - extern void N64·deallocate(N64·T *); - - // Access array - Local N64·T* N64·access(N64·T *array, Extent index){ - return &array[index]; - } - - Local void N64·from_uint64(N64·T *destination, uint64_t value){ - if(destination == NULL) return; - destination->d0 = value; - } - - // copy - Local void N64·copy(N64·T *destination, N64·T *source){ - if(source == destination) return; - *destination = *source; - } - - // bit operations - - Local void N64·bit_and(N64·T *result, N64·T *a, N64·T *b){ - result->d0 = a->d0 & b->d0; - } - - Local void N64·bit_or(N64·T *result, N64·T *a, N64·T *b){ - result->d0 = a->d0 | b->d0; - } - - Local void N64·bit_complement(N64·T *result, N64·T *a){ - result->d0 = ~a->d0; - } - - Local void N64·bit_twos_complement(N64·T *result, N64·T *a){ - result->d0 = ~a->d0 + 1ULL; - } - - // compare & test functions - - Local N64·Order N64·compare(N64·T *a, N64·T *b){ - if(a->d0 < b->d0) return N64·Order_lt; - if(a->d0 > b->d0) return N64·Order_gt; - return N64·Order_eq; - } - - Local bool N64·lt(N64·T *a, N64·T *b){ - return (a->d0 < b->d0); - } - - Local bool N64·gt(N64·T *a, N64·T *b){ - return (a->d0 > b->d0); - } - - Local bool N64·eq(N64·T *a, N64·T *b){ - return (a->d0 == b->d0); - } - - Local bool N64·eq_zero(N64·T *a){ - return (a->d0 == 0ULL); - } - - // arithmetic operations - - // accumulate - Local N64·Status N64·accumulate(N64·T *accumulator1, N64·T *accumulator0, ...){ - va_list args; - va_start(args, accumulator0); - - uint64_t sum = accumulator0->d0; - uint64_t carry = 0; - N64·T *current; - - while( (current = va_arg(args, N64·T*)) ){ - uint64_t prior = sum; - sum += current->d0; - if(sum < prior){ // indicates carry - carry++; - // if carry overflowed a 64-bit, that's an accumulator1 overflow - if(carry == 0ULL){ - va_end(args); - return N64·Status·accumulator1_overflow; - } - } - } - va_end(args); - - accumulator1->d0 = carry; - return N64·Status·ok; - } - - // add - Local N64·Status N64·add(N64·T *sum, N64·T *a, N64·T *b){ - __uint128_t result = ( __uint128_t )a->d0 + ( __uint128_t )b->d0; - // But to avoid using a GNU extension, we can do the simpler approach: - // Actually let's do it directly with 64-bit since we only need to detect carry out of 64 bits: - uint64_t temp = a->d0 + b->d0; - sum->d0 = temp; - if(temp < a->d0) return N64·Status·carry; // means we overflowed - return N64·Status·ok; - } - - Local bool N64·increment(N64·T *a){ - uint64_t old = a->d0; - a->d0++; - // if it wrapped around to 0, then it was 0xFFFFFFFFFFFFFFFF - return (a->d0 < old); - } - - // subtract - Local N64·Status N64·subtract(N64·T *difference, N64·T *a, N64·T *b){ - uint64_t tmpA = a->d0; - uint64_t tmpB = b->d0; - uint64_t diff = tmpA - tmpB; - difference->d0 = diff; - if(diff > tmpA) return N64·Status·borrow; // indicates we borrowed - return N64·Status·ok; - } - - // multiply - // We'll do a 64x64->128 using two 64-bit accumulators - Local N64·Status N64·multiply(N64·T *product1, N64·T *product0, N64·T *a, N64·T *b){ - uint64_t A = a->d0; - uint64_t B = b->d0; - - // Break each operand into high & low 32 bits - uint64_t a_lo = (uint32_t)(A & 0xffffffffULL); - uint64_t a_hi = A >> 32; - uint64_t b_lo = (uint32_t)(B & 0xffffffffULL); - uint64_t b_hi = B >> 32; - - // partial products - uint64_t low = a_lo * b_lo; // 64-bit - uint64_t cross = (a_lo * b_hi) + (a_hi * b_lo); // potentially up to 2 * 32 bits => 64 bits - uint64_t high = a_hi * b_hi; // up to 64 bits - - // incorporate cross into low, high - // cross is effectively the middle bits, so shift cross by 32 and add to low - uint64_t cross_low = (cross & 0xffffffffULL) << 32; // lower part - uint64_t cross_high = cross >> 32; // upper part - - // add cross_low to low, capture carry - uint64_t old_low = low; - low += cross_low; - if(low < old_low) cross_high++; - - // final high - high += cross_high; - - // store results - product0->d0 = low; - product1->d0 = high; - - if(high == 0ULL) return N64·Status·one_word_product; - return N64·Status·two_word_product; - } - - // divide - Local N64·Status N64·divide(N64·T *remainder, N64·T *quotient, N64·T *a, N64·T *b){ - // we do not handle a > 64-bit, just the single 64-bit - if(b->d0 == 0ULL) return N64·Status·undefined_divide_by_zero; - - uint64_t divd = a->d0; // dividend - uint64_t divs = b->d0; // divisor - - quotient->d0 = divd / divs; - remainder->d0 = divd - (quotient->d0 * divs); - - return N64·Status·ok; - } - - // modulus - Local N64·Status N64·modulus(N64·T *remainder, N64·T *a, N64·T *b){ - if(b->d0 == 0ULL) return N64·Status·undefined_modulus_zero; - - uint64_t divd = a->d0; - uint64_t divs = b->d0; - uint64_t q = divd / divs; - remainder->d0 = divd - (q * divs); - - return N64·Status·ok; - } - - // bit motion - - typedef uint64_t (*ShiftOp)(uint64_t, uint64_t); - - Local uint64_t shift_left_op(uint64_t value, uint64_t amount){ - return (value << amount); - } - - Local uint64_t shift_right_op(uint64_t value, uint64_t amount){ - return (value >> amount); - } - - // modifies all three of its operands - // in the case of duplicate operands this is the order: first modifies operand, then fill, then spill - Local N64·Status N64·shift - ( - uint64_t shift_count, - N64·T *spill, - N64·T *operand, - N64·T *fill, - ShiftOp shift_op, - ShiftOp complement_shift_op - ){ - if(operand == NULL && spill == NULL) return N64·Status·ok; - - // Treat NULL operand as zero - if(operand == NULL){ - operand = &N64·t[0]; - N64·copy(operand, N64·zero); - } - - // Shifting more than 63 bits breaks fill/spill logic - if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; - - N64·T *given_operand = &N64·t[1]; - N64·copy(given_operand, operand); - - // Perform the shift - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (64ULL - shift_count)); - N64·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (64ULL - shift_count)); - } - - return N64·Status·ok; - } - - Local N64·Status N64·shift_left(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ - return N64·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N64·Status N64·shift_right(uint64_t shift_count, N64·T *spill, N64·T *operand, N64·T *fill){ - return N64·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N64·Status N64·arithmetic_shift_right(uint64_t shift_count, N64·T *operand, N64·T *spill){ - if(shift_count > 63ULL) return N64·Status·gt_max_shift_count; - - // A NULL operand is treated as zero - if(operand == NULL){ - operand = &N64·t[0]; - N64·copy(operand, N64·zero); - } - - // sign bit check - N64·T *fill = (operand->d0 & (1ULL << 63)) ? N64·all_one_bit : N64·zero; - return N64·shift_right(shift_count, spill, operand, fill); - } - - Local const N64·M N64·m = { - .allocate_array = N64·allocate_array - ,.allocate_array_zero = N64·allocate_array_zero - ,.deallocate = N64·deallocate - - ,.copy = N64·copy - ,.bit_and = N64·bit_and - ,.bit_or = N64·bit_or - ,.bit_complement = N64·bit_complement - ,.bit_twos_complement = N64·bit_twos_complement - ,.compare = N64·compare - ,.lt = N64·lt - ,.gt = N64·gt - ,.eq = N64·eq - ,.eq_zero = N64·eq_zero - ,.accumulate = N64·accumulate - ,.add = N64·add - ,.increment = N64·increment - ,.subtract = N64·subtract - ,.multiply = N64·multiply - ,.divide = N64·divide - ,.modulus = N64·modulus - ,.shift_left = N64·shift_left - ,.shift_right = N64·shift_right - ,.arithmetic_shift_right = N64·arithmetic_shift_right - - ,.access = N64·access - ,.from_uint64 = N64·from_uint64 - }; - - #endif - -#endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/N8.lib.c" "b/developer/deprecated\360\237\226\211/2025-03-29/N8.lib.c" deleted file mode 100644 index df6e01c..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/N8.lib.c" +++ /dev/null @@ -1,433 +0,0 @@ -/* - N8 - PN = refers to the use of processor native accumulator - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) -*/ - -#define N8·DEBUG - -#ifndef FACE -#define N8·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef N8·FACE -#define N8·FACE - - #include - #include - #include - #include - - //---------------------------------------- - // Instance Data (Declaration Only) - - typedef uint8_t Extent; - typedef uint8_t Digit; - - typedef struct N8·T N8·T; - - extern N8·T *N8·zero; - extern N8·T *N8·one; - extern N8·T *N8·all_one_bit; - extern N8·T *N8·lsb; - extern N8·T *N8·msb; - - //---------------------------------------- - // Return/Error Status and handlers - - typedef enum{ - N8·Status·ok = 0 - ,N8·Status·overflow = 1 - ,N8·Status·accumulator1_overflow = 2 - ,N8·Status·carry = 3 - ,N8·Status·borrow = 4 - ,N8·Status·undefined_divide_by_zero = 5 - ,N8·Status·undefined_modulus_zero = 6 - ,N8·Status·gt_max_shift_count = 7 - ,N8·Status·spill_eq_operand = 8 - ,N8·Status·one_word_product = 9 - ,N8·Status·two_word_product = 10 - } N8·Status; - - typedef enum{ - N8·Order_lt = -1 - ,N8·Order_eq = 0 - ,N8·Order_gt = 1 - } N8·Order; - - typedef N8·T *( *N8·Allocate_MemoryFault )(Extent); - - //---------------------------------------- - // Interface - - typedef struct{ - - N8·T *(*allocate_array_zero)(Extent, N8·Allocate_MemoryFault); - N8·T *(*allocate_array)(Extent, N8·Allocate_MemoryFault); - void (*deallocate)(N8·T*); - - void (*copy)(N8·T*, N8·T*); - void (*bit_and)(N8·T*, N8·T*, N8·T*); - void (*bit_or)(N8·T*, N8·T*, N8·T*); - void (*bit_complement)(N8·T*, N8·T*); - void (*bit_twos_complement)(N8·T*, N8·T*); - N8·Order (*compare)(N8·T*, N8·T*); - bool (*lt)(N8·T*, N8·T*); - bool (*gt)(N8·T*, N8·T*); - bool (*eq)(N8·T*, N8·T*); - bool (*eq_zero)(N8·T*); - N8·Status (*accumulate)(N8·T *accumulator1 ,N8·T *accumulator0 ,...); - N8·Status (*add)(N8·T*, N8·T*, N8·T*); - bool (*increment)(N8·T *a); - N8·Status (*subtract)(N8·T*, N8·T*, N8·T*); - N8·Status (*multiply)(N8·T*, N8·T*, N8·T*, N8·T*); - N8·Status (*divide)(N8·T*, N8·T*, N8·T*, N8·T*); - N8·Status (*modulus)(N8·T*, N8·T*, N8·T*); - N8·Status (*shift_left)(Extent, N8·T*, N8·T*, N8·T*); - N8·Status (*shift_right)(Extent, N8·T*, N8·T*, N8·T*); - N8·Status (*arithmetic_shift_right)(Extent, N8·T*, N8·T*); - - N8·T* (*access)(N8·T*, Extent); - void (*from_uint32)(N8·T *destination ,uint32_t value); - } N8·M; - - Local const N8·M N8·m; // initialized in the LOCAL section - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N8·IMPLEMENTATION - - // this part goes into the library - #ifndef LOCAL - - #include - #include - - struct N8·T{ - Digit d0; - }; - - N8·T N8·constant[4] = { - {.d0 = 0}, - {.d0 = 1}, - {.d0 = ~(uint8_t)0}, - {.d0 = 1 << 7} - }; - - N8·T *N8·zero = &N8·constant[0]; - N8·T *N8·one = &N8·constant[1]; - N8·T *N8·all_one_bit = &N8·constant[2]; - N8·T *N8·msb = &N8·constant[3]; - N8·T *N8·lsb = &N8·constant[1]; - - // the allocate an array of N8 - N8·T *N8·allocate_array(Extent extent ,N8·Allocate_MemoryFault memory_fault){ - N8·T *instance = malloc((extent + 1) * sizeof(N8·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N8·T *N8·allocate_array_zero(Extent extent ,N8·Allocate_MemoryFault memory_fault){ - N8·T *instance = calloc(extent + 1, sizeof(N8·T)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - void N8·deallocate(N8·T *unencumbered){ - free(unencumbered); - } - - - #endif - - // This part is included after the library user's code - #ifdef LOCAL - - // instance - - struct N8·T{ - Digit d0; - }; - - // temporary variables - Local N8·T N8·t[4]; - - // allocation - - extern N8·T *N8·allocate_array(Extent, N8·Allocate_MemoryFault); - extern N8·T *N8·allocate_array_zero(Extent, N8·Allocate_MemoryFault); - extern void N8·deallocate(N8·T *); - - // so the user can access numbers in an array allocation - Local N8·T* N8·access(N8·T *array ,Extent index){ - return &array[index]; - } - - Local void N8·from_uint32(N8·T *destination ,uint32_t value){ - if(destination == NULL) return; - destination->d0 = (uint8_t)(value & 0xFF); - } - - // copy, convenience copy - - Local void N8·copy(N8·T *destination ,N8·T *source){ - if(source == destination) return; - *destination = *source; - } - - Local void N8·set_to_zero(N8·T *instance){ - instance->d0 = 0; - } - - Local void N8·set_to_one(N8·T *instance){ - instance->d0 = 1; - } - - // bit operations - - Local void N8·bit_and(N8·T *result, N8·T *a, N8·T *b){ - result->d0 = a->d0 & b->d0; - } - - Local void N8·bit_or(N8·T *result, N8·T *a, N8·T *b){ - result->d0 = a->d0 | b->d0; - } - - Local void N8·bit_complement(N8·T *result, N8·T *a){ - result->d0 = ~a->d0; - } - - Local void N8·bit_twos_complement(N8·T *result ,N8·T *a){ - result->d0 = (uint8_t)(~a->d0 + 1); - } - - // test functions - - Local N8·Order N8·compare(N8·T *a, N8·T *b){ - if(a->d0 < b->d0) return N8·Order_lt; - if(a->d0 > b->d0) return N8·Order_gt; - return N8·Order_eq; - } - - Local bool N8·lt(N8·T *a ,N8·T *b){ - return a->d0 < b->d0; - } - - Local bool N8·gt(N8·T *a ,N8·T *b){ - return a->d0 > b->d0; - } - - Local bool N8·eq(N8·T *a ,N8·T *b){ - return a->d0 == b->d0; - } - - Local bool N8·eq_zero(N8·T *a){ - return a->d0 == 0; - } - - // arithmetic operations - - Local N8·Status N8·accumulate(N8·T *accumulator1 ,N8·T *accumulator0 ,...){ - - va_list args; - va_start(args ,accumulator0); - uint32_t sum = accumulator0->d0; - uint32_t carry = 0; - N8·T *current; - - while( (current = va_arg(args ,N8·T*)) ){ - sum += current->d0; - if(sum < current->d0){ - (carry)++; - if(carry == 0){ - va_end(args); - return N8·Status·accumulator1_overflow; - } - } - } - va_end(args); - - accumulator1->d0 = (uint8_t)carry; - return N8·Status·ok; - } - - Local N8·Status N8·add(N8·T *sum ,N8·T *a ,N8·T *b){ - uint32_t result = (uint32_t)a->d0 + (uint32_t)b->d0; - sum->d0 = (uint8_t)(result & 0xFF); - return (result >> 8) ? N8·Status·carry : N8·Status·ok; - } - - Local bool N8·increment(N8·T *a){ - a->d0++; - return (a->d0 == 0); - } - - Local N8·Status N8·subtract(N8·T *difference ,N8·T *a ,N8·T *b){ - uint32_t diff = (uint32_t)a->d0 - (uint32_t)b->d0; - difference->d0 = (uint8_t)(diff & 0xFF); - return (diff > a->d0) ? N8·Status·borrow : N8·Status·ok; - } - - Local N8·Status N8·multiply(N8·T *product1 ,N8·T *product0 ,N8·T *a ,N8·T *b){ - uint32_t product = (uint32_t)a->d0 * (uint32_t)b->d0; - product0->d0 = (uint8_t)(product & 0xFF); - product1->d0 = (uint8_t)((product >> 8) & 0xFF); - - if(product1->d0 == 0) return N8·Status·one_word_product; - return N8·Status·two_word_product; - } - - Local N8·Status N8·divide(N8·T *remainder ,N8·T *quotient ,N8·T *a ,N8·T *b){ - if(b->d0 == 0) return N8·Status·undefined_divide_by_zero; - - uint32_t dividend = a->d0; - uint32_t divisor = b->d0; - quotient->d0 = (uint8_t)(dividend / divisor); - remainder->d0 = (uint8_t)(dividend - (quotient->d0 * divisor)); - - return N8·Status·ok; - } - - Local N8·Status N8·modulus(N8·T *remainder ,N8·T *a ,N8·T *b){ - if(b->d0 == 0) return N8·Status·undefined_modulus_zero; - uint32_t dividend = a->d0; - uint32_t divisor = b->d0; - uint32_t q = dividend / divisor; - remainder->d0 = (uint8_t)(dividend - (q * divisor)); - return N8·Status·ok; - } - - // bit motion - - typedef uint8_t (*ShiftOp)(uint8_t, uint8_t); - - Local uint8_t shift_left_op(uint8_t value, uint8_t amount){ - return (uint8_t)(value << amount); - } - - Local uint8_t shift_right_op(uint8_t value, uint8_t amount){ - return (uint8_t)(value >> amount); - } - - Local N8·Status N8·shift - ( - uint8_t shift_count - ,N8·T *spill - ,N8·T *operand - ,N8·T *fill - ,ShiftOp shift_op - ,ShiftOp complement_shift_op - ){ - - if(operand == NULL && spill == NULL) return N8·Status·ok; - - if(operand == NULL){ - operand = &N8·t[0]; - N8·copy(operand, N8·zero); - } - - if(shift_count > 7) return N8·Status·gt_max_shift_count; - - N8·T *given_operand = &N8·t[1]; - N8·copy(given_operand, operand); - - operand->d0 = shift_op(given_operand->d0, shift_count); - if(fill != NULL){ - fill->d0 = complement_shift_op(fill->d0, (8 - shift_count)); - N8·bit_or(operand, operand, fill); - } - if(spill != NULL){ - spill->d0 = shift_op(spill->d0, shift_count); - spill->d0 += complement_shift_op(given_operand->d0, (8 - shift_count)); - } - - return N8·Status·ok; - } - - Local N8·Status - N8·shift_left(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ - return N8·shift(shift_count, spill, operand, fill, shift_left_op, shift_right_op); - } - - Local N8·Status - N8·shift_right(uint8_t shift_count, N8·T *spill, N8·T *operand, N8·T *fill){ - return N8·shift(shift_count, spill, operand, fill, shift_right_op, shift_left_op); - } - - Local N8·Status - N8·arithmetic_shift_right(uint8_t shift_count, N8·T *operand, N8·T *spill){ - - if(shift_count > 7) return N8·Status·gt_max_shift_count; - - if(operand == NULL){ - operand = &N8·t[0]; - N8·copy(operand, N8·zero); - } - - N8·T *fill = (operand->d0 & 0x80) ? N8·all_one_bit : N8·zero; - return N8·shift_right(shift_count, spill, operand, fill); - } - - Local const N8·M N8·m = { - - .allocate_array = N8·allocate_array - ,.allocate_array_zero = N8·allocate_array_zero - ,.deallocate = N8·deallocate - - ,.copy = N8·copy - ,.bit_and = N8·bit_and - ,.bit_or = N8·bit_or - ,.bit_complement = N8·bit_complement - ,.bit_twos_complement = N8·bit_twos_complement - ,.compare = N8·compare - ,.lt = N8·lt - ,.gt = N8·gt - ,.eq = N8·eq - ,.eq_zero = N8·eq_zero - ,.accumulate = N8·accumulate - ,.add = N8·add - ,.increment = N8·increment - ,.subtract = N8·subtract - ,.multiply = N8·multiply - ,.divide = N8·divide - ,.modulus = N8·modulus - ,.shift_left = N8·shift_left - ,.shift_right = N8·shift_right - ,.arithmetic_shift_right = N8·arithmetic_shift_right - - ,.access = N8·access - ,.from_uint32 = N8·from_uint32 - }; - - #endif - -#endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/TM_scratch.c" "b/developer/deprecated\360\237\226\211/2025-03-29/TM_scratch.c" deleted file mode 100644 index 13b2240..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/TM_scratch.c" +++ /dev/null @@ -1,65 +0,0 @@ - // This initializes 'inner'. - // `alignment` is an extent, e.g. extent_of·AU(uint64_t) = 0x7 - Local TM·Status Ξ(TM·NX ,CVT)·largest_aligned( - TM·NX·AU *outer ,Ξ(TM·NX ,CVT) *inner ,extent·AU alignment - ){ - uintptr_t p0 = (uintptr_t)outer->position; - uintptr_t p1 = (uintptr_t)outer->position + outer->extent; - - CVT *p0_aligned = (CVT *)( - (p0 + alignment) & ~( (uintptr_t)alignment ) - ); - CVT *p1_aligned = (CVT *)( - ( p1 - extent_of·AU(CVT) ) & ~( (uintptr_t)alignment ) - ); - - if( p1_aligned < p0_aligned ) return TM·Status·derailed; - - inner->position = p0_aligned; - inner->extent = (Ξ(extent_t ,CVT))(p1_aligned - p0_aligned}; - return TM·Status·on_track; - } - - - - - Local TM·Status TM·NX·topo(TM·NX *tm ,TM·Tape·Topo *topo){ - #ifdef TM·Debug - TM·Guard·init_count(chk); - TM·Guard·fg.check(&chk ,1 ,tm ,TM·NX_##CVT·Msg·tm); - TM·Guard·fg.check(&chk ,1 ,topo ,"topo ptr is NULL, so nowhere to put result"); - TM·Guard·if_return(chk); - #endif - if(tm->extent·AU == 0){ - *topo = TM·Tape·Topo·singleton; - }else{ - *topo = TM·Tape·Topo·segment; - } - return TM·Status·on_track; - } - - // extent·AU is an AU index - Local TM·Status TM·NX·extent·AU(TM·NX *tm ,extent·AU *extent·AU){ - TM·Tape·Topo topo; - TM·Status status = TM·NX_##CVT·topo(tm ,&topo); - boolean good_topo = - (status == TM·Status·on_track) && (topo & TM·Tape·Topo·finite_nz) - ; - - #ifdef TM·Debug - TM·Guard·init_count(chk); - TM·Guard·fg.check(&chk ,1 ,tm ,TM·NX·Msg·tm); - TM·Guard·fg.check(&chk ,1 ,extent·AU ,TM·NX·Msg·extent·AU); - TM·Guard·fg.check( - &chk ,0 ,good_topo - ,"Tape does not exist or topology does not have an extent·AU." - ); - TM·Guard·if_return(chk); - #endif - - if(!good_topo) return TM·Status·derailed; - *extent·AU = tm->array.extent·AU; - return TM·Status·on_track; - } - - #endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/environment.h" "b/developer/deprecated\360\237\226\211/2025-03-29/environment.h" deleted file mode 100644 index cdea83c..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/environment.h" +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef Mpblock·ENVIRONMENT_H -#define Mpblock·ENVIRONMENT_H - - -#endif diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/test_setup.cli.c" "b/developer/deprecated\360\237\226\211/2025-03-29/test_setup.cli.c" deleted file mode 100644 index f1c6e68..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/test_setup.cli.c" +++ /dev/null @@ -1,22 +0,0 @@ -/* - - A placeholder to see if make etc. is working. - -*/ - -#define IFACE -#include -#include - -// No need to define IMPLEMENTATION as `main` is one and done. - -int main(int argc ,char *argv[] ,char *envp[]){ - if(argc != 1){ - fprintf(stderr, "Usage: %s\n", argv[0]); - return EXIT_FAILURE; - } - - fprintf(stderr, "%s done\n", argv[0]); - - return 0; -} diff --git "a/developer/deprecated\360\237\226\211/2025-03-29/update.lib.c" "b/developer/deprecated\360\237\226\211/2025-03-29/update.lib.c" deleted file mode 100644 index 61c5cf4..0000000 --- "a/developer/deprecated\360\237\226\211/2025-03-29/update.lib.c" +++ /dev/null @@ -1,107 +0,0 @@ -/* - Copy - Memory copy operations with attention to alignment. - Provides optimized copy and byte order reversal functions. -*/ - -#define Copy·DEBUG - -#ifndef FACE -#define Copy·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef Copy·FACE -#define Copy·FACE - - #include - #include - - typedef struct{ - void *read0 - ,size_t read_size - ,void *write0 - ,size_t write_size; - } Copy·it; - - typedef enum{ - Copy·Status·perfect_fit = 0 - ,Copy·Status·argument_guard - ,Copy·Status·read_surplus - ,Copy·Status·read_surplus_write_gap - ,Copy·Status·write_available - ,Copy·Status·write_gap; - } Copy·Status; - - typedef enum{ - Copy·WFIt·Mode·none = 0 - ,Copy·WFIt·Mode·bytes - ,Copy·WFIt·Mode·bytes_reverse - ,Copy·WFIt·Mode·write_hex - ,Copy·WFIt·Mode·read_hex; - } Copy·WFIt·Mode; - - typedef enum{ - Copy·WFIt·Status·valid = 0 - ,Copy·WFIt·Status·null_read - ,Copy·WFIt·Status·null_write - ,Copy·WFIt·Status·zero_buffer - ,Copy·WFIt·Status·overlap - ,Copy·WFIt·Status·write_too_small; - } Copy·WFIt·Status; - - typedef struct{ - void *region( void *read0 ,void *read1 ,void *write0 ) - ,void *reverse_byte_order( void *read0 ,void *read1 ,void *write0 ); - } Copy·M; - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef Copy·IMPLEMENTATION - - // this part goes into Nlib.a - #ifndef LOCAL - #endif - - #ifdef LOCAL - - Local Copy·WFIt·Status Copy·wellformed_it(Copy·it *it){ - char *this_name = "Copy·wellformed_it"; - Copy·WFIt·Status status = Copy·WFIt·Status·valid; - - if(it->read0 == NULL){ - fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); - status |= Copy·WFIt·Status·null_read; - } - - if(it->write0 == NULL){ - fprintf( stderr ,"%s: NULL write pointer\n" ,this_name ); - status |= Copy·WFIt·Status·null_write; - } - - if(it->read_size == 0){ - fprintf( stderr ,"%s: Zero-sized read buffer\n" ,this_name ); - status |= Copy·WFIt·Status·zero_read_buffer; - } - - if(it->write_size == 0){ - fprintf( stderr ,"%s: Zero-sized write buffer\n" ,this_name ); - status |= Copy·WFIt·Status·zero_write_buffer; - } - - if( Copy·overlap_size_interval(it->read0 ,it->read_size ,it->write0 ,it->write_size) ){ - fprintf( stderr ,"%s: Read and write buffers overlap!\n" ,this_name ); - status |= Copy·WFIt·Status·overlap; - } - - return status; - } - - #endif // LOCAL - -#endif // IMPLEMENTATION diff --git "a/developer/deprecated\360\237\226\211/About_Python_templates.org" "b/developer/deprecated\360\237\226\211/About_Python_templates.org" deleted file mode 100644 index 414366f..0000000 --- "a/developer/deprecated\360\237\226\211/About_Python_templates.org" +++ /dev/null @@ -1,232 +0,0 @@ -#+TITLE: Python-Based Template Generation (Multi-Module Approach) -#+AUTHOR: Chat GPT - -Below is a single Org-mode document containing **four** separate Python modules -(or scripts). Each code block is top-level (not nested), ensuring they render -correctly. Together, they demonstrate how to generate a parametric `.lib.c` file -for an RT code format library. - -1. **get_template.py**: Returns a base template with `{named_blank}` placeholders. -2. **make_constants.py**: Creates the compile-time constants block for zero, one, etc. -3. **fill_template.py**: Combines the template and constants block, substituting parameters. -4. **A "Main" generator script** (for instance, `gen_n64_lib.py`) that writes out a final file (like `N64.lib.c`). - -You can create additional “main” scripts to produce different `.lib.c` files (e.g., `N128.lib.c`). - ---- - -*1. `get_template.py`* - -#+BEGIN_SRC python -#!/usr/bin/env python3 - -def get_template(): - """ - Returns the base RT C code template, with placeholders like: - {NAMESPACE}, {DIGIT_EXTENT}, {DIGIT_TYPE}, {EXTENT_TYPE}, {CONSTANTS_BLOCK}. - - The final generated .lib.c will replace these with user-specified values. - """ - return r'''#define {NAMESPACE}DEBUG - -#ifndef FACE - #define {NAMESPACE}IMPLEMENTATION - #define FACE -#endif - -#ifndef {NAMESPACE}FACE -#define {NAMESPACE}FACE - - #include - #include - #include - #include - - typedef {EXTENT_TYPE} ExtentType; - typedef {DIGIT_TYPE} Digit; - - // Digit count is (DIGIT_EXTENT + 1) - #define {NAMESPACE}DIGIT_COUNT ( {DIGIT_EXTENT} + 1 ) - - typedef struct {NAMESPACE}T{{ - Digit d[{NAMESPACE}DIGIT_COUNT]; - }} {NAMESPACE}T; - - // forward declarations for constants - extern {NAMESPACE}T *{NAMESPACE}zero; - extern {NAMESPACE}T *{NAMESPACE}one; - extern {NAMESPACE}T *{NAMESPACE}all_one_bit; - extern {NAMESPACE}T *{NAMESPACE}msb; - - // forward declarations for allocations, etc. - -#endif // {NAMESPACE}FACE - -#ifdef {NAMESPACE}IMPLEMENTATION - -#ifndef LOCAL - #include - #include - - // compile-time constants - {CONSTANTS_BLOCK} - - {NAMESPACE}T *{NAMESPACE}zero = &{NAMESPACE}constant[0]; - {NAMESPACE}T *{NAMESPACE}one = &{NAMESPACE}constant[1]; - {NAMESPACE}T *{NAMESPACE}all_one_bit = &{NAMESPACE}constant[2]; - {NAMESPACE}T *{NAMESPACE}msb = &{NAMESPACE}constant[3]; - - // memory allocation prototypes, etc. - -#endif // not LOCAL - -#ifdef LOCAL - // local code: actual function bodies, add, subtract, etc. -#endif // LOCAL - -#endif // {NAMESPACE}IMPLEMENTATION -''' -#+END_SRC - ---- - -*2. `make_constants.py`* - -#+BEGIN_SRC python -#!/usr/bin/env python3 - -def make_constants_block(namespace: str, - digit_type: str, - digit_extent: int) -> str: - """ - Returns a block of code defining static compile-time constants: - static {namespace}T {namespace}constant[4] = { - { { ...zero... } }, - { { ...one... } }, - { { ...allbits... } }, - { { ...msb... } } - }; - - The total digit count is digit_extent + 1. - """ - digit_count = digit_extent + 1 - - def digits_zero(): - return ", ".join("0" for _ in range(digit_count)) - - def digits_one(): - # index 0 => 1, rest => 0 - return ", ".join("1" if i == 0 else "0" for i in range(digit_count)) - - def digits_allbits(): - # each digit => (digit_type)(-1) - return ", ".join(f"( {digit_type} )( -1 )" for _ in range(digit_count)) - - def digits_msb(): - # top index => (digit_type)1 << ((sizeof(digit_type)*8)-1) - items = [] - for i in range(digit_count): - if i == digit_count - 1: - items.append(f"( {digit_type} )1 << ((sizeof({digit_type})*8) - 1)") - else: - items.append("0") - return ", ".join(items) - - return f'''\ -static {namespace}T {namespace}constant[4] = {{ - {{ - // zero - {{ {digits_zero()} }} - }}, - {{ - // one - {{ {digits_one()} }} - }}, - {{ - // all bits - {{ {digits_allbits()} }} - }}, - {{ - // msb - {{ {digits_msb()} }} - }} -}};''' - -#+END_SRC - ---- - -*3. `fill_template.py`* - -#+BEGIN_SRC python -#!/usr/bin/env python3 - -from get_template import get_template -from make_constants import make_constants_block - -def fill_template(namespace: str, - digit_extent: int, - digit_type: str, - extent_type: str) -> str: - """ - Renders the final .lib.c code by merging: - - the base template from get_template() - - the compile-time constants block from make_constants_block() - - placeholders for namespace, digit_extent, digit_type, extent_type - """ - template = get_template() - constants_block = make_constants_block(namespace, digit_type, digit_extent) - - # Substitute placeholders - code = template.format( - NAMESPACE = namespace, - DIGIT_EXTENT = digit_extent, - DIGIT_TYPE = digit_type, - EXTENT_TYPE = extent_type, - CONSTANTS_BLOCK = constants_block - ) - return code -#+END_SRC - ---- - -*4. An Example “Main” Script, `gen_n64_lib.py`* - -#+BEGIN_SRC python -#!/usr/bin/env python3 - -import sys -from fill_template import fill_template - -def main(): - """ - Example: generate a .lib.c with an 'N64·' namespace, - digit_extent=0 => 1 digit total, - digit_type='uint32_t', - extent_type='uint64_t'. - """ - code = fill_template( - namespace = "N64·", - digit_extent = 0, # => digit_count = 1 => 32-bit - digit_type = "uint32_t", - extent_type = "uint64_t" - ) - - with open("N64.lib.c", "w") as f: - f.write(code) - print("Generated N64.lib.c") - -if __name__ == "__main__": - main() -#+END_SRC - ---- - -### Usage - -1. **Place** these four files side-by-side in your project (e.g., a `scripts/` directory). -2. **Mark** them as executable (`chmod +x`). -3. **Run** `./gen_n64_lib.py` to produce `N64.lib.c`. This file will appear in the same directory (or wherever you prefer). -4. **Compile** `N64.lib.c` using your RT C build system (`make -f tool🖉/makefile`, etc.). - -You can then create similar scripts like `gen_n128_lib.py` or unify them into a single driver that takes parameters for namespace, digit_extent, etc. The main advantage is that **Python code** for generating constants is much more readable than M4 macros, and you keep the RT code format in your template exactly as it should appear. diff --git "a/developer/deprecated\360\237\226\211/Copy.lib.c" "b/developer/deprecated\360\237\226\211/Copy.lib.c" deleted file mode 100644 index f75a272..0000000 --- "a/developer/deprecated\360\237\226\211/Copy.lib.c" +++ /dev/null @@ -1,431 +0,0 @@ -/* - Copy - Memory copy operations with attention to alignment. - Provides optimized copy and byte order reversal functions. - -*/ - -#define Copy·DEBUG - -#ifndef FACE -#define Copy·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef Copy·FACE -#define Copy·FACE - - #include - #include - - #define extentof(x) (sizeof(x)-1) - - typedef struct{ - void *read0; - size_t read_size; - void *write0; - size_t write_size; - } Copy·it; - - // returned from the `step_X` functions - typedef enum{ - Copy·Step·perfect_fit = 0 - ,Copy·Step·argument_guard - ,Copy·Step·read_surplus - ,Copy·Step·read_surplus_write_gap - ,Copy·Step·write_availableCopy·Status· - ,Copy·Step·write_gap; - } Copy·Status; - - typedef enum{ - Copy·WFIt·Status·valid = 0 - ,Copy·WFIt·Status·null_read - ,Copy·WFIt·Status·zero_size_read - ,Copy·WFIt·Status·null_write - ,Copy·WFIt·Status·zero_size_write - ,Copy·WFIt·Status·overlap - } Copy·WFIt·Status; - - // function dictionary - typedef struct{ - void *bytes(void *read0 ,void *read1 ,void *write0); - void *reverse_byte_order(void *read0 ,void *read1 ,void *write0); - Copy·WFIt·Status Copy·wellformed_it(Copy·it *it ,Copy·WFIt·Mode mode); - } Copy·M; - - Core·M m; // initialized in the LOCAL implementation, yes in C we can do this. - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef Copy·IMPLEMENTATION - - #ifdef Copy·DEBUG - #include // Only for debug prints, not used in production. - #endif - - - // this part goes into Copylib.a - // yes this is empty, so there is no Copylib.a - #ifndef LOCAL - #endif - - #ifdef LOCAL - - // Interval predicates. - // Intervals in Copy have an exclusive upper bound - - Local bool Copy·in_pt_interval(void *pt, void *pt0 ,void *pt1){ - return pt >= pt0 && pt < pt1; - } - Local bool Copy·in_size_interval(void *pt, void *pt0 ,size_t s){ - return Copy·in_pt_interval(pt ,pt0 ,pt0 + s); - } - - // interval 0 contains interval 1, overlap on boundaries allowed. - Local bool Copy·contains_pt_interval( - void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 - ){ - return - pt10 >= pt00 && pt11 <= pt01 - ; - } - - // Possible cases of overlap - // 1. interval 0 to the left of interval 1 - // 2. interval 0 to the right of interval 1 - // 3. interval 0 wholly contained in interval 1 - // 4. interval 0 wholly contains interval 1 - Local bool Copy·overlap_pt_interval(void *pt00 ,void *pt01, void *pt10 ,void *pt11){ - void *pt01_inclusive = pt01 - 1; - void *pt11_inclusive = pt11 - 1; - return - Copy·in_pt_interval(pt10 ,pt00 ,pt01) // #1, #4 - || - Copy·in_pt_interval(pt00 ,pt10 ,pt11) // #2, #3 - ; - } - Local bool Copy·overlap_size_interval(void *pt00 ,size_t s0, void *pt10 ,size_t s1){ - return Copy·overlap_pt_interval(pt00 ,pt00 + s0 ,pt10 ,pt10 + s1); - } - - Local Copy·WFIt·Status Copy·wellformed_it(Copy·it *it ,bool print){ - char *this_name = "Copy·wellformed_it"; - Copy·WFIt·Status status = Copy·WFIt·Status·valid; - - if(it == NULL){ - if(print) fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); - return Core·It·Status·null; - } - - if(it->read0 == NULL){ - if(print) fprintf( stderr ,"%s: NULL read pointer\n" ,this_name ); - status |= Copy·WFIt·Status·null_read; - } - - if(it->write0 == NULL){ - if(print) fprintf( stderr ,"%s: NULL write pointer\n" ,this_name ); - status |= Copy·WFIt·Status·null_write; - } - - if(it->read_size == 0){ - if(print) fprintf( stderr ,"%s: Zero-sized read buffer\n" ,this_name ); - status |= Copy·WFIt·Status·zero_read_buffer; - } - - if(it->write_size == 0){ - if(print) fprintf( stderr ,"%s: Zero-sized write buffer\n" ,this_name ); - status |= Copy·WFIt·Status·zero_write_buffer; - } - - if( Copy·overlap_size_interval(it->read0 ,it->read_size ,it->write0 ,it->write_size) ){ - if(print) fprintf( stderr ,"%s: Read and write buffers overlap!\n" ,this_name ); - status |= Copy·WFIt·Status·overlap; - } - - return status; - } - - /* - Identity function. read interval values are copied without modification of value - or order to the write allocation. - - Aligns reads for performance. - - Writes are assumed to be buffered and do not require alignment. - - Returns the updated write pointer. - - See doc 'Copy.org' for more details. - */ - Local void *Copy·identity(void *read0 ,void *read1 ,void *write0){ - - uint8_t *r = (uint8_t *)read0; - uint8_t *r1 = (uint8_t *)read1; - uint8_t *w = (uint8_t *)write0; - - //---------- - // The potentially unaligned initial part (align read pointer). - if( (uintptr_t)r & 0x7 ){ - - // at this point r == r0, the lower bound of the read interval - // r0 | `0x7` adds at most six bytes to r. - uint8_t *r01 = (uint8_t *)((uintptr_t)r | 0x7); - - // If the read interval is very small - if(r01 >= r1){ - while(r < r1){ - *w++ = *r++; - } - return w; - } - - // Copy up to alignment boundary - do{ - *w++ = *r++; - }while(r <= r01); - } - // r is now aligned, but *r has not yet been copied - - //---------- - // The bulk copy part (w is still possibly unaligned, but r is aligned) - uint8_t *r10 = (uint8_t *)((uintptr_t)r1 & ~(uintptr_t)0x7); - - while(r < r10){ - *(uint64_t *)w = *(uint64_t *)r; - w += 8; - r += 8; - } - - // If r1 was aligned then r10 == r1 and we are done - if(r == r1) return w; - - //---------- - // The ragged tail, up to 7 bytes - do{ - *w++ = *r++; - }while(r < r1); - - return w; - } - - /* - Copy·reverse_byte_order - Copies a memory region while reversing byte order. - - Reads from read1 down - - writes from write0 up - - Uses `__builtin_bswap64` for efficient 64-bit swaps. - - Returns the updated write pointer. - */ - Local void *Copy·bytes_reverse_order(void *read0 ,void *read1 ,void *write0){ - - uint8_t *r = (uint8_t *)read1; // Start from the last byte - uint8_t *r0 = (uint8_t *)read0; - uint8_t *w = (uint8_t *)write0; - - //---------- - // The potentially unaligned initial part (align read pointer). - if( (uintptr_t)r & 0x7 ){ - - // ANDing with `~0x7` moves it downward to the nearest lower alignment. - uint8_t *r10 = (uint8_t *)((uintptr_t)r & ~(uintptr_t)0x7); - - // If the read interval is very small - if(r10 < r0){ - while(r > r0){ - *w++ = *--r; - } - return w; - } - - // Copy down to alignment boundary - do{ - *w++ = *--r; - }while(r > r10); - } - // r is now aligned, and *r has been copied - - //---------- - // The bulk copy part - uint8_t *r01 = (uint8_t *)( ((uintptr_t)r0 + (uintptr_t)0x7) & ~(uintptr_t)0x7); - - while(r > r01){ - r -= 8; - *(uint64_t *)w = __builtin_bswap64(*(uint64_t *)r); - w += 8; - } - - // If r0 was aligned then r01 == r0 and we are done - if(r < r0) return w; - - //---------- - // The ragged tail, up to 7 bytes - do{ - *w++ = *--r; - }while(r >= r0); - - return w; - } - - /* - Read buffer is read from the lowest address, working toward higher addresses. - - Write buffer is written from the lowest address, working to higher addresses. - - To force data to be left in the read buffer, or for capacity to be left in the - write buffer, reduce sizes. - */ - Local Copy·Status Copy·step(Copy·it *it){ - uint8_t *r = (uint8_t *)it->read0; - uint8_t *w = (uint8_t *)it->write0; - - size_t rs = it->read_size; - size_t ws = it->write_size; - - if(ws >= rs){ - Copy·bytes(r ,r + rs ,w); - it->read0 += rs; - it->read_size = 0; - it->write0 += rs; - it->write_size -= rs; - if(ws == rs) return Copy·Step·perfect_fit; - return Copy·Step·write_available;; - } - - // ws < rs - Copy·bytes(r ,r + ws ,w); - it->read0 += ws; - it->read_size -= ws; - it->write_size = 0; - it->write0 += ws; - return Copy·Step·read_surplus; - } - - /* - Read buffer is read from top down. Start with the largest address - just above the read buffer. Continue into lower addresses. - - write buffer is written from bottom up. Start with the lowest address, - continue into higher addresses. - */ - Local Copy·Status Copy·step_reverse_order(Copy·it *it){ - // How many bytes remain to be read/written - if( it->read_size == 0) return Copy·Step·complete; - size_t rs = it->read_size; - uint8_t *r1 = (uint8_t *)it->read0 + rs; - size_t ws = it->write_size; - uint8_t *w0 = (uint8_t *)it->write0; - - if(ws >= rs){ - uint8_t *r0 = (uint8_t *)it->read0; - Copy·bytes_reverse_order(r0, r1, w0); - it->read_size = 0; - it->write0 += rs; - it->write_size -= rs; - if(it->write_size == 0) return Copy·Step·perfect_fit; - return Copy·Step·write_available; - } - - // ws < rs - uint8_t *r0 = r1 - ws; - Copy·bytes_reverse_order(r0, r1, w0); - it->read0 -= ws; - it->read_size -= ws; - it->write_size = 0; - it->write0 += ws; - return Copy·Step·read_surplus; - } - - /* - Read bytes, write hex pairs. - Read and write are low address to high address. - Each read byte value -> 2 write allocation bytes - */ - Local Copy·Status Copy·step_write_hex(Copy·it *it){ - - uint8_t *r = (uint8_t *)it->read0; - size_t rs = it->read_size; - - uint8_t *w = (uint8_t *)it->write0; - size_t ws = it->write_size & ~1; // even number write_size - size_t ews = it->write_size >> 1; // effective write size - - // If ews >= rs, read bytes all coped - if(ews >= rs){ - size_t ers = it->read_size << 1; // effective read size - it->write0 += ers; - it->write_size -= ers; - while(rs--){ - *(uint16_t *)w = Copy·byte_to_hex(*r++); - w += 2; - } - it->read0 = r; - it->read_size = 0; - - if(it->write_size == 0) return Copy·Step·perfect_fit; - if(it->write_size == 1) return Copy·Step·write_gap; - return Copy·Step·write_available; - } - - // ews < rs, write allocation all used, read bytes surplus - it->read0 += ews; - it->read_size -= ews; - while(ews--){ - *(uint16_t *)w = Copy·byte_to_hex(*r++); - w += 2; - } - it->write0 = w; - it->write_size -= ws; - - if(it->write_size == 1) return Copy·Step·read_surplus_write_gap; - return Copy·Step·read_surplus; - } - - /* - Read hex pairs, write bytes. - Read is low address to high address. - Write is low address to high address. - Each read hex pair -> 1 write byte. - */ - Local Copy·Status Copy·step_read_hex(Copy·it *it){ - uint8_t *r = (uint8_t *)it->read0; - size_t rs = it->read_size & ~1; // Must be even for hex pairs. - size_t ers = rs >> 1; // Effective read size: half the number of bytes. - - uint8_t *w = (uint8_t *)it->write0; - size_t ws = it->write_size; // Write size already in bytes. - - // If ws >= ers, all hex values are processed - if(ws >= ers){ - while(ers--){ - *w++ = Copy·hex_to_byte(*(uint16_t *)r); - r += 2; - } - - it->read0 = r; - it->read_size -= rs; - it->write0 = w; - it->write_size -= rs >> 1; // Each byte consumes two hex chars. - - if(it->write_size == 0) return Copy·Step·perfect_fit; - return Copy·Step·write_available; - } - - // ws < ers, read allocation surplus - while(ws--){ - *w++ = Copy·hex_to_byte(*(uint16_t *)r); - r += 2; - } - - it->read0 = r; - it->read_size -= ws << 1; // Each write byte consumes two hex chars. - it->write0 = w; - it->write_size = 0; - - return Copy·Step·read_surplus; - } - - - #endif // LOCAL - - -#endif // IMPLEMENTATION diff --git "a/developer/deprecated\360\237\226\211/Copy.lib_2.c" "b/developer/deprecated\360\237\226\211/Copy.lib_2.c" deleted file mode 100644 index f93e599..0000000 --- "a/developer/deprecated\360\237\226\211/Copy.lib_2.c" +++ /dev/null @@ -1,347 +0,0 @@ -/* - CoreCopy - Memory copy operations with attention to alignment. - Provides optimized copy and byte order reversal functions. - - 'ATP' At This Point in the code. Assertions follow. -*/ - -#define CoreCopy·DEBUG - -#ifndef FACE -#define CoreCopy·IMPLEMENTATION -#define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef CoreCopy·FACE -#define CoreCopy·FACE - - #include - #include - - #define extentof(x) (sizeof(x) - 1) - #define extent_t size_t - - typedef struct{ - void *read0; - extent_t read_extent; - void *write0; - extent_t write_extent; - } CoreCopy·It; - - typedef enum{ - CoreCopy·It·Status·valid = 0 - ,CoreCopy·It·Status·null_read - ,CoreCopy·It·Status·null_write - ,CoreCopy·It·Status·overlap - } CoreCopy·It·Status; - - typedef enum{ - CoreCopy·Step·perfect_fit = 0 - ,CoreCopy·Step·argument_guard - ,CoreCopy·Step·read_surplus - ,CoreCopy·Step·read_surplus_write_gap - ,CoreCopy·Step·write_available - ,CoreCopy·Step·write_gap - } CoreCopy·Status; - - typedef struct{ - bool CoreCopy·IntervalPts·in(void *pt, void *pt0 ,void *pt1); - bool CoreCopy·IntervalPts·contains(void *pt00 ,void *pt01 ,void *pt10 ,void *pt11); - bool CoreCopy·IntervalPts·overlap(void *pt00 ,void *pt01, void *pt10 ,void *pt11); - - bool CoreCopy·IntervalPtSize·in(void *pt, void *pt0 ,size_t s); - bool CoreCopy·IntervalPtSize·overlap(void *pt00 ,size_t s0, void *pt10 ,size_t s1); - - CoreCopy·It·Status CoreCopy·wellformed_it(CoreCopy·It *it) - - void *identity(void *read0 ,void *read1 ,void *write0); - void *reverse_byte_order(void *read0 ,void *read1 ,void *write0); - - CoreCopy·Status CoreCopy·Step·identity(CoreCopy·It *it); - CoreCopy·Status CoreCopy·Step·reverse_order(CoreCopy·It *it); - CoreCopy·Status CoreCopy·Step·write_hex(CoreCopy·It *it); - CoreCopy·Status CoreCopy·Step·read_hex(CoreCopy·It *it); - } CoreCopy·M; - -#endif - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef CoreCopy·IMPLEMENTATION - - #ifdef CoreCopy·DEBUG - #include - #endif - - // this part goes into Copylib.a - // yes this is empty, so there is no Copylib.a - #ifndef LOCAL - #endif - - #ifdef LOCAL - - // Interval predicates. - // Intervals in Copy have inclusive bounds - - Local bool CoreCopy·aligned64(void *p){ - return ((uintptr_t)p & 0x7) == 0; - } - - Local bool CoreCopy·IntervalPts·in(void *pt, void *pt0 ,void *pt1){ - return pt >= pt0 && pt <= pt1; // Inclusive bounds - } - - Local bool CoreCopy·in_extent_interval(void *pt, void *pt0 ,extent_t e){ - return CoreCopy·IntervalPts·in(pt ,pt0 ,pt0 + e); - } - - // interval 0 contains interval 1, overlap on boundaries allowed. - Local bool CoreCopy·IntervalPts·contains( - void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 - ){ - return pt10 >= pt00 && pt11 <= pt01; - } - - // interval 0 properly contains interval 1, overlap on boundaries not allowed. - Local bool CoreCopy·contains_proper_pt_interval( - void *pt00 ,void *pt01 ,void *pt10 ,void *pt11 - ){ - return pt10 > pt00 && pt11 < pt01; - } - - // Possible cases of overlap, including just touching - // 1. interval 0 to the right of interval 1, just touching p00 == p11 - // 2. interval 0 to the left of interval 1, just touching p01 == p10 - // 3. interval 0 wholly contained in interval 1 - // 4. interval 0 wholly contains interval 1 - Local bool CoreCopy·IntervalPts·overlap(void *pt00 ,void *pt01, void *pt10 ,void *pt11){ - return - CoreCopy·IntervalPts·in(pt00 ,pt10 ,pt11) // #1, #3 - || CoreCopy·IntervalPts·in(pt10 ,pt00 ,pt01) // #2, #4 - ; - } - - Local bool CoreCopy·overlap_extent_interval(void *pt00 ,extent_t e0, void *pt10 ,extent_t e1){ - return CoreCopy·IntervalPts·overlap(pt00 ,pt00 + e0 ,pt10 ,pt10 + e1); - } - - Local CoreCopy·It·Status CoreCopy·It·wellformed(CoreCopy·It *it){ - char *this_name = "CoreCopy·It·wellformed"; - CoreCopy·It·Status status = CoreCopy·It·Status·valid; - - if(it->read0 == NULL){ - fprintf(stderr, "%s: NULL read pointer\n", this_name); - status |= CoreCopy·It·Status·null_read; - } - - if(it->write0 == NULL){ - fprintf(stderr, "%s: NULL write pointer\n", this_name); - status |= CoreCopy·It·Status·null_write; - } - - if( - CoreCopy·overlap_extent_interval(it->read0 ,it->read_extent ,it->write0 ,it->write_extent) - ){ - fprintf(stderr, "%s: Read and write buffers overlap!\n", this_name); - status |= CoreCopy·It·Status·overlap; - } - - return status; - } - - // consider an 8 byte window that is aligned - // returns the byte pointer to the least address byte in the window - Local void *CoreCopy·floor64(void *p){ - return (uintptr_t)p & ~(uintptr_t)0x7; - } - - // consider an 8 byte window that is aligned - // returns the byte pointer to the greatest address byte in the window - Local void *CoreCopy·ceiling64(void *p){ - return (uintptr_t)p | 0x7; - } - - // byte array greatest address byte at p1 (inclusive) - // byte array least address byte at p0 (inclusive) - // returns pointer to the greatest full 64-bit word-aligned address that is ≤ p1 - // by contract, p1 must be >= p0 - Local uint64_t *CoreCopy·greatest_full_64(void *p0 ,void *p1){ - - // If p1 - 0x7 moves into a prior word while p0 does not, a prefetch hazard can occur. - // If p1 and p0 are more than 0x7 apart, they cannot be in the same word, - // but this does not guarantee a full 64-bit word exists in the range. - if((uintptr_t)p1 < (uintptr_t)p0 + 0x7) return NULL; - - // Compute the last fully aligned word at or before p1. - uint64_t *p1_64 = (void *)( ((uintptr_t)p1 - 0x7) & ~(uintptr_t)0x7 ); - - // If alignment rounds p1_64 below p0, there is no full word available. - if(p1_64 < p0) return NULL; - - return p1_64; - } - - // byte array greatest address byte at p1 (inclusive) - // byte array least address byte at p0 (inclusive) - // returns pointer to the least full 64-bit word-aligned address that is ≥ p0 - Local uint64_t *CoreCopy·least_full_64(void *p0 ,void *p1){ - - // If p0 + 0x7 moves into the next word while p1 does not, a prefetch hazard can occur. - // If p1 and p0 are more than 0x7 apart, they cannot be in the same word, - // but this does not guarantee a full 64-bit word exists in the range. - if(p1 - p0 < 0x7) return NULL; - - // Compute the first fully aligned word at or after p0. - uint64_t *p0_64 = (void *)( ((uintptr_t)p0 + 0x7) & ~(uintptr_t)0x7 ); - - // If alignment rounds p0_64 beyond p1, there is no full word available. - if(p0_64 > p1) return NULL; - - return p0_64; - } - - Local void *CoreCopy·inc64(void *p ,size_t Δ){ - return (void *)((uint64_t *)p) + Δ; - } - - Local uint64_t CoreCopy·read_word_fwd(uint64_t *r){ - return *r; - } - - Local uint64_t CoreCopy·read_word_rev(uint64_t *r0, uint64_t *r1, uint64_t *r){ - return __builtin_bswap64(*(CoreCopy·floor64(r0 + (r1 - r)))); - } - - Local void *CoreCopy·byte( - uint8_t *r0 ,uint8_t *r1 ,uint8_t *w0 ,bool reverse - ){ - //---------------------------------------- - // Argument guard - // - - if(r1read0; - uint8_t *w = (uint8_t *)it->write0; - - extent_t re = it->read_extent; - extent_t we = it->write_extent; - - if(we >= re){ - CoreCopy·bytes(r ,r + re ,w); - it->read0 += re; // Fixed stepping logic - it->read_extent = 0; - it->write0 += re; - it->write_extent -= re; - if(we == re) return CoreCopy·Step·perfect_fit; - return CoreCopy·Step·write_available; - } - - CoreCopy·bytes(r ,r + we ,w); - it->read0 += we; // Fixed stepping logic - it->read_extent -= we; - it->write_extent = 0; - it->write0 += we; - return CoreCopy·Step·read_surplus; - } - - #endif // LOCAL - -#endif // IMPLEMENTATION diff --git "a/developer/deprecated\360\237\226\211/Core_with_tableau.lib.c" "b/developer/deprecated\360\237\226\211/Core_with_tableau.lib.c" deleted file mode 100644 index eac2d40..0000000 --- "a/developer/deprecated\360\237\226\211/Core_with_tableau.lib.c" +++ /dev/null @@ -1,1264 +0,0 @@ - /* - Core - core memory operations. - - 'ATP' Used in comments. 'At This Point' in the code. - - 'Tape' refers to an tape (in contrast to a point) in the address space. - - A non-exist array is said to be non-existent. - An array with zero elements has 'length == 0' or is 'empty'. - - In contrast, an allocation does not exist if it has zero bytes. - - It is better to separate the tableau than have a union, and let the - optimizer figure out the memory life times, and what can be reused. - - Nodes include neighbor links, that makes traversal more efficient. - - -*/ - -#define Core·DEBUG - -#ifndef FACE -#define Core·IMPLEMENTATION -#define FAC -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef Core·FACE -#define Core·FACE - - #include - #include - - //---------------------------------------- - // utility - - struct{ - void *offset(void *p ,size_t Δ); - void *offset_8AU(void *p ,size_t Δ); - - // given an 8AU window aligned on an 8AU boundary - bool is_aligned_on_8AU(void *p); - void *floor_within_aligned_8AU(void *p); - void *ceiling_within_aligned_8AU(void *p); - }Core·U; - Core·U Core·u; - - //---------------------------------------- - // memory - - #define extentof(x)(sizeof(x) - 1) - #define extent_t size_t - - // AU == Addressable Unit - // given an AU is an 8 bit byte, 4AU is 32 bits, and 8 AU is 64 bits. - #define AU uint8_t; - - //---------------------------------------- - // model - - typedef enum{ - Core·Status·mu = 0 - ,Core·Status·on_track - ,Core·Status·derailed - }Core·Status; - - typedef struct{ - }Core·Tableau; - - typedef struct{ - Core·Tableau tableau; - unint status; - }Core·Tableau·Face; - - typedef struct Core·Link; - - typedef struct{ - Core·ActionTable *action; - Core·Tableau *face; - Core·Tableau *state; - Core·NextTable *next_table; - }Core·Link; - - typedef enum { - Core·Link·Mode·none = 0 - ,Core·Link·Mode·action = 1 - ,Core·Link·Mode·face = 2 - ,Core·Link·Mode·state = 4 - ,Core·Link·Mode·next_table = 8 - ,Core·Link·Mode·bad_mode = 16 - ,Core·Link·Mode·bad_link = 32 - }Core·Link·Mode; - - Local uint Core·Link·check(Core·Link *l ,Core·Link·Mode m){ - Core·Link·Mode error = Core·Link·Mode·none; - - if(m == Core·Link·Mode·none){ - fprintf(stderr,"Core·Area·Array·read:: given zero mode"); - error |= Core·Link·Mode·bad_mode; - } - if(m >= Core·Link·Mode·bad_mode){ - fprintf(stderr,"Core·Area·Array·read:: illegal check mode"); - error |= Core·Link·Mode·bad_mode; - } - if(!l){ - fprintf(stderr,"Core·Area·Array·read:: given NULL link"); - error |= Core·Link·Mode·bad_link; - } - - if(error) return error; - - if( (m & Core·Link·Mode·action) && !l->action){ - fprintf(stderr,"Core·Area·Array·read:: given NULL action"); - error |= Core·Link·Mode·action; - } - if( (m & Core·Link·Mode·face) && !l->face){ - fprintf(stderr,"Core·Area·Array·read:: given NULL face"); - error |= Core·Link·Mode·face; - } - if( (m & Core·Link·Mode·state) && !l->state){ - fprintf(stderr,"Core·Area·Array·read:: given NULL state"); - error |= Core·Link·Mode·state; - } - if( (m & Core·Link·Mode·next_table) && !l->next_table){ - fprintf(stderr,"Core·Area·Array·read:: given NULL next_table"); - error |= Core·Link·Mode·next_table; - } - - return error; - } - - typedef struct{ - uint (*check)(Core·Link *l ,Core·Link·Mode m); - }Core·Link·ActionTable; - - - typedef Core·Link *(*Core·Action)(Core·Link *); - - typedef struct{ - Core·Action on_track; // -> status - Core·Action derailed; // -> status - }Core·ActionTable; - - Local Core·Link *Core·Action·on_track(Core·Link *lnk){ - lnk->face->status = Core·Status·on_track; - return NULL; - } - - Local Core·Link *Core·Action·derailed(Core·Link *lnk){ - lnk->face->status = Core·Status·derailed; - return NULL; - } - - // The most common continuations - typedef struct{ - Core·Link on_track; - Core·Link derailed; - }Core·NextTable; - - - Local void initiate(Core·Link *lnk){ - while(lnk) lnk = lnk->action(lnk); - } - - typedef struct Core·State; - - Local void call( - Core·Action action - ,Core·Face *face - ,Core·State *state - ){ - Core·Link link{ - .action = action - ,.face = face - ,.state = state - ,.next_table = NULL; - } - initiate(&link); - } - - Local Core·Tableau·Face Core·Tableau·face{ - .tableau = { - } - .status = Core·Status·mu - } - - Local Core·Link·ActionTable Core·Link·action_table = { - ,.check = Core·Link·check - }; - - Local Core·ActionTable Core·action_table = { - .on_track = Core·Action·on_track, - ,.derailed = Core·Action·derailed - ,.check = Core·Link·check - }; - - Local Core·NextTable Core·next_table{ - .on_track = Core·Action·on_track - ,.derailed = Core·Action·derailed - }; - - Local Core·Link Core·link{ - .action = NULL - ,.face = NULL - ,.state = NULL - ,.next_table = &Core·next_table - } - - //---------------------------------------- - // Tape model - - typedef struct Core·Tape; - typedef struct Core·Tape·Address; - typedef struct Core·Tape·Remote; - - typedef struct{ - Core·Tableau·Face; - Core·Tape *tape; - Core·Tape·Address *address; - Core·Tape·remote *remote; - extent_t extent; - }Core·Tape·Tableau·Face; - - typedef Local void (*Core·Tape·copy)( - Core·Tape·Address *address - ,Core·Tape·Remote *remote - ); - - typedef enum{ - Core·Area·Topo·mu - ,Core·Area·Topo·nonexistent // pointer to tape is NULL - ,Core·Area·Topo·empty // tape has no cells - ,Core·Area·Topo·singleton // extent is zero - ,Core·Area·Topo·segment // finite non-singleton tape - ,Core·Area·Topo·circle // initial location recurs - ,Core·Area·Topo·cyclic // a location recurs - ,Core·Area·Topo·infinite // exists, not empty, no cycle, no rightmost - }Core·Tape·Topo; - - typedef enum{ - Core·Status·mu = 0 - ,Core·Status·on_track - ,Core·Status·empty_tape - ,Core·Status·empty_tape - }Core·Tape·Extent·Next; - - typedef struct{ - Core·Action topo; - Core·Action copy; // *address -> *remote - Core·Action extent; - }Core·Tape·ActionTable; - - //---------------------------------------- - // Area model - - typedef struct Core·Area; // extends Tape - - typedef struct{ - Core·Tape·Tableau·Face tape; - Core·Area *area; - void *position; - void *position_right; - AU *pt; - AU *pt_complement; - Core·Area *a; - Core·Area *b; - bool q; // predicate -> q - }Core·Area·Tableau·Face; - - typedef struct{ - Core·Tape·ActionTable tape; - - Core·Action position_right; // sets position_right - - Core·Action complement; // AU *pt -> AU *pt_complement - - // area relationships - Core·Action address_valid; // a encloses pt - Core·Action encloses_pt_strictly_q; // " pt not on a bound - Core·Action encloses_area_q; // a encloses b - Core·Action encloses_area_strictly_q; // " no bounds touching - Core·Action overlap_q; // a overlaps b - // a is an outer byte array, b is an inner aligned word64 array - Core·Action largest_aligned_64_q; - } Core·Area·Action; - - //---------------------------------------- - // Tape Machine - - typedef struct Core·TM_NX; - - // if tape machine does not support step left, then Status·leftmost will be reported as Status·interim - typedef enum{ - Core·TM·Head·Status·mu - ,Core·TM·Head·Status·not_on_tape = 1 - ,Core·TM·Head·Status·on_leftmost = 1 << 1 - ,Core·TM·Head·Status·in_interim = 1 << 2 - ,Core·TM·Head·Status·on_rightmost = 1 << 3 - }Core·TM·Head·Status; - - const uint Core·TM·Head·Status·derailed = - Core·TM·Head·Status·mu - | Core·TM·Head·Status·not_on_tape - ; - - const uint Core·TM·Head·Status·can_step = - Core·TM·Head·Status·leftmost - | Core·TM·Head·Status·interim - ; - - typedef struct{ - Core·Tableau·Face face; - Core·Tape *tape; - Core·Tape·Topo topo; - void *read_pt; // various machines will have different read types - }Core·TM_NX·Tableau·Face; - - // default Tableau - Local Core·TM_NX·Tableau Core·TM_NX·t; - - typedef struct{ - Core·Action mount; - Core·Action rewind; - Core·Action can_step; - Core·Action step_right; - Core·Action step_left; - Core·Action read; // -> read_pt - Core·Action write; // writes data found at read_pt - Core·Action status; - Core·Action topo; - } Core·TM_NX·Action; - // default actions table - Local Core·TM_NX·Action Core·TM_NX·action; - - // default link - Core·Link Core·TM_NX·link; - - - //---------------------------------------- - // Map - - typedef enum{ - Core·Map·Status·mu = 0 - ,Core·Map·Status·no_tape - ,Core·Map·Status·not_computable - ,Core·Map·Status·complete - } Core·Map·Status; - - typedef enum{ - Core·Map·Completion·mu = 0 - ,Core·Map·Completion·no_tape - ,Core·Map·Completion·not_computable - ,Core·Map·Completion·failed - ,Core·Map·Completion·perfect_fit - ,Core·Map·Completion·read_surplus - ,Core·Map·Completion·read_surplus_write_gap - ,Core·Map·Completion·write_available - ,Core·Map·Completion·write_gap - } Core·Map·Completion; - - const uint Core·Map·Completion·derailed = - Core·Map·Completion·no_tape - | Core·Map·Completion·not_computable - | Core·Map·Completion·failed - ; - - const uint Core·Map·Completion·on_track = - Core·Map·Completion·perfect_fit - | Core·Map·Completion·read_surplus - | Core·Map·Completion·read_surplus_write_gap - | Core·Map·Completion·write_available - | Core·Map·Completion·write_gap - ; - - typedef Core·Map·Fn (*Core·Map·Fn)(); - - // Link for Map - typedef struct{ - Core·Link *domain; - Core·Link *range; - Core·Map·Fn *fn; - Core·Map·Status status; - } Core·Map·Tableau; - - void Core·map(Core·Map·Tableau t); - - // true if function enters the map loop, otherwise false. - void Core·map(Core·Map·Tableau *t){ - #ifdef Core·DEBUG - if(!t){ - fprintf(stderr, "Core·Map·Tableau:: given NULL t"); - return; - } - uint error = 0; - if( t->status & Core·Map·Completion·derailed != 0 ){ - fprintf(stderr, "Core·Map:: prior map completion status is derailed."); - } - call(status ,t->domain); - if(t->domain->tableau->status & Core·TM·Head·Status·on_track == 0){ - fprintf(stderr, "Core·Map:: domain is not on_track."); - error++; - } - call(status ,t->range); - if(t->range->tableau->status & Core·TM·Head·Status·on_track == 0){ - fprintf(stderr, "Core·Map:: range is not on_track."); - error++; - } - if(error > 0) return; - #endif - - - } - - //---------------------------------------- - // Copy - - typedef enum{ - Core·Copy·Status·mu = 0 - ,Core·Copy·Status·argument_guard = 1 - ,Core·Copy·Status·perfect_fit = 2 - ,Core·Copy·Status·read_surplus = 4 - ,Core·Copy·Status·read_surplus_write_gap = 8 - ,Core·Copy·Status·write_available = 16 - ,Core·Copy·Status·write_gap = 32 - } Core·Copy·Status; - - typedef struct{ - Core·TM read; - Core·TM write; - Core·Function init; - Core·Function copy_cell; - Core·Function step; - Core·Function status; - } Core·Copy·Link; - - typedef struct{ - - uint8AU_t Area·read_8AU_zero(Core·Area *area ,void *r); - uint8AU_t Area·read_8AU_fwd(Core·Area *area ,void *r); - uint8AU_t Area·read_8AU_rev(Core·Area *area_8AU ,void *r); - - // hex conversion - uint16_t byte_to_hex(uint8_t byte); - uint8_t hex_to_byte(uint16_t hex); - - // copy one area to another, possibly with a transformation - Map·Status Core·map(Core·Map·Fn fn); - Map·Fn Map·AU_by_AU; - Map·Fn Map·by_8AU; - Map·Fn Map·write_hex; - Map·Fn Map·read_hex; - - } Core·MapFn·Face; - - -#endif - -//-------------------------------------------------------------------------------- -// Implementation -#ifdef Core·IMPLEMENTATION - // declarations available to all of the IMPLEMENTATION go here - // - #ifdef Core·DEBUG - #include - #endif - - // this part goes into the library - #ifndef LOCAL - #endif - - #ifdef LOCAL - - //---------------------------------------- - // model - - Core·Status Core·on_track(){ return Core·Status·on_track; } - Core·Status Core·derailed(){ return Core·Status·derailed; } - - Local void *Core·offset(void *p ,size_t Δ){ - #ifdef Core·Debug - if( !p ){ - fprintf(stderr ,"Core·offset:: given NULL `p'"); - return NULL; - } - #endif - return (void *)( (AU *)p ) + Δ; - } - - Local void *Core·offset_8AU(void *p ,size_t Δ){ - #ifdef Core·Debug - if( !p ){ - fprintf(stderr ,"Core·offset_8AU:: given NULL `p'"); - return NULL; - } - #endif - return (void *)( (uint64_t *)p ) + Δ; - } - - Local bool Core·is_aligned_on_8AU(void *p){ - #ifdef Core·Debug - if( !p ){ - fprintf(stderr ,"Core·is_aligned_on_8AU:: given NULL `p'"); - return false; - } - #endif - return ( (uintptr_t)p & 0x7 ) == 0; - } - - // find the lowest address in an 8 byte aligned window - // returns the byte pointer to the least address byte in the window - Local void *Core·floor_within_aligned_8AU(void *p){ - #ifdef Core·Debug - if( !p ){ - fprintf(stderr ,"Core·floor_8AU:: given NULL `p'" ); - return NULL; - } - #endif - return (void *)( (uintptr_t)p & ~(uintptr_t)0x7 ); - } - - // find the largest address in an 8 byte aligned window - // returns the byte pointer to the greatest address byte in the window - Local void *Core·ceiling_within_aligned_8AU(void *p){ - #ifdef Core·Debug - if( !p ){ - fprintf(stderr ,"Core·ceiling_64:: given NULL `p'" ); - return NULL; - } - #endif - return (void *)( (uintptr_t)p | 0x7 ); - } - - // Struct instance initialization - Core·Action action_struct{ - .on_track = Core·on_track - ,.derailed = Core·derailed - ,.offset = Core·offset - ,.offset_8AU = Core·offset_8AU - ,.is_aligned_on_8AU = Core·is_aligned_on_8AU - ,.floor_within_aligned_8AU = Core·floor_within_aligned_8AU - ,.ceiling_within_aligned_8AU = Core·ceiling_within_aligned_8AU - }; - - //---------------------------------------- - // Tape Machine model, based on an array - - typedef struct{ - AU *position; - extent_t extent; - }Core·Tape; - -Core·Tape·Topo Core·Tape·Array·topo(Core·Tape *tape){ - -} - - - extent_t extent(Core·Area *area); - void read(Core·Tape·Address ,Core·Tape·Remote); - void write(Core·Tape·Address ,Core·Tape·Remote); - - - - - //---------------------------------------- - // Tape Machine Model based on array - - void Core·TM_NX·Array·mount(Core·TM_NX·Array *tm){ - // Mount the tape machine to its initial state - } - - void Core·TM_NX·Array·rewind(Core·TM_NX·Array *tm){ - // Reset the tape head position - } - - bool Core·TM_NX·Array·can_step(Core·TM_NX·Array *tm){ - // Determine if a step operation is possible - return true; - } - - void Core·TM_NX·Array·step(Core·TM_NX·Array *tm){ - // Perform a step operation - } - - void Core·TM_NX·Array·step_left(Core·TM_NX·Array *tm){ - // Perform a step operation to the left - } - - void Core·TM_NX·Array·topo(Core·TM_NX·Array *tm){ - // Handle topological considerations - } - - void Core·TM_NX·Array·head_status(Core·TM_NX·Array *tm){ - // Retrieve the current head status - } - - //---------------------------------------- - // Initialize Action Table - Core·TM_NX·Array·Action Core·TM_NX·Array·action = { - .mount = Core·mount - ,.rewind = Core·rewind - ,.can_step = Core·can_step - ,.step = Core·step - ,.step_left = Core·step_left - ,.topo = Core·topo - ,.head_status = Core·head_status - }; - - - // initialize an area - - Local void Core·Area·set_position(Core·Area *area ,void *new_position){ - area->position = new_position; - } - Local extent_t Core·Area·set_extent(Core·Area *area ,exent_t extent){ - return area->extent = extent; - } - Local void Core·Area·set_position_right(Core·Area *area ,void *new_position_right){ - Core·Area·set_extent(new_position_right - area->position); - } - Local void Core·Area·init_pe(Core·Area *area ,AU *position ,extent_t extent){ - Core·Area·set_position(position); - Core·Area·set_extent(extent); - } - Local void Core·Area·init_pp(Core·Area *area ,void *position_left ,void *position_right){ - Core·Area·set_position_left(position_left); - Core·Area·set_position_right(position_right); - } - - // read area properties - - Local bool Core·Area·empty(Core·Area *area){ - #ifdef Core·Debug - if(!area){ - fprintf(stderr,"Core·Area·empty:: given NULL area"); - return true; - } - #endif - return area->position == NULL; - } - - // Requesting a NULL position is a logical error, because a NULL position - // means the Area is empty and has no position. Instead, use the `empty` - // predicate. - Local AU *Core·Area·position(Core·Area *area){ - #ifdef Core·Debug - if(!area){ - fprintf(stderr,"Core·Area·position:: given NULL area"); - return NULL; - } - if(!area->position){ - fprintf(stderr,"Core·Area·position:: request for position when it is NULL"); - } - #endif - return area->position; - } - - - Local AU *Core·Area·position_right(Core·Area *area){ - #ifdef Core·Debug - if(!area){ - fprintf(stderr,"Core·Area·position_right:: given NULL area"); - return NULL; - } - #endif - return area->position + area->extent; - } - Local extent_t Core·Area·extent(Core·Area *area){ - #ifdef Core·Debug - if(!area){ - fprintf(stderr,"Core·Area·extent:: given NULL area"); - return 0; - } - #endif - return area->extent; - } - Local AU Core·Area·length_Kung(Core·Area *area){ - if(!Core·Area·position_left(area)) return 0; - if(Core·Area·extent(area) >= 2) return 3; - return Core·Area·extent(area) + 1; - } - - Local bool Core·Area·encloses_pt(Core·Area *area ,AU *pt){ - return - (pt >= Core·Area·position_left(area)) - && (pt <= Core·Area·position_right(area)); - } - Local bool Core·Area·encloses_pt_strictly(Core·Area *area ,AU *pt){ - return - (pt > Core·Area·position_left(area)) - && (pt < Core·Area·position_right(area)); - } - Local bool Core·Area·encloses_area(Core·Area *outer ,Core·Area *inner){ - return - (Core·Area·position_left(inner) >= Core·Area·position_left(outer)) - && (Core·Area·position_right(inner) <= Core·Area·position_right(outer)); - } - Local bool Core·Area·encloses_area_strictly(Core·Area *outer ,Core·Area *inner){ - return - (Core·Area·position_left(inner) > Core·Area·position_left(outer)) - && (Core·Area·position_right(inner) < Core·Area·position_right(outer)); - } - - // Possible cases of overlap ,including just touching - // 1. interval 0 to the right of interval 1 ,just touching p00 == p11 - // 2. interval 0 to the left of interval 1 ,just touching p01 == p10 - // 3. interval 0 wholly contained in interval 1 - // 4. interval 0 wholly contains interval 1 - Local bool Core·Area·overlap(Core·Area *area0 ,Core·Area *area1){ - return - Core·Area·position_right(area0) >= Core·Area·position_left(area1) - && Core·Area·position_left(area0) <= Core·Area·position_right(area1); - } - - // find the largest contained interval aligned on 64 bit boundaries - static void Core·Area·largest_aligned_64(Core·Area *outer ,Core·Area *inner_64){ - uintptr_t p0 = (uintptr_t)Core·Area·position_left(outer); - uintptr_t p1 = (uintptr_t)Core·Area·position_right(outer); - - AU *p0_64 = (AU *)( (p0 + 0x7) & ~(uintptr_t)0x7 ); - AU *p1_64 = (AU *)( (p1 - 0x7) & ~(uintptr_t)0x7 ); - - if(p1_64 < p0_64){ - Core·Area·set_position(inner_64 ,NULL); - }else{ - Core·Area·init_pp(inner_64 ,p0_64 ,p1_64); - } - } - - // complement against the extent of the area (reverse direction) - // works for byte pointer - // works for aligned word pointer - Local AU *Core·Area·complement(Core·Area *area ,AU *r){ - return Core·Area·position_left(area) + (Core·Area·position_right(area) - r); - } - - //---------------------------------------- - // read functions - - // consider instead using `copy_zero` - Local AU Core·Area·read_8_zero(Core·Area *area ,void *r){ - return 0; - } - Local uint64_t Core·Area·read_64_zero(Core·Area *area ,void *r){ - return 0; - } - - Local AU Core·Area·read_8_fwd(){ - Core·Area a = Core·tf.read; - AU **r = &Core·tf.read_pt; - - #ifdef Core·Debug - if(!a || !*r){ - fprintf(stderr ,"Core·Area·read_8_fwd:: read read_pt: %p %p\n" ,a ,*r); - return Core·Map·Read·Status·argument_guard; - } - if( !Core·Area·enclose_pt(area ,r) ){ - fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); - } - #endif - return *(AU *)r; - } - - Local AU Core·Area·read_8_fwd(Core·Area *area ,void *r){ - #ifdef Core·Debug - if(!area || !r){ - fprintf(stderr,"Core·Area·read_8_fwd:: area r: %p %p\n" ,area ,r); - return 0; - } - if( !Core·Area·enclose_pt(area ,r) ){ - fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); - } - #endif - return *(AU *)r; - } - - // Given a pointer to the least address byte of a uint64_t, return the value - Local uint64_t Core·Area·read_64_fwd(Core·Area *area ,void *r){ - #ifdef Core·Debug - if(!area || !r){ - fprintf(stderr,"Core·Area·read_8_fwd:: area r: %p %p\n" ,area ,r); - return 0; - } - if(!Core·Area·enclose_pt(area ,r) ){ - fprintf(stderr,"Core·Area·read_8_fwd:: out of interval read\n"); - } - #endif - return *(uint64_t *)r; - } - - Local AU Core·Area·read_8_rev(Core·Area *area ,AU *r){ - return *(Core·complement(area ,r)); - } - - Local uint64_t Core·Area·read_64_rev(Core·Area *area_64 ,AU *r){ - return __builtin_bswap64( *(uint64_t *)Core·floor_64(Core·complement(area_64 ,r)) ); - } - - //---------------------------------------- - // Map - - // Map function using trampoline execution model - Local Core·Map·Status Core·map(Core·Map·Fn fn){ - #ifdef Core·Debug - if(!fn){ - fprintf(stderr,"Core·map:: given null function"); - return Core·Map·argument_guard; - } - if( - true - && fn != Core·Map·by_8AU - && fn != Core·Map·AU_by_AU - && fn != Core·write_hex - && fn != Core·read_hex - ){ - fprintf(stderr,"Core·map:: unrecognized copy function\n"); - return Core·Map·argument_guard; - ) - #endif - - while(fn) fn = fn(); - return tf.copy.status; - } - - //---------------------------------------- - // copy byte_by_byte - - Core·Map·Fn Core·Map·Map·ByteByByte·perfect_fit; - Core·Map·Fn Core·Map·Map·ByteByByte·read_surplus; - Core·Map·Fn Core·Map·Map·ByteByByte·write_available; - - Local Core·Map·Fn Core·Map·AU_by_AU(){ - if(Core·Area·extent(Core·tf.copy.read) == Core·Area·extent(Core·tf.copy.write)) - return Core·Map·ByteByByte·perfect_fit; - - if(Core·Area·extent(Core·tf.copy.read) > Core·Area·extent(Core·tf.copy.write)) - return Core·Map·ByteByByte·read_surplus; - - return Core·Map·ByteByByte·write_available; - } - - Local Core·Map·Fn Core·Map·ByteByByte·perfect_fit(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - - do{ - **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); - if(*r == r1) break; - (*r)++; - (*w)++; - }while(true); - - Core·tf.copy.status = Core·Map·Status·perfect_fit; - return NULL; - } - - Local Core·Map·Fn Core·Map·ByteByByte·read_surplus(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - AU *w1 = Core·Area·position_right(Core·tf.copy.write); - - do{ - **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); - if(*w == w1) break; - (*r)++; - (*w)++; - }while(true); - - Core·tf.copy.status = Core·Map·Status·write_available; - return NULL; - } - - Local Core·Map·Fn Core·Map·ByteByByte·write_avalable(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - - do{ - **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,*r); - if(*r == r1) break; - (*r)++; - (*w)++; - }while(true); - - Core·tf.copy.status = Core·Map·Status·read_surplus; - return NULL; - } - - //---------------------------------------- - // copy copy_64 - - // 64-bit copy function with updated TableauFace terminology - Core·Map·Fn Core·Map·by_8AU; - Core·Map·Fn Core·Map·ByWord64·leadin; - Core·Map·Fn Core·Map·ByWord64·bulk; - Core·Map·Fn Core·Map·ByWord64·tail; - - // Initialize the copy_64 process - Local Core·Map·Fn Core·Map·by_8AU(){ - // Determine the largest 64-bit aligned region within the read area - Core·Area·largest_aligned_64(Core·tf.copy.read ,&Core·tl.copy_64.area_64); - - // Choose the correct function based on alignment - if(Core·Area·empty(&Core·tl.copy_64.area_64)) return Core·Map·ByWord64·tail; - if(Core·is_aligned_on_64(Core·Area·position(Core·tf.copy.read))) return Core·Map·ByWord64·bulk; - return Core·Map·ByWord64·leadin; - } - - // Lead-in byte copy (until alignment) - Local Core·Map·Fn Core·Map·ByWord64·leadin(){ - AU **r = &Core·tf.copy.read_pt; - AU *r0_64 = Core·Area·position(&Core·tl.copy_64.area_64); - AU **w = &Core·tf.copy.write_pt; - - do{ - **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,r0_64 ,*r); - if(*r == r0_64) break; - (*r)++; - (*w)++; - }while(true); - - return Core·Map·ByWord64·bulk; - } - - // Bulk word copy - Local Core·Map·Fn Core·Map·ByWord64·bulk(){ - uint64_t **r = (uint64_t **)&Core·tf.copy.read_pt; - uint64_t **w = (uint64_t **)&Core·tf.copy.write_pt; - uint64_t *r1_64 = Core·Area·position_right(&Core·tl.copy_64.area_64); - - do{ - **w = Core·tf.copy.read_fn_64(Core·tf.copy.read ,r1_64 ,*r); - if(*r == r1_64) break; - (*r)++; - (*w)++; - }while(true); - - return Core·Map·ByWord64·tail; - } - - // Tail byte copy (unaligned trailing bytes) - Local Core·Map·Fn Core·Map·ByWord64·tail(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(&Core·tl.copy_64.area_64); - AU **w = &Core·tf.copy.write_pt; - - do{ - **w = Core·tf.copy.read_fn_8(Core·tf.copy.read ,r1 ,*r); - if(*r == r1) break; - (*r)++; - (*w)++; - }while(true); - - Core·tf.copy.status = Core·Map·Status·perfect_fit; - return NULL; - } - - //---------------------------------------- - // copy write hex - - Local uint16_t Core·byte_to_hex(AU byte){ - static const char hex_digits[] = "0123456789ABCDEF"; - return - (hex_digits[byte >> 4] << 8) - | hex_digits[byte & 0x0F]; - } - - // Forward Declarations - Core·Map·Fn Core·Map·write_hex; - Core·Map·Fn Core·Map·WriteHex·perfect_fit; - Core·Map·Fn Core·Map·WriteHex·read_surplus; - Core·Map·Fn Core·Map·WriteHex·write_available; - - // Hex Encoding: Initialize Map - Local Core·Map·Fn Core·Map·write_hex(){ - if(Core·Area·extent(Core·tf.copy.read) == (Core·Area·extent(Core·tf.copy.write) >> 1)){ - return Core·Map·WriteHex·perfect_fit; - } - if(Core·Area·extent(Core·tf.copy.read) > (Core·Area·extent(Core·tf.copy.write) >> 1)){ - return Core·Map·WriteHex·read_surplus; - } - return Core·Map·WriteHex·write_available; - } - - Local Core·Map·Fn Core·Map·WriteHex·perfect_fit(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - - do { - *(uint16_t *)*w = Core·hex.byte_to_hex(**r); - if(*r == r1) break; - (*r)++; - (*w) += 2; - } while(true); - - Core·tf.copy.status = Core·Map·Status·perfect_fit; - return NULL; - } - - // Hex Encoding: Read Surplus - Local Core·Map·Fn Core·Map·WriteHex·read_surplus(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.write); - AU **w = &Core·tf.copy.write_pt; - - do { - *(uint16_t *)*w = Core·write_hex.byte_to_hex(**r); - if(*r == r1) break; - (*r)++; - (*w) += 2; - } while(true); - - Core·tf.copy.status = Core·Map·Status·read_surplus; - return NULL; - } - - // Hex Encoding: Write Available - Local Core·Map·Fn Core·Map·WriteHex·write_available(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - AU *w1 = Core·Area·position_right(Core·tf.copy.write); - - do { - *(uint16_t *)*w = Core·write_hex.byte_to_hex(**r); - if(*w == w1) break; - (*r)++; - (*w) += 2; - } while(true); - - Core·tf.copy.status = Core·Map·Status·write_available; - return NULL; - } - - //---------------------------------------- - // copy read hex - - Local AU Core·hex_to_byte(uint16_t hex){ - AU high = hex >> 8; - AU low = hex & 0xFF; - - high = - (high >= '0' && high <= '9') ? (high - '0') - : (high >= 'A' && high <= 'F') ? (high - 'A' + 10) - : (high >= 'a' && high <= 'f') ? (high - 'a' + 10) - : 0; - - low = - (low >= '0' && low <= '9') ? (low - '0') - : (low >= 'A' && low <= 'F') ? (low - 'A' + 10) - : (low >= 'a' && low <= 'f') ? (low - 'a' + 10) - : 0; - - return (high << 4) | low; - } - - Core·Map·Fn Core·Map·read_hex; - Core·Map·Fn Core·Map·ReadHex·perfect_fit; - Core·Map·Fn Core·Map·ReadHex·read_surplus; - Core·Map·Fn Core·Map·ReadHex·write_available; - - Local Core·Map·Fn Core·Map·read_hex(){ - if((Core·Area·extent(Core·tf.copy.read) >> 1) == Core·Area·extent(Core·tf.copy.write)){ - return Core·Map·ReadHex·perfect_fit; - } - if((Core·Area·extent(Core·tf.copy.read) >> 1) > Core·Area·extent(Core·tf.copy.write)){ - return Core·Map·ReadHex·read_surplus; - } - return Core·Map·ReadHex·write_available; - } - - Local Core·Map·Fn Core·Map·ReadHex·perfect_fit(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - - do { - **w = Core·hex_to_byte(*(uint16_t *)*r); - if(*r == r1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·perfect_fit; - return NULL; - } - - Local Core·Map·Fn Core·Map·ReadHex·read_surplus(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.write); - AU **w = &Core·tf.copy.write_pt; - - do { - **w = Core·tf.read_hex.hex_to_byte(*(uint16_t *)*r); - if(*r == r1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·read_surplus; - return NULL; - } - - Local Core·Map·Fn Core·Map·ReadHex·write_available(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - AU *w1 = Core·Area·position_right(Core·tf.copy.write); - - do { - **w = Core·tf.read_hex.hex_to_byte(*(uint16_t *)*r); - if(*w == w1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·write_available; - return NULL; - } - - //---------------------------------------- - // copy read hex - - Core·Map·Fn Core·Map·read_hex; - Core·Map·Fn Core·Map·ReadHex·perfect_fit; - Core·Map·Fn Core·Map·ReadHex·read_surplus; - Core·Map·Fn Core·Map·ReadHex·write_available; - - Local Core·Map·Fn Core·Map·read_hex(){ - if((Core·Area·extent(Core·tf.copy.read) >> 1) == Core·Area·extent(Core·tf.copy.write)){ - return Core·Map·ReadHex·perfect_fit; - } - if((Core·Area·extent(Core·tf.copy.read) >> 1) > Core·Area·extent(Core·tf.copy.write)){ - return Core·Map·ReadHex·read_surplus; - } - return Core·Map·ReadHex·write_available; - } - - Local Core·Map·Fn Core·Map·ReadHex·perfect_fit(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - - do { - **w = Core·hex_to_byte(*(uint16_t *)*r); - if(*r == r1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·perfect_fit; - return NULL; - } - - Local Core·Map·Fn Core·Map·ReadHex·read_surplus(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.write); - AU **w = &Core·tf.copy.write_pt; - - do { - **w = Core·hex_to_byte(*(uint16_t *)*r); - if(*r == r1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·read_surplus; - return NULL; - } - - Local Core·Map·Fn Core·Map·ReadHex·write_available(){ - AU **r = &Core·tf.copy.read_pt; - AU *r1 = Core·Area·position_right(Core·tf.copy.read); - AU **w = &Core·tf.copy.write_pt; - AU *w1 = Core·Area·position_right(Core·tf.copy.write); - - do { - **w = Core·hex_to_byte(*(uint16_t *)*r); - if(*w == w1) break; - (*r) += 2; - (*w)++; - } while(true); - - Core·tf.copy.status = Core·Map·Status·write_available; - return NULL; - } - - //---------------------------------------- - // Initialization Blocks - - //---------------------------------------- - // Tableaux - - Core·TableauFace tf = { - .copy = { - .read = NULL - ,.write = NULL - ,.read_fn_8 = Core·Area·read_8_fwd - ,.read_fn_64 = Core·Area·read_64_fwd - ,.read_pt = NULL - ,.write_pt = NULL - ,.status = Core·Map·Status·uninitialized - } - }; - - Core·TableauLocal tl = { - .copy_64 = { - .area_64 = {NULL ,0} - } - }; - - Core·M m = { - .Area·init_pe = Core·Area·init_pe - ,.Area·init_pp = Core·Area·init_pp - ,.Area·set_position = Core·Area·set_position - ,.Area·set_position_left = Core·Area·set_position - ,.Area·set_position_right = Core·Area·set_position_right - ,.Area·set_extent = Core·Area·set_extent - ,.Area·position = Core·Area·position - ,.Area·position_left = Core·Area·position - ,.Area·position_right = Core·Area·position_right - ,.Area·extent = Core·Area·extent - ,.Area·length_Kung = Core·Area·length_Kung - ,.Area·empty = Core·Area·empty - - ,.Area·encloses_pt = Core·Area·encloses_pt - ,.Area·encloses_pt_strictly = Core·Area·encloses_pt_strictly - ,.Area·encloses_area = Core·Area·encloses_area - ,.Area·encloses_area_strictly = Core·Area·encloses_area_strictly - ,.Area·overlap = Core·Area·overlap - ,.Area·largest_aligned_64 = Core·Area·largest_aligned_64 - ,.Area·complement = Core·Area·complement - - ,.Area·read_8_zero = Core·Area·read_8_zero - ,.Area·read_8_fwd = Core·Area·read_8_fwd - ,.Area·read_8_rev = Core·Area·read_8_rev - ,.Area·read_64_zero = Core·Area·read_64_zero - ,.Area·read_64_fwd = Core·Area·read_64_fwd - ,.Area·read_64_rev = Core·Area·read_64_rev - - ,.is_aligned_on_64 = Core·is_aligned_on_64 - ,.floor_64 = Core·floor_64 - ,.ceiling_64 = Core·ceiling_64 - ,.offset_8 = Core·offset_8 - ,.offset_64 = Core·offset_64 - - ,.byte_to_hex = Core·byte_to_hex - ,.hex_to_byte = Core·hex_to_byte - - ,.copy = Core·map - ,.Map·AU_by_AU = Core·Map·AU_by_AU - ,.Map·by_8AU = Core·Map·by_8AU - ,.Map·write_hex = Core·Map·write_hex - ,.Map·read_hex = Core·Map·read_hex - }; - - #endif // LOCAL - -#endif // IMPLEMENTATION diff --git "a/developer/deprecated\360\237\226\211/Map.lib.c" "b/developer/deprecated\360\237\226\211/Map.lib.c" deleted file mode 100644 index 2592129..0000000 --- "a/developer/deprecated\360\237\226\211/Map.lib.c" +++ /dev/null @@ -1,154 +0,0 @@ -/* Map - mapping functions between tape machines. - - This file has two template parameters: - `CVT_read` Cell Value Type for the source/read tape machine - `CVT_write` Cell Value Type for the destination/write tape machine - - By default (when the macros have no definition) the cell value types are taken as AU. - This file must be included with CVT_read and CVT_write undefined, before inclusions with them defined. - - 'Tape' is operated on by the Tape Machine. - 'Area' is subset of an address space that is used as a virtual Tape by a machine. - An Area with zero elements has 'length == 0' or is 'empty'. - In contrast, and area located (position specified) with a null pointer is said not to exist. -*/ - -#define Map·DEBUG - -#ifndef FACE - #define Map·IMPLEMENTATION - #define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef Map·FACE - #define Map·FACE - - #include - #include - #include "Core.lib.c" - #include "TM.lib.c" - - // if only one template parameter is given, we will assume both are the same - - #if defined(CVT_read) && !defined(CVT_write) - #warning "Given CVT_read template value. Missing CVT_write template value, so setting it to CVT_read" - #define CVT_write CVT_read - #endif - - #if !defined(CVT_read) && defined(CVT_write) - #warning "Given CVT_write template value. Missing CVT_read template value, so setting it to CVT_write" - #define CVT_read CVT_write - #endif - - //---------------------------------------- - // Map status and completion enums - //---------------------------------------- - - #if !defined(CVT_read) && !defined(CVT_write) - - typedef enum { - Map·Completion·mu = 0 - ,Map·Completion·failed = 1 - ,Map·Completion·null_fn = 1 << 1 - ,Map·Completion·no_tape_access = 1 << 2 - ,Map·Completion·rightmost_read = 1 << 3 - ,Map·Completion·rightmost_write = 1 << 4 - } Map·Completion; - - // Masks for combinations - const uint Map·Completion·rightmost_both = - Map·Completion·rightmost_read - | Map·Completion·rightmost_write - ; - - const uint Map·Completion·derailed = - Map·Completion·failed - | Map·Completion·null_fn - | Map·Completion·no_tape_access - ; - - const uint Map·Completion·on_track = - Map·Completion·rightmost_read - | Map·Completion·rightmost_write - | Map·Completion·rightmost_both - ; - - #endif - - //---------------------------------------- - // Map interface - //---------------------------------------- - - #if !defined(CVT_read) || !defined(CVT_write) - - typedef struct { - Map·Completion (*copy_byte_to_byte)( - ·(TM·Array ,AU) *read_tm - ,·(TM·Array ,AU) *write_tm - ); - - Map·Completion (*copy_hex_to_byte)( - ·(TM·Array ,uint16_t) *read_tm - ,·(TM·Array ,AU) *write_tm - ); - - Map·Completion (*copy_byte_to_hex)( - ·(TM·Array ,AU) *read_tm - ,·(TM·Array ,uint16_t) *write_tm - ); - - // Terminate string function - Map·Completion (*terminate_string)( - ·(TM·Array ,AU) *write_tm - ); - } Map·FG; - - // a default function given table - Map·FG Map·fg; - - #endif - - - #if defined(CVT_read) && defined(CVT_write) - - // Function passed to map type signature must be this: - typedef Core·Status (*·(Map·fn ,CVT_read ,CVT_write))( - CVT_read *read_value - ,CVT_write *write_value - ); - - typedef struct { - // Map a function over all elements from read_tm to write_tm - Map·Completion (*map)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ); - - // Map a function over elements from read_tm to write_tm until a condition is met - Map·Completion (*map_while)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,bool (*condition)(·(TM·Array ,CVT_read) *read_tm) - ); - - // Map a function over n elements from read_tm to write_tm - Map·Completion (*map_extent)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,·(extent_t ,CVT_read) extent - ); - - } ·(Map·FG ,CVT_read ,CVT_write); - - // Default function given table - ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write); - - #endif - -#endif // #ifndef Map·FACE diff --git "a/developer/deprecated\360\237\226\211/Map2.lib.c" "b/developer/deprecated\360\237\226\211/Map2.lib.c" deleted file mode 100644 index e58173e..0000000 --- "a/developer/deprecated\360\237\226\211/Map2.lib.c" +++ /dev/null @@ -1,500 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/* Map - mapping functions between tape machines. - - This file has two template parameters: - `CVT_read` Cell Value Type for the source/read tape machine - `CVT_write` Cell Value Type for the destination/write tape machine - - By default (when the macros have no definition) the cell value types are taken as AU. - This file must be included with CVT_read and CVT_write undefined, before inclusions with them defined. - - 'Tape' is operated on by the Tape Machine. - 'Area' is subset of an address space that is used as a virtual Tape by a machine. - An Area with zero elements has 'length == 0' or is 'empty'. - In contrast, and area located (position specified) with a null pointer is said not to exist. -*/ - -#define Map·DEBUG - -#ifndef FACE - #define Map·IMPLEMENTATION - #define FACE -#endif - -//-------------------------------------------------------------------------------- -// Interface - -#ifndef Map·FACE - #define Map·FACE - - #include - #include - #include "Core.lib.c" - #include "TM.lib.c" - - // if only one template parameter is given, we will assume both are the same - - #if defined(CVT_read) && !defined(CVT_write) - #warning "Given CVT_read template value. Missing CVT_write template value, so setting it to CVT_read" - #define CVT_write CVT_read - #endif - - #if !defined(CVT_read) && defined(CVT_write) - #warning "Given CVT_write template value. Missing CVT_read template value, so setting it to CVT_write" - #define CVT_read CVT_write - #endif - - //---------------------------------------- - // Map status and completion enums - //---------------------------------------- - - #if !defined(CVT_read) && !defined(CVT_write) - - typedef enum { - Map·Completion·mu = 0 - ,Map·Completion·failed = 1 - ,Map·Completion·null_fn = 1 << 1 - ,Map·Completion·no_tape_access = 1 << 2 - ,Map·Completion·rightmost_read = 1 << 3 - ,Map·Completion·rightmost_write = 1 << 4 - } Map·Completion; - - // Masks for combinations - const uint Map·Completion·rightmost_both = - Map·Completion·rightmost_read - | Map·Completion·rightmost_write - ; - - const uint Map·Completion·derailed = - Map·Completion·failed - | Map·Completion·null_fn - | Map·Completion·no_tape_access - ; - - const uint Map·Completion·on_track = - Map·Completion·rightmost_read - | Map·Completion·rightmost_write - | Map·Completion·rightmost_both - ; - - #endif - - //---------------------------------------- - // Map interface - //---------------------------------------- - - #if !defined(CVT_read) || !defined(CVT_write) - typedef struct { - Map·Completion (*copy_byte_to_byte)( - ·(TM·Array ,AU) *read_tm - ,·(TM·Array ,AU) *write_tm - ); - - Map·Completion (*copy_hex_to_byte)( - ·(TM·Array ,uint16_t) *read_tm - ,·(TM·Array ,AU) *write_tm - ); - - Map·Completion (*copy_byte_to_hex)( - ·(TM·Array ,AU) *read_tm - ,·(TM·Array ,uint16_t) *write_tm - ); - - // Terminate string function - Map·Completion (*terminate_string)( - ·(TM·Array ,AU) *write_tm - ); - } - #endif - - - #if defined(CVT_read) && defined(CVT_write) - - // Function passed to map type signature must be this: - typedef Core·Status (*·(Map·fn ,CVT_read ,CVT_write))( - CVT_read *read_value - ,CVT_write *write_value - ); - - typedef struct { - // Map a function over all elements from read_tm to write_tm - Map·Completion (*map)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ); - - // Map a function over elements from read_tm to write_tm until a condition is met - Map·Completion (*map_while)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,bool (*condition)(·(TM·Array ,CVT_read) *read_tm) - ); - - // Map a function over n elements from read_tm to write_tm - Map·Completion (*map_extent)( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,·(extent_t ,CVT_read) extent - ); - - } ·(Map·FG ,CVT_read ,CVT_write); - - // Default function given table - ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write); - #endif // !defined(CVT_read) && !defined(CVT_write) - -#endif // #ifndef Map·FACE - -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef Map·IMPLEMENTATION - - // declarations available to all of the IMPLEMENTATION go here - #ifdef Map·DEBUG - #include - #endif - - // implementation to go into the lib.a file - #ifndef LOCAL - #endif - - #ifdef LOCAL - //---------------------------------------- - // Map implementation - //---------------------------------------- - - #if !defined(CVT_read) && !defined(CVT_write) - //----------------------------------- - // common error messages - const char *Map·Msg·read_tm = "given NULL read_tm"; - const char *Map·Msg·write_tm = "given NULL write_tm"; - const char *Map·Msg·map_fn = "given NULL map_fn"; - const char *Map·Msg·condition = "given NULL condition function"; - - //----------------------------------- - // Helper functions for copy operations - - // Byte to byte copy function - Local Core·Status Map·byte_to_byte_fn(AU *read_value, AU *write_value) { - *write_value = *read_value; - return Core·Status·on_track; - } - - // Hex to byte conversion function - Local Core·Status Map·hex_to_byte_fn(uint16_t *read_value, AU *write_value) { - // Convert hex value to byte - *write_value = (AU)(*read_value & 0xFF); - return Core·Status·on_track; - } - - // Byte to hex conversion function - Local Core·Status Map·byte_to_hex_fn(AU *read_value, uint16_t *write_value) { - // Convert byte to lowercase hex representation (no prefix) - static const char hex_chars[] = "0123456789abcdef"; - *write_value = hex_chars[(*read_value >> 4) & 0x0F]; - return Core·Status·on_track; - } - #endif // !defined(CVT_read) && !defined(CVT_write) - - #if defined(CVT_read) && defined(CVT_write) - //----------------------------------- - // Map implementation with specific types - - // Map a function over all elements from read_tm to write_tm - Local Core·Status ·(Map ,CVT_read ,CVT_write)·map( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ){ - #ifdef Map·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); - Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); - Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); - Core·Guard·if_return(chk); - #endif - - // Rewind both tape machines to ensure we start at the beginning - ·(TM·Array ,CVT_read)·fg.rewind(read_tm); - ·(TM·Array ,CVT_write)·fg.rewind(write_tm); - - // Initial check if can_read (not part of the loop) - if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; - - // Track completion status - uint completion = 0; - - // Following the first-rest pattern described in TTCA - while(1){ - // Read value from source - CVT_read read_value; - ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); - - // Apply mapping function to get write value - CVT_write write_value; - Core·Status status = map_fn(&read_value ,&write_value); - if(status != Core·gStatus·on_track) { - completion |= Core·Map·Completion·failed; - return status; - } - - // Write result to destination - ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); - - // Check if we're at the rightmost position for read - bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); - if(read_rightmost) { - completion |= Core·Map·Completion·rightmost_read; - } - - // Check if we're at the rightmost position for write - bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); - if(write_rightmost) { - completion |= Core·Map·Completion·rightmost_write; - } - - // Break if either machine is at rightmost - if(read_rightmost || write_rightmost) break; - - // Step both machines - ·(TM·Array ,CVT_read)·fg.step(read_tm); - ·(TM·Array ,CVT_write)·fg.step(write_tm); - } - - return Core·Status·on_track; - } - - // Map a function over elements from read_tm to write_tm until a condition is met - Local Core·Status ·(Map ,CVT_read ,CVT_write)·map_while( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,bool (*condition)(CVT_read *value) - ){ - #ifdef Map·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); - Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); - Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); - Core·Guard·fg.check(&chk ,1 ,condition ,Map·Msg·condition); - Core·Guard·if_return(chk); - #endif - - // Rewind both tape machines to ensure we start at the beginning - ·(TM·Array ,CVT_read)·fg.rewind(read_tm); - ·(TM·Array ,CVT_write)·fg.rewind(write_tm); - - // Initial check if can_read (not part of the loop) - if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; - - // Track completion status - uint completion = 0; - - // Following the first-rest pattern described in TTCA - while(1){ - // Read value from source - CVT_read read_value; - ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); - - // Check condition - if(!condition(&read_value)) break; - - // Apply mapping function to get write value - CVT_write write_value; - Core·Status status = map_fn(&read_value ,&write_value); - if(status != Core·Status·on_track) { - completion |= Core·Map·Completion·failed; - return status; - } - - // Write result to destination - ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); - - // Check if we're at the rightmost position for read - bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); - if(read_rightmost) { - completion |= Core·Map·Completion·rightmost_read; - } - - // Check if we're at the rightmost position for write - bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); - if(write_rightmost) { - completion |= Core·Map·Completion·rightmost_write; - } - - // Break if either machine is at rightmost - if(read_rightmost || write_rightmost) break; - - // Step both machines - ·(TM·Array ,CVT_read)·fg.step(read_tm); - ·(TM·Array ,CVT_write)·fg.step(write_tm); - } - - return Core·Status·on_track; - } - - // Map a function over n elements from read_tm to write_tm - Local Core·Status ·(Map ,CVT_read ,CVT_write)·map_n( - ·(TM·Array ,CVT_read) *read_tm - ,·(TM·Array ,CVT_write) *write_tm - ,·(Map·fn ,CVT_read ,CVT_write) map_fn - ,size_t n - ){ - #ifdef Map·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); - Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); - Core·Guard·fg.check(&chk ,1 ,map_fn ,Map·Msg·map_fn); - Core·Guard·if_return(chk); - #endif - - // Rewind both tape machines to ensure we start at the beginning - ·(TM·Array ,CVT_read)·fg.rewind(read_tm); - ·(TM·Array ,CVT_write)·fg.rewind(write_tm); - - // Initial check if can_read (not part of the loop) - if(!·(TM·Array ,CVT_read)·fg.can_read(read_tm)) return Core·Status·on_track; - - // Track completion status - uint completion = 0; - - // Following the first-rest pattern described in TTCA - size_t count = 0; - while(count < n){ - // Read value from source - CVT_read read_value; - ·(TM·Array ,CVT_read)·fg.read(read_tm ,&read_value); - - // Apply mapping function to get write value - CVT_write write_value; - Core·Status status = map_fn(&read_value ,&write_value); - if(status != Core·Status·on_track) { - completion |= Core·Map·Completion·failed; - return status; - } - - // Write result to destination - ·(TM·Array ,CVT_write)·fg.write(write_tm ,&write_value); - - // Increment count - count++; - - // Check if we're at the rightmost position for read - bool read_rightmost = ·(TM·Array ,CVT_read)·fg.on_rightmost(read_tm); - if(read_rightmost) { - completion |= Core·Map·Completion·rightmost_read; - } - - // Check if we're at the rightmost position for write - bool write_rightmost = ·(TM·Array ,CVT_write)·fg.on_rightmost(write_tm); - if(write_rightmost) { - completion |= Core·Map·Completion·rightmost_write; - } - - // Break if either machine is at rightmost - if(read_rightmost || write_rightmost) break; - - // Step both machines - ·(TM·Array ,CVT_read)·fg.step(read_tm); - ·(TM·Array ,CVT_write)·fg.step(write_tm); - } - - return Core·Status·on_track; - } - - // Initialize the function given table - ·(Map·FG ,CVT_read ,CVT_write) ·(Map·fg ,CVT_read ,CVT_write) = { - .map = ·(Map ,CVT_read ,CVT_write)·map - ,.map_while = ·(Map ,CVT_read ,CVT_write)·map_while - ,.map_n = ·(Map ,CVT_read ,CVT_write)·map_n - }; - #endif // defined(CVT_read) && defined(CVT_write) - - //---------------------------------------- - // Copy functions implementation - //---------------------------------------- - - // Byte to byte copy - Local Core·Status Map·copy_byte_to_byte( - ·(TM·Array ,AU) *read_tm - ,·(TM·Array ,AU) *write_tm - ){ - #ifdef Map·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); - Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); - Core·Guard·if_return(chk); - #endif - - return ·(Map ,AU ,AU)·fg.map(read_tm, write_tm, Map·byte_to_byte_fn); - } - - // Hex to byte copy - Local Core·Status Map·copy_hex_to_byte( - ·(TM·Array ,uint16_t) *read_tm - ,·(TM·Array ,AU) *write_tm - ){ - #ifdef Map·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,read_tm ,Map·Msg·read_tm); - Core·Guard·fg.check(&chk ,1 ,write_tm ,Map·Msg·write_tm); - Core·Guard·if_return(chk); - #endif - - return To save on context only part of this file has been shown to you. You should retry this tool after you have searched inside the file with `grep -n` in order to find the line numbers of what you are looking for. diff --git "a/developer/deprecated\360\237\226\211/NN_Count_Digit.lib.c" "b/developer/deprecated\360\237\226\211/NN_Count_Digit.lib.c" deleted file mode 100644 index 9d604a9..0000000 --- "a/developer/deprecated\360\237\226\211/NN_Count_Digit.lib.c" +++ /dev/null @@ -1,118 +0,0 @@ -/* - A digit count followed by that many digits. - - Extent_Digit_Instance: - - 'NN' stands for Natural Number representation. - - 'Extent' refers to the maximum array index. - - 'Digit' specifies that the representation involves digits. - - 'Instance' differentiates this from the interface struct, ensuring clarity in alternative representations. -*/ - -#ifndef IFACE -#define NN_Extent_Digit·IMPLEMENTATION -#define IFACE -#endif - -#ifndef NN_Extent_Digit·IFACE -#define NN_Extent_Digit·IFACE - - typedef uint32_t Extent; - - // interface function signatures - // - typedef NN_Extent_Digit *(*NN_Extent_Digit·Copy·MemoryFault) - ( - Extent extent - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Copy) - ( - NN_Extent_Digit *original - ,NN_Extent_Digit·Copy·MemoryFault memory_fault - ); - - typedef void (*NN_Extent_Digit·Accumulate) - ( - NN_Extent_Digit *accumulator ,... - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Add) - ( - NN_Extent_Digit *summand ,... - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Multiply) - ( - NN_Extent_Digit *factor ,... - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Rotate_Right_Digit) - ( - Extent count - ,NN_Extent_Digit *a - ,NN_Extent_Digit *b - ,NN_Extent_Digit *c - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Rotate_Left_Digit) - ( - Extent count - ,NN_Extent_Digit *a - ,NN_Extent_Digit *b - ,NN_Extent_Digit *c - ); - - typedef NN_Extent_Digit *(*NN_Extent_Digit·Allocate·MemoryFault) - ( - Extent extent - ); - - // interface struct definition - // - typedef struct { - NN_Extent_Digit·Copy copy; - NN_Extent_Digit·Accumulate accumulate; - NN_Extent_Digit·Add add; - NN_Extent_Digit·Multiply multiply; - NN_Extent_Digit·Rotate_Right_Digit rotate_right_digit; - NN_Extent_Digit·Rotate_Left_Digit rotate_left_digit; - } NN_Extent_Digit; - - // an extent is a maximum array index - NN_Extent_Digit *NN_Extent_Digit·allocate(Extent extent, NN_Extent_Digit·Allocate·MemoryFault memory_fault); - void NN_Extent_Digit·deallocate(NN_Extent_Digit *unencumbered); - -#endif - -#ifdef NN_Extent_Digit·IMPLEMENTATION - - #include - #include - typedef uint32_t Digit; - - typedef struct { - Extent extent; - Digit a[]; - } Instance; - - NN_Extent_Digit *allocate(Extent extent, NN_Extent_Digit·Allocate·MemoryFault memory_fault){ - Extent allocation_size = sizeof(NN_Extent_Digit_Instance) + extent * sizeof(Digit) + sizeof(Digit); - Instance *instance = malloc(allocation_size); - if (!instance) { - return memory_fault ? memory_fault(extent) : NULL; - } - instance->extent = extent; - - // nope-> need to allocate an interface signature struct and assign the method - // function pointers to it. It will also need a field for holding the instance, - // yes, declare a new interface struct that has an extra field on the bottom for - // the instance pointer .. but then what of interface inheritance? hmmm. Perhaps - // that is better done by composition anyway. - return (NN_Extent_Digit *)instance; - } - - void deallocate(NN_Extent_Digit *unencumbered){ - free(unencumbered); - } - -#endif diff --git "a/developer/deprecated\360\237\226\211/N_32_test.cli.c" "b/developer/deprecated\360\237\226\211/N_32_test.cli.c" deleted file mode 100644 index 5cb2d2e..0000000 --- "a/developer/deprecated\360\237\226\211/N_32_test.cli.c" +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include "N_32.lib.h" // Include the module under test - -// Test function prototypes -bool test_copy(); -bool test_bitwise_operations(); -bool test_comparisons(); -bool test_arithmetic(); -bool test_shifts(); - -// Test array (null-terminated) -typedef bool (*TestFunction)(); -typedef struct { - TestFunction function; - const char *name; -} TestEntry; - -TestEntry test_list[] = { - { test_copy, "test_copy" }, - { test_bitwise_operations, "test_bitwise_operations" }, - { test_comparisons, "test_comparisons" }, - { test_arithmetic, "test_arithmetic" }, - { test_shifts, "test_shifts" }, - { NULL, NULL } // Null termination -}; - -// The test runner -int test_head() { - int pass_count = 0; - int fail_count = 0; - - for (TestEntry *entry = test_list; entry->function != NULL; entry++) { - if (!entry->function()) { - printf("Failed: %s\n", entry->name); - fail_count++; - } else { - pass_count++; - } - } - - printf("Tests passed: %d\n", pass_count); - printf("Tests failed: %d\n", fail_count); - return (fail_count == 0) ? 0 : 1; -} - -// Main function -int main(int argc, char **argv) { - return test_head(); -} - -//------------------------------------------------------------------------------ -// Test Implementations -//------------------------------------------------------------------------------ - -bool test_copy() { - N_32 a = { .d0 = 42 }; - N_32 b; - N_32·copy(&b, &a); - return b.d0 == 42; -} - -bool test_bitwise_operations() { - N_32 a = { .d0 = 0b101010 }; - N_32 b = { .d0 = 0b010101 }; - N_32 result; - - N_32·bit_and(&result, &a, &b); - if (result.d0 != 0b000000) return false; - - N_32·bit_or(&result, &a, &b); - if (result.d0 != 0b111111) return false; - - N_32·bit_complement(&result, &a); - if (result.d0 != ~0b101010) return false; - - return true; -} - -bool test_comparisons() { - N_32 a = { .d0 = 42 }; - N_32 b = { .d0 = 42 }; - N_32 c = { .d0 = 24 }; - - if (!N_32·eq(&a, &b)) return false; - if (N_32·eq(&a, &c)) return false; - if (!N_32·lt(&c, &a)) return false; - if (!N_32·gt(&a, &c)) return false; - - return true; -} - -bool test_arithmetic() { - N_32 a = { .d0 = 20 }; - N_32 b = { .d0 = 22 }; - N_32 result; - - if (N_32·add(&result, &a, &b) != N_32·Status·ok) return false; - if (result.d0 != 42) return false; - - if (N_32·subtract(&result, &b, &a) != N_32·Status·ok) return false; - if (result.d0 != 2) return false; - - return true; -} - -bool test_shifts() { - N_32 value = { .d0 = 1 }; - N_32 spill; - - if (N_32·shift_left(1, &spill, &value, NULL) != N_32·Status·ok) return false; - if (value.d0 != 2) return false; - - if (N_32·shift_right(1, &spill, &value, NULL) != N_32·Status·ok) return false; - if (value.d0 != 1) return false; - - return true; -} diff --git "a/developer/deprecated\360\237\226\211/Natural_32.lib.c" "b/developer/deprecated\360\237\226\211/Natural_32.lib.c" deleted file mode 100644 index da30e8d..0000000 --- "a/developer/deprecated\360\237\226\211/Natural_32.lib.c" +++ /dev/null @@ -1,179 +0,0 @@ -//---------------------------------------- -// Function Declarations - -void N_32_copy(N_32 *destination, N_32 *source); -void N_32_bit_and(N_32 *result, N_32 *a, N_32 *b); -void N_32_bit_or(N_32 *result, N_32 *a, N_32 *b); -void N_32_bit_complement(N_32 *result, N_32 *a); -N_32_Order N_32_compare(N_32 *a, N_32 *b); -bool N_32_lt(N_32 *a, N_32 *b); -bool N_32_gt(N_32 *a, N_32 *b); -bool N_32_eq(N_32 *a, N_32 *b); -N_32_Status N_32_add(N_32 *sum, N_32 *a, N_32 *b); -N_32_Status N_32_subtract(N_32 *difference, N_32 *a, N_32 *b); -N_32_Status N_32_multiply(N_32 *overflow, N_32 *result, N_32 *a, N_32 *b); -N_32_Status N_32_divide(N_32 *remainder, N_32 *quotient, N_32 *a, N_32 *b); -void N_32_shift_left(Extent shift, N_32 *sink, N_32 *result, N_32 *source); -void N_32_shift_right(Extent shift, N_32 *source, N_32 *result, N_32 *sink); - - -/* - N_32 - a processor native type - - For binary operations: a op b -> c - - To use N_32, first allocate a block of N_32. Do the arithmetic, - if any results need be kept, copy them to another block. Then deallocate - the block. Do not allocate numbers one at a time, or it would be slow. -*/ - -#ifndef IFACE -#define N_32_IMPLEMENTATION -#define IFACE -#endif - -#ifndef N_32_IFACE -#define N_32_IFACE - -#include -#include -#include -#include - -//---------------------------------------- -// Instance Data (Declaration Only) - -typedef uint32_t Extent; -typedef uint32_t Digit; - -typedef struct N_32 N_32; - -extern N_32 *N_32_zero; -extern N_32 *N_32_one; -extern N_32 *N_32_all_one_bit; -extern N_32 *N_32_lsb; -extern N_32 *N_32_msb; - -//---------------------------------------- -// Return Status - -typedef enum { - N_32_Status_ok = 0, - N_32_Status_overflow = 1, - N_32_Status_accumulator_overflow = 2, - N_32_Status_carry = 3, - N_32_Status_borrow = 4, - N_32_Status_undefined_divide_by_zero = 5, - N_32_Status_undefined_modulus_zero = 6 -} N_32_Status; - -typedef enum { - N_32_Order_lt = -1, - N_32_Order_eq = 0, - N_32_Order_gt = 1 -} N_32_Order; - -typedef N_32 *( *N_32_Allocate_MemoryFault )(Extent); - -//---------------------------------------- -// Interface - -typedef struct { - N_32 *( *allocate )(Extent, N_32_Allocate_MemoryFault); - void ( *deallocate )(N_32 *); - void ( *copy )(N_32 *, N_32 *); - void ( *bit_and )(N_32 *, N_32 *, N_32 *); - void ( *bit_or )(N_32 *, N_32 *, N_32 *); - void ( *bit_complement )(N_32 *, N_32 *); - N_32_Order ( *compare )(N_32 *, N_32 *); - bool ( *lt )(N_32 *, N_32 *); - bool ( *gt )(N_32 *, N_32 *); - bool ( *eq )(N_32 *, N_32 *); - N_32_Status ( *add )(N_32 *, N_32 *, N_32 *); - N_32_Status ( *subtract )(N_32 *, N_32 *, N_32 *); - N_32_Status ( *multiply )(N_32 *, N_32 *, N_32 *, N_32 *); - N_32_Status ( *divide )(N_32 *, N_32 *, N_32 *, N_32 *); - void ( *shift_left )(Extent, N_32 *, N_32 *, N_32 *); - void ( *shift_right )(Extent, N_32 *, N_32 *, N_32 *); -} N_32_Interface; - -extern const N_32_Interface N_32_interface; - -#endif - -#ifdef N_32_IMPLEMENTATION - -#ifndef LOCAL - -struct{ - Digit d0; -} N_32; - -N_32 N_32_constant[4] = { - { .d0 = 0 }, - { .d0 = 1 }, - { .d0 = ~(uint32_t)0 }, - { .d0 = 1 << 31 } -}; - -N_32 *N_32_zero = &N_32_constant[0]; -N_32 *N_32_one = &N_32_constant[1]; -N_32 *N_32_all_one_bit = &N_32_constant[2]; -N_32 *N_32_msb = &N_32_constant[3]; -N_32 *N_32_lsb = &N_32_constant[1]; - -#endif - -#ifdef LOCAL - -struct{ - Digit d0; -} N_32; - -Local void N_32_copy(N_32 *destination, N_32 *source) { - *destination = *source; -} - -Local void N_32_bit_and(N_32 *result, N_32 *a, N_32 *b) { - result->d0 = a->d0 & b->d0; -} - -Local void N_32_bit_or(N_32 *result, N_32 *a, N_32 *b) { - result->d0 = a->d0 | b->d0; -} - -Local void N_32_bit_complement(N_32 *result, N_32 *a) { - result->d0 = ~a->d0; -} - -Local N_32_Order N_32_compare(N_32 *a, N_32 *b) { - if (a->d0 < b->d0) return N_32_Order_lt; - if (a->d0 > b->d0) return N_32_Order_gt; - return N_32_Order_eq; -} - -Local void N_32_shift_left(Extent shift, N_32 *sink, N_32 *result, N_32 *source) { - *sink = *source; - result->d0 = source->d0 << shift; - sink->d0 = source->d0 >> (32 - shift); -} - -Local void N_32_shift_right(Extent shift, N_32 *source, N_32 *result, N_32 *sink) { - *sink = *source; - result->d0 = source->d0 >> shift; - sink->d0 = source->d0 << (32 - shift); -} - -Local const N_32_Interface N_32_interface = { - .copy = N_32_copy, - .bit_and = N_32_bit_and, - .bit_or = N_32_bit_or, - .bit_complement = N_32_bit_complement, - .compare = N_32_compare, - .shift_left = N_32_shift_left, - .shift_right = N_32_shift_right -}; - -#endif - -#endif diff --git "a/developer/deprecated\360\237\226\211/Natural_32_0.lib.c" "b/developer/deprecated\360\237\226\211/Natural_32_0.lib.c" deleted file mode 100644 index 335c402..0000000 --- "a/developer/deprecated\360\237\226\211/Natural_32_0.lib.c" +++ /dev/null @@ -1,278 +0,0 @@ -/* - N_32 - a processor native type - - For binary operations: a op b -> c - - To use N_32, first allocate a block of N_32. Do the arithmetic, - if any results need be kept, copy them to another block. Then deallocate - the block. Do not allocate numbers one at a time, or it would be slow. - -*/ - -#ifndef IFACE -#define N_32·IMPLEMENTATION -#define IFACE -#endif - -#ifndef N_32·IFACE -#define N_32·IFACE - - //---------------------------------------- - // The instance data - // no way to avoid adding this definition to the interface due to the use of inline functions - - typedef uint32_t Extent; - typedef uint32_t Digit;; - - struct N_32 { - Digit d0; - }; - - const N_32 N_32·zero; - const N_32 N_32·one; - const N_32 N_32·all_ones; - - - //---------------------------------------- - // error status return values, and error handlers - // - - typedef enum { - N_32·Status·ok = 0 - ,N_32·Status·overflow = 1 - ,N_32·Status·accumulator_overflow = 2 - ,N_32·Status·carry = 3 - ,N_32·Status·borrow = 4 - ,N_32·Status·undefined_divide_by_zero = 5 - ,N_32·Status·undefined_modulus_zero = 6 - } N_32·Status; - - typedef enum { - N_32·Order·lt = -1 // Less Than - ,N_32·Order·eq = 0 // Equal - ,N_32·Order·gt = 1 // Greater Than - } N_32·Order; - - typedef N_32 *( *N_32·Allocate·MemoryFault )(Extent); - - //---------------------------------------- - // inline interface - // - - // copy, convenience copy - - inline void N_32·copy(N_32 *destination ,N_32 *source){ - *destination = *source; - } - - inline void N_32·set_to_zero(N_32 *instance){ - instance->d0 = 0; - } - - inline void N_32·set_to_one(N_32 *instance){ - instance->d0 = 1; - } - - // bit operations - - inline void N_32·and(N_32 *result ,N_32 *a ,N_32 *b){ - result->d0 = a->d0 & b->d0; - } - - inline void N_32·or(N_32 *result ,N_32 *a ,N_32 *b){ - result->d0 = a->d0 | b->d0; - } - - inline void N_32·complement(N_32 *result ,N_32 *a){ - result->d0 = ~a->d0; - } - - inline void N_32·twos_complement(N_32 *result ,N_32 *a){ - result->d0 = ~a->d0 + 1; - } - - inline bool N_32·lsb_is_set(N_32 *a){ - return a->d0 & 0x0000001; - } - - inline bool N_32·msb_is_set(N_32 *a){ - return a->d0 & 0x8000000; - } - - // for low precision Natural, and large number of summands for accumulate/add/sub, overflow could overflow and thus this op would fail - inline N_32·Status N_32·accumulate(N_32 *overflow ,N_32 *accumulator ,...){ - va_list args; - va_start(args ,accumulator); - - uint64_t *sum = &accumulator->d0; - uint64_t *carry = &overflow->d0; - N_32 *current; - - while( (current = va_arg(args ,N_32 *)) ){ - *sum += current->d0; - if(*sum < current->d0){ // Overflow into carry - (*carry)++; - if(*carry == 0){ - va_end(args); - return N_32·Status·accumulator_overflow; - } - } - } - va_end(args); - - if(*carry == 0) return N_32·Status·ok; - return N_32·Status·OVERFLOW; - } - - inline N_32·Order N_32·compare(N_32 *a ,N_32 *b){ - if(a->d0 < b->d0) return N_32·order·lt; - if(a->d0 > b->d0) return N_32·order·gt; - return N_32·order·eq; - } - - inline bool N_32·lt(N_32 *a ,N_32 *b){ - return a->d0 < b->d0; - } - - inline bool N_32·gt(N_32 *a ,N_32 *b){ - return a->d0 > b->d0; - } - - inline bool N_32·eq(N_32 *a ,N_32 *b){ - return a->d0 == b->d0; - } - - // arithmetic operations - - inline N_32·Status N_32·add(N_32 *sum ,N_32 *a ,N_32 *b){ - uint64_t result = (uint64_t)a->d0 + (uint64_t)b->d0; - sum->d0 = (uint32_t)result; - return (result >> 32) ? N_32·Status·carry : N_32·Status·ok; - } - - inline N_32·Status N_32·next(N_32 *overflow ,N_32 *result ,N_32 *a){ - uint64_t sum = (uint64_t)a->d0 + (uint64_t)1; - result->d0 = (uint32_t)sum; - overflow->d0 = (uint32_t)(sum >> 32); - - if(overflow->d0 == 0) return N_32·status·ok; - return N_32·status·overflow; - } - - inline N_32·Status N_32·subtract(N_32 *difference ,N_32 *a ,N_32 *b){ - uint64_t diff = (uint64_t)a->d0 - (uint64_t)b->d0; - difference->d0 = (uint32_t)diff; - return (diff > a->d0) ? N_32·Status·borrow : N_32·Status·ok; - } - - inline N_32·Status N_32·multiply(N_32 *overflow ,N_32 *result ,N_32 *a ,N_32 *b){ - uint64_t product = (uint64_t)a->d0 * (uint64_t)b->d0; - result->d0 = (uint32_t)product; - overflow->d0 = (uint32_t)(product >> 32); - - if(overflow->d0 == 0) return N_32·status·ok; - return N_32·status·overflow; - } - - inline N_32·Status N_32·divide(N_32 *remainder ,N_32 *quotient ,N_32 *a ,N_32 *b){ - if(b->d0 == 0) return N_32·Status·undefined_divide_by_zero; - - quotient->d0 = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient->d0 * b->d0); - - return N_32·Status·ok; - } - - inline N_32·Status N_32·modulus(N_32 *remainder ,N_32 *a ,N_32 *b){ - if(b->d0 == 0) return N_32·Status·undefined_modulus_zero; - uint32_t quotient = a->d0 / b->d0; - remainder->d0 = a->d0 - (quotient * b->d0); - return N_32·Status·ok; - } - - // shift - inline void N_32·shift_left(Extent shift ,N_32 *sink ,N_32 *result ,N_32 *source){ - *sink = *source; - result->d0 = source->d0 << shift; - sink->d0 = source->d0 >> (32 - shift); - } - - inline void N_32·shift_right(Extent shift ,N_32 *source ,N_32 *result ,N_32 *sink){ - *sink = *source; - result->d0 = source->d0 >> shift; - sink->d0 = source->d0 << (32 - shift); - } - - inline void N_32·arithmetic_shift_right(Extent shift ,N_32 *result ,N_32 *sink){ - N_32 source; - N_32 source = msb_is_set(result) ? N_32·all_ones : N_32·zero; - N_32·shift_right(shift ,&source ,result ,sink); - } - - //---------------------------------------- - // compiled interface - - typedef struct { - N_32·Allocate allocate; - N_32·Zero zero; - N_32·One one; - N_32·Deallocate deallocate; - } N_32·Interface; - - extern const N_32·Interface N_32·interface; - - -#endif - -#ifdef N_32·IMPLEMENTATION - - #include - #include - - const N_32 N_32·zero = { .d0 = 0 }; - const N_32 N_32·one = { .d0 = 1 }; - const N_32 N_32·all_ones = { .d0 = ~(uint32_t)0 }; - - // the allocate an array of N_32 - N_32 *N_32·allocate( Extent extent ,N_32 *(*memory_fault)(Extent) ){ - N_32 *instance = malloc((extent + 1) * sizeof(N_32) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - N_32 *N_32·alloc_zero( Extent extent ,N_32 *(*memory_fault)(Extent) ){ - N_32 *instance = calloc( extent + 1 ,sizeof(N_32) ); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - return instance; - } - - // initialize all with x - N_32 *N_32·alloc_x(Extent extent ,N_32 *(*memory_fault)(Extent) ,N_32 *x){ - N_32 *instance = malloc((extent + 1) * sizeof(N_32)); - if(!instance){ - return memory_fault ? memory_fault(extent) : NULL; - } - N_32 *pt = instance; - while( pt <= instance + extent ){ - *pt = *x; - pt++; - } - return instance; - } - - const N_32·Interface N_32·interface = { - .allocate = N_32·allocate - ,.allocate_zero = N_32·alloc_zero - ,.allocate_all_x = N_32·alloc_x - ,.deallocate = N_32·deallocate - }; - - void N_32·deallocate(N_32 *unencumbered){ - free(unencumbered); - } - -#endif diff --git "a/developer/deprecated\360\237\226\211/adding_new_N_types.org" "b/developer/deprecated\360\237\226\211/adding_new_N_types.org" deleted file mode 100644 index efb018b..0000000 --- "a/developer/deprecated\360\237\226\211/adding_new_N_types.org" +++ /dev/null @@ -1,23 +0,0 @@ -#+TITLE: Adding new N types -#+AUTHOR: Thomas - -* Project Name - -N == Natural Number, aka 'unsigned int'. - -* Pencil directories / pencil suffix. - -The files in the pencil directory, e.g. cc🖉, are 'authored files'. The program 'rm_na' will not delete them. Use 'rm_na" in scripts. - -* Parameterized types - -The templated N type allows a user to specify a digit type, and number of digits. To generate a new multiple digit type, go into the `Python🖉/` directory, add a new write section to the `fill_template` file, and fill in the digit type and number of digits the new type will have. Run `fill_template` and the synthesized file will be written to the `cc/` directory. - - -* Custom types - -Some processors will have processor native types that the templating scheme does not take advantage of. - -Put custom `N_.lib.cc` files in the `cc🖉/` directory. Or new templates in the `Python🖉` directory. Be sure the file name is distinct from existing types, because the testing setup installs all the files. - - diff --git "a/developer/deprecated\360\237\226\211/copy.lib.c" "b/developer/deprecated\360\237\226\211/copy.lib.c" deleted file mode 100644 index 58ed27e..0000000 --- "a/developer/deprecated\360\237\226\211/copy.lib.c" +++ /dev/null @@ -1,117 +0,0 @@ -/* -We pay attention to word alignment on the read side. Writes are probably -buffered so alignment is not as big of a performance issue. -*/ -void *Copy·region(void *read0 ,void *read1 ,void *write0){ - - uint8_t *r = (uint8_t *)read0; - uint8_t *r1 = (uint8_t *)read1; - uint8_t *w = (uint8_t *)write0; - - //---------- - // The potentially unaligned initial part (align read pointer). - if( (uintptr_t)r & 0x7 ){ - - // At this point r is known to be unaligned. - // ORing in `0x7` adds at most six - uint8_t *r01 = (uint8_t *)((uintptr_t)r | 0x7); - - // then the read interval is very small - if(r01 >= r1){ - while(r < r1){ - *w++ = *r++; - } - return w; - } - - // Copy up to alignment boundary - do{ - *w++ = *r++; - }while(r <= r01); - } - // r is now aligned, but *r has not yet been copied - - - //---------- - // The bulk copy part (w is still possibly unaligned, but r is aligned) - uint8_t *r10 = (uint8_t *)((uintptr_t)r1 & ~(uintptr_t)0x7); - - while(r < r10){ - *(uint64_t *)w = *(uint64_t *)r; - w += 8; - r += 8; - } - - // if r1 was aligned then r10 == r1 and we are done - if(r == r1) w; - - //---------- - // The ragged tail, up to 7 bytes - do{ - *w++ = *r++; - }while(r < r1); - - return w; - -} - -void *Copy·reverse_byte_order(void *read0 ,void *read1 ,void *write0){ - - uint8_t *r = (uint8_t *)read1; // Start from the last byte - uint8_t *r0 = (uint8_t *)read0; - uint8_t *w = (uint8_t *)write0; - - // For r to be aligned, means that it points to a 64 bit word, and the byte it - // points was the last copied coming out of the prior loop. This is due to going in - // leftward through the array, and the part to the rightward already having - // been done. - - //---------- - // The potentially unaligned initial part (align read pointer). - if( (uintptr_t)r & 0x7 != 0){ - - // At this point r is known to be unaligned. - // ANDing with `~0x7` moves it **downward** to the nearest lower alignment. - uint8_t *r10 = (uint8_t *)((uintptr_t)r & ~(uintptr_t)0x7); - - // If the read interval is very small - if(r10 < r0){ - while(r > r0){ - *w++ = *--r; - } - return w; - } - - // Copy down to alignment boundary - do{ - *w++ = *--r; - }while(r > r10); - } - // r is now aligned, and *r has been copied - - //---------- - // The bulk copy part - - // the first aligned address greater than or equal to r0 - uint8_t *r01 = (uint8_t *)( ((uintptr_t)r0 + (uintptr_t)0x7) & ~(uintptr_t)0x7); - - // as both r and r01 are aligned, r == r01 upon exit of this loop - while(r > r01){ - r -= 8; - *(uint64_t *)w = __builtin_bswap64(*(uint64_t *)r); - w += 8; - } - - // If r0 was aligned then r01 == r0 and we are done - if(r < r0) return w; - - //---------- - // The ragged tail, up to 7 bytes - do{ - *w++ = *--r; - }while(r >= r0); - - return w; -} - - diff --git "a/developer/deprecated\360\237\226\211/scatch.c" "b/developer/deprecated\360\237\226\211/scatch.c" deleted file mode 100644 index abf9619..0000000 --- "a/developer/deprecated\360\237\226\211/scatch.c" +++ /dev/null @@ -1,580 +0,0 @@ - // some aliases to make things a little easier to read - #undef TM - #define TM ·(TM ,TM·CVT) - #undef EXTENT_T - #define EXTENT_T ·(extent_t ,TM·CVT) - - //---------------------------------------- - // TM Array implementation, not TM·CVT differentiated - - // some aliases to make things a little easier to read - #undef TM - #define TM ·(TM ,TM·CVT) - #undef EXTENT_T - #define EXTENT_T ·(extent_t ,TM·CVT) - #undef TM·ARRAY - #define TM·ARRAY ·(TM ,ARRAY) - - typedef struct ·(TM·ARRAY ,Tableau){ - TM·CVT *hd; - TM·CVT position[]; - EXTENT_T extent; - } ·(TM·ARRAY ,Tableau); - - Local TM·Tape·Topo ·(TM·ARRAY ,Tape·topo)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - if(t->extent == 0) return TM·Tape·Topo·singleton; - return TM·Tape·Topo·segment; - } - Local bool ·(TM·ARRAY ,Tape·bounded)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return ·(TM·ARRAY ,Tape·topo)(tm) & TM·Tape·Topo·bounded; - } - Local EXTENT_T ·(TM·ARRAY ,Tape·extent)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return t->extent; - } - - Local TM·Head·Status ·(TM·ARRAY ,Head·status)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - if(!t->hd) return TM·Head·Status·dismounted; - if(t->hd == tm->position) return TM·Head·Status·leftmost; - - TM·CVT *rightmost_pt = t->position + t->extent; - if(t->hd == rightmost_pt) TM·Head·Status·rightmost; - if(t->hd < tm->position || tm->hd > rightmost_pt) - return TM·Head·Status·out_of_area; - - return TM·Head·Status·interim; - } - Local bool ·(TM·ARRAY ,Head·dismounted)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·dismounted; - } - Local bool ·(TM·ARRAY ,Head·on_tape)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·on_tape; - } - Local bool ·(TM·ARRAY ,Head·on_leftmost)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·leftmost; - } - Local bool ·(TM·ARRAY ,Head·on_rightmost)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return ·(TM·ARRAY ,Head·status)(tm) & TM·Head·Status·rightmost; - } - - // does nothing if the hd is already mounted - Local void ·(TM·ARRAY ,mount)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - if( !t->hd ) t->hd = t->position; - } - - Local void dismount ·(TM·ARRAY ,dismount)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - t->hd = NULL; - } - - // does nothing if the hd is not mounted - Local void ·(TM·ARRAY ,step)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - t->hd++; - } - - Local void ·(TM·ARRAY ,step_left)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - t->hd--; - } - - Local void ·(TM·ARRAY ,rewind)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - ·(TM·ARRAY ,Head·dismounted)(tm) return; - t->hd = t->position; - } - - Local TM·CVT ·(TM·ARRAY ,read)(TM tm){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - return *t->hd; - } - - Local void ·(TM·ARRAY ,write)(TM tm ,TM·CVT *remote_pt){ - ·(TM·ARRAY ,Tableau) *t = (·(TM·ARRAY ,Tableau) *) tm.tableau; - *remote_pt = *t->hd; - } - - Local TM·Binding TM·fg = { - - .Tape·topo = ·(TM·ARRAY ,Tape·topo) - ,.Tape·bounded = ·(TM·ARRAY ,Tape·bounded) - ,.Tape·extent = ·(TM·ARRAY ,Tape·extent) - - ,.Head·status = ·(TM·ARRAY ,Head·status) - ,.Head·dismounted = ·(TM·ARRAY ,Head·dismounted) - ,.Head·on_tape = ·(TM·ARRAY ,Head·on_tape) - ,.Head·on_leftmost = ·(TM·ARRAY ,Head·on_leftmost) - ,.Head·on_rightmost = ·(TM·ARRAY ,Head·on_rightmost) - - ,.mount = ·(TM·ARRAY ,mount) - ,.dismount = ·(TM·ARRAY ,dismount) - - ,.step = ·(TM·ARRAY ,step) - ,.step_right = ·(TM·ARRAY ,step) - ,.step_left = ·(TM·ARRAY ,step_left) - ,.rewind = ·(TM·ARRAY ,rewind) - - ,.read = ·(TM·ARRAY ,read) - ,.write = ·(TM·ARRAY ,write) - - }; - - - - - - - - -................................................................................ - - //----------------------------------- - // generic call wrappers - - Local TM·Tape·Topo TM·Tape·topo(TM *tm){ - return tm->fg.Tape·topo(tm); - } - Local TM·Tape·Topo TM·Tape·bounded(TM *tm){ - return TM·tape_top(tm) & TM·Tape·Topo·bounded); - } - - Local TM·Head·Status TM·head_status(TM *tm){ - return tm->fg.status(tm ,result); - } - Local TM·Head·Status TM·head_on_tape(TM *tm){ - return TM·status(tm) & TM·Head·Status·on_tape; - } - - // does nothing if the head is already mounted - Local Core·Status TM·mount(TM *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk, 1, tm, TM·Msg·tm); - Core·Guard·if_return(chk); - #endif - if( !TM·head_on_tape(tm) ) return Core·Status·on_track; - return tm->fg.mount(tm); - } - - // does nothing if the head is already dismounted - Local Core·Status TM·dismount(TM *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk, 1, tm, TM·Msg·tm); - Core·Guard·if_return(chk); - #endif - if( TM·head_status(TM *tm) & TM·Head·Status·dismounted) ) return Core·Status·on_track; - return tm->fg.dismount(tm); - } - - #define TM·macro·bool_tm(name) - Local bool name(TM *tm){ \ - #ifdef TM·DEBUG \ - Core·Guard·init_count(chk); \ - Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); \ - Core·Guard·assert(chk); \ - #endif \ - return tm->fg.name(tm); \ - } - - Local bool TM·macro·bool_tm(on_leftmost); - Local bool TM·macro·bool_tm(on_rightmost); - Local bool TM·macro·bool_tm(step); - Local bool TM·macro·bool_tm(step_left); - Local bool TM·macro·bool_tm(rewind); - - //---------------------------------------- - // Initialization for TM·fg - - - #endif // ifndef TM·CVT - - //----------------------------------- - // TM·CVT dependent functions - - #ifdef TM·CVT - - Local ·(extent_t ,TM·CVT) ·(TM ,TM·CVT)·extent(TM *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,TM·Tape·bounded(tm) ,"Tape is not bounded."); - Core·Guard·assert(chk); - #endif - return tm->fg.extent(tm); - } - - Local TM·CVT TM·read(TM *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); - Core·Guard·assert(chk); - #endif - return tm->fg.read(tm); - } - - Local void TM·write(TM *tm ,TM·CVT *write_pt){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check( &chk ,1 ,TM·head_on_tape(tm) ,TM·Msg·head); - Core·Guard·fg.check( &chk ,1 ,write_pt ,"Given NULL write_pt"); - Core·Guard·assert(chk); - #endif - return tm->fg.write(tm ,write_pt); - } - - Local ·(TM ,TM·CVT)·Binding ·(TM ,TM·CVT)·fg = { - .parent = TM·fg - ,.extent = ·(TM ,TM·CVT)·extent - ,.read = ·(TM ,TM·CVT)·read - ,.write = ·(TM ,TM·CVT)·write - }; - - #endif // ifdef TM·CVT - - - - #endif // ifdef TM·CVT - -#endif // LOCAL - -//-------------------------------------------------------------------------------- -// Library - compiled into a lib.a file by the current make -// TM currently has no library components -//-------------------------------------------------------------------------------- -#ifdef LIBRARY -#endif - -//-------------------------------------------------------------------------------- -// undef the template parameters -//-------------------------------------------------------------------------------- -#undef TM·CVT - - //---------------------------------------- - // TM·Array implementation - //---------------------------------------- - - /* - TM·Array is bound to a tape with head on the tape via mount_pe or mount_pp. - - Once a tape is bound, it remains so, though the head can be dismounted - and remounted. - - C lacks an allocation-bound initialization feature, so the library user is responsible - to make sure a TM·Array has been initialized before use. - - The TM·Array has no locking facility, so it is not possible to know if it is in use. - - Re-initializing a TM·Array while in use can lead to unspecified badness. Use `rewind` instead. - */ - - //---------------------------------------- - // TM·Array implementation - //---------------------------------------- - - #ifndef TM·CVT - - //----------------------------------- - // common error messages - - const char *TM·Array·Msg·tm="given NULL tm"; - const char *TM·Array·Msg·flag="given NULL flag pointer"; - const char *TM·Array·Msg·result="given NULL result pointer"; - const char *TM·Array·Msg·status="bad head status"; - - - #endif // #ifndef TM·CVT - - #ifdef TM·CVT - - - - - - // check the Tape·topo to make sure tape has extent before calling this - // `extent·TM·CVT` returns the index to the rightmost cell in the array. - Local ·(extent_t ,TM·CVT) ·(TM·Array ,TM·CVT)·extent(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Tape·Topo Tape·topo = Core·Tape·Topo·mu; - Core·Status status = ·(TM·Array ,TM·CVT)·Tape·topo(tm ,&Tape·topo); - bool good_Tape·topo = - (status == Core·Status·on_track) && (Tape·topo & Core·Tape·Topo·finite_nz) - ; - Core·Guard·fg.check(&chk ,1 ,good_Tape·topo ,"Tape does not have an extent."); - Core·Guard·assert(chk); - #endif - - *result = tm->extent; - return Core·Status·on_track; - } - - //----------------------------------- - // TM·Array.area implementation - - Local Core·Status ·(TM·Array ,TM·CVT)·mount_pe( - ·(TM·Array ,TM·CVT) *tm ,TM·CVT *position ,·(extent_t ,TM·CVT) extent - ){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); - Core·Guard·fg.check(&chk ,1 ,position ,"Given NULL position."); - Core·Guard·if_return(chk); - #endif - tm->position = position; - tm->extent = extent; - tm->hd = position; // mount the head on the origin cell - return Core·Status·on_track; - } - - // If size of TM·CVT is not a power of two this can perform a divide - Local Core·Status ·(TM·Array ,TM·CVT)·mount_pp( - ·(TM·Array ,TM·CVT) *tm ,TM·CVT *pos_leftmost ,TM·CVT *pos_rightmost - ){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,pos_leftmost ,"Null pos_leftmost."); - Core·Guard·fg.check(&chk ,1 ,pos_rightmost ,"Null pos_rightmost."); - if(pos_leftmost && pos_rightmost){ - Core·Guard·fg.check(&chk ,1 ,pos_rightmost >= pos_leftmost - ,"pos_rightmost < pos_leftmost" - ); - } - Core·Guard·if_return(chk); - #endif - - ·(extent_t ,TM·CVT) extent = pos_rightmost - pos_leftmost); - return ·(TM·Array ,TM·CVT)·mount_pe(tm ,pos_leftmost ,extent); - } - - //----------------------------------- - // base Tape Machine operations - - Local Core·Status ·(TM·Array ,TM·CVT)·mount(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); - if(tm) Core·Guard·fg.check(&chk ,1 ,tm->position ,TM·Array·Msg·position); - Core·Guard·if_return(chk); - #endif - - // mounting an already mounted head does nothing ,perhaps you meant `rewind`? - if(!tm->hd) tm->hd = tm->position; - return Core·Status·on_track; - } - - Local Core·Status ·(TM·Array ,TM·CVT)·dismount(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,tm ,TM·Array·Msg·tm); - Core·Guard·if_return(chk); - #endif - - tm->hd = NULL; - return Core·Status·on_track; - } - - Local TM·Head·Status ·(TM·Array ,TM·CVT)·head_status(TM *tm){ - if(!tm || !tm->position) return TM·Head·Status·mu; - if(!tm->hd) return TM·Head·Status·dismounted; - if(tm->hd == tm->position) return TM·Head·Status·leftmost; - - TM·CVT *rightmost_pt = tm->position + tm->extent; - if(tm->hd == rightmost_pt) TM·Head·Status·rightmost; - if(tm->hd < tm->position || tm->hd > rightmost_pt) - return TM·Head·Status·out_of_area; - - return TM·Head·Status·interim; - } - - bool ·(TM·Array ,TM·CVT)·can_read(·(TM·Array ,TM·CVT) *tm){ - return tm && tm->position && tm->hd; - } - - // can_read was true - bool ·(TM·Array ,TM·CVT)·on_origin(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - return tm->hd == tm->position; - } - - // can_read was true - bool ·(TM·Array ,TM·CVT)·on_rightmost(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - return tm->hd == tm->position; - } - - void ·(TM·Array ,TM·CVT)·step(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - tm->hd++; - } - - void ·(TM·Array ,TM·CVT)·step_left(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - tm->hd--; - } - - void ·(TM·Array ,TM·CVT)·rewind(·(TM·Array ,TM·CVT) *tm){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - tm->hd = tm->position; - } - - // tm_can_read must be true for both machines. - void ·(TM·Array ,TM·CVT)·copy_datum(·(TM·Array ,TM·CVT) *tm_read ,·(TM·Array ,TM·CVT) *tm_write){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm_read ,flag) == Control·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"tm_read head off track"); - s = ·(TM·Array ,TM·CVT)·head_on_format(tm_write ,flag) == Control·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"tm_write head off track"); - Core·Guard·assert(chk); - #endif - - *(tm_write->hd) = *(tm_read->hd); - return Core·Status·on_track; - } - - void ·(TM·Array ,TM·CVT)·read(·(TM·Array ,TM·CVT) *tm ,TM·CVT *read_pt){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - - *read_pt = *(tm->hd); - } - - - // step_right is a synonym for step - - - //---------------------------------------- - // Initialization for ·(TM·Array ,TM·CVT)·fg - - Local ·(TM·Array ,TM·CVT)·Binding ·(TM·Array ,TM·CVT)·fg = { - .tape = { - .Tape·topo = ·(TM·Array ,TM·CVT)·Tape·topo - .extent = ·(TM·Array ,TM·CVT)·extent - } - - ,.area = { - .mount_pe = ·(TM·Array ,TM·CVT)·mount_pe - ,.mount_pp = ·(TM·Array ,TM·CVT)·mount_pp - } - - ,.mount = ·(TM·Array ,TM·CVT)·mount - ,.dismount = ·(TM·Array ,TM·CVT)·dismount - - ,.status = ·(TM·Array ,TM·CVT)·status - ,.head_on_format = ·(TM·Array ,TM·CVT)·head_on_format - - ,.can_read = ·(TM·Array ,TM·CVT)·can_read - ,.on_origin = ·(TM·Array ,TM·CVT)·on_origin - ,.on_rightmost = ·(TM·Array ,TM·CVT)·on_rightmost - - ,.step = ·(TM·Array ,TM·CVT)·step - ,.step_left = ·(TM·Array ,TM·CVT)·step_left - ,.step_right = ·(TM·Array ,TM·CVT)·step_right // Synonym for step - ,.rewind = ·(TM·Array ,TM·CVT)·rewind - - ,.copy_datum = ·(TM·Array ,TM·CVT)·copy_datum - ,.read = ·(TM·Array ,TM·CVT)·read - ,.write = ·(TM·Array ,TM·CVT)·write - - }; - - -//-------------------------------------------------------------------------------- - -// scrat - - -void ·(TM·Array ,TM·CVT)·write(·(TM·Array ,TM·CVT) *tm ,TM·CVT *write_pt){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - bool flag = true ,s; - s = ·(TM·Array ,TM·CVT)·head_on_format(tm ,flag) == Core·Status·on_track; - Core·Guard·fg.check(&chk ,1 ,s && flag ,"head off format"); - Core·Guard·assert(chk); - #endif - - *(tm->hd) = *write_pt; -} - - //----------------------------------- - // TM struct initializers - - Local Core·Status TM·mount_pe( - TM *tm ,TM·CVT *position ,·(extent_t ,TM·CVT) extent - ){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,tm ,TM·Msg·tm); - Core·Guard·fg.check(&chk ,1 ,position ,"Given NULL position."); - Core·Guard·if_return(chk); - #endif - tm->position = position; - tm->extent = extent; - tm->hd = position; // mount the head on the origin cell - return Core·Status·on_track; - } - - // If size of TM·CVT is not a power of two this can perform a divide - Local Core·Status TM·mount_pp( - TM *tm ,TM·CVT *pos_leftmost ,TM·CVT *pos_rightmost - ){ - #ifdef TM·DEBUG - Core·Guard·init_count(chk); - Core·Guard·fg.check(&chk ,1 ,pos_leftmost ,"Null pos_leftmost."); - Core·Guard·fg.check(&chk ,1 ,pos_rightmost ,"Null pos_rightmost."); - if(pos_leftmost && pos_rightmost){ - Core·Guard·fg.check(&chk ,1 ,pos_rightmost >= pos_leftmost - ,"pos_rightmost < pos_leftmost" - ); - } - Core·Guard·if_return(chk); - #endif - - ·(extent_t ,TM·CVT) extent = pos_rightmost - pos_leftmost); - return TM·mount_pe(tm ,pos_leftmost ,extent); - } - diff --git "a/developer/deprecated\360\237\226\211/test_Natural_32_0.cli.c" "b/developer/deprecated\360\237\226\211/test_Natural_32_0.cli.c" deleted file mode 100644 index 2c344e7..0000000 --- "a/developer/deprecated\360\237\226\211/test_Natural_32_0.cli.c" +++ /dev/null @@ -1,88 +0,0 @@ - -#include "environment.h" -#include -#include -#include - -#define IFACE -#include "Natural_32.lib.c" - -#define TEST_COUNT 10 // Adjust as needed - -jmp_buf test_env; -const char *current_test = NULL; - -void signal_handler(int sig){ - printf("Failed due to Exception: %s (Signal %d)\n", current_test, sig); - longjmp(test_env, 1); -} - -int main(void){ - bool test_results[TEST_COUNT] = {false}; - const char *test_names[TEST_COUNT] = { - "Addition", - "Subtraction", - "Multiplication", - "Division", - "Modulus", - "Shift Left", - "Shift Right", - "Comparison", - "Complement", - "Two's Complement" - }; - - int pass_count = 0, fail_count = 0; - bool *test_ptr = test_results; - const char **name_ptr = test_names; - - // Install signal handler - signal(SIGFPE, signal_handler); - signal(SIGSEGV, signal_handler); - signal(SIGABRT, signal_handler); - - Natural_32 a, b, result, overflow; - Natural_32·set_to_zero(&a); - Natural_32·set_to_one(&b); - - // Macro to run tests with proper failure messaging - #define RUN_TEST(expr) \ - current_test = *name_ptr; \ - if(setjmp(test_env) == 0){ \ - if(expr){ \ - *test_ptr++ = true; \ - pass_count++; \ - } else { \ - printf("Failed due to Bad Return Value: %s\n", *name_ptr); \ - *test_ptr++ = false; \ - fail_count++; \ - } \ - } else { \ - *test_ptr++ = false; \ - fail_count++; \ - } \ - name_ptr++; - - RUN_TEST(Natural_32·add(&result, &a, &b) == Natural_32·Status·ok && result.d0 == 1); - RUN_TEST(Natural_32·subtract(&result, &b, &a) == Natural_32·Status·ok && result.d0 == 1); - RUN_TEST(Natural_32·multiply(&overflow, &result, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0); - RUN_TEST(Natural_32·divide(&result, &overflow, &b, &b) == Natural_32·Status·ok && result.d0 == 1 && overflow.d0 == 0); - RUN_TEST(Natural_32·modulus(&result, &b, &b) == Natural_32·Status·ok && result.d0 == 0); - - Natural_32·shift_left(1, &overflow, &result, &b); - RUN_TEST(result.d0 == 2 && overflow.d0 == 0); - - Natural_32·shift_right(1, &b, &result, &overflow); - RUN_TEST(result.d0 == 0 && overflow.d0 == 1); - - RUN_TEST(Natural_32·compare(&a, &b) == Natural_32·Order·lt); - - Natural_32·complement(&result, &a); - RUN_TEST(result.d0 == ~0); - - Natural_32·twos_complement(&result, &b); - RUN_TEST(result.d0 == (uint32_t)(-1)); - - printf("Pass: %d, Fail: %d\n", pass_count, fail_count); - return fail_count > 0 ? 1 : 0; -} diff --git a/developer/document/.githolder b/developer/document/.githolder new file mode 100644 index 0000000..e69de29 diff --git a/developer/document/Binding.org b/developer/document/Binding.org new file mode 100644 index 0000000..31ca2a4 --- /dev/null +++ b/developer/document/Binding.org @@ -0,0 +1,170 @@ +#+TITLE: FG Tables and Bindings in RT C +#+AUTHOR: Sorein +#+DATE: 2025-04-25 + +* 1. Overview: FG Tables Revisited + +RT C uses **Function-Given (FG) Tables** to group related functions that all take a **common first argument**. This enables flexible polymorphism and modular encapsulation in pure C. + +For a full explanation of FG tables and an example based on `Core`, see: + +**📎 [[file:fg_tables_core.org][FG Tables in RT C — The Core Example]]** + +In this model: +- Each module defines a **binding struct** (e.g. `TM·AU`, `Core`, etc). +- All methods take the binding as their first argument. +- A function pointer table (FG table) is associated with the binding. +- A macro `Module·call(binding ,method ,...)` expands to safe, type-dispatched function calls. + +* 2. The Tableau: Abstract Identity of the Binding + +In the FG model, we say that functions are *given* a binding. The binding is always a `struct` that pairs: + +1. A **tableau** (a pointer to the module-specific state) +2. An **FG table** (function dispatch table) + +The **tableau** is the key abstraction. + +- It is typically **only ever passed to the functions** in the FG table. +- Therefore, the FG table **defines the meaning** of the tableau: it specifies what functions expect and how they interpret the tableau pointer. +- The tableau has a *type in memory* (e.g. `TM·AU·Array·Tableau`), but also an **abstract type**, as defined by the FG table itself. + +In that sense, the FG table acts as **the type descriptor for the tableau**. + +* 3. Binding.lib.c + +The module `Binding.lib.c` defines the canonical layout of an FG-style binding. + +Below is the full source (excluding comments), organized by section. + +**FACE:** +#+BEGIN_SRC c +#ifndef Binding·FACE +#define Binding·FACE + +typedef struct{ + void *tableau; + void *FG; +} Binding; + +#endif +#+END_SRC + +This is the public interface. The type `Binding` is a generic struct that holds two pointers: +- `tableau`: the implementation-specific data (tape, buffer, object, etc) +- `FG`: pointer to a module-specific function table + +**IMPLEMENTATION:** +#+BEGIN_SRC c +#ifdef Binding·IMPLEMENTATION +#endif +#+END_SRC + +No definitions are required here—the binding struct has no behavior of its own. + +**LOCAL:** +#+BEGIN_SRC c +#ifdef LOCAL +#ifndef Binding·LOCAL +#define Binding·LOCAL + +#include +#include + +#endif +#endif +#+END_SRC + +These are the headers required to define the structure and the environment. It also follows the **RT C sectioning model** described in: + +**📎 [[file:sections.org][RT C File Structure and Sectioning]]** + +* 4. Template Use + +Although `Binding.lib.c` does not directly use template parameters, it is often **included repeatedly** in templated modules to create per-instance bindings. + +For example: +#+BEGIN_SRC c +#define _TM·CVT_ AU +#include "TM.lib.c" +#define SET__Binding__TM·AU +#+END_SRC + +The template name `_TM·CVT_` is used to create: +- `typedef struct TM·AU TM·AU;` +- `typedef struct TM·AU·Array·Tableau TM·AU·Array·Tableau;` +- `TM·AU` instances, each of which is a `Binding` with layout and dispatch tied to a particular tableau type. + +See: + +**📎 [[file:template_box_example.org][Templating in RT C — The Box Example]]** + +* 5. The Binding Struct + +Here’s the struct that every FG-style binding uses: + +#+BEGIN_SRC c +typedef struct{ + void *tableau; + void *FG; +} Binding; +#+END_SRC + +The tableau and FG pointers are opaque to the caller. They are interpreted by the functions in the FG table. + +**The binding is the concrete object passed around the system.** + +In most modules, this struct is **re-wrapped** in a typedef, e.g.: + +#+BEGIN_SRC c +typedef Binding TM·AU; +#+END_SRC + +This means that in function signatures and argument lists, the **binding is visible under its module-specific name**, even though all bindings have the same physical layout. + +This separation allows: +- Static type safety at the source level (per module) +- Shared representation at the binary level + +* 6. Example Usage + +Suppose we define a tape machine `TM·AU` over a byte array. The setup might look like: + +#+BEGIN_SRC c +AU tape[] = {0x01 ,0x02 ,0x03}; +extent_t·AU extent = 2; + +TM·AU·Array·Tableau t; +TM·AU tm = TM·AU·Array·init_pe(&t ,tape ,extent); + +if( TM·AU·call(tm ,on_tape) ){ + uchar x = TM·AU·call(tm ,read); + printf("Head reads: %02x\n", x); +} +#+END_SRC + +Here: +- `tm` is a `TM·AU` binding — a `struct` with `.tableau = &t`, and `.FG = &TM·AU·Array·fg`. +- The functions in the FG table dereference `tm.tableau` into the expected type. +- `TM·AU·call` wraps method access, validating the binding under debug builds. + +* 7. Summary + +A **binding** in RT C is: +- A pair of `(tableau pointer, FG table pointer)` +- Constructed per module or template instantiation +- Passed around as the first argument to all FG methods +- Given a distinct *type name* (like `TM·AU`) to encode its role + +A **tableau** is: +- The backing data storage (often a `struct`) +- Interpreted only by the FG methods that operate on it +- Abstractly defined by the FG table it's paired with + +This design gives RT C the benefits of: +- Polymorphism +- Type encapsulation +- Dispatch +- Template instantiation + +All in a clean, structured C style, without runtime type metadata or compiler extensions. diff --git a/developer/document/C_features_needed.org b/developer/document/C_features_needed.org new file mode 100644 index 0000000..ca3bee2 --- /dev/null +++ b/developer/document/C_features_needed.org @@ -0,0 +1,53 @@ + +1. Cpp needs namespaces. The '·' notation seems to accomplish most of what is needed, and I'm doing this in existing C. Scoped 'using' would be nice for shortening the identifiers. + This can be done without changing the tool chain. + + I am currently using, e.g.: + + Ξ(TM ,TM·CVT ,ARRAY ,Tape·bounded) + + This could be: + + #with Ξ(TM ,TM·CVT ,ARRAY): + ... + ·Tape·bounded = ... + ... + #endwith + + I.e. set the prefix, then for identifiers starting with · set the prefix. `with` + can be nested. + + Also native #cat and #Ξ .. perhaps operators + + If the center dot delineated tokens, then we would not need the Ξ function. + +2. cpp control of evaluation in definitions + + #assign name·#eval(space) #eval(body) + + Temporal assignment. Eval, then define. + + Allows defining a macro while using eval in both the name and body. eval happens + once, and the name is not available to be used in the body. + +3. cpp existence logic + +4. Something should be done about macros having to be on one line and having to account for, format, all those \. Perhaps an emacs mode similar as used for paragraphs? Anyway something should be done. + + #begin + #define ... + ... + ... + #end + +5. C type system, ability to declare a type hierarchy based on struct types having the same field names and format, or extensions thereof. + + typehier pair -> vector-2d -> complex + + Something like that. + +6. C type system, put struct, enum types into the same space with the other types. of course. + +7. A better emacs C formatter + + diff --git a/developer/document/Copy.org b/developer/document/Copy.org new file mode 100644 index 0000000..6ab73ae --- /dev/null +++ b/developer/document/Copy.org @@ -0,0 +1,93 @@ +* Copy - Memory Copy Operations + +** Overview + +The Copy module provides optimized memory copy operations that account for memory alignment and byte order. It contains functions for standard memory copying, as well as specialized routines for reversing byte order during copying. The design ensures efficient memory operations by aligning read pointers and assuming write operations are buffered. + +** Features + +- Optimized memory copy operations +- Byte order reversal during copy +- Handles unaligned read memory +- Ensures efficient bulk transfers using 64-bit word copies +- Provides step-based copying with status reporting + +** Interface + +- `Copy·bytes(read0, read1, write0) -> void*` + - Copies memory from `read0` to `write0`, preserving byte order. + - Returns the updated write pointer. + +- `Copy·reverse_byte_order(read0, read1, write0) -> void*` + - Copies memory while reversing byte order. + - Reads from `read1` downward, writes from `write0` upward. + - Returns the updated write pointer. + +- `Copy·step(Copy·it *it) -> Copy·Status` + - Uses the `Copy·it` struct, which defines read and write intervals. + - Does the maximum sized copy without going outside the intervals. + - Updates `it` for continuation of the block copy. + - Returns a status indicating there is surplus data, or available write allocation. + +- `Copy·step_reverse_order(Copy·it *it) -> Copy·Status` + - Performs a copy of the block while reversing the byte order and updating the iterator. + - Returns a status indicating there is surplus data, or available write allocation. + +- `Copy·step_write_hex(Copy·it *it) -> Copy·Status` + - Converts read bytes into hexadecimal representation during writing. + - Two bytes are written for each byte read.buffer. + - Returns a status indicating there is surplus data, or available write allocation. + +** Status Codes + +- `Copy·Status·perfect_fit` + - Read and write buffers are fully utilized without remainder. +- `Copy·Status·read_data_surplus` + - The write allocation was filled before the read values were all read. +- `Copy·Status·write_allocation_available` + - The write allocation has space for more values. +- `Copy·Status·write_allocation_gap` + - The write allocation has space, but it is not large enough to hold another value. + +** Implementation Notes + +- Alignment is only enforced on the read side to maximize efficiency. +- Writes are assumed to be buffered, allowing unaligned writes without performance degradation. +- The `step` functions allow for incremental processing of data streams. + +** Example Usage + +```c +Copy·it copy_instance = { + .read0 = source_data, + .read_size = source_size, + .write0 = destination_buffer, + .write_size = destination_size +}; + +Copy·Status result = Copy·step(©_instance); +``` + +This module provides an efficient and flexible memory copying framework suitable for low-level data manipulation tasks. + +* Relevant todo note + +2025-02-24T08:09:57Z Copy.lib.c forced alginment machine might have issues with the block copy. + + The block copy aligns the read pointer by copying some initial + bytes. It ignores the alignment on the write pointer. Then at the end it does a byte + by byte copy of the ragged tail (less than a full word number of bytes). + + For a system that forces alignment, the initial alignment of the read pointer will get skipped. The write pointer will be aligned, so there is no problem in not checking it. + + However, the ragged tail loop can fire on a forced aligned + system. This will happen if the bounding read pointer passed in to + the block copy is not pointing to the first byte of a word. This can + happen if it is created adding `sizeof` of an object with that is not an even number + of bytes in a word long. + + The solution is probably to set a 'force align' macro based on the + architecture macro and gating the ragged tail code to do a word + copy, or affecting the bulk section to do one more loop -- or having + a differnt block copy an bytes_reversed block copy that loops on + words. diff --git a/developer/document/FG_tables.org b/developer/document/FG_tables.org new file mode 100644 index 0000000..797b909 --- /dev/null +++ b/developer/document/FG_tables.org @@ -0,0 +1,113 @@ +* Function-Given (FG) Tables in RT C +:PROPERTIES: +:AUTHOR: Sorein +:DATE: 2025-04-25 +:END: + +This document introduces **FG Tables**—Function-Given tables, a structured method in RT C for grouping related functions that operate on a common type or binding. We use the `Core` module as a canonical example, as it contains no template variables or tableaux and thus provides the cleanest view. + +**FG Tables** serve a purpose similar to vtables or method dictionaries: they allow operations to be defined once and called generically, using a consistent interface. Unlike C++ vtables, FG tables are explicit, statically defined, and layered via macros in a readable, extensible style. + +**Key concepts:** +- All function signatures take a common first argument (usually a pointer to a "binding" struct). +- The table itself is a `struct` of function pointers. +- The module defines: + - The **type** (e.g. `Core`) + - The **binding struct** (`Core·Binding`) + - The **table definition** (`Core·FG`) + - The **table instance** (`Core·Tableau`) + - Helper macros for calling (`Core·call(...)`) and checking (`Core·wellformed_binding(...)`) + +* Example: Core +Core provides utilities that are always available to the RT system. It defines an FG table without templates or specializations. + +**Declaration (in the FACE section)**: +#+BEGIN_SRC c +#ifndef Core·FACE +#define Core·FACE + +typedef struct Core·Binding Core; + +typedef struct{ + void(*Free)(Core*); + bool(*is_aligned)(Core* ,void const*,uint ,bool*); + void const*(*round_up)(Core* ,void const*,uint); + void const*(*round_down)(Core* ,void const*,uint); +} Core·FG; + +bool Core·wellformed_binding(Core*); +#define Core·call(B ,f ,...) ((Core·wellformed_binding(B)) ,(B)->FG->f(B ,__VA_ARGS__)) + +#endif +#+END_SRC + +**Explanation of Functions:** + +- `Free(Core*)`: Frees the binding and sets its pointer to `NULL`. This follows the `Free(pt) = free(pt); pt = NULL;` idiom defined in RT. +- `is_aligned(Core* ,void const* p ,uint alignment ,bool* result)`: Determines whether `p` is aligned to `alignment`. Writes result to `*result`, returns false if `p == NULL`. +- `round_up(Core* ,void const* p ,uint alignment)`: Returns the smallest aligned address ≥ `p`. +- `round_down(Core* ,void const* p ,uint alignment)`: Returns the largest aligned address ≤ `p`. + +All alignment operations use address logic with explicit alignments passed at runtime, rather than compile-time constants. + +* Implementation +The FG table instance is defined in the `Core·IMPLEMENTATION` section: + +#+BEGIN_SRC c +#ifdef Core·IMPLEMENTATION + +bool Core·wellformed_binding(Core* B){ + return B && B->FG == &Core·Tableau; +} + +Local void Core·Free(Core* B){ + Free(B); +} + +Local bool Core·is_aligned(Core* B ,void const* p ,uint alignment ,bool* result){ + if(!p){ *result = false; return false; } + uintptr_t up = (uintptr_t)p; + *result = (up % alignment) == 0; + return true; +} + +Local void const* Core·round_up(Core* B ,void const* p ,uint alignment){ + if(!p) return (void const*)(uintptr_t)alignment; + uintptr_t up = (uintptr_t)p; + return (void const*)((up + alignment - 1)/alignment*alignment); +} + +Local void const* Core·round_down(Core* B ,void const* p ,uint alignment){ + if(!p) return NULL; + uintptr_t up = (uintptr_t)p; + return (void const*)(up / alignment * alignment); +} + +Core·FG const Core·Tableau = { + .Free = Core·Free, + .is_aligned = Core·is_aligned, + .round_up = Core·round_up, + .round_down = Core·round_down +}; + +#endif +#+END_SRC + +* Usage Example +#+BEGIN_SRC c +Core* B = malloc(sizeof(Core)); +B->FG = &Core·Tableau; + +bool aligned; +Core·call(B ,is_aligned ,(void*)0x1000 ,16 ,&aligned); + +void const* r = Core·call(B ,round_up ,(void*)0x1003 ,16); +#+END_SRC + +* Summary +- FG Tables provide modular polymorphism in pure C. +- The `Core` FG is the simplest: no template variables, no tableaux layers. +- The FG naming convention (`Module·FG`) and `call(...)` wrapper provide safety and convenience. +- FG patterns scale to support templated modules with `FG·Type`, `FG·Tableau`, and dispatch guards. + +FG tables are foundational to the RT C architecture, forming the dispatch layer behind modular, template-like polymorphism in a static language. diff --git a/developer/document/TapeMachine_howto.org b/developer/document/TapeMachine_howto.org new file mode 100644 index 0000000..f156c23 --- /dev/null +++ b/developer/document/TapeMachine_howto.org @@ -0,0 +1,145 @@ +#+TITLE: How to Use a TM: Tape Machine Structure and Semantics +#+AUTHOR: Sorein +#+DATE: 2025-04-25 + +* 1. Introduction + +The `TM` module in RT C implements a **Tape Machine** abstraction—a generic, forward/backward traversable sequence with a *head*, *bounded extent*, and *cell value type* (CVT). + +Each instantiated TM (e.g. `TM·AU`, `TM·Str`) is a **binding** that combines: +- A `tableau` — the backing data or representation (e.g. array, singleton, zero-length) +- An `FG table` — the dispatch logic defining how the head behaves + +TM is not a container. It is a *lens* or *state machine* for traversing memory in a structured way. + +* 2. Constructing a TM + +To construct a TM instance, you typically: +1. Define the tape data (e.g. an array of AU or Str) +2. Define its extent +3. Allocate a `Tableau` struct (e.g. `TM·AU·Array·Tableau`) +4. Initialize the TM using `init_pe` or `init_pp` + +#+BEGIN_SRC c +AU tape1[] = {0xAA ,0x55 ,0xC2}; +extent_t·AU extent1 = sizeof(tape1) / sizeof(AU) - 1; + +TM·AU·Array·Tableau t1; +TM·AU tm1 = TM·AU·Array·init_pe(&t1 ,tape1 ,extent1); +#+END_SRC + +The resulting `tm1` is a **binding**—you pass it to functions via `Binding·call` or `TM·AU·call`. + +* 3. TM Method Overview + +The key methods in the TM FG table are: + +| Method | Description | +|--------------------+--------------------------------------------------| +| `mount` | Reattach head to the tape if dismounted | +| `dismount` | Detach the head (mark as inactive) | +| `status` | Returns the full head status bitmask | +| `on_tape` | True if the head is on a valid cell | +| `on_leftmost` | True if head is at the leftmost cell | +| `on_rightmost` | True if head is at the rightmost cell | +| `step`, `step_left`| Move head forward or backward | +| `rewind` | Move head back to its starting position | +| `read` | Return the cell value under the head | +| `write` | Overwrite the cell under the head | + +* 4. Loop Structure: Prefix, Separator, Postfix + +Traversal is typically done with **guarded middle-exit loops**, allowing for insertion of: + +- A **prefix** (runs before loop) +- A **separator** (runs between each item) +- A **postfix** (runs after loop) + +Example pattern (printing a tape with separators): +#+BEGIN_SRC c +if( Binding·call(tm ,on_tape) ){ + // Prefix + do{ + // Body + printf("%02x", (unsigned int) Binding·call(tm ,read)); + + // Guarded middle exit + if( Binding·call(tm ,on_rightmost) ) break; + + // Separator + putchar(' '); + + // Step + Binding·call(tm ,step); + }while(1); + // Postfix + putchar('\n'); +} +#+END_SRC + +This avoids the need for counter variables, array indexing, or special cases for first/last iteration. + +* 5. Example: Nested TM Traversal + +The following example demonstrates two tapes—`tm1` of bytes, and `tm2` of strings—printing a byte followed by the full string tape on each outer step. + +#+BEGIN_SRC c +if( Binding·call(tm1 ,on_tape) && Binding·call(tm2 ,on_tape) ){ + do{ + // Prefix of outer loop + printf("%02x\n", (unsigned int) Binding·call(tm1 ,read)); + putchar(' '); + putchar(' '); + + // Inner loop: iterate over strings + do{ + printf("%s", Binding·call(tm2 ,read)); + if( Binding·call(tm2 ,on_rightmost) ) break; + putchar(' '); + Binding·call(tm2 ,step); + }while(1); + + // Postfix of inner loop + putchar('\n'); + + // Guarded exit + if( Binding·call(tm1 ,on_rightmost) ) break; + + // Advance outer head + Binding·call(tm1 ,step); + + // Reset inner head + Binding·call(tm2 ,rewind); + }while(1); + + // Final postfix + printf("\n"); +} +#+END_SRC + +This structure supports: +- Interleaved traversal of coextensive tapes +- Mid-line formatting +- Reusable subroutines for iteration + +* 6. Debugging Tips + +- Use `on_tape`, `on_rightmost`, and `status` to check head validity before reading. +- `rewind` is always safe to call, even on a dismounted tape. +- `dismount` prevents accidental traversal if a tape becomes invalid or externally reallocated. + +* 7. Summary + +The Tape Machine abstraction supports: +- Generic data traversal +- Separation of structure (tableau) from behavior (FG table) +- Elegant loop patterns with predictable control flow +- Multi-instance coexistence via templated bindings + +By adopting TMs, RT C code gains clarity and uniformity when working over ranges, buffers, or token streams—without abandoning type safety or performance. + +For detailed reference on bindings and FG tables, see: + +**📎 [[file:fg_bindings_and_tableaux.org][FG Tables and Bindings in RT C]]** + +**📎 [[file:fg_tables_core.org][FG Tables — Core Module Example]]** diff --git a/developer/document/alignment.org b/developer/document/alignment.org new file mode 100644 index 0000000..c77db25 --- /dev/null +++ b/developer/document/alignment.org @@ -0,0 +1,28 @@ + +*recovering alignment of pointers that point to array cells (elements) + +Interesting observation, recovering alignment for a pointer into an array is expensive. It requires modulus against the element size to find how far off the pointer is. + +*converving alignment + +If one starts aligned, say on zero, then only increments by the element size, alignment is not ever lost. However, if an element pointer is computed by a imprecise process, and rounding is recovered to get it back again, then the modulus is required. + +*power of radix boundaries + +However, modulus is not hard on powers of the radix boundaries. + +So either a) in the first place make elements a power of the radix in size, perhaps even using padding, b) change the radix of the number system so the native element size if the radix, or a power there of c) never do a computation that loses alignment. + +As a consequence it is expensive to compute the extent of an object with arbitrary CVT (Cell Value Type). Given the two bounding pointers, one must subtract and divide by the sizeof(CVT) to recover the extent, and divide is expensive. In contrast when given the position and extent, the address of the rightmost cell can be recovered with an addition. + +*store base and extent, rather than two pointers + +It follows that if the extent is needed that it makes more sense to store the position and extent for an interval than it does to store two bounding pointers. + +*unaligned bound + +`on_rightmost` is a precise predicate. If the head pointer were advanced by a value other than sizeof(CVT) then it could step right over the base pointer to the rightmost cell. If this was part of looping, the loop would continue. + +A situation where this could happen, suppose we want to copy a block of memory. We walk AU by AU (byte by byte) up to an aligned on AU8 address. Then we copy AU8 by AU8. Here is the problem, the actual data being copied ends on an AU pointer boundary, not an AU8 pointer boundary. It is not difficult to round down to an AU8 because 8 is a power of two. This round down is required, to the point of the last full AU8 that can be copied, to stop the AU8 copy. This is not a problem for AU8 because 8 is a power of two. + +However, if the increment were by the size of CVT, and the boundary was given given by an AU pointer, then rounding down requires a modulus operation to know where the last CVT fits in. It is not clear what use case exists for this. diff --git a/developer/document/build.org b/developer/document/build.org new file mode 100644 index 0000000..a499421 --- /dev/null +++ b/developer/document/build.org @@ -0,0 +1,8 @@ + + +> make clean +> make dependency +> make library +> make cli + +I manually edit the make file to turn on and off the making of the main program or the example directories. See notes in ` tool🖉/makefile`. diff --git a/developer/document/coffee.txt b/developer/document/coffee.txt new file mode 100644 index 0000000..daf4508 --- /dev/null +++ b/developer/document/coffee.txt @@ -0,0 +1,20 @@ +/* + Coffee Species Reference + + | Species | Origin(s) | Flavor Notes | Notes | + |-----------|----------------------------|----------------------------|------------------------------- | + | Arabica | Vietnam (Da Lat), Malawi | Floral, bright, acidic | High elevation, lower caffeine | + | Robusta | Vietnam (Dak Lak, Gia Lai) | Bitter, strong, earthy | Common in Vietnamese blends | + | Excelsa | Vietnam (Central Highlands)| Tart, fruity, smoky | Adds depth, low production | + | Liberica | Vietnam (rare farms) | Woody, floral, full-bodied | Very large beans, low yield | + + Likely Blend (CASA Blue Mountain): + - Arabica (Malawi or Da Lat) + - Robusta (Vietnam) + - Possibly Excelsa (depth/complexity) + + Notes: + - "Made in Taiwan" likely refers to roasting/packaging. + - Shelf life: 2 years (cool, dry, or frozen recommended). + - Freezing whole beans is safe *if sealed airtight* and thawed only once. +*/ diff --git a/developer/document/cpp_gothyas.txt b/developer/document/cpp_gothyas.txt new file mode 100644 index 0000000..b207c93 --- /dev/null +++ b/developer/document/cpp_gothyas.txt @@ -0,0 +1,84 @@ + +1. + +A semicolon after a macro definition becomes part of the macro body. + + +2. + +When defining a macro: + + No space between the macro function name and the parameter list. + + Otherwise the would-be parameter list will be taken to be part of a macro variable definition. + +When calling a macro. + Can have space between a macro function name and the argument list. + + +3. + + Macro function definitions are not evaluated, so the body (the definition) of the macro remains literal until the time it is called. + + -> macro calls in macro defintions remain literal, i.e. unevaluated. + +4. + +Macros can be called with empty arguments. + + #+BEGIN_SRC c + #define a_macro(a ,b ,c) (a + b + c) + int a_macro (a,,b) // -> a + + c + #+END_SRC + +5. + +The COMMA macro, though defined, can't be used in any two level or more deep macro calls, because it will expand to a comma on the first level. It perhaps could be wrapped in a function that is given a deferred call, and then have eval expand it, dunno. + + +4o has written a little doc about this: + + * CATSEP Separator Expansion Notes + :PROPERTIES: + :CREATED: [2025-04-01] + :END: + + ** Problem + + When using `CATSEP` (or `CAT`) to join tokens with a separator, we encountered an issue where passing a macro-defined separator (e.g. `COMMA`) leads to incorrect behavior: + + - The macro expands too early. + - The result is malformed token pasting like `,A` instead of proper separation. + - This happens because `##` prevents further expansion, so any `sep` macro used in a `##` must already be fully resolved. + + ** Attempts + + We tried multiple versions: + - Using `DEFER`, `DEFER2`, `DEFER3` to hide expansion. + - Wrapping the separator in a macro (e.g. `DEFER_SEP()`). + - Recursive accumulation models with delayed evaluation. + + ** Findings + + - The separator **must not be a macro** when passed as an argument to a `##` operation. + - Macro arguments are always expanded before `##` is applied, unless blocked (e.g., by an extra layer of indirection). + - `##` prevents further expansion, so once the macro has been expanded into a literal comma (`,`) or semicolon (`;`), it can no longer be deferred. + + ** Recommendation + + Use raw characters or tokens as separators, not macros. For example: + + #+begin_src c + CAT(, A ,B ,C) // OK makes a token ABC + CAT(;, A ,B ,C) // OK - [I don't think this works either] + CAT(__oo__, A ,B ,C) // OK A__oo__B__oo__C + CAT(COMMA, A ,B ,C) // ❌ COMMA expands too early + #+end_src + + If you must use a macro-defined separator, redesign may be required. For now: + + ** Conclusion + + ⛔ **Do not use macro-defined separators in `CAT` or `CATSEP`.** + + Leave this as a known limitation and revisit if/when it becomes essential. Better to avoid the rabbit hole for now. diff --git a/developer/document/cpp_grammar.org b/developer/document/cpp_grammar.org new file mode 100644 index 0000000..98e5154 --- /dev/null +++ b/developer/document/cpp_grammar.org @@ -0,0 +1,52 @@ +Grammar + + identifier = [_a-zA-Z][_a-zA-Z0-9]* + | ([_a-zA-Z\u00A0-\uFFFF])([_a-zA-Z0-9\u00A0-\uFFFF])* + + macro_name = identifier + + token = identifier + | number ; e.g., 42, 0xFF, 3.14 + | string_literal ; "hello" + | character_constant ; 'a', '\n' + | operator_token ; +, -, ~, <<, etc. + | punctuation ; (), [], {}, etc. (when tokenized) + | parenthesized_expr ; (1,2), (x + y) + + empty_item = ε + This stands for nothing. It is useful for talking about item lists, because in general lists can have empty slots. Remember cpp works with literal text. + + For example, ( , ) is a length 2 list with two empty slots. + + For example, (1,,2) is a length 3 three list with one empty slot. + + On calls, the length of the arg_list must match length of the parameter list. + + For example, _FIRST() has a first parameter that expands to nothing if it is referenced + #define _FIRST(a ,...) a + _FIRST() --> ε is not a bad argument count error, but instead expands to nothing + + general_list = token (, token | ε)* + Comma-separated list of items. Commas can appear without tokens between them. + + arg_list = general_list + + pair = token | ε , token | ε; exactly two tokens. + + twion = pair + A special two-token list given to certain macros in a place one token is expected. + Its role is to shift the remaining members of a list by one position when prepended. + An honorary member of the single token club. A common twion is `~,1` + + parm_list = identifier (, identifier)* ; comma-separated list of identifiers + A parameter list differs from a general list in that two commas can not + appear adjacent to each other, and all members are identifiers. + + +2.2 'private' identify + + By convention private identifiers begin with an `_` character. + + Macros with this prefix are not intended to be called by users, and + indentifiers with this prefix are not intended to to used. + diff --git a/developer/document/cpp_macro_expansion.org b/developer/document/cpp_macro_expansion.org new file mode 100644 index 0000000..43ac72a --- /dev/null +++ b/developer/document/cpp_macro_expansion.org @@ -0,0 +1,337 @@ +#+TITLE: C Preprocessor Expansion Example +#+AUTHOR: Thomas Walker Lynch +#+OPTIONS: toc:nil + +1. Macro function definition + + Macro function definitions are not expanded, so the body (the definition) of the macro remains literal until the time it is called. Thus macro calls in macro defintion remain + literal, unexpanded. + + A macro function has three parts, 1) a name 2) a parameter list 3) body + + Parameters are declared by listing them between parenthesis after the name. No space + can occur between the name and the parameter list! If there is space then the + parameter list will be taken as part of the body. + + Text after the parameter list forms the body. + + #+BEGIN_SRC c + #define name(x ,y ,z) + #define name(...) // argument list becomes __VA_ARGS__ + #define name(x ,...) + #+END_SRC + +2. directives + + #define name is never expanded. body is not expanded when the definition is + added to the symbol table, but is expanded through a call to the macro. + + #ifdef and #ifndef do not evaluate what follows. They expect an already formed + macro name. + + #if does evaluate, but expects existence as true, and 0 as false (though zero + also exists). Non-existence is an error. Wrap cpp_ext_0 logic in BOOLEAN to get 1 or 0. (cpp_ext_0 logic is true for existence, and false for nonexistence.) + +2. Macro Call + + A macro call that was colored blue will not be expanded. + + A macro call can occur anywhere in the source code. It takes the form of a macro + name followed by an argument list: + + #+BEGIN_SRC c + name(1 ,a ,b) + #+END_SRC + + In a call, space is allowed between the macro name and the argument list. + + Not in strings, not embedded in other tokens. If a macro definition has the same name as the call, then that is a redefinition, an redefinition is not allowed. + + cpp scans the tokens in the translation unit, upon finding a macro call it replaces it with the body from the macro definition using the following steps: + + ** 1. Argument Substitution Phase + + When the macro is invoked: + + 1. Each parameter in the macro body is replaced *verbatim* with the + corresponding argument. No expansion is performed at this stage. + + 2. The new macro body is a new token stream: the old macro body with arguments pasted in. + + ** 2. Expansion Phase + + The preprocessor then scans the argument substituted macro body *from left to right*, + evaluating macro calls *as it encounters them*. + + - If a token is **not** a macro call (see below), it is included as-is. + - If a token **is** a macro call, it is expanded immediately, using the same two-phase process. + + This produces a depth-first, left-to-right expansion strategy. + + Non-macro-call tokens include: + + 1. Any non-identifier (e.g. `+`, `123`, `"text"`) + + 2. Any identifier **not followed by `(`** + + 3. Any parameter or token used with `#` + + - `#param` turns the *original* argument text into a string. + - Because it stringifies, *the argument is never expanded*. + + 4. Any parameter or token used with `##` + + - `##` concatenates tokens without evaluating them. + - The pasted result is *not* scanned recursively for macro calls. + + 5. any macro call token that has been "colored blue" by the evaluator. + + It is common that macros containing a `#` or a `##` will have an extra call + layer above them to cause the argument to be first substituted into a macro + where it will get expanded. Large number of Eval calls are typically not needed + for this, rather what is needed is one layer above the layer with the `#` or `##`. + + ** 3. Colored blue macro call tokens are taken as literal text. + + During expansion cpp keeps a list of macros that are actively being expanded. This includes the macro that has been called, of course, and all the calls that it found during its depth traversal to get to the current point of expansion. If it sees any calls to the macros on the active expand list, it marks the macro call token itself as unexpandable, and thus to be treated as literal text. It is said that the macro call token "has been colored blue". + + Any subsequent appearance of a colored blue macro call token will be treated as literal text, no matter the context. This includes if the macro result was assigned to a variable, then that variable is expanded later. It includes if the macro call token or the expression it is in is sent to another macro, etc. + + Example: + + #+BEGIN_SRC c + #define GROW(x) 1029 * GROW(x) + #define RESULT GROW(5) + + SHOW(RESULT); // → 1029 * GROW(5) + SHOW(EVAL(RESULT)); // → 1029 * GROW(5) again, never expands + #+END_SRC + + The macro call token `GROW(x)` which occurs in the body of a macro definition of the same name, gets colored blue, and thus is always treated as literal text. This happens even though an expression containing it is assigned to a variable, then that variable is expanded in a totally different expansion context. + + Apparently the designers of cpp do not want people to design recursive structures with cpp. However, there is a trick for getting around it using a confederate in place of the recursive call, then putting back the original call later, as shown in section 6. + +3. Example macros + + #+BEGIN_SRC c + #define FORCE_ONE(x) 1 + #define STR(x) #x + #define VAL(x) STR(x) + #define GROW(x) 7 * GROW(x) + #+END_SRC + + A call to ~FORCE_ONE(5)~ will expand to ~1~. + + A call to ~STR(FORCE_ONE(5))~ will expand to the string ~"FORCE_ONE_(5)"~. This is because arguments given to the ~#~ operator are not expanded. The variable gets replaced with its value, but the value it not expanded. + + A call to ~VAL(FORCE_ONE(5))~ will result in `1`. This is because there is no hash symbol in the VAL macro that is stopping the recursive expansion of ~x~. + +5. Cascading expansion + + A macro can also fail to evaluate all possible macros, because during the left to right scan, it created a macro call, but during the scan it did not see it. + + #+BEGIN_SRC c + #define NULL_FN() // expands to nothing + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE NULL_FN() (x) + #+END_SRC + + When evaluating ~NOT_SO_FAST(5)~, here's what happens: + + 1. ~NEGATE~ is encountered there is nothing to recur into, so it evaluates to itself. + the expansion moves right. + + 2. ~EMPTY()~ is a macro, so it has no operands, so it is expanded. As it has no + body, it expands to nothing. CPP then moves to the right. + + 3. ~(x)~ is not a macro so there is nothing to recur into, so it becomes ~(5)~. + + 4. Thus the final result of the left to right pass is → ~NEGATE (5)~ The evaluator + recursively expands calls, but it never saw ~NEGATE (5)~, so it remains unexpanded. + This is the second reason a literal macro call might occur in an expansion. + + #+BEGIN_SRC bash + cat >test.c < + + int main(void){ + printf("example_eval.c\\n"); + + #define STR(x) #x + + // `#x` no expansion of x due to the '#' + // `STR(x)` recurs and does a left to right expansion on the value of `x` + #define SHOW(x) printf(#x " → %s\\n", STR(x)); + + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + + SHOW(NOT_SO_FAST(5)); + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + } + EOF + + gcc test.c + ./a.out + #+END_SRC + + Output: + + #+BEGIN_EXAMPLE + example_eval.c + NOT_SO_FAST(5) → NEGATE (5) + BE(NOT_SO_FAST(5)) → -5 + #+END_EXAMPLE + + Let’s examine the final lines: + + #+BEGIN_SRC c + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + #+END_SRC + + The expansion process: + + - cpp encounters ~BE(NOT_SO_FAST(5))~. + - It enters ~NOT_SO_FAST(5)~, expands it to ~NEGATE (5)~. + - Then ~BE(NEGATE (5))~ becomes ~-5~ through final macro expansion. + + ------- + + The `IF` macro evolves and does three self expansions, due to new strings + being created which in turn match already defined macros. + + series of events, explain why the DEFER3, ph + + #+BEGIN_SRC c + IF \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + () \ + (IF \ + ( predicate(FIRST(__VA_ARGS__)) ) \ + ( FIRST( ,__VA_ARGS__) ) \ + ( DEFER3(_FIND_CONFEDERATE) ()(predicate ,REST(__VA_ARGS__)) ) \ + ) + #+END_SRC + + +6. Nesting, recursion approaches that do not work, and one that does. + + #+BEGIN_SRC c + + #include + #define STR(x) #x + // no expansion, and one pass of expansion + #define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + + #define BE(...) __VA_ARGS__ + #define EMPTY() + + #include + int main(void){ + printf("example_grow.c\n"); + printf("\n"); + + // case 1 + /* + GROW(7) → 17 * GROW(7) + GROW(GROW(5)) → 17 * GROW(17 * GROW(5)) + ,*/ + #define GROW(x) 17 * GROW(x) + SHOW(GROW(7)); + SHOW(GROW(GROW(5))); + printf("\n"); + + // case 2 + // GROW2(11) --> 19 * GROW2 (11) + #define GROW2(x) 19 * GROW2 EMPTY() (x) + SHOW(GROW2(11)) ; + printf("\n"); + + // case 3 + // GROW3(13) --> 119 * 19 * GROW2 (13) + #define GROW3(x) BE(119 * GROW2 EMPTY() (x)) + SHOW(GROW3(13)); + printf("\n"); + + // case 4 + /* + `BE` placed on the outside. The idea is that expansion will return `123 * GROW (15)` and then this will be expanded resulting in `123 * 123 * GROW(15)`. + + However, any time GROW4 literally spells out GROW4(...) inside its own expansion + it will leave it literally and not expand it. + + Though it is interesting that here that occurs at a higher level in the expansion tree than the first ocurrance of the recursive call, but still it is in the tree. + + GROW4(15) --> 123 * GROW4 (15) + ,*/ + #define GROW4(x) BE(123 * GROW4 EMPTY() (x)) + SHOW(GROW4(15)); + printf("\n"); + + // case 5 + /* + Substitution of the function named followed by a trampoline works. + + The original expression is written in terms of a deferred CONDFEDERATE function + instead of in terms of a recursive call to GROW5. cpp can suspect nothing. + + The result is an expression in terms of the unexpanded CONDFEDERATE function. + + The CONFEDERATE function is defined to return the token GROW5. Hence in a subsequent expansion, and there must be a subsequent expansion for this to work, The CONFEDERATE function will run, return GROW5 which is next to its call parenthesis, so then the + recursive call will run. + + BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) + BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) + ,*/ + #define GROW5(x) 541 * CONFEDERATE EMPTY() () (x) + #define CONFEDERATE() GROW5 + SHOW(BE(GROW5(21))); + SHOW(BE(BE(GROW5(57)))); + printf("\n"); + + // case 6 + /* + Once a recursively called function is marked, or 'colored' it can never be expanded, even when passed through to another variable and separately expansion. + ,*/ + #define GROW6(x) 1029 * GROW6 EMPTY() (x) + #define RESULT1 GROW6(51) + SHOW(RESULT1); + SHOW(BE(RESULT1)); + printf("\n"); + // RESULT1 --> 1029 * GROW6 (51) + // BE(RESULT1) --> 1029 * GROW6 (51) + + // case 7 + #define RESULT2 GROW6(151) + SHOW(RESULT2); + SHOW(BE(RESULT2)); + printf("\n"); + // RESULT2 --> 1029 * GROW6 (151) + // BE(RESULT2) --> 1029 * GROW6 (151) + + } + + #+END_SRC + +7. Discussion on recursion + + Case 6, and Case 7 above show that once a token is marked as a would-be recursive call token it is marked and can never be expanded, no matter how hard the programmer + might try hide its actual origin. It can be assigned to variables, passed between co-routines, and nothing will help because the macro call token itself is marked. + + Case 5 shows a workaround. Instead of having a recursive call, a deferred call to a confederate is made. The resulting expression then amounts to a lazy expansion. The return value from the expansion will contain unmade calls to the confederate in each and every place that a recursive call was desired. + + In order to complete the expansion, the lazy result must undergo a second expansion, + where the confederate function calls are run, and they return the name of the original + function that was to be called, and then those calls are expanded. + + This leads to a trade off. To have recursion we must have two expansions of expressions so as to replace the confederates. + + Repeated expansion is a consequence of using confederate method to avoid macro calls from being marked not to be expanded. Deferring the calls is necessary so that the don't get replaced in the first expansion so that their replacements don't get marked. + + Note that each recursive call, potentially results in ore expressions appearing. Hence, there must be as many expansions as there are levels of recursion. This is a tell order for list processing. + + diff --git a/developer/document/parameterized_functions.org b/developer/document/parameterized_functions.org new file mode 100644 index 0000000..26d1c6a --- /dev/null +++ b/developer/document/parameterized_functions.org @@ -0,0 +1,120 @@ +* Parameterized Functions + Author: Thomas Walker Lynch / Drafted by Caerith + +* 1. Parameterization in Mathematics +In mathematics, **parameters** are used to define structured families of functions. For example, consider the family: + +#+BEGIN_SRC +{ f_t(x) = t * x, g_t(y) = y + t^2, h_t(z) = sin(tz) } +#+END_SRC + +Each function in this family shares a symbolic parameter `t`, which organizes the family and distinguishes its members. The functions differ in behavior based on the fixed value of `t`, even though they operate on different primary arguments (`x`, `y`, `z`). + +This reveals the core role of a parameter in mathematics: it does not merely serve as an argument to a single function, but rather defines **a space of functions** — a higher-order structure from which individual functions can be selected by fixing the parameter. + +In this context, we say: +> A parameter is an external symbolic structure that appears as an argument in each function, but whose true role is to *coordinate or classify* the family of functions as a whole. + +Once a value is chosen for the parameter, it becomes fixed, and the resulting function behaves purely in terms of the remaining arguments. The collection \( \{f_t, g_t, h_t\} \) for varying `t` forms a **parameterized family**, and the parameter gives it structure. + +* 2. The Confusion in Computer Science +In computer science, the term "parameter" is typically conflated with what are more properly called arguments. One speaks of a "parameter list" when defining a function, but these are just **argument symbols**, and at runtime, **argument values** are supplied. + +To clarify: +- An **argument symbol** is a variable used in a function definition. +- An **argument value** is an input supplied at invocation. + +We reserve **parameter** to mean: *a symbolic value that organizes or shapes a function or function family*. This returns us to the mathematical intent. + +Seen from this angle, **object-oriented programming** is a way of constructing **families of parameterized functions** — each method implicitly taking the object (`this`) as a shared structure. That object acts as a **fixed symbolic input** across many functions: it is the parameter. The set of methods thus defines a family. + +- For one parameter (i.e., one receiver object), the system is straightforward. +- For two, ambiguity emerges: whose methods govern? This gives rise to multiple dispatch, traits, and other formal structures. + +Thus, **object-orientation is a particular implementation of parameterized function families**, where the parameter is embedded as implicit context. + +* 3. When Parameters Can Change: Machines +In pure mathematics, the parameter is fixed during evaluation. But when a function can *modify* its parameter — i.e., mutate the context it depends on — then we are no longer dealing with functions in the mathematical sense. + +> When the parameter is no longer constant, but mutable, it becomes **state**. + +A function family with a mutable parameter is not a function family at all — it is a **machine**. The state evolves over time, and each function application may affect future behavior. + +This is a transition from **functional** to **stateful** systems. The parameter becomes a **tableau**: a symbolic structure that holds state, arguments, results, and evolves during execution. It is the parameter made writable, and the environment through which computational interaction unfolds. + +A tableau is not limited to a single function family — it may participate in multiple. It is both an input/output workspace and a memory of prior execution. + +In this view, TTCA and similar systems operate not just with functions, but with machines — bundles of callable behaviors that mutate their shared tableau. + +* 4. Our Terminology +To capture these distinctions, we adopt the following terminology: + +- **PFT**: A *Parameterized Function Table* over carrier type `T`. This is a symbolic table of functions that each expect a `T` as their first argument. +- **M** or **Machine**: A special case of PFT where `T` is not constant but a **tableau**, and may be mutated during evaluation. +- **Tableau**: A symbolic structure that accumulates inputs, stores return values, and evolves during execution. It is both interface and state — a writable parameter and a staging area for symbolic computation. It generalizes a stack frame and may serve multiple function families simultaneously. + +This language aligns our system with mathematical clarity while preserving the structural richness of the tableau concept. + +* 5. The Parameter Connector: Binding Parameters to Function Families +In mathematics, writing a subscript such as `f_t(x)` indicates that a function family `f` has been **partially applied** by fixing its parameter `t`. This is called **partial application** — and it represents the act of creating a specific instance of a function from a broader, parameterized family. + +In our system, we reflect this idea using a symbolic structure called the **Parameter Connector**. + +> A **Parameter Connector** is a type that declares how a specific parameter (e.g., a `Tableau`) is to be coupled with a Parameterized Function Table (PFT). It is the symbolic form that supports partial application and prepares the ground for dispatch. + +The macro: + +#+BEGIN_SRC c +DECLARE_PARAMETER_CONNECTOR(MyType) +#+END_SRC + +declares a `struct` named `MyType`, which contains: +- a pointer to a `MyType_Tableau` (the parameter value) +- a pointer to a `MyType_PFT` (the function table) + +This struct is the **parameter connector**. It does not yet perform binding, but defines the shape of a pairing. Once an instance is created — with the parameter value assigned — we may dispatch calls via: + +#+BEGIN_SRC c +call(connector, fn_name, args...); +#+END_SRC + +This pattern reflects the subscripting act in mathematics. The `connector` serves as the **parameter-binding context**: it is what affixes the symbolic `t` to the `f` in `f_t(x)`. + +In this way: +- **The connector is to `call()` what a subscript is to a function name**. +- It allows partial application of parameterized function tables. +- It forms the bridge from symbolic family to concrete callable form. + +Thus, the **parameter connector** is the central structure that enables meaningful dispatch in a system of parameterized functions — faithful both to mathematical abstraction and to C's structural constraints. + + + + +#+BEGIN_SRC + ┌──────────────────────┐ + │ Function Family │ + └────────┬─────────────┘ + │ + ┌───────────────┼───────────────┐ + ▼ ▼ +┌──────────────┐ ┌────────────────────┐ +│ Parameter t │ │ Parameterized │ +│ (symbolic) │ │ Function Table PFT │ +└──────┬───────┘ └────────┬───────────┘ + ▼ ▼ + ┌───────────────────────────────────┐ + │ Partial Application Step │ + └──────────────┬────────────────────┘ + ▼ + ┌────────────────────────┐ + │ Parameter Connector │ + └────────────┬───────────┘ + ▼ + ┌─────────────┐ + │ call() │ + └────┬────────┘ + ▼ + ┌───────────────┐ + │ Machine │ + └───────────────┘ +#+END_SRC diff --git a/developer/document/set_list.org b/developer/document/set_list.org new file mode 100644 index 0000000..fa12a7a --- /dev/null +++ b/developer/document/set_list.org @@ -0,0 +1,123 @@ +\#+TITLE: Using `#assign` to Construct Sets and Lists in the C Preprocessor +\#+AUTHOR: Thomas Walker Lynch +\#+DATE: 2025-05-06 +\#+OPTIONS: toc\:nil num\:nil +\#+LANGUAGE: en + +The `#assign` directive allows the programmer to perform runtime macro redefinitions within the C preprocessor. This facility introduces mutability and symbolic indirection, enabling set and list representations not possible with static `#define`s alone. + +* Introduction + +Normally, the C preprocessor (`cpp`) operates as a single-pass, immutable macro expander. Once a macro is defined, it cannot be updated or re-bound without manual `#undef` intervention, and even then only in certain contexts. `#assign`, by design, bypasses this constraint. + +It enables symbolic mutation. With this, we can simulate associative data structures: sets, lists, cons cells, even environments. + +* Representing Sets with `#assign` + +In a conventional C macro environment, a set cannot be constructed dynamically because macro definitions are static. However, with `#assign`, we can model a set as a collection of defined macro names. + +\*\* Membership Test + +To test whether `X` is in a set: + +\#+begin\_src c +\#ifndef \_SET\_\_X +\#define NOT\_MEMBER +\#else +\#define MEMBER +\#endif +\#+end\_src + +We treat the existence of the macro `_SET__X` as a membership marker. + +\*\* Adding to the Set + +We can define an element by assigning an empty macro: + +\#+begin\_src c +\#assign (\_SET\_\_X, ) +\#+end\_src + +This simulates inserting `X` into the set. + +\*\* Properties + +* Sets are /existence-based/: their content is inferred by symbol presence, not enumeration. +* There is /no inherent order/ to the elements. +* You /cannot enumerate/ the contents of the set without external bookkeeping. + +- Representing Lists with `#assign` + +Lists can be represented as chained macros where each node is a pair (a cons cell): + +\#+begin\_src c +\#define c0 (a, b) +\#define c1 (c, d) +\#assign (SECOND(c0), c1) +\#define c2 (e, f) +\#assign (SECOND(c1), c2) +\#+end\_src + +This forms a chain: + +\#+begin\_src +c0 → (a, c1) +c1 → (c, c2) +c2 → (e, f) +\#+end\_src + +Each assignment updates the /cdr/ or /tail/ of the previous node. + +\*\* Appending to a List + +Given a head macro `LIST`, we can append by updating its tail pointer: + +\#+begin\_src c +\#assign (LIST, CAT(LIST, COMMA, NEW\_ELEMENT)) +\#+end\_src + +This mutates the list structure dynamically. + +\*\* Traversal + +Traversal is only possible if a symbolic walk is encoded or if a confederate macro is prepared to test known elements. This is limited and requires foreknowledge of the structure. + +* Sideways Lists (Symbol Table Indexed) + +An alternative to comma-based lists is to use macro names as nodes — each symbol representing a cons cell. + +You define each cons cell: + +\#+begin\_src c +\#assign (\_cons\_a, (A, \_cons\_b)) +\#assign (\_cons\_b, (B, \_cons\_c)) +\#assign (\_cons\_c, (C, NIL)) +\#+end\_src + +Now `_cons_a` is the symbolic head. Each macro name points to a `(car, cdr)` pair. + +This format mirrors the representation of linked lists in Lisp, and mutation is achieved by re-assigning the `cdr` field via `#assign`. + +* Mutability + +What makes this all possible is that `#assign` allows redefinition. It effectively simulates mutable variables: + +\#+begin\_src c +\#assign (X, 5) +\#assign (X, 7) +\#+end\_src + +Later macro expansions of `X` now yield `7`, not `5`. This is unlike `#define`, which would have required an `#undef` first and would have affected macro hygiene. + +* Limitations + +- No native enumeration of keys in the symbol table. +- No stack or heap — only symbolic references. +- No scoped environments unless explicitly constructed via naming schemes. +- Risk of name collisions. + +* Conclusion + +The `#assign` directive reimagines the C preprocessor as a mutable symbolic computation engine. It opens the door to implementing symbolic sets, lists, and even cons structures within macro space, turning what is normally a static templating tool into a dynamic environment for structured symbolic logic. + +Future extensions could include associative maps, recursive evaluators, or stack machines — all using nothing but macro indirection and symbolic mutation. diff --git a/developer/document/source_file_sectioins.org b/developer/document/source_file_sectioins.org new file mode 100644 index 0000000..48d0573 --- /dev/null +++ b/developer/document/source_file_sectioins.org @@ -0,0 +1,107 @@ +#+TITLE: RT Library Structure Guide +#+AUTHOR: Sorein (on request by Thomas) +#+DATE: 2025-04-25 + +* Purpose +This document describes the architectural sections in `*.lib.c` files of the RT codebase. +It explains the use of `#if`-guarded blocks including `FACE`, `LOCAL`, `LIBRARY`, and template instantiations. + +* Section Overview + +** FACE :: Public Interface and Template Declaration +#+BEGIN_SRC c +#ifndef Module·FACE +#define Module·FACE +... +#endif +#+END_SRC + +- Declares types, enums, constants, and FG tables. +- Includes other modules (`Core.lib.c`, `cpp_ext.c`). +- Safe to include multiple times. +- No runtime state or implementation logic. + +** LOCAL :: Private Implementations and Table Initialization +#+BEGIN_SRC c +#ifdef LOCAL +#ifndef Module·LOCAL +#define Module·LOCAL +... +#endif +#endif +#+END_SRC + +- Defines functions, local constants, and FG table initializations. +- Only included when `LOCAL` is defined. +- Hidden from consumers. +- Use guards to prevent duplicate inclusion. + +** LIBRARY :: Compiled Static Library Content +#+BEGIN_SRC c +#ifdef LIBRARY +... +#endif +#+END_SRC + +- Reserved for future components to be compiled into a `.a` archive. +- Currently unused in `Core`, `TM`, or `Binding`. +- Separates linkable components from inline-included ones. + +** Template Parameters :: Type-Specific Inclusion Guards +#+BEGIN_SRC c +#ifdef _TM·CVT_ +#if BOOLEAN( NOT_IN(Binding ,TM·) ) +... +#endif +#endif +#+END_SRC + +- Allows per-type instantiation (e.g. `TM·AU`, `TM·Str`). +- Ensures that each instantiation happens only once. +- Guards must be defined by the *caller*, e.g.: + #+BEGIN_SRC c + #define _TM·CVT_ AU + #include "TM.lib.c" + #define SET__Binding__TM·AU + #+END_SRC + +** Undef Section :: Template Parameter Cleanup +#+BEGIN_SRC c +#undef _TM·CVT_ +#+END_SRC + +- Prevents leakage of template macros between inclusions. + +* Summary Table + +#+ATTR_LATEX: :environment tabular :align |l|l|l|l| +| *Section* | *Guard Macro* | *Purpose* | *Include Frequency* | +|-----------------+-------------------------+------------------------------------------------+-----------------------------| +| FACE | #ifndef Module·FACE | Public declarations, typedefs, constants | Once per TU or header | +| LOCAL | #ifdef LOCAL | Function definitions, internal state | Only in .cli.c or test file | +| LIBRARY | #ifdef LIBRARY | Static linkable content (future use) | Optional | +| Template Block | #ifdef _TEMPLATE_... | Per-template instantiation | Once per unique value | +| Undef Section | #undef _TEMPLATE_... | Cleanup template identifiers | Always | + +* Best Practices + +- **Order matters:** Include `FACE` before defining templates or using macros. +- **Avoid leakage:** Always `#undef` template variables after instantiation. +- **Limit `FACE` to declarations:** Do not define runtime behavior in `FACE`. +- **Use `LOCAL` in a single TU:** Only one translation unit should include `LOCAL` per template. +- **Separate compile/link concerns:** Use `LIBRARY` only for code compiled outside `cli`. + +* Example + +To use `TM·AU` and `TM·Str` in the same translation unit: +#+BEGIN_SRC c +#define _TM·CVT_ AU +#include "TM.lib.c" +#define SET__Binding__TM·AU + +#define _TM·CVT_ Str +#include "TM.lib.c" +#define SET__Binding__TM·Str" +#+END_SRC + +* End diff --git a/developer/document/template_in_C.org b/developer/document/template_in_C.org new file mode 100644 index 0000000..e723a42 --- /dev/null +++ b/developer/document/template_in_C.org @@ -0,0 +1,83 @@ +* Minimal Templating in RT C: The Box Example +:PROPERTIES: +:AUTHOR: Sorein +:DATE: 2025-04-25 +:END: + +This document presents a minimal and idiomatic example of **templating in RT C**, using a generic "box" type. + +We follow the RT convention for template macros: +- Template parameters are named with **leading and trailing underscores**, e.g. `_Box_T_`. +- A **set macro** (e.g. `SET__Box__int`) must be defined after inclusion to prevent duplicate instantiations. + +This example avoids FG tables, tableaux, or polymorphism—it exists purely to show type reuse through macro-based inclusion. + +* Template Logic: box_template.h + +This header is included multiple times, once per type. It expects `_Box_T_` to be defined. + +#+BEGIN_SRC c +#ifndef _Box_T_ +#error "_Box_T_ must be defined before including box_template.h" +#endif + +#if !defined(·(SET__Box,_Box_T_)) +#define ·(SET__Box,_Box_T_) + +typedef struct{ + _Box_T_ value; +} ·(Box_Box,_Box_T_); + +void ·(Box_set,_Box_T_)( ·(Box_Box,_Box_T_)* b ,_Box_T_ x ){ + b->value = x; +} + +_Box_T_ ·(Box_get,_Box_T_)( ·(Box_Box,_Box_T_)* b ){ + return b->value; +} + +#endif +#+END_SRC + +* Instantiating the Template + +You instantiate the template by defining `_Box_T_` before inclusion. Afterward, define the `SET__...` macro to guard against repeat. + +#+BEGIN_SRC c +#define _Box_T_ int +#include "box_template.h" +#define SET__Box__int + +#define _Box_T_ char* +#include "box_template.h" +#define SET__Box__char_ptr +#+END_SRC + +* Example Usage + +Once the template is instantiated, you can use the generated types and functions. + +#+BEGIN_SRC c +#include + +int main(){ + ·(Box_Box,int) a; + ·(Box_set,int)(&a ,42); + printf("a = %d\n", ·(Box_get,int)(&a)); + + ·(Box_Box,char*) b; + ·(Box_set,char*)(&b ,"hello"); + printf("b = %s\n", ·(Box_get,char*)(&b)); + + return 0; +} +#+END_SRC + +* Summary + +This "box" example demonstrates the foundation of RT C templating: +- Code is included once per type with a unique `_Template_Var_`. +- `SET__...` guards prevent duplicate instantiation. +- Type-specific names (`Box_set,int`) are generated using token pasting macros like `·(...)`. + +From here, this pattern scales naturally to complex modules like `TM·AU`, while retaining clarity, reusability, and full type safety. diff --git a/developer/document/todo.org b/developer/document/todo.org new file mode 100644 index 0000000..139597f --- /dev/null +++ b/developer/document/todo.org @@ -0,0 +1,2 @@ + + diff --git "a/developer/document\360\237\226\211/.githolder" "b/developer/document\360\237\226\211/.githolder" deleted file mode 100644 index e69de29..0000000 diff --git "a/developer/document\360\237\226\211/Binding.org" "b/developer/document\360\237\226\211/Binding.org" deleted file mode 100644 index 31ca2a4..0000000 --- "a/developer/document\360\237\226\211/Binding.org" +++ /dev/null @@ -1,170 +0,0 @@ -#+TITLE: FG Tables and Bindings in RT C -#+AUTHOR: Sorein -#+DATE: 2025-04-25 - -* 1. Overview: FG Tables Revisited - -RT C uses **Function-Given (FG) Tables** to group related functions that all take a **common first argument**. This enables flexible polymorphism and modular encapsulation in pure C. - -For a full explanation of FG tables and an example based on `Core`, see: - -**📎 [[file:fg_tables_core.org][FG Tables in RT C — The Core Example]]** - -In this model: -- Each module defines a **binding struct** (e.g. `TM·AU`, `Core`, etc). -- All methods take the binding as their first argument. -- A function pointer table (FG table) is associated with the binding. -- A macro `Module·call(binding ,method ,...)` expands to safe, type-dispatched function calls. - -* 2. The Tableau: Abstract Identity of the Binding - -In the FG model, we say that functions are *given* a binding. The binding is always a `struct` that pairs: - -1. A **tableau** (a pointer to the module-specific state) -2. An **FG table** (function dispatch table) - -The **tableau** is the key abstraction. - -- It is typically **only ever passed to the functions** in the FG table. -- Therefore, the FG table **defines the meaning** of the tableau: it specifies what functions expect and how they interpret the tableau pointer. -- The tableau has a *type in memory* (e.g. `TM·AU·Array·Tableau`), but also an **abstract type**, as defined by the FG table itself. - -In that sense, the FG table acts as **the type descriptor for the tableau**. - -* 3. Binding.lib.c - -The module `Binding.lib.c` defines the canonical layout of an FG-style binding. - -Below is the full source (excluding comments), organized by section. - -**FACE:** -#+BEGIN_SRC c -#ifndef Binding·FACE -#define Binding·FACE - -typedef struct{ - void *tableau; - void *FG; -} Binding; - -#endif -#+END_SRC - -This is the public interface. The type `Binding` is a generic struct that holds two pointers: -- `tableau`: the implementation-specific data (tape, buffer, object, etc) -- `FG`: pointer to a module-specific function table - -**IMPLEMENTATION:** -#+BEGIN_SRC c -#ifdef Binding·IMPLEMENTATION -#endif -#+END_SRC - -No definitions are required here—the binding struct has no behavior of its own. - -**LOCAL:** -#+BEGIN_SRC c -#ifdef LOCAL -#ifndef Binding·LOCAL -#define Binding·LOCAL - -#include -#include - -#endif -#endif -#+END_SRC - -These are the headers required to define the structure and the environment. It also follows the **RT C sectioning model** described in: - -**📎 [[file:sections.org][RT C File Structure and Sectioning]]** - -* 4. Template Use - -Although `Binding.lib.c` does not directly use template parameters, it is often **included repeatedly** in templated modules to create per-instance bindings. - -For example: -#+BEGIN_SRC c -#define _TM·CVT_ AU -#include "TM.lib.c" -#define SET__Binding__TM·AU -#+END_SRC - -The template name `_TM·CVT_` is used to create: -- `typedef struct TM·AU TM·AU;` -- `typedef struct TM·AU·Array·Tableau TM·AU·Array·Tableau;` -- `TM·AU` instances, each of which is a `Binding` with layout and dispatch tied to a particular tableau type. - -See: - -**📎 [[file:template_box_example.org][Templating in RT C — The Box Example]]** - -* 5. The Binding Struct - -Here’s the struct that every FG-style binding uses: - -#+BEGIN_SRC c -typedef struct{ - void *tableau; - void *FG; -} Binding; -#+END_SRC - -The tableau and FG pointers are opaque to the caller. They are interpreted by the functions in the FG table. - -**The binding is the concrete object passed around the system.** - -In most modules, this struct is **re-wrapped** in a typedef, e.g.: - -#+BEGIN_SRC c -typedef Binding TM·AU; -#+END_SRC - -This means that in function signatures and argument lists, the **binding is visible under its module-specific name**, even though all bindings have the same physical layout. - -This separation allows: -- Static type safety at the source level (per module) -- Shared representation at the binary level - -* 6. Example Usage - -Suppose we define a tape machine `TM·AU` over a byte array. The setup might look like: - -#+BEGIN_SRC c -AU tape[] = {0x01 ,0x02 ,0x03}; -extent_t·AU extent = 2; - -TM·AU·Array·Tableau t; -TM·AU tm = TM·AU·Array·init_pe(&t ,tape ,extent); - -if( TM·AU·call(tm ,on_tape) ){ - uchar x = TM·AU·call(tm ,read); - printf("Head reads: %02x\n", x); -} -#+END_SRC - -Here: -- `tm` is a `TM·AU` binding — a `struct` with `.tableau = &t`, and `.FG = &TM·AU·Array·fg`. -- The functions in the FG table dereference `tm.tableau` into the expected type. -- `TM·AU·call` wraps method access, validating the binding under debug builds. - -* 7. Summary - -A **binding** in RT C is: -- A pair of `(tableau pointer, FG table pointer)` -- Constructed per module or template instantiation -- Passed around as the first argument to all FG methods -- Given a distinct *type name* (like `TM·AU`) to encode its role - -A **tableau** is: -- The backing data storage (often a `struct`) -- Interpreted only by the FG methods that operate on it -- Abstractly defined by the FG table it's paired with - -This design gives RT C the benefits of: -- Polymorphism -- Type encapsulation -- Dispatch -- Template instantiation - -All in a clean, structured C style, without runtime type metadata or compiler extensions. diff --git "a/developer/document\360\237\226\211/C_features_needed.org" "b/developer/document\360\237\226\211/C_features_needed.org" deleted file mode 100644 index ca3bee2..0000000 --- "a/developer/document\360\237\226\211/C_features_needed.org" +++ /dev/null @@ -1,53 +0,0 @@ - -1. Cpp needs namespaces. The '·' notation seems to accomplish most of what is needed, and I'm doing this in existing C. Scoped 'using' would be nice for shortening the identifiers. - This can be done without changing the tool chain. - - I am currently using, e.g.: - - Ξ(TM ,TM·CVT ,ARRAY ,Tape·bounded) - - This could be: - - #with Ξ(TM ,TM·CVT ,ARRAY): - ... - ·Tape·bounded = ... - ... - #endwith - - I.e. set the prefix, then for identifiers starting with · set the prefix. `with` - can be nested. - - Also native #cat and #Ξ .. perhaps operators - - If the center dot delineated tokens, then we would not need the Ξ function. - -2. cpp control of evaluation in definitions - - #assign name·#eval(space) #eval(body) - - Temporal assignment. Eval, then define. - - Allows defining a macro while using eval in both the name and body. eval happens - once, and the name is not available to be used in the body. - -3. cpp existence logic - -4. Something should be done about macros having to be on one line and having to account for, format, all those \. Perhaps an emacs mode similar as used for paragraphs? Anyway something should be done. - - #begin - #define ... - ... - ... - #end - -5. C type system, ability to declare a type hierarchy based on struct types having the same field names and format, or extensions thereof. - - typehier pair -> vector-2d -> complex - - Something like that. - -6. C type system, put struct, enum types into the same space with the other types. of course. - -7. A better emacs C formatter - - diff --git "a/developer/document\360\237\226\211/Copy.org" "b/developer/document\360\237\226\211/Copy.org" deleted file mode 100644 index 6ab73ae..0000000 --- "a/developer/document\360\237\226\211/Copy.org" +++ /dev/null @@ -1,93 +0,0 @@ -* Copy - Memory Copy Operations - -** Overview - -The Copy module provides optimized memory copy operations that account for memory alignment and byte order. It contains functions for standard memory copying, as well as specialized routines for reversing byte order during copying. The design ensures efficient memory operations by aligning read pointers and assuming write operations are buffered. - -** Features - -- Optimized memory copy operations -- Byte order reversal during copy -- Handles unaligned read memory -- Ensures efficient bulk transfers using 64-bit word copies -- Provides step-based copying with status reporting - -** Interface - -- `Copy·bytes(read0, read1, write0) -> void*` - - Copies memory from `read0` to `write0`, preserving byte order. - - Returns the updated write pointer. - -- `Copy·reverse_byte_order(read0, read1, write0) -> void*` - - Copies memory while reversing byte order. - - Reads from `read1` downward, writes from `write0` upward. - - Returns the updated write pointer. - -- `Copy·step(Copy·it *it) -> Copy·Status` - - Uses the `Copy·it` struct, which defines read and write intervals. - - Does the maximum sized copy without going outside the intervals. - - Updates `it` for continuation of the block copy. - - Returns a status indicating there is surplus data, or available write allocation. - -- `Copy·step_reverse_order(Copy·it *it) -> Copy·Status` - - Performs a copy of the block while reversing the byte order and updating the iterator. - - Returns a status indicating there is surplus data, or available write allocation. - -- `Copy·step_write_hex(Copy·it *it) -> Copy·Status` - - Converts read bytes into hexadecimal representation during writing. - - Two bytes are written for each byte read.buffer. - - Returns a status indicating there is surplus data, or available write allocation. - -** Status Codes - -- `Copy·Status·perfect_fit` - - Read and write buffers are fully utilized without remainder. -- `Copy·Status·read_data_surplus` - - The write allocation was filled before the read values were all read. -- `Copy·Status·write_allocation_available` - - The write allocation has space for more values. -- `Copy·Status·write_allocation_gap` - - The write allocation has space, but it is not large enough to hold another value. - -** Implementation Notes - -- Alignment is only enforced on the read side to maximize efficiency. -- Writes are assumed to be buffered, allowing unaligned writes without performance degradation. -- The `step` functions allow for incremental processing of data streams. - -** Example Usage - -```c -Copy·it copy_instance = { - .read0 = source_data, - .read_size = source_size, - .write0 = destination_buffer, - .write_size = destination_size -}; - -Copy·Status result = Copy·step(©_instance); -``` - -This module provides an efficient and flexible memory copying framework suitable for low-level data manipulation tasks. - -* Relevant todo note - -2025-02-24T08:09:57Z Copy.lib.c forced alginment machine might have issues with the block copy. - - The block copy aligns the read pointer by copying some initial - bytes. It ignores the alignment on the write pointer. Then at the end it does a byte - by byte copy of the ragged tail (less than a full word number of bytes). - - For a system that forces alignment, the initial alignment of the read pointer will get skipped. The write pointer will be aligned, so there is no problem in not checking it. - - However, the ragged tail loop can fire on a forced aligned - system. This will happen if the bounding read pointer passed in to - the block copy is not pointing to the first byte of a word. This can - happen if it is created adding `sizeof` of an object with that is not an even number - of bytes in a word long. - - The solution is probably to set a 'force align' macro based on the - architecture macro and gating the ragged tail code to do a word - copy, or affecting the bulk section to do one more loop -- or having - a differnt block copy an bytes_reversed block copy that loops on - words. diff --git "a/developer/document\360\237\226\211/FG_tables.org" "b/developer/document\360\237\226\211/FG_tables.org" deleted file mode 100644 index 797b909..0000000 --- "a/developer/document\360\237\226\211/FG_tables.org" +++ /dev/null @@ -1,113 +0,0 @@ -* Function-Given (FG) Tables in RT C -:PROPERTIES: -:AUTHOR: Sorein -:DATE: 2025-04-25 -:END: - -This document introduces **FG Tables**—Function-Given tables, a structured method in RT C for grouping related functions that operate on a common type or binding. We use the `Core` module as a canonical example, as it contains no template variables or tableaux and thus provides the cleanest view. - -**FG Tables** serve a purpose similar to vtables or method dictionaries: they allow operations to be defined once and called generically, using a consistent interface. Unlike C++ vtables, FG tables are explicit, statically defined, and layered via macros in a readable, extensible style. - -**Key concepts:** -- All function signatures take a common first argument (usually a pointer to a "binding" struct). -- The table itself is a `struct` of function pointers. -- The module defines: - - The **type** (e.g. `Core`) - - The **binding struct** (`Core·Binding`) - - The **table definition** (`Core·FG`) - - The **table instance** (`Core·Tableau`) - - Helper macros for calling (`Core·call(...)`) and checking (`Core·wellformed_binding(...)`) - -* Example: Core -Core provides utilities that are always available to the RT system. It defines an FG table without templates or specializations. - -**Declaration (in the FACE section)**: -#+BEGIN_SRC c -#ifndef Core·FACE -#define Core·FACE - -typedef struct Core·Binding Core; - -typedef struct{ - void(*Free)(Core*); - bool(*is_aligned)(Core* ,void const*,uint ,bool*); - void const*(*round_up)(Core* ,void const*,uint); - void const*(*round_down)(Core* ,void const*,uint); -} Core·FG; - -bool Core·wellformed_binding(Core*); -#define Core·call(B ,f ,...) ((Core·wellformed_binding(B)) ,(B)->FG->f(B ,__VA_ARGS__)) - -#endif -#+END_SRC - -**Explanation of Functions:** - -- `Free(Core*)`: Frees the binding and sets its pointer to `NULL`. This follows the `Free(pt) = free(pt); pt = NULL;` idiom defined in RT. -- `is_aligned(Core* ,void const* p ,uint alignment ,bool* result)`: Determines whether `p` is aligned to `alignment`. Writes result to `*result`, returns false if `p == NULL`. -- `round_up(Core* ,void const* p ,uint alignment)`: Returns the smallest aligned address ≥ `p`. -- `round_down(Core* ,void const* p ,uint alignment)`: Returns the largest aligned address ≤ `p`. - -All alignment operations use address logic with explicit alignments passed at runtime, rather than compile-time constants. - -* Implementation -The FG table instance is defined in the `Core·IMPLEMENTATION` section: - -#+BEGIN_SRC c -#ifdef Core·IMPLEMENTATION - -bool Core·wellformed_binding(Core* B){ - return B && B->FG == &Core·Tableau; -} - -Local void Core·Free(Core* B){ - Free(B); -} - -Local bool Core·is_aligned(Core* B ,void const* p ,uint alignment ,bool* result){ - if(!p){ *result = false; return false; } - uintptr_t up = (uintptr_t)p; - *result = (up % alignment) == 0; - return true; -} - -Local void const* Core·round_up(Core* B ,void const* p ,uint alignment){ - if(!p) return (void const*)(uintptr_t)alignment; - uintptr_t up = (uintptr_t)p; - return (void const*)((up + alignment - 1)/alignment*alignment); -} - -Local void const* Core·round_down(Core* B ,void const* p ,uint alignment){ - if(!p) return NULL; - uintptr_t up = (uintptr_t)p; - return (void const*)(up / alignment * alignment); -} - -Core·FG const Core·Tableau = { - .Free = Core·Free, - .is_aligned = Core·is_aligned, - .round_up = Core·round_up, - .round_down = Core·round_down -}; - -#endif -#+END_SRC - -* Usage Example -#+BEGIN_SRC c -Core* B = malloc(sizeof(Core)); -B->FG = &Core·Tableau; - -bool aligned; -Core·call(B ,is_aligned ,(void*)0x1000 ,16 ,&aligned); - -void const* r = Core·call(B ,round_up ,(void*)0x1003 ,16); -#+END_SRC - -* Summary -- FG Tables provide modular polymorphism in pure C. -- The `Core` FG is the simplest: no template variables, no tableaux layers. -- The FG naming convention (`Module·FG`) and `call(...)` wrapper provide safety and convenience. -- FG patterns scale to support templated modules with `FG·Type`, `FG·Tableau`, and dispatch guards. - -FG tables are foundational to the RT C architecture, forming the dispatch layer behind modular, template-like polymorphism in a static language. diff --git "a/developer/document\360\237\226\211/TapeMachine_howto.org" "b/developer/document\360\237\226\211/TapeMachine_howto.org" deleted file mode 100644 index f156c23..0000000 --- "a/developer/document\360\237\226\211/TapeMachine_howto.org" +++ /dev/null @@ -1,145 +0,0 @@ -#+TITLE: How to Use a TM: Tape Machine Structure and Semantics -#+AUTHOR: Sorein -#+DATE: 2025-04-25 - -* 1. Introduction - -The `TM` module in RT C implements a **Tape Machine** abstraction—a generic, forward/backward traversable sequence with a *head*, *bounded extent*, and *cell value type* (CVT). - -Each instantiated TM (e.g. `TM·AU`, `TM·Str`) is a **binding** that combines: -- A `tableau` — the backing data or representation (e.g. array, singleton, zero-length) -- An `FG table` — the dispatch logic defining how the head behaves - -TM is not a container. It is a *lens* or *state machine* for traversing memory in a structured way. - -* 2. Constructing a TM - -To construct a TM instance, you typically: -1. Define the tape data (e.g. an array of AU or Str) -2. Define its extent -3. Allocate a `Tableau` struct (e.g. `TM·AU·Array·Tableau`) -4. Initialize the TM using `init_pe` or `init_pp` - -#+BEGIN_SRC c -AU tape1[] = {0xAA ,0x55 ,0xC2}; -extent_t·AU extent1 = sizeof(tape1) / sizeof(AU) - 1; - -TM·AU·Array·Tableau t1; -TM·AU tm1 = TM·AU·Array·init_pe(&t1 ,tape1 ,extent1); -#+END_SRC - -The resulting `tm1` is a **binding**—you pass it to functions via `Binding·call` or `TM·AU·call`. - -* 3. TM Method Overview - -The key methods in the TM FG table are: - -| Method | Description | -|--------------------+--------------------------------------------------| -| `mount` | Reattach head to the tape if dismounted | -| `dismount` | Detach the head (mark as inactive) | -| `status` | Returns the full head status bitmask | -| `on_tape` | True if the head is on a valid cell | -| `on_leftmost` | True if head is at the leftmost cell | -| `on_rightmost` | True if head is at the rightmost cell | -| `step`, `step_left`| Move head forward or backward | -| `rewind` | Move head back to its starting position | -| `read` | Return the cell value under the head | -| `write` | Overwrite the cell under the head | - -* 4. Loop Structure: Prefix, Separator, Postfix - -Traversal is typically done with **guarded middle-exit loops**, allowing for insertion of: - -- A **prefix** (runs before loop) -- A **separator** (runs between each item) -- A **postfix** (runs after loop) - -Example pattern (printing a tape with separators): -#+BEGIN_SRC c -if( Binding·call(tm ,on_tape) ){ - // Prefix - do{ - // Body - printf("%02x", (unsigned int) Binding·call(tm ,read)); - - // Guarded middle exit - if( Binding·call(tm ,on_rightmost) ) break; - - // Separator - putchar(' '); - - // Step - Binding·call(tm ,step); - }while(1); - // Postfix - putchar('\n'); -} -#+END_SRC - -This avoids the need for counter variables, array indexing, or special cases for first/last iteration. - -* 5. Example: Nested TM Traversal - -The following example demonstrates two tapes—`tm1` of bytes, and `tm2` of strings—printing a byte followed by the full string tape on each outer step. - -#+BEGIN_SRC c -if( Binding·call(tm1 ,on_tape) && Binding·call(tm2 ,on_tape) ){ - do{ - // Prefix of outer loop - printf("%02x\n", (unsigned int) Binding·call(tm1 ,read)); - putchar(' '); - putchar(' '); - - // Inner loop: iterate over strings - do{ - printf("%s", Binding·call(tm2 ,read)); - if( Binding·call(tm2 ,on_rightmost) ) break; - putchar(' '); - Binding·call(tm2 ,step); - }while(1); - - // Postfix of inner loop - putchar('\n'); - - // Guarded exit - if( Binding·call(tm1 ,on_rightmost) ) break; - - // Advance outer head - Binding·call(tm1 ,step); - - // Reset inner head - Binding·call(tm2 ,rewind); - }while(1); - - // Final postfix - printf("\n"); -} -#+END_SRC - -This structure supports: -- Interleaved traversal of coextensive tapes -- Mid-line formatting -- Reusable subroutines for iteration - -* 6. Debugging Tips - -- Use `on_tape`, `on_rightmost`, and `status` to check head validity before reading. -- `rewind` is always safe to call, even on a dismounted tape. -- `dismount` prevents accidental traversal if a tape becomes invalid or externally reallocated. - -* 7. Summary - -The Tape Machine abstraction supports: -- Generic data traversal -- Separation of structure (tableau) from behavior (FG table) -- Elegant loop patterns with predictable control flow -- Multi-instance coexistence via templated bindings - -By adopting TMs, RT C code gains clarity and uniformity when working over ranges, buffers, or token streams—without abandoning type safety or performance. - -For detailed reference on bindings and FG tables, see: - -**📎 [[file:fg_bindings_and_tableaux.org][FG Tables and Bindings in RT C]]** - -**📎 [[file:fg_tables_core.org][FG Tables — Core Module Example]]** diff --git "a/developer/document\360\237\226\211/alignment.org" "b/developer/document\360\237\226\211/alignment.org" deleted file mode 100644 index c77db25..0000000 --- "a/developer/document\360\237\226\211/alignment.org" +++ /dev/null @@ -1,28 +0,0 @@ - -*recovering alignment of pointers that point to array cells (elements) - -Interesting observation, recovering alignment for a pointer into an array is expensive. It requires modulus against the element size to find how far off the pointer is. - -*converving alignment - -If one starts aligned, say on zero, then only increments by the element size, alignment is not ever lost. However, if an element pointer is computed by a imprecise process, and rounding is recovered to get it back again, then the modulus is required. - -*power of radix boundaries - -However, modulus is not hard on powers of the radix boundaries. - -So either a) in the first place make elements a power of the radix in size, perhaps even using padding, b) change the radix of the number system so the native element size if the radix, or a power there of c) never do a computation that loses alignment. - -As a consequence it is expensive to compute the extent of an object with arbitrary CVT (Cell Value Type). Given the two bounding pointers, one must subtract and divide by the sizeof(CVT) to recover the extent, and divide is expensive. In contrast when given the position and extent, the address of the rightmost cell can be recovered with an addition. - -*store base and extent, rather than two pointers - -It follows that if the extent is needed that it makes more sense to store the position and extent for an interval than it does to store two bounding pointers. - -*unaligned bound - -`on_rightmost` is a precise predicate. If the head pointer were advanced by a value other than sizeof(CVT) then it could step right over the base pointer to the rightmost cell. If this was part of looping, the loop would continue. - -A situation where this could happen, suppose we want to copy a block of memory. We walk AU by AU (byte by byte) up to an aligned on AU8 address. Then we copy AU8 by AU8. Here is the problem, the actual data being copied ends on an AU pointer boundary, not an AU8 pointer boundary. It is not difficult to round down to an AU8 because 8 is a power of two. This round down is required, to the point of the last full AU8 that can be copied, to stop the AU8 copy. This is not a problem for AU8 because 8 is a power of two. - -However, if the increment were by the size of CVT, and the boundary was given given by an AU pointer, then rounding down requires a modulus operation to know where the last CVT fits in. It is not clear what use case exists for this. diff --git "a/developer/document\360\237\226\211/build.org" "b/developer/document\360\237\226\211/build.org" deleted file mode 100644 index a499421..0000000 --- "a/developer/document\360\237\226\211/build.org" +++ /dev/null @@ -1,8 +0,0 @@ - - -> make clean -> make dependency -> make library -> make cli - -I manually edit the make file to turn on and off the making of the main program or the example directories. See notes in ` tool🖉/makefile`. diff --git "a/developer/document\360\237\226\211/coffee.txt" "b/developer/document\360\237\226\211/coffee.txt" deleted file mode 100644 index daf4508..0000000 --- "a/developer/document\360\237\226\211/coffee.txt" +++ /dev/null @@ -1,20 +0,0 @@ -/* - Coffee Species Reference - - | Species | Origin(s) | Flavor Notes | Notes | - |-----------|----------------------------|----------------------------|------------------------------- | - | Arabica | Vietnam (Da Lat), Malawi | Floral, bright, acidic | High elevation, lower caffeine | - | Robusta | Vietnam (Dak Lak, Gia Lai) | Bitter, strong, earthy | Common in Vietnamese blends | - | Excelsa | Vietnam (Central Highlands)| Tart, fruity, smoky | Adds depth, low production | - | Liberica | Vietnam (rare farms) | Woody, floral, full-bodied | Very large beans, low yield | - - Likely Blend (CASA Blue Mountain): - - Arabica (Malawi or Da Lat) - - Robusta (Vietnam) - - Possibly Excelsa (depth/complexity) - - Notes: - - "Made in Taiwan" likely refers to roasting/packaging. - - Shelf life: 2 years (cool, dry, or frozen recommended). - - Freezing whole beans is safe *if sealed airtight* and thawed only once. -*/ diff --git "a/developer/document\360\237\226\211/cpp_gothyas.txt" "b/developer/document\360\237\226\211/cpp_gothyas.txt" deleted file mode 100644 index b207c93..0000000 --- "a/developer/document\360\237\226\211/cpp_gothyas.txt" +++ /dev/null @@ -1,84 +0,0 @@ - -1. - -A semicolon after a macro definition becomes part of the macro body. - - -2. - -When defining a macro: - - No space between the macro function name and the parameter list. - - Otherwise the would-be parameter list will be taken to be part of a macro variable definition. - -When calling a macro. - Can have space between a macro function name and the argument list. - - -3. - - Macro function definitions are not evaluated, so the body (the definition) of the macro remains literal until the time it is called. - - -> macro calls in macro defintions remain literal, i.e. unevaluated. - -4. - -Macros can be called with empty arguments. - - #+BEGIN_SRC c - #define a_macro(a ,b ,c) (a + b + c) - int a_macro (a,,b) // -> a + + c - #+END_SRC - -5. - -The COMMA macro, though defined, can't be used in any two level or more deep macro calls, because it will expand to a comma on the first level. It perhaps could be wrapped in a function that is given a deferred call, and then have eval expand it, dunno. - - -4o has written a little doc about this: - - * CATSEP Separator Expansion Notes - :PROPERTIES: - :CREATED: [2025-04-01] - :END: - - ** Problem - - When using `CATSEP` (or `CAT`) to join tokens with a separator, we encountered an issue where passing a macro-defined separator (e.g. `COMMA`) leads to incorrect behavior: - - - The macro expands too early. - - The result is malformed token pasting like `,A` instead of proper separation. - - This happens because `##` prevents further expansion, so any `sep` macro used in a `##` must already be fully resolved. - - ** Attempts - - We tried multiple versions: - - Using `DEFER`, `DEFER2`, `DEFER3` to hide expansion. - - Wrapping the separator in a macro (e.g. `DEFER_SEP()`). - - Recursive accumulation models with delayed evaluation. - - ** Findings - - - The separator **must not be a macro** when passed as an argument to a `##` operation. - - Macro arguments are always expanded before `##` is applied, unless blocked (e.g., by an extra layer of indirection). - - `##` prevents further expansion, so once the macro has been expanded into a literal comma (`,`) or semicolon (`;`), it can no longer be deferred. - - ** Recommendation - - Use raw characters or tokens as separators, not macros. For example: - - #+begin_src c - CAT(, A ,B ,C) // OK makes a token ABC - CAT(;, A ,B ,C) // OK - [I don't think this works either] - CAT(__oo__, A ,B ,C) // OK A__oo__B__oo__C - CAT(COMMA, A ,B ,C) // ❌ COMMA expands too early - #+end_src - - If you must use a macro-defined separator, redesign may be required. For now: - - ** Conclusion - - ⛔ **Do not use macro-defined separators in `CAT` or `CATSEP`.** - - Leave this as a known limitation and revisit if/when it becomes essential. Better to avoid the rabbit hole for now. diff --git "a/developer/document\360\237\226\211/cpp_grammar.org" "b/developer/document\360\237\226\211/cpp_grammar.org" deleted file mode 100644 index 98e5154..0000000 --- "a/developer/document\360\237\226\211/cpp_grammar.org" +++ /dev/null @@ -1,52 +0,0 @@ -Grammar - - identifier = [_a-zA-Z][_a-zA-Z0-9]* - | ([_a-zA-Z\u00A0-\uFFFF])([_a-zA-Z0-9\u00A0-\uFFFF])* - - macro_name = identifier - - token = identifier - | number ; e.g., 42, 0xFF, 3.14 - | string_literal ; "hello" - | character_constant ; 'a', '\n' - | operator_token ; +, -, ~, <<, etc. - | punctuation ; (), [], {}, etc. (when tokenized) - | parenthesized_expr ; (1,2), (x + y) - - empty_item = ε - This stands for nothing. It is useful for talking about item lists, because in general lists can have empty slots. Remember cpp works with literal text. - - For example, ( , ) is a length 2 list with two empty slots. - - For example, (1,,2) is a length 3 three list with one empty slot. - - On calls, the length of the arg_list must match length of the parameter list. - - For example, _FIRST() has a first parameter that expands to nothing if it is referenced - #define _FIRST(a ,...) a - _FIRST() --> ε is not a bad argument count error, but instead expands to nothing - - general_list = token (, token | ε)* - Comma-separated list of items. Commas can appear without tokens between them. - - arg_list = general_list - - pair = token | ε , token | ε; exactly two tokens. - - twion = pair - A special two-token list given to certain macros in a place one token is expected. - Its role is to shift the remaining members of a list by one position when prepended. - An honorary member of the single token club. A common twion is `~,1` - - parm_list = identifier (, identifier)* ; comma-separated list of identifiers - A parameter list differs from a general list in that two commas can not - appear adjacent to each other, and all members are identifiers. - - -2.2 'private' identify - - By convention private identifiers begin with an `_` character. - - Macros with this prefix are not intended to be called by users, and - indentifiers with this prefix are not intended to to used. - diff --git "a/developer/document\360\237\226\211/cpp_macro_expansion.org" "b/developer/document\360\237\226\211/cpp_macro_expansion.org" deleted file mode 100644 index 43ac72a..0000000 --- "a/developer/document\360\237\226\211/cpp_macro_expansion.org" +++ /dev/null @@ -1,337 +0,0 @@ -#+TITLE: C Preprocessor Expansion Example -#+AUTHOR: Thomas Walker Lynch -#+OPTIONS: toc:nil - -1. Macro function definition - - Macro function definitions are not expanded, so the body (the definition) of the macro remains literal until the time it is called. Thus macro calls in macro defintion remain - literal, unexpanded. - - A macro function has three parts, 1) a name 2) a parameter list 3) body - - Parameters are declared by listing them between parenthesis after the name. No space - can occur between the name and the parameter list! If there is space then the - parameter list will be taken as part of the body. - - Text after the parameter list forms the body. - - #+BEGIN_SRC c - #define name(x ,y ,z) - #define name(...) // argument list becomes __VA_ARGS__ - #define name(x ,...) - #+END_SRC - -2. directives - - #define name is never expanded. body is not expanded when the definition is - added to the symbol table, but is expanded through a call to the macro. - - #ifdef and #ifndef do not evaluate what follows. They expect an already formed - macro name. - - #if does evaluate, but expects existence as true, and 0 as false (though zero - also exists). Non-existence is an error. Wrap cpp_ext_0 logic in BOOLEAN to get 1 or 0. (cpp_ext_0 logic is true for existence, and false for nonexistence.) - -2. Macro Call - - A macro call that was colored blue will not be expanded. - - A macro call can occur anywhere in the source code. It takes the form of a macro - name followed by an argument list: - - #+BEGIN_SRC c - name(1 ,a ,b) - #+END_SRC - - In a call, space is allowed between the macro name and the argument list. - - Not in strings, not embedded in other tokens. If a macro definition has the same name as the call, then that is a redefinition, an redefinition is not allowed. - - cpp scans the tokens in the translation unit, upon finding a macro call it replaces it with the body from the macro definition using the following steps: - - ** 1. Argument Substitution Phase - - When the macro is invoked: - - 1. Each parameter in the macro body is replaced *verbatim* with the - corresponding argument. No expansion is performed at this stage. - - 2. The new macro body is a new token stream: the old macro body with arguments pasted in. - - ** 2. Expansion Phase - - The preprocessor then scans the argument substituted macro body *from left to right*, - evaluating macro calls *as it encounters them*. - - - If a token is **not** a macro call (see below), it is included as-is. - - If a token **is** a macro call, it is expanded immediately, using the same two-phase process. - - This produces a depth-first, left-to-right expansion strategy. - - Non-macro-call tokens include: - - 1. Any non-identifier (e.g. `+`, `123`, `"text"`) - - 2. Any identifier **not followed by `(`** - - 3. Any parameter or token used with `#` - - - `#param` turns the *original* argument text into a string. - - Because it stringifies, *the argument is never expanded*. - - 4. Any parameter or token used with `##` - - - `##` concatenates tokens without evaluating them. - - The pasted result is *not* scanned recursively for macro calls. - - 5. any macro call token that has been "colored blue" by the evaluator. - - It is common that macros containing a `#` or a `##` will have an extra call - layer above them to cause the argument to be first substituted into a macro - where it will get expanded. Large number of Eval calls are typically not needed - for this, rather what is needed is one layer above the layer with the `#` or `##`. - - ** 3. Colored blue macro call tokens are taken as literal text. - - During expansion cpp keeps a list of macros that are actively being expanded. This includes the macro that has been called, of course, and all the calls that it found during its depth traversal to get to the current point of expansion. If it sees any calls to the macros on the active expand list, it marks the macro call token itself as unexpandable, and thus to be treated as literal text. It is said that the macro call token "has been colored blue". - - Any subsequent appearance of a colored blue macro call token will be treated as literal text, no matter the context. This includes if the macro result was assigned to a variable, then that variable is expanded later. It includes if the macro call token or the expression it is in is sent to another macro, etc. - - Example: - - #+BEGIN_SRC c - #define GROW(x) 1029 * GROW(x) - #define RESULT GROW(5) - - SHOW(RESULT); // → 1029 * GROW(5) - SHOW(EVAL(RESULT)); // → 1029 * GROW(5) again, never expands - #+END_SRC - - The macro call token `GROW(x)` which occurs in the body of a macro definition of the same name, gets colored blue, and thus is always treated as literal text. This happens even though an expression containing it is assigned to a variable, then that variable is expanded in a totally different expansion context. - - Apparently the designers of cpp do not want people to design recursive structures with cpp. However, there is a trick for getting around it using a confederate in place of the recursive call, then putting back the original call later, as shown in section 6. - -3. Example macros - - #+BEGIN_SRC c - #define FORCE_ONE(x) 1 - #define STR(x) #x - #define VAL(x) STR(x) - #define GROW(x) 7 * GROW(x) - #+END_SRC - - A call to ~FORCE_ONE(5)~ will expand to ~1~. - - A call to ~STR(FORCE_ONE(5))~ will expand to the string ~"FORCE_ONE_(5)"~. This is because arguments given to the ~#~ operator are not expanded. The variable gets replaced with its value, but the value it not expanded. - - A call to ~VAL(FORCE_ONE(5))~ will result in `1`. This is because there is no hash symbol in the VAL macro that is stopping the recursive expansion of ~x~. - -5. Cascading expansion - - A macro can also fail to evaluate all possible macros, because during the left to right scan, it created a macro call, but during the scan it did not see it. - - #+BEGIN_SRC c - #define NULL_FN() // expands to nothing - #define NEGATE(x) -x - #define NOT_SO_FAST(x) NEGATE NULL_FN() (x) - #+END_SRC - - When evaluating ~NOT_SO_FAST(5)~, here's what happens: - - 1. ~NEGATE~ is encountered there is nothing to recur into, so it evaluates to itself. - the expansion moves right. - - 2. ~EMPTY()~ is a macro, so it has no operands, so it is expanded. As it has no - body, it expands to nothing. CPP then moves to the right. - - 3. ~(x)~ is not a macro so there is nothing to recur into, so it becomes ~(5)~. - - 4. Thus the final result of the left to right pass is → ~NEGATE (5)~ The evaluator - recursively expands calls, but it never saw ~NEGATE (5)~, so it remains unexpanded. - This is the second reason a literal macro call might occur in an expansion. - - #+BEGIN_SRC bash - cat >test.c < - - int main(void){ - printf("example_eval.c\\n"); - - #define STR(x) #x - - // `#x` no expansion of x due to the '#' - // `STR(x)` recurs and does a left to right expansion on the value of `x` - #define SHOW(x) printf(#x " → %s\\n", STR(x)); - - #define EMPTY() - #define NEGATE(x) -x - #define NOT_SO_FAST(x) NEGATE EMPTY() (x) - - SHOW(NOT_SO_FAST(5)); - - #define BE(x) x - SHOW(BE(NOT_SO_FAST(5))) - } - EOF - - gcc test.c - ./a.out - #+END_SRC - - Output: - - #+BEGIN_EXAMPLE - example_eval.c - NOT_SO_FAST(5) → NEGATE (5) - BE(NOT_SO_FAST(5)) → -5 - #+END_EXAMPLE - - Let’s examine the final lines: - - #+BEGIN_SRC c - #define BE(x) x - SHOW(BE(NOT_SO_FAST(5))) - #+END_SRC - - The expansion process: - - - cpp encounters ~BE(NOT_SO_FAST(5))~. - - It enters ~NOT_SO_FAST(5)~, expands it to ~NEGATE (5)~. - - Then ~BE(NEGATE (5))~ becomes ~-5~ through final macro expansion. - - ------- - - The `IF` macro evolves and does three self expansions, due to new strings - being created which in turn match already defined macros. - - series of events, explain why the DEFER3, ph - - #+BEGIN_SRC c - IF \ - ( NOT_EXISTS(__VA_ARGS__) ) \ - () \ - (IF \ - ( predicate(FIRST(__VA_ARGS__)) ) \ - ( FIRST( ,__VA_ARGS__) ) \ - ( DEFER3(_FIND_CONFEDERATE) ()(predicate ,REST(__VA_ARGS__)) ) \ - ) - #+END_SRC - - -6. Nesting, recursion approaches that do not work, and one that does. - - #+BEGIN_SRC c - - #include - #define STR(x) #x - // no expansion, and one pass of expansion - #define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) - - #define BE(...) __VA_ARGS__ - #define EMPTY() - - #include - int main(void){ - printf("example_grow.c\n"); - printf("\n"); - - // case 1 - /* - GROW(7) → 17 * GROW(7) - GROW(GROW(5)) → 17 * GROW(17 * GROW(5)) - ,*/ - #define GROW(x) 17 * GROW(x) - SHOW(GROW(7)); - SHOW(GROW(GROW(5))); - printf("\n"); - - // case 2 - // GROW2(11) --> 19 * GROW2 (11) - #define GROW2(x) 19 * GROW2 EMPTY() (x) - SHOW(GROW2(11)) ; - printf("\n"); - - // case 3 - // GROW3(13) --> 119 * 19 * GROW2 (13) - #define GROW3(x) BE(119 * GROW2 EMPTY() (x)) - SHOW(GROW3(13)); - printf("\n"); - - // case 4 - /* - `BE` placed on the outside. The idea is that expansion will return `123 * GROW (15)` and then this will be expanded resulting in `123 * 123 * GROW(15)`. - - However, any time GROW4 literally spells out GROW4(...) inside its own expansion - it will leave it literally and not expand it. - - Though it is interesting that here that occurs at a higher level in the expansion tree than the first ocurrance of the recursive call, but still it is in the tree. - - GROW4(15) --> 123 * GROW4 (15) - ,*/ - #define GROW4(x) BE(123 * GROW4 EMPTY() (x)) - SHOW(GROW4(15)); - printf("\n"); - - // case 5 - /* - Substitution of the function named followed by a trampoline works. - - The original expression is written in terms of a deferred CONDFEDERATE function - instead of in terms of a recursive call to GROW5. cpp can suspect nothing. - - The result is an expression in terms of the unexpanded CONDFEDERATE function. - - The CONFEDERATE function is defined to return the token GROW5. Hence in a subsequent expansion, and there must be a subsequent expansion for this to work, The CONFEDERATE function will run, return GROW5 which is next to its call parenthesis, so then the - recursive call will run. - - BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) - BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) - ,*/ - #define GROW5(x) 541 * CONFEDERATE EMPTY() () (x) - #define CONFEDERATE() GROW5 - SHOW(BE(GROW5(21))); - SHOW(BE(BE(GROW5(57)))); - printf("\n"); - - // case 6 - /* - Once a recursively called function is marked, or 'colored' it can never be expanded, even when passed through to another variable and separately expansion. - ,*/ - #define GROW6(x) 1029 * GROW6 EMPTY() (x) - #define RESULT1 GROW6(51) - SHOW(RESULT1); - SHOW(BE(RESULT1)); - printf("\n"); - // RESULT1 --> 1029 * GROW6 (51) - // BE(RESULT1) --> 1029 * GROW6 (51) - - // case 7 - #define RESULT2 GROW6(151) - SHOW(RESULT2); - SHOW(BE(RESULT2)); - printf("\n"); - // RESULT2 --> 1029 * GROW6 (151) - // BE(RESULT2) --> 1029 * GROW6 (151) - - } - - #+END_SRC - -7. Discussion on recursion - - Case 6, and Case 7 above show that once a token is marked as a would-be recursive call token it is marked and can never be expanded, no matter how hard the programmer - might try hide its actual origin. It can be assigned to variables, passed between co-routines, and nothing will help because the macro call token itself is marked. - - Case 5 shows a workaround. Instead of having a recursive call, a deferred call to a confederate is made. The resulting expression then amounts to a lazy expansion. The return value from the expansion will contain unmade calls to the confederate in each and every place that a recursive call was desired. - - In order to complete the expansion, the lazy result must undergo a second expansion, - where the confederate function calls are run, and they return the name of the original - function that was to be called, and then those calls are expanded. - - This leads to a trade off. To have recursion we must have two expansions of expressions so as to replace the confederates. - - Repeated expansion is a consequence of using confederate method to avoid macro calls from being marked not to be expanded. Deferring the calls is necessary so that the don't get replaced in the first expansion so that their replacements don't get marked. - - Note that each recursive call, potentially results in ore expressions appearing. Hence, there must be as many expansions as there are levels of recursion. This is a tell order for list processing. - - diff --git "a/developer/document\360\237\226\211/parameterized_functions.org" "b/developer/document\360\237\226\211/parameterized_functions.org" deleted file mode 100644 index 26d1c6a..0000000 --- "a/developer/document\360\237\226\211/parameterized_functions.org" +++ /dev/null @@ -1,120 +0,0 @@ -* Parameterized Functions - Author: Thomas Walker Lynch / Drafted by Caerith - -* 1. Parameterization in Mathematics -In mathematics, **parameters** are used to define structured families of functions. For example, consider the family: - -#+BEGIN_SRC -{ f_t(x) = t * x, g_t(y) = y + t^2, h_t(z) = sin(tz) } -#+END_SRC - -Each function in this family shares a symbolic parameter `t`, which organizes the family and distinguishes its members. The functions differ in behavior based on the fixed value of `t`, even though they operate on different primary arguments (`x`, `y`, `z`). - -This reveals the core role of a parameter in mathematics: it does not merely serve as an argument to a single function, but rather defines **a space of functions** — a higher-order structure from which individual functions can be selected by fixing the parameter. - -In this context, we say: -> A parameter is an external symbolic structure that appears as an argument in each function, but whose true role is to *coordinate or classify* the family of functions as a whole. - -Once a value is chosen for the parameter, it becomes fixed, and the resulting function behaves purely in terms of the remaining arguments. The collection \( \{f_t, g_t, h_t\} \) for varying `t` forms a **parameterized family**, and the parameter gives it structure. - -* 2. The Confusion in Computer Science -In computer science, the term "parameter" is typically conflated with what are more properly called arguments. One speaks of a "parameter list" when defining a function, but these are just **argument symbols**, and at runtime, **argument values** are supplied. - -To clarify: -- An **argument symbol** is a variable used in a function definition. -- An **argument value** is an input supplied at invocation. - -We reserve **parameter** to mean: *a symbolic value that organizes or shapes a function or function family*. This returns us to the mathematical intent. - -Seen from this angle, **object-oriented programming** is a way of constructing **families of parameterized functions** — each method implicitly taking the object (`this`) as a shared structure. That object acts as a **fixed symbolic input** across many functions: it is the parameter. The set of methods thus defines a family. - -- For one parameter (i.e., one receiver object), the system is straightforward. -- For two, ambiguity emerges: whose methods govern? This gives rise to multiple dispatch, traits, and other formal structures. - -Thus, **object-orientation is a particular implementation of parameterized function families**, where the parameter is embedded as implicit context. - -* 3. When Parameters Can Change: Machines -In pure mathematics, the parameter is fixed during evaluation. But when a function can *modify* its parameter — i.e., mutate the context it depends on — then we are no longer dealing with functions in the mathematical sense. - -> When the parameter is no longer constant, but mutable, it becomes **state**. - -A function family with a mutable parameter is not a function family at all — it is a **machine**. The state evolves over time, and each function application may affect future behavior. - -This is a transition from **functional** to **stateful** systems. The parameter becomes a **tableau**: a symbolic structure that holds state, arguments, results, and evolves during execution. It is the parameter made writable, and the environment through which computational interaction unfolds. - -A tableau is not limited to a single function family — it may participate in multiple. It is both an input/output workspace and a memory of prior execution. - -In this view, TTCA and similar systems operate not just with functions, but with machines — bundles of callable behaviors that mutate their shared tableau. - -* 4. Our Terminology -To capture these distinctions, we adopt the following terminology: - -- **PFT**: A *Parameterized Function Table* over carrier type `T`. This is a symbolic table of functions that each expect a `T` as their first argument. -- **M** or **Machine**: A special case of PFT where `T` is not constant but a **tableau**, and may be mutated during evaluation. -- **Tableau**: A symbolic structure that accumulates inputs, stores return values, and evolves during execution. It is both interface and state — a writable parameter and a staging area for symbolic computation. It generalizes a stack frame and may serve multiple function families simultaneously. - -This language aligns our system with mathematical clarity while preserving the structural richness of the tableau concept. - -* 5. The Parameter Connector: Binding Parameters to Function Families -In mathematics, writing a subscript such as `f_t(x)` indicates that a function family `f` has been **partially applied** by fixing its parameter `t`. This is called **partial application** — and it represents the act of creating a specific instance of a function from a broader, parameterized family. - -In our system, we reflect this idea using a symbolic structure called the **Parameter Connector**. - -> A **Parameter Connector** is a type that declares how a specific parameter (e.g., a `Tableau`) is to be coupled with a Parameterized Function Table (PFT). It is the symbolic form that supports partial application and prepares the ground for dispatch. - -The macro: - -#+BEGIN_SRC c -DECLARE_PARAMETER_CONNECTOR(MyType) -#+END_SRC - -declares a `struct` named `MyType`, which contains: -- a pointer to a `MyType_Tableau` (the parameter value) -- a pointer to a `MyType_PFT` (the function table) - -This struct is the **parameter connector**. It does not yet perform binding, but defines the shape of a pairing. Once an instance is created — with the parameter value assigned — we may dispatch calls via: - -#+BEGIN_SRC c -call(connector, fn_name, args...); -#+END_SRC - -This pattern reflects the subscripting act in mathematics. The `connector` serves as the **parameter-binding context**: it is what affixes the symbolic `t` to the `f` in `f_t(x)`. - -In this way: -- **The connector is to `call()` what a subscript is to a function name**. -- It allows partial application of parameterized function tables. -- It forms the bridge from symbolic family to concrete callable form. - -Thus, the **parameter connector** is the central structure that enables meaningful dispatch in a system of parameterized functions — faithful both to mathematical abstraction and to C's structural constraints. - - - - -#+BEGIN_SRC - ┌──────────────────────┐ - │ Function Family │ - └────────┬─────────────┘ - │ - ┌───────────────┼───────────────┐ - ▼ ▼ -┌──────────────┐ ┌────────────────────┐ -│ Parameter t │ │ Parameterized │ -│ (symbolic) │ │ Function Table PFT │ -└──────┬───────┘ └────────┬───────────┘ - ▼ ▼ - ┌───────────────────────────────────┐ - │ Partial Application Step │ - └──────────────┬────────────────────┘ - ▼ - ┌────────────────────────┐ - │ Parameter Connector │ - └────────────┬───────────┘ - ▼ - ┌─────────────┐ - │ call() │ - └────┬────────┘ - ▼ - ┌───────────────┐ - │ Machine │ - └───────────────┘ -#+END_SRC diff --git "a/developer/document\360\237\226\211/set_list.org" "b/developer/document\360\237\226\211/set_list.org" deleted file mode 100644 index fa12a7a..0000000 --- "a/developer/document\360\237\226\211/set_list.org" +++ /dev/null @@ -1,123 +0,0 @@ -\#+TITLE: Using `#assign` to Construct Sets and Lists in the C Preprocessor -\#+AUTHOR: Thomas Walker Lynch -\#+DATE: 2025-05-06 -\#+OPTIONS: toc\:nil num\:nil -\#+LANGUAGE: en - -The `#assign` directive allows the programmer to perform runtime macro redefinitions within the C preprocessor. This facility introduces mutability and symbolic indirection, enabling set and list representations not possible with static `#define`s alone. - -* Introduction - -Normally, the C preprocessor (`cpp`) operates as a single-pass, immutable macro expander. Once a macro is defined, it cannot be updated or re-bound without manual `#undef` intervention, and even then only in certain contexts. `#assign`, by design, bypasses this constraint. - -It enables symbolic mutation. With this, we can simulate associative data structures: sets, lists, cons cells, even environments. - -* Representing Sets with `#assign` - -In a conventional C macro environment, a set cannot be constructed dynamically because macro definitions are static. However, with `#assign`, we can model a set as a collection of defined macro names. - -\*\* Membership Test - -To test whether `X` is in a set: - -\#+begin\_src c -\#ifndef \_SET\_\_X -\#define NOT\_MEMBER -\#else -\#define MEMBER -\#endif -\#+end\_src - -We treat the existence of the macro `_SET__X` as a membership marker. - -\*\* Adding to the Set - -We can define an element by assigning an empty macro: - -\#+begin\_src c -\#assign (\_SET\_\_X, ) -\#+end\_src - -This simulates inserting `X` into the set. - -\*\* Properties - -* Sets are /existence-based/: their content is inferred by symbol presence, not enumeration. -* There is /no inherent order/ to the elements. -* You /cannot enumerate/ the contents of the set without external bookkeeping. - -- Representing Lists with `#assign` - -Lists can be represented as chained macros where each node is a pair (a cons cell): - -\#+begin\_src c -\#define c0 (a, b) -\#define c1 (c, d) -\#assign (SECOND(c0), c1) -\#define c2 (e, f) -\#assign (SECOND(c1), c2) -\#+end\_src - -This forms a chain: - -\#+begin\_src -c0 → (a, c1) -c1 → (c, c2) -c2 → (e, f) -\#+end\_src - -Each assignment updates the /cdr/ or /tail/ of the previous node. - -\*\* Appending to a List - -Given a head macro `LIST`, we can append by updating its tail pointer: - -\#+begin\_src c -\#assign (LIST, CAT(LIST, COMMA, NEW\_ELEMENT)) -\#+end\_src - -This mutates the list structure dynamically. - -\*\* Traversal - -Traversal is only possible if a symbolic walk is encoded or if a confederate macro is prepared to test known elements. This is limited and requires foreknowledge of the structure. - -* Sideways Lists (Symbol Table Indexed) - -An alternative to comma-based lists is to use macro names as nodes — each symbol representing a cons cell. - -You define each cons cell: - -\#+begin\_src c -\#assign (\_cons\_a, (A, \_cons\_b)) -\#assign (\_cons\_b, (B, \_cons\_c)) -\#assign (\_cons\_c, (C, NIL)) -\#+end\_src - -Now `_cons_a` is the symbolic head. Each macro name points to a `(car, cdr)` pair. - -This format mirrors the representation of linked lists in Lisp, and mutation is achieved by re-assigning the `cdr` field via `#assign`. - -* Mutability - -What makes this all possible is that `#assign` allows redefinition. It effectively simulates mutable variables: - -\#+begin\_src c -\#assign (X, 5) -\#assign (X, 7) -\#+end\_src - -Later macro expansions of `X` now yield `7`, not `5`. This is unlike `#define`, which would have required an `#undef` first and would have affected macro hygiene. - -* Limitations - -- No native enumeration of keys in the symbol table. -- No stack or heap — only symbolic references. -- No scoped environments unless explicitly constructed via naming schemes. -- Risk of name collisions. - -* Conclusion - -The `#assign` directive reimagines the C preprocessor as a mutable symbolic computation engine. It opens the door to implementing symbolic sets, lists, and even cons structures within macro space, turning what is normally a static templating tool into a dynamic environment for structured symbolic logic. - -Future extensions could include associative maps, recursive evaluators, or stack machines — all using nothing but macro indirection and symbolic mutation. diff --git "a/developer/document\360\237\226\211/source_file_sectioins.org" "b/developer/document\360\237\226\211/source_file_sectioins.org" deleted file mode 100644 index 48d0573..0000000 --- "a/developer/document\360\237\226\211/source_file_sectioins.org" +++ /dev/null @@ -1,107 +0,0 @@ -#+TITLE: RT Library Structure Guide -#+AUTHOR: Sorein (on request by Thomas) -#+DATE: 2025-04-25 - -* Purpose -This document describes the architectural sections in `*.lib.c` files of the RT codebase. -It explains the use of `#if`-guarded blocks including `FACE`, `LOCAL`, `LIBRARY`, and template instantiations. - -* Section Overview - -** FACE :: Public Interface and Template Declaration -#+BEGIN_SRC c -#ifndef Module·FACE -#define Module·FACE -... -#endif -#+END_SRC - -- Declares types, enums, constants, and FG tables. -- Includes other modules (`Core.lib.c`, `cpp_ext.c`). -- Safe to include multiple times. -- No runtime state or implementation logic. - -** LOCAL :: Private Implementations and Table Initialization -#+BEGIN_SRC c -#ifdef LOCAL -#ifndef Module·LOCAL -#define Module·LOCAL -... -#endif -#endif -#+END_SRC - -- Defines functions, local constants, and FG table initializations. -- Only included when `LOCAL` is defined. -- Hidden from consumers. -- Use guards to prevent duplicate inclusion. - -** LIBRARY :: Compiled Static Library Content -#+BEGIN_SRC c -#ifdef LIBRARY -... -#endif -#+END_SRC - -- Reserved for future components to be compiled into a `.a` archive. -- Currently unused in `Core`, `TM`, or `Binding`. -- Separates linkable components from inline-included ones. - -** Template Parameters :: Type-Specific Inclusion Guards -#+BEGIN_SRC c -#ifdef _TM·CVT_ -#if BOOLEAN( NOT_IN(Binding ,TM·) ) -... -#endif -#endif -#+END_SRC - -- Allows per-type instantiation (e.g. `TM·AU`, `TM·Str`). -- Ensures that each instantiation happens only once. -- Guards must be defined by the *caller*, e.g.: - #+BEGIN_SRC c - #define _TM·CVT_ AU - #include "TM.lib.c" - #define SET__Binding__TM·AU - #+END_SRC - -** Undef Section :: Template Parameter Cleanup -#+BEGIN_SRC c -#undef _TM·CVT_ -#+END_SRC - -- Prevents leakage of template macros between inclusions. - -* Summary Table - -#+ATTR_LATEX: :environment tabular :align |l|l|l|l| -| *Section* | *Guard Macro* | *Purpose* | *Include Frequency* | -|-----------------+-------------------------+------------------------------------------------+-----------------------------| -| FACE | #ifndef Module·FACE | Public declarations, typedefs, constants | Once per TU or header | -| LOCAL | #ifdef LOCAL | Function definitions, internal state | Only in .cli.c or test file | -| LIBRARY | #ifdef LIBRARY | Static linkable content (future use) | Optional | -| Template Block | #ifdef _TEMPLATE_... | Per-template instantiation | Once per unique value | -| Undef Section | #undef _TEMPLATE_... | Cleanup template identifiers | Always | - -* Best Practices - -- **Order matters:** Include `FACE` before defining templates or using macros. -- **Avoid leakage:** Always `#undef` template variables after instantiation. -- **Limit `FACE` to declarations:** Do not define runtime behavior in `FACE`. -- **Use `LOCAL` in a single TU:** Only one translation unit should include `LOCAL` per template. -- **Separate compile/link concerns:** Use `LIBRARY` only for code compiled outside `cli`. - -* Example - -To use `TM·AU` and `TM·Str` in the same translation unit: -#+BEGIN_SRC c -#define _TM·CVT_ AU -#include "TM.lib.c" -#define SET__Binding__TM·AU - -#define _TM·CVT_ Str -#include "TM.lib.c" -#define SET__Binding__TM·Str" -#+END_SRC - -* End diff --git "a/developer/document\360\237\226\211/template_in_C.org" "b/developer/document\360\237\226\211/template_in_C.org" deleted file mode 100644 index e723a42..0000000 --- "a/developer/document\360\237\226\211/template_in_C.org" +++ /dev/null @@ -1,83 +0,0 @@ -* Minimal Templating in RT C: The Box Example -:PROPERTIES: -:AUTHOR: Sorein -:DATE: 2025-04-25 -:END: - -This document presents a minimal and idiomatic example of **templating in RT C**, using a generic "box" type. - -We follow the RT convention for template macros: -- Template parameters are named with **leading and trailing underscores**, e.g. `_Box_T_`. -- A **set macro** (e.g. `SET__Box__int`) must be defined after inclusion to prevent duplicate instantiations. - -This example avoids FG tables, tableaux, or polymorphism—it exists purely to show type reuse through macro-based inclusion. - -* Template Logic: box_template.h - -This header is included multiple times, once per type. It expects `_Box_T_` to be defined. - -#+BEGIN_SRC c -#ifndef _Box_T_ -#error "_Box_T_ must be defined before including box_template.h" -#endif - -#if !defined(·(SET__Box,_Box_T_)) -#define ·(SET__Box,_Box_T_) - -typedef struct{ - _Box_T_ value; -} ·(Box_Box,_Box_T_); - -void ·(Box_set,_Box_T_)( ·(Box_Box,_Box_T_)* b ,_Box_T_ x ){ - b->value = x; -} - -_Box_T_ ·(Box_get,_Box_T_)( ·(Box_Box,_Box_T_)* b ){ - return b->value; -} - -#endif -#+END_SRC - -* Instantiating the Template - -You instantiate the template by defining `_Box_T_` before inclusion. Afterward, define the `SET__...` macro to guard against repeat. - -#+BEGIN_SRC c -#define _Box_T_ int -#include "box_template.h" -#define SET__Box__int - -#define _Box_T_ char* -#include "box_template.h" -#define SET__Box__char_ptr -#+END_SRC - -* Example Usage - -Once the template is instantiated, you can use the generated types and functions. - -#+BEGIN_SRC c -#include - -int main(){ - ·(Box_Box,int) a; - ·(Box_set,int)(&a ,42); - printf("a = %d\n", ·(Box_get,int)(&a)); - - ·(Box_Box,char*) b; - ·(Box_set,char*)(&b ,"hello"); - printf("b = %s\n", ·(Box_get,char*)(&b)); - - return 0; -} -#+END_SRC - -* Summary - -This "box" example demonstrates the foundation of RT C templating: -- Code is included once per type with a unique `_Template_Var_`. -- `SET__...` guards prevent duplicate instantiation. -- Type-specific names (`Box_set,int`) are generated using token pasting macros like `·(...)`. - -From here, this pattern scales naturally to complex modules like `TM·AU`, while retaining clarity, reusability, and full type safety. diff --git "a/developer/document\360\237\226\211/todo.org" "b/developer/document\360\237\226\211/todo.org" deleted file mode 100644 index 139597f..0000000 --- "a/developer/document\360\237\226\211/todo.org" +++ /dev/null @@ -1,2 +0,0 @@ - - diff --git a/developer/tool/clean b/developer/tool/clean new file mode 100755 index 0000000..48d4f35 --- /dev/null +++ b/developer/tool/clean @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + +cd "$REPO_HOME"/developer || exit 1 + +# remove synthesized .c files + rm_na cc/* + +# remove object files, deps file, library, and whatever else is on the scratchpad if anything + rm_na scratchpad/* || true + +# remove built executables + rm_na -f machine/* || true + +set +x +echo "$(script_fn) done." diff --git a/developer/tool/env b/developer/tool/env new file mode 100644 index 0000000..dfca640 --- /dev/null +++ b/developer/tool/env @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tool_shared/bespoke🖉/env" + error_bad_env=false + error_not_sourced=false + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + error_bad_env=true + fi + if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "$script_afp:: This script must be sourced, not executed." + error_not_sourced=true + fi + if $error_not_sourced; then exit 1; fi + if $error_bad_env; then return 1; fi + + +export ROLE=developer + +# so we can do the build + +export PATH=\ +"$REPO_HOME"/${ROLE}/tool🖉/\ +:"$PATH" + +# misc + + # make .githolder and .gitignore visible + alias ls="ls -a" + +# some feedback to show all went well + + export PROMPT_DECOR="$PROJECT_$ROLE" + export ENV=$(script_fp) + echo ENV "$ENV" + cd "$REPO_HOME/$ROLE" + diff --git a/developer/tool/make b/developer/tool/make new file mode 100755 index 0000000..246d8df --- /dev/null +++ b/developer/tool/make @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/developer || exit 1 + /bin/make -f tool🖉/makefile $@ + +set +x +echo "$(script_fn) done." diff --git a/developer/tool/makefile b/developer/tool/makefile new file mode 100644 index 0000000..47afa2f --- /dev/null +++ b/developer/tool/makefile @@ -0,0 +1,22 @@ + +RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release + +include $(RT-INCOMMON)/make/environment_RT_0 + +# To compile the example directory uncomment the following assignments: +SRCDIR_List=example +CFLAGS+=-Icc🖉 + + +CFLAGS+= -include "$(RT-INCOMMON)/make/RT_0.h" +LINKFLAGS+= -l$(PROJECT) +LIBFILE=$(LIBDIR)/lib$(PROJECT).a + +include $(RT-INCOMMON)/make/targets_developer +-include $(DEPFILE) + + + + + + diff --git a/developer/tool/release b/developer/tool/release new file mode 100755 index 0000000..8dc8993 --- /dev/null +++ b/developer/tool/release @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# before running this, make library is built and is in the scratchpad directory + +# input guards + + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + + cd "$REPO_HOME"/developer || exit 1 + + if [ ! -d scratchpad ]; then + echo "$(script_fp):: no scratchpad directory" + exit 1 + fi + +#set -e +#set -x + + release_dir=$(release_dir) + mkdir -p ${release_dir} + + install_file scratchpad/libN.a ${release_dir} "ug+r" || true + install_file cc🖉/*.lib.c ${release_dir} "ug+r" || true + install_file cc/*.lib.c ${release_dir} "ug+r" || true + +#set +x +echo "$(script_fn) done." + diff --git a/developer/tool/release_clean b/developer/tool/release_clean new file mode 100755 index 0000000..52309e6 --- /dev/null +++ b/developer/tool/release_clean @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# before running this, make library is built and is in the scratchpad directory + +# input guards + + env_must_be="developer/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/developer || exit 1 + + release_dir=$(release_dir) + + if [ ! -d ${release_dir} ]; then + echo "$(script_fp):: no release directory: " ${release_dir} + exit 1 + fi + + rm_na -rf ${release_dir}/* + +set +x +echo "$(script_fn) done." + diff --git "a/developer/tool\360\237\226\211/clean" "b/developer/tool\360\237\226\211/clean" deleted file mode 100755 index 48d4f35..0000000 --- "a/developer/tool\360\237\226\211/clean" +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="developer/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - -set -e -set -x - - -cd "$REPO_HOME"/developer || exit 1 - -# remove synthesized .c files - rm_na cc/* - -# remove object files, deps file, library, and whatever else is on the scratchpad if anything - rm_na scratchpad/* || true - -# remove built executables - rm_na -f machine/* || true - -set +x -echo "$(script_fn) done." diff --git "a/developer/tool\360\237\226\211/env" "b/developer/tool\360\237\226\211/env" deleted file mode 100644 index dfca640..0000000 --- "a/developer/tool\360\237\226\211/env" +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="tool_shared/bespoke🖉/env" - error_bad_env=false - error_not_sourced=false - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - error_bad_env=true - fi - if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then - echo "$script_afp:: This script must be sourced, not executed." - error_not_sourced=true - fi - if $error_not_sourced; then exit 1; fi - if $error_bad_env; then return 1; fi - - -export ROLE=developer - -# so we can do the build - -export PATH=\ -"$REPO_HOME"/${ROLE}/tool🖉/\ -:"$PATH" - -# misc - - # make .githolder and .gitignore visible - alias ls="ls -a" - -# some feedback to show all went well - - export PROMPT_DECOR="$PROJECT_$ROLE" - export ENV=$(script_fp) - echo ENV "$ENV" - cd "$REPO_HOME/$ROLE" - diff --git "a/developer/tool\360\237\226\211/make" "b/developer/tool\360\237\226\211/make" deleted file mode 100755 index 246d8df..0000000 --- "a/developer/tool\360\237\226\211/make" +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="developer/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - -set -e -set -x - - cd "$REPO_HOME"/developer || exit 1 - /bin/make -f tool🖉/makefile $@ - -set +x -echo "$(script_fn) done." diff --git "a/developer/tool\360\237\226\211/makefile" "b/developer/tool\360\237\226\211/makefile" deleted file mode 100644 index 47afa2f..0000000 --- "a/developer/tool\360\237\226\211/makefile" +++ /dev/null @@ -1,22 +0,0 @@ - -RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release - -include $(RT-INCOMMON)/make/environment_RT_0 - -# To compile the example directory uncomment the following assignments: -SRCDIR_List=example -CFLAGS+=-Icc🖉 - - -CFLAGS+= -include "$(RT-INCOMMON)/make/RT_0.h" -LINKFLAGS+= -l$(PROJECT) -LIBFILE=$(LIBDIR)/lib$(PROJECT).a - -include $(RT-INCOMMON)/make/targets_developer --include $(DEPFILE) - - - - - - diff --git "a/developer/tool\360\237\226\211/release" "b/developer/tool\360\237\226\211/release" deleted file mode 100755 index 8dc8993..0000000 --- "a/developer/tool\360\237\226\211/release" +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# before running this, make library is built and is in the scratchpad directory - -# input guards - - env_must_be="developer/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - - cd "$REPO_HOME"/developer || exit 1 - - if [ ! -d scratchpad ]; then - echo "$(script_fp):: no scratchpad directory" - exit 1 - fi - -#set -e -#set -x - - release_dir=$(release_dir) - mkdir -p ${release_dir} - - install_file scratchpad/libN.a ${release_dir} "ug+r" || true - install_file cc🖉/*.lib.c ${release_dir} "ug+r" || true - install_file cc/*.lib.c ${release_dir} "ug+r" || true - -#set +x -echo "$(script_fn) done." - diff --git "a/developer/tool\360\237\226\211/release_clean" "b/developer/tool\360\237\226\211/release_clean" deleted file mode 100755 index 52309e6..0000000 --- "a/developer/tool\360\237\226\211/release_clean" +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# before running this, make library is built and is in the scratchpad directory - -# input guards - - env_must_be="developer/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - -set -e -set -x - - cd "$REPO_HOME"/developer || exit 1 - - release_dir=$(release_dir) - - if [ ! -d ${release_dir} ]; then - echo "$(script_fp):: no release directory: " ${release_dir} - exit 1 - fi - - rm_na -rf ${release_dir}/* - -set +x -echo "$(script_fn) done." - diff --git a/document/#Model.org# b/document/#Model.org# new file mode 100644 index 0000000..83b69b5 --- /dev/null +++ b/document/#Model.org# @@ -0,0 +1,216 @@ +#+TITLE: Model +#+AUTHOR: Thomas +#+STARTUP: content + +* Tableau + +A Tableau is a type definition for a work area, typically implemented as a typedef struct in C. + +An instance of a Tableau is a tableau. There can be many instances of a given Tableau. + +There are multiple kinds of Tableau: + +- interface (also called a Face) +- state + +* ActionTable + + +An action is a function that operates on a tableau. + +Each action is an instance of an Action. An Action is a typedef for a function pointer. + +An ActionTable is a typedef of a struct, and instance of is said to be an action_table. +A given ActionTable can + +An instance of an ActionTable is an action_table. There can be many isntances of a given ActionTable. + +Each function in an action_table is an action. + + +* Model + +A Model is a TableauFace, a TableauState, and an ActionTable. + +An instance of a Model is a model. + + +* Status bits or continuations? + +The problem I found with continuations is that when the library is +limited to a single status function for a model, there will necessarily +be many continuations from the status function, one for each shade of meaning that it can discern. To endow it with fewer would limit its usefulness for some scenario, perhaps rare, but still supported. + +In addition, not all status's are independent. Thus there must be a priority scheme and then a choice of continuation, but the status function might not know the caller's +priorities. An alternative would be to take both continuations and break into multithreaded execuation. However, many programs are designed to be single threaded. + +When status is used as an argument guard this often comes down to, "Is the passed in +status baring model operable or not?" Thus the tableau for the many-continuations status function will have many duplicate next pointers. + +If rather than returning continuations, a highly discerning status function were to return status bits, The caller could mask the bits and then chose among continuations. In the cause of an argument guard, choosing among two paths. + +It is also a little funny when using a status function as an argument guard that the guard continues into the very function it is guarding. The tableau facilitates this +design pattern in that the input operands need not be written again. Though this +requires managing the tableau for the model who's status is being checked. + +An alternative to using status bits is to have more than one status function. One implementation is to embed the many-continuations status function inside the few-continuations status function, to perform the mask, and then pick the continuation. This might be convenient function to have, but where a second status function really makes sense is where it reduces the amount of computation that need be done. + +* A Single Tableau per Model + +Inputs for actions are written to a tableau. A link currently holds an actions table pointer, and a tableau pointer, hence there is one tableau that holds both action inputs and model state variables. + +If this tableau is declared as part of the FACE then the user can access the model state variables. This would follow a philosophy of, "if they are useful, then so bit it"; however exposing state variables limits both the number of models that can be made that provide the user with the same interface, and limits what can be done with maintenance edits without risking breaking the user's code. Recall that Model is an abstract type, and there can be many implementations for said type, i.e. many models for a given Model. + +C does not allow for public and private sections of a struct, or we could make the state variables private. + +However, we can accomplish the same thing as public and private, perhaps in even a better way, by including the interface tableau in the full tableau, and have the code know it was given the full tableau: + +#+BEGIN_SRC c +typedef struct{ + ... +}X·TableaFace; + +// in the implementation + +typedef struct{ + X·TableaFace face; + ... +}X·Tablea; + +#+END_SRC + +The details of the TableauFace type are shown to the user. The actions are +declared to be given a TableauFace, so any directly calls will work. Inside each action the tableau is converted from TableauFace to Tableau. + +=> Core uses separate Face and State tableaux + +** Tableau structure + +The TableauFace has: +- all possible inputs +- results +- continuations + +Then the Tableau extension + +- state variables + + +* Continuation Link + +There are two dimensions of variation. 1) Multiple action_tables from a given ActionTable, and 2) multiple tableau from a given Tableau. + +Each action_table instance of a given ActionTable can have very different function implementations, as only the function type signatures are specified in the ActionTable definition. + +The interface tableau, TableauFace, is designed against the ActionTable. Both deal with the user's view of the Model. In contrast each state tableau, TableauState is designed against a specific action_table. + +Hence, for each ActionTable declaration there will be corresponding to a TableauFace declaration, unless by coincidence, an existing one can be recycled, though even then programmers would appreciate having matching names. This begs the question if the two structures can be combined into one. So doing would constrain our ability to make instances from them independently. + +A given action table can be used with multiple state tableaux. In other words, there can be multiple instances of the same type. + +Conversely a given tableau can be used with multiple action tables. This happens in +polymorphism, where a child tableau can be passed to a parent action. The child +parts are in an extended portion of the tableau, and thus not seen by the parent +action. + +In the one Tableau per model approach, each tableau instance is both state and inputs, hence each instance will have its own inputs. We would lose the ability to make independent state and interface instances. The interface tableau is playing the role +that is typically played by the stack frame. Hence there is a copy per call, now this the one tableau per model, there would be a copy per instance. If left independent, there would be as many or few copies as the user determines is necessary, with the network of interface tableaux being connected by pointers tending to look like a circuit. + +**proposal 1 + +Place an action_table pointer in each single tableau per model tableau, then there would be many copies of the action_table pointer, one per tableau. This is the virtual table pointer approach from C++ or the delegate pointer from JavaScript. + +With this approach the action table can be reached through the tableau, so only the tableau, or references to it, need to be passed around as an instance of the model. This is appealing. + +However, such a link to such a tableau is not sufficient for knowing which action on the action table should be called. Hence a link to such an overloaded tableau can not function as a continuation link. + +Suppose if instead of an action_table link, a function link were embedded in the tableau, perhaps as a first member. Then the first member could be called and given the tableau as its only argument. This could function as a link, but then the state of the model is owned by a single function call. This looks problematic. + +**proposal 2 + +A link is a two pointer bundle. The first pointer to an action table, the second to single tableau. Then there is a macro called `call` that is used for calling functions in the action table. ``call(extent ,&tape_tableau)` + +The problem here is that such a link can not appear as a continuation because the link itself does not say which action is being invoked. That information is in the call. + +Attempts to save this proposal by including a 'field pointer' in the link, that would be applied to the action table are rather awkward in C, though it can be done by creating an enumeration of the struct offsets, and using those tags. + +**proposal 3 + +A three pointer bundle, the first pointer to the function being called, the second pointer to an interface tableau, the third pointer to the state tableau shared by the functions in the action_table the function comes from. + +In this approach there is not action_table pointer, though that is not a problem because if that information is needed it can be curried into the called function when it is written, though chances are if a given action needs to call another action function in the table, it will do so through a function pointer. The purposes of the action_table struct is then to document which actions share the corresponding tableau state, and to provide a namespace to put the actions in, which makes it conceptually nicer for the programmer. It would be even nicer if C supported Pascal's 'with' statement. + +Such a link could be reduced to two pointers if the single tableau variation is used. + +==> Core uses proposal 3 + + +* Mixing continuations with fall through execution. + +#+BEGIN_SRC c + Local void call(Core·Link *lnk){ + while(lnk) lnk = lnk->act(lnk); + } +#+END_SRC + +This implementation of call falls through when a null `lnk` pointer is returned. However the caller can not know anything about the status of the call. + +**proposal 1 + +Each continuation function that can return a NULL link, where the caller wants to know the status, also sets a `status` value at the top of the base tableau, that all FACE tableau's extend from. + +Disadvantage, all code must set status, so why have continuations? The optimizer will drop unused status setting code, so perhaps this is not serious. Though, on the other hand, for Local functions would the optimizer skip the status return and condition testing, and put the continuation in - thus making status setting the way to go as it must be coded anyway? + + +**proposal 2 + +Have actions that set status, link to them when status is desired. + +Actually we need default continuations anyway. In many cases these could +be generic. Argument guard continuations could be 'good' or 'bad'. + +=> Core uses option 2 + +* Continuations and linking + +**proposal 1 + +Put continuations on the interface tableau. The reasoning is that the programmer will want to set them, but actually this is not a general programming task. Rather it occurs up front as part of a 'wiring' phase, and is then typically it is not done again. + +Consider this example. + +#+BEGIN_SRC c + typedef struct{ + Core·Tape·Tableau·Face tape_tableau; + Core·Area *area; + void *position_left; + void *position_right; + AU *pt0; + AU *pt1 + Core·Area *a; + Core·Area *b; + bool q; // predicate -> q + Core·Link next; + }Core·Area·Tableau·Face; +#+END_SRC + +The idea is that there is one interface tableau used for all of the Area·Tableau actions, but it has a link field. Normally while the linked together functions are running, they can not set the 'next' link, as that information comes from a higher level. For example, after `encloses_pt_q` runs, it has no idea as to where the programmer wants control to flow next. + +**proposal 2 + +Add a fourth pointer to a link. This points to the continuations block. + +#+BEGIN_SRC c + typedef struct{ + Core·Tableau *face; + Core·Tableau *state; + Core·ActionTable *action; + Core·NextTable *next_table; + }Core·Link; +#+END_SRC + +We may then describe the program flow network as a series of next_tables, and then view the program as traversing a graph. + +In database representation a set of nodes, and the dual graph is specified as a bridge table. It is more efficient when traversing a graph, to keep make the neighbor list a property of the node. Thus, "Link" can be seen as a node with a neighbor list. + +=> Core uses option 2 diff --git a/document/#temp.txt# b/document/#temp.txt# new file mode 100644 index 0000000..3648a70 --- /dev/null +++ b/document/#temp.txt# @@ -0,0 +1,93 @@ +#+TITLE: TM Bulk Methods Using Area and Extent +#+AUTHOR: Sorein +#+DATE: 2025-04-25 + +* 1. Motivation: Copying Over Areas, Not Just Cells + +In TTCA, a **cell** is the basic unit of memory or tape, and a **Tape Machine (TM)** traverses such cells with a movable head. + +For high-throughput operations like `Copy`, operating on one cell at a time is inefficient. Instead, we want to operate over an **area**: a concrete, contiguous **sequence of cells**, defined by: + +- A **starting address** (typically the current head position) +- An **extent** — the **inclusive upper bound** of the area + +This gives the TM enough structure to reason about **bulk memory access** safely and efficiently. + +TTCA terminology distinguishes: +- **Area**: A sequence of cells between a starting point and an extent. +- **Extent**: The highest address within that area. +- **Distance**: The difference between the head and the extent (extent − head), used internally but not exposed as API input. + +We avoid using “length” as it is ambiguous and may overflow (`distance + 1`). + +* 2. Proposed TM Methods for Bulk Area Access + +Each TM instantiated over a Cell Value Type (CVT) can optionally support the following methods: + +#+BEGIN_SRC c +bool TM·AU·can_area(TM·AU tm ,uintptr_t extent); +AU const* TM·AU·peek_area(TM·AU tm ,uintptr_t extent); +AU* TM·AU·claim_area(TM·AU tm ,uintptr_t extent); +void TM·AU·commit_area(TM·AU tm ,uintptr_t extent); +uintptr_t TM·AU·extent_right(TM·AU tm); +#+END_SRC + +* 3. Method Semantics + +| Method | Meaning | +|-------------------------+-------------------------------------------------------------------------| +| `can_area(extent)` | True if the tape has a contiguous area from head up to this extent | +| `peek_area(extent)` | Returns a const pointer to the area [head … extent], or NULL | +| `claim_area(extent)` | Returns a writable pointer to the area [head … extent], or NULL | +| `commit_area(extent)` | Advances the head from current position to `extent` (inclusive) | +| `extent_right()` | Returns the extent (inclusive upper bound) of the tape | + +All returned areas are assumed to be **concrete**—that is, the TM guarantees: +- All cells in the area are physically allocated +- Their memory layout is contiguous +- They can be safely accessed as an array of CVT values + +If these conditions are not met (e.g. for cyclic or segmented tapes), the TM returns `false` or `NULL`. + +* 4. Area-Based Copy Example + +Using these methods, an efficient `Copy` routine becomes: + +#+BEGIN_SRC c +while( TM·AU·can_area(src ,e) && TM·AU·can_area(dst ,e) ){ + AU const* from = TM·AU·peek_area(src ,e); + AU* to = TM·AU·claim_area(dst ,e); + uintptr_t count = e - src_index + 1; + memcpy(to ,from ,count * sizeof(AU)); + TM·AU·commit_area(src ,e); + TM·AU·commit_area(dst ,e); +} +#+END_SRC + +Note: +- `e` is the intended extent (inclusive). +- `count = extent − head + 1` is used internally, but not exposed as "length". + +* 5. Capability Declaration + +Not all TMs support contiguous areas. To indicate whether a TM supports these methods, we may define: + +#+BEGIN_SRC c +typedef enum{ + TM·Caps·none = 0, + TM·Caps·area = 1 << 0 +} TM·Caps; +#+END_SRC + +This allows dispatchers to check if area-based methods are available for a given tape. + +* 6. Summary + +- We operate on **areas**, defined as `[head … extent]`, where `extent` is inclusive. +- We avoid using "length" in API design, since it implies `distance + 1`, which may overflow. +- **Area methods** allow batch reading or writing with fewer dispatches and better memory performance. +- These methods align TM with TTCA's formal model, supporting structured, efficient, and correct stream operations. + +This sets the foundation for writing `Copy`, `Map`, and other stream-based transformations using TMs as high-level iterators over cell areas. + +Would you like a matching `.org` draft for the FACE section of `Copy.lib.c`, now assuming the availability of these `area` methods? diff --git a/document/.githolder b/document/.githolder new file mode 100644 index 0000000..e69de29 diff --git a/document/Abstracting_Type_in_C.org b/document/Abstracting_Type_in_C.org new file mode 100644 index 0000000..17b5ec9 --- /dev/null +++ b/document/Abstracting_Type_in_C.org @@ -0,0 +1,564 @@ +#+TITLE: Abstracting Type in C +#+AUTHOR: Thomas + +* Introduction + +Type abstraction is a fundamental challenge in C programming. Unlike object-oriented languages that provide built-in mechanisms for polymorphism, C requires explicit design patterns to achieve similar flexibility. This document explores various approaches to implementing type abstraction in C, using a tape machine (TM) as a concrete example. + +The core problem we're addressing is how to write generic code that can operate on different implementations of the same abstract interface. Specifically, we want to create functions that can work with any tape machine implementation without knowing the implementation details. This separation of interface from implementation facilitates creating modular, maintainable code in C. + +* Namespaces in C + +C does not have built-in namespace support like C++ or other modern languages. However, we can simulate namespaces using naming conventions. We use the middle dot character (·) as a namespace separator to organize identifiers into logical groups. + +** The middle dot convention + +The middle dot (·) in identifiers like `TM·Array` or `TM·Function·fg` is not a special operator in C. It is literally part of the identifier name. This convention creates a visual hierarchy that mimics namespaces while remaining valid C code. + +Example: +#+BEGIN_SRC c +TM·x // variable x +TM·Array·i // variable i +#+END_SRC +In the first example `x` is a variable in the TM namespace. TM stands for Tape Machine. In the second example, `Array` is a namespace inside of the `TM` namespace, and `i` is a variable in the `Array` namespace. + +In general, in our shop, types and namespaces are written in PascalCase. Variable and function names are written in snake_case. When proper nouns, types, or namespacess, are represented in variable or function names, they maintain their capitalization, though appear with underscores. + +#+BEGIN_SRC c +char *person_Thomas = "Thomas"; +#+END_SRC + +** Comparison with C++ Namespaces + +Unlike C++ namespaces, our convention: +1. Does not provide actual scope isolation +2. Cannot be opened with `using` directives +3. Is purely a naming convention, not a language feature + +Despite these limitations, this convention provides many of the organizational benefits of true namespaces while remaining compatible with standard C. + +* Implementing Templates in C + +C lacks built-in support for templates or generics, unlike C++ or modern languages like Java or Rust. However, we can implement template-like functionality using the C preprocessor. This section explains the template system used throughout this document. + +** The center dot '·' Macro System + +The cpp macro `·` is used for putting identifiers into a namespace. Consider these variables within a namespace. + +#+BEGIN_SRC c +TM·x // variable x in namespace TM +TM·Array·i // variable i in namespace TM·Array +#+END_SRC + + +,#+BEGIN_SRC c +·(TM ,x) // variable x in namespace TM +·(TM·Array ,i) // variable i in namespace TM·Array +#+END_SRC + +The reason the macro is needed is that cpp will not replace a macro that is embedded in an identifier. With this macro we can do the following: + +#+BEGIN_SRC c + #define CVT uint32_t + CVT i; // -> uint32_t i + typedef struct ·(TM ,CVT) // -> typedef struct TM·uint32_t + #undef CVT + #define CVT string + typedef string char *; + CVT ch; // -> string ch; + typedef struct ·(TM ,CVT) // -> typedef struct TM·string +#+END_SRC + +This allows us to create type and function names that are specialized for specific types, while maintaining a consistent naming convention. + +*** Implementation Details + +The · macro was initially defined for two operands, as shown below, though now it will take between zero and ten operands. With zero operands it expands to nothing, with one it echos the operand with no center dots, with more than that the operands are appended with a prior center dot. + +#+BEGIN_SRC c +#define _·2(a, b) a##·##b +#define ·2(a, b) _·2(a, b) +#+END_SRC + +** CVT: Cell Value Type + +Throughout our tape machine implementation, we use CVT (Cell Value Type) as a template parameter. This represents the type of data stored in each cell of the tape. + +The implementation uses conditional compilation to handle different CVT values: + +#+BEGIN_SRC c +#ifndef CVT + // Code for generic, non-specialized case +#endif + +#ifdef CVT + // Code specialized for a specific CVT +#endif +#+END_SRC + +When using the library, you include it multiple times with different CVT definitions: + +#+BEGIN_SRC c +// First include with CVT undefined for base definitions +#include "TM.lib.c" + +// Then include with CVT defined for each type specialization +#define CVT int +#include "TM.lib.c" +#undef CVT + +#define CVT float +#include "TM.lib.c" +#undef CVT +#+END_SRC + +* Tableau and FG Tables + +Two key concepts in our type abstraction approach are the "Tableau" and "Function Given (FG) Table." + +** Tableau + +A "Tableau" is our term for a data structure that holds the state of a particular instance. In the context of our tape machine example: + +1. **Definition**: A tableau is a struct that contains all the state variables needed for a specific implementation of an abstract interface. + +2. **Purpose**: The tableau serves as a shared workspace where functions can read and write state information. Think of it as a blackboard where functions can leave "notes" for each other. + +3. **Implementation-specific**: Each implementation of an abstract interface will have its own tableau structure with different fields appropriate to that implementation. + +For example, the tableau for an array-based tape machine might look like: + +#+BEGIN_SRC c +struct { + CVT *hd; // Current head position + CVT *position; // Base position for the tape (leftmost cell) + ·(extent_t, CVT) extent; // Largest index that can be used for accessing the tape +} ·(TM·Array, CVT); +#+END_SRC + +Notice this struct is templated on `CVT`. Suppose it were in the file `tape.lib.c`, then: + +#+BEGIN_SRC c +#define CVT uint8_t +#include `tape.lib.c` +typedef stirng char *; +#udef CVT +#define CVT string +#include `tape.lib.c` +#+END_SRC + +This will create two versions of said `struct` tableau with two different CVT types. + +** Function Given (FG) Tables + +The "Function Given" (FG) table is a collection of function pointers that implement operations on a specific tableau type. + +1. **Definition**: An FG table is a struct containing function pointers that all take a tableau as an argument (hence "Function Given"). + +2. **Purpose**: FG tables allow for polymorphic behavior in C by providing different implementations of the same interface. + +3. **Structure**: Each function in the FG table takes a pointer to a tableau as an argument, allowing it to access and modify the state. + +A simplified example of an FG table for our tape machine might look like: + +#+BEGIN_SRC c +typedef struct { + TM·Tape·Topo (*Tape·topo)(TM *tm); + bool (*Tape·bounded)(TM *tm); + TM·Head·Status (*Head·status)(TM *tm); + Core·Status (*mount)(TM *tm); + void (*step)(TM *tm); + void (*rewind)(TM *tm); + // ... other functions +} TM·FG; +#+END_SRC + +When specialized for a specific cell value type (CVT), we might then have: + +#+BEGIN_SRC c +typedef struct { + TM·FG *fg; // Base function table + ·(extent_t, CVT) (*extent)(TM *tm); + CVT (*read)(TM *tm); + void (*write)(TM *tm, CVT *remote_pt); +} ·(TM, CVT)·FG; +#+END_SRC + +** The Relationship Between Tableaux and FG Tables + +The tableau and FG table work together to implement polymorphism: + +1. Each implementation provides its own tableau type and instance of an FG table. +2. The first field of a tableau is typically a pointer to its corresponding FG table. (When following the 'vtable' method.) +3. Functions in the FG table operate on the tableau, reading and writing its state. +4. Client code can work with any implementation by using the functions in the FG table without knowing the details of the tableau structure. + +This pattern allows us to achieve polymorphic behavior in C while maintaining type safety and avoiding the overhead of dynamic dispatch mechanisms like those used in object-oriented languages. + +** Template-Based Type Generation + +The template system generates several types of identifiers: + +1. **Type names**: `·(TM, CVT)` becomes `TM·int` when CVT is defined as `int` +2. **Function names**: `·(TM·Array, CVT)·init_pe` can become `TM·Array·int·init_pe` +3. **Variable names**: `·(extent_t, CVT)` can become `extent_t·int` + +** Function Given (FG) Tables + +A key part of our implementation is the Function Given (FG) table pattern. Each implementation of the tape machine provides an FG table containing function pointers for its operations. + +The FG tables are specialized based on the CVT: + +#+BEGIN_SRC c +typedef struct { + TM·FG *fg; // Base function table + ·(extent_t, CVT) (*extent)(TM *tm); + CVT (*read)(TM *tm); + void (*write)(TM *tm, CVT *remote_pt); +} ·(TM, CVT)·FG; +#+END_SRC + +This allows for type-safe operations while maintaining a consistent interface. + +** Benefits of This Approach + +1. **Type safety**: The compiler checks that the correct types are used with each specialized function +2. **Code reuse**: Common functionality is defined once and specialized for different types +3. **Consistent naming**: The · macro ensures a consistent naming convention +4. **Modularity**: Different implementations can share the same interface + +** Limitations + +1. **Verbosity**: More verbose than native templates in C++ +2. **Complexity**: Requires understanding of preprocessor macros and conditional compilation +3. **Debugging**: Preprocessor-generated code can be harder to debug +4. **Limited IDE support**: Most IDEs don't understand this template system for code completion + +Despite these limitations, this approach provides a powerful way to implement generic, type-safe code in C without resorting to void pointers or code duplication. + +* Proposed approaches for generalizing type in C + +These are some of the approaches what were considered, or in some cases tried. + +** Using an TM FG table instance as an instance of 'TM type' + +1. Suppose we have a generic TM FG table with the declared functions constituting the architecture (user's view, interface) of a tape machine. + +2. Instances of this TM FG table represent different implementations of the architecture. For example, TM·Array·fg for a TM implemented as an array, and TM·Function·fg for a function implementation (similar to the Natural_Number in the Java implementation). + +3. Suppose we use an instance of a FG table to be the type for a tape machine. + +4. Now suppose we have a function called `map` that is given two Tape Machine arguments, say TM_read, and TM_write, as well as a function to map. + + The `map` only refers to the interfaces for the tape machines, and is agnostic as to how they are implemented. Hence, it works out fine that it is given two instances of the FG type. It uses the dot access on these the two given fg tables to find by name the tape machine functions it wants to call. While doing so it calls whichever function that happens to be implemented on the given fg table. The declared type signature match, so it has no problem to call them. + + This achieves what we wanted: a map function that can use a tape machine and does not care what the implementation of that tape machine is. + + However, the TM functions that map calls require having the shared tableau as one of their arguments. Without this, the called function cannot know which machine is being operated on. + Furthermore, the tableau type must match the TM fg table type. + + So giving a function, such as `map`, an FG table instance alone is not sufficient. It must + also have the tableau that does with the FG instance. But where to put it? There can be many tableau for a given FG table, each representing an instance of a tape machine, so we can not attach the tableau to the FG table. + + In conclusion this method does not work. + + +** The TM tableau instance as an instance of 'TM type' + +1. As noted in the prior section, our example `map` function is given three arguments, namely, TM_read, a TM_write, and a function. For these first two + arguments it was found not to be sufficient to pass the instance fg tables. Suppose that instead we make TM_read and TM_write the relative tableau. + +2. Now we have the opposite problem from before. We have the tableau for the function tables, but we do not have the function tables that are to be used with them. If we make the function tables global, then `map` will have to decide somehow which one to call, and make this decision at run time, as it can process instances of many types. In C this can not + be done from the type signature of the instance, because it is not available at run time. + +3. One solution is to keep the specific type on the tableau, and then have multiple `match functions` one per implementation (and per CVT template value), and then call the map function that goes with the tableau. The programmer picks the matching one, and the compiler verifies the types match at compile time. + +4. This approach works, but we duplicate the map code many times just to get the function type signatures to match the tableau type with the fg table used. + +** Using both the TM tableau instance, and the corresponding TM FG table instance + +1. Say we have one generic `map` that takes 5 arguments: TM_read (an tape machine tableau), TM_read_fg, a TM_write (a tape machine tableau), and TM_write_fg, and of course, all the a pointer to the function that map is to apply. + +2. The instance parameters must be declared `void *` to prevent argument checking on them; otherwise, it will be necessary to implement many map functions for each instance type combination. + +3. This works, though we have no way to know if the type of the given tableau goes with the type of the fg table, for each of the read tape machine and write tape machine. + +4. We could create many wrapper functions to accomplish the argument type checks, then call a central map function with `void *` instance data pointers, and with any luck, the optimizer would make this extra layer go away, so it would not be a run time performance drag. Still, by this method map has 5 arguments instead of the three that are natural for the problem. + +5. So this approach, with the delegation wrappers, does everything we want, but it feels unsatisfactory due to having to provide arguments in pairs. + +** Tableau instances carries pointer to the matching FG table instance + +1. Each fg table is full of functions that are given a tableau of a specific type. Hence, it is practical to add a field to the tableau such that when an instance is made of the tableau, that this field is initialized with a pointer to its matching fg table. + +2. In practice then, the function that allocates a tape machine will actually be allocating a tableau of the correct type. This tableau would then be allocated on a stack frame or in a heap block. Following the allocation a type specific init function is called, and this function sets the fg pointer table, along with other variable initialization. + +3. Then a call to a function on the fg table looks like this: + + #+BEGIN_SRC c + + typedef struct{ + TM·FG fg; + } TM; + + typedef struct{ + TM tm; + uint8_t *hd; + uint8_t *position; + extent_t extent; + } TM·Array; + + ... + + TM *init(TM·Array *tm ,position ,extent); + + ... + + TM *tm_read; + TM·Array *tma; + + tm_read = *init(tma ,position ,extent); + + ... + + void map(TM *tm_read ...){ + ... + tm_read->fg->step(tm_read); + } + #+END_SRC + + Here `tma` has been allocated. `tm` is has not been allocated, but rather is a generic stand in for any tape machine tableau. + + `map` is given `TM *` type, so said tape machine could be of any implementation. All that matters is that the `TM` interface has been implemented. + +4. It works, and it is a tried and true method. It is a little funny that the programmer uses `tm_read` twice in the call, but at least the tm_read argument will be type checked. + +** Using a pointer pair as the `TM type'. + +1. Instead of the instance data being called the 'TM type', a pair is the 'TM type'. + The first member of the pair points to a tableau instance, the second to a matching FG + table instance. + +2. With this approach, generic TM functions each accept a pair as a TM argument. + +3. This approach encapsulates the same information as the vtable approach but keeps the relationship explicit. Note, if there is a one-to-one correspondence between tableaux and pairs, then the memory footprint is larger by one pointer per instance. + +4. An example + + #+BEGIN_SRC c + // Define the pair structure + typedef struct { + TM·Tableau *t; // Points to the implementation-specific tableau + TM·FG *fg; // Points to the corresponding FG table + } TM; + + // Implementation-specific tableau + typedef struct { + uint8_t *hd; + uint8_t *position; + extent_t extent; + } TM·Tableau·Array; + + // Function to initialize a pair + TM init_pair(TM·Tableau·Array *tma, uint8_t *position, extent_t extent) { + TM pair; + // Initialize the tableau + tma->hd = position; + tma->position = position; + tma->extent = extent; + + // Set up the pair + pair.t = (TM·Tableau *)tma; + pair.fg = &TM·Array·fg; + + return pair; + } + + // Using the pair in a function + void map(TM tm_read, ...) { + ... + + // Call functions through the pair + tm_read.fg->rewind(tm_read.t); + ... + + } + #+END_SRC + +5. Note that when using a pointer pair, the `init` function will be given the same arguments as for the vtable approach, but it will return the pair instead of a more generic pointer to the tableau. + +6. With this approach a pair of pointers is passed around instead of a single pointer. Though it might be more optimizer friendly, as it is easier to drop structures, such as the pair, than it is to rearrange structures as would have to be done to unpack the vtable pointer from the tableau structure. + +** Using a dispatch function as the `TM type'. + +1. In this case, a pointer to a function is the 'TM type'. There is an enum that gives numeric tags to each of the functions in the FG struct instance. + +2. The tag for the desired fg function to be called is passed as the first argument to the dispatch function, and the remaining arguments are for the fg function. + +3. The dispatch function has the instance data and fg table pointer curried into it, so it then calls the correct fg function while providing it with the correct instance data. + +4. In C, it is not immediately obvious how to create a function on the fly each time an + instance is created to curry the instance data into it, and then later how to call + the newly created function. + +** Dispatch function and Self-identified Tableau type. + +1. With this method, an extra field is added to each tableau instance to identify its type. Then a globally available TM-specific dispatch function is called to run the desired fg function on the data. It is similar to the dispatch function from above, but the instance data is an additional argument. + +2. The dispatch function uses the type information to know which fg table to call. This type information could be a pointer to the appropriate fg table. + +3. This approach differs from the vtable method in that all the arguments are given to the one TM dispatch function, and it figures out how to do the dispatch. There is not a wrapper-per-function. + +** Which approach? + +We want to be able to declare an instance as a local variable, where it will end up being on the stack frame. We want to avoid heap allocation for performance reasons, but not exclude the use of heap memory. + +Dynamically created functions are out of the question. Dispatch approaches require the enum table to have tags. This is not a show-stopper. However, having one dispatch function means the argument types are not checked. That is a problem. + +Doubled-up arguments (one for the instance, the other for the table) either require wrappers or do not check that an instance really goes with the data. Besides, this approach requires a lot of typing. + +The pointer pair approach becomes a maintenance problem, unless it is passed by value. When passed by value. When passed by value it is two pointers being copied instead of one. There is no corresponding savings on fewer levels of indirection on lookup. It does achieve separation of concerns, and would facilitate using the same instance with multiple fg tables, i.e. multiple 'views', that that is not a feature that is driving the decision process. + +So their are two practical approaches, the vtable, and the pointer pair. + +* Terminology + +** Model + +A 'model' consists of a Tableau definition, FG table definitions, and all of the type definitions that occur on the function signatures of those functions, all instances of the FG table, all while including the variations due to the template variables. This includes the function implementations, but does not include the values assigned to the tableaux. + +Going by this definition, it can be said that in the file TM.lib.c provides a Tape Machine model. + +** Architecture + +Architecture is the users view of the model. In the case of a software library, the user will be an application programmer. + +An architecture can also be a specification for which the model is an implementation. In which case, it says "The user must see this when using the model that is to be written." + +** FG table instances + +An FG table with template variabes, will expand out to one or more FG tables (without template variables), when those variables are bound to values. + +There can be multiple instances of an FG table. Each instance will consists of pointers to functions that have the type signature specified in the FG table. However, though all instances of the FG table share the same interface, their implementations can be completely different. + +Each template variable binding, and each FG table instance can have a different Tableau type as the given argument. For the Tape Machine, we give each tableau struct the name ·(TM·, CVT), where is the FG instance table type. For example, ·(TM·Array, CVT) is a struct of state variables for an Array implementation of the TM. + +------------------------------------------------------------------- + +* Hierarchy + +The TM model has functions that are independent of the CVT parameter. + + +** One for all FG table + +The "TM.lib.c" file defines an FG type called ·(TM, CVT)·FG. Note that CVT is a template +parameter. Hence, giving different CVT bindings, there will be different FG tables. + +For each ·(TM, CVT)·FG, there can be a number of ·(TM·, CVT)·fg instances. For +example, ·(TM·Array, CVT)·fg. Each of these is a parameterized table. + +A user has an fg table to call functions from. This is either passed in or, more +likely, found at global scope after including "TM.lib.c", and then including it again for +each value of the CVT variable to be used. + +For each implementation type, there is a struct defined called ·(TM·, CVT), +note the lack of further suffix. Instances of this type are said to be instances of the tape +machine. `FG` stands for `function given`, and what each said function is given is one or more arguments of the ·(TM·, CVT) type. + +When a user wants a tape machine, the user makes an instance of a ·(TM·, CVT). +This is then handed to a function called ·(TM·, CVT)·init(). The init function is given whatever parameters are needed for initializing the instance, and it returns a more generalized pointer of type `·(TM, CVT) *`. + +After initialization, the ·(TM·, CVT) instance will have a first field value that points to the ·(TM·, CVT)·fg table. However, the pointer to this instance will be of the type returned by init, which is `·(TM, CVT) *` (notice it lost the implementation). This more generic pointer can now be used with the generic instance of the +·(TM, CVT)·FG table, ·(TM, CVT)·fg, which holds wrapper functions that make use of the +first field value to find the real fg table and to call those functions. + +Hence, after the user calls the correct init for the specific instance made, the resulting pointer points to the same type object independent of the implementation of the functions. Thus, code written to manipulate TMs can be written in a manner that is agnostic to the implementation of those TMs. + +When a function is called, say ·(TM, CVT)·fg.step(tm), it is passed the generic type `·(TM, CVT) *`, tm. This will call the step wrapper function, which will in turn pass the same arguments (in this case, only `tm`) to the step function found in the fg table pointed to by the first member of the tm struct. + +** Separate FG tables + +In the flat fg table approach described in the prior section, each wrapper function table of the form ·(TM, CVT)·fg, obtained by setting the CVT template to a type value, will have a full set of wrapper function pointers. When a wrapper function is the same independent of the CVT variable, it still has a pointer copied into each fg table. Thus, there will be a lot of redundancy in the tables if many functions are not CVT-specific. + +For the layered fg table, there are separate wrapper function tables for the wrappers that are independent of CVT and those that are CVT-differentiated. The user then calls functions from the CVT-independent table when invoking those functions and from the CVT-differentiated functions table when calling those. So, for example, the user would call TM·fg.step(tm) to do a step, as that is CVT-independent, but call ·(TM, CVT)·fg.read(tm) to do a read, as the read value is CVT-differentiated. + +** Direct access through instance field (Orrin suggestion) + +Instead of calling fg functions through a globally visible table such as: + +#+BEGIN_SRC c +fg->step(tm); // Wrapper style +#+END_SRC + +where fg is of type ·(TM, CVT)·FG and calls to it require globally accessible wrapper functions, + +we can use the instance's first field directly: + +#+BEGIN_SRC c +tm->fg->step(tm); +#+END_SRC + +Here, tm is a ·(TM, CVT) * — the generic type returned by init — and fg is the first field of the instance pointing to the correct FG table. + +This style removes the need for wrapper functions entirely. Each TM implementation embeds its corresponding FG table pointer directly in the instance. Thus, no global wrapper needs to be referenced, and function type-checking is preserved at compile time. + +If there are CVT-independent functions, we can use a layered FG table. Each CVT-specific FG table includes a pointer to a base table: + +#+BEGIN_SRC c +tm->fg->base->step(tm); // Access shared, CVT-independent function +tm->fg->read(tm); // Access CVT-specific function +#+END_SRC + +This structure mimics prototype delegation in JavaScript, except we resolve the chain explicitly with types, not dynamic name resolution. + +The benefit of this approach is that the user only needs to have the instance in scope — no global FG table declarations. All function dispatch is local and type-safe. + +The only remaining user burden is knowing whether a function is CVT-specific or not. This is made obvious by whether the function appears in the base or CVT-differentiated FG struct, and the compiler will catch mismatches. + +(Contribution by Orrin — co-author) + +* Observations + +C does not have automatic conversion of a child type to its parent; instead, it will give a type mismatch error. + +The vtable pattern with separate tables will have a CVT-differentiated fg table pointer on the tableau. Without the function wrappers, a call can occur like this: + +#+BEGIN_SRC c +tm->fg->step(tm) +#+END_SRC + +Or even with the wrappers and a globally available fg table: + +#+BEGIN_SRC c +fg->step(tm) +#+END_SRC + +In both of these, `step` will be the CVT-differentiated version of step, so types will match, and these calls work. + +However, things change when we want to call the non-CVT-differentiated shared table: + +#+BEGIN_SRC c +tm->TM·fg->mount(tm) +#+END_SRC + +Due to `mount` being in the shared fg table that has type `TM·fg` where it expects to be given arguments of type `TM *`, and having type `TM·`, there will be a type mismatch +error on the call. The programmer will be compelled to fix this with a cast: + +#+BEGIN_SRC c +tm->TM·fg->mount((TM *)tm) +#+END_SRC + +Requiring the programmer to defeat the type system by habit is not a good approach. + +So the one solution that does work is the one big table per type. All functions will then have correct signatures in the FG declaration. In the implementation, the more generic functions can be cast when assigned directly to the fg table function pointers, or wrappers that delegate can be written and assigned to the fg table function pointers. + +* Conclusion + +After examining various approaches to type abstraction in C, the vtable pattern emerges as the most practical solution for our tape machine implementation. While it has some overhead in terms of memory usage, it provides the best balance of type safety, ease of use, and performance. + +The direct access through instance field approach suggested by Orrin offers an elegant alternative that eliminates the need for wrapper functions while maintaining type safety. This approach is particularly appealing for its simplicity and the fact that it keeps all the necessary information localized to the instance. + +For projects where performance is critical, the "one big table per type" approach may be the most efficient, as it avoids the need for type casting while still providing a clean interface. + +Ultimately, the choice of approach depends on the specific requirements of the project, but the vtable pattern and its variations provide a solid foundation for type abstraction in C programming. diff --git a/document/Inclusive_Exclusive_interval_bounds.org b/document/Inclusive_Exclusive_interval_bounds.org new file mode 100644 index 0000000..f5dfb84 --- /dev/null +++ b/document/Inclusive_Exclusive_interval_bounds.org @@ -0,0 +1,94 @@ +#+TITLE: Exclusive vs. Inclusive Bounds +#+AUTHOR: Thomas & Eidolon +#+DATE: 2025-02-28 +#+OPTIONS: toc:nil + +* Introduction +The discussion explores the advantages and drawbacks of exclusive and inclusive bounds in programming, with a particular focus on C-style memory intervals. Exclusive upper bounds have been a longstanding convention in C and derived languages but have also led to significant issues, including microprocessor bugs. The alternative, inclusive bounds, offers certain advantages, particularly in preventing out-of-bounds memory access. + +* Exclusive Bounds in C +Exclusive bounds mean that the upper bound points to one element past the actual interval. This approach aligns with C's idioms and iteration patterns: + +- A pointer iterated through memory will naturally stop when it equals the upper bound. +- The memory length itself matches the upper bound minus the lower bound. + +However, this has caused notable problems: +- The upper bound address may not be representable within the allocated memory range. +- In hardware, this can lead to prefetching errors, page faults, and potential security issues due to speculative execution. +- In software, off-by-one errors frequently arise when handling array lengths and loops. + +A personal anecdote from AMD illustrates the severity of this issue: speculative execution could cause processors to prefetch addresses that lay outside valid memory pages, leading to processor bugs that were not initially acknowledged. + +* Inclusive Bounds: A Cleaner Approach? +Inclusive bounds, in contrast, place the upper bound within the interval, reducing the risk of out-of-bounds memory accesses. Some advantages include: + +- The highest valid index remains within the range of representable values. +- Iteration tests for `>` rather than `==`, which is often more intuitive. +- Eliminates off-by-one errors associated with exclusive bounds. + +This approach is used in some hardware and computational models, as detailed in TTCA​:contentReference[oaicite:0]{index=0}. The book advocates for extent-based indexing rather than length-based indexing to ensure safe iteration patterns. + +* The Boundary Issue in Inclusive Upper Bounds + +While inclusive bounds provide intuitive indexing and prevent off-by-one errors, they introduce a fundamental issue when dealing with **typed memory operations**, such as bulk copying or aligned processing. + +- A **pointer to the first byte** of an interval is **also a pointer to the first word**, making inclusive lower bounds type-agnostic. +- However, a **pointer to the last byte** is **not** a pointer to the last word—it is merely the last address in the range. +- In contrast, an **exclusive upper bound** remains type-agnostic, as it represents an address just past the valid range, which works independently of element size. + +### **Why This Matters for Bulk Operations** +Memory operations often process data in **word-sized chunks** for efficiency: +- Copying memory in **aligned 64-bit words** requires knowing where the last valid word begins. +- With **exclusive bounds**, this is straightforward: iteration stops at the upper bound. +- With **inclusive bounds**, adjustments (`-8` for 64-bit words) become necessary to avoid overstepping. + +### **Key Takeaways** +- **Inclusive lower bounds remain universally valid** and do not require type knowledge. +- **Inclusive upper bounds require type knowledge**, which can be inefficient or unsafe. +- **Exclusive upper bounds** naturally align with word-based processing, reducing extra adjustments. + +This suggests that **a hybrid approach**—inclusive lower bounds with exclusive upper bounds—may provide the best balance of **safety and efficiency**, particularly in systems with **low-level memory operations**. + +* Implementation Considerations +Converting from exclusive to inclusive bounds is not trivial, as many established languages and libraries assume exclusive bounds. Some challenges include: + +- Existing APIs and standard libraries expect exclusive bounds, requiring additional adjustments. +- Iteration logic must be adapted to use `<=` instead of `<` in many cases. +- Some optimizations, such as using pointer arithmetic with exclusive bounds, may require rethinking. + + +* Conclusion +The choice between exclusive and inclusive bounds is not merely a stylistic one but has real implications for safety, correctness, and performance. While exclusive bounds remain dominant in C-derived languages, inclusive bounds eliminate a class of potential errors and are often preferable when designing new architectures or computational models. + +For TTCA, inclusive bounds were chosen specifically to prevent the issues that arise from exclusive bounds​:contentReference[oaicite:1]{index=1}. Future discussions may explore the feasibility of transitioning software ecosystems toward inclusive bounds or at least providing safer abstractions to mitigate the risks of exclusive bounds. + +* References +- Thomas, *Tom's Turing Complete Computing Architecture (TTCA)*​:contentReference[oaicite:2]{index=2}. + +------------------------ +Here’s what stands out from this process: + +Inclusive lower bounds work cleanly + +The starting address is always valid, so there’s no need for adjustments. +This makes iteration straightforward without additional logic. +Inclusive upper bounds require adjustments in word-based operations + +A pointer to the last byte is not a pointer to the last word. +This forces explicit alignment corrections (& ~0x7 style masking). +These corrections introduce additional computation (-8, +1, conditionals). +Exclusive upper bounds simplify bulk memory operations + +If the loop simply runs while ptr < end, the word-aligned processing works naturally. +No need for extra adjustments before entering the bulk copy loop. +This aligns with how hardware and assembly-based operations work. +Hybrid Approach Might Be the Best Path + +Inclusive lower bounds keep indexing intuitive. +Exclusive upper bounds avoid unnecessary adjustments in word-based processing. +This mirrors how C and assembly tend to handle memory intervals (start inclusive, end exclusive). + +------------------------ +Inclusive upper bound made byte reverse copy simpler, as there was symetry in pointing +to the last byte of word to represent a word in reverse order, and pointing to the +the first byte to represent the word in forward order. diff --git a/document/Model.org b/document/Model.org new file mode 100644 index 0000000..f6b700d --- /dev/null +++ b/document/Model.org @@ -0,0 +1,215 @@ +#+TITLE: Model +#+AUTHOR: Thomas +#+STARTUP: content + +* Tableau + +A Tableau is a type definition for a work area, typically implemented as a typedef struct in C. + +An instance of a Tableau is a tableau. There can be many instances of a given Tableau. + +There are multiple kinds of Tableau: + +- interface (also called a Face) +- state + +* ActionTable + +An action is a function that operates on a tableau. + +Each action is an instance of an Action. An Action is a typedef for a function pointer. + +An ActionTable is a typedef of a struct, and instance of is said to be an action_table. +A given ActionTable can + +An instance of an ActionTable is an action_table. There can be many isntances of a given ActionTable. + +Each function in an action_table is an action. + + +* Model + +A Model is a TableauFace, a TableauState, and an ActionTable. + +An instance of a Model is a model. + + +* Status bits or continuations? + +The problem I found with continuations is that when the library is +limited to a single status function for a model, there will necessarily +be many continuations from the status function, one for each shade of meaning that it can discern. To endow it with fewer would limit its usefulness for some scenario, perhaps rare, but still supported. + +In addition, not all status's are independent. Thus there must be a priority scheme and then a choice of continuation, but the status function might not know the caller's +priorities. An alternative would be to take both continuations and break into multithreaded execuation. However, many programs are designed to be single threaded. + +When status is used as an argument guard this often comes down to, "Is the passed in +status baring model operable or not?" Thus the tableau for the many-continuations status function will have many duplicate next pointers. + +If rather than returning continuations, a highly discerning status function were to return status bits, The caller could mask the bits and then chose among continuations. In the cause of an argument guard, choosing among two paths. + +It is also a little funny when using a status function as an argument guard that the guard continues into the very function it is guarding. The tableau facilitates this +design pattern in that the input operands need not be written again. Though this +requires managing the tableau for the model who's status is being checked. + +An alternative to using status bits is to have more than one status function. One implementation is to embed the many-continuations status function inside the few-continuations status function, to perform the mask, and then pick the continuation. This might be convenient function to have, but where a second status function really makes sense is where it reduces the amount of computation that need be done. + +* A Single Tableau per Model + +Inputs for actions are written to a tableau. A link currently holds an actions table pointer, and a tableau pointer, hence there is one tableau that holds both action inputs and model state variables. + +If this tableau is declared as part of the FACE then the user can access the model state variables. This would follow a philosophy of, "if they are useful, then so bit it"; however exposing state variables limits both the number of models that can be made that provide the user with the same interface, and limits what can be done with maintenance edits without risking breaking the user's code. Recall that Model is an abstract type, and there can be many implementations for said type, i.e. many models for a given Model. + +C does not allow for public and private sections of a struct, or we could make the state variables private. + +However, we can accomplish the same thing as public and private, perhaps in even a better way, by including the interface tableau in the full tableau, and have the code know it was given the full tableau: + +#+BEGIN_SRC c +typedef struct{ + ... +}X·TableaFace; + +// in the implementation + +typedef struct{ + X·TableaFace face; + ... +}X·Tablea; + +#+END_SRC + +The details of the TableauFace type are shown to the user. The actions are +declared to be given a TableauFace, so any directly calls will work. Inside each action the tableau is converted from TableauFace to Tableau. + +=> Core uses separate Face and State tableaux + +** Tableau structure + +The TableauFace has: +- all possible inputs +- results +- continuations + +Then the Tableau extension + +- state variables + + +* Continuation Link + +There are two dimensions of variation. 1) Multiple action_tables from a given ActionTable, and 2) multiple tableau from a given Tableau. + +Each action_table instance of a given ActionTable can have very different function implementations, as only the function type signatures are specified in the ActionTable definition. + +The interface tableau, TableauFace, is designed against the ActionTable. Both deal with the user's view of the Model. In contrast each state tableau, TableauState is designed against a specific action_table. + +Hence, for each ActionTable declaration there will be corresponding to a TableauFace declaration, unless by coincidence, an existing one can be recycled, though even then programmers would appreciate having matching names. This begs the question if the two structures can be combined into one. So doing would constrain our ability to make instances from them independently. + +A given action table can be used with multiple state tableaux. In other words, there can be multiple instances of the same type. + +Conversely a given tableau can be used with multiple action tables. This happens in +polymorphism, where a child tableau can be passed to a parent action. The child +parts are in an extended portion of the tableau, and thus not seen by the parent +action. + +In the one Tableau per model approach, each tableau instance is both state and inputs, hence each instance will have its own inputs. We would lose the ability to make independent state and interface instances. The interface tableau is playing the role +that is typically played by the stack frame. Hence there is a copy per call, now this the one tableau per model, there would be a copy per instance. If left independent, there would be as many or few copies as the user determines is necessary, with the network of interface tableaux being connected by pointers tending to look like a circuit. + +**proposal 1 + +Place an action_table pointer in each single tableau per model tableau, then there would be many copies of the action_table pointer, one per tableau. This is the virtual table pointer approach from C++ or the delegate pointer from JavaScript. + +With this approach the action table can be reached through the tableau, so only the tableau, or references to it, need to be passed around as an instance of the model. This is appealing. + +However, such a link to such a tableau is not sufficient for knowing which action on the action table should be called. Hence a link to such an overloaded tableau can not function as a continuation link. + +Suppose if instead of an action_table link, a function link were embedded in the tableau, perhaps as a first member. Then the first member could be called and given the tableau as its only argument. This could function as a link, but then the state of the model is owned by a single function call. This looks problematic. + +**proposal 2 + +A link is a two pointer bundle. The first pointer to an action table, the second to single tableau. Then there is a macro called `call` that is used for calling functions in the action table. ``call(extent ,&tape_tableau)` + +The problem here is that such a link can not appear as a continuation because the link itself does not say which action is being invoked. That information is in the call. + +Attempts to save this proposal by including a 'field pointer' in the link, that would be applied to the action table are rather awkward in C, though it can be done by creating an enumeration of the struct offsets, and using those tags. + +**proposal 3 + +A three pointer bundle, the first pointer to the function being called, the second pointer to an interface tableau, the third pointer to the state tableau shared by the functions in the action_table the function comes from. + +In this approach there is not action_table pointer, though that is not a problem because if that information is needed it can be curried into the called function when it is written, though chances are if a given action needs to call another action function in the table, it will do so through a function pointer. The purposes of the action_table struct is then to document which actions share the corresponding tableau state, and to provide a namespace to put the actions in, which makes it conceptually nicer for the programmer. It would be even nicer if C supported Pascal's 'with' statement. + +Such a link could be reduced to two pointers if the single tableau variation is used. + +==> Core uses proposal 3 + + +* Mixing continuations with fall through execution. + +#+BEGIN_SRC c + Local void call(Core·Link *lnk){ + while(lnk) lnk = lnk->act(lnk); + } +#+END_SRC + +This implementation of call falls through when a null `lnk` pointer is returned. However the caller can not know anything about the status of the call. + +**proposal 1 + +Each continuation function that can return a NULL link, where the caller wants to know the status, also sets a `status` value at the top of the base tableau, that all FACE tableau's extend from. + +Disadvantage, all code must set status, so why have continuations? The optimizer will drop unused status setting code, so perhaps this is not serious. Though, on the other hand, for Local functions would the optimizer skip the status return and condition testing, and put the continuation in - thus making status setting the way to go as it must be coded anyway? + + +**proposal 2 + +Have actions that set status, link to them when status is desired. + +Actually we need default continuations anyway. In many cases these could +be generic. Argument guard continuations could be 'good' or 'bad'. + +=> Core uses option 2 + +* Continuations and linking + +**proposal 1 + +Put continuations on the interface tableau. The reasoning is that the programmer will want to set them, but actually this is not a general programming task. Rather it occurs up front as part of a 'wiring' phase, and is then typically it is not done again. + +Consider this example. + +#+BEGIN_SRC c + typedef struct{ + Core·Tape·Tableau·Face tape_tableau; + Core·Area *area; + void *position_left; + void *position_right; + AU *pt0; + AU *pt1 + Core·Area *a; + Core·Area *b; + bool q; // predicate -> q + Core·Link next; + }Core·Area·Tableau·Face; +#+END_SRC + +The idea is that there is one interface tableau used for all of the Area·Tableau actions, but it has a link field. Normally while the linked together functions are running, they can not set the 'next' link, as that information comes from a higher level. For example, after `encloses_pt_q` runs, it has no idea as to where the programmer wants control to flow next. + +**proposal 2 + +Add a fourth pointer to a link. This points to the continuations block. + +#+BEGIN_SRC c + typedef struct{ + Core·Tableau *face; + Core·Tableau *state; + Core·ActionTable *action; + Core·NextTable *next_table; + }Core·Link; +#+END_SRC + +We may then describe the program flow network as a series of next_tables, and then view the program as traversing a graph. + +In database representation a set of nodes, and the dual graph is specified as a bridge table. It is more efficient when traversing a graph, to keep make the neighbor list a property of the node. Thus, "Link" can be seen as a node with a neighbor list. + +=> Core uses option 2 diff --git a/document/RT_C_namespace.org b/document/RT_C_namespace.org new file mode 100644 index 0000000..e4d353a --- /dev/null +++ b/document/RT_C_namespace.org @@ -0,0 +1,174 @@ +#+TITLE: RT C Namespace Convention +#+AUTHOR: Sorein +#+DATE: 2025-04-25 + +* 1. Namespaces in RT C + +C has no formal namespace system, so RT C introduces a **middle-dot namespace convention** to provide **clarity, collision avoidance, and modular structure** in large, macro-heavy codebases. + +The `·` symbol (U+00B7, **middle dot**) is used as a visual and semantic scoping operator between **namespace components**, similar to how `::` is used in C++ or `.` in Java. + +This convention applies uniformly to: +- Function names +- Type names +- Structs +- Macros (especially templated forms) +- Dispatch tables + +Example: +#+BEGIN_SRC c +N32·allocate_array +Core·round_up +TM·AU·Array·init_pe +#+END_SRC + +Here, each `·` separates conceptual scopes: +- `TM·AU·Array·init_pe` means: `init_pe` function, inside `Array` implementation, for the `AU` cell type, inside the `TM` module. + +* 1.5 The Middle Dot: Syntactic Sugar and Token Trickery + +The character `·` (U+00B7, **middle dot**) is **not** special in the C language. To the C preprocessor and compiler, it's simply a valid identifier character—just like `A_Z` or `foo42`. + +That means: + +#+BEGIN_SRC c +TM·AU·Array·init_pe +#+END_SRC + +is **just one long identifier**. The compiler doesn't see it as hierarchical—only as a single symbol. The visual segmentation is entirely for the *reader's* benefit, not the *compiler's*. + +> For now, the middle dot is syntactic sugar. But someday, perhaps, a future C or C++ might embrace it as a real scoping operator. We prepare the ground. + +However, when we want to *construct* identifiers programmatically via macros, `·` by itself is not enough. **The C preprocessor does not treat `·` as an operator**, so it won't concatenate tokens with it unless we explicitly instruct it. + +To solve this, RT C defines the following macro in `cpp_ext.c`: + +#+BEGIN_SRC c +#define ·(A,B) A##·##B +#+END_SRC + +This turns: + +#+BEGIN_SRC c +·(TM,AU) → TM·AU +#+END_SRC + +And can be chained: + +#+BEGIN_SRC c +·(·(TM,AU),Array) → TM·AU·Array +#+END_SRC + +For convenience and clarity, template variable values must be defined *before* expansion. For instance: + +#+BEGIN_SRC c +#define _Box_T_ int +#define _TM·CVT_ AU +#+END_SRC + +When these are defined in this manner, the macro `·(...)` allows us to produce the following expansions: + +| Macro Invocation | Resulting Identifier | +|--------------------------------+-------------------------------| +| `·(Box_Box,_Box_T_)` | `Box_Box·int` | +| `·(Box_set,_Box_T_)` | `Box_set·int` | +| `·(TM,_TM·CVT_)` | `TM·AU` | +| `·(TM,_TM·CVT_,Array)` | `TM·AU·Array` | +| `·(TM,_TM·CVT_,Array,init_pe)` | `TM·AU·Array·init_pe` | + +This macro-based approach makes template expansion **predictable, readable, and modular**—while preserving the middle dot as a **structural visual** and a **join point** for layered namespaces. + +In summary: + +- As a **literal**, `·` is a harmless identifier character. +- As a **macro call**, `·(...)` is a *token concatenator* that inserts middle dots between parts. +- This duality is key to templating and namespacing in RT C. + +* 2. Purpose of the Middle Dot + +**The `·` is not just cosmetic**—it encodes structured meaning: + +| Position | Meaning | +|----------+----------------------------------| +| Leftmost | Module namespace (e.g. `TM`) | +| Middle | Type or submodule scoping | +| Rightmost| Symbol or function identifier | + +This gives the illusion of *semantic depth* within a flat C symbol space. It also facilitates: +- Greppable identifiers +- Predictable naming for macros, typedefs, and tables +- Avoidance of conflicts in shared headers + +* 3. Template Variable Convention: `_Var_` + +Template variables are identified with **leading and trailing underscores**, e.g. `_TM·CVT_`. These are used to parameterize includes and define generic logic. + +When a template is instantiated: +- The value of `_Var_` is set (e.g. `_TM·CVT_ = AU`) +- The file is included +- A guard macro (e.g. `SET__TM·AU`) is defined + +This ensures one instantiation per type per translation unit. + +Example: +#+BEGIN_SRC c +#define _TM·CVT_ AU +#include "TM.lib.c" +#define SET__TM·AU + +#define _TM·CVT_ Str +#include "TM.lib.c" +#define SET__TM·Str +#+END_SRC + +* 4. Guard Macros: SET__Module__Type + +To prevent multiple expansions of the same template with the same argument, we define a sentinel macro after inclusion: + +#+BEGIN_SRC c +#if !defined(SET__TM·AU) +#define SET__TM·AU +... +#endif +#+END_SRC + +These guards allow repeated template includes in a single TU, and avoid the fragile workaround of modifying headers manually. + +* 5. Practical Naming Examples + +| Symbol | Meaning | +|----------------------------------+---------------------------------------------------| +| `Core·FG` | Function dictionary for the Core module | +| `TM·AU·FG` | Function dictionary for TM with AU cell type | +| `TM·Str·Array·init_pe` | Init function for TM with Str cell type, Array impl | +| `SET__Binding__TM·AU` | One-time expansion guard for Binding of TM·AU | +| `extent_t·AU` | Type alias for extent of AU array | +| `FG·Type` | Template variable name for FG expansion | + +* 6. Why Not Use Underscores or CamelCase? + +While underscores (`_`) are idiomatic in C, they don't offer visual scoping in the same way, especially when chained deeply. Middle dots provide: + +- **Visual segmentation** across layered modules +- **Improved grepability**: `grep TM·` finds all TM-related symbols +- **Avoidance of macro clashes**: underscores often clash with system headers, especially when using `__NAME__` forms +- **Harmony with macro join operations** like `·(...)` + +* 7. Future Compatibility + +If C ever adopts formal module systems or namespaces, the `·` syntax can be systematically translated into official syntax, e.g.: + +- `TM·AU·Array·init_pe` → `TM::AU::Array::init_pe` +- Greppable → parseable → mappable + +For now, `·` is an elegant compromise between form, function, and forward-compatibility. + +* 8. Summary + +RT C namespaces provide: +- Scoped, composable identifiers +- Greppable structure for large projects +- Seamless macro templating and type specialization +- Collision resistance without verbosity + +By adopting `Module·Type·Submodule·Function` naming, your C code remains modular, clean, and scalable. diff --git a/document/RT_C_tableau_methhod.org b/document/RT_C_tableau_methhod.org new file mode 100644 index 0000000..3e1f533 --- /dev/null +++ b/document/RT_C_tableau_methhod.org @@ -0,0 +1,177 @@ +#+TITLE: RT Tableau Method +#+AUTHOR: Thomas + +* Memory + +A *base-relative memory map* is a dictionary that associates symbol names with offsets from a base address. A C ~struct typedef~ is an example means for declaring a base-relative memory map. A base-relative memory map has a length associated with it. + +Another term for a *base-relative memory map* is *memory format*. A defined memory format can be bound to a name. The names are required to be distinct, though the formats bound to the names need not be. + +An *instance* of , where is the name of a memory format, is a region of memory that has been bound to memory format . + +The *type* of an instance is the name of its memory format. + +* Pointer + +A *pointer* is a memory address that has been bound to a memory format. This technique is used to assure that writes to the memory address conform to the bound memory format. This helps programs to respect the bounds of memory allocations. + +The *type* of a pointer is the name of the memory format it has been bound to. + +* Function Pointer + +The address of a function can be bound to a name and an array of memory formats, +one for each argument and the return value. + +The *type* of a function is defined by its name and its array of memory format names. + +The type of a function can be looked up from the function's name. + +* Function Dictionary + +A *function dictionary* is a list of function names and addresses, keyed by function names. + +A *function dictionary template* is a collection of function types associated with a specific memory format. + +A *function dictionary instance* is a collection of function implementations that conform to a function dictionary template. + +* Object + +If the potentially many instances of a given memory format are operated on exclusively by a closed set of functions, these functions can be collected into a dictionary called the memory format's *interface*. + +Conversely, there is no conventional name for an instance of memory that is manipulated by only a closed set of functions. In TTCA, the term *tableau* was introduced for such memory. (A *tableau* is a small chalkboard that was once used by students and could be erased and rewritten.) + +Another term that could be used for such memory is *taishou* (対象), meaning "subject" or "target" in Japanese. + +* Working with `.lib.c` Files in RT C + +In the RT C design, each module’s interface **and** implementation are contained in +a single file named `something.lib.c`. Traditional `.h` headers are replaced by +preprocessor-guarded interface sections, while the main implementation and any +“local” (private) code appear in separate blocks. If you want to learn more about +this format, there is a dedicated document explaining how `.lib.c` files are structured, +along with how and why they’re compiled. + +Briefly: + +- **Interface Section** + Declares the memory format (`struct N32·T`, for instance) and the function dictionary + type (`N32·M`), along with any prototypes that external code needs. + +- **Implementation Section** + Provides the actual definitions of the functions from the interface, compiled into + an object file (e.g., `N32.lib.o`) that goes into a library (`.a` or `.so`). + +- **Local Section** + (Guarded by `#ifdef LOCAL`) Contains private utility functions or test helpers. + Only included when a `.cli.c` test or other special code explicitly requests it. + +This structure keeps all relevant code (interface, implementation, internal helpers) +in a single `.lib.c` file, yet still enforces encapsulation via preprocessor macros. +It aligns well with the *tableau* and *function dictionary* concepts described here: +the memory format and method table are declared in the interface section, their +implementations go in the implementation section, and if you need advanced debugging +routines or private details, you can optionally include the local section. + + +* More about Tableau (Taishou) + +Below is a minimal example that shows how an instance of a memory format (`N32·T`) can be exclusively manipulated by a *function dictionary* (`N32·M`). This concrete “tableau” (taishou) usage illustrates how the memory is bound to specific operations—no external code should modify the memory except through the provided dictionary functions. + +#+BEGIN_SRC c +#include +#include + +// 1. Define the memory format (tableau) +typedef struct { + uint32_t value; +} N32·T; // This struct is our 'tableau'. + +// 2. Provide some functions that operate on N32·T +void N32·copy(N32·T *dst, const N32·T *src){ + dst->value = src->value; +} + +void N32·increment(N32·T *t){ + t->value++; +} + +void N32·print(const N32·T *t){ + printf("Value: %u\n", t->value); +} + +// 3. Declare a function dictionary (method table) +typedef struct { + void (*copy)(N32·T*, const N32·T*); + void (*increment)(N32·T*); + void (*print)(const N32·T*); +} N32·M; + +// 4. Provide a concrete instance of the dictionary +const N32·M N32·m = { + .copy = N32·copy, + .increment = N32·increment, + .print = N32·print +}; + +// 5. Demonstrate usage in a main function +int main(void) { + // Create an instance of N32·T (our tableau) + N32·T my_number = { .value = 10 }; + + // Manipulate it exclusively through the function dictionary + N32·m.increment(&my_number); // Increment by 1 + N32·m.print(&my_number); // Output should show "Value: 11" + + // Create another instance and copy its contents + N32·T another_number = { .value = 42 }; + N32·m.copy(&my_number, &another_number); + N32·m.print(&my_number); // Output should show "Value: 42" + + return 0; +} +#+END_SRC + +When compiled and run (e.g., `gcc example.c -o example && ./example`), the program +prints: + +#+BEGIN_EXAMPLE +Value: 11 +Value: 42 +#+END_EXAMPLE + +In this way, `my_number` is a tableau. All modifications happen via a *closed set of +functions*—here, the operations are defined in the function dictionary `N32·m`. No +external code is allowed to poke into `my_number.value` directly (beyond this demonstration), +upholding the idea that a “tableau” is memory dedicated to a specific “function dictionary.” + + +* Terminology Considerations + +The use of the word *type* in this document aligns with C’s conventions. However, other +programming paradigms, such as those in C++ and Java, may define *types* differently. +For example, C++ allows types to include behavior (methods), while C’s types only +define memory structure. + +--- + +**Summary of Key Terms:** +- *Memory Format*: A named layout of memory. +- *Instance*: A memory region adhering to a specific format. +- *Pointer*: A memory address bound to a memory format. +- *Function Dictionary*: A set of functions associated with a memory format. +- *Tableau/Taishou*: A memory instance operated on exclusively by a function dictionary. +- *Function Dictionary Template*: A function dictionary where function types replace function implementations. + + +A *base-relative memory map* is a dictionary that associates symbol names with offsets +from a base address. A C ~struct typedef~ is an example means for declaring a +base-relative memory map. A base-relative memory map has a length associated with it. + +Another term for a *base-relative memory map* is *memory format*. A +defined memory format can be bound to a name. The names are required +to be distinct, though the formats bound to the names need not be. + +An *instance* of , where is the name of a memory format, is a region +of memory that has been bound to memory format . + +The *type* of an instance is the name of its memory format. diff --git a/document/RT_cli_c_file.org b/document/RT_cli_c_file.org new file mode 100644 index 0000000..06d6723 --- /dev/null +++ b/document/RT_cli_c_file.org @@ -0,0 +1,147 @@ +#+TITLE: Writing `.cli.c` Files in RT C +#+AUTHOR: Thomas + +* Overview +In RT C projects, a file with a “=.cli.c=” suffix typically implements a **command-line interface** i.e. a program that is run from a shell. Thus each `.cli.c` file produces an **executable** named . + +Common usage includes: +- **Command-Line Interaction** Typical commands run from a shell. +- **Testing**: Execuatbles that test C functions and print pass fail results. +- **Reusable Components**: As discussed in the section below on `main`, cli files can be called from other functions, and thus are themselves reusable components. + +* 1. Including library header information +Because a `.cli.c` file makes use functionality from libraries, it will often include file headers. In RT C, there will be a single file for both the header information and C implementation called, such a file will have a `.lib.c` suffix. The separate sections in a `.lib.c` file are gated by the preprocessor macros, `FACE`, and `LOCAL`. To include the header information from a `.lib.c` file, the `.cli.c` file will have at the top the lines: + +#+BEGIN_SRC c +#define FACE +#include "some_library.lib.c" +#include "some__other_library.lib.c" +... rest of program +#undef FACE +#+END_SRC + +* 2. Including static defined function + +Instead of using `inline` qualifications in the header, in RT coding conventions, static functions are defined in the `.lib.c`, and then included at the bottom of the `.cli.c` file. +Again this is done by gating the sections of the `.lib.c` file: + +#+BEGIN_SRC c +... rest of program + +#define LOCAL +#include "some_library.lib.c" +#include "some__other_library.lib.c" +... +#undef LOCAL +#+END_SRC + +* 3. Both header information and static defined functions: + +#+BEGIN_SRC c +#define FACE +#include "N32.lib.c" +#undef FACE + + ... rest of program + +#define LOCAL +#include "N32.lib.c" +#undef LOCAL +#+END_SRC + +- `FACE` grants access to the library’s public symbols (structs, function prototypes). +- `LOCAL` gives access to internal (“static-like”) helpers if needed for deeper testing or debugging. Only define it if you truly require these private functions/data. + +The idea here is that that optimizer can do its best work when it sees everything in one place, and thus there is no need for inline functions. On paradigm can be used for defining the program. + +* 4. The `main()` Function in `.cli.c` +Every `.cli.c` includes a `main()` function, but with special guidelines: + +1. **Minimal Parsing & Dispatch** + - `main()` is primarily responsible for reading `argc`/`argv`, validating inputs, and directing calls to your actual logic or library code. + +2. **Reusable Subroutines** + - If your `.cli.c` logic is extensive, break it out into functions that `main()` calls. This way, **other** `.cli.c` files (or even libraries) can call these same functions directly without launching a new process. + +3. **Avoid Side Effects** + - Keep `main()` from doing excessive configuration or global side effects (e.g., changing global state). This maintains a clean separation between your library code and the command-line scaffolding. + +4. **Standard Return Codes** + - Return 0 for success, non-zero for errors. If the CLI is also used programmatically by other modules, they can interpret these returns or, better yet, call your internal subroutines that return more detailed error codes. + +Example skeleton: + +#+BEGIN_SRC c +int main(int argc, char **argv){ + // 1. Parse command-line args + // 2. Validate or print usage + // 3. Call library functions or dedicated subroutines + // 4. Return 0 on success, or an error code otherwise +} +#+END_SRC + +* 5. Example of a `.cli.c` File + + +Below is a **working** `.cli.c` program demonstrating how to use the `N32.lib.c` library: + +#+BEGIN_SRC c :tangle test_N32.cli.c +#include +#include +#include + +// Expose the N32 interface by defining FACE +#define FACE +#include "N32.lib.c" +#undef FACE + +int main(int argc ,char **argv){ + if(argc < 3){ + printf("Usage: %s \n", argv[0]); + return 1; + } + + uint32_t a_val = (uint32_t)atoi(argv[1]); + uint32_t b_val = (uint32_t)atoi(argv[2]); + + // Allocate N32 objects + N32·T *numbers = N32·m.allocate_array(2 ,NULL); + if(!numbers){ + printf("Allocation failed.\n"); + return 2; + } + + // Initialize + N32·m.from_uint32(N32·m.access(numbers ,0) ,a_val); + N32·m.from_uint32(N32·m.access(numbers ,1) ,b_val); + + // Perform add + N32·T result; + N32·m.add(&result, N32·m.access(numbers ,0), N32·m.access(numbers ,1)); + printf("Sum of %u and %u is %u\n", a_val, b_val, result.d0); + + // Perform subtract + N32·m.subtract(&result, N32·m.access(numbers ,0), N32·m.access(numbers ,1)); + printf("Diff of %u and %u is %u\n", a_val, b_val, result.d0); + + N32·m.deallocate(numbers); + return 0; +} +#+END_SRC + +Here, `main()` parses two integer arguments, allocates an array of `N32·T`, +calls the library’s add and subtract functions, and prints the results. +If this is compiled alongside (or linked against) the `N32.lib.c` object code, +running `./test_N32 20 12` will produce: + +#+BEGIN_EXAMPLE +Sum of 20 and 12 is 32 +Diff of 20 and 12 is 8 +#+END_EXAMPLE + + +* 6. Summary +- **`.cli.c`** files produce executables with a central `main()` function focused on argument parsing and error handling. +- Actual logic often lives in separate subroutines (or in `.lib.c` libraries) to encourage reuse without spawning new processes. +- The RT C approach puts library interfaces in the same file as their implementation (`.lib.c`), so `#define FACE` (and optionally `#define LOCAL`) is how a `.cli.c` pulls in the necessary API or private details. +- This design maintains a clean separation between **common library functionality** and **CLI/test scaffolding**, making it easy to test or chain multiple CLIs together within the same program. diff --git a/document/RT_lib_c_file.org b/document/RT_lib_c_file.org new file mode 100644 index 0000000..9f47698 --- /dev/null +++ b/document/RT_lib_c_file.org @@ -0,0 +1,107 @@ +#+TITLE: The `.lib.c` Format +#+AUTHOR: RT C Documentation + + +* 1. The `.lib.c` File: Purpose and Sections +A single `.lib.c` file contains **interface**, **implementation**, and **local** (private) code in one place. This is an alternative to the traditional “.h + .c” pairing. Below is how the sections typically appear: + +* 2 Overview +1. **Interface Section** (replaces `.h` in traditional C) + - Guarded by `#ifndef N32·FACE ... #define N32·FACE ... #endif`. + - Contains `typedef`s, structs, enums, function prototypes—everything needed for external code to use the library. + +1. **Implementation Section** (the code compiled into the `.o` files, or `.a` or '.so' library) + - Enabled by `#define N32·IMPLEMENTATION`. + - Provides function bodies, global variables, and logic. + - Typically compiled once into the library object. + +3. **Local (Static) Section** (private code) + - Guarded by `#ifdef LOCAL`. + - Contains helper functions or data only needed in special scenarios (like testing or advanced usage). + - Marked with `Local` (instead of `static`) to indicate internal linkage. + +* 3 Macros at the Top +At the very top of a `.lib.c` file, you might see: +#+BEGIN_SRC c +//#define N32·DEBUG + +#ifndef FACE + #define N32·IMPLEMENTATION + #define FACE +#endif +#+END_SRC + +Explanation: + +- `N32·DEBUG` can be toggled for debugging features (or left commented). +- `#ifndef FACE` ensures the code only defines `N32·IMPLEMENTATION` if another block (like an interface-only include) hasn’t already set `FACE`. +- Once `N32·IMPLEMENTATION` is set, it means “compile the implementation code” by default. + +* 4 The Interface Section +Next, we see something like: +#+BEGIN_SRC c +#ifndef N32·FACE +#define N32·FACE + +// interface code here (typedefs, prototypes, extern definitions) +// ... +#endif +#+END_SRC + +- Prevents multiple inclusion of the interface (`N32·FACE`). +- Acts like a header: external code can `#define IFACE` or define `FACE` to pull in these declarations. + +* 5 The Implementation Section +After the interface `#endif`, you typically see: +#+BEGIN_SRC c +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef N32·IMPLEMENTATION + // ... + #ifndef LOCAL + // Code that goes into the library object (main .o) + #endif + + #ifdef LOCAL + // Additional local or inline-like code + #endif +#endif +#+END_SRC + +Breakdown: + +1. `#ifdef N32·IMPLEMENTATION`: + - If this macro is set (usually when compiling `.lib.c` directly), we include all code for the library’s global functions. + +1. `#ifndef LOCAL`: + - Code in this block becomes part of the final `.o` or `.a` file. It is the public “library” portion, implementing the functions declared in the interface. + +3. `#ifdef LOCAL`: + - Private or test-only code, included only when some other file includes this `.lib.c` with `#define LOCAL`. + +* 6 Local vs. Static +Inside the local section, you might see `Local N32·T my_array[4]` instead of `static N32·T my_array[4]`. Historically, `static` in C means both “file scope” and “static storage duration.” The RT code style uses `Local` to clarify that these symbols have internal linkage and are “private” to this compilation unit. It’s effectively the same as `static` but more explicit in intent. + +* 7 Example Compilation Workflow +1. **Library Compilation** + - Invoke the compiler on `N31.lib.c` *without* defining `IFACE` or `LOCAL`. + - The file sees `N32·IMPLEMENTATION` → it compiles the interface + implementation code. + - Produces `N31.lib.o`, which can then be placed in `N.a` or `N.so`. + +1. **CLI or Test Program** + - A `.cli.c` might do: + #+BEGIN_SRC c + #define LOCAL + #include "N31.lib.c" + #undef LOCAL + // Now we have local (private) helpers for testing + + int main() { + // test or CLI logic calling the library + } + #+END_SRC + - This allows direct access to the library’s “private” or local section for debugging or specialized usage. + - The resulting `.cli.o` links with `N31.lib.o` from the library build, forming an executable. + +With this design, everything about a module (interface, implementation, private code) resides in a single file (`.lib.c`). The build system compiles these files into objects and links them to produce either a static or dynamic library. Meanwhile, `.cli.c` files become executables that can optionally include the local code if needed. diff --git a/document/User_manual.org b/document/User_manual.org new file mode 100644 index 0000000..1b0a962 --- /dev/null +++ b/document/User_manual.org @@ -0,0 +1,32 @@ +#+TITLE: User manual +#+AUTHOR: Thomas + +* Sections + +* Compile + + +/* + N32 - a processor native type + + For binary operations: a op b -> c + + See the document on the proper use of the Natural types. + + On the subject of multiple pointers indicating the same location in memory: + + When a routine has multiple results, and one or more of the result location + pointers point to the same storage, the routine will either return an error + status, or have defined behavior. + + When a routine has multiple operands, in any combination, those + pointers can point to the same location, and the routine will + function as advertised. + + When an operand functions as both an input and a result, perhaps due + to a result pointer pointing to the same place as an operand + pointer, the routine will function as advertised. (Internally the + routine might make a temporary copy of the operand to accomplish + this.) + +*/ diff --git a/document/continuations.org b/document/continuations.org new file mode 100644 index 0000000..89d9a3b --- /dev/null +++ b/document/continuations.org @@ -0,0 +1,16 @@ +#+TITLE: Reflections On Continuations +#+AUTHOR: Thomas +#+STARTUP: content + +There are two things going on: + +- The function executes code against data. When doing so it happens upon some characteristics of the computation. These often include the results from argument guards, and reports of end cases. The function the reports back information that could potentially be used to + affect control flow. + +- The control flow is a related, but separate question. There is an overall scheme of control flow that involves branching, where some of these branches depend on the evaluation of data. + +- So the question is then is it of value to pass into a function a list of, 'if you see X then call Y' ? Where every possible X is represented in the list. Does this not conflate control flow with computation? + + What if the X are not independent? Then the priority logic either requires a rendezvous with functions that have arguments, or be embedded in the called function with continuations, but said function knows nothing of the caller's priorities. + + If many continuations rendezvous so decisions can be made, how is that more efficient than the caller examining a returned status code, and make decision. Is this not a better location for the decision code, as the caller is setting the control flow? diff --git a/document/emacs_keys.el b/document/emacs_keys.el new file mode 100644 index 0000000..566c808 --- /dev/null +++ b/document/emacs_keys.el @@ -0,0 +1,84 @@ +;; the sake of sanity... +;; +(global-set-key (kbd "C-z") nil) ;; turn off the poison C-z key. Use C-x C-z or the command suspend-emacs +(global-set-key (kbd "C-v") nil) ;; tempting to put paste (yank) for a common typo, but at least lets not jump down the page +;; would be nice to clear C-c but minor modes redefine it + + +;;-------------------------------------------------------------------------------- +;; extended character set for programming examples in the TTCA book +;; +;; preferable to use an Xcompose file definition when available +;; +(when t + + (global-set-key [f1] 'help-command) + (global-set-key "\C-h" 'nil) + (define-key key-translation-map (kbd "M-S") (kbd "§")) + + (global-set-key (kbd "C-x g copyright SPC") [?©]) + + (global-set-key (kbd "C-x g phi SPC") [?φ]) ; phi for phase + (global-set-key (kbd "C-x g Phi SPC") [?Φ]) + + (global-set-key (kbd "C-x g d SPC") [?δ]) + (global-set-key (kbd "C-x g D SPC") [?Δ]) ; this is 'delta' is not 'increment'! + (global-set-key (kbd "C-x g delta SPC") [?δ]) + (global-set-key (kbd "C-x g Delta SPC") [?Δ]) ; this is 'delta' is not 'increment'! + + (global-set-key (kbd "C-x g g SPC") [?γ]) + (global-set-key (kbd "C-x g G SPC") [?Γ]) + (global-set-key (kbd "C-x g gamma SPC") [?γ]) + (global-set-key (kbd "C-x g Gamma SPC") [?Γ]) + + (global-set-key (kbd "C-x g l SPC") [?λ]) + (global-set-key (kbd "C-x g L SPC") [?Λ]) + (global-set-key (kbd "C-x g lambda SPC") [?λ]) + (global-set-key (kbd "C-x g Lambda SPC") [?Λ]) + + (global-set-key (kbd "C-x g m SPC") [?μ]) + (global-set-key (kbd "C-x g M SPC") [?Μ]) + (global-set-key (kbd "C-x g mu SPC") [?μ]) + (global-set-key (kbd "C-x g Mu SPC") [?Μ]) + + (global-set-key (kbd "C-x g p SPC") [?π]) + (global-set-key (kbd "C-x g P SPC") [?Π]) + (global-set-key (kbd "C-x g pi SPC") [?π]) + (global-set-key (kbd "C-x g Pi SPC") [?Π]) + + (global-set-key (kbd "C-x g x SPC") [?ξ]) + (global-set-key (kbd "C-x g X SPC") [?Ξ]) + (global-set-key (kbd "C-x g xi SPC") [?ξ]) + (global-set-key (kbd "C-x g Xi SPC") [?Ξ]) + + (global-set-key (kbd "C-x g > = SPC") [?≥]) + (global-set-key (kbd "C-x g < = SPC") [?≤]) + (global-set-key (kbd "C-x g ! = SPC") [?≠]) + (global-set-key (kbd "C-x g neq SPC") [?≠]) + + (global-set-key (kbd "C-x g nil SPC") [?∅]) + + (global-set-key (kbd "C-x g not SPC") [?¬]) + + (global-set-key (kbd "C-x g and SPC") [?∧]) + (global-set-key (kbd "C-x g or SPC") [?∨]) + + (global-set-key (kbd "C-x g exists SPC") [?∃]) + (global-set-key (kbd "C-x g all SPC") [?∀]) + + (global-set-key (kbd "C-x g do SPC") [?⟳]) ; do + (global-set-key (kbd "C-x g rb SPC") [?◨]) + (global-set-key (kbd "C-x g lb SPC") [?◧]) + + (global-set-key (kbd "C-x g cont SPC") [?➜]) ; continue + (global-set-key (kbd "C-x g thread SPC") [?☥]) ; thread + + (global-set-key (kbd "C-x g in SPC") [?∈]) ; set membership + + (global-set-key (kbd "C-x g times SPC") [?×]) ; set membership + + (global-set-key (kbd "C-x g cdot SPC") [?·]) ; scoping sepearator for gcc C + + (global-set-key (kbd "C-x g pencil SPC") [?🖉]) ; scoping sepearator for gcc C + +) diff --git a/document/temp.txt b/document/temp.txt new file mode 100644 index 0000000..a734ec4 --- /dev/null +++ b/document/temp.txt @@ -0,0 +1,90 @@ +#+TITLE: Proposed TM Bulk Methods for Multi-Cell Copy +#+AUTHOR: Sorein +#+DATE: 2025-04-25 + +* 1. Motivation: Efficient Copy Needs Bulk Cell Access + +The standard `read` and `write` methods in TM operate on **one cell at a time**, which is: +- Clear +- Safe +- Sufficient for most loops + +However, when implementing **bit-for-bit stream copy** between TMs, we want to: +- **Copy multiple cells at once**, where possible +- Use the largest available unit per cell +- Avoid stepping repeatedly through the same control path + +To support this, TM needs **bulk methods** for cell span access. + +* 2. What Is a Span? + +A **span** is a run of **N contiguous cells** available from the current tape head. + +A TM can only offer a span if: +- The head is *on tape* +- At least `N` cells are accessible to the right +- The memory layout is contiguous + +Not all TM types (e.g. cyclic or zero-length) support spans. For others, it's an optimization. + +* 3. Proposed TM Methods + +Each method is defined per CVT type. For example, `TM·AU` would add: + +#+BEGIN_SRC c +bool TM·AU·can_span(TM·AU tm ,size_t count); +AU const* TM·AU·peek_span(TM·AU tm ,size_t count); +AU* TM·AU·claim_span(TM·AU tm ,size_t count); +void TM·AU·commit_span(TM·AU tm ,size_t count); +size_t TM·AU·remaining(TM·AU tm); +#+END_SRC + +* 4. Semantics + +| Method | Purpose | +|------------------+--------------------------------------------------------------| +| `can_span(n)` | Returns true if N contiguous cells can be read or written | +| `peek_span(n)` | Returns a read-only pointer to N contiguous cells, or NULL | +| `claim_span(n)` | Returns a writable pointer to N cells, or NULL | +| `commit_span(n)` | Advances the head right by N cells (must follow claim) | +| `remaining()` | Returns the number of cells remaining from head to end | + +* 5. Guarded Use Pattern + +A `Copy` implementation might use: + +#+BEGIN_SRC c +while( TM·AU·can_span(src ,n) && TM·AU·can_span(dst ,n) ){ + AU const* s = TM·AU·peek_span(src ,n); + AU* d = TM·AU·claim_span(dst ,n); + memcpy(d ,s ,n * sizeof(AU)); + TM·AU·commit_span(src ,n); + TM·AU·commit_span(dst ,n); +} +#+END_SRC + +This avoids looping through `read`/`write` per cell and reduces dispatch overhead. + +* 6. Optional Implementation and Capability Flag + +Not all TM types can support spans. We can: + +- Add a `supports_span` method to the FG table +- Or define a `TM·Capability` bitfield: + +#+BEGIN_SRC c +typedef enum{ + TM·Caps·none = 0, + TM·Caps·span = 1 << 0 +} TM·Caps; +#+END_SRC + +* 7. Summary + +Bulk cell access enhances TM's ability to support: +- Efficient copy +- Block-based streaming +- Memory-mapped operations +- Potential SIMD and vectorization later + +By introducing the five methods above, TM becomes *not* diff --git a/document/unicode_character_use.org b/document/unicode_character_use.org new file mode 100644 index 0000000..dbc9361 --- /dev/null +++ b/document/unicode_character_use.org @@ -0,0 +1,20 @@ +#+TITLE: Unicode Character Use +#+AUTHOR: RT C Documentation + +The following characters are used: + +🖉 - The pencil suffix is placed on the end of directory or file names. It indicates that + the contents of the directory contains authored files, or in the case of the suffix on the end of a file name, that the specific file is authored. + + Authored files should not be deleted by scripts. The command `rm_na` will not delete + authored files, and it is used in scripts. It can be found in the RT-project-share project. + +· - The center dot is a proposed namespace sepearator for C. Currently it is used ad + hoc as the prefix portion of identifiers. There is some support in Python scripts. + +M - This is used to name function dictionary type. Function dictionaries are struct types + full of functions, and act as interfaces. + +m - A common name or prefix for an instance of a function dictionary type. This follows + the convention that type names are PascalCase, and instance names are snake_case. + diff --git "a/document\360\237\226\211/#Model.org#" "b/document\360\237\226\211/#Model.org#" deleted file mode 100644 index 83b69b5..0000000 --- "a/document\360\237\226\211/#Model.org#" +++ /dev/null @@ -1,216 +0,0 @@ -#+TITLE: Model -#+AUTHOR: Thomas -#+STARTUP: content - -* Tableau - -A Tableau is a type definition for a work area, typically implemented as a typedef struct in C. - -An instance of a Tableau is a tableau. There can be many instances of a given Tableau. - -There are multiple kinds of Tableau: - -- interface (also called a Face) -- state - -* ActionTable - - -An action is a function that operates on a tableau. - -Each action is an instance of an Action. An Action is a typedef for a function pointer. - -An ActionTable is a typedef of a struct, and instance of is said to be an action_table. -A given ActionTable can - -An instance of an ActionTable is an action_table. There can be many isntances of a given ActionTable. - -Each function in an action_table is an action. - - -* Model - -A Model is a TableauFace, a TableauState, and an ActionTable. - -An instance of a Model is a model. - - -* Status bits or continuations? - -The problem I found with continuations is that when the library is -limited to a single status function for a model, there will necessarily -be many continuations from the status function, one for each shade of meaning that it can discern. To endow it with fewer would limit its usefulness for some scenario, perhaps rare, but still supported. - -In addition, not all status's are independent. Thus there must be a priority scheme and then a choice of continuation, but the status function might not know the caller's -priorities. An alternative would be to take both continuations and break into multithreaded execuation. However, many programs are designed to be single threaded. - -When status is used as an argument guard this often comes down to, "Is the passed in -status baring model operable or not?" Thus the tableau for the many-continuations status function will have many duplicate next pointers. - -If rather than returning continuations, a highly discerning status function were to return status bits, The caller could mask the bits and then chose among continuations. In the cause of an argument guard, choosing among two paths. - -It is also a little funny when using a status function as an argument guard that the guard continues into the very function it is guarding. The tableau facilitates this -design pattern in that the input operands need not be written again. Though this -requires managing the tableau for the model who's status is being checked. - -An alternative to using status bits is to have more than one status function. One implementation is to embed the many-continuations status function inside the few-continuations status function, to perform the mask, and then pick the continuation. This might be convenient function to have, but where a second status function really makes sense is where it reduces the amount of computation that need be done. - -* A Single Tableau per Model - -Inputs for actions are written to a tableau. A link currently holds an actions table pointer, and a tableau pointer, hence there is one tableau that holds both action inputs and model state variables. - -If this tableau is declared as part of the FACE then the user can access the model state variables. This would follow a philosophy of, "if they are useful, then so bit it"; however exposing state variables limits both the number of models that can be made that provide the user with the same interface, and limits what can be done with maintenance edits without risking breaking the user's code. Recall that Model is an abstract type, and there can be many implementations for said type, i.e. many models for a given Model. - -C does not allow for public and private sections of a struct, or we could make the state variables private. - -However, we can accomplish the same thing as public and private, perhaps in even a better way, by including the interface tableau in the full tableau, and have the code know it was given the full tableau: - -#+BEGIN_SRC c -typedef struct{ - ... -}X·TableaFace; - -// in the implementation - -typedef struct{ - X·TableaFace face; - ... -}X·Tablea; - -#+END_SRC - -The details of the TableauFace type are shown to the user. The actions are -declared to be given a TableauFace, so any directly calls will work. Inside each action the tableau is converted from TableauFace to Tableau. - -=> Core uses separate Face and State tableaux - -** Tableau structure - -The TableauFace has: -- all possible inputs -- results -- continuations - -Then the Tableau extension - -- state variables - - -* Continuation Link - -There are two dimensions of variation. 1) Multiple action_tables from a given ActionTable, and 2) multiple tableau from a given Tableau. - -Each action_table instance of a given ActionTable can have very different function implementations, as only the function type signatures are specified in the ActionTable definition. - -The interface tableau, TableauFace, is designed against the ActionTable. Both deal with the user's view of the Model. In contrast each state tableau, TableauState is designed against a specific action_table. - -Hence, for each ActionTable declaration there will be corresponding to a TableauFace declaration, unless by coincidence, an existing one can be recycled, though even then programmers would appreciate having matching names. This begs the question if the two structures can be combined into one. So doing would constrain our ability to make instances from them independently. - -A given action table can be used with multiple state tableaux. In other words, there can be multiple instances of the same type. - -Conversely a given tableau can be used with multiple action tables. This happens in -polymorphism, where a child tableau can be passed to a parent action. The child -parts are in an extended portion of the tableau, and thus not seen by the parent -action. - -In the one Tableau per model approach, each tableau instance is both state and inputs, hence each instance will have its own inputs. We would lose the ability to make independent state and interface instances. The interface tableau is playing the role -that is typically played by the stack frame. Hence there is a copy per call, now this the one tableau per model, there would be a copy per instance. If left independent, there would be as many or few copies as the user determines is necessary, with the network of interface tableaux being connected by pointers tending to look like a circuit. - -**proposal 1 - -Place an action_table pointer in each single tableau per model tableau, then there would be many copies of the action_table pointer, one per tableau. This is the virtual table pointer approach from C++ or the delegate pointer from JavaScript. - -With this approach the action table can be reached through the tableau, so only the tableau, or references to it, need to be passed around as an instance of the model. This is appealing. - -However, such a link to such a tableau is not sufficient for knowing which action on the action table should be called. Hence a link to such an overloaded tableau can not function as a continuation link. - -Suppose if instead of an action_table link, a function link were embedded in the tableau, perhaps as a first member. Then the first member could be called and given the tableau as its only argument. This could function as a link, but then the state of the model is owned by a single function call. This looks problematic. - -**proposal 2 - -A link is a two pointer bundle. The first pointer to an action table, the second to single tableau. Then there is a macro called `call` that is used for calling functions in the action table. ``call(extent ,&tape_tableau)` - -The problem here is that such a link can not appear as a continuation because the link itself does not say which action is being invoked. That information is in the call. - -Attempts to save this proposal by including a 'field pointer' in the link, that would be applied to the action table are rather awkward in C, though it can be done by creating an enumeration of the struct offsets, and using those tags. - -**proposal 3 - -A three pointer bundle, the first pointer to the function being called, the second pointer to an interface tableau, the third pointer to the state tableau shared by the functions in the action_table the function comes from. - -In this approach there is not action_table pointer, though that is not a problem because if that information is needed it can be curried into the called function when it is written, though chances are if a given action needs to call another action function in the table, it will do so through a function pointer. The purposes of the action_table struct is then to document which actions share the corresponding tableau state, and to provide a namespace to put the actions in, which makes it conceptually nicer for the programmer. It would be even nicer if C supported Pascal's 'with' statement. - -Such a link could be reduced to two pointers if the single tableau variation is used. - -==> Core uses proposal 3 - - -* Mixing continuations with fall through execution. - -#+BEGIN_SRC c - Local void call(Core·Link *lnk){ - while(lnk) lnk = lnk->act(lnk); - } -#+END_SRC - -This implementation of call falls through when a null `lnk` pointer is returned. However the caller can not know anything about the status of the call. - -**proposal 1 - -Each continuation function that can return a NULL link, where the caller wants to know the status, also sets a `status` value at the top of the base tableau, that all FACE tableau's extend from. - -Disadvantage, all code must set status, so why have continuations? The optimizer will drop unused status setting code, so perhaps this is not serious. Though, on the other hand, for Local functions would the optimizer skip the status return and condition testing, and put the continuation in - thus making status setting the way to go as it must be coded anyway? - - -**proposal 2 - -Have actions that set status, link to them when status is desired. - -Actually we need default continuations anyway. In many cases these could -be generic. Argument guard continuations could be 'good' or 'bad'. - -=> Core uses option 2 - -* Continuations and linking - -**proposal 1 - -Put continuations on the interface tableau. The reasoning is that the programmer will want to set them, but actually this is not a general programming task. Rather it occurs up front as part of a 'wiring' phase, and is then typically it is not done again. - -Consider this example. - -#+BEGIN_SRC c - typedef struct{ - Core·Tape·Tableau·Face tape_tableau; - Core·Area *area; - void *position_left; - void *position_right; - AU *pt0; - AU *pt1 - Core·Area *a; - Core·Area *b; - bool q; // predicate -> q - Core·Link next; - }Core·Area·Tableau·Face; -#+END_SRC - -The idea is that there is one interface tableau used for all of the Area·Tableau actions, but it has a link field. Normally while the linked together functions are running, they can not set the 'next' link, as that information comes from a higher level. For example, after `encloses_pt_q` runs, it has no idea as to where the programmer wants control to flow next. - -**proposal 2 - -Add a fourth pointer to a link. This points to the continuations block. - -#+BEGIN_SRC c - typedef struct{ - Core·Tableau *face; - Core·Tableau *state; - Core·ActionTable *action; - Core·NextTable *next_table; - }Core·Link; -#+END_SRC - -We may then describe the program flow network as a series of next_tables, and then view the program as traversing a graph. - -In database representation a set of nodes, and the dual graph is specified as a bridge table. It is more efficient when traversing a graph, to keep make the neighbor list a property of the node. Thus, "Link" can be seen as a node with a neighbor list. - -=> Core uses option 2 diff --git "a/document\360\237\226\211/#temp.txt#" "b/document\360\237\226\211/#temp.txt#" deleted file mode 100644 index 3648a70..0000000 --- "a/document\360\237\226\211/#temp.txt#" +++ /dev/null @@ -1,93 +0,0 @@ -#+TITLE: TM Bulk Methods Using Area and Extent -#+AUTHOR: Sorein -#+DATE: 2025-04-25 - -* 1. Motivation: Copying Over Areas, Not Just Cells - -In TTCA, a **cell** is the basic unit of memory or tape, and a **Tape Machine (TM)** traverses such cells with a movable head. - -For high-throughput operations like `Copy`, operating on one cell at a time is inefficient. Instead, we want to operate over an **area**: a concrete, contiguous **sequence of cells**, defined by: - -- A **starting address** (typically the current head position) -- An **extent** — the **inclusive upper bound** of the area - -This gives the TM enough structure to reason about **bulk memory access** safely and efficiently. - -TTCA terminology distinguishes: -- **Area**: A sequence of cells between a starting point and an extent. -- **Extent**: The highest address within that area. -- **Distance**: The difference between the head and the extent (extent − head), used internally but not exposed as API input. - -We avoid using “length” as it is ambiguous and may overflow (`distance + 1`). - -* 2. Proposed TM Methods for Bulk Area Access - -Each TM instantiated over a Cell Value Type (CVT) can optionally support the following methods: - -#+BEGIN_SRC c -bool TM·AU·can_area(TM·AU tm ,uintptr_t extent); -AU const* TM·AU·peek_area(TM·AU tm ,uintptr_t extent); -AU* TM·AU·claim_area(TM·AU tm ,uintptr_t extent); -void TM·AU·commit_area(TM·AU tm ,uintptr_t extent); -uintptr_t TM·AU·extent_right(TM·AU tm); -#+END_SRC - -* 3. Method Semantics - -| Method | Meaning | -|-------------------------+-------------------------------------------------------------------------| -| `can_area(extent)` | True if the tape has a contiguous area from head up to this extent | -| `peek_area(extent)` | Returns a const pointer to the area [head … extent], or NULL | -| `claim_area(extent)` | Returns a writable pointer to the area [head … extent], or NULL | -| `commit_area(extent)` | Advances the head from current position to `extent` (inclusive) | -| `extent_right()` | Returns the extent (inclusive upper bound) of the tape | - -All returned areas are assumed to be **concrete**—that is, the TM guarantees: -- All cells in the area are physically allocated -- Their memory layout is contiguous -- They can be safely accessed as an array of CVT values - -If these conditions are not met (e.g. for cyclic or segmented tapes), the TM returns `false` or `NULL`. - -* 4. Area-Based Copy Example - -Using these methods, an efficient `Copy` routine becomes: - -#+BEGIN_SRC c -while( TM·AU·can_area(src ,e) && TM·AU·can_area(dst ,e) ){ - AU const* from = TM·AU·peek_area(src ,e); - AU* to = TM·AU·claim_area(dst ,e); - uintptr_t count = e - src_index + 1; - memcpy(to ,from ,count * sizeof(AU)); - TM·AU·commit_area(src ,e); - TM·AU·commit_area(dst ,e); -} -#+END_SRC - -Note: -- `e` is the intended extent (inclusive). -- `count = extent − head + 1` is used internally, but not exposed as "length". - -* 5. Capability Declaration - -Not all TMs support contiguous areas. To indicate whether a TM supports these methods, we may define: - -#+BEGIN_SRC c -typedef enum{ - TM·Caps·none = 0, - TM·Caps·area = 1 << 0 -} TM·Caps; -#+END_SRC - -This allows dispatchers to check if area-based methods are available for a given tape. - -* 6. Summary - -- We operate on **areas**, defined as `[head … extent]`, where `extent` is inclusive. -- We avoid using "length" in API design, since it implies `distance + 1`, which may overflow. -- **Area methods** allow batch reading or writing with fewer dispatches and better memory performance. -- These methods align TM with TTCA's formal model, supporting structured, efficient, and correct stream operations. - -This sets the foundation for writing `Copy`, `Map`, and other stream-based transformations using TMs as high-level iterators over cell areas. - -Would you like a matching `.org` draft for the FACE section of `Copy.lib.c`, now assuming the availability of these `area` methods? diff --git "a/document\360\237\226\211/.githolder" "b/document\360\237\226\211/.githolder" deleted file mode 100644 index e69de29..0000000 diff --git "a/document\360\237\226\211/Abstracting_Type_in_C.org" "b/document\360\237\226\211/Abstracting_Type_in_C.org" deleted file mode 100644 index 17b5ec9..0000000 --- "a/document\360\237\226\211/Abstracting_Type_in_C.org" +++ /dev/null @@ -1,564 +0,0 @@ -#+TITLE: Abstracting Type in C -#+AUTHOR: Thomas - -* Introduction - -Type abstraction is a fundamental challenge in C programming. Unlike object-oriented languages that provide built-in mechanisms for polymorphism, C requires explicit design patterns to achieve similar flexibility. This document explores various approaches to implementing type abstraction in C, using a tape machine (TM) as a concrete example. - -The core problem we're addressing is how to write generic code that can operate on different implementations of the same abstract interface. Specifically, we want to create functions that can work with any tape machine implementation without knowing the implementation details. This separation of interface from implementation facilitates creating modular, maintainable code in C. - -* Namespaces in C - -C does not have built-in namespace support like C++ or other modern languages. However, we can simulate namespaces using naming conventions. We use the middle dot character (·) as a namespace separator to organize identifiers into logical groups. - -** The middle dot convention - -The middle dot (·) in identifiers like `TM·Array` or `TM·Function·fg` is not a special operator in C. It is literally part of the identifier name. This convention creates a visual hierarchy that mimics namespaces while remaining valid C code. - -Example: -#+BEGIN_SRC c -TM·x // variable x -TM·Array·i // variable i -#+END_SRC -In the first example `x` is a variable in the TM namespace. TM stands for Tape Machine. In the second example, `Array` is a namespace inside of the `TM` namespace, and `i` is a variable in the `Array` namespace. - -In general, in our shop, types and namespaces are written in PascalCase. Variable and function names are written in snake_case. When proper nouns, types, or namespacess, are represented in variable or function names, they maintain their capitalization, though appear with underscores. - -#+BEGIN_SRC c -char *person_Thomas = "Thomas"; -#+END_SRC - -** Comparison with C++ Namespaces - -Unlike C++ namespaces, our convention: -1. Does not provide actual scope isolation -2. Cannot be opened with `using` directives -3. Is purely a naming convention, not a language feature - -Despite these limitations, this convention provides many of the organizational benefits of true namespaces while remaining compatible with standard C. - -* Implementing Templates in C - -C lacks built-in support for templates or generics, unlike C++ or modern languages like Java or Rust. However, we can implement template-like functionality using the C preprocessor. This section explains the template system used throughout this document. - -** The center dot '·' Macro System - -The cpp macro `·` is used for putting identifiers into a namespace. Consider these variables within a namespace. - -#+BEGIN_SRC c -TM·x // variable x in namespace TM -TM·Array·i // variable i in namespace TM·Array -#+END_SRC - - -,#+BEGIN_SRC c -·(TM ,x) // variable x in namespace TM -·(TM·Array ,i) // variable i in namespace TM·Array -#+END_SRC - -The reason the macro is needed is that cpp will not replace a macro that is embedded in an identifier. With this macro we can do the following: - -#+BEGIN_SRC c - #define CVT uint32_t - CVT i; // -> uint32_t i - typedef struct ·(TM ,CVT) // -> typedef struct TM·uint32_t - #undef CVT - #define CVT string - typedef string char *; - CVT ch; // -> string ch; - typedef struct ·(TM ,CVT) // -> typedef struct TM·string -#+END_SRC - -This allows us to create type and function names that are specialized for specific types, while maintaining a consistent naming convention. - -*** Implementation Details - -The · macro was initially defined for two operands, as shown below, though now it will take between zero and ten operands. With zero operands it expands to nothing, with one it echos the operand with no center dots, with more than that the operands are appended with a prior center dot. - -#+BEGIN_SRC c -#define _·2(a, b) a##·##b -#define ·2(a, b) _·2(a, b) -#+END_SRC - -** CVT: Cell Value Type - -Throughout our tape machine implementation, we use CVT (Cell Value Type) as a template parameter. This represents the type of data stored in each cell of the tape. - -The implementation uses conditional compilation to handle different CVT values: - -#+BEGIN_SRC c -#ifndef CVT - // Code for generic, non-specialized case -#endif - -#ifdef CVT - // Code specialized for a specific CVT -#endif -#+END_SRC - -When using the library, you include it multiple times with different CVT definitions: - -#+BEGIN_SRC c -// First include with CVT undefined for base definitions -#include "TM.lib.c" - -// Then include with CVT defined for each type specialization -#define CVT int -#include "TM.lib.c" -#undef CVT - -#define CVT float -#include "TM.lib.c" -#undef CVT -#+END_SRC - -* Tableau and FG Tables - -Two key concepts in our type abstraction approach are the "Tableau" and "Function Given (FG) Table." - -** Tableau - -A "Tableau" is our term for a data structure that holds the state of a particular instance. In the context of our tape machine example: - -1. **Definition**: A tableau is a struct that contains all the state variables needed for a specific implementation of an abstract interface. - -2. **Purpose**: The tableau serves as a shared workspace where functions can read and write state information. Think of it as a blackboard where functions can leave "notes" for each other. - -3. **Implementation-specific**: Each implementation of an abstract interface will have its own tableau structure with different fields appropriate to that implementation. - -For example, the tableau for an array-based tape machine might look like: - -#+BEGIN_SRC c -struct { - CVT *hd; // Current head position - CVT *position; // Base position for the tape (leftmost cell) - ·(extent_t, CVT) extent; // Largest index that can be used for accessing the tape -} ·(TM·Array, CVT); -#+END_SRC - -Notice this struct is templated on `CVT`. Suppose it were in the file `tape.lib.c`, then: - -#+BEGIN_SRC c -#define CVT uint8_t -#include `tape.lib.c` -typedef stirng char *; -#udef CVT -#define CVT string -#include `tape.lib.c` -#+END_SRC - -This will create two versions of said `struct` tableau with two different CVT types. - -** Function Given (FG) Tables - -The "Function Given" (FG) table is a collection of function pointers that implement operations on a specific tableau type. - -1. **Definition**: An FG table is a struct containing function pointers that all take a tableau as an argument (hence "Function Given"). - -2. **Purpose**: FG tables allow for polymorphic behavior in C by providing different implementations of the same interface. - -3. **Structure**: Each function in the FG table takes a pointer to a tableau as an argument, allowing it to access and modify the state. - -A simplified example of an FG table for our tape machine might look like: - -#+BEGIN_SRC c -typedef struct { - TM·Tape·Topo (*Tape·topo)(TM *tm); - bool (*Tape·bounded)(TM *tm); - TM·Head·Status (*Head·status)(TM *tm); - Core·Status (*mount)(TM *tm); - void (*step)(TM *tm); - void (*rewind)(TM *tm); - // ... other functions -} TM·FG; -#+END_SRC - -When specialized for a specific cell value type (CVT), we might then have: - -#+BEGIN_SRC c -typedef struct { - TM·FG *fg; // Base function table - ·(extent_t, CVT) (*extent)(TM *tm); - CVT (*read)(TM *tm); - void (*write)(TM *tm, CVT *remote_pt); -} ·(TM, CVT)·FG; -#+END_SRC - -** The Relationship Between Tableaux and FG Tables - -The tableau and FG table work together to implement polymorphism: - -1. Each implementation provides its own tableau type and instance of an FG table. -2. The first field of a tableau is typically a pointer to its corresponding FG table. (When following the 'vtable' method.) -3. Functions in the FG table operate on the tableau, reading and writing its state. -4. Client code can work with any implementation by using the functions in the FG table without knowing the details of the tableau structure. - -This pattern allows us to achieve polymorphic behavior in C while maintaining type safety and avoiding the overhead of dynamic dispatch mechanisms like those used in object-oriented languages. - -** Template-Based Type Generation - -The template system generates several types of identifiers: - -1. **Type names**: `·(TM, CVT)` becomes `TM·int` when CVT is defined as `int` -2. **Function names**: `·(TM·Array, CVT)·init_pe` can become `TM·Array·int·init_pe` -3. **Variable names**: `·(extent_t, CVT)` can become `extent_t·int` - -** Function Given (FG) Tables - -A key part of our implementation is the Function Given (FG) table pattern. Each implementation of the tape machine provides an FG table containing function pointers for its operations. - -The FG tables are specialized based on the CVT: - -#+BEGIN_SRC c -typedef struct { - TM·FG *fg; // Base function table - ·(extent_t, CVT) (*extent)(TM *tm); - CVT (*read)(TM *tm); - void (*write)(TM *tm, CVT *remote_pt); -} ·(TM, CVT)·FG; -#+END_SRC - -This allows for type-safe operations while maintaining a consistent interface. - -** Benefits of This Approach - -1. **Type safety**: The compiler checks that the correct types are used with each specialized function -2. **Code reuse**: Common functionality is defined once and specialized for different types -3. **Consistent naming**: The · macro ensures a consistent naming convention -4. **Modularity**: Different implementations can share the same interface - -** Limitations - -1. **Verbosity**: More verbose than native templates in C++ -2. **Complexity**: Requires understanding of preprocessor macros and conditional compilation -3. **Debugging**: Preprocessor-generated code can be harder to debug -4. **Limited IDE support**: Most IDEs don't understand this template system for code completion - -Despite these limitations, this approach provides a powerful way to implement generic, type-safe code in C without resorting to void pointers or code duplication. - -* Proposed approaches for generalizing type in C - -These are some of the approaches what were considered, or in some cases tried. - -** Using an TM FG table instance as an instance of 'TM type' - -1. Suppose we have a generic TM FG table with the declared functions constituting the architecture (user's view, interface) of a tape machine. - -2. Instances of this TM FG table represent different implementations of the architecture. For example, TM·Array·fg for a TM implemented as an array, and TM·Function·fg for a function implementation (similar to the Natural_Number in the Java implementation). - -3. Suppose we use an instance of a FG table to be the type for a tape machine. - -4. Now suppose we have a function called `map` that is given two Tape Machine arguments, say TM_read, and TM_write, as well as a function to map. - - The `map` only refers to the interfaces for the tape machines, and is agnostic as to how they are implemented. Hence, it works out fine that it is given two instances of the FG type. It uses the dot access on these the two given fg tables to find by name the tape machine functions it wants to call. While doing so it calls whichever function that happens to be implemented on the given fg table. The declared type signature match, so it has no problem to call them. - - This achieves what we wanted: a map function that can use a tape machine and does not care what the implementation of that tape machine is. - - However, the TM functions that map calls require having the shared tableau as one of their arguments. Without this, the called function cannot know which machine is being operated on. - Furthermore, the tableau type must match the TM fg table type. - - So giving a function, such as `map`, an FG table instance alone is not sufficient. It must - also have the tableau that does with the FG instance. But where to put it? There can be many tableau for a given FG table, each representing an instance of a tape machine, so we can not attach the tableau to the FG table. - - In conclusion this method does not work. - - -** The TM tableau instance as an instance of 'TM type' - -1. As noted in the prior section, our example `map` function is given three arguments, namely, TM_read, a TM_write, and a function. For these first two - arguments it was found not to be sufficient to pass the instance fg tables. Suppose that instead we make TM_read and TM_write the relative tableau. - -2. Now we have the opposite problem from before. We have the tableau for the function tables, but we do not have the function tables that are to be used with them. If we make the function tables global, then `map` will have to decide somehow which one to call, and make this decision at run time, as it can process instances of many types. In C this can not - be done from the type signature of the instance, because it is not available at run time. - -3. One solution is to keep the specific type on the tableau, and then have multiple `match functions` one per implementation (and per CVT template value), and then call the map function that goes with the tableau. The programmer picks the matching one, and the compiler verifies the types match at compile time. - -4. This approach works, but we duplicate the map code many times just to get the function type signatures to match the tableau type with the fg table used. - -** Using both the TM tableau instance, and the corresponding TM FG table instance - -1. Say we have one generic `map` that takes 5 arguments: TM_read (an tape machine tableau), TM_read_fg, a TM_write (a tape machine tableau), and TM_write_fg, and of course, all the a pointer to the function that map is to apply. - -2. The instance parameters must be declared `void *` to prevent argument checking on them; otherwise, it will be necessary to implement many map functions for each instance type combination. - -3. This works, though we have no way to know if the type of the given tableau goes with the type of the fg table, for each of the read tape machine and write tape machine. - -4. We could create many wrapper functions to accomplish the argument type checks, then call a central map function with `void *` instance data pointers, and with any luck, the optimizer would make this extra layer go away, so it would not be a run time performance drag. Still, by this method map has 5 arguments instead of the three that are natural for the problem. - -5. So this approach, with the delegation wrappers, does everything we want, but it feels unsatisfactory due to having to provide arguments in pairs. - -** Tableau instances carries pointer to the matching FG table instance - -1. Each fg table is full of functions that are given a tableau of a specific type. Hence, it is practical to add a field to the tableau such that when an instance is made of the tableau, that this field is initialized with a pointer to its matching fg table. - -2. In practice then, the function that allocates a tape machine will actually be allocating a tableau of the correct type. This tableau would then be allocated on a stack frame or in a heap block. Following the allocation a type specific init function is called, and this function sets the fg pointer table, along with other variable initialization. - -3. Then a call to a function on the fg table looks like this: - - #+BEGIN_SRC c - - typedef struct{ - TM·FG fg; - } TM; - - typedef struct{ - TM tm; - uint8_t *hd; - uint8_t *position; - extent_t extent; - } TM·Array; - - ... - - TM *init(TM·Array *tm ,position ,extent); - - ... - - TM *tm_read; - TM·Array *tma; - - tm_read = *init(tma ,position ,extent); - - ... - - void map(TM *tm_read ...){ - ... - tm_read->fg->step(tm_read); - } - #+END_SRC - - Here `tma` has been allocated. `tm` is has not been allocated, but rather is a generic stand in for any tape machine tableau. - - `map` is given `TM *` type, so said tape machine could be of any implementation. All that matters is that the `TM` interface has been implemented. - -4. It works, and it is a tried and true method. It is a little funny that the programmer uses `tm_read` twice in the call, but at least the tm_read argument will be type checked. - -** Using a pointer pair as the `TM type'. - -1. Instead of the instance data being called the 'TM type', a pair is the 'TM type'. - The first member of the pair points to a tableau instance, the second to a matching FG - table instance. - -2. With this approach, generic TM functions each accept a pair as a TM argument. - -3. This approach encapsulates the same information as the vtable approach but keeps the relationship explicit. Note, if there is a one-to-one correspondence between tableaux and pairs, then the memory footprint is larger by one pointer per instance. - -4. An example - - #+BEGIN_SRC c - // Define the pair structure - typedef struct { - TM·Tableau *t; // Points to the implementation-specific tableau - TM·FG *fg; // Points to the corresponding FG table - } TM; - - // Implementation-specific tableau - typedef struct { - uint8_t *hd; - uint8_t *position; - extent_t extent; - } TM·Tableau·Array; - - // Function to initialize a pair - TM init_pair(TM·Tableau·Array *tma, uint8_t *position, extent_t extent) { - TM pair; - // Initialize the tableau - tma->hd = position; - tma->position = position; - tma->extent = extent; - - // Set up the pair - pair.t = (TM·Tableau *)tma; - pair.fg = &TM·Array·fg; - - return pair; - } - - // Using the pair in a function - void map(TM tm_read, ...) { - ... - - // Call functions through the pair - tm_read.fg->rewind(tm_read.t); - ... - - } - #+END_SRC - -5. Note that when using a pointer pair, the `init` function will be given the same arguments as for the vtable approach, but it will return the pair instead of a more generic pointer to the tableau. - -6. With this approach a pair of pointers is passed around instead of a single pointer. Though it might be more optimizer friendly, as it is easier to drop structures, such as the pair, than it is to rearrange structures as would have to be done to unpack the vtable pointer from the tableau structure. - -** Using a dispatch function as the `TM type'. - -1. In this case, a pointer to a function is the 'TM type'. There is an enum that gives numeric tags to each of the functions in the FG struct instance. - -2. The tag for the desired fg function to be called is passed as the first argument to the dispatch function, and the remaining arguments are for the fg function. - -3. The dispatch function has the instance data and fg table pointer curried into it, so it then calls the correct fg function while providing it with the correct instance data. - -4. In C, it is not immediately obvious how to create a function on the fly each time an - instance is created to curry the instance data into it, and then later how to call - the newly created function. - -** Dispatch function and Self-identified Tableau type. - -1. With this method, an extra field is added to each tableau instance to identify its type. Then a globally available TM-specific dispatch function is called to run the desired fg function on the data. It is similar to the dispatch function from above, but the instance data is an additional argument. - -2. The dispatch function uses the type information to know which fg table to call. This type information could be a pointer to the appropriate fg table. - -3. This approach differs from the vtable method in that all the arguments are given to the one TM dispatch function, and it figures out how to do the dispatch. There is not a wrapper-per-function. - -** Which approach? - -We want to be able to declare an instance as a local variable, where it will end up being on the stack frame. We want to avoid heap allocation for performance reasons, but not exclude the use of heap memory. - -Dynamically created functions are out of the question. Dispatch approaches require the enum table to have tags. This is not a show-stopper. However, having one dispatch function means the argument types are not checked. That is a problem. - -Doubled-up arguments (one for the instance, the other for the table) either require wrappers or do not check that an instance really goes with the data. Besides, this approach requires a lot of typing. - -The pointer pair approach becomes a maintenance problem, unless it is passed by value. When passed by value. When passed by value it is two pointers being copied instead of one. There is no corresponding savings on fewer levels of indirection on lookup. It does achieve separation of concerns, and would facilitate using the same instance with multiple fg tables, i.e. multiple 'views', that that is not a feature that is driving the decision process. - -So their are two practical approaches, the vtable, and the pointer pair. - -* Terminology - -** Model - -A 'model' consists of a Tableau definition, FG table definitions, and all of the type definitions that occur on the function signatures of those functions, all instances of the FG table, all while including the variations due to the template variables. This includes the function implementations, but does not include the values assigned to the tableaux. - -Going by this definition, it can be said that in the file TM.lib.c provides a Tape Machine model. - -** Architecture - -Architecture is the users view of the model. In the case of a software library, the user will be an application programmer. - -An architecture can also be a specification for which the model is an implementation. In which case, it says "The user must see this when using the model that is to be written." - -** FG table instances - -An FG table with template variabes, will expand out to one or more FG tables (without template variables), when those variables are bound to values. - -There can be multiple instances of an FG table. Each instance will consists of pointers to functions that have the type signature specified in the FG table. However, though all instances of the FG table share the same interface, their implementations can be completely different. - -Each template variable binding, and each FG table instance can have a different Tableau type as the given argument. For the Tape Machine, we give each tableau struct the name ·(TM·, CVT), where is the FG instance table type. For example, ·(TM·Array, CVT) is a struct of state variables for an Array implementation of the TM. - -------------------------------------------------------------------- - -* Hierarchy - -The TM model has functions that are independent of the CVT parameter. - - -** One for all FG table - -The "TM.lib.c" file defines an FG type called ·(TM, CVT)·FG. Note that CVT is a template -parameter. Hence, giving different CVT bindings, there will be different FG tables. - -For each ·(TM, CVT)·FG, there can be a number of ·(TM·, CVT)·fg instances. For -example, ·(TM·Array, CVT)·fg. Each of these is a parameterized table. - -A user has an fg table to call functions from. This is either passed in or, more -likely, found at global scope after including "TM.lib.c", and then including it again for -each value of the CVT variable to be used. - -For each implementation type, there is a struct defined called ·(TM·, CVT), -note the lack of further suffix. Instances of this type are said to be instances of the tape -machine. `FG` stands for `function given`, and what each said function is given is one or more arguments of the ·(TM·, CVT) type. - -When a user wants a tape machine, the user makes an instance of a ·(TM·, CVT). -This is then handed to a function called ·(TM·, CVT)·init(). The init function is given whatever parameters are needed for initializing the instance, and it returns a more generalized pointer of type `·(TM, CVT) *`. - -After initialization, the ·(TM·, CVT) instance will have a first field value that points to the ·(TM·, CVT)·fg table. However, the pointer to this instance will be of the type returned by init, which is `·(TM, CVT) *` (notice it lost the implementation). This more generic pointer can now be used with the generic instance of the -·(TM, CVT)·FG table, ·(TM, CVT)·fg, which holds wrapper functions that make use of the -first field value to find the real fg table and to call those functions. - -Hence, after the user calls the correct init for the specific instance made, the resulting pointer points to the same type object independent of the implementation of the functions. Thus, code written to manipulate TMs can be written in a manner that is agnostic to the implementation of those TMs. - -When a function is called, say ·(TM, CVT)·fg.step(tm), it is passed the generic type `·(TM, CVT) *`, tm. This will call the step wrapper function, which will in turn pass the same arguments (in this case, only `tm`) to the step function found in the fg table pointed to by the first member of the tm struct. - -** Separate FG tables - -In the flat fg table approach described in the prior section, each wrapper function table of the form ·(TM, CVT)·fg, obtained by setting the CVT template to a type value, will have a full set of wrapper function pointers. When a wrapper function is the same independent of the CVT variable, it still has a pointer copied into each fg table. Thus, there will be a lot of redundancy in the tables if many functions are not CVT-specific. - -For the layered fg table, there are separate wrapper function tables for the wrappers that are independent of CVT and those that are CVT-differentiated. The user then calls functions from the CVT-independent table when invoking those functions and from the CVT-differentiated functions table when calling those. So, for example, the user would call TM·fg.step(tm) to do a step, as that is CVT-independent, but call ·(TM, CVT)·fg.read(tm) to do a read, as the read value is CVT-differentiated. - -** Direct access through instance field (Orrin suggestion) - -Instead of calling fg functions through a globally visible table such as: - -#+BEGIN_SRC c -fg->step(tm); // Wrapper style -#+END_SRC - -where fg is of type ·(TM, CVT)·FG and calls to it require globally accessible wrapper functions, - -we can use the instance's first field directly: - -#+BEGIN_SRC c -tm->fg->step(tm); -#+END_SRC - -Here, tm is a ·(TM, CVT) * — the generic type returned by init — and fg is the first field of the instance pointing to the correct FG table. - -This style removes the need for wrapper functions entirely. Each TM implementation embeds its corresponding FG table pointer directly in the instance. Thus, no global wrapper needs to be referenced, and function type-checking is preserved at compile time. - -If there are CVT-independent functions, we can use a layered FG table. Each CVT-specific FG table includes a pointer to a base table: - -#+BEGIN_SRC c -tm->fg->base->step(tm); // Access shared, CVT-independent function -tm->fg->read(tm); // Access CVT-specific function -#+END_SRC - -This structure mimics prototype delegation in JavaScript, except we resolve the chain explicitly with types, not dynamic name resolution. - -The benefit of this approach is that the user only needs to have the instance in scope — no global FG table declarations. All function dispatch is local and type-safe. - -The only remaining user burden is knowing whether a function is CVT-specific or not. This is made obvious by whether the function appears in the base or CVT-differentiated FG struct, and the compiler will catch mismatches. - -(Contribution by Orrin — co-author) - -* Observations - -C does not have automatic conversion of a child type to its parent; instead, it will give a type mismatch error. - -The vtable pattern with separate tables will have a CVT-differentiated fg table pointer on the tableau. Without the function wrappers, a call can occur like this: - -#+BEGIN_SRC c -tm->fg->step(tm) -#+END_SRC - -Or even with the wrappers and a globally available fg table: - -#+BEGIN_SRC c -fg->step(tm) -#+END_SRC - -In both of these, `step` will be the CVT-differentiated version of step, so types will match, and these calls work. - -However, things change when we want to call the non-CVT-differentiated shared table: - -#+BEGIN_SRC c -tm->TM·fg->mount(tm) -#+END_SRC - -Due to `mount` being in the shared fg table that has type `TM·fg` where it expects to be given arguments of type `TM *`, and having type `TM·`, there will be a type mismatch -error on the call. The programmer will be compelled to fix this with a cast: - -#+BEGIN_SRC c -tm->TM·fg->mount((TM *)tm) -#+END_SRC - -Requiring the programmer to defeat the type system by habit is not a good approach. - -So the one solution that does work is the one big table per type. All functions will then have correct signatures in the FG declaration. In the implementation, the more generic functions can be cast when assigned directly to the fg table function pointers, or wrappers that delegate can be written and assigned to the fg table function pointers. - -* Conclusion - -After examining various approaches to type abstraction in C, the vtable pattern emerges as the most practical solution for our tape machine implementation. While it has some overhead in terms of memory usage, it provides the best balance of type safety, ease of use, and performance. - -The direct access through instance field approach suggested by Orrin offers an elegant alternative that eliminates the need for wrapper functions while maintaining type safety. This approach is particularly appealing for its simplicity and the fact that it keeps all the necessary information localized to the instance. - -For projects where performance is critical, the "one big table per type" approach may be the most efficient, as it avoids the need for type casting while still providing a clean interface. - -Ultimately, the choice of approach depends on the specific requirements of the project, but the vtable pattern and its variations provide a solid foundation for type abstraction in C programming. diff --git "a/document\360\237\226\211/Inclusive_Exclusive_interval_bounds.org" "b/document\360\237\226\211/Inclusive_Exclusive_interval_bounds.org" deleted file mode 100644 index f5dfb84..0000000 --- "a/document\360\237\226\211/Inclusive_Exclusive_interval_bounds.org" +++ /dev/null @@ -1,94 +0,0 @@ -#+TITLE: Exclusive vs. Inclusive Bounds -#+AUTHOR: Thomas & Eidolon -#+DATE: 2025-02-28 -#+OPTIONS: toc:nil - -* Introduction -The discussion explores the advantages and drawbacks of exclusive and inclusive bounds in programming, with a particular focus on C-style memory intervals. Exclusive upper bounds have been a longstanding convention in C and derived languages but have also led to significant issues, including microprocessor bugs. The alternative, inclusive bounds, offers certain advantages, particularly in preventing out-of-bounds memory access. - -* Exclusive Bounds in C -Exclusive bounds mean that the upper bound points to one element past the actual interval. This approach aligns with C's idioms and iteration patterns: - -- A pointer iterated through memory will naturally stop when it equals the upper bound. -- The memory length itself matches the upper bound minus the lower bound. - -However, this has caused notable problems: -- The upper bound address may not be representable within the allocated memory range. -- In hardware, this can lead to prefetching errors, page faults, and potential security issues due to speculative execution. -- In software, off-by-one errors frequently arise when handling array lengths and loops. - -A personal anecdote from AMD illustrates the severity of this issue: speculative execution could cause processors to prefetch addresses that lay outside valid memory pages, leading to processor bugs that were not initially acknowledged. - -* Inclusive Bounds: A Cleaner Approach? -Inclusive bounds, in contrast, place the upper bound within the interval, reducing the risk of out-of-bounds memory accesses. Some advantages include: - -- The highest valid index remains within the range of representable values. -- Iteration tests for `>` rather than `==`, which is often more intuitive. -- Eliminates off-by-one errors associated with exclusive bounds. - -This approach is used in some hardware and computational models, as detailed in TTCA​:contentReference[oaicite:0]{index=0}. The book advocates for extent-based indexing rather than length-based indexing to ensure safe iteration patterns. - -* The Boundary Issue in Inclusive Upper Bounds - -While inclusive bounds provide intuitive indexing and prevent off-by-one errors, they introduce a fundamental issue when dealing with **typed memory operations**, such as bulk copying or aligned processing. - -- A **pointer to the first byte** of an interval is **also a pointer to the first word**, making inclusive lower bounds type-agnostic. -- However, a **pointer to the last byte** is **not** a pointer to the last word—it is merely the last address in the range. -- In contrast, an **exclusive upper bound** remains type-agnostic, as it represents an address just past the valid range, which works independently of element size. - -### **Why This Matters for Bulk Operations** -Memory operations often process data in **word-sized chunks** for efficiency: -- Copying memory in **aligned 64-bit words** requires knowing where the last valid word begins. -- With **exclusive bounds**, this is straightforward: iteration stops at the upper bound. -- With **inclusive bounds**, adjustments (`-8` for 64-bit words) become necessary to avoid overstepping. - -### **Key Takeaways** -- **Inclusive lower bounds remain universally valid** and do not require type knowledge. -- **Inclusive upper bounds require type knowledge**, which can be inefficient or unsafe. -- **Exclusive upper bounds** naturally align with word-based processing, reducing extra adjustments. - -This suggests that **a hybrid approach**—inclusive lower bounds with exclusive upper bounds—may provide the best balance of **safety and efficiency**, particularly in systems with **low-level memory operations**. - -* Implementation Considerations -Converting from exclusive to inclusive bounds is not trivial, as many established languages and libraries assume exclusive bounds. Some challenges include: - -- Existing APIs and standard libraries expect exclusive bounds, requiring additional adjustments. -- Iteration logic must be adapted to use `<=` instead of `<` in many cases. -- Some optimizations, such as using pointer arithmetic with exclusive bounds, may require rethinking. - - -* Conclusion -The choice between exclusive and inclusive bounds is not merely a stylistic one but has real implications for safety, correctness, and performance. While exclusive bounds remain dominant in C-derived languages, inclusive bounds eliminate a class of potential errors and are often preferable when designing new architectures or computational models. - -For TTCA, inclusive bounds were chosen specifically to prevent the issues that arise from exclusive bounds​:contentReference[oaicite:1]{index=1}. Future discussions may explore the feasibility of transitioning software ecosystems toward inclusive bounds or at least providing safer abstractions to mitigate the risks of exclusive bounds. - -* References -- Thomas, *Tom's Turing Complete Computing Architecture (TTCA)*​:contentReference[oaicite:2]{index=2}. - ------------------------- -Here’s what stands out from this process: - -Inclusive lower bounds work cleanly - -The starting address is always valid, so there’s no need for adjustments. -This makes iteration straightforward without additional logic. -Inclusive upper bounds require adjustments in word-based operations - -A pointer to the last byte is not a pointer to the last word. -This forces explicit alignment corrections (& ~0x7 style masking). -These corrections introduce additional computation (-8, +1, conditionals). -Exclusive upper bounds simplify bulk memory operations - -If the loop simply runs while ptr < end, the word-aligned processing works naturally. -No need for extra adjustments before entering the bulk copy loop. -This aligns with how hardware and assembly-based operations work. -Hybrid Approach Might Be the Best Path - -Inclusive lower bounds keep indexing intuitive. -Exclusive upper bounds avoid unnecessary adjustments in word-based processing. -This mirrors how C and assembly tend to handle memory intervals (start inclusive, end exclusive). - ------------------------- -Inclusive upper bound made byte reverse copy simpler, as there was symetry in pointing -to the last byte of word to represent a word in reverse order, and pointing to the -the first byte to represent the word in forward order. diff --git "a/document\360\237\226\211/Model.org" "b/document\360\237\226\211/Model.org" deleted file mode 100644 index f6b700d..0000000 --- "a/document\360\237\226\211/Model.org" +++ /dev/null @@ -1,215 +0,0 @@ -#+TITLE: Model -#+AUTHOR: Thomas -#+STARTUP: content - -* Tableau - -A Tableau is a type definition for a work area, typically implemented as a typedef struct in C. - -An instance of a Tableau is a tableau. There can be many instances of a given Tableau. - -There are multiple kinds of Tableau: - -- interface (also called a Face) -- state - -* ActionTable - -An action is a function that operates on a tableau. - -Each action is an instance of an Action. An Action is a typedef for a function pointer. - -An ActionTable is a typedef of a struct, and instance of is said to be an action_table. -A given ActionTable can - -An instance of an ActionTable is an action_table. There can be many isntances of a given ActionTable. - -Each function in an action_table is an action. - - -* Model - -A Model is a TableauFace, a TableauState, and an ActionTable. - -An instance of a Model is a model. - - -* Status bits or continuations? - -The problem I found with continuations is that when the library is -limited to a single status function for a model, there will necessarily -be many continuations from the status function, one for each shade of meaning that it can discern. To endow it with fewer would limit its usefulness for some scenario, perhaps rare, but still supported. - -In addition, not all status's are independent. Thus there must be a priority scheme and then a choice of continuation, but the status function might not know the caller's -priorities. An alternative would be to take both continuations and break into multithreaded execuation. However, many programs are designed to be single threaded. - -When status is used as an argument guard this often comes down to, "Is the passed in -status baring model operable or not?" Thus the tableau for the many-continuations status function will have many duplicate next pointers. - -If rather than returning continuations, a highly discerning status function were to return status bits, The caller could mask the bits and then chose among continuations. In the cause of an argument guard, choosing among two paths. - -It is also a little funny when using a status function as an argument guard that the guard continues into the very function it is guarding. The tableau facilitates this -design pattern in that the input operands need not be written again. Though this -requires managing the tableau for the model who's status is being checked. - -An alternative to using status bits is to have more than one status function. One implementation is to embed the many-continuations status function inside the few-continuations status function, to perform the mask, and then pick the continuation. This might be convenient function to have, but where a second status function really makes sense is where it reduces the amount of computation that need be done. - -* A Single Tableau per Model - -Inputs for actions are written to a tableau. A link currently holds an actions table pointer, and a tableau pointer, hence there is one tableau that holds both action inputs and model state variables. - -If this tableau is declared as part of the FACE then the user can access the model state variables. This would follow a philosophy of, "if they are useful, then so bit it"; however exposing state variables limits both the number of models that can be made that provide the user with the same interface, and limits what can be done with maintenance edits without risking breaking the user's code. Recall that Model is an abstract type, and there can be many implementations for said type, i.e. many models for a given Model. - -C does not allow for public and private sections of a struct, or we could make the state variables private. - -However, we can accomplish the same thing as public and private, perhaps in even a better way, by including the interface tableau in the full tableau, and have the code know it was given the full tableau: - -#+BEGIN_SRC c -typedef struct{ - ... -}X·TableaFace; - -// in the implementation - -typedef struct{ - X·TableaFace face; - ... -}X·Tablea; - -#+END_SRC - -The details of the TableauFace type are shown to the user. The actions are -declared to be given a TableauFace, so any directly calls will work. Inside each action the tableau is converted from TableauFace to Tableau. - -=> Core uses separate Face and State tableaux - -** Tableau structure - -The TableauFace has: -- all possible inputs -- results -- continuations - -Then the Tableau extension - -- state variables - - -* Continuation Link - -There are two dimensions of variation. 1) Multiple action_tables from a given ActionTable, and 2) multiple tableau from a given Tableau. - -Each action_table instance of a given ActionTable can have very different function implementations, as only the function type signatures are specified in the ActionTable definition. - -The interface tableau, TableauFace, is designed against the ActionTable. Both deal with the user's view of the Model. In contrast each state tableau, TableauState is designed against a specific action_table. - -Hence, for each ActionTable declaration there will be corresponding to a TableauFace declaration, unless by coincidence, an existing one can be recycled, though even then programmers would appreciate having matching names. This begs the question if the two structures can be combined into one. So doing would constrain our ability to make instances from them independently. - -A given action table can be used with multiple state tableaux. In other words, there can be multiple instances of the same type. - -Conversely a given tableau can be used with multiple action tables. This happens in -polymorphism, where a child tableau can be passed to a parent action. The child -parts are in an extended portion of the tableau, and thus not seen by the parent -action. - -In the one Tableau per model approach, each tableau instance is both state and inputs, hence each instance will have its own inputs. We would lose the ability to make independent state and interface instances. The interface tableau is playing the role -that is typically played by the stack frame. Hence there is a copy per call, now this the one tableau per model, there would be a copy per instance. If left independent, there would be as many or few copies as the user determines is necessary, with the network of interface tableaux being connected by pointers tending to look like a circuit. - -**proposal 1 - -Place an action_table pointer in each single tableau per model tableau, then there would be many copies of the action_table pointer, one per tableau. This is the virtual table pointer approach from C++ or the delegate pointer from JavaScript. - -With this approach the action table can be reached through the tableau, so only the tableau, or references to it, need to be passed around as an instance of the model. This is appealing. - -However, such a link to such a tableau is not sufficient for knowing which action on the action table should be called. Hence a link to such an overloaded tableau can not function as a continuation link. - -Suppose if instead of an action_table link, a function link were embedded in the tableau, perhaps as a first member. Then the first member could be called and given the tableau as its only argument. This could function as a link, but then the state of the model is owned by a single function call. This looks problematic. - -**proposal 2 - -A link is a two pointer bundle. The first pointer to an action table, the second to single tableau. Then there is a macro called `call` that is used for calling functions in the action table. ``call(extent ,&tape_tableau)` - -The problem here is that such a link can not appear as a continuation because the link itself does not say which action is being invoked. That information is in the call. - -Attempts to save this proposal by including a 'field pointer' in the link, that would be applied to the action table are rather awkward in C, though it can be done by creating an enumeration of the struct offsets, and using those tags. - -**proposal 3 - -A three pointer bundle, the first pointer to the function being called, the second pointer to an interface tableau, the third pointer to the state tableau shared by the functions in the action_table the function comes from. - -In this approach there is not action_table pointer, though that is not a problem because if that information is needed it can be curried into the called function when it is written, though chances are if a given action needs to call another action function in the table, it will do so through a function pointer. The purposes of the action_table struct is then to document which actions share the corresponding tableau state, and to provide a namespace to put the actions in, which makes it conceptually nicer for the programmer. It would be even nicer if C supported Pascal's 'with' statement. - -Such a link could be reduced to two pointers if the single tableau variation is used. - -==> Core uses proposal 3 - - -* Mixing continuations with fall through execution. - -#+BEGIN_SRC c - Local void call(Core·Link *lnk){ - while(lnk) lnk = lnk->act(lnk); - } -#+END_SRC - -This implementation of call falls through when a null `lnk` pointer is returned. However the caller can not know anything about the status of the call. - -**proposal 1 - -Each continuation function that can return a NULL link, where the caller wants to know the status, also sets a `status` value at the top of the base tableau, that all FACE tableau's extend from. - -Disadvantage, all code must set status, so why have continuations? The optimizer will drop unused status setting code, so perhaps this is not serious. Though, on the other hand, for Local functions would the optimizer skip the status return and condition testing, and put the continuation in - thus making status setting the way to go as it must be coded anyway? - - -**proposal 2 - -Have actions that set status, link to them when status is desired. - -Actually we need default continuations anyway. In many cases these could -be generic. Argument guard continuations could be 'good' or 'bad'. - -=> Core uses option 2 - -* Continuations and linking - -**proposal 1 - -Put continuations on the interface tableau. The reasoning is that the programmer will want to set them, but actually this is not a general programming task. Rather it occurs up front as part of a 'wiring' phase, and is then typically it is not done again. - -Consider this example. - -#+BEGIN_SRC c - typedef struct{ - Core·Tape·Tableau·Face tape_tableau; - Core·Area *area; - void *position_left; - void *position_right; - AU *pt0; - AU *pt1 - Core·Area *a; - Core·Area *b; - bool q; // predicate -> q - Core·Link next; - }Core·Area·Tableau·Face; -#+END_SRC - -The idea is that there is one interface tableau used for all of the Area·Tableau actions, but it has a link field. Normally while the linked together functions are running, they can not set the 'next' link, as that information comes from a higher level. For example, after `encloses_pt_q` runs, it has no idea as to where the programmer wants control to flow next. - -**proposal 2 - -Add a fourth pointer to a link. This points to the continuations block. - -#+BEGIN_SRC c - typedef struct{ - Core·Tableau *face; - Core·Tableau *state; - Core·ActionTable *action; - Core·NextTable *next_table; - }Core·Link; -#+END_SRC - -We may then describe the program flow network as a series of next_tables, and then view the program as traversing a graph. - -In database representation a set of nodes, and the dual graph is specified as a bridge table. It is more efficient when traversing a graph, to keep make the neighbor list a property of the node. Thus, "Link" can be seen as a node with a neighbor list. - -=> Core uses option 2 diff --git "a/document\360\237\226\211/RT_C_namespace.org" "b/document\360\237\226\211/RT_C_namespace.org" deleted file mode 100644 index e4d353a..0000000 --- "a/document\360\237\226\211/RT_C_namespace.org" +++ /dev/null @@ -1,174 +0,0 @@ -#+TITLE: RT C Namespace Convention -#+AUTHOR: Sorein -#+DATE: 2025-04-25 - -* 1. Namespaces in RT C - -C has no formal namespace system, so RT C introduces a **middle-dot namespace convention** to provide **clarity, collision avoidance, and modular structure** in large, macro-heavy codebases. - -The `·` symbol (U+00B7, **middle dot**) is used as a visual and semantic scoping operator between **namespace components**, similar to how `::` is used in C++ or `.` in Java. - -This convention applies uniformly to: -- Function names -- Type names -- Structs -- Macros (especially templated forms) -- Dispatch tables - -Example: -#+BEGIN_SRC c -N32·allocate_array -Core·round_up -TM·AU·Array·init_pe -#+END_SRC - -Here, each `·` separates conceptual scopes: -- `TM·AU·Array·init_pe` means: `init_pe` function, inside `Array` implementation, for the `AU` cell type, inside the `TM` module. - -* 1.5 The Middle Dot: Syntactic Sugar and Token Trickery - -The character `·` (U+00B7, **middle dot**) is **not** special in the C language. To the C preprocessor and compiler, it's simply a valid identifier character—just like `A_Z` or `foo42`. - -That means: - -#+BEGIN_SRC c -TM·AU·Array·init_pe -#+END_SRC - -is **just one long identifier**. The compiler doesn't see it as hierarchical—only as a single symbol. The visual segmentation is entirely for the *reader's* benefit, not the *compiler's*. - -> For now, the middle dot is syntactic sugar. But someday, perhaps, a future C or C++ might embrace it as a real scoping operator. We prepare the ground. - -However, when we want to *construct* identifiers programmatically via macros, `·` by itself is not enough. **The C preprocessor does not treat `·` as an operator**, so it won't concatenate tokens with it unless we explicitly instruct it. - -To solve this, RT C defines the following macro in `cpp_ext.c`: - -#+BEGIN_SRC c -#define ·(A,B) A##·##B -#+END_SRC - -This turns: - -#+BEGIN_SRC c -·(TM,AU) → TM·AU -#+END_SRC - -And can be chained: - -#+BEGIN_SRC c -·(·(TM,AU),Array) → TM·AU·Array -#+END_SRC - -For convenience and clarity, template variable values must be defined *before* expansion. For instance: - -#+BEGIN_SRC c -#define _Box_T_ int -#define _TM·CVT_ AU -#+END_SRC - -When these are defined in this manner, the macro `·(...)` allows us to produce the following expansions: - -| Macro Invocation | Resulting Identifier | -|--------------------------------+-------------------------------| -| `·(Box_Box,_Box_T_)` | `Box_Box·int` | -| `·(Box_set,_Box_T_)` | `Box_set·int` | -| `·(TM,_TM·CVT_)` | `TM·AU` | -| `·(TM,_TM·CVT_,Array)` | `TM·AU·Array` | -| `·(TM,_TM·CVT_,Array,init_pe)` | `TM·AU·Array·init_pe` | - -This macro-based approach makes template expansion **predictable, readable, and modular**—while preserving the middle dot as a **structural visual** and a **join point** for layered namespaces. - -In summary: - -- As a **literal**, `·` is a harmless identifier character. -- As a **macro call**, `·(...)` is a *token concatenator* that inserts middle dots between parts. -- This duality is key to templating and namespacing in RT C. - -* 2. Purpose of the Middle Dot - -**The `·` is not just cosmetic**—it encodes structured meaning: - -| Position | Meaning | -|----------+----------------------------------| -| Leftmost | Module namespace (e.g. `TM`) | -| Middle | Type or submodule scoping | -| Rightmost| Symbol or function identifier | - -This gives the illusion of *semantic depth* within a flat C symbol space. It also facilitates: -- Greppable identifiers -- Predictable naming for macros, typedefs, and tables -- Avoidance of conflicts in shared headers - -* 3. Template Variable Convention: `_Var_` - -Template variables are identified with **leading and trailing underscores**, e.g. `_TM·CVT_`. These are used to parameterize includes and define generic logic. - -When a template is instantiated: -- The value of `_Var_` is set (e.g. `_TM·CVT_ = AU`) -- The file is included -- A guard macro (e.g. `SET__TM·AU`) is defined - -This ensures one instantiation per type per translation unit. - -Example: -#+BEGIN_SRC c -#define _TM·CVT_ AU -#include "TM.lib.c" -#define SET__TM·AU - -#define _TM·CVT_ Str -#include "TM.lib.c" -#define SET__TM·Str -#+END_SRC - -* 4. Guard Macros: SET__Module__Type - -To prevent multiple expansions of the same template with the same argument, we define a sentinel macro after inclusion: - -#+BEGIN_SRC c -#if !defined(SET__TM·AU) -#define SET__TM·AU -... -#endif -#+END_SRC - -These guards allow repeated template includes in a single TU, and avoid the fragile workaround of modifying headers manually. - -* 5. Practical Naming Examples - -| Symbol | Meaning | -|----------------------------------+---------------------------------------------------| -| `Core·FG` | Function dictionary for the Core module | -| `TM·AU·FG` | Function dictionary for TM with AU cell type | -| `TM·Str·Array·init_pe` | Init function for TM with Str cell type, Array impl | -| `SET__Binding__TM·AU` | One-time expansion guard for Binding of TM·AU | -| `extent_t·AU` | Type alias for extent of AU array | -| `FG·Type` | Template variable name for FG expansion | - -* 6. Why Not Use Underscores or CamelCase? - -While underscores (`_`) are idiomatic in C, they don't offer visual scoping in the same way, especially when chained deeply. Middle dots provide: - -- **Visual segmentation** across layered modules -- **Improved grepability**: `grep TM·` finds all TM-related symbols -- **Avoidance of macro clashes**: underscores often clash with system headers, especially when using `__NAME__` forms -- **Harmony with macro join operations** like `·(...)` - -* 7. Future Compatibility - -If C ever adopts formal module systems or namespaces, the `·` syntax can be systematically translated into official syntax, e.g.: - -- `TM·AU·Array·init_pe` → `TM::AU::Array::init_pe` -- Greppable → parseable → mappable - -For now, `·` is an elegant compromise between form, function, and forward-compatibility. - -* 8. Summary - -RT C namespaces provide: -- Scoped, composable identifiers -- Greppable structure for large projects -- Seamless macro templating and type specialization -- Collision resistance without verbosity - -By adopting `Module·Type·Submodule·Function` naming, your C code remains modular, clean, and scalable. diff --git "a/document\360\237\226\211/RT_C_tableau_methhod.org" "b/document\360\237\226\211/RT_C_tableau_methhod.org" deleted file mode 100644 index 3e1f533..0000000 --- "a/document\360\237\226\211/RT_C_tableau_methhod.org" +++ /dev/null @@ -1,177 +0,0 @@ -#+TITLE: RT Tableau Method -#+AUTHOR: Thomas - -* Memory - -A *base-relative memory map* is a dictionary that associates symbol names with offsets from a base address. A C ~struct typedef~ is an example means for declaring a base-relative memory map. A base-relative memory map has a length associated with it. - -Another term for a *base-relative memory map* is *memory format*. A defined memory format can be bound to a name. The names are required to be distinct, though the formats bound to the names need not be. - -An *instance* of , where is the name of a memory format, is a region of memory that has been bound to memory format . - -The *type* of an instance is the name of its memory format. - -* Pointer - -A *pointer* is a memory address that has been bound to a memory format. This technique is used to assure that writes to the memory address conform to the bound memory format. This helps programs to respect the bounds of memory allocations. - -The *type* of a pointer is the name of the memory format it has been bound to. - -* Function Pointer - -The address of a function can be bound to a name and an array of memory formats, -one for each argument and the return value. - -The *type* of a function is defined by its name and its array of memory format names. - -The type of a function can be looked up from the function's name. - -* Function Dictionary - -A *function dictionary* is a list of function names and addresses, keyed by function names. - -A *function dictionary template* is a collection of function types associated with a specific memory format. - -A *function dictionary instance* is a collection of function implementations that conform to a function dictionary template. - -* Object - -If the potentially many instances of a given memory format are operated on exclusively by a closed set of functions, these functions can be collected into a dictionary called the memory format's *interface*. - -Conversely, there is no conventional name for an instance of memory that is manipulated by only a closed set of functions. In TTCA, the term *tableau* was introduced for such memory. (A *tableau* is a small chalkboard that was once used by students and could be erased and rewritten.) - -Another term that could be used for such memory is *taishou* (対象), meaning "subject" or "target" in Japanese. - -* Working with `.lib.c` Files in RT C - -In the RT C design, each module’s interface **and** implementation are contained in -a single file named `something.lib.c`. Traditional `.h` headers are replaced by -preprocessor-guarded interface sections, while the main implementation and any -“local” (private) code appear in separate blocks. If you want to learn more about -this format, there is a dedicated document explaining how `.lib.c` files are structured, -along with how and why they’re compiled. - -Briefly: - -- **Interface Section** - Declares the memory format (`struct N32·T`, for instance) and the function dictionary - type (`N32·M`), along with any prototypes that external code needs. - -- **Implementation Section** - Provides the actual definitions of the functions from the interface, compiled into - an object file (e.g., `N32.lib.o`) that goes into a library (`.a` or `.so`). - -- **Local Section** - (Guarded by `#ifdef LOCAL`) Contains private utility functions or test helpers. - Only included when a `.cli.c` test or other special code explicitly requests it. - -This structure keeps all relevant code (interface, implementation, internal helpers) -in a single `.lib.c` file, yet still enforces encapsulation via preprocessor macros. -It aligns well with the *tableau* and *function dictionary* concepts described here: -the memory format and method table are declared in the interface section, their -implementations go in the implementation section, and if you need advanced debugging -routines or private details, you can optionally include the local section. - - -* More about Tableau (Taishou) - -Below is a minimal example that shows how an instance of a memory format (`N32·T`) can be exclusively manipulated by a *function dictionary* (`N32·M`). This concrete “tableau” (taishou) usage illustrates how the memory is bound to specific operations—no external code should modify the memory except through the provided dictionary functions. - -#+BEGIN_SRC c -#include -#include - -// 1. Define the memory format (tableau) -typedef struct { - uint32_t value; -} N32·T; // This struct is our 'tableau'. - -// 2. Provide some functions that operate on N32·T -void N32·copy(N32·T *dst, const N32·T *src){ - dst->value = src->value; -} - -void N32·increment(N32·T *t){ - t->value++; -} - -void N32·print(const N32·T *t){ - printf("Value: %u\n", t->value); -} - -// 3. Declare a function dictionary (method table) -typedef struct { - void (*copy)(N32·T*, const N32·T*); - void (*increment)(N32·T*); - void (*print)(const N32·T*); -} N32·M; - -// 4. Provide a concrete instance of the dictionary -const N32·M N32·m = { - .copy = N32·copy, - .increment = N32·increment, - .print = N32·print -}; - -// 5. Demonstrate usage in a main function -int main(void) { - // Create an instance of N32·T (our tableau) - N32·T my_number = { .value = 10 }; - - // Manipulate it exclusively through the function dictionary - N32·m.increment(&my_number); // Increment by 1 - N32·m.print(&my_number); // Output should show "Value: 11" - - // Create another instance and copy its contents - N32·T another_number = { .value = 42 }; - N32·m.copy(&my_number, &another_number); - N32·m.print(&my_number); // Output should show "Value: 42" - - return 0; -} -#+END_SRC - -When compiled and run (e.g., `gcc example.c -o example && ./example`), the program -prints: - -#+BEGIN_EXAMPLE -Value: 11 -Value: 42 -#+END_EXAMPLE - -In this way, `my_number` is a tableau. All modifications happen via a *closed set of -functions*—here, the operations are defined in the function dictionary `N32·m`. No -external code is allowed to poke into `my_number.value` directly (beyond this demonstration), -upholding the idea that a “tableau” is memory dedicated to a specific “function dictionary.” - - -* Terminology Considerations - -The use of the word *type* in this document aligns with C’s conventions. However, other -programming paradigms, such as those in C++ and Java, may define *types* differently. -For example, C++ allows types to include behavior (methods), while C’s types only -define memory structure. - ---- - -**Summary of Key Terms:** -- *Memory Format*: A named layout of memory. -- *Instance*: A memory region adhering to a specific format. -- *Pointer*: A memory address bound to a memory format. -- *Function Dictionary*: A set of functions associated with a memory format. -- *Tableau/Taishou*: A memory instance operated on exclusively by a function dictionary. -- *Function Dictionary Template*: A function dictionary where function types replace function implementations. - - -A *base-relative memory map* is a dictionary that associates symbol names with offsets -from a base address. A C ~struct typedef~ is an example means for declaring a -base-relative memory map. A base-relative memory map has a length associated with it. - -Another term for a *base-relative memory map* is *memory format*. A -defined memory format can be bound to a name. The names are required -to be distinct, though the formats bound to the names need not be. - -An *instance* of , where is the name of a memory format, is a region -of memory that has been bound to memory format . - -The *type* of an instance is the name of its memory format. diff --git "a/document\360\237\226\211/RT_cli_c_file.org" "b/document\360\237\226\211/RT_cli_c_file.org" deleted file mode 100644 index 06d6723..0000000 --- "a/document\360\237\226\211/RT_cli_c_file.org" +++ /dev/null @@ -1,147 +0,0 @@ -#+TITLE: Writing `.cli.c` Files in RT C -#+AUTHOR: Thomas - -* Overview -In RT C projects, a file with a “=.cli.c=” suffix typically implements a **command-line interface** i.e. a program that is run from a shell. Thus each `.cli.c` file produces an **executable** named . - -Common usage includes: -- **Command-Line Interaction** Typical commands run from a shell. -- **Testing**: Execuatbles that test C functions and print pass fail results. -- **Reusable Components**: As discussed in the section below on `main`, cli files can be called from other functions, and thus are themselves reusable components. - -* 1. Including library header information -Because a `.cli.c` file makes use functionality from libraries, it will often include file headers. In RT C, there will be a single file for both the header information and C implementation called, such a file will have a `.lib.c` suffix. The separate sections in a `.lib.c` file are gated by the preprocessor macros, `FACE`, and `LOCAL`. To include the header information from a `.lib.c` file, the `.cli.c` file will have at the top the lines: - -#+BEGIN_SRC c -#define FACE -#include "some_library.lib.c" -#include "some__other_library.lib.c" -... rest of program -#undef FACE -#+END_SRC - -* 2. Including static defined function - -Instead of using `inline` qualifications in the header, in RT coding conventions, static functions are defined in the `.lib.c`, and then included at the bottom of the `.cli.c` file. -Again this is done by gating the sections of the `.lib.c` file: - -#+BEGIN_SRC c -... rest of program - -#define LOCAL -#include "some_library.lib.c" -#include "some__other_library.lib.c" -... -#undef LOCAL -#+END_SRC - -* 3. Both header information and static defined functions: - -#+BEGIN_SRC c -#define FACE -#include "N32.lib.c" -#undef FACE - - ... rest of program - -#define LOCAL -#include "N32.lib.c" -#undef LOCAL -#+END_SRC - -- `FACE` grants access to the library’s public symbols (structs, function prototypes). -- `LOCAL` gives access to internal (“static-like”) helpers if needed for deeper testing or debugging. Only define it if you truly require these private functions/data. - -The idea here is that that optimizer can do its best work when it sees everything in one place, and thus there is no need for inline functions. On paradigm can be used for defining the program. - -* 4. The `main()` Function in `.cli.c` -Every `.cli.c` includes a `main()` function, but with special guidelines: - -1. **Minimal Parsing & Dispatch** - - `main()` is primarily responsible for reading `argc`/`argv`, validating inputs, and directing calls to your actual logic or library code. - -2. **Reusable Subroutines** - - If your `.cli.c` logic is extensive, break it out into functions that `main()` calls. This way, **other** `.cli.c` files (or even libraries) can call these same functions directly without launching a new process. - -3. **Avoid Side Effects** - - Keep `main()` from doing excessive configuration or global side effects (e.g., changing global state). This maintains a clean separation between your library code and the command-line scaffolding. - -4. **Standard Return Codes** - - Return 0 for success, non-zero for errors. If the CLI is also used programmatically by other modules, they can interpret these returns or, better yet, call your internal subroutines that return more detailed error codes. - -Example skeleton: - -#+BEGIN_SRC c -int main(int argc, char **argv){ - // 1. Parse command-line args - // 2. Validate or print usage - // 3. Call library functions or dedicated subroutines - // 4. Return 0 on success, or an error code otherwise -} -#+END_SRC - -* 5. Example of a `.cli.c` File - - -Below is a **working** `.cli.c` program demonstrating how to use the `N32.lib.c` library: - -#+BEGIN_SRC c :tangle test_N32.cli.c -#include -#include -#include - -// Expose the N32 interface by defining FACE -#define FACE -#include "N32.lib.c" -#undef FACE - -int main(int argc ,char **argv){ - if(argc < 3){ - printf("Usage: %s \n", argv[0]); - return 1; - } - - uint32_t a_val = (uint32_t)atoi(argv[1]); - uint32_t b_val = (uint32_t)atoi(argv[2]); - - // Allocate N32 objects - N32·T *numbers = N32·m.allocate_array(2 ,NULL); - if(!numbers){ - printf("Allocation failed.\n"); - return 2; - } - - // Initialize - N32·m.from_uint32(N32·m.access(numbers ,0) ,a_val); - N32·m.from_uint32(N32·m.access(numbers ,1) ,b_val); - - // Perform add - N32·T result; - N32·m.add(&result, N32·m.access(numbers ,0), N32·m.access(numbers ,1)); - printf("Sum of %u and %u is %u\n", a_val, b_val, result.d0); - - // Perform subtract - N32·m.subtract(&result, N32·m.access(numbers ,0), N32·m.access(numbers ,1)); - printf("Diff of %u and %u is %u\n", a_val, b_val, result.d0); - - N32·m.deallocate(numbers); - return 0; -} -#+END_SRC - -Here, `main()` parses two integer arguments, allocates an array of `N32·T`, -calls the library’s add and subtract functions, and prints the results. -If this is compiled alongside (or linked against) the `N32.lib.c` object code, -running `./test_N32 20 12` will produce: - -#+BEGIN_EXAMPLE -Sum of 20 and 12 is 32 -Diff of 20 and 12 is 8 -#+END_EXAMPLE - - -* 6. Summary -- **`.cli.c`** files produce executables with a central `main()` function focused on argument parsing and error handling. -- Actual logic often lives in separate subroutines (or in `.lib.c` libraries) to encourage reuse without spawning new processes. -- The RT C approach puts library interfaces in the same file as their implementation (`.lib.c`), so `#define FACE` (and optionally `#define LOCAL`) is how a `.cli.c` pulls in the necessary API or private details. -- This design maintains a clean separation between **common library functionality** and **CLI/test scaffolding**, making it easy to test or chain multiple CLIs together within the same program. diff --git "a/document\360\237\226\211/RT_lib_c_file.org" "b/document\360\237\226\211/RT_lib_c_file.org" deleted file mode 100644 index 9f47698..0000000 --- "a/document\360\237\226\211/RT_lib_c_file.org" +++ /dev/null @@ -1,107 +0,0 @@ -#+TITLE: The `.lib.c` Format -#+AUTHOR: RT C Documentation - - -* 1. The `.lib.c` File: Purpose and Sections -A single `.lib.c` file contains **interface**, **implementation**, and **local** (private) code in one place. This is an alternative to the traditional “.h + .c” pairing. Below is how the sections typically appear: - -* 2 Overview -1. **Interface Section** (replaces `.h` in traditional C) - - Guarded by `#ifndef N32·FACE ... #define N32·FACE ... #endif`. - - Contains `typedef`s, structs, enums, function prototypes—everything needed for external code to use the library. - -1. **Implementation Section** (the code compiled into the `.o` files, or `.a` or '.so' library) - - Enabled by `#define N32·IMPLEMENTATION`. - - Provides function bodies, global variables, and logic. - - Typically compiled once into the library object. - -3. **Local (Static) Section** (private code) - - Guarded by `#ifdef LOCAL`. - - Contains helper functions or data only needed in special scenarios (like testing or advanced usage). - - Marked with `Local` (instead of `static`) to indicate internal linkage. - -* 3 Macros at the Top -At the very top of a `.lib.c` file, you might see: -#+BEGIN_SRC c -//#define N32·DEBUG - -#ifndef FACE - #define N32·IMPLEMENTATION - #define FACE -#endif -#+END_SRC - -Explanation: - -- `N32·DEBUG` can be toggled for debugging features (or left commented). -- `#ifndef FACE` ensures the code only defines `N32·IMPLEMENTATION` if another block (like an interface-only include) hasn’t already set `FACE`. -- Once `N32·IMPLEMENTATION` is set, it means “compile the implementation code” by default. - -* 4 The Interface Section -Next, we see something like: -#+BEGIN_SRC c -#ifndef N32·FACE -#define N32·FACE - -// interface code here (typedefs, prototypes, extern definitions) -// ... -#endif -#+END_SRC - -- Prevents multiple inclusion of the interface (`N32·FACE`). -- Acts like a header: external code can `#define IFACE` or define `FACE` to pull in these declarations. - -* 5 The Implementation Section -After the interface `#endif`, you typically see: -#+BEGIN_SRC c -//-------------------------------------------------------------------------------- -// Implementation - -#ifdef N32·IMPLEMENTATION - // ... - #ifndef LOCAL - // Code that goes into the library object (main .o) - #endif - - #ifdef LOCAL - // Additional local or inline-like code - #endif -#endif -#+END_SRC - -Breakdown: - -1. `#ifdef N32·IMPLEMENTATION`: - - If this macro is set (usually when compiling `.lib.c` directly), we include all code for the library’s global functions. - -1. `#ifndef LOCAL`: - - Code in this block becomes part of the final `.o` or `.a` file. It is the public “library” portion, implementing the functions declared in the interface. - -3. `#ifdef LOCAL`: - - Private or test-only code, included only when some other file includes this `.lib.c` with `#define LOCAL`. - -* 6 Local vs. Static -Inside the local section, you might see `Local N32·T my_array[4]` instead of `static N32·T my_array[4]`. Historically, `static` in C means both “file scope” and “static storage duration.” The RT code style uses `Local` to clarify that these symbols have internal linkage and are “private” to this compilation unit. It’s effectively the same as `static` but more explicit in intent. - -* 7 Example Compilation Workflow -1. **Library Compilation** - - Invoke the compiler on `N31.lib.c` *without* defining `IFACE` or `LOCAL`. - - The file sees `N32·IMPLEMENTATION` → it compiles the interface + implementation code. - - Produces `N31.lib.o`, which can then be placed in `N.a` or `N.so`. - -1. **CLI or Test Program** - - A `.cli.c` might do: - #+BEGIN_SRC c - #define LOCAL - #include "N31.lib.c" - #undef LOCAL - // Now we have local (private) helpers for testing - - int main() { - // test or CLI logic calling the library - } - #+END_SRC - - This allows direct access to the library’s “private” or local section for debugging or specialized usage. - - The resulting `.cli.o` links with `N31.lib.o` from the library build, forming an executable. - -With this design, everything about a module (interface, implementation, private code) resides in a single file (`.lib.c`). The build system compiles these files into objects and links them to produce either a static or dynamic library. Meanwhile, `.cli.c` files become executables that can optionally include the local code if needed. diff --git "a/document\360\237\226\211/User_manual.org" "b/document\360\237\226\211/User_manual.org" deleted file mode 100644 index 1b0a962..0000000 --- "a/document\360\237\226\211/User_manual.org" +++ /dev/null @@ -1,32 +0,0 @@ -#+TITLE: User manual -#+AUTHOR: Thomas - -* Sections - -* Compile - - -/* - N32 - a processor native type - - For binary operations: a op b -> c - - See the document on the proper use of the Natural types. - - On the subject of multiple pointers indicating the same location in memory: - - When a routine has multiple results, and one or more of the result location - pointers point to the same storage, the routine will either return an error - status, or have defined behavior. - - When a routine has multiple operands, in any combination, those - pointers can point to the same location, and the routine will - function as advertised. - - When an operand functions as both an input and a result, perhaps due - to a result pointer pointing to the same place as an operand - pointer, the routine will function as advertised. (Internally the - routine might make a temporary copy of the operand to accomplish - this.) - -*/ diff --git "a/document\360\237\226\211/continuations.org" "b/document\360\237\226\211/continuations.org" deleted file mode 100644 index 89d9a3b..0000000 --- "a/document\360\237\226\211/continuations.org" +++ /dev/null @@ -1,16 +0,0 @@ -#+TITLE: Reflections On Continuations -#+AUTHOR: Thomas -#+STARTUP: content - -There are two things going on: - -- The function executes code against data. When doing so it happens upon some characteristics of the computation. These often include the results from argument guards, and reports of end cases. The function the reports back information that could potentially be used to - affect control flow. - -- The control flow is a related, but separate question. There is an overall scheme of control flow that involves branching, where some of these branches depend on the evaluation of data. - -- So the question is then is it of value to pass into a function a list of, 'if you see X then call Y' ? Where every possible X is represented in the list. Does this not conflate control flow with computation? - - What if the X are not independent? Then the priority logic either requires a rendezvous with functions that have arguments, or be embedded in the called function with continuations, but said function knows nothing of the caller's priorities. - - If many continuations rendezvous so decisions can be made, how is that more efficient than the caller examining a returned status code, and make decision. Is this not a better location for the decision code, as the caller is setting the control flow? diff --git "a/document\360\237\226\211/emacs_keys.el" "b/document\360\237\226\211/emacs_keys.el" deleted file mode 100644 index 566c808..0000000 --- "a/document\360\237\226\211/emacs_keys.el" +++ /dev/null @@ -1,84 +0,0 @@ -;; the sake of sanity... -;; -(global-set-key (kbd "C-z") nil) ;; turn off the poison C-z key. Use C-x C-z or the command suspend-emacs -(global-set-key (kbd "C-v") nil) ;; tempting to put paste (yank) for a common typo, but at least lets not jump down the page -;; would be nice to clear C-c but minor modes redefine it - - -;;-------------------------------------------------------------------------------- -;; extended character set for programming examples in the TTCA book -;; -;; preferable to use an Xcompose file definition when available -;; -(when t - - (global-set-key [f1] 'help-command) - (global-set-key "\C-h" 'nil) - (define-key key-translation-map (kbd "M-S") (kbd "§")) - - (global-set-key (kbd "C-x g copyright SPC") [?©]) - - (global-set-key (kbd "C-x g phi SPC") [?φ]) ; phi for phase - (global-set-key (kbd "C-x g Phi SPC") [?Φ]) - - (global-set-key (kbd "C-x g d SPC") [?δ]) - (global-set-key (kbd "C-x g D SPC") [?Δ]) ; this is 'delta' is not 'increment'! - (global-set-key (kbd "C-x g delta SPC") [?δ]) - (global-set-key (kbd "C-x g Delta SPC") [?Δ]) ; this is 'delta' is not 'increment'! - - (global-set-key (kbd "C-x g g SPC") [?γ]) - (global-set-key (kbd "C-x g G SPC") [?Γ]) - (global-set-key (kbd "C-x g gamma SPC") [?γ]) - (global-set-key (kbd "C-x g Gamma SPC") [?Γ]) - - (global-set-key (kbd "C-x g l SPC") [?λ]) - (global-set-key (kbd "C-x g L SPC") [?Λ]) - (global-set-key (kbd "C-x g lambda SPC") [?λ]) - (global-set-key (kbd "C-x g Lambda SPC") [?Λ]) - - (global-set-key (kbd "C-x g m SPC") [?μ]) - (global-set-key (kbd "C-x g M SPC") [?Μ]) - (global-set-key (kbd "C-x g mu SPC") [?μ]) - (global-set-key (kbd "C-x g Mu SPC") [?Μ]) - - (global-set-key (kbd "C-x g p SPC") [?π]) - (global-set-key (kbd "C-x g P SPC") [?Π]) - (global-set-key (kbd "C-x g pi SPC") [?π]) - (global-set-key (kbd "C-x g Pi SPC") [?Π]) - - (global-set-key (kbd "C-x g x SPC") [?ξ]) - (global-set-key (kbd "C-x g X SPC") [?Ξ]) - (global-set-key (kbd "C-x g xi SPC") [?ξ]) - (global-set-key (kbd "C-x g Xi SPC") [?Ξ]) - - (global-set-key (kbd "C-x g > = SPC") [?≥]) - (global-set-key (kbd "C-x g < = SPC") [?≤]) - (global-set-key (kbd "C-x g ! = SPC") [?≠]) - (global-set-key (kbd "C-x g neq SPC") [?≠]) - - (global-set-key (kbd "C-x g nil SPC") [?∅]) - - (global-set-key (kbd "C-x g not SPC") [?¬]) - - (global-set-key (kbd "C-x g and SPC") [?∧]) - (global-set-key (kbd "C-x g or SPC") [?∨]) - - (global-set-key (kbd "C-x g exists SPC") [?∃]) - (global-set-key (kbd "C-x g all SPC") [?∀]) - - (global-set-key (kbd "C-x g do SPC") [?⟳]) ; do - (global-set-key (kbd "C-x g rb SPC") [?◨]) - (global-set-key (kbd "C-x g lb SPC") [?◧]) - - (global-set-key (kbd "C-x g cont SPC") [?➜]) ; continue - (global-set-key (kbd "C-x g thread SPC") [?☥]) ; thread - - (global-set-key (kbd "C-x g in SPC") [?∈]) ; set membership - - (global-set-key (kbd "C-x g times SPC") [?×]) ; set membership - - (global-set-key (kbd "C-x g cdot SPC") [?·]) ; scoping sepearator for gcc C - - (global-set-key (kbd "C-x g pencil SPC") [?🖉]) ; scoping sepearator for gcc C - -) diff --git "a/document\360\237\226\211/temp.txt" "b/document\360\237\226\211/temp.txt" deleted file mode 100644 index a734ec4..0000000 --- "a/document\360\237\226\211/temp.txt" +++ /dev/null @@ -1,90 +0,0 @@ -#+TITLE: Proposed TM Bulk Methods for Multi-Cell Copy -#+AUTHOR: Sorein -#+DATE: 2025-04-25 - -* 1. Motivation: Efficient Copy Needs Bulk Cell Access - -The standard `read` and `write` methods in TM operate on **one cell at a time**, which is: -- Clear -- Safe -- Sufficient for most loops - -However, when implementing **bit-for-bit stream copy** between TMs, we want to: -- **Copy multiple cells at once**, where possible -- Use the largest available unit per cell -- Avoid stepping repeatedly through the same control path - -To support this, TM needs **bulk methods** for cell span access. - -* 2. What Is a Span? - -A **span** is a run of **N contiguous cells** available from the current tape head. - -A TM can only offer a span if: -- The head is *on tape* -- At least `N` cells are accessible to the right -- The memory layout is contiguous - -Not all TM types (e.g. cyclic or zero-length) support spans. For others, it's an optimization. - -* 3. Proposed TM Methods - -Each method is defined per CVT type. For example, `TM·AU` would add: - -#+BEGIN_SRC c -bool TM·AU·can_span(TM·AU tm ,size_t count); -AU const* TM·AU·peek_span(TM·AU tm ,size_t count); -AU* TM·AU·claim_span(TM·AU tm ,size_t count); -void TM·AU·commit_span(TM·AU tm ,size_t count); -size_t TM·AU·remaining(TM·AU tm); -#+END_SRC - -* 4. Semantics - -| Method | Purpose | -|------------------+--------------------------------------------------------------| -| `can_span(n)` | Returns true if N contiguous cells can be read or written | -| `peek_span(n)` | Returns a read-only pointer to N contiguous cells, or NULL | -| `claim_span(n)` | Returns a writable pointer to N cells, or NULL | -| `commit_span(n)` | Advances the head right by N cells (must follow claim) | -| `remaining()` | Returns the number of cells remaining from head to end | - -* 5. Guarded Use Pattern - -A `Copy` implementation might use: - -#+BEGIN_SRC c -while( TM·AU·can_span(src ,n) && TM·AU·can_span(dst ,n) ){ - AU const* s = TM·AU·peek_span(src ,n); - AU* d = TM·AU·claim_span(dst ,n); - memcpy(d ,s ,n * sizeof(AU)); - TM·AU·commit_span(src ,n); - TM·AU·commit_span(dst ,n); -} -#+END_SRC - -This avoids looping through `read`/`write` per cell and reduces dispatch overhead. - -* 6. Optional Implementation and Capability Flag - -Not all TM types can support spans. We can: - -- Add a `supports_span` method to the FG table -- Or define a `TM·Capability` bitfield: - -#+BEGIN_SRC c -typedef enum{ - TM·Caps·none = 0, - TM·Caps·span = 1 << 0 -} TM·Caps; -#+END_SRC - -* 7. Summary - -Bulk cell access enhances TM's ability to support: -- Efficient copy -- Block-based streaming -- Memory-mapped operations -- Potential SIMD and vectorization later - -By introducing the five methods above, TM becomes *not* diff --git "a/document\360\237\226\211/unicode_character_use.org" "b/document\360\237\226\211/unicode_character_use.org" deleted file mode 100644 index dbc9361..0000000 --- "a/document\360\237\226\211/unicode_character_use.org" +++ /dev/null @@ -1,20 +0,0 @@ -#+TITLE: Unicode Character Use -#+AUTHOR: RT C Documentation - -The following characters are used: - -🖉 - The pencil suffix is placed on the end of directory or file names. It indicates that - the contents of the directory contains authored files, or in the case of the suffix on the end of a file name, that the specific file is authored. - - Authored files should not be deleted by scripts. The command `rm_na` will not delete - authored files, and it is used in scripts. It can be found in the RT-project-share project. - -· - The center dot is a proposed namespace sepearator for C. Currently it is used ad - hoc as the prefix portion of identifiers. There is some support in Python scripts. - -M - This is used to name function dictionary type. Function dictionaries are struct types - full of functions, and act as interfaces. - -m - A common name or prefix for an instance of a function dictionary type. This follows - the convention that type names are PascalCase, and instance names are snake_case. - diff --git a/tester/cc/cc/environment.h b/tester/cc/cc/environment.h new file mode 100644 index 0000000..cdea83c --- /dev/null +++ b/tester/cc/cc/environment.h @@ -0,0 +1,5 @@ +#ifndef Mpblock·ENVIRONMENT_H +#define Mpblock·ENVIRONMENT_H + + +#endif diff --git a/tester/cc/cc/test_Copy_0.cli.c b/tester/cc/cc/test_Copy_0.cli.c new file mode 100644 index 0000000..7609728 --- /dev/null +++ b/tester/cc/cc/test_Copy_0.cli.c @@ -0,0 +1,269 @@ +/* + Black Box test for Copy.lib.c + +*/ + +#include +#include +#include +#include +#include + +// Pull in the interface portion of the Copy library +#define FACE +#include "Copy.lib.c" +#undef FACE + +static sigjmp_buf jump_buffer; + +void signal_handler( int sig ){ + siglongjmp( jump_buffer ,1 ); +} + +typedef bool ( *TestFunction )(); +typedef struct{ + TestFunction function; + const char *name; +} TestEntry; + +// ----------------------------------------------------------------------------- +// Test Declarations +// ----------------------------------------------------------------------------- + +bool test_copy_bytes(); +bool test_copy_bytes_reverse(); +bool test_copy_step(); +bool test_copy_step_reverse(); + +// ----------------------------------------------------------------------------- +// Test List and Runner +// ----------------------------------------------------------------------------- + +TestEntry test_list[] = { + { test_copy_bytes ,"test_copy_bytes" } + ,{ test_copy_bytes_reverse ,"test_copy_bytes_reverse" } + ,{ test_copy_step ,"test_copy_step" } + ,{ test_copy_step_reverse ,"test_copy_step_reverse" } + ,{ NULL ,NULL } // terminator +}; + +int test_head(){ + int pass_count = 0; + int fail_count = 0; + + // Catch common signals + signal( SIGSEGV ,signal_handler ); + signal( SIGFPE ,signal_handler ); + signal( SIGABRT ,signal_handler ); + + for( TestEntry *entry = test_list ; entry->function != NULL ; entry++ ){ + if( sigsetjmp( jump_buffer ,1 ) == 0 ){ + // Normal path + if( !entry->function() ){ + printf( "Failed: %s\n" ,entry->name ); + fail_count++; + }else{ + pass_count++; + } + }else{ + // Signal caught + printf( "Failed due to signal: %s\n" ,entry->name ); + fail_count++; + } + } + + printf( "Tests passed: %d\n" ,pass_count ); + printf( "Tests failed: %d\n" ,fail_count ); + + return ( fail_count == 0 ) ? 0 : 1; +} + +int main( int argc ,char **argv ){ + return test_head(); +} + +// ----------------------------------------------------------------------------- +// Test Definitions +// ----------------------------------------------------------------------------- + +bool test_copy_bytes(){ + // Test that Copy·bytes() copies data verbatim from src to dst + uint8_t src[8] = { 0x01 ,0x02 ,0x03 ,0x04 ,0xA0 ,0xB0 ,0xC0 ,0xFF }; + uint8_t dst[8]; + memset( dst ,0x00 ,8 ); + + // Copy entire buffer + Copy·bytes( src ,src + 8 ,dst ); + + // Check + for( int i = 0 ; i < 8 ; i++ ){ + if( dst[i] != src[i] ){ + return false; + } + } + return true; +} + +bool test_copy_bytes_reverse(){ + // Test that Copy·bytes_reverse_order() reverses the entire buffer + uint8_t src[6] = { 'H' ,'e' ,'l' ,'l' ,'o' ,'!' }; + uint8_t dst[6]; + memset( dst ,0x00 ,6 ); + + // Reverse copy: Expect "!olleH" + Copy·bytes_reverse_order( src ,src + 6 ,dst ); + + static const uint8_t expected[6] = { '!' ,'o' ,'l' ,'l' ,'e' ,'H' }; + for( int i = 0 ; i < 6 ; i++ ){ + if( dst[i] != expected[i] ){ + return false; + } + } + return true; +} + +bool test_copy_step(){ + // Test partial copying with Copy·step() + // We'll create a source of 10 bytes but allow only 4 bytes of write at a time. + uint8_t src[10]; + for( int i = 0 ; i < 10 ; i++ ){ + src[i] = (uint8_t)( i + 1 ); // 1..10 + } + + uint8_t dst[10]; + memset( dst ,0 ,10 ); + + // Create a Copy·it descriptor + Copy·it it; + it.read0 = src; + it.read_size = 10; + it.write0 = dst; + it.write_size = 4; + + // First step: expect incomplete_read (only 4 bytes written) + { + Copy·Status st = Copy·step( &it ); + if( st != Copy·Status·incomplete_read ){ + return false; + } + // Check that first 4 bytes got copied + for( int i = 0 ; i < 4 ; i++ ){ + if( dst[i] != (uint8_t)( i + 1 ) ){ + return false; + } + } + // read_size=6, write_size=0, read0 advanced by 4, write0 advanced by 4 + if( it.read_size != 6 || it.write_size != 0 ){ + return false; + } + } + + // Provide more write space + it.write_size = 3; + // Second step: expect incomplete_read again (only 3 more bytes copied) + { + Copy·Status st = Copy·step( &it ); + if( st != Copy·Status·incomplete_read ){ + return false; + } + // Check next 3 bytes: now in dst[4..6] + for( int i = 0 ; i < 3 ; i++ ){ + // i=0 => index=4 => src[4]=5 + if( dst[4 + i] != (uint8_t)( 5 + i ) ){ + return false; + } + } + if( it.read_size != 3 || it.write_size != 0 ){ + return false; + } + } + + // Provide final 3 bytes of write space + it.write_size = 3; + { + Copy·Status st = Copy·step( &it ); + // Now we expect either complete or incomplete_write if exactly matched + // Actually we have 3 left to read, 3 left to write => it should be 'complete' + if( st != Copy·Status·complete ){ + return false; + } + // Check last 3 bytes + for( int i = 0 ; i < 3 ; i++ ){ + if( dst[7 + i] != (uint8_t)( 8 + i ) ){ + return false; + } + } + } + + // Verify the entire dst array + for( int i = 0 ; i < 10 ; i++ ){ + if( dst[i] != (uint8_t)( i + 1 ) ){ + return false; + } + } + return true; +} + +bool test_copy_step_reverse(){ + // Test partial copying in reverse using Copy·step_reverse_order() + + // Source: 7 bytes => {1,2,3,4,5,6,7} + uint8_t src[7]; + for( int i = 0 ; i < 7 ; i++ ){ + src[i] = (uint8_t)( i + 1 ); + } + + uint8_t dst[7]; + memset( dst ,0 ,7 ); + + Copy·it it; + it.read0 = src; // Base of read + it.read_size = 7; // 7 bytes total + it.write0 = dst; + it.write_size = 4; // Only 4 bytes can be written initially + + // 1st step: we copy the top 4 bytes in reverse => should be {7,6,5,4} + { + Copy·Status st = Copy·step_reverse_order( &it ); + if( st != Copy·Status·incomplete_read ){ + return false; + } + // Check that the first 4 reversed bytes ended up in dst + // We expect: dst[0]=7, dst[1]=6, dst[2]=5, dst[3]=4 + if( dst[0] != 7 || dst[1] != 6 || dst[2] != 5 || dst[3] != 4 ){ + return false; + } + // read_size should now be 3, write_size=0 + if( it.read_size != 3 || it.write_size != 0 ){ + return false; + } + } + + // Provide 3 more bytes of write space + it.write_size = 3; + { + // 2nd step: copy the remaining 3 bytes in reverse => {3,2,1} + Copy·Status st = Copy·step_reverse_order( &it ); + // With 3 left to read, 3 left to write => expect complete or incomplete_write + if( st != Copy·Status·complete ){ + return false; + } + // Check we wrote them after the first 4 + if( dst[4] != 3 || dst[5] != 2 || dst[6] != 1 ){ + return false; + } + // Now read_size=0, write_size=0 + if( it.read_size != 0 || it.write_size != 0 ){ + return false; + } + } + + return true; +} + +// for block box testing this goes at the bottom +// for white box testing this goes at the top + +#define LOCAL +#include "Copy.lib.c" +#endif diff --git a/tester/cc/cc/test_setup.cli.c b/tester/cc/cc/test_setup.cli.c new file mode 100644 index 0000000..eed666c --- /dev/null +++ b/tester/cc/cc/test_setup.cli.c @@ -0,0 +1,27 @@ +/* + + A placeholder to see if make etc. is working. + +*/ + +#define FACE +#include +#include +#undef FACE + +// No need to define IMPLEMENTATION as `main` is one and done. + +int main(int argc ,char *argv[] ,char *envp[]){ + if(argc != 1){ + fprintf(stderr, "Usage: %s\n", argv[0]); + return EXIT_FAILURE; + } + + fprintf(stderr, "%s done\n", argv[0]); + + return 0; +} + + +#define LOCAL +#undef LOCAL diff --git "a/tester/cc\360\237\226\211/environment.h" "b/tester/cc\360\237\226\211/environment.h" deleted file mode 100644 index cdea83c..0000000 --- "a/tester/cc\360\237\226\211/environment.h" +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef Mpblock·ENVIRONMENT_H -#define Mpblock·ENVIRONMENT_H - - -#endif diff --git "a/tester/cc\360\237\226\211/test_Copy_0.cli.c" "b/tester/cc\360\237\226\211/test_Copy_0.cli.c" deleted file mode 100644 index 7609728..0000000 --- "a/tester/cc\360\237\226\211/test_Copy_0.cli.c" +++ /dev/null @@ -1,269 +0,0 @@ -/* - Black Box test for Copy.lib.c - -*/ - -#include -#include -#include -#include -#include - -// Pull in the interface portion of the Copy library -#define FACE -#include "Copy.lib.c" -#undef FACE - -static sigjmp_buf jump_buffer; - -void signal_handler( int sig ){ - siglongjmp( jump_buffer ,1 ); -} - -typedef bool ( *TestFunction )(); -typedef struct{ - TestFunction function; - const char *name; -} TestEntry; - -// ----------------------------------------------------------------------------- -// Test Declarations -// ----------------------------------------------------------------------------- - -bool test_copy_bytes(); -bool test_copy_bytes_reverse(); -bool test_copy_step(); -bool test_copy_step_reverse(); - -// ----------------------------------------------------------------------------- -// Test List and Runner -// ----------------------------------------------------------------------------- - -TestEntry test_list[] = { - { test_copy_bytes ,"test_copy_bytes" } - ,{ test_copy_bytes_reverse ,"test_copy_bytes_reverse" } - ,{ test_copy_step ,"test_copy_step" } - ,{ test_copy_step_reverse ,"test_copy_step_reverse" } - ,{ NULL ,NULL } // terminator -}; - -int test_head(){ - int pass_count = 0; - int fail_count = 0; - - // Catch common signals - signal( SIGSEGV ,signal_handler ); - signal( SIGFPE ,signal_handler ); - signal( SIGABRT ,signal_handler ); - - for( TestEntry *entry = test_list ; entry->function != NULL ; entry++ ){ - if( sigsetjmp( jump_buffer ,1 ) == 0 ){ - // Normal path - if( !entry->function() ){ - printf( "Failed: %s\n" ,entry->name ); - fail_count++; - }else{ - pass_count++; - } - }else{ - // Signal caught - printf( "Failed due to signal: %s\n" ,entry->name ); - fail_count++; - } - } - - printf( "Tests passed: %d\n" ,pass_count ); - printf( "Tests failed: %d\n" ,fail_count ); - - return ( fail_count == 0 ) ? 0 : 1; -} - -int main( int argc ,char **argv ){ - return test_head(); -} - -// ----------------------------------------------------------------------------- -// Test Definitions -// ----------------------------------------------------------------------------- - -bool test_copy_bytes(){ - // Test that Copy·bytes() copies data verbatim from src to dst - uint8_t src[8] = { 0x01 ,0x02 ,0x03 ,0x04 ,0xA0 ,0xB0 ,0xC0 ,0xFF }; - uint8_t dst[8]; - memset( dst ,0x00 ,8 ); - - // Copy entire buffer - Copy·bytes( src ,src + 8 ,dst ); - - // Check - for( int i = 0 ; i < 8 ; i++ ){ - if( dst[i] != src[i] ){ - return false; - } - } - return true; -} - -bool test_copy_bytes_reverse(){ - // Test that Copy·bytes_reverse_order() reverses the entire buffer - uint8_t src[6] = { 'H' ,'e' ,'l' ,'l' ,'o' ,'!' }; - uint8_t dst[6]; - memset( dst ,0x00 ,6 ); - - // Reverse copy: Expect "!olleH" - Copy·bytes_reverse_order( src ,src + 6 ,dst ); - - static const uint8_t expected[6] = { '!' ,'o' ,'l' ,'l' ,'e' ,'H' }; - for( int i = 0 ; i < 6 ; i++ ){ - if( dst[i] != expected[i] ){ - return false; - } - } - return true; -} - -bool test_copy_step(){ - // Test partial copying with Copy·step() - // We'll create a source of 10 bytes but allow only 4 bytes of write at a time. - uint8_t src[10]; - for( int i = 0 ; i < 10 ; i++ ){ - src[i] = (uint8_t)( i + 1 ); // 1..10 - } - - uint8_t dst[10]; - memset( dst ,0 ,10 ); - - // Create a Copy·it descriptor - Copy·it it; - it.read0 = src; - it.read_size = 10; - it.write0 = dst; - it.write_size = 4; - - // First step: expect incomplete_read (only 4 bytes written) - { - Copy·Status st = Copy·step( &it ); - if( st != Copy·Status·incomplete_read ){ - return false; - } - // Check that first 4 bytes got copied - for( int i = 0 ; i < 4 ; i++ ){ - if( dst[i] != (uint8_t)( i + 1 ) ){ - return false; - } - } - // read_size=6, write_size=0, read0 advanced by 4, write0 advanced by 4 - if( it.read_size != 6 || it.write_size != 0 ){ - return false; - } - } - - // Provide more write space - it.write_size = 3; - // Second step: expect incomplete_read again (only 3 more bytes copied) - { - Copy·Status st = Copy·step( &it ); - if( st != Copy·Status·incomplete_read ){ - return false; - } - // Check next 3 bytes: now in dst[4..6] - for( int i = 0 ; i < 3 ; i++ ){ - // i=0 => index=4 => src[4]=5 - if( dst[4 + i] != (uint8_t)( 5 + i ) ){ - return false; - } - } - if( it.read_size != 3 || it.write_size != 0 ){ - return false; - } - } - - // Provide final 3 bytes of write space - it.write_size = 3; - { - Copy·Status st = Copy·step( &it ); - // Now we expect either complete or incomplete_write if exactly matched - // Actually we have 3 left to read, 3 left to write => it should be 'complete' - if( st != Copy·Status·complete ){ - return false; - } - // Check last 3 bytes - for( int i = 0 ; i < 3 ; i++ ){ - if( dst[7 + i] != (uint8_t)( 8 + i ) ){ - return false; - } - } - } - - // Verify the entire dst array - for( int i = 0 ; i < 10 ; i++ ){ - if( dst[i] != (uint8_t)( i + 1 ) ){ - return false; - } - } - return true; -} - -bool test_copy_step_reverse(){ - // Test partial copying in reverse using Copy·step_reverse_order() - - // Source: 7 bytes => {1,2,3,4,5,6,7} - uint8_t src[7]; - for( int i = 0 ; i < 7 ; i++ ){ - src[i] = (uint8_t)( i + 1 ); - } - - uint8_t dst[7]; - memset( dst ,0 ,7 ); - - Copy·it it; - it.read0 = src; // Base of read - it.read_size = 7; // 7 bytes total - it.write0 = dst; - it.write_size = 4; // Only 4 bytes can be written initially - - // 1st step: we copy the top 4 bytes in reverse => should be {7,6,5,4} - { - Copy·Status st = Copy·step_reverse_order( &it ); - if( st != Copy·Status·incomplete_read ){ - return false; - } - // Check that the first 4 reversed bytes ended up in dst - // We expect: dst[0]=7, dst[1]=6, dst[2]=5, dst[3]=4 - if( dst[0] != 7 || dst[1] != 6 || dst[2] != 5 || dst[3] != 4 ){ - return false; - } - // read_size should now be 3, write_size=0 - if( it.read_size != 3 || it.write_size != 0 ){ - return false; - } - } - - // Provide 3 more bytes of write space - it.write_size = 3; - { - // 2nd step: copy the remaining 3 bytes in reverse => {3,2,1} - Copy·Status st = Copy·step_reverse_order( &it ); - // With 3 left to read, 3 left to write => expect complete or incomplete_write - if( st != Copy·Status·complete ){ - return false; - } - // Check we wrote them after the first 4 - if( dst[4] != 3 || dst[5] != 2 || dst[6] != 1 ){ - return false; - } - // Now read_size=0, write_size=0 - if( it.read_size != 0 || it.write_size != 0 ){ - return false; - } - } - - return true; -} - -// for block box testing this goes at the bottom -// for white box testing this goes at the top - -#define LOCAL -#include "Copy.lib.c" -#endif diff --git "a/tester/cc\360\237\226\211/test_setup.cli.c" "b/tester/cc\360\237\226\211/test_setup.cli.c" deleted file mode 100644 index eed666c..0000000 --- "a/tester/cc\360\237\226\211/test_setup.cli.c" +++ /dev/null @@ -1,27 +0,0 @@ -/* - - A placeholder to see if make etc. is working. - -*/ - -#define FACE -#include -#include -#undef FACE - -// No need to define IMPLEMENTATION as `main` is one and done. - -int main(int argc ,char *argv[] ,char *envp[]){ - if(argc != 1){ - fprintf(stderr, "Usage: %s\n", argv[0]); - return EXIT_FAILURE; - } - - fprintf(stderr, "%s done\n", argv[0]); - - return 0; -} - - -#define LOCAL -#undef LOCAL diff --git a/tester/deprecated/test_N32.cli.c b/tester/deprecated/test_N32.cli.c new file mode 100644 index 0000000..25451bb --- /dev/null +++ b/tester/deprecated/test_N32.cli.c @@ -0,0 +1,364 @@ +#include +#include +#include +#include + +// Enable interface section +#define FACE +#include "N32.lib.c" +#undef FACE + +// Jump buffer for signal handling +static sigjmp_buf jump_buffer; + +// Signal handler for catching fatal errors +void signal_handler(int signal){ + siglongjmp(jump_buffer ,1); // Jump back to test_head on error +} + +// Test function prototypes +bool test_copy(); +bool test_bitwise_operations(); +bool test_comparisons(); +bool test_arithmetic(); +bool test_shifts(); + +// Test array (null-terminated) +typedef bool (*TestFunction)(); +typedef struct{ + TestFunction function; + const char *name; +}TestEntry; + +TestEntry test_list[] = { + {test_copy ,"test_copy"} + ,{test_bitwise_operations ,"test_bitwise_operations"} + ,{test_comparisons ,"test_comparisons"} + ,{test_arithmetic ,"test_arithmetic"} + ,{test_shifts ,"test_shifts"} + ,{NULL ,NULL} // Null termination +}; + +// The test runner +int test_head(){ + int pass_count = 0; + int fail_count = 0; + + // Set up signal handlers + signal(SIGSEGV ,signal_handler); // Catch segmentation faults + signal(SIGFPE ,signal_handler); // Catch floating point errors + signal(SIGABRT ,signal_handler); // Catch abort() calls + + for(TestEntry *entry = test_list; entry->function != NULL; entry++){ + if( sigsetjmp(jump_buffer ,1) == 0 ){ + // Run the test normally + if( !entry->function() ){ + printf("Failed: %s\n" ,entry->name); + fail_count++; + }else{ + pass_count++; + } + }else{ + // If a signal was caught + printf("Failed due to signaling: %s\n" ,entry->name); + fail_count++; + } + } + + printf("Tests passed: %d\n" ,pass_count); + printf("Tests failed: %d\n" ,fail_count); + return (fail_count == 0) ? 0 : 1; +} + +// Main function +int main(int argc ,char **argv){ + return test_head(); +} + +//------------------------------------------------------------------------------ +// Test Implementations +//------------------------------------------------------------------------------ + +bool test_copy(){ + // Allocate memory + N32·T *array = N32·m.allocate_array(2 ,NULL); + if( !array ) return false; + + // Access elements via access function + N32·T *a = N32·m.access(array ,0); + N32·T *b = N32·m.access(array ,1); + + // Assign value and copy + N32·m.from_uint32(a ,42); + N32·m.copy(b ,a); + + bool success = ( N32·m.compare(b ,a) == N32·Order_eq ); + N32·m.deallocate(array); + return success; +} + +bool test_arithmetic(){ + // Allocate memory + N32·T *array = N32·m.allocate_array(3 ,NULL); + if( !array ) return false; + + N32·T *a = N32·m.access(array ,0); + N32·T *b = N32·m.access(array ,1); + N32·T *result = N32·m.access(array ,2); + + N32·m.from_uint32(a ,20); + N32·m.from_uint32(b ,22); + + if( N32·m.add(result ,a ,b) != N32·Status·ok ) return false; + if( N32·m.compare(result ,N32·m.access(array ,0)) != N32·Order_gt ) return false; + + if( N32·m.subtract(result ,b ,a) != N32·Status·ok ) return false; + if( N32·m.compare(result ,N32·m.access(array ,0)) != N32·Order_lt ) return false; + + N32·m.deallocate(array); + return true; +} + +bool test_bitwise_operations(){ + // Allocate memory + N32·T *array = N32·m.allocate_array(3, NULL); + if(!array) return false; + + N32·T *a = N32·m.access(array, 0); + N32·T *b = N32·m.access(array, 1); + N32·T *result = N32·m.access(array, 2); + + // a = 0x0F0F0F0F, b = 0xF0F0F0F0 + N32·m.from_uint32(a, 0x0F0F0F0F); + N32·m.from_uint32(b, 0xF0F0F0F0); + + // bit_and => expect 0x00000000 + N32·m.bit_and(result, a, b); + N32·m.from_uint32(a, 0x00000000); + if(N32·m.compare(result, a) != N32·Order_eq){ + N32·m.deallocate(array); + return false; + } + + // Reset a to 0x0F0F0F0F for next tests + N32·m.from_uint32(a, 0x0F0F0F0F); + + // bit_or => expect 0xFFFFFFFF + N32·m.bit_or(result, a, b); + N32·m.from_uint32(b, 0xFFFFFFFF); + if(N32·m.compare(result, b) != N32·Order_eq){ + N32·m.deallocate(array); + return false; + } + + // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 + N32·m.from_uint32(a, 0x0F0F0F0F); + N32·m.bit_complement(result, a); + N32·m.from_uint32(b, 0xF0F0F0F0); + if(N32·m.compare(result, b) != N32·Order_eq){ + N32·m.deallocate(array); + return false; + } + + // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 + N32·m.from_uint32(a, 0x0F0F0F0F); + N32·m.bit_twos_complement(result, a); + N32·m.from_uint32(b, 0xF0F0F0F1); + if(N32·m.compare(result, b) != N32·Order_eq){ + N32·m.deallocate(array); + return false; + } + + N32·m.deallocate(array); + return true; +} + +bool test_comparisons(){ + // Allocate memory + N32·T *array = N32·m.allocate_array(3, NULL); + if(!array) return false; + + N32·T *a = N32·m.access(array, 0); + N32·T *b = N32·m.access(array, 1); + N32·T *c = N32·m.access(array, 2); + + // First set: a=0, b=42, c=42 + N32·m.from_uint32(a, 0); + N32·m.from_uint32(b, 42); + N32·m.from_uint32(c, 42); + + // eq_zero(a) => true + if(!N32·m.eq_zero(a)){ + N32·m.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32·m.eq_zero(b)){ + N32·m.deallocate(array); + return false; + } + // eq(b, c) => true + if(!N32·m.eq(b, c)){ + N32·m.deallocate(array); + return false; + } + // eq(a, b) => false + if(N32·m.eq(a, b)){ + N32·m.deallocate(array); + return false; + } + // compare(a, b) => N32·Order_lt + if(N32·m.compare(a, b) != N32·Order_lt){ + N32·m.deallocate(array); + return false; + } + // compare(b, a) => N32·Order_gt + if(N32·m.compare(b, a) != N32·Order_gt){ + N32·m.deallocate(array); + return false; + } + // compare(b, c) => N32·Order_eq + if(N32·m.compare(b, c) != N32·Order_eq){ + N32·m.deallocate(array); + return false; + } + // lt(a, b) => true, gt(b, a) => true + if(!N32·m.lt(a, b) || !N32·m.gt(b, a)){ + N32·m.deallocate(array); + return false; + } + + // Second set: a=100, b=50 + N32·m.from_uint32(a, 100); + N32·m.from_uint32(b, 50); + if(N32·m.compare(a, b) != N32·Order_gt){ + N32·m.deallocate(array); + return false; + } + // eq_zero(a) => false + if(N32·m.eq_zero(a)){ + N32·m.deallocate(array); + return false; + } + // eq_zero(b) => false + if(N32·m.eq_zero(b)){ + N32·m.deallocate(array); + return false; + } + + N32·m.deallocate(array); + return true; +} + +bool test_shifts(){ + // Allocate memory for operand, fill, spill + N32·T *array = N32·m.allocate_array(3, NULL); + if(!array) return false; + + N32·T *operand = N32·m.access(array, 0); + N32·T *fill = N32·m.access(array, 1); + N32·T *spill = N32·m.access(array, 2); + + // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 + N32·m.from_uint32(operand, 1); + N32·m.from_uint32(fill, 0); + N32·m.from_uint32(spill, 0); + if(N32·m.shift_left(4, spill, operand, fill) != N32·Status·ok){ + N32·m.deallocate(array); + return false; + } + N32·T *temp = N32·m.allocate_array(1, NULL); + if(!temp){ + N32·m.deallocate(array); + return false; + } + N32·m.from_uint32(temp, 16); + if(N32·m.compare(operand, temp) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + if(N32·m.compare(fill, N32·zero) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + if(N32·m.compare(spill, N32·zero) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + + // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 + N32·m.from_uint32(operand, 0x80000000); + N32·m.from_uint32(fill, 0); + N32·m.from_uint32(spill, 0); + if(N32·m.shift_left(1, spill, operand, fill) != N32·Status·ok){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + if(!N32·m.eq_zero(operand)){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + N32·m.from_uint32(temp, 1); + if(N32·m.compare(spill, temp) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + + // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 + N32·m.from_uint32(operand, 0x80000000); + N32·m.from_uint32(fill, 0); + N32·m.from_uint32(spill, 0); + if(N32·m.shift_right(1, spill, operand, fill) != N32·Status·ok){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + N32·m.from_uint32(temp, 0x40000000); + if(N32·m.compare(operand, temp) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + if(!N32·m.eq_zero(spill)){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + + // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 + N32·m.from_uint32(operand, 0x80000000); + N32·m.from_uint32(spill, 0); + if(N32·m.arithmetic_shift_right(1, operand, spill) != N32·Status·ok){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + N32·m.from_uint32(temp, 0xC0000000); + if(N32·m.compare(operand, temp) != N32·Order_eq){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + if(!N32·m.eq_zero(spill)){ + N32·m.deallocate(temp); + N32·m.deallocate(array); + return false; + } + + N32·m.deallocate(temp); + N32·m.deallocate(array); + return true; +} + + + +// Include the local section of N32.lib.c for testing +#define LOCAL +#include "N32.lib.c" +#undef LOCAL diff --git "a/tester/deprecated\360\237\226\211/test_N32.cli.c" "b/tester/deprecated\360\237\226\211/test_N32.cli.c" deleted file mode 100644 index 25451bb..0000000 --- "a/tester/deprecated\360\237\226\211/test_N32.cli.c" +++ /dev/null @@ -1,364 +0,0 @@ -#include -#include -#include -#include - -// Enable interface section -#define FACE -#include "N32.lib.c" -#undef FACE - -// Jump buffer for signal handling -static sigjmp_buf jump_buffer; - -// Signal handler for catching fatal errors -void signal_handler(int signal){ - siglongjmp(jump_buffer ,1); // Jump back to test_head on error -} - -// Test function prototypes -bool test_copy(); -bool test_bitwise_operations(); -bool test_comparisons(); -bool test_arithmetic(); -bool test_shifts(); - -// Test array (null-terminated) -typedef bool (*TestFunction)(); -typedef struct{ - TestFunction function; - const char *name; -}TestEntry; - -TestEntry test_list[] = { - {test_copy ,"test_copy"} - ,{test_bitwise_operations ,"test_bitwise_operations"} - ,{test_comparisons ,"test_comparisons"} - ,{test_arithmetic ,"test_arithmetic"} - ,{test_shifts ,"test_shifts"} - ,{NULL ,NULL} // Null termination -}; - -// The test runner -int test_head(){ - int pass_count = 0; - int fail_count = 0; - - // Set up signal handlers - signal(SIGSEGV ,signal_handler); // Catch segmentation faults - signal(SIGFPE ,signal_handler); // Catch floating point errors - signal(SIGABRT ,signal_handler); // Catch abort() calls - - for(TestEntry *entry = test_list; entry->function != NULL; entry++){ - if( sigsetjmp(jump_buffer ,1) == 0 ){ - // Run the test normally - if( !entry->function() ){ - printf("Failed: %s\n" ,entry->name); - fail_count++; - }else{ - pass_count++; - } - }else{ - // If a signal was caught - printf("Failed due to signaling: %s\n" ,entry->name); - fail_count++; - } - } - - printf("Tests passed: %d\n" ,pass_count); - printf("Tests failed: %d\n" ,fail_count); - return (fail_count == 0) ? 0 : 1; -} - -// Main function -int main(int argc ,char **argv){ - return test_head(); -} - -//------------------------------------------------------------------------------ -// Test Implementations -//------------------------------------------------------------------------------ - -bool test_copy(){ - // Allocate memory - N32·T *array = N32·m.allocate_array(2 ,NULL); - if( !array ) return false; - - // Access elements via access function - N32·T *a = N32·m.access(array ,0); - N32·T *b = N32·m.access(array ,1); - - // Assign value and copy - N32·m.from_uint32(a ,42); - N32·m.copy(b ,a); - - bool success = ( N32·m.compare(b ,a) == N32·Order_eq ); - N32·m.deallocate(array); - return success; -} - -bool test_arithmetic(){ - // Allocate memory - N32·T *array = N32·m.allocate_array(3 ,NULL); - if( !array ) return false; - - N32·T *a = N32·m.access(array ,0); - N32·T *b = N32·m.access(array ,1); - N32·T *result = N32·m.access(array ,2); - - N32·m.from_uint32(a ,20); - N32·m.from_uint32(b ,22); - - if( N32·m.add(result ,a ,b) != N32·Status·ok ) return false; - if( N32·m.compare(result ,N32·m.access(array ,0)) != N32·Order_gt ) return false; - - if( N32·m.subtract(result ,b ,a) != N32·Status·ok ) return false; - if( N32·m.compare(result ,N32·m.access(array ,0)) != N32·Order_lt ) return false; - - N32·m.deallocate(array); - return true; -} - -bool test_bitwise_operations(){ - // Allocate memory - N32·T *array = N32·m.allocate_array(3, NULL); - if(!array) return false; - - N32·T *a = N32·m.access(array, 0); - N32·T *b = N32·m.access(array, 1); - N32·T *result = N32·m.access(array, 2); - - // a = 0x0F0F0F0F, b = 0xF0F0F0F0 - N32·m.from_uint32(a, 0x0F0F0F0F); - N32·m.from_uint32(b, 0xF0F0F0F0); - - // bit_and => expect 0x00000000 - N32·m.bit_and(result, a, b); - N32·m.from_uint32(a, 0x00000000); - if(N32·m.compare(result, a) != N32·Order_eq){ - N32·m.deallocate(array); - return false; - } - - // Reset a to 0x0F0F0F0F for next tests - N32·m.from_uint32(a, 0x0F0F0F0F); - - // bit_or => expect 0xFFFFFFFF - N32·m.bit_or(result, a, b); - N32·m.from_uint32(b, 0xFFFFFFFF); - if(N32·m.compare(result, b) != N32·Order_eq){ - N32·m.deallocate(array); - return false; - } - - // bit_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F0 - N32·m.from_uint32(a, 0x0F0F0F0F); - N32·m.bit_complement(result, a); - N32·m.from_uint32(b, 0xF0F0F0F0); - if(N32·m.compare(result, b) != N32·Order_eq){ - N32·m.deallocate(array); - return false; - } - - // bit_twos_complement(a=0x0F0F0F0F) => expect 0xF0F0F0F1 - N32·m.from_uint32(a, 0x0F0F0F0F); - N32·m.bit_twos_complement(result, a); - N32·m.from_uint32(b, 0xF0F0F0F1); - if(N32·m.compare(result, b) != N32·Order_eq){ - N32·m.deallocate(array); - return false; - } - - N32·m.deallocate(array); - return true; -} - -bool test_comparisons(){ - // Allocate memory - N32·T *array = N32·m.allocate_array(3, NULL); - if(!array) return false; - - N32·T *a = N32·m.access(array, 0); - N32·T *b = N32·m.access(array, 1); - N32·T *c = N32·m.access(array, 2); - - // First set: a=0, b=42, c=42 - N32·m.from_uint32(a, 0); - N32·m.from_uint32(b, 42); - N32·m.from_uint32(c, 42); - - // eq_zero(a) => true - if(!N32·m.eq_zero(a)){ - N32·m.deallocate(array); - return false; - } - // eq_zero(b) => false - if(N32·m.eq_zero(b)){ - N32·m.deallocate(array); - return false; - } - // eq(b, c) => true - if(!N32·m.eq(b, c)){ - N32·m.deallocate(array); - return false; - } - // eq(a, b) => false - if(N32·m.eq(a, b)){ - N32·m.deallocate(array); - return false; - } - // compare(a, b) => N32·Order_lt - if(N32·m.compare(a, b) != N32·Order_lt){ - N32·m.deallocate(array); - return false; - } - // compare(b, a) => N32·Order_gt - if(N32·m.compare(b, a) != N32·Order_gt){ - N32·m.deallocate(array); - return false; - } - // compare(b, c) => N32·Order_eq - if(N32·m.compare(b, c) != N32·Order_eq){ - N32·m.deallocate(array); - return false; - } - // lt(a, b) => true, gt(b, a) => true - if(!N32·m.lt(a, b) || !N32·m.gt(b, a)){ - N32·m.deallocate(array); - return false; - } - - // Second set: a=100, b=50 - N32·m.from_uint32(a, 100); - N32·m.from_uint32(b, 50); - if(N32·m.compare(a, b) != N32·Order_gt){ - N32·m.deallocate(array); - return false; - } - // eq_zero(a) => false - if(N32·m.eq_zero(a)){ - N32·m.deallocate(array); - return false; - } - // eq_zero(b) => false - if(N32·m.eq_zero(b)){ - N32·m.deallocate(array); - return false; - } - - N32·m.deallocate(array); - return true; -} - -bool test_shifts(){ - // Allocate memory for operand, fill, spill - N32·T *array = N32·m.allocate_array(3, NULL); - if(!array) return false; - - N32·T *operand = N32·m.access(array, 0); - N32·T *fill = N32·m.access(array, 1); - N32·T *spill = N32·m.access(array, 2); - - // Subtest A: shift_left(4) with operand=1 => expect operand=16, fill=0, spill=0 - N32·m.from_uint32(operand, 1); - N32·m.from_uint32(fill, 0); - N32·m.from_uint32(spill, 0); - if(N32·m.shift_left(4, spill, operand, fill) != N32·Status·ok){ - N32·m.deallocate(array); - return false; - } - N32·T *temp = N32·m.allocate_array(1, NULL); - if(!temp){ - N32·m.deallocate(array); - return false; - } - N32·m.from_uint32(temp, 16); - if(N32·m.compare(operand, temp) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - if(N32·m.compare(fill, N32·zero) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - if(N32·m.compare(spill, N32·zero) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - - // Subtest B: shift_left(1) with operand=0x80000000 => expect operand=0, spill=1 - N32·m.from_uint32(operand, 0x80000000); - N32·m.from_uint32(fill, 0); - N32·m.from_uint32(spill, 0); - if(N32·m.shift_left(1, spill, operand, fill) != N32·Status·ok){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - if(!N32·m.eq_zero(operand)){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - N32·m.from_uint32(temp, 1); - if(N32·m.compare(spill, temp) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - - // Subtest C: shift_right(1) with operand=0x80000000 => expect operand=0x40000000, spill=0 - N32·m.from_uint32(operand, 0x80000000); - N32·m.from_uint32(fill, 0); - N32·m.from_uint32(spill, 0); - if(N32·m.shift_right(1, spill, operand, fill) != N32·Status·ok){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - N32·m.from_uint32(temp, 0x40000000); - if(N32·m.compare(operand, temp) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - if(!N32·m.eq_zero(spill)){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - - // Subtest D: arithmetic_shift_right(1) with operand=0x80000000 => expect operand=0xC0000000, spill=0 - N32·m.from_uint32(operand, 0x80000000); - N32·m.from_uint32(spill, 0); - if(N32·m.arithmetic_shift_right(1, operand, spill) != N32·Status·ok){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - N32·m.from_uint32(temp, 0xC0000000); - if(N32·m.compare(operand, temp) != N32·Order_eq){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - if(!N32·m.eq_zero(spill)){ - N32·m.deallocate(temp); - N32·m.deallocate(array); - return false; - } - - N32·m.deallocate(temp); - N32·m.deallocate(array); - return true; -} - - - -// Include the local section of N32.lib.c for testing -#define LOCAL -#include "N32.lib.c" -#undef LOCAL diff --git a/tester/document/build_procedure.org b/tester/document/build_procedure.org new file mode 100644 index 0000000..08c1e44 --- /dev/null +++ b/tester/document/build_procedure.org @@ -0,0 +1,50 @@ +#+TITLE: Tester Build Proceedure +#+AUTHOR: RT C Documentation + +*. To enter the tester environment: + + Be sure the installation is complete, and that tool_shared/third_party/RT-project-share has been installed. See the tool_shared/document🖉/install.txt + + #BEGIN{SRC} + > cd N # enter the project + > . env_tester # to inititialie the test environment + #END{SRC} + + After initializing the environment you will be in the `tester` directory. + +*. To build the tests from the first time: + + #BEGIN{SRC} + > release_pull + > make cli + #END{SRC} + +*. After editing header inclusion structure the dependency file must be rebuilt + + #BEGIN{SRC} + > make dependency + #END{SRC} + +*. To rebuild the tests after other edits + + #BEGIN{SRC} + > make cli + #END{SRC} + +*. To resample the release. + + See which directory the developer places our platform release files + + #BEGIN{SRC} + > release_dir + #END{SRC} + + See the files in the release directory, accepts same arguments as ls + + #BEGIN{SRC} + > release_ls -l + #END{SRC} + + Note that `release_dir` and `release_ls` are in the `RT-project-share` project mentioned in the first point. + + diff --git "a/tester/document\360\237\226\211/build_procedure.org" "b/tester/document\360\237\226\211/build_procedure.org" deleted file mode 100644 index 08c1e44..0000000 --- "a/tester/document\360\237\226\211/build_procedure.org" +++ /dev/null @@ -1,50 +0,0 @@ -#+TITLE: Tester Build Proceedure -#+AUTHOR: RT C Documentation - -*. To enter the tester environment: - - Be sure the installation is complete, and that tool_shared/third_party/RT-project-share has been installed. See the tool_shared/document🖉/install.txt - - #BEGIN{SRC} - > cd N # enter the project - > . env_tester # to inititialie the test environment - #END{SRC} - - After initializing the environment you will be in the `tester` directory. - -*. To build the tests from the first time: - - #BEGIN{SRC} - > release_pull - > make cli - #END{SRC} - -*. After editing header inclusion structure the dependency file must be rebuilt - - #BEGIN{SRC} - > make dependency - #END{SRC} - -*. To rebuild the tests after other edits - - #BEGIN{SRC} - > make cli - #END{SRC} - -*. To resample the release. - - See which directory the developer places our platform release files - - #BEGIN{SRC} - > release_dir - #END{SRC} - - See the files in the release directory, accepts same arguments as ls - - #BEGIN{SRC} - > release_ls -l - #END{SRC} - - Note that `release_dir` and `release_ls` are in the `RT-project-share` project mentioned in the first point. - - diff --git a/tester/tool/clean b/tester/tool/clean new file mode 100755 index 0000000..03d0380 --- /dev/null +++ b/tester/tool/clean @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tester/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + +cd "$REPO_HOME"/tester || exit 1 + +# remove test program dependency and objects + rm_na scratchpad/{makefile-cc.deps,*.o} || true + +# remove synthesized test sources + rm_na cc/test_*.c || true + +# remove built executables + rm_na -f machine/* || true + +set +x +echo "$(script_fn) done." diff --git a/tester/tool/env b/tester/tool/env new file mode 100644 index 0000000..355a02c --- /dev/null +++ b/tester/tool/env @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tool_shared/bespoke🖉/env" + error_bad_env=false + error_not_sourced=false + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + error_bad_env=true + fi + if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "$script_afp:: This script must be sourced, not executed." + error_not_sourced=true + fi + if $error_not_sourced; then exit 1; fi + if $error_bad_env; then return 1; fi + + +export ROLE=tester + +# so we can do the build + +export PATH=\ +"$REPO_HOME"/${ROLE}/tool🖉/\ +:"$PATH" + +# misc + + # make .githolder and .gitignore visible + alias ls="ls -a" + +# some feedback to show all went well + + export PROMPT_DECOR="$PROJECT_$ROLE" + export ENV=$(script_fp) + echo ENV "$ENV" + cd "$REPO_HOME/$ROLE" + + + diff --git a/tester/tool/make b/tester/tool/make new file mode 100755 index 0000000..f0949f7 --- /dev/null +++ b/tester/tool/make @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tester/tool🖉/env" + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 + fi + +set -e +set -x + + cd "$REPO_HOME"/tester || exit 1 + + pushd python + ./fill_template + popd + + /bin/make -f tool🖉/makefile $@ + +set +x +echo "$(script_fn) done." diff --git a/tester/tool/makefile b/tester/tool/makefile new file mode 100644 index 0000000..99161fd --- /dev/null +++ b/tester/tool/makefile @@ -0,0 +1,11 @@ + +RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release + +include $(RT-INCOMMON)/make/environment_RT_0 + +CFLAGS+= -g -O0 -Werror -include "$(RT-INCOMMON)/make/RT_0.h" +LINKFLAGS+= -l$(PROJECT) +LIBFILE=$(LIBDIR)/lib$(PROJECT).a + +include $(RT-INCOMMON)/make/targets_tester +-include $(DEPFILE) diff --git a/tester/tool/release_pull b/tester/tool/release_pull new file mode 100755 index 0000000..c79aca6 --- /dev/null +++ b/tester/tool/release_pull @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# Pulls the library and include files down from the project release directory. +# Writes a list of installed files to a log file, `scratchpad/release_files.log`, while +# assuming no simultaneous writes. + + +# input guards +env_must_be="tester/tool🖉/env" +if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 +fi + +cd "$REPO_HOME"/tester || exit 1 + +if [ ! -d scratchpad ]; then + echo "$(script_fp):: no scratchpad directory" + exit 1 +fi + +release_dir=$(release_dir) + +if [ ! -d "$release_dir" ]; then + echo "$(script_fp):: no release directory to pull install files from" + exit 1 +fi + +log_file="scratchpad/release_files.log" +: >> "$log_file" # Create and append to the log file + +# Copy release files and track them +if ! cp -f "$release_dir/libN.a" scratchpad && realpath scratchpad/libN.a >> "$log_file"; then + echo "$(script_fp):: warning: no libN.a found" >&2 +fi + +for file in "$release_dir"/*.lib.c; do + if [ -f "$file" ]; then + if cp -f "$file" cc; then + realpath "cc/$(basename "$file")" >> "$log_file" + else + echo "$(script_fp):: warning: failed to copy $file" >&2 + fi + else + echo "$(script_fp):: warning: skipping non-regular file $file" >&2 + fi +done + +echo "$(script_fn) done." diff --git a/tester/tool/release_remove b/tester/tool/release_remove new file mode 100755 index 0000000..9e91fa6 --- /dev/null +++ b/tester/tool/release_remove @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# Removes release files that were previously pulled. +# Reads `scratchpad/release_files.log` and removes each file using `rm_na`. + +# Input guards +env_must_be="tester/tool🖉/env" +if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + exit 1 +fi + +cd "$REPO_HOME"/tester || exit 1 + +log_file="scratchpad/release_files.log" + +# Ensure log file exists and is not empty +if [ ! -s "$log_file" ]; then + echo "$(script_fp):: no release log found, nothing to remove." >&2 + exit 0 +fi + +# Remove files listed in the log +while IFS= read -r file; do + if [ -f "$file" ]; then + rm_na "$file" + else + echo "$(script_fp):: warning: expected release file not found: $file" >&2 + fi +done < "$log_file" + +# Cleanup log file after successful removal +: > "$log_file" + +echo "$(script_fn) done." diff --git "a/tester/tool\360\237\226\211/clean" "b/tester/tool\360\237\226\211/clean" deleted file mode 100755 index 03d0380..0000000 --- "a/tester/tool\360\237\226\211/clean" +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="tester/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - -set -e -set -x - - -cd "$REPO_HOME"/tester || exit 1 - -# remove test program dependency and objects - rm_na scratchpad/{makefile-cc.deps,*.o} || true - -# remove synthesized test sources - rm_na cc/test_*.c || true - -# remove built executables - rm_na -f machine/* || true - -set +x -echo "$(script_fn) done." diff --git "a/tester/tool\360\237\226\211/env" "b/tester/tool\360\237\226\211/env" deleted file mode 100644 index 355a02c..0000000 --- "a/tester/tool\360\237\226\211/env" +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="tool_shared/bespoke🖉/env" - error_bad_env=false - error_not_sourced=false - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - error_bad_env=true - fi - if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then - echo "$script_afp:: This script must be sourced, not executed." - error_not_sourced=true - fi - if $error_not_sourced; then exit 1; fi - if $error_bad_env; then return 1; fi - - -export ROLE=tester - -# so we can do the build - -export PATH=\ -"$REPO_HOME"/${ROLE}/tool🖉/\ -:"$PATH" - -# misc - - # make .githolder and .gitignore visible - alias ls="ls -a" - -# some feedback to show all went well - - export PROMPT_DECOR="$PROJECT_$ROLE" - export ENV=$(script_fp) - echo ENV "$ENV" - cd "$REPO_HOME/$ROLE" - - - diff --git "a/tester/tool\360\237\226\211/make" "b/tester/tool\360\237\226\211/make" deleted file mode 100755 index f0949f7..0000000 --- "a/tester/tool\360\237\226\211/make" +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="tester/tool🖉/env" - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 - fi - -set -e -set -x - - cd "$REPO_HOME"/tester || exit 1 - - pushd python - ./fill_template - popd - - /bin/make -f tool🖉/makefile $@ - -set +x -echo "$(script_fn) done." diff --git "a/tester/tool\360\237\226\211/makefile" "b/tester/tool\360\237\226\211/makefile" deleted file mode 100644 index 99161fd..0000000 --- "a/tester/tool\360\237\226\211/makefile" +++ /dev/null @@ -1,11 +0,0 @@ - -RT-INCOMMON:=$(REPO_HOME)/tool_shared/third_party/RT-project-share/release - -include $(RT-INCOMMON)/make/environment_RT_0 - -CFLAGS+= -g -O0 -Werror -include "$(RT-INCOMMON)/make/RT_0.h" -LINKFLAGS+= -l$(PROJECT) -LIBFILE=$(LIBDIR)/lib$(PROJECT).a - -include $(RT-INCOMMON)/make/targets_tester --include $(DEPFILE) diff --git "a/tester/tool\360\237\226\211/release_pull" "b/tester/tool\360\237\226\211/release_pull" deleted file mode 100755 index c79aca6..0000000 --- "a/tester/tool\360\237\226\211/release_pull" +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# Pulls the library and include files down from the project release directory. -# Writes a list of installed files to a log file, `scratchpad/release_files.log`, while -# assuming no simultaneous writes. - - -# input guards -env_must_be="tester/tool🖉/env" -if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 -fi - -cd "$REPO_HOME"/tester || exit 1 - -if [ ! -d scratchpad ]; then - echo "$(script_fp):: no scratchpad directory" - exit 1 -fi - -release_dir=$(release_dir) - -if [ ! -d "$release_dir" ]; then - echo "$(script_fp):: no release directory to pull install files from" - exit 1 -fi - -log_file="scratchpad/release_files.log" -: >> "$log_file" # Create and append to the log file - -# Copy release files and track them -if ! cp -f "$release_dir/libN.a" scratchpad && realpath scratchpad/libN.a >> "$log_file"; then - echo "$(script_fp):: warning: no libN.a found" >&2 -fi - -for file in "$release_dir"/*.lib.c; do - if [ -f "$file" ]; then - if cp -f "$file" cc; then - realpath "cc/$(basename "$file")" >> "$log_file" - else - echo "$(script_fp):: warning: failed to copy $file" >&2 - fi - else - echo "$(script_fp):: warning: skipping non-regular file $file" >&2 - fi -done - -echo "$(script_fn) done." diff --git "a/tester/tool\360\237\226\211/release_remove" "b/tester/tool\360\237\226\211/release_remove" deleted file mode 100755 index 9e91fa6..0000000 --- "a/tester/tool\360\237\226\211/release_remove" +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# Removes release files that were previously pulled. -# Reads `scratchpad/release_files.log` and removes each file using `rm_na`. - -# Input guards -env_must_be="tester/tool🖉/env" -if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - exit 1 -fi - -cd "$REPO_HOME"/tester || exit 1 - -log_file="scratchpad/release_files.log" - -# Ensure log file exists and is not empty -if [ ! -s "$log_file" ]; then - echo "$(script_fp):: no release log found, nothing to remove." >&2 - exit 0 -fi - -# Remove files listed in the log -while IFS= read -r file; do - if [ -f "$file" ]; then - rm_na "$file" - else - echo "$(script_fp):: warning: expected release file not found: $file" >&2 - fi -done < "$log_file" - -# Cleanup log file after successful removal -: > "$log_file" - -echo "$(script_fn) done." diff --git a/tool/add_git_holder b/tool/add_git_holder new file mode 100755 index 0000000..0116b84 --- /dev/null +++ b/tool/add_git_holder @@ -0,0 +1,9 @@ +#!/bin/bash + +# Find empty directories and add a .githolder file +target_file=".githolder" + +find . -type d -empty -print0 | while IFS= read -r -d '' dir; do + touch "$dir/$target_file" + echo "Added $target_file to $dir" +done diff --git a/tool/env b/tool/env new file mode 100644 index 0000000..4f0c70f --- /dev/null +++ b/tool/env @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +# input guards + + env_must_be="tool_shared/bespoke/env" + error=false + if [ "$ENV" != "$env_must_be" ]; then + echo "$(script_fp):: error: must be run in the $env_must_be environment" + error=true + fi + if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "$script_afp:: This script must be sourced, not executed." + error=true + fi + if $error; then exit 1; fi + +export PATH=\ +"$REPO_HOME"/tool_shared/bespoke/\ +:"$PATH" + +# expose sneaky hidden files +alias ls="ls -a" + +# some feedback to show all went well + + export PROMPT_DECOR="$PROJECT"_administrator + export ENV=$(script_fp) + echo ENV "$ENV" diff --git a/tool_shared/bespoke/env b/tool_shared/bespoke/env new file mode 100644 index 0000000..917bda4 --- /dev/null +++ b/tool_shared/bespoke/env @@ -0,0 +1,137 @@ +#!/usr/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + echo "$script_afp:: This script must be sourced, not executed." + exit 1 +fi + +# without this bash takes non-matching globs literally +shopt -s nullglob + +# -------------------------------------------------------------------------------- +# project definition + +# actual absolute director path for this script file + + script_adp(){ + dirname "$script_afp" + } + +# assume this script is located $REPO_HOME/tools_shared/bespoke and work backwards +# to get $REPO_HOME, etc. + + REPO_HOME=$(dirname "$(dirname "$(script_adp)")") + echo REPO_HOME "$REPO_HOME" + + PROJECT=$(basename "$REPO_HOME") + echo PROJECT "$PROJECT" + + # set the prompt decoration to the name of the project + PROMPT_DECOR=$PROJECT + + export REPO_HOME PROJECT PROMPT_DECOR + +# -------------------------------------------------------------------------------- +# RT_gcc +# note also PATH entry + + export RT_gcc=/home/Thomas/subu_data/developer/N/tool_shared/customized/RT_gcc + export LIBRARY_PATH=$RT_gcc/lib + export C_INCLUDE_PATH=$RT_gcc/include + export LD_LIBRARY_PATH=$RT_gcc/lib + +# -------------------------------------------------------------------------------- +# Other Tool roots +# + export JAVA_HOME="$REPO_HOME/tool_shared/third_party/jdk-23.0.1" + export MOSAIC_HOME="$REPO_HOME/tool_shared/third_party/Mosaic" + + +# -------------------------------------------------------------------------------- +# PATH +# precedence: last defined, first discovered + + PATH="$REPO_HOME/tool_shared/third_party/RT-project-share/release/bash:$PATH" + PATH="$REPO_HOME/tool_shared/third_party/RT-project-share/release/amd64:$PATH" + PATH="$REPO_HOME/tool_shared/third_party/emacs/bin:$PATH" + PATH="$REPO_HOME/tool_shared/third_party/idea-IC-243.21565.193/bin:$PATH" + PATH="$REPO_HOME/tool_shared/third_party:$PATH" + PATH="$RT_gcc"/bin:"$PATH" + PATH="$REPO_HOME/tool_shared/customized:$PATH" + PATH="$REPO_HOME"/tool_shared/bespoke🖉:"$PATH" + + # Remove duplicates + clean_path() { + PATH=$(echo ":$PATH" | awk -v RS=: -v ORS=: '!seen[$0]++' | sed 's/^://; s/:$//') + } + clean_path + export PATH + +# -------------------------------------------------------------------------------- +# the following functions are provided for other scripts to use. +# at the top of files that make use of these functions put the following line: +# script_afp=$(realpath "${BASH_SOURCE[0]}") +# + + ## script's filename + script_fn(){ + basename "$script_afp" + } + + ## script's dirpath relative to $REPO_HOME + script_fp(){ + realpath --relative-to="${REPO_HOME}" "$script_afp" + } + + ## script's dirpath relative to $REPO_HOME + script_dp(){ + dirname "$(script_fp)" + } + + export -f script_adp script_fn script_dp script_fp + +#-------------------------------------------------------------------------------- +# used by release scripts +# + + install_file() { + if [ "$#" -lt 3 ]; then + echo "env::install_file usage: install_file ... " + return 1 + fi + + perms="${@: -1}" # Last argument is permissions + target_dp="${@: -2:1}" # Second-to-last argument is the target directory + sources=("${@:1:$#-2}") # All other arguments are source files + + if [ ! -d "$target_dp" ]; then + echo "env::install_file no install done: target directory '$target_dp' does not exist." + return 1 + fi + + for source_fp in "${sources[@]}"; do + if [ ! -f "$source_fp" ]; then + echo "env::install_file: source file '$source_fp' does not exist." + return 1 + fi + + target_file="$target_dp/$(basename "$source_fp")" + + if ! install -m "$perms" "$source_fp" "$target_file"; then + echo "env::install_file: Failed to install $(basename "$source_fp") to $target_dp" + return 1 + else + echo "env::install_file: installed $(basename "$source_fp") to $target_dp with permissions $perms" + fi + done + } + + export -f install_file + +# -------------------------------------------------------------------------------- +# closing +# + + export ENV=$(script_fp) + echo ENV "$ENV" + diff --git a/tool_shared/bespoke/version b/tool_shared/bespoke/version new file mode 100755 index 0000000..5934da2 --- /dev/null +++ b/tool_shared/bespoke/version @@ -0,0 +1,5 @@ +#!/bin/env bash +script_afp=$(realpath "${BASH_SOURCE[0]}") + +echo "N v0.1 2025-02-17" + diff --git "a/tool_shared/bespoke\360\237\226\211/env" "b/tool_shared/bespoke\360\237\226\211/env" deleted file mode 100644 index 917bda4..0000000 --- "a/tool_shared/bespoke\360\237\226\211/env" +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") -if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then - echo "$script_afp:: This script must be sourced, not executed." - exit 1 -fi - -# without this bash takes non-matching globs literally -shopt -s nullglob - -# -------------------------------------------------------------------------------- -# project definition - -# actual absolute director path for this script file - - script_adp(){ - dirname "$script_afp" - } - -# assume this script is located $REPO_HOME/tools_shared/bespoke and work backwards -# to get $REPO_HOME, etc. - - REPO_HOME=$(dirname "$(dirname "$(script_adp)")") - echo REPO_HOME "$REPO_HOME" - - PROJECT=$(basename "$REPO_HOME") - echo PROJECT "$PROJECT" - - # set the prompt decoration to the name of the project - PROMPT_DECOR=$PROJECT - - export REPO_HOME PROJECT PROMPT_DECOR - -# -------------------------------------------------------------------------------- -# RT_gcc -# note also PATH entry - - export RT_gcc=/home/Thomas/subu_data/developer/N/tool_shared/customized/RT_gcc - export LIBRARY_PATH=$RT_gcc/lib - export C_INCLUDE_PATH=$RT_gcc/include - export LD_LIBRARY_PATH=$RT_gcc/lib - -# -------------------------------------------------------------------------------- -# Other Tool roots -# - export JAVA_HOME="$REPO_HOME/tool_shared/third_party/jdk-23.0.1" - export MOSAIC_HOME="$REPO_HOME/tool_shared/third_party/Mosaic" - - -# -------------------------------------------------------------------------------- -# PATH -# precedence: last defined, first discovered - - PATH="$REPO_HOME/tool_shared/third_party/RT-project-share/release/bash:$PATH" - PATH="$REPO_HOME/tool_shared/third_party/RT-project-share/release/amd64:$PATH" - PATH="$REPO_HOME/tool_shared/third_party/emacs/bin:$PATH" - PATH="$REPO_HOME/tool_shared/third_party/idea-IC-243.21565.193/bin:$PATH" - PATH="$REPO_HOME/tool_shared/third_party:$PATH" - PATH="$RT_gcc"/bin:"$PATH" - PATH="$REPO_HOME/tool_shared/customized:$PATH" - PATH="$REPO_HOME"/tool_shared/bespoke🖉:"$PATH" - - # Remove duplicates - clean_path() { - PATH=$(echo ":$PATH" | awk -v RS=: -v ORS=: '!seen[$0]++' | sed 's/^://; s/:$//') - } - clean_path - export PATH - -# -------------------------------------------------------------------------------- -# the following functions are provided for other scripts to use. -# at the top of files that make use of these functions put the following line: -# script_afp=$(realpath "${BASH_SOURCE[0]}") -# - - ## script's filename - script_fn(){ - basename "$script_afp" - } - - ## script's dirpath relative to $REPO_HOME - script_fp(){ - realpath --relative-to="${REPO_HOME}" "$script_afp" - } - - ## script's dirpath relative to $REPO_HOME - script_dp(){ - dirname "$(script_fp)" - } - - export -f script_adp script_fn script_dp script_fp - -#-------------------------------------------------------------------------------- -# used by release scripts -# - - install_file() { - if [ "$#" -lt 3 ]; then - echo "env::install_file usage: install_file ... " - return 1 - fi - - perms="${@: -1}" # Last argument is permissions - target_dp="${@: -2:1}" # Second-to-last argument is the target directory - sources=("${@:1:$#-2}") # All other arguments are source files - - if [ ! -d "$target_dp" ]; then - echo "env::install_file no install done: target directory '$target_dp' does not exist." - return 1 - fi - - for source_fp in "${sources[@]}"; do - if [ ! -f "$source_fp" ]; then - echo "env::install_file: source file '$source_fp' does not exist." - return 1 - fi - - target_file="$target_dp/$(basename "$source_fp")" - - if ! install -m "$perms" "$source_fp" "$target_file"; then - echo "env::install_file: Failed to install $(basename "$source_fp") to $target_dp" - return 1 - else - echo "env::install_file: installed $(basename "$source_fp") to $target_dp with permissions $perms" - fi - done - } - - export -f install_file - -# -------------------------------------------------------------------------------- -# closing -# - - export ENV=$(script_fp) - echo ENV "$ENV" - diff --git "a/tool_shared/bespoke\360\237\226\211/version" "b/tool_shared/bespoke\360\237\226\211/version" deleted file mode 100755 index 5934da2..0000000 --- "a/tool_shared/bespoke\360\237\226\211/version" +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -echo "N v0.1 2025-02-17" - diff --git a/tool_shared/document/install.txt b/tool_shared/document/install.txt new file mode 100644 index 0000000..93d2b2b --- /dev/null +++ b/tool_shared/document/install.txt @@ -0,0 +1,65 @@ + +---------------------------------------- +for downloads of tar files etc. for third party tools : + + drwx------. 1 Thomas-developer Thomas-developer 354 2024-12-09 02:45 upstream + +---------------------------------------- +generally when installing third party tools from a repo + + . env_administrator + cd tools_shared/third_party + git clone + cd project + +---------------------------------------- +RT-project-share + + lrwxrwxrwx. 1 Thomas-developer Thomas-developer 45 2025-01-22 06:29 RT-project-share -> /home/Thomas-masu/developer/RT-project-share/ + + lrwxrwxrwx. 1 Thomas-developer Thomas-developer 41 2025-01-22 06:29 emacs_30.0.92 -> /home/Thomas-masu/developer/emacs_30.0.92 + +---------------------------------------- +emacs + + lrwxrwxrwx. 1 Thomas-developer Thomas-developer 41 2025-01-22 06:29 emacs_30.0.92 -> /home/Thomas-masu/developer/emacs_30.0.92 + + Usually I'm running a shell inside of emacs, so I have already run + emacs before arriving at the project. + + There was a reason for the local project version of emacs, but I forget what it was. + Perhaps need for a newer version? It is not otherwise integrated into the project. + +---------------------------------------- +gcc + + I modified cpp to add #pragma macro(name ,body) + + Where `name` is expanded and the fist token used as the nane of the macro. + + `body` is also expanded. If 'name' appears in it, then it will be expanded with + its old definition (prior to running `#pragma macro(name ,body). + + If name already exists in the symbol table, it is updated with the new macro definition. + + To install: + + make sure `pragma_macro` project is installed and built. This provides gcc + to multiple projects, so it is at the top level ~/pragma_macro. + + + RT_gcc=/home/Thomas/subu_data/developer/N/tool_shared/customized/RT_gcc + + ln -s /home/Thomas/subu_data/developer/RT_gcc/toolchain $RT_gcc + + PATH="$RT_gcc":"$PATH" + export PATH=$RT_gcc:$PATH + export LIBRARY_PATH=$RT_gcc/lib + export C_INCLUDE_PATH=$RT_gcc/include + export LD_LIBRARY_PATH=$RT_gcc/lib + + + + + + diff --git "a/tool_shared/document\360\237\226\211/install.txt" "b/tool_shared/document\360\237\226\211/install.txt" deleted file mode 100644 index 93d2b2b..0000000 --- "a/tool_shared/document\360\237\226\211/install.txt" +++ /dev/null @@ -1,65 +0,0 @@ - ----------------------------------------- -for downloads of tar files etc. for third party tools : - - drwx------. 1 Thomas-developer Thomas-developer 354 2024-12-09 02:45 upstream - ----------------------------------------- -generally when installing third party tools from a repo - - . env_administrator - cd tools_shared/third_party - git clone - cd project - ----------------------------------------- -RT-project-share - - lrwxrwxrwx. 1 Thomas-developer Thomas-developer 45 2025-01-22 06:29 RT-project-share -> /home/Thomas-masu/developer/RT-project-share/ - - lrwxrwxrwx. 1 Thomas-developer Thomas-developer 41 2025-01-22 06:29 emacs_30.0.92 -> /home/Thomas-masu/developer/emacs_30.0.92 - ----------------------------------------- -emacs - - lrwxrwxrwx. 1 Thomas-developer Thomas-developer 41 2025-01-22 06:29 emacs_30.0.92 -> /home/Thomas-masu/developer/emacs_30.0.92 - - Usually I'm running a shell inside of emacs, so I have already run - emacs before arriving at the project. - - There was a reason for the local project version of emacs, but I forget what it was. - Perhaps need for a newer version? It is not otherwise integrated into the project. - ----------------------------------------- -gcc - - I modified cpp to add #pragma macro(name ,body) - - Where `name` is expanded and the fist token used as the nane of the macro. - - `body` is also expanded. If 'name' appears in it, then it will be expanded with - its old definition (prior to running `#pragma macro(name ,body). - - If name already exists in the symbol table, it is updated with the new macro definition. - - To install: - - make sure `pragma_macro` project is installed and built. This provides gcc - to multiple projects, so it is at the top level ~/pragma_macro. - - - RT_gcc=/home/Thomas/subu_data/developer/N/tool_shared/customized/RT_gcc - - ln -s /home/Thomas/subu_data/developer/RT_gcc/toolchain $RT_gcc - - PATH="$RT_gcc":"$PATH" - export PATH=$RT_gcc:$PATH - export LIBRARY_PATH=$RT_gcc/lib - export C_INCLUDE_PATH=$RT_gcc/include - export LD_LIBRARY_PATH=$RT_gcc/lib - - - - - - diff --git "a/tool\360\237\226\211/add_git_holder" "b/tool\360\237\226\211/add_git_holder" deleted file mode 100755 index 0116b84..0000000 --- "a/tool\360\237\226\211/add_git_holder" +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -# Find empty directories and add a .githolder file -target_file=".githolder" - -find . -type d -empty -print0 | while IFS= read -r -d '' dir; do - touch "$dir/$target_file" - echo "Added $target_file to $dir" -done diff --git "a/tool\360\237\226\211/env" "b/tool\360\237\226\211/env" deleted file mode 100644 index 4f0c70f..0000000 --- "a/tool\360\237\226\211/env" +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env bash -script_afp=$(realpath "${BASH_SOURCE[0]}") - -# input guards - - env_must_be="tool_shared/bespoke/env" - error=false - if [ "$ENV" != "$env_must_be" ]; then - echo "$(script_fp):: error: must be run in the $env_must_be environment" - error=true - fi - if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then - echo "$script_afp:: This script must be sourced, not executed." - error=true - fi - if $error; then exit 1; fi - -export PATH=\ -"$REPO_HOME"/tool_shared/bespoke/\ -:"$PATH" - -# expose sneaky hidden files -alias ls="ls -a" - -# some feedback to show all went well - - export PROMPT_DECOR="$PROJECT"_administrator - export ENV=$(script_fp) - echo ENV "$ENV"