*/
#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
--- /dev/null
+/*
+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
+
*/
#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;
--- /dev/null
+#+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.
+
--- /dev/null
+
+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.)
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ 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))
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/*
+ 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))
+
+
--- /dev/null
+/*
+ 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))
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+/*===========================================================================
+ 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 */)
--- /dev/null
+/* 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
--- /dev/null
+/*===========================================================================
+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__
+
+
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+// 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;
+}
--- /dev/null
+#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)));
+ | ^~~~
+
+*./
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
+}
--- /dev/null
+#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
+
+
+*/
--- /dev/null
+
+/*===========================================================================
+ 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;
+}