adding cpp extentions as per cpp magic
authorThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 26 Mar 2025 10:08:44 +0000 (10:08 +0000)
committerThomas Walker Lynch <eknp9n@reasoningtechnology.com>
Wed, 26 Mar 2025 10:08:44 +0000 (10:08 +0000)
25 files changed:
developer/cc🖉/Core.lib.c
developer/cc🖉/FG.lib.c [new file with mode: 0644]
developer/cc🖉/TM.lib.c
developer/document🖉/cpp.org [new file with mode: 0644]
developer/document🖉/cpp.txt [new file with mode: 0644]
developer/example/#try_connectors.c# [new file with mode: 0644]
developer/example/cpp_RT.c [new file with mode: 0644]
developer/example/cpp_recursion.c [new file with mode: 0644]
developer/example/scratchpad/cpp_IF.c [new file with mode: 0644]
developer/example/scratchpad/cpp_extentions.c [new file with mode: 0644]
developer/example/scratchpad/cpp_magic.c [new file with mode: 0644]
developer/example/scratchpad/example_macro_access.c [new file with mode: 0644]
developer/example/scratchpad/example_macro_logic.c [new file with mode: 0644]
developer/example/scratchpad/macro_cat.c [new file with mode: 0644]
developer/example/scratchpad/macro_lib.c [new file with mode: 0644]
developer/example/scratchpad/macro_logic.c [new file with mode: 0644]
developer/example/scratchpad/macro_use.c [new file with mode: 0644]
developer/example/scratchpad/try_eval_order.c [new file with mode: 0644]
developer/example/scratchpad/try_macro_cat.c [new file with mode: 0644]
developer/example/scratchpad/try_pasting.c [new file with mode: 0644]
developer/example/tempt_eval.c [new file with mode: 0644]
developer/example/try_connectors.c [new file with mode: 0644]
developer/example/try_exists.c [new file with mode: 0644]
developer/experiment/macro_guards.c [new file with mode: 0644]
developer/experiment/macro_lib_examples.c [new file with mode: 0644]

index a14ec2e..3e78126 100644 (file)
@@ -17,6 +17,9 @@
 */
 
 #define Core·DEBUG
+#ifdef FG·DEBUG
+  #include <stdio.h>
+#endif
 
 #ifndef FACE
 #define Core·IMPLEMENTATION
       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
   //----------------------------------------
     } 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 <stdio.h>
-    #endif
 
   //--------------------------------------------------------------------------------
   // implementation to go into the lib.a file
diff --git a/developer/cc🖉/FG.lib.c b/developer/cc🖉/FG.lib.c
new file mode 100644 (file)
index 0000000..566460e
--- /dev/null
@@ -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 <stdio.h>
+  #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
+
index 35a9ded..f748db6 100644 (file)
 */
 
 #define TM·DEBUG
+#ifdef TM·DEBUG
+  #include <stdio.h>
+#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 <stdint.h>
   #include <stddef.h>
 
   #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
       | TM·Head·Status·rightmost
       ;
 
-
   #endif // #ifndef CVT
 
-  #ifdef CVT
+  #if TM·All
 
+    // TM·<CVT>·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 <stdio.h>
-    #endif
 
   // implementation to go into the lib.a file
   //
       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
 
 
     #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🖉/cpp.org b/developer/document🖉/cpp.org
new file mode 100644 (file)
index 0000000..3d26734
--- /dev/null
@@ -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🖉/cpp.txt b/developer/document🖉/cpp.txt
new file mode 100644 (file)
index 0000000..3896b03
--- /dev/null
@@ -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##<empty>. 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 <empty> 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 (file)
index 0000000..af96825
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#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 (file)
index 0000000..5482691
--- /dev/null
@@ -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 `_<name>_`
+// 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__<x>__oo__<y>
+//   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 (file)
index 0000000..9f758e1
--- /dev/null
@@ -0,0 +1,35 @@
+#include <stdio.h>
+#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 (file)
index 0000000..0fcce7f
--- /dev/null
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#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 (file)
index 0000000..5e828bb
--- /dev/null
@@ -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 `_<name>_`
+// 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__<A>__oo__<A> 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 (file)
index 0000000..5e828bb
--- /dev/null
@@ -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 `_<name>_`
+// 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__<A>__oo__<A> 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 (file)
index 0000000..7a39ef7
--- /dev/null
@@ -0,0 +1,44 @@
+#include <stdio.h>
+
+/* 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 (file)
index 0000000..37bf0fe
--- /dev/null
@@ -0,0 +1,48 @@
+#include <stdio.h>
+
+#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 (file)
index 0000000..732b431
--- /dev/null
@@ -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 (file)
index 0000000..de15113
--- /dev/null
@@ -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_<x>_<y> it is replaced by its #define definition,presumably that of a Probe.
+// The rule will then be  #define _IS_EQ_<X>_<X> 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)(<true case>)(<false case>)
+===========================================================================*/
+#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_<x>_<x> 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 (file)
index 0000000..090fc7c
--- /dev/null
@@ -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 `<empty>,·FALSE` for
+     `x`. This makes x into a two token value, and the argument list for SECOND will be:
+
+     `<empty> ,·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)(<true case>)(<false case>)
+===========================================================================*/
+#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 (file)
index 0000000..d90dcf1
--- /dev/null
@@ -0,0 +1,64 @@
+#include <stdio.h>
+#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 (file)
index 0000000..f1ffcb0
--- /dev/null
@@ -0,0 +1,32 @@
+#include <stdio.h>
+
+/*===========================================================================
+  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 (file)
index 0000000..258d08f
--- /dev/null
@@ -0,0 +1,41 @@
+// try_macro_cat.c
+#include <stdio.h>
+#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 (file)
index 0000000..033a638
--- /dev/null
@@ -0,0 +1,41 @@
+#include <stdio.h>
+
+#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 (file)
index 0000000..4f7b8aa
--- /dev/null
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#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 (file)
index 0000000..af96825
--- /dev/null
@@ -0,0 +1,90 @@
+#include <stdio.h>
+#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 (file)
index 0000000..4eee2e8
--- /dev/null
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#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 (file)
index 0000000..a0b3453
--- /dev/null
@@ -0,0 +1,66 @@
+#include<stdio.h>
+#include<stdint.h>
+
+#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 (file)
index 0000000..74b0d69
--- /dev/null
@@ -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;
+}