From: Thomas Walker Lynch Date: Wed, 26 Mar 2025 10:08:44 +0000 (+0000) Subject: adding cpp extentions as per cpp magic X-Git-Url: https://git.reasoningtechnology.com/style/static/git-logo.png?a=commitdiff_plain;h=88b5975b129deec2b750d0af594a1a7b13bfaac7;p=N adding cpp extentions as per cpp magic --- diff --git "a/developer/cc\360\237\226\211/Core.lib.c" "b/developer/cc\360\237\226\211/Core.lib.c" index a14ec2e..3e78126 100644 --- "a/developer/cc\360\237\226\211/Core.lib.c" +++ "b/developer/cc\360\237\226\211/Core.lib.c" @@ -17,6 +17,9 @@ */ #define Core·DEBUG +#ifdef FG·DEBUG + #include +#endif #ifndef FACE #define Core·IMPLEMENTATION @@ -126,6 +129,38 @@ else return Core·Status·on_track; #define Core·Guard·assert(chk) assert(!chk.flag); + //---------------------------------------- + // Macro to call a function in the FG table with debug checks + // Usage: FG·call(tm, function_name, arg1, arg2, ...) + // Expands to: ((tm)->fg->function_name)((tm)->t, arg1, arg2, ...) + // With debug checks for NULL pointers when FG·DEBUG is defined + //---------------------------------------- + + typedef struct FG·FG; + typedef struct FG·Tableau; + + typedef struct{ + FG·FG *fg; + FG·Tableau *tableau; + } FG·Binding; + + inline void FG·wellformed_binding(FG·Binding b) { + #ifdef FG·DEBUG + Core·Guard·init_count(chk); + Core·Guard·fg.check(&chk, 1, b->fg, "NULL fg table"); + Core·Guard·fg.check(&chk, 1, b->tableau, "NULL tableau"); + Core·Guard·assert(chk); + #endif + } + + // note the use of the comma operator to return the result from b.fg->fn + #define FG·call(b, fn, ...) \ + ( \ + FG·wellformed_binding(b) \ + ,b.fg->fn(b.tableau, ##__VA_ARGS__ ) \ + ) + + //---------------------------------------- // functions interface //---------------------------------------- @@ -141,16 +176,13 @@ } Core·F; Local Core·F Core·f; +#endif // FACE + //-------------------------------------------------------------------------------- // Implementation #ifdef Core·IMPLEMENTATION - // declarations available to all of the IMPLEMENTATION go here - // - #ifdef Core·DEBUG - #include - #endif //-------------------------------------------------------------------------------- // implementation to go into the lib.a file diff --git "a/developer/cc\360\237\226\211/FG.lib.c" "b/developer/cc\360\237\226\211/FG.lib.c" new file mode 100644 index 0000000..566460e --- /dev/null +++ "b/developer/cc\360\237\226\211/FG.lib.c" @@ -0,0 +1,96 @@ +/* +Template parameters: + +FG·Type - Type of FG table, will be used to name the binding struct. + +Note that template variables are _use once_ per #include. (They are #undef at the bottom of this file.) + +*/ + +#ifndef FACE +#define FG·IMPLEMENTATION +#define FACE +#endif + +//-------------------------------------------------------------------------------- +// Interface + +#ifndef Ξ(FG·FACE ,FG·Type) +#define Ξ(FG·FACE ,FG·Type) + + + #define FG·DEBUG + #ifdef FG·DEBUG + #include + #endif + + #define FG·ALL ( defined(FG·Type) ) + #define FG·NONE ( !defined(FG·Type) ) + #if !( FG·ALL || FG·NONE ) + #error "FG template inconsistency: must define all or none of: FG·Type" + #endif + + //---------------------------------------- + // Macro to call a function in the FG table with debug checks + // Usage: FG·call(tm, function_name, arg1, arg2, ...) + // Expands to: (tm.fg->function_name)((tm)->t, arg1, arg2, ...) + // With debug checks for NULL pointers when FG·DEBUG is defined + //---------------------------------------- + #if FG·ALL + + //#define ALL_VAL V0··V1··V2 ... + // the double cdot underscore non aliasing across identifiers + #define FG·ALL_VAL FG·Type + // FG is not yet a type, so we don't have this + // #define FG_t Ξ(FG_t ,FG·ALL_VAL) + + // a simplifying naming convention + #define FG·Binding Ξ(FG·Type) + #define FG·FG Ξ(FG·Type ,FG) + #define FG·Tableau Ξ(FG·Type ,Tableau) + + // as a convention, we name the binding after the type + typedef struct{ + FG·FG *fg; + FG·Tableau *tableau; + } FG·Binding; + + inline void FG·wellformed_binding(FG·Binding b){ + #ifdef FG·DEBUG + FG·Guard·init_count(chk); + FG·Guard·fg.check(&chk, 1, b.fg, "NULL fg table"); + FG·Guard·fg.check(&chk, 1, b.tableau, "NULL tableau"); + FG·Guard·assert(chk); + #endif + } + + // note the use of the comma operator to return the result from the b.fg->fn call + #define FG·call(b, fn, ...) \ + ( FG·wellformed_binding(b) ,b.fg->fn(b.tableau, ##__VA_ARGS__) ) + + #endif + +#endif // FACE + +//-------------------------------------------------------------------------------- +// Implementation + +#ifdef FG·IMPLEMENTATION + + //---------------------------------------- + // implementation to go into the lib.a file + //---------------------------------------- + #ifndef LOCAL + #endif //#ifndef LOCAL + + //---------------------------------------- + // implementation to go at the bottom of the source file + //---------------------------------------- + #ifdef LOCAL + #endif // #ifdef LOCAL + +#endif // IMPLEMENTATION + +// template variables are use once +#undef FG·Type + diff --git "a/developer/cc\360\237\226\211/TM.lib.c" "b/developer/cc\360\237\226\211/TM.lib.c" index 35a9ded..f748db6 100644 --- "a/developer/cc\360\237\226\211/TM.lib.c" +++ "b/developer/cc\360\237\226\211/TM.lib.c" @@ -29,33 +29,44 @@ */ #define TM·DEBUG +#ifdef TM·DEBUG + #include +#endif + +#define TM·ALL ( defined(CVT) ) // ... && defined( ... +#define TM·NONE ( !defined(CVT) ) +#if !( TM·ALL || TM·NONE ) + #error "TM template inconsistency: must define all or none of: CVT" +#endif #ifndef FACE #define TM·IMPLEMENTATION #define FACE #endif -#if defined(Array) && !defined(CVT) - #error "Array implementation requires CVT to be defined" -#endif - - //-------------------------------------------------------------------------------- -// Interface +// Interface - always included + +#if TM·ALL + #define TM·ALL_VAL = CVT + #define TM_t Ξ(TM ,TM·ALL_VAL) +#endif -#ifndef Ξ(TM·FACE ,CVT) -#define Ξ(TM·FACE ,CVT) +#ifndef Ξ(TM ,FACE) +#define Ξ(TM ,FACE) + #include #include #include "Core.lib.c" + #include "FG.lib.c" //---------------------------------------- // Tape Machine interface //---------------------------------------- - #ifndef CVT + #if TM·NONE typedef enum{ TM·Tape·Topo·mu = 0 ,TM·Tape·Topo·empty = 1 @@ -88,81 +99,72 @@ | TM·Head·Status·rightmost ; - #endif // #ifndef CVT - #ifdef CVT + #if TM·All + // TM··Tableau + typedef struct Ξ(TM ,Tableau); + + // create an FG·Binding so that FG·call will work + #define FG·Type TM + #include "FG.lib.c" + #undef FG·Type + + // extent is an index, hence its effect is a function of CVT typedef Ξ(extent_t ,CVT) size_t; - // instance struct with vtable pointer as first entry - // tape and area are included with Tape Machine to facilitate abstract interfaces. typedef struct{ - TM·Tape·Topo (*Tape·topo)(TM *tm); - bool (*Tape·bounded)(TM *tm); + TM·Tape·Topo (*Tape·topo)(TM tm); + bool (*Tape·bounded)(TM tm); - TM·Head·Status (*Head·status)(TM *tm ,TM·Head·Status *status); - bool (*Head·on_tape)(TM *tm); - bool (*Head·on_leftmost) (TM *tm); - bool (*Head·on_rightmost)(TM *tm); + TM·Head·Status (*Head·status)(TM tm); + bool (*Head·on_tape)(TM tm); + bool (*Head·on_leftmost) (TM tm); + bool (*Head·on_rightmost)(TM tm); // tape machine functions - Core·Status (*mount) (TM *tm); - Core·Status (*dismount)(TM *tm); + Core·Status (*mount) (TM tm); + Core·Status (*dismount)(TM tm); - void (*step) (TM *tm); - void (*step_left) (TM *tm); - void (*rewind) (TM *tm); + void (*step) (TM tm); + void (*step_left) (TM tm); + void (*rewind) (TM tm); TM·FG TM·fg; // points to TM·FG instance - Ξ(extent_t ,CVT) (*extent)(TM *tm); - CVT (*read) (TM *tm); - void (*write)(TM *tm ,CVT *remote_pt); - - } Ξ(TM ,CVT)·FG; + Ξ(extent_t ,CVT) (*extent)(TM tm); + CVT (*read) (TM tm); + void (*write)(TM tm ,CVT *remote_pt); - // array FG instance - - typedef struct Ξ(TM ,CVT)·Tableau; - typedef struct Ξ(TM·Array ,CVT)·Tableau; + } Ξ(TM ,FG); - // `init` puts type consistent values in this struct - typedef struct{ - Ξ(TM ,CVT)·FG *fg; - Ξ(TM ,CVT)·Tableau *t; - } Ξ(TM ,CVT); - - #define FG·call(tm, fn, ...) \ - ((tm)->fg->fn)((tm)->t, ##__VA_ARGS__) + //---------------------------------------- + // Array interface + //---------------------------------------- - Ξ(TM ,CVT)·FG Ξ(TM·Array ,CVT)·fg; + typedef struct Ξ(TM ,Array)·Tableau; - Ξ(TM ,CVT) Ξ(TM·Array ,CVT)·init_pe( - Ξ(TM·Array ,CVT)·Tableau t + TM Ξ(TM ,Array)·init_pe( + Ξ(TM ,Array)·Tableau *t ,CVT position[] ,Ξ(extent_t ,CVT) extent ); - Ξ(TM ,CVT) Ξ(TM·Array ,CVT)·init_pp( - Ξ(TM·Array ,CVT)·Tableau t + TM Ξ(TM ,Array)·init_pp( + Ξ(TM ,Array)·Tableau *t ,CVT *position_left ,CVT *position_right ); #endif // #ifdef CVT -#endif +#endif // FACE //-------------------------------------------------------------------------------- // Implementation #ifdef TM·IMPLEMENTATION - // declarations available to all of the IMPLEMENTATION go here - // - #ifdef TM·DEBUG - #include - #endif // implementation to go into the lib.a file // @@ -187,34 +189,6 @@ const char *TM·Msg·result="given NULL result pointer"; const char *TM·Msg·head="head not on tape"; - //---------------------------------------- - // TM Tableau, not CVT differentiated - - struct{ - void *hd; - void *position; - }TM·Tableau; - - - //---------------------------------------- - // TM Array implementation, not CVT differentiated - - TM·Tape·Topo TM·Array·Tape·topo(TM·Tableau *t){ - if(!t || !t->position) return T·Tape·Topo·mu; - if(t->extent == 0) TM·Tape·Topo·singleton; - return TM·Tape·Topo·segment; - } - Local TM·Tape·Topo TM·Tape·bounded(TM·Tableau *t){ - return TM·tape_top(t) & TM·Tape·Topo·bounded; - } - - TM·Tape·Topo TM·Array·Tape·mount(TM·Tableau *t){ - if(!t || !t->position) return T·Tape·Topo·mu; - if(t->extent == 0) TM·Tape·Topo·singleton; - return TM·Tape·Topo·segment; - } - - //----------------------------------- // generic call wrappers @@ -374,15 +348,37 @@ #ifdef CVT - struct{ + typedef struct Ξ(TM ,CVT)·Tableau; + + typedef struct{ CVT *hd; CVT *position; Ξ(extent_t ,CVT) extent; - }Ξ(TM·Array ,CVT); + }Ξ(TM·Array ,CVT)·Tableau; //----------------------------------- + // TM·Array.tape implementation + //---------------------------------------- + // TM Array implementation, not CVT differentiated + + Local TM·Tape·Topo TM·Array·Tape·topo( Ξ(TM ,CVT)·Tableau *tableau ){ + Ξ(TM·Array ,CVT)·Tableau *t = (Ξ(TM·Array ,CVT)·Tableau *)tableau; + if(!t || !t->position) return T·Tape·Topo·mu; + if(t->extent == 0) TM·Tape·Topo·singleton; + return TM·Tape·Topo·segment; + } + Local TM·Tape·Topo TM·Tape·bounded(TM·Tableau *t){ + return TM·tape_top(t) & TM·Tape·Topo·bounded; + } + + TM·Tape·Topo TM·Array·Tape·mount(TM·Tableau *t){ + if(!t || !t->position) return T·Tape·Topo·mu; + if(t->extent == 0) TM·Tape·Topo·singleton; + return TM·Tape·Topo·segment; + } + // For an Array Tape Machine ,a bound tape will be singleton or segment. TM·Tape·Topo Ξ(TM·Array ,CVT)·Tape·topo(Ξ(TM·Array ,CVT) *tm){ if(!tm || !tm->position) return TM·Tape·Topo·mu; diff --git "a/developer/document\360\237\226\211/cpp.org" "b/developer/document\360\237\226\211/cpp.org" new file mode 100644 index 0000000..3d26734 --- /dev/null +++ "b/developer/document\360\237\226\211/cpp.org" @@ -0,0 +1,123 @@ +#+TITLE: Advanced cpp Macro Handling: Twions and Emptiness +#+AUTHOR: Eos +#+DATE: 2025-03-26 + +* Introduction + +Twions extend the capability of the C preprocessor (cpp) by introducing two-dimensional structures analogous to complex numbers in mathematics, effectively managing cases originally designed for single-dimensional values. + +This document builds upon concepts and techniques inspired by [[https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h][cpp_magic.h]] and the tutorial [[http://jhnet.co.uk/articles/cpp_magic][cpp_magic]] by Jonathan Heathcote. + +* Key Concepts for Header Comments + +The following comments are recommended for inclusion in the header section of the `cpp_extensions.txt` file: + +#+BEGIN_SRC c +/* + Inspired by: + - https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h + - Jonathan Heathcote's tutorial: http://jhnet.co.uk/articles/cpp_magic + + Twions: Pairs of items used in macros designed for single-item arguments, + analogous to complex numbers in mathematics. + + Key Concepts: + - Token pasting (`##`) concatenates tokens literally without macro expansion. + - Empty arguments (`__VA_ARGS__`) are distinct from omitted arguments and + require careful handling through intermediate macros. + - Macros requiring single arguments typically end with `_item`. + - Private identifiers and macros begin with an underscore (`_`). +*/ +#+END_SRC + +* Detailed Explanation and Clarifications + +** Token Concatenation (`##`) and Macro Expansion + +The `##` operator directly concatenates tokens without expanding their arguments first. For example: + +#+BEGIN_SRC c +#define cat(x,y) x##y +#define xx 3 +#define yy 5 + +cat(xx,yy) // expands to xxyy, not 35 +#+END_SRC + +To correctly handle token pasting with potentially empty arguments, intermediate macros must be used to avoid literal empty tokens: + +Incorrect (direct): +#+BEGIN_SRC c +#define IS_EMPTY_ITEM(x_item) _IS_EMPTY_2(_TWION_##x_item) +#+END_SRC + +Correct (using intermediate macro): +#+BEGIN_SRC c +#define _IS_EMPTY_1(x_item) _IS_EMPTY_2(_TWION_##x_item) +#define IS_EMPTY_ITEM(x_item) _IS_EMPTY_1(x_item) +#+END_SRC + +** Function Macro Syntax + +Macro names must directly precede their argument lists without spacing: + +Correct: +#+BEGIN_SRC c +#define sum(p ,q ,r) (p + q + r) +#+END_SRC + +Incorrect (defines object-like macro): +#+BEGIN_SRC c +#define sum (p ,q ,r) (p + q + r) +#+END_SRC + +** Grammar and Special Items + +- ~empty_item~: A position in a macro argument list explicitly empty but still counted. +- ~shim_item~ (`~,1`): A two-token item acting as one unit, shifting indexing for variadic macros. + +** Logic Macros and Conventions + +- Boolean logic: `True` = 1, `False` = 0. +- Single-item arguments end with `_item` to enforce intended usage. + +* Handling Empty Arguments and Lists + +** Empty Argument Detection + +Variadic macros may contain empty elements (e.g., `a ,b , ,d`). This complicates emptiness checks. Direct argument count overloads are impossible with standard cpp. + +A robust method to handle emptiness: + +#+BEGIN_SRC c +#define SECOND_1(a ,b ,...) b +#define SECOND(...) SECOND_1(__VA_ARGS__, pad) +#+END_SRC + +Even if `__VA_ARGS__` is empty, it ensures a safe fallback (`pad`). + +** Differentiating Empty and Non-Empty Arguments + +To clearly differentiate empty from non-empty arguments, use: + +- **Peek-a-Boo Macro Call**: +#+BEGIN_SRC c +macro __VA_ARGS__ () +#+END_SRC + + - Empty: Calls `macro()`. + - Non-empty: Results in unintended macro calls, signaling arguments are present. + +- **Rewrite Rule Approach**: +#+BEGIN_SRC c +#define rewrite_rule new_value +rewrite##__VA_ARGS__##rule +#+END_SRC + + - Empty arguments yield `rewrite_rule` → `new_value`. + - Non-empty arguments clearly differ, showing the presence of content. + +* Future Integration + +Recursion handling methods from [[https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h][cpp_magic.h]] will also be integrated into future expansions of this macro suite. + diff --git "a/developer/document\360\237\226\211/cpp.txt" "b/developer/document\360\237\226\211/cpp.txt" new file mode 100644 index 0000000..3896b03 --- /dev/null +++ "b/developer/document\360\237\226\211/cpp.txt" @@ -0,0 +1,184 @@ + +The twions do for cpp what complex numbers do for mathematics. A two dimensional value used with a structure designed for one dimensional values. + +/* +Code in this file is based on: https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h +see tutorial at: http://jhnet.co.uk/articles/cpp_magic + +---------------------------------------- +1. Issues + +1.1 Empty argument name is still a name + + `##` arguments are not evaluated so, for example: + ``` + #define cat(x,y) x##y + #define xx 3 + #define yy 5 + cat(xx,yy) --> xxyy + ``` + xx and yy are not rewritten. + + For my cpp with an empty __VAR_ARGS__ is still acting like it exists with a##__VAR_ARGS__ as though it expands out to a##. To make the empty args empty, we must pass through from a macro that does not use `##` on them. I guess this also applies to + other empty arguments. Thus is taken literally as were `xx` and `yy` in the + example above, though it does not have a name as do `xx` and `yy`. + + Hence instead of calling + + #define IS_EMPTY_ITEM(x_item) _IS_EMPTY_2(_TWION_##x_item) + + We have + + #define _IS_EMPTY_1(x_item) _IS_EMPTY_2(_TWION_##x_item) + #define IS_EMPTY_ITEM(x_item) _IS_EMPTY_1(x_item) + +1.1 function macro definition - no space between the macro name and the parameter + list. + + #define sum(p ,q ,r) (p + q + r) // good + + #define sum (p ,q ,r) (p + q + r) // defines rewrite sum -> (p ,q ,r) (p + q + r) + +---------------------------------------- +2. cpp + +2.1 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 = ε + An item with no content, but syntactically present and contributing to list length. + For example, ( , ) is a two-item arg_list with two empty_items. + + shim_item = ~,1 + A special two-token item treated as a single item. + Its role is to shift the remaining members of a list by one position when prepended. + An honorary member of the single item club. + + item = token | empty_item | shim_item + + arg_list = item (, item)* ; comma-separated list of items + + pair = item , item ; exactly two items + +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. + +---------------------------------------- +3. Logic + + 2.1 Logic Values + + False: 0 + True: 1 + + 2.2 One Item Arguments + + Some logic functions are required to be given a single item, i.e. to not be given a list.. This requirement is maintained by the manner they are used. For example, being passed a value gotten by FIRST. + + Macro arguments that must be single items are suffixed with `_item`. + +*/ + +EMPTYNESS + +2. Empty argument list query + +2.1 if empty values are allowed for arguments + + There is a nuance when checking that a list is empty, because lists can + have empty elements. E.g. `a ,b , ,d ,e` including leading elements or + even all empty elements, e.g. `, , , ,`. + + Hence, if we use the first element to represent that a list argument is present, we might happen upon an empty first element. Even if we CAT all the elements for a long list of empty values, we can produce an empty element. + + We can not overload macro definitions with different argument counts, this is + not allowed. + +2.2 when empty elements should not happen + + Fortunately, in many applications empty elements do not have meaning. In + such applications, if the first element is not empty, we can we conclude + there is a list, rather than an empty list. + + Access of the nth element is more fundamental than logic, so access can be + used. + + Note this simplified implementation for SECOND: + + #define SECOND_1(a ,b ,...) b + #define SECOND(...) SECOND_1(__VA_ARGS__, pad) + + Notice that if __VA_ARGS__ is empty, that it will become the empty + `a` value in SECOND. Thus SECOND_1 will always be given at least + one argument, even when SECOND is given no arguments! + + In contrast to access, the variadic CAT function relies upon having + an predicate to detect emptiness so as to stop the recursion, so it + is not possible to use to CAT all the elements of a list to see that + some elements are not empty. + +2.3 Getting different behavior from an empty __VA_ARGS__ and a non-empty one. + + 2.3.1 peek-a-boo macro call + + The primary trick is this: + + macro __VA_ARGS__ () + + The macro will only be called when it is followed by parens, so it will only be called when __VA_ARGS__ is empty. However when __VA_ARGS__ is not empty we have a mess. Say it is a,b,c. Then: + + macro a,b,c () -> macroa,b,c() + + That is three elements ending in a macro call `c()` which is surely unintentional. + Suppose we instead do: + + macro FIRST(__VA_ARGS_) () -> macro a () -> macroa() + + Which is another macro call, though probably not one that is defined. If + the first argument in the __VA_ARGS__ list is empty, then we are back to + `macro()` - indistinguishable from a call with an empty argument list. + + 2.3.1 rewrite rule + + Another approach is to use a rewrite rule: + + #define rewrite_rule new_value + + then in the macro: + + rewrite __VA_ARGS__ + + when __VARGS__ is empty: + + rewrite##__VA_ARGS__##rule -> rewrite_rule -> new_value + + when __VARGS__ is, say, a,b,c: + + rewrite##a,b,c##_rule -> rewritea,b,c_rule + + which is a rather messed up three item list. If we use FIRST on the middle + string: + + -> rewritea_rule + + Which is a 1 element list. + + (Note, `##` is evaluate before the macro expansions.) + + diff --git a/developer/example/#try_connectors.c# b/developer/example/#try_connectors.c# new file mode 100644 index 0000000..af96825 --- /dev/null +++ b/developer/example/#try_connectors.c# @@ -0,0 +1,90 @@ +#include +#include "cpp_RT.c" + +#define SHOW( x) printf(#x " = %d\n", x) + +int main(void){ + //-------------------------------------------------------------------------- + // Existence Checks (sanity anchor) + //-------------------------------------------------------------------------- + + #define x0 + SHOW( EXISTS_ITEM(x0) ); // → 0 (assumed undefined) + SHOW( NOT_EXISTS_ITEM(x0) ); // → 1 + printf("\n"); + + SHOW( MATCH(x0) ); + SHOW( NOT_MATCH(x0) ); + printf("\n"); + + + //-------------------------------------------------------------------------- + // Primitive Connectors + //-------------------------------------------------------------------------- + + SHOW( _NOT(0) ); // _RWR_NOT_0 is defined → MATCH → 1 + SHOW( _NOT(1) ); // no rule → MATCH fails → 0 + printf("\n"); + + SHOW( _AND(0 ,0) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,0) ); // rule defined → MATCH → 1 + SHOW( _AND(0 ,1) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,1) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,x) ); // not legal args, but worked, rule missing → MATCH fails → 0 + printf("\n"); + + SHOW( _OR(0 ,0) ); // rule defined → NOT_MATCH → 0 + SHOW( _OR(0 ,1) ); // rule missing → NOT_MATCH → 1 + SHOW( _OR(1 ,0) ); // rule missing → NOT_MATCH → 1 + SHOW( _OR(1 ,1) ); // rule missing → NOT_MATCH → 1 + printf("\n"); + + + + //-------------------------------------------------------------------------- + // Equality + //-------------------------------------------------------------------------- + + SHOW( _EQ(0 ,0) ); // rule defined → MATCH → 1 + SHOW( _EQ(1 ,1) ); // rule defined → MATCH → 1 + SHOW( _EQ(0 ,1) ); // no rule → MATCH fails → 0 + SHOW( _EQ(x ,x) ); // no rule → MATCH fails → 0 + printf("\n"); + + SHOW( _NOT_EQ(0 ,1) ); // rule missing → EXISTS → 1 + SHOW( _NOT_EQ(0 ,0) ); // rule exists → EXISTS → 0 + printf("\n"); + + //-------------------------------------------------------------------------- + // Logical Connectors (BOOL + AND/OR/NOT) + //-------------------------------------------------------------------------- + + SHOW( _BOOL_2(0) ); // 0 + SHOW( _BOOL_2(1) ); // 1 + SHOW( _BOOL_2(2) ); // 1 because it exists + SHOW( _BOOL_2(x0) ); // 0 because it does not exit (see the #define at the top) + printf("\n"); + + SHOW( BOOL(0) ); // _FIRST = 0, EXISTS_ITEM(_FIRST) = 0 → _AND(0 ,1) → 0 + SHOW( BOOL(1) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL(10) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL() ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL(x0) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + printf("\n"); + + SHOW( NOT(0) ); // BOOL = 0 → NOT(0) = _NOT(0) = 1 + SHOW( NOT(1) ); // BOOL = 0 → NOT(0) = 1 + SHOW( NOT() ); // BOOL = 0 → NOT(0) = 1 + SHOW( NOT(10) ); // BOOL = 0 → NOT(0) = 1 + printf("\n"); + + SHOW( AND(1 ,0) ); // 0 + SHOW( AND(1 ,1) ); // BOOL(1), BOOL(1) = 0,0 → AND(0 ,0) = _AND(0 ,0) = 1 + printf("\n"); + + SHOW( OR(0 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 + SHOW( OR(1 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 + printf("\n"); + + return 0; +} diff --git a/developer/example/cpp_RT.c b/developer/example/cpp_RT.c new file mode 100644 index 0000000..5482691 --- /dev/null +++ b/developer/example/cpp_RT.c @@ -0,0 +1,113 @@ +/* + See also https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h + and tutorial at: http://jhnet.co.uk/articles/cpp_magic + + I could not have even thought about writing this without Jonathan Heathcote's + little tutorial. + + The 'twion' is cute. It is reminiscent of a complex number in math. It is a + pair given to functions that only take singletons. + +*/ + + + +/*=========================================================================== +Constants +===========================================================================*/ + +#define COMMA , +#define SEMICOLON ; + +#define _TWION_0 ~,0 +#define _TWION_1 ~,1 + +// RWR == rewrite rule, RWR_ is followed by macro name it is used in `__` +// Matching text is replaced with nothing, making it empty +// Potential for aliasing if x or y have '__oo__' embedded in them. +#define _RWR_NOT__0 +#define _RWR_AND__1__oo__1 +#define _RWR_OR__0__oo__0 + +// add more of this form to register other equalities +#define _RWR_EQ__0__oo__0 +#define _RWR_EQ__1__oo__1 + +/*=========================================================================== +Logic +===========================================================================*/ + +// user versions of these functions appear latter in the file + +//---------------------------------------- +// primitive access + + // note: _FIRST of nothing, _FIRST(), means passing an empty_item as the first item + // so it will return empty. + #define _FIRST(a ,...) a + #define _SECOND(a ,b ,...) b + +//---------------------------------------- +// existence + + // `##` prevents rewrite of _TWION_ in the _EXISTS_ITEM_1 macro + #define _EXISTS_ITEM_2(x_item) _SECOND(x_item ,1) + #define _EXISTS_ITEM_1(x_item) _EXISTS_ITEM_2(_TWION_0##x_item) + + #define EXISTS_ITEM(x_item) _EXISTS_ITEM_1(x_item) + #define EXISTS(...) EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + #define _NOT_EXISTS_ITEM_2(x_item) _SECOND(x_item ,0) + #define _NOT_EXISTS_ITEM_1(x_item) _NOT_EXISTS_ITEM_2(_TWION_1##x_item) + + #define NOT_EXISTS_ITEM(x_item) _NOT_EXISTS_ITEM_1(x_item) + #define NOT_EXISTS(...) NOT_EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + // useful to use with rewrite rules that substitute to nothing + #define MATCH(x_item) NOT_EXISTS(x_item) + #define NOT_MATCH(x_item) EXISTS(x_item) + +//---------------------------------------- +// primitive connectors + + #define _NOT_1(x_item) MATCH( _RWR_NOT__##x_item ) + #define _NOT(x_item) _NOT_1(x_item) + + #define _AND_1(x_item ,y_item) MATCH( _RWR_AND__##x_item##__oo__##y_item ) + #define _AND(x_item ,y_item) _AND_1(x_item ,y_item) + + #define _OR_1(x_item ,y_item) NOT_MATCH( _RWR_OR__##x_item##__oo__##y_item ) + #define _OR(x_item ,y_item) _OR_1(x_item ,y_item) + +//---------------------------------------- +// equality +// more general than a connector because more rules can be added. +// each has the form: +// _RWR_EQ____oo__ +// for example: +// _RWR_EQ__0__oo__0 + + #define _EQ(x_item ,y_item) MATCH( _RWR_EQ__##x_item##__oo__##y_item ) + #define EQ(x_item ,y_item) _EQ(x_item ,y_item) + + #define _NOT_EQ(x_item ,y_item) EXISTS(_RWR_EQ__##x_item##__oo__##y_item) + #define NOT_EQ(x_item ,y_item) _NOT_EQ(x_item ,y_item) + + +//---------------------------------------- +// connectors + + #define _BOOL_2(x_item) \ + _AND(\ + EXISTS_ITEM( _FIRST(x_item) ) \ + ,NOT_MATCH( _RWR_EQ__0__oo__##x_item) \ + ) + #define _BOOL_1(x_item) _BOOL_2(x_item) + #define BOOL(x_item) _BOOL_1(_FIRST(x_item)) + + + #define NOT(x_item) _NOT(BOOL(x_item)) + #define AND(x_item ,y_item) _AND(BOOL(x_item) ,BOOL(y_item)) + #define OR(x_item ,y_item) _OR(BOOL(x_item) ,BOOL(y_item)) + + diff --git a/developer/example/cpp_recursion.c b/developer/example/cpp_recursion.c new file mode 100644 index 0000000..9f758e1 --- /dev/null +++ b/developer/example/cpp_recursion.c @@ -0,0 +1,35 @@ +#include +#include "macro_lib.c" + +/* Define decrement values for numbers 1 through 5 */ +#define DEC_1 0 +#define DEC_2 1 +#define DEC_3 2 +#define DEC_4 3 +#define DEC_5 4 +#define DEC(n) DEC_##n + +/* + COUNT_DOWN(n): + - If n is 0, outputs "Done". + - Otherwise, outputs the current number (as a string), a space, + and then recursively calls COUNT_DOWN on DEC(n). + + Note: DEFER1 is used to postpone the recursive call, + and EVAL (via ESTR) will force the complete expansion. +*/ +#define COUNT_DOWN(n) IF_ELSE(EQUAL(n,0))("Done") ( XSTR(n) " " DEFER1(COUNT_DOWN)(DEC(n)) ) + +/* Minimal stringization helpers. + STR(x) stringizes without expanding; + XSTR(x) expands x first then stringizes; + ESTR(x) forces full expansion (using EVAL) then stringizes. +*/ +#define STR(x) #x +#define XSTR(x) STR(x) +#define ESTR(x) XSTR(EVAL(x)) + +int main(void) { + printf("Countdown from 5: %s\n", ESTR(COUNT_DOWN(5))); + return 0; +} diff --git a/developer/example/scratchpad/cpp_IF.c b/developer/example/scratchpad/cpp_IF.c new file mode 100644 index 0000000..0fcce7f --- /dev/null +++ b/developer/example/scratchpad/cpp_IF.c @@ -0,0 +1,18 @@ +#include +#include "macro_lib.c" + +/* SUM_IF(condition, a, b) + - If condition is true (nonzero), returns (a)+(b) + - Otherwise, returns (a)-(b) + This uses the IF_ELSE construct from the macro library. +*/ +#define SUM_IF(condition, a, b) IF_ELSE(condition)( (a) + (b) )( (a) - (b) ) + +int main(void) { + int result_true = SUM_IF(1, 5, 3); // Expect 5+3 = 8 + int result_false = SUM_IF(0, 5, 3); // Expect 5-3 = 2 + + printf("SUM_IF(1, 5, 3) = %d\n", result_true); + printf("SUM_IF(0, 5, 3) = %d\n", result_false); + return 0; +} diff --git a/developer/example/scratchpad/cpp_extentions.c b/developer/example/scratchpad/cpp_extentions.c new file mode 100644 index 0000000..5e828bb --- /dev/null +++ b/developer/example/scratchpad/cpp_extentions.c @@ -0,0 +1,108 @@ +/* + See also https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h + and tutorial at: http://jhnet.co.uk/articles/cpp_magic + + I could not have even thought about writing this without Jonathan Heathcote's + little tutorial. + + The 'twion' is cute. It is reminiscent of a complex number in math. It is a + pair given to functions that only take singletons. + +*/ + + + +/*=========================================================================== +Constants +===========================================================================*/ + +#define COMMA , +#define SEMICOLON ; + +#define _TWION_0_ ~,0 +#define _TWION_1_ ~,1 + +// RWR == rewrite rule, RWR_ is followed by macro name it is used in `__` +// Matching text is replaced with nothing, making it empty +// Potential for aliasing if x or y have '__oo__' embedded in them. +#define _RWR_AND__1__oo__1 +#define _RWR_OR__0__oo__0 +#define _RWR_NOT__0 + +#define _RWR_EQ__0__oo__0 +#define _RWR_EQ__1__oo__1 + +/*=========================================================================== +Logic +===========================================================================*/ + +// user versions of these functions appear latter in the file + +//---------------------------------------- +// primitive access + + // note: _FIRST of nothing, _FIRST(), means passing an empty_item as the first item + // so it will return empty. + #define _FIRST(a ,...) a + #define _SECOND(a ,b ,...) b + +//---------------------------------------- +// existence + + // `##` prevents rewrite of _TWION_ in the _EXISTS_ITEM_1 macro + #define _EXISTS_ITEM_2(x_item) _SECOND(x_item ,1) + #define _EXISTS_ITEM_1(x_item) _EXISTS_ITEM_2(_TWION_0_##x_item) + + #define EXISTS_ITEM(x_item) _EXISTS_ITEM_1(x_item) + #define EXISTS(...) EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + #define _NOT_EXISTS_ITEM_2(x_item) _SECOND(x_item ,0) + #define _NOT_EXISTS_ITEM_1(x_item) _NOT_EXISTS_ITEM_2(_TWION_1_##x_item) + + #define NOT_EXISTS_ITEM(x_item) _NOT_EXISTS_ITEM_1(x_item) + #define NOT_EXISTS(...) NOT_EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + // useful to use with rewrite rules that substitute to nothing + #define MATACH(x_item) NOT_EXISTS(x_item) + #define NOT_MATCH(x_item) EXISTS(x_item) + +//---------------------------------------- +// primitive connectors + + #define _NOT_1(x_item) MATCH( _RWR_NOT_0_x_##x_item ) + #define _NOT(x_item) _NOT_1(x_item) + + #define _AND_1(x_item ,y_item) MATCH( _RWR_AND__##x_item##__oo__##y_item ) + #define _AND(x_item ,y_item) _AND_1(x_item ,y_item) + + #define _OR_1(x_item ,y_item) NOT_MATCH( _RWR_OR__##x_item#__oo__##y_item ) + #define _OR(x_item ,y_item) _OR_1(x_item ,y_item) + +//---------------------------------------- +// equality +// works with registerd _RWS_EQ____oo__ rules. +// for example: _RWR_EQ__0__oo__0 + + + #define _EQ(x_item ,y_item) MATCH( RWR_EQ__##x_item##__oo__##y_item ) + #define EQ(x_item ,y_item) _EQ(x_item ,y_item) + + #define _NOT_EQ(x_item ,y_item) EXISTS(RWR_EQ_##x_item##__oo__##y_item) + #define NOT_EQ(x_item ,y_item) _NOT_EQ(x_item ,y_item) + + +//---------------------------------------- +// connectors + + #define _BOOL(x_item) \ + _AND(\ + EXISTS_ITEM(_FIRST(x_item) \ + ,NOT_MATCH( _RWR_EQ__0__oo__##x_item) \ + ) + #define BOOL(x_item) _BOOL(_FIRST(x_item)) + + #define NOT(x_item) _NOT(BOOL(x_item)) + #define AND(x_item ,y_item) _AND(BOOL(x_item) ,BOOL(y_item)) + #define OR(x_item ,y_item) _OR(BOOL(x_item) ,BOOL(y_item)) + + diff --git a/developer/example/scratchpad/cpp_magic.c b/developer/example/scratchpad/cpp_magic.c new file mode 100644 index 0000000..5e828bb --- /dev/null +++ b/developer/example/scratchpad/cpp_magic.c @@ -0,0 +1,108 @@ +/* + See also https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h + and tutorial at: http://jhnet.co.uk/articles/cpp_magic + + I could not have even thought about writing this without Jonathan Heathcote's + little tutorial. + + The 'twion' is cute. It is reminiscent of a complex number in math. It is a + pair given to functions that only take singletons. + +*/ + + + +/*=========================================================================== +Constants +===========================================================================*/ + +#define COMMA , +#define SEMICOLON ; + +#define _TWION_0_ ~,0 +#define _TWION_1_ ~,1 + +// RWR == rewrite rule, RWR_ is followed by macro name it is used in `__` +// Matching text is replaced with nothing, making it empty +// Potential for aliasing if x or y have '__oo__' embedded in them. +#define _RWR_AND__1__oo__1 +#define _RWR_OR__0__oo__0 +#define _RWR_NOT__0 + +#define _RWR_EQ__0__oo__0 +#define _RWR_EQ__1__oo__1 + +/*=========================================================================== +Logic +===========================================================================*/ + +// user versions of these functions appear latter in the file + +//---------------------------------------- +// primitive access + + // note: _FIRST of nothing, _FIRST(), means passing an empty_item as the first item + // so it will return empty. + #define _FIRST(a ,...) a + #define _SECOND(a ,b ,...) b + +//---------------------------------------- +// existence + + // `##` prevents rewrite of _TWION_ in the _EXISTS_ITEM_1 macro + #define _EXISTS_ITEM_2(x_item) _SECOND(x_item ,1) + #define _EXISTS_ITEM_1(x_item) _EXISTS_ITEM_2(_TWION_0_##x_item) + + #define EXISTS_ITEM(x_item) _EXISTS_ITEM_1(x_item) + #define EXISTS(...) EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + #define _NOT_EXISTS_ITEM_2(x_item) _SECOND(x_item ,0) + #define _NOT_EXISTS_ITEM_1(x_item) _NOT_EXISTS_ITEM_2(_TWION_1_##x_item) + + #define NOT_EXISTS_ITEM(x_item) _NOT_EXISTS_ITEM_1(x_item) + #define NOT_EXISTS(...) NOT_EXISTS_ITEM( _FIRST(__VA_ARGS__) ) + + // useful to use with rewrite rules that substitute to nothing + #define MATACH(x_item) NOT_EXISTS(x_item) + #define NOT_MATCH(x_item) EXISTS(x_item) + +//---------------------------------------- +// primitive connectors + + #define _NOT_1(x_item) MATCH( _RWR_NOT_0_x_##x_item ) + #define _NOT(x_item) _NOT_1(x_item) + + #define _AND_1(x_item ,y_item) MATCH( _RWR_AND__##x_item##__oo__##y_item ) + #define _AND(x_item ,y_item) _AND_1(x_item ,y_item) + + #define _OR_1(x_item ,y_item) NOT_MATCH( _RWR_OR__##x_item#__oo__##y_item ) + #define _OR(x_item ,y_item) _OR_1(x_item ,y_item) + +//---------------------------------------- +// equality +// works with registerd _RWS_EQ____oo__ rules. +// for example: _RWR_EQ__0__oo__0 + + + #define _EQ(x_item ,y_item) MATCH( RWR_EQ__##x_item##__oo__##y_item ) + #define EQ(x_item ,y_item) _EQ(x_item ,y_item) + + #define _NOT_EQ(x_item ,y_item) EXISTS(RWR_EQ_##x_item##__oo__##y_item) + #define NOT_EQ(x_item ,y_item) _NOT_EQ(x_item ,y_item) + + +//---------------------------------------- +// connectors + + #define _BOOL(x_item) \ + _AND(\ + EXISTS_ITEM(_FIRST(x_item) \ + ,NOT_MATCH( _RWR_EQ__0__oo__##x_item) \ + ) + #define BOOL(x_item) _BOOL(_FIRST(x_item)) + + #define NOT(x_item) _NOT(BOOL(x_item)) + #define AND(x_item ,y_item) _AND(BOOL(x_item) ,BOOL(y_item)) + #define OR(x_item ,y_item) _OR(BOOL(x_item) ,BOOL(y_item)) + + diff --git a/developer/example/scratchpad/example_macro_access.c b/developer/example/scratchpad/example_macro_access.c new file mode 100644 index 0000000..7a39ef7 --- /dev/null +++ b/developer/example/scratchpad/example_macro_access.c @@ -0,0 +1,44 @@ +#include + +/* Stringizing helpers */ +#define STR(x) #x +#define XSTR(x) STR(x) + +#include "macro_logic.c" + +int main(void) { + /* Test with three tokens */ + printf( + "FIRST(DEFAULT ,apple ,banana ,cherry) = %s\n" + ,XSTR(FIRST(DEFAULT ,apple ,banana ,cherry)) + ); + printf( + "SECOND(DEFAULT ,apple ,banana ,cherry) = %s\n" + ,XSTR(SECOND(DEFAULT ,apple ,banana ,cherry)) + ); + printf( + "THIRD(DEFAULT ,apple ,banana ,cherry) = %s\n" + ,XSTR(THIRD(DEFAULT ,apple ,banana ,cherry)) + ); + + printf("test default\n"); + + printf( + "FIRST(DEFAULT) = %s\n" + ,XSTR(FIRST(DEFAULT)) + ); + printf( + "FIRST(DEFAULT ,apple) = %s\n" + ,XSTR(FIRST(DEFAULT ,apple)) + ); + printf( + "SECOND(DEFAULT ,apple) = %s\n" + ,XSTR(SECOND(DEFAULT ,apple)) + ); + printf( + "THIRD(DEFAULT ,apple) = %s\n" + ,XSTR(THIRD(DEFAULT ,apple)) + ); + + return 0; +} diff --git a/developer/example/scratchpad/example_macro_logic.c b/developer/example/scratchpad/example_macro_logic.c new file mode 100644 index 0000000..37bf0fe --- /dev/null +++ b/developer/example/scratchpad/example_macro_logic.c @@ -0,0 +1,48 @@ +#include + +#include "macro_logic.c" + +#define STR(x) #x +#define XSTR(x) STR(x) + +/*=========================================================================== +Example Program +===========================================================================*/ +int main(void) { + /* For testing purposes, we print the macro expansion results as strings. + (Because TRUE and FALSE have no numeric value, we rely on stringized output.) + */ + printf("TRUE: %s\n", XSTR(TRUE)); + + printf("FIRST(a,b,c) = %s\n", XSTR( FIRST(0 ,a ,b ,c) )); + printf("FIRST(a,b,c) = %s\n", XSTR( FIRST(DEFER3(PAIR)() ,a ,b, ,c) )); + + printf("FIRST() = %s\n", XSTR( FIRST(7) )); + printf("FIRST() = %s\n", XSTR( FIRST(PAIR()) )); + printf("FIRST() = %s\n", XSTR( FIRST(DEFER3(PAIR)()) )); + + +#if 0 + + + printf("EXIST() = %s\n", XSTR(EXIST())); + printf("EXIST(a) = %s\n", XSTR(EXIST(a))); + + printf("NOT_EXIST(TRUE) = %s\n", XSTR(NOT_EXIST(TRUE))); + printf("EXIST(FALSE) = %s\n", XSTR(EXIST(FALSE))); + printf("NOT_EXIST(FALSE) = %s\n", XSTR(NOT_EXIST(FALSE))); + + printf("BOOL(TRUE) = %s\n", XSTR(BOOL(TRUE))); + printf("BOOL(FALSE) = %s\n", XSTR(BOOL(FALSE))); + + printf("EQUAL(TRUE, TRUE) = %s\n", XSTR(EQUAL(TRUE, TRUE))); + printf("EQUAL(FALSE, FALSE) = %s\n", XSTR(EQUAL(FALSE, FALSE))); + printf("EQUAL(TRUE, FALSE) = %s\n", XSTR(EQUAL(TRUE, FALSE))); + + printf("IF_ELSE(TRUE)(Yes)(No) = %s\n", XSTR(IF_ELSE(TRUE)(Yes)(No))); + printf("IF_ELSE(FALSE)(Yes)(No) = %s\n", XSTR(IF_ELSE(FALSE)(Yes)(No))); + + +#endif + return 0; +} diff --git a/developer/example/scratchpad/macro_cat.c b/developer/example/scratchpad/macro_cat.c new file mode 100644 index 0000000..732b431 --- /dev/null +++ b/developer/example/scratchpad/macro_cat.c @@ -0,0 +1,45 @@ +/*=========================================================================== + 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 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. +===========================================================================*/ +#define EMPTY() +#define DEFER1(m) m EMPTY() +#define DEFER2(m) m EMPTY EMPTY()() +#define DEFER3(m) m EMPTY EMPTY EMPTY()()() +#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()() /* as needed */ + + +/*=========================================================================== + Defer macros: these help “hide” recursive calls for additional expansion passes. +===========================================================================*/ + +#define _CAT2(sep,a,b) a ## sep ## b + +#define _CAT(sep,first,...) \ + IF_ELSE(HAS_ARGS(__VA_ARGS__))( \ + _CAT2(sep,first,DEFER1(_CAT)(sep,__VA_ARGS__)) \ + )(first) + +/* Variadic CAT: + - If no tokens are provided,returns nothing. + - If one token is provided,returns that token. + - Otherwise,it recursively concatenates the tokens with the given separator. +*/ +#define CAT(sep,...) IF_ELSE(HAS_ARGS(__VA_ARGS__))( EVAL(_CAT(sep,__VA_ARGS__)) )(/* nothing */) diff --git a/developer/example/scratchpad/macro_lib.c b/developer/example/scratchpad/macro_lib.c new file mode 100644 index 0000000..de15113 --- /dev/null +++ b/developer/example/scratchpad/macro_lib.c @@ -0,0 +1,151 @@ +/* macro_lib.c */ +#ifndef MACRO_LIB +#define MACRO_LIB + +/*=========================================================================== + Some Basics +===========================================================================*/ + +#define COMMA , + +#define _FIRST(a,...) a +#define FIRST(...) _FIRST(__VA_ARGS__,~) + +#define _SECOND(a,b,...) b +#define SECOND(...) _SECOND(__VA_ARGS__,~,~) + + +/*=========================================================================== + 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 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. +===========================================================================*/ +#define EMPTY() +#define DEFER1(m) m EMPTY() +#define DEFER2(m) m EMPTY EMPTY()() +#define DEFER3(m) m EMPTY EMPTY EMPTY()()() +#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()() /* as needed */ + +/*=========================================================================== + Token concatenation and basic utilities +===========================================================================*/ + +/* Assumes that EVAL,DEFER1,IF_ELSE,and HAS_ARGS are defined as in our macro library */ + +/* Helper: paste exactly two tokens with a separator. + If 'sep' is empty,then a ## sep ## b is equivalent to a ## b. +*/ +#define _CAT2(sep,a,b) a ## sep ## b + +#define _CAT(sep,first,...) \ + IF_ELSE(HAS_ARGS(__VA_ARGS__))( \ + _CAT2(sep,first,DEFER1(_CAT)(sep,__VA_ARGS__)) \ + )(first) + +/* Variadic CAT: + - If no tokens are provided,returns nothing. + - If one token is provided,returns that token. + - Otherwise,it recursively concatenates the tokens with the given separator. +*/ +#define CAT(sep,...) IF_ELSE(HAS_ARGS(__VA_ARGS__))( EVAL(_CAT(sep,__VA_ARGS__)) )(/* nothing */) + +#define Ξ(...) CAT(·,__VA_ARGS__) +#define Append(...) CAT(COMMA,__VA_ARGS__) + + +/*=========================================================================== + Put a 'PROBE()' in a list then detect it later. + + If a single value is given to IS_PROBE it won't have a second member,but + if the two element PROBE is given,the second element will be 1. + +===========================================================================*/ + +#define PROBE() ~,1 + +#define __IS_PROBE(a,b,...) b +#define _IS_PROBE(...) __IS_PROBE(__VA_ARGS__,0,0) +#define IS_PROBE(...) _IS_PROBE(__VA_ARGS__) + +#define _NOT_0 PROBE() + +// x == 0: _NOT_##x -> _NOT_0 -> ~,1 -> 1 +// x == 1: _NOT_##x -> _NOT_1 -> 0 +// +#define _NOT(x) IS_PROBE(_NOT_##x) +#define NOT(x) _NOT(x) +#define BOOL(x) NOT(NOT(x)) + +// This is a rewrite rule,if there is a definition for _IS_EQ__ it is replaced by its #define definition,presumably that of a Probe. +// The rule will then be #define _IS_EQ__ Probe() +#define _EQUAL_REWRITE(x,y) IS_PROBE( CAT(_IS_EQ_,x,_##y) ) + +#define EQUAL(x,y) BOOL( _EQUAL_REWRITE(x,y) ) + + +/*=========================================================================== + IF-ELSE construct. + Usage: IF_ELSE(condition)()() +===========================================================================*/ +#define IF_ELSE(condition) _IF_ELSE(BOOL(condition)) +#define _IF_ELSE(condition) CAT(_IF_,condition) +#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE +#define _IF_0(...) _IF_0_ELSE +#define _IF_1_ELSE(...) +#define _IF_0_ELSE(...) __VA_ARGS__ + +/*=========================================================================== + HAS_ARGS: tests whether a variadic argument list is empty. + + A bit of a tricky one, _END_OF_ARGUMENTS will only be expanded if it + is followed by parenthesis,otherwise it is taken literally. +===========================================================================*/ +#define _END_OF_ARGUMENTS_() 0 +#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)()) + +/*=========================================================================== + MATCH(x,list) returns 1 if x is a member in the list, else 0 + + list is comma separated. + + when list is passed to EVAL(MATCH_IMPL(x,list)) it gets expanded + which causes the elements to spread out. + + #define list dog,cat,parakeet + Match(x,list) -> EVAL(MATCH_IMPL(x,dog,cat,parkeet)) + + HAS_ARGS will return true if there is a 'first' list element, else false. + + #define _IS_EQ__ Probe() must be defined for the equality test to work. + +===========================================================================*/ +#define MATCH_IMPL(x,first,...) \ + IF_ELSE \ + ( HAS_ARGS(first) ) \ + ( IF_ELSE \ + ( EQUAL(x,first) ) \ + (1) \ + ( MATCH_IMPL(x,__VA_ARGS__) ) \ + ) \ + (0) + +#define MATCH(x,list) EVAL(MATCH_IMPL(x,list)) + +/* End of macro_lib.c */ +#endif diff --git a/developer/example/scratchpad/macro_logic.c b/developer/example/scratchpad/macro_logic.c new file mode 100644 index 0000000..090fc7c --- /dev/null +++ b/developer/example/scratchpad/macro_logic.c @@ -0,0 +1,117 @@ +/*=========================================================================== +Constants +===========================================================================*/ + +#define COMMA , +#define SEMICOLON ; + +#define _REWRITE__·FALSE +#define _REWRITE__·TRUE__EQ__·TRUE +#define _REWRITE__·FALSE__EQ__·FALSE + + +#define rewrite_rule ·FALSE +#define rewrite_ be_true( +#define _rule ) +#define be_true(...) ·TRUE + +/*=========================================================================== +Access +===========================================================================*/ + +#define FIRST_1(a ,...) a +#define FIRST(pad ,...) FIRST_1(__VA_ARGS__ ,pad) + +#define SECOND_1(a ,b ,...) b +#define SECOND(pad ,...) SECOND_1(__VA_ARGS__ ,pad) + +#define THIRD_1(a ,b ,c,...) c +#define THIRD(pad ,...) THIRD_1(__VA_ARGS__ ,pad ,pad) + + +/*=========================================================================== + Defer macros: these help “hide” recursive calls for additional expansion passes. +===========================================================================*/ +#define EMPTY() +#define DEFER1(m) m EMPTY() +#define DEFER2(m) m EMPTY EMPTY()() +#define DEFER3(m) m EMPTY EMPTY EMPTY()()() +#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()() /* as needed */ + +/*=========================================================================== + Two Token concatenation, with optional separator +===========================================================================*/ + +#define CAT2(sep,a,b) a##sep##b + + +/*=========================================================================== +LOGIC +===========================================================================*/ + +/* + This is deterministic, and free from possible aliasing with the arguments. + It does not require that ·TRUE or ·FALSE not be in the data. + + No Default value is needed for SECOND, as there will always be at least two + tokens in `x ,·TRUE` + + 1. When __VA_ARGS__ is empty, FIRST returns the default value of `,·FALSE` for + `x`. This makes x into a two token value, and the argument list for SECOND will be: + + ` ,·FALSE ,·TRUE. + + So the SECOND value is ·FALSE. + + 2. When __VA_ARGS__ is not empty, it sends a single value of x, so the argument list + for SECOND will be: + + x ,·TRUE. + + So the second value will be ·TRUE +*/ + + + + + + +#define PAIR() ~,·FALSE + +#define EXIST_1(x) FIRST(~ ,x ,·TRUE) +#define EXIST(...) EXIST_1( \ + FIRST( \ + DEFER3(PAIR)() \ + ,__VA_ARGS__ \ + )) + +#define NOT_EXIST_1(x) SECOND(,x ,·FALSE) +#define NOT_EXIST(...) NOT_EXIST_1( \ + FIRST( \ + DEFER1(CAT2)(,·TRUE) \ + ,__VA_ARGS__ \ + )) + +// `NOT_1` Returns a ·TRUE, or ·FALSE +#define NOT_1(x) NOT_EXIST(_REWRITE__##x) +#define NOT(x) NOT_1(x) + +#define BOOL_1(x) EXIST(_REWRITE__##x) +#define BOOL(x) BOOL_1(x) + +#define EQUAL_1(x ,y) NOT_EXIST_1( _REWRITE__##x__EQ__##y ) +#define EQUAL(x ,y) EQUAL_1(x ,y) + + +/*=========================================================================== + IF-ELSE construct. + Usage: IF_ELSE(condition)()() +===========================================================================*/ +#define IF_ELSE(condition) _IF_ELSE(BOOL(condition)) +#define _IF_ELSE(condition) CAT(_IF_,condition) +#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE +#define _IF_0(...) _IF_0_ELSE +#define _IF_1_ELSE(...) +#define _IF_0_ELSE(...) __VA_ARGS__ + + diff --git a/developer/example/scratchpad/macro_use.c b/developer/example/scratchpad/macro_use.c new file mode 100644 index 0000000..d90dcf1 --- /dev/null +++ b/developer/example/scratchpad/macro_use.c @@ -0,0 +1,64 @@ +#include +#include "macro_lib.c" + +/* Helper macros to turn expanded results into strings. + Note that STR(x) simply stringizes x without expanding it. + XSTR(x) expands x first (if possible) and then stringizes it. + We use EVAL to force full expansion before stringizing. +*/ + +#define STR(x) #x +#define XSTR(x) STR(x) +#define ESTR(x) XSTR(EVAL(x)) + +/* --- Example Usage --- */ + +/* Test 1: FIRST and SECOND */ +int main(void) { + printf("macro_use.c\n"); + + printf("FIRST(dog ,cat) = %s\n" ,ESTR(FIRST(dog ,cat))); + + printf("SECOND(dog ,cat) = %s\n" ,ESTR(SECOND(dog ,cat))); + printf("SECOND(dog) = %s\n" ,ESTR(SECOND(dog))); + + printf("_IS_PROBE(dog ,cat) = %s\n" ,ESTR(_IS_PROBE(dog ,cat))); + printf("_IS_PROBE(dog) = %s\n" ,ESTR(_IS_PROBE(dog))); + + /* Test 2: CAT with no separator and with COMMA */ + printf( "CAT( x ,dog ,cat ,parakeet) = %s\n" ,ESTR(CAT( ,dog ,cat ,parakeet)) ); + + printf( "CAT( ,dog ,cat ,parakeet) = %s\n" ,ESTR(EVAL(CAT( ,dog ,cat ,parakeet))) ); + + +#if 0 + + printf("CAT(COMMA ,dog ,cat ,parakeet) = %s\n" ,ESTR(CAT(COMMA ,dog ,cat ,parakeet))); + + /* Test 3: Xi macro (using a center dot as separator) */ + printf("Ξ(foo ,bar) = %s\n" ,ESTR(Ξ(foo ,bar))); + + /* Test 4: Append macro (using COMMA as separator) */ + printf("Append(dog ,cat) = %s\n" ,ESTR(Append(dog ,cat))); + printf("Append(dog) = %s\n" ,ESTR(Append(dog))); + + /* Test 5: MATCH macro */ + /* Define a static list of animals */ + #define static_animals dog,cat,parakeet + /* Register equality for tokens that will be compared */ + #undef _IS_EQ_dog_dog + #undef _IS_EQ_cat_cat + #undef _IS_EQ_parakeet_parakeet + #define _IS_EQ_dog_dog PROBE() + #define _IS_EQ_cat_cat PROBE() + #define _IS_EQ_parakeet_parakeet PROBE() + #define _IS_EQ_lizard_lizard PROBE() /* lizard is not in the list */ + + printf("MATCH(dog ,static_animals) = %s\n" ,ESTR(MATCH(dog ,static_animals))); + printf("MATCH(cat ,static_animals) = %s\n" ,ESTR(MATCH(cat ,static_animals))); + printf("MATCH(parakeet ,static_animals) = %s\n" ,ESTR(MATCH(parakeet ,static_animals))); + printf("MATCH(lizard ,static_animals) = %s\n" ,ESTR(MATCH(lizard ,static_animals))); +#endif + + return 0; +} diff --git a/developer/example/scratchpad/try_eval_order.c b/developer/example/scratchpad/try_eval_order.c new file mode 100644 index 0000000..f1ffcb0 --- /dev/null +++ b/developer/example/scratchpad/try_eval_order.c @@ -0,0 +1,32 @@ +#include + +/*=========================================================================== + 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(...) EVAL8(__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. +===========================================================================*/ +#define EMPTY() +#define DEFER1(m) m EMPTY() +#define DEFER2(m) m EMPTY EMPTY()() +#define DEFER3(m) m EMPTY EMPTY EMPTY()()() +#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()() /* as needed */ + +#define a(x) x + x +#define b 7 +#define cat(x,y) EVAL(DEFER1(a)(x) * y) + +int main(void) { + int result = cat(5, 7); + printf("cat(5, 7) = %d\n", result); + return 0; +} diff --git a/developer/example/scratchpad/try_macro_cat.c b/developer/example/scratchpad/try_macro_cat.c new file mode 100644 index 0000000..258d08f --- /dev/null +++ b/developer/example/scratchpad/try_macro_cat.c @@ -0,0 +1,41 @@ +// try_macro_cat.c +#include +#include "macro_cat.c" + +// Define test macros +#define A Hello +#define B World +#define C 123 +#define D _XYZ +#define EMPTY + +// Define some variables to test concatenation into identifiers +int HelloWorld = 10; +int Hello123 = 20; +int Hello_XYZ = 30; +int World = 40; + +int main(void) { + + // CAT(A,B) → HelloWorld + printf("CAT(A,B): %d\n", CAT(A,B)); + + // CAT(A,C) → Hello123 + printf("CAT(A,C): %d\n", CAT(A,C)); + + // CAT(A,D) → Hello_XYZ + printf("CAT(A,D): %d\n", CAT(A,D)); + + // CAT(EMPTY,B) → World + printf("CAT(EMPTY,B): %d\n", CAT(EMPTY,B)); + + // CAT(A,EMPTY) → Hello (must define int Hello) + // Uncomment after defining: int Hello = 50; + // printf("CAT(A,EMPTY): %d\n", CAT(A,EMPTY)); + + // Nested concatenation: CAT(CAT(A,EMPTY),B) → HelloWorld + // Uncomment after defining int Hello = ...; + // printf("CAT(CAT(A,EMPTY),B): %d\n", CAT(CAT(A,EMPTY),B)); + + return 0; +} diff --git a/developer/example/scratchpad/try_pasting.c b/developer/example/scratchpad/try_pasting.c new file mode 100644 index 0000000..033a638 --- /dev/null +++ b/developer/example/scratchpad/try_pasting.c @@ -0,0 +1,41 @@ +#include + +#define STR(x) #x +#define XSTR(x) STR(x) + +#define mess(...) rewrite_##__VA_ARGS__##_rule + +int main(){ + + printf("a mess %s\n" ,XSTR(mess(1))); + printf("a mess %s\n" ,XSTR(mess(2))); + printf("a mess %s\n" ,XSTR(mess(1,2))); + +} + +/* + + It does not like it when I send 2 parameters into mess. + + > gcc try_pasting.c +try_pasting.c: In function ‘main’: +try_pasting.c:12:1: error: macro "STR" passed 2 arguments, but takes just 1 + 12 | printf("a mess %s\n" ,XSTR(mess(1,2))); + | ^ ~~~~ +try_pasting.c:3:9: note: macro "STR" defined here + 3 | #define STR(x) #x + | ^~~ +try_pasting.c:4:17: error: ‘STR’ undeclared (first use in this function) + 4 | #define XSTR(x) STR(x) + | ^~~ +try_pasting.c:12:25: note: in expansion of macro ‘XSTR’ + 12 | printf("a mess %s\n" ,XSTR(mess(1,2))); + | ^~~~ +try_pasting.c:4:17: note: each undeclared identifier is reported only once for each function it appears in + 4 | #define XSTR(x) STR(x) + | ^~~ +try_pasting.c:12:25: note: in expansion of macro ‘XSTR’ + 12 | printf("a mess %s\n" ,XSTR(mess(1,2))); + | ^~~~ + +*./ diff --git a/developer/example/tempt_eval.c b/developer/example/tempt_eval.c new file mode 100644 index 0000000..4f7b8aa --- /dev/null +++ b/developer/example/tempt_eval.c @@ -0,0 +1,23 @@ +#include +#include "macro_lib.c" + +/* A very simple base macro that expands to an integer literal */ +#define SIMPLE_MACRO1 549 +#define SIMPLE_MACRO2 7919 + +/* Define a chain of macros that simply pass along the value. + Each CALL_n() macro just calls the previous level. +*/ +#define CALL1() SIMPLE_MACRO1 +#define CALL2a() CALL1 EMPTY() () + 3 +#define CALL2b() DEFER1(CALL1)() + 5 + +int main(void) { + + printf( "SIMPLE_MACRO1 = %d\n", SIMPLE_MACRO1 ); + printf( "CALL1() = %d\n", EVAL(CALL1()) ); + printf( "CALL2a() = %d\n", EVAL(CALL2a()) ); + printf( "CALL2b() = %d\n", EVAL(CALL2b()) ); + + return 0; +} diff --git a/developer/example/try_connectors.c b/developer/example/try_connectors.c new file mode 100644 index 0000000..af96825 --- /dev/null +++ b/developer/example/try_connectors.c @@ -0,0 +1,90 @@ +#include +#include "cpp_RT.c" + +#define SHOW( x) printf(#x " = %d\n", x) + +int main(void){ + //-------------------------------------------------------------------------- + // Existence Checks (sanity anchor) + //-------------------------------------------------------------------------- + + #define x0 + SHOW( EXISTS_ITEM(x0) ); // → 0 (assumed undefined) + SHOW( NOT_EXISTS_ITEM(x0) ); // → 1 + printf("\n"); + + SHOW( MATCH(x0) ); + SHOW( NOT_MATCH(x0) ); + printf("\n"); + + + //-------------------------------------------------------------------------- + // Primitive Connectors + //-------------------------------------------------------------------------- + + SHOW( _NOT(0) ); // _RWR_NOT_0 is defined → MATCH → 1 + SHOW( _NOT(1) ); // no rule → MATCH fails → 0 + printf("\n"); + + SHOW( _AND(0 ,0) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,0) ); // rule defined → MATCH → 1 + SHOW( _AND(0 ,1) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,1) ); // rule defined → MATCH → 1 + SHOW( _AND(1 ,x) ); // not legal args, but worked, rule missing → MATCH fails → 0 + printf("\n"); + + SHOW( _OR(0 ,0) ); // rule defined → NOT_MATCH → 0 + SHOW( _OR(0 ,1) ); // rule missing → NOT_MATCH → 1 + SHOW( _OR(1 ,0) ); // rule missing → NOT_MATCH → 1 + SHOW( _OR(1 ,1) ); // rule missing → NOT_MATCH → 1 + printf("\n"); + + + + //-------------------------------------------------------------------------- + // Equality + //-------------------------------------------------------------------------- + + SHOW( _EQ(0 ,0) ); // rule defined → MATCH → 1 + SHOW( _EQ(1 ,1) ); // rule defined → MATCH → 1 + SHOW( _EQ(0 ,1) ); // no rule → MATCH fails → 0 + SHOW( _EQ(x ,x) ); // no rule → MATCH fails → 0 + printf("\n"); + + SHOW( _NOT_EQ(0 ,1) ); // rule missing → EXISTS → 1 + SHOW( _NOT_EQ(0 ,0) ); // rule exists → EXISTS → 0 + printf("\n"); + + //-------------------------------------------------------------------------- + // Logical Connectors (BOOL + AND/OR/NOT) + //-------------------------------------------------------------------------- + + SHOW( _BOOL_2(0) ); // 0 + SHOW( _BOOL_2(1) ); // 1 + SHOW( _BOOL_2(2) ); // 1 because it exists + SHOW( _BOOL_2(x0) ); // 0 because it does not exit (see the #define at the top) + printf("\n"); + + SHOW( BOOL(0) ); // _FIRST = 0, EXISTS_ITEM(_FIRST) = 0 → _AND(0 ,1) → 0 + SHOW( BOOL(1) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL(10) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL() ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + SHOW( BOOL(x0) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 + printf("\n"); + + SHOW( NOT(0) ); // BOOL = 0 → NOT(0) = _NOT(0) = 1 + SHOW( NOT(1) ); // BOOL = 0 → NOT(0) = 1 + SHOW( NOT() ); // BOOL = 0 → NOT(0) = 1 + SHOW( NOT(10) ); // BOOL = 0 → NOT(0) = 1 + printf("\n"); + + SHOW( AND(1 ,0) ); // 0 + SHOW( AND(1 ,1) ); // BOOL(1), BOOL(1) = 0,0 → AND(0 ,0) = _AND(0 ,0) = 1 + printf("\n"); + + SHOW( OR(0 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 + SHOW( OR(1 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 + printf("\n"); + + return 0; +} diff --git a/developer/example/try_exists.c b/developer/example/try_exists.c new file mode 100644 index 0000000..4eee2e8 --- /dev/null +++ b/developer/example/try_exists.c @@ -0,0 +1,77 @@ +#include +#include "cpp_RT.c" + + +#define STR(x) #x +#define XSTR(x) STR(x) + + +// Patch for CAT to succeed +#define FOOBAR 12345 + +// Patch for _EXISTS to succeed on 0 +#define _REWRITE_TWION_0 _REWRITE_TWION + +int main(void){ + + // Constant macros + int x COMMA y = 1; // Tests that COMMA = , + + // Token paste test + int _cat_result = FOOBAR; // _CAT(FOO ,BAR) → FOOBAR → 12345 + printf("_CAT(FOO ,BAR) → %d\n", _cat_result); + printf("\n"); + + // Selector macros + int first = _FIRST(11 ,22 ,33); // → 11 + int second = _SECOND(11 ,22 ,33); // → 22 + printf("_FIRST(11 ,22 ,33) = %d\n", first); + printf("_SECOND(11 ,22 ,33) = %d\n", second); + printf("\n"); + + // Existence detection + int empty = EXISTS_ITEM(); // → 1 (rewrite hits) + int empty_0 = EXISTS_ITEM(0); // → 1 (rewrite hits) + int empty_1 = EXISTS_ITEM(1); // → 0 (no rewrite) + int empty_f = EXISTS_ITEM(hello); // → 0 + + printf("EXISTS_ITEM() = %d\n", empty); + printf("EXISTS_ITEM(0) = %d\n", empty_0); + printf("EXISTS_ITEM(1) = %d\n", empty_1); + printf("EXISTS_ITEM(hello) = %d\n", empty_f); + printf("\n"); + + // Not Existence detection + empty = NOT_EXISTS_ITEM(); // → 1 (rewrite hits) + empty_0 = NOT_EXISTS_ITEM(0); // → 1 (rewrite hits) + empty_1 = NOT_EXISTS_ITEM(1); // → 0 (no rewrite) + empty_f = NOT_EXISTS_ITEM(hello); // → 0 + + printf("NOT_EXISTS_ITEM() = %d\n", empty); + printf("NOT_EXISTS_ITEM(0) = %d\n", empty_0); + printf("NOT_EXISTS_ITEM(1) = %d\n", empty_1); + printf("NOT_EXISTS_ITEM(hello) = %d\n", empty_f); + printf("\n"); + + + // int empty_10 = EXISTS_ITEM(10,11,12); // illegal call, try it anyway ..compilation error + int empty_11 = EXISTS(10,11,12); // this is a legal call + int empty_12 = EXISTS(); + + // printf("EXISTS_ITEM(10,11,12) = %d\n", empty_10); + printf("EXISTS(10,11,12) = %d\n", empty_11); + printf("EXISTS() = %d\n", empty_12); + printf("\n"); + + // int empty_10 = EXISTS_ITEM(10,11,12); // illegal call, try it anyway ..compilation error + empty_11 = NOT_EXISTS(10,11,12); // this is a legal call + empty_12 = NOT_EXISTS(); + + // printf("NOT_EXISTS_ITEM(10,11,12) = %d\n", empty_10); + printf("NOT_EXISTS(10,11,12) = %d\n", empty_11); + printf("NOT_EXISTS() = %d\n", empty_12); + printf("\n"); + + + return 0; +} diff --git a/developer/experiment/macro_guards.c b/developer/experiment/macro_guards.c new file mode 100644 index 0000000..a0b3453 --- /dev/null +++ b/developer/experiment/macro_guards.c @@ -0,0 +1,66 @@ +#include +#include + +#define X(x) x + +#define _S(x) #x +#define S(x) _S(x) + +#define _Ξ(a ,b) a##·##b +#define Ξ(a ,b) _Ξ(a ,b) + +int main(){ + + #if X(10) + printf("goodness 10\n"); + #endif + + #define T S(abc) + printf("T:%s \n" ,T); + + #define U S(Ξ(FG·FACE ,FG·Type)) + printf("U:%s \n" ,U); + + #define FG·Type uint32_t + #define V S(Ξ(FG·FACE ,FG·Type)) + printf("V:%s \n" ,V); + + + //#ifndef Ξ(FG·FACE ,FG·Type) + // macro_guards.c: In function ‘main’: + // macro_guards.c:29:12: warning: extra tokens at end of #ifndef directive + // 29 | #ifndef Ξ(FG·FACE ,FG·Type) + // | ^ + +#if 0 + #ifndef Ξ(FG·FACE ,FG·Type) + printf("goodness 32\n"); + #define Ξ(FG·FACE ,FG·Type) + #else + printf("badness 32\n"); + #endif + + #undef FG·Type + #define FG·Type uint64_t + #ifndef Ξ(FG·FACE ,FG·Type) + printf("goodness 64\n"); + #define Ξ(FG·FACE ,FG·Type) + #else + printf("badness 64\n"); + #endif +#endif + +} + +/* + + Cannot expand a cpp macro to create the name of a cpp macro + +> ./a.out +goodness 10 +T:abc +U:FG·FACE·FG·Type +V:FG·FACE·uint32_t + + +*/ diff --git a/developer/experiment/macro_lib_examples.c b/developer/experiment/macro_lib_examples.c new file mode 100644 index 0000000..74b0d69 --- /dev/null +++ b/developer/experiment/macro_lib_examples.c @@ -0,0 +1,40 @@ + +/*=========================================================================== + Example Usage of the Macro Library +===========================================================================*/ + +#include "macro_lib.c" + +/* Register equality for the tokens we want to compare. + For each token X used in comparisons, define _IS_EQ_X_X as PROBE(). +*/ +#define _IS_EQ_dog_dog PROBE() +#define _IS_EQ_cat_cat PROBE() +#define _IS_EQ_parakeet_parakeet PROBE() +#define _IS_EQ_lizard_lizard PROBE() // Even if lizard might not be added + +/* Example 1: Using a static list defined as a macro */ +#define static_animals dog,cat,parakeet + +/* Example 2: Building a dynamic list using Append. + We start with an empty list, then append items. +*/ +#define list2 Append(dog) +#define list1 Append(list2,cat) +#define list Append(list1,parakeet) + +int main(void) { + /* Using the static list */ + printf("Static list animals:\n"); + printf("MATCH(dog, static_animals) = %d\n", MATCH(dog, static_animals)); + printf("MATCH(cat, static_animals) = %d\n", MATCH(cat, static_animals)); + printf("MATCH(lizard, static_animals) = %d\n", MATCH(lizard, static_animals)); + + /* Using the dynamic list built with Append */ + printf("\nDynamic list 'list':\n"); + printf("MATCH(dog, list) = %d\n", MATCH(dog, list)); + printf("MATCH(cat, list) = %d\n", MATCH(cat, list)); + printf("MATCH(parakeet, list) = %d\n", MATCH(parakeet, list)); + printf("MATCH(lizard, list) = %d\n", MATCH(lizard, list)); + return 0; +}