From: Thomas Walker Lynch Date: Thu, 27 Mar 2025 12:46:33 +0000 (+0000) Subject: nice study on cpp evaluation X-Git-Url: https://git.reasoningtechnology.com/style/static/git-logo.png?a=commitdiff_plain;h=f087cc8d4d1e138dc17b010c46782f4d6dc5f3e5;p=N nice study on cpp evaluation --- diff --git "a/developer/document\360\237\226\211/cpp_evaluation.org" "b/developer/document\360\237\226\211/cpp_evaluation.org" new file mode 100644 index 0000000..f9deead --- /dev/null +++ "b/developer/document\360\237\226\211/cpp_evaluation.org" @@ -0,0 +1,259 @@ +#+TITLE: C Preprocessor Evaluation Example +#+AUTHOR: Thomas Walker Lynch +#+OPTIONS: toc:nil + +1. Macro function definition + + A macro function has three parts, 1) a name 2) a parameter list 3) definition + + Parameters are declared by listing them between parenthesis after the name. No space + can occur between the name and the parameter list! If there is space then the + parameter list will be taken as part of the definition. + + Text after the parameter list forms the definition. + + #+BEGIN_SRC c + #define name(x ,y ,z) + #define name(...) // argument list becomes __VA_ARGS__ + #define name(x ,...) + #+END_SRC + +2. Macro call + + Can occur anywhere in the source code. Takes the form of an macro function + name followed by an argument list. + + #+BEGIN_SRC c + name (1 ,a ,b) + #+END_SRC + + In a call, space is allowed between the macro name and the arguments list. + + 1. Each parameter in the definition is replaced with the corresponding argument. + + 2. cpp then scans the definition from left to right. + + 2.1 Upon finding a non-macro call token cpp includes it as part of the result. + + 2.2. Uon finding a macro call token, it does a recursive evaluation on it. + + Non-macro call tokens include: + + 1. a non-identifier. + + 2. an identifier not followed by parenthesis. + + 3. anything followed by a `#` + + `#` returns an atomic string token made from what follows it + + 4. anything connected by '##' + + `##` does a concatenation and returns a new token. This new token is not evaluated. + + 2. Recursion has been designed out. + + Any macro call token that matches the name of the macro being evaluated is marked, and can never be called. It will forever more be treated as literal text. Note + the examples in the next section. + +3. Example macros + + #+BEGIN_SRC c + #define FORCE_ONE(x) 1 + #define STR(x) #x + #define VAL(x) STR(x) + #define GROW(x) 7 * GROW(x) + #+END_SRC + + A call to ~FORCE_ONE(5)~ will expand to ~1~. + + A call to ~STR(FORCE_ONE(5))~ will expand to the string ~"FORCE_ONE_(5)"~. This is because arguments given to the ~#~ operator are not expanded. The variable gets replaced with its value, but the value it not evaluated. + + A call to ~VAL(FORCE_ONE(5))~ will result in `1`. This is because there is no hash symbol in the VAL macro that is stopping the recursive expansion of ~x~. + +5. Example of delayed evaluation + + #+BEGIN_SRC c + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + #+END_SRC + + When evaluating ~NOT_SO_FAST(5)~, here's what happens: + + 1. ~NEGATE~ is encountered there is nothing to recur into, so it evaluates to itself. + the evaluation moves right. + + 2. ~EMPTY()~ is a macro, so it has no operands, so it is expanded. As it has no + definition, it expands to nothing. CPP then moves to the right. + + 3. ~(x)~ is not a macro so there is nothing to recur into, so it becomes ~(5)~. + + 4. Thus the final result of the left to right pass is → ~NEGATE (5)~ + + #+BEGIN_SRC bash + cat >test.c < + + int main(void){ + printf("example_eval.c\\n"); + + #define STR(x) #x + + // `#x` no evaluation of x due to the '#' + // `STR(x)` recurs and does a left to right expansion on the value of `x` + #define SHOW(x) printf(#x " → %s\\n", STR(x)); + + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + + SHOW(NOT_SO_FAST(5)); + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + } + EOF + + gcc test.c + ./a.out + #+END_SRC + + Output: + + #+BEGIN_EXAMPLE + example_eval.c + NOT_SO_FAST(5) → NEGATE (5) + BE(NOT_SO_FAST(5)) → -5 + #+END_EXAMPLE + + Let’s examine the final lines: + + #+BEGIN_SRC c + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + #+END_SRC + + The evaluation process: + + - cpp encounters ~BE(NOT_SO_FAST(5))~. + - It enters ~NOT_SO_FAST(5)~, expands it to ~NEGATE (5)~. + - Then ~BE(NEGATE (5))~ becomes ~-5~ through final macro expansion. + +6. Nesting, recursion approaches that do not work, and one that does. + + #+BEGIN_SRC c + + #include + #define STR(x) #x + // no evaluation, and one pass of evaluation + #define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + + #define BE(...) __VA_ARGS__ + #define EMPTY() + + #include + int main(void){ + printf("example_grow.c\n"); + printf("\n"); + + // case 1 + /* + GROW(7) → 17 * GROW(7) + GROW(GROW(5)) → 17 * GROW(17 * GROW(5)) + ,*/ + #define GROW(x) 17 * GROW(x) + SHOW(GROW(7)); + SHOW(GROW(GROW(5))); + printf("\n"); + + // case 2 + // GROW2(11) --> 19 * GROW2 (11) + #define GROW2(x) 19 * GROW2 EMPTY() (x) + SHOW(GROW2(11)) ; + printf("\n"); + + // case 3 + // GROW3(13) --> 119 * 19 * GROW2 (13) + #define GROW3(x) BE(119 * GROW2 EMPTY() (x)) + SHOW(GROW3(13)); + printf("\n"); + + // case 4 + /* + `BE` placed on the outside. The idea is that evaluation will return `123 * GROW (15)` and then this will be evaluated resulting in `123 * 123 * GROW(15)`. + + However, any time GROW4 literally spells out GROW4(...) inside its own expansion + it will leave it literally and not expand it. + + Though it is interesting that here that occurs at a higher level in the evaluation tree than the first ocurrance of the recursive call, but still it is in the tree. + + GROW4(15) --> 123 * GROW4 (15) + ,*/ + #define GROW4(x) BE(123 * GROW4 EMPTY() (x)) + SHOW(GROW4(15)); + printf("\n"); + + // case 5 + /* + Substitution of the function named followed by a trampoline works. + + The original expression is written in terms of a deferred CONDFEDERATE function + instead of in terms of a recursive call to GROW5. cpp can suspect nothing. + + The result is an expression in terms of the unevaluated CONDFEDERATE function. + + The CONFEDERATE function is defined to return the token GROW5. Hence in a subsequent evaluation, and there must be a subsequent evaluation for this to work, The CONFEDERATE function will run, return GROW5 which is next to its call parenthesis, so then the + recursive call will run. + + BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) + BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) + ,*/ + #define GROW5(x) 541 * CONFEDERATE EMPTY() () (x) + #define CONFEDERATE() GROW5 + SHOW(BE(GROW5(21))); + SHOW(BE(BE(GROW5(57)))); + printf("\n"); + + // case 6 + /* + Once a recursively called function is marked, or 'colored' it can never be expanded, even when passed through to another variable and separately evaluation. + ,*/ + #define GROW6(x) 1029 * GROW6 EMPTY() (x) + #define RESULT1 GROW6(51) + SHOW(RESULT1); + SHOW(BE(RESULT1)); + printf("\n"); + // RESULT1 --> 1029 * GROW6 (51) + // BE(RESULT1) --> 1029 * GROW6 (51) + + // case 7 + #define RESULT2 GROW6(151) + SHOW(RESULT2); + SHOW(BE(RESULT2)); + printf("\n"); + // RESULT2 --> 1029 * GROW6 (151) + // BE(RESULT2) --> 1029 * GROW6 (151) + + } + + #+END_SRC + +7. Discussion on recursion + + Case 6, and Case 7 above show that once a token is marked as a would-be recursive call token it is marked and can never be evaluated, no matter how hard the programmer + might try hide its actual origin. It can be assigned to variables, passed between co-routines, and nothing will help because the macro call token itself is marked. + + Case 5 shows a workaround. Instead of having a recursive call, a deferred call to a confederate is made. The resulting expression then amounts to a lazy evaluation. The return value from the evaluation will contain unmade calls to the confederate in each and every place that a recursive call was desired. + + In order to complete the evaluation, the lazy result must undergo a second evaluation, + where the confederate function calls are run, and they return the name of the original + function that was to be called, and then those calls are evaluated. + + This leads to a trade off. To have recursion we must have two evaluations of expressions so as to replace the confederates. + + Repeated evaluation is a consequence of using confederate method to avoid macro calls from being marked not to be evaluated. Deferring the calls is necessary so that the don't get replaced in the first evaluation so that their replacements don't get marked. + + Note that each recursive call, potentially results in ore expressions appearing. Hence, there must be as many evaluations as there are levels of recursion. This is a tell order for list processing. + + diff --git a/developer/example/cpp_RT.c b/developer/example/cpp_RT.c deleted file mode 100644 index 5482691..0000000 --- a/developer/example/cpp_RT.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - See also https://github.com/18sg/uSHET/blob/master/lib/cpp_magic.h - and tutorial at: http://jhnet.co.uk/articles/cpp_magic - - I could not have even thought about writing this without Jonathan Heathcote's - little tutorial. - - The 'twion' is cute. It is reminiscent of a complex number in math. It is a - pair given to functions that only take singletons. - -*/ - - - -/*=========================================================================== -Constants -===========================================================================*/ - -#define COMMA , -#define SEMICOLON ; - -#define _TWION_0 ~,0 -#define _TWION_1 ~,1 - -// RWR == rewrite rule, RWR_ is followed by macro name it is used in `__` -// Matching text is replaced with nothing, making it empty -// Potential for aliasing if x or y have '__oo__' embedded in them. -#define _RWR_NOT__0 -#define _RWR_AND__1__oo__1 -#define _RWR_OR__0__oo__0 - -// add more of this form to register other equalities -#define _RWR_EQ__0__oo__0 -#define _RWR_EQ__1__oo__1 - -/*=========================================================================== -Logic -===========================================================================*/ - -// user versions of these functions appear latter in the file - -//---------------------------------------- -// primitive access - - // note: _FIRST of nothing, _FIRST(), means passing an empty_item as the first item - // so it will return empty. - #define _FIRST(a ,...) a - #define _SECOND(a ,b ,...) b - -//---------------------------------------- -// existence - - // `##` prevents rewrite of _TWION_ in the _EXISTS_ITEM_1 macro - #define _EXISTS_ITEM_2(x_item) _SECOND(x_item ,1) - #define _EXISTS_ITEM_1(x_item) _EXISTS_ITEM_2(_TWION_0##x_item) - - #define EXISTS_ITEM(x_item) _EXISTS_ITEM_1(x_item) - #define EXISTS(...) EXISTS_ITEM( _FIRST(__VA_ARGS__) ) - - #define _NOT_EXISTS_ITEM_2(x_item) _SECOND(x_item ,0) - #define _NOT_EXISTS_ITEM_1(x_item) _NOT_EXISTS_ITEM_2(_TWION_1##x_item) - - #define NOT_EXISTS_ITEM(x_item) _NOT_EXISTS_ITEM_1(x_item) - #define NOT_EXISTS(...) NOT_EXISTS_ITEM( _FIRST(__VA_ARGS__) ) - - // useful to use with rewrite rules that substitute to nothing - #define MATCH(x_item) NOT_EXISTS(x_item) - #define NOT_MATCH(x_item) EXISTS(x_item) - -//---------------------------------------- -// primitive connectors - - #define _NOT_1(x_item) MATCH( _RWR_NOT__##x_item ) - #define _NOT(x_item) _NOT_1(x_item) - - #define _AND_1(x_item ,y_item) MATCH( _RWR_AND__##x_item##__oo__##y_item ) - #define _AND(x_item ,y_item) _AND_1(x_item ,y_item) - - #define _OR_1(x_item ,y_item) NOT_MATCH( _RWR_OR__##x_item##__oo__##y_item ) - #define _OR(x_item ,y_item) _OR_1(x_item ,y_item) - -//---------------------------------------- -// equality -// more general than a connector because more rules can be added. -// each has the form: -// _RWR_EQ____oo__ -// for example: -// _RWR_EQ__0__oo__0 - - #define _EQ(x_item ,y_item) MATCH( _RWR_EQ__##x_item##__oo__##y_item ) - #define EQ(x_item ,y_item) _EQ(x_item ,y_item) - - #define _NOT_EQ(x_item ,y_item) EXISTS(_RWR_EQ__##x_item##__oo__##y_item) - #define NOT_EQ(x_item ,y_item) _NOT_EQ(x_item ,y_item) - - -//---------------------------------------- -// connectors - - #define _BOOL_2(x_item) \ - _AND(\ - EXISTS_ITEM( _FIRST(x_item) ) \ - ,NOT_MATCH( _RWR_EQ__0__oo__##x_item) \ - ) - #define _BOOL_1(x_item) _BOOL_2(x_item) - #define BOOL(x_item) _BOOL_1(_FIRST(x_item)) - - - #define NOT(x_item) _NOT(BOOL(x_item)) - #define AND(x_item ,y_item) _AND(BOOL(x_item) ,BOOL(y_item)) - #define OR(x_item ,y_item) _OR(BOOL(x_item) ,BOOL(y_item)) - - diff --git a/developer/example/cpp_ext_0.c b/developer/example/cpp_ext_0.c new file mode 100644 index 0000000..35e8d81 --- /dev/null +++ b/developer/example/cpp_ext_0.c @@ -0,0 +1,255 @@ +/* + +Provides: + + COMMA, SEMICOLON, EXISTS, NOT_EXISTS, ,MATCH_RWR ,NOT_MATCH_RWR, BOOL, NOT, AND, OR, EQ, NOT_EQ, IF_ELSE + +1. + 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. + +2. + These are the non-recursive extensions. See cpp_ext_1 for the recursive extensions. + +3. + The 'twion' is cute. It is reminiscent of a complex number in math. Like the complex number that is fed into scalar equestions. The twion is a pair given to functions that only take singletons. + +4. + 0 is false + 1 is true + + Macros starting with an '_' (underscore) are private. + + EQ comparisons apart from logic comparisons, must be registered in advance. They take the form of, _RWR_EQ____oo__, note comments below. + +5. Evaluation + + 1. cpp does not evaluate arguments that in the definition are attached to hash operator. + + #define STR(x) #x // x is not evaluated. + #define VAL(x) STR(x) // x is evaluated recursively before STR is expanded + + The same applies for '##' + + 2. cpp evaluates from left to right, for each macro it finds it does depth first revalution. + + 3. Due to the left to right evaluation a funny things happens. + + #define EMPTY() + #define NEGATE(x) -x + + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + + What happens in left to right evaluation of NOT_SO_FAST(5) + 1. first NEGATE will be evaluated, there is nothing to expand + 2. EMPTY() is evaluated to nothing + 3. (x) is evaluated to 5. + 4. reached the right side, done result is: + + -> NEGATE (x) + + > cat >test.c << EOF + #include + int main(void){ + printf("example_eval.c\n"); + + #define STR(x) #x + + // `#x` no evaluation of x + // `STR(x)` one left to right pass evaluation of `x` due to depth recursion + #define SHOW(x) printf(#x " → %s\n", STR(x)); + + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + SHOW(NOT_SO_FAST(5)); + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + } + EOF + + > gcc test.c + > ./a.out + example_eval.c + NOT_SO_FAST(5) → NEGATE (5) + BE(NOT_SO_FAST(5)) → -5 + > + + Consider the lines: + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + + cpp left to right scan finds one macro to expand: BE(NOT_SO_FAST(5)) + cpp depth first into that macro finds 5, which expands to -> 5 + going up a level cpp tries: NOT_SO_FAST(5) -> NEGATE (5) + going up a level cpp tries: BE( NEGATE (5) ) -> BE( -5 ) -> -5 + + + + +*/ + +#ifndef CPP_EXT_0 +#define CPP_EXT_0 + + +/*=========================================================================== +Constants +===========================================================================*/ + +#define COMMA , +#define SEMICOLON ; + +#define ZERO 0 +#define ONE 1 + +//--------- + +#define _TWION_0 ~,0 +#define _TWION_1 ~,1 + +// RWR == rewrite rule, RWR_ is followed by macro name it is used in `__` +// Matching text is replaced with nothing, making it empty +// Potential for aliasing if x or y values 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 equivalences +#define _RWR_EQ__0__oo__0 +#define _RWR_EQ__1__oo__1 + +/*=========================================================================== +Logic +===========================================================================*/ + + //---------------------------------------- + // 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_RWR(x_item) NOT_EXISTS(x_item) + #define NOT_MATCH_RWR(x_item) EXISTS(x_item) + +/*=========================================================================== +Logic Connectors +===========================================================================*/ + + #define _NOT_1(x_item) MATCH_RWR( _RWR_NOT__##x_item ) + #define _NOT(x_item) _NOT_1(x_item) + + #define _AND_1(x_item ,y_item) MATCH_RWR( _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( _RWR_OR__##x_item##__oo__##y_item ) + #define _OR(x_item ,y_item) _OR_1(x_item ,y_item) + + #define _BOOL_2(x_item) \ + _AND(\ + EXISTS_ITEM( _FIRST(x_item) ) \ + ,NOT_MATCH_RWR( _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)) + +/*=========================================================================== + Equality + + more general than a connector because more rules can be added. + + each registered equality rule has the form + _RWR_EQ____oo__ + for example, logic equalities are already registered: + _RWR_EQ__0__oo__0 + _RWR_EQ__1__oo__1 + +===========================================================================*/ + + #define _EQ(x_item ,y_item) MATCH_RWR( _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) + + +/*=========================================================================== + IF-ELSE construct. + Usage: IF_ELSE(condition)()() + + A most amazing little macro. It has no dependencies on the other macros + in this file, though many will be useful for setting (condition) +===========================================================================*/ + + #define IF_ELSE(condition) _IF_ELSE(BOOL(condition)) + #define _IF_ELSE(condition) _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__ + +/*=========================================================================== +Access + see below the recursion section for Nth .. when it is written ;-) + +===========================================================================*/ + + // _FIRST defined in the logic section + #define FIRST(pad ,...)\ + If_ELSE \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + (pad) \ + ( _FIRST(__VA_ARGS__) ) + + #define _REST(a ,...) __VA_ARGS__ + #define REST(...)\ + If_ELSE \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + () \ + ( _REST(__VA_ARGS__) ) + + // _SECOND defined in the logic section + #define SECOND(pad ,...) \ + If_ELSE \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + (pad) \ + ( _SECOND(__VA_ARGS__ ,pad) ) + + #define _THIRD(a ,b ,c ,...) c + #define THIRD(pad ,...) \ + If_ELSE \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + (pad) \ + ( _THIRD(__VA_ARGS__ ,pad, pad) ) + + + +#endif diff --git a/developer/example/cpp_ext_1.c b/developer/example/cpp_ext_1.c new file mode 100644 index 0000000..1e35310 --- /dev/null +++ b/developer/example/cpp_ext_1.c @@ -0,0 +1,113 @@ +/* +These are the recursive extension. + +Simple errors can lead to very long error outputs, which might be why +the cpp designers had obviously intended that recursion would not be possible. + +*/ + +#ifndef CPP_EXT_1 +#define CPP_EXT_1 + +/*=========================================================================== + Force extra macro expansion (the EVAL trick) + This chain of EVAL macros forces the preprocessor to perform many rescans, + which is necessary to “unroll” recursive macros. +===========================================================================*/ +#define EVAL(...) EVAL1024(__VA_ARGS__) +#define 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 */ + + +/*=========================================================================== + IF-ELSE construct. + Usage: IF_ELSE(condition)()() + + A most amazing little macro. It has no dependencies on the other macros + in this file, though many will be useful for setting (condition) +===========================================================================*/ + + #define IF_ELSE(condition) 77 +# #define IF_ELSE(condition) BE64(_IF_ELSE_1(BOOL(condition))) + #define _IF_ELSE_1(condition) _IF_ELSE_2(condition) + #define _IF_ELSE_2(condition) _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__ + + + +/*=========================================================================== + 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 */) + + +/*=========================================================================== + MATCH(x,list) returns 1 if x is a member in the list, else 0 + + list is comma separated. + + when list is passed to EVAL(MATCH_IMPL(x,list)) it gets expanded + which causes the elements to spread out. + + #define list dog,cat,parakeet + Match(x,list) -> EVAL(MATCH_IMPL(x,dog,cat,parkeet)) + + HAS_ARGS will return true if there is a 'first' list element, else false. + + #define _IS_EQ__ Probe() must be defined for the equality test to work. + +===========================================================================*/ +#define MATCH_IMPL(x,first,...) \ + IF_ELSE \ + ( HAS_ARGS(first) ) \ + ( IF_ELSE \ + ( EQUAL(x,first) ) \ + (1) \ + ( MATCH_IMPL(x,__VA_ARGS__) ) \ + ) \ + (0) + +#define MATCH(x,list) EVAL(MATCH_IMPL(x,list)) + + + +#endif diff --git a/developer/example/cpp_recursion.c b/developer/example/cpp_recursion.c deleted file mode 100644 index 9f758e1..0000000 --- a/developer/example/cpp_recursion.c +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include "macro_lib.c" - -/* Define decrement values for numbers 1 through 5 */ -#define DEC_1 0 -#define DEC_2 1 -#define DEC_3 2 -#define DEC_4 3 -#define DEC_5 4 -#define DEC(n) DEC_##n - -/* - COUNT_DOWN(n): - - If n is 0, outputs "Done". - - Otherwise, outputs the current number (as a string), a space, - and then recursively calls COUNT_DOWN on DEC(n). - - Note: DEFER1 is used to postpone the recursive call, - and EVAL (via ESTR) will force the complete expansion. -*/ -#define COUNT_DOWN(n) IF_ELSE(EQUAL(n,0))("Done") ( XSTR(n) " " DEFER1(COUNT_DOWN)(DEC(n)) ) - -/* Minimal stringization helpers. - STR(x) stringizes without expanding; - XSTR(x) expands x first then stringizes; - ESTR(x) forces full expansion (using EVAL) then stringizes. -*/ -#define STR(x) #x -#define XSTR(x) STR(x) -#define ESTR(x) XSTR(EVAL(x)) - -int main(void) { - printf("Countdown from 5: %s\n", ESTR(COUNT_DOWN(5))); - return 0; -} diff --git a/developer/example/example_A.c b/developer/example/example_A.c new file mode 100644 index 0000000..9e02e3a --- /dev/null +++ b/developer/example/example_A.c @@ -0,0 +1,34 @@ +// from http://jhnet.co.uk/articles/cpp_magic + +#include +#define STR(x) #x +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#define EMPTY() +#define EVAL1(...) __VA_ARGS__ + +#define A(n) I like the number n + + +int main(){ + + printf( + " I like the number 123\n" + " A (123)\n" + ); + SHOW(A (123)); + SHOW(A EMPTY() (123)); + printf("\n"); + + printf( + " I like the number 123\n" + ); + SHOW(EVAL1(A EMPTY() (123))); + printf("\n"); + + + /* + ... The reason this works is that when CPP encounters a function-style macro, it recursively expands the macro's arguments before substituting the macro's body and expanding that. ... + */ + +}; diff --git a/developer/example/example_eval.c b/developer/example/example_eval.c new file mode 100644 index 0000000..99ae937 --- /dev/null +++ b/developer/example/example_eval.c @@ -0,0 +1,29 @@ +#include +#define STR(x) #x +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +int main(void){ + printf("example_eval.c\n"); + + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + SHOW(NOT_SO_FAST(5)); + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) +} + +/* + 2025-03-27T04:47:02Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > gcc example_eval.c + + 2025-03-27T04:47:32Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > ./a.out + example_eval.c + NOT_SO_FAST(5) → NEGATE (5) + BE(NOT_SO_FAST(5)) → -5 + +*/ diff --git a/developer/example/example_grow.c b/developer/example/example_grow.c new file mode 100644 index 0000000..ff88987 --- /dev/null +++ b/developer/example/example_grow.c @@ -0,0 +1,121 @@ +#include +#define STR(x) #x +// no evaluation, and one pass of evaluation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#define BE(...) __VA_ARGS__ +#define EMPTY() + +#include +int main(void){ + printf("example_grow.c\n"); + printf("\n"); + + // case 1 + /* + GROW(7) → 17 * GROW(7) + GROW(GROW(5)) → 17 * GROW(17 * GROW(5)) + */ + #define GROW(x) 17 * GROW(x) + SHOW(GROW(7)); + SHOW(GROW(GROW(5))); + printf("\n"); + + // case 2 + // GROW2(11) --> 19 * GROW2 (11) + #define GROW2(x) 19 * GROW2 EMPTY() (x) + SHOW(GROW2(11)) ; + printf("\n"); + + // case 3 + // GROW3(13) --> 119 * 19 * GROW2 (13) + #define GROW3(x) BE(119 * GROW2 EMPTY() (x)) + SHOW(GROW3(13)); + printf("\n"); + + // case 4 + /* + `BE` placed on the outside. The idea is that evaluation will return `123 * GROW (15)` and then this will be evaluated resulting in `123 * 123 * GROW(15)`. + + However, any time GROW4 literally spells out GROW4(...) inside its own expansion + it will leave it literally and not expand it. + + Though it is interesting that here that occurs at a higher level in the evaluation tree than the first ocurrance of the recursive call, but still it is in the tree. + + GROW4(15) --> 123 * GROW4 (15) + */ + #define GROW4(x) BE(123 * GROW4 EMPTY() (x)) + SHOW(GROW4(15)); + printf("\n"); + + // case 5 + /* + Substitution of the function named followed by a trampoline works. + + The original expression is written in terms of a deferred CONDFEDERATE function + instead of in terms of a recursive call to GROW5. cpp can suspect nothing. + + The result is an expression in terms of the unevaluated CONDFEDERATE function. + + The CONFEDERATE function is defined to return the token GROW5. Hence in a subsequent evaluation, and there must be a subsequent evaluation for this to work, The CONFEDERATE function will run, return GROW5 which is next to its call parenthesis, so then the + recursive call will run. + + BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) + BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) + */ + #define GROW5(x) 541 * CONFEDERATE EMPTY() () (x) + #define CONFEDERATE() GROW5 + SHOW(BE(GROW5(21))); + SHOW(BE(BE(GROW5(57)))); + printf("\n"); + + // case 6 + /* + Once a recursively called function is marked, or 'colored' it can never be expanded, even when passed through to another variable and separately evaluation. + */ + #define GROW6(x) 1029 * GROW6 EMPTY() (x) + #define RESULT1 GROW6(51) + SHOW(RESULT1); + SHOW(BE(RESULT1)); + printf("\n"); + // RESULT1 --> 1029 * GROW6 (51) + // BE(RESULT1) --> 1029 * GROW6 (51) + + // case 7 + #define RESULT2 GROW6(151) + SHOW(RESULT2); + SHOW(BE(RESULT2)); + printf("\n"); + // RESULT2 --> 1029 * GROW6 (151) + // BE(RESULT2) --> 1029 * GROW6 (151) + +} +/* + 2025-03-27T10:45:39Z[developer] +Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ +> gcc example_grow.c + +2025-03-27T11:43:19Z[developer] +Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ +> ./a.out +example_grow.c + +GROW(7) --> 17 * GROW(7) +GROW(GROW(5)) --> 17 * GROW(17 * GROW(5)) + +GROW2(11) --> 19 * GROW2 (11) + +GROW3(13) --> 119 * 19 * GROW2 (13) + +GROW4(15) --> 123 * GROW4 (15) + +BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) +BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) + +RESULT1 --> 1029 * GROW6 (51) +BE(RESULT1) --> 1029 * GROW6 (51) + +RESULT2 --> 1029 * GROW6 (151) +BE(RESULT2) --> 1029 * GROW6 (151) + +*/ diff --git a/developer/example/example_grow2.c b/developer/example/example_grow2.c new file mode 100644 index 0000000..714691e --- /dev/null +++ b/developer/example/example_grow2.c @@ -0,0 +1,29 @@ +#include + +#define STR(...) #__VA_ARGS__ +// no evaluation, and one pass of evaluation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#define BE(...) __VA_ARGS__ + +#define EMPTY() +#define GROW(x) 19 * _GROW EMPTY() ()(x) +#define _GROW() GROW + + +int main(void) +{ + printf("One-trampoline minimal example:\n\n"); + + //19 * _GROW ()(7) + SHOW(GROW(7)); + + // 19 * 19 * _GROW ()(7) + SHOW(BE(GROW(7))); + + // 19 * 19 * 19 * _GROW ()(7) + SHOW(BE(BE(GROW(7)))); + + + return 0; +} diff --git a/developer/example/example_recurse.c b/developer/example/example_recurse.c new file mode 100644 index 0000000..4c65d9b --- /dev/null +++ b/developer/example/example_recurse.c @@ -0,0 +1,54 @@ +// from http://jhnet.co.uk/articles/cpp_magic + +#include + +#define STR(...) #__VA_ARGS__ +// no evaluation, and one pass of evalutation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#define EMPTY() + +#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__ + +#define DEFER1(m) m EMPTY() + +#define RECURSE() I am recursive, look: DEFER1(_RECURSE)()() +#define _RECURSE() RECURSE + + +int main(){ + + printf( + "No EVAL:\n" + " RECURSE()\n" + ); + SHOW(RECURSE()); + printf("\n"); + + printf( + "With EVAL1:\n" + " EVAL1(RECURSE())\n" + ); + SHOW(EVAL1(RECURSE())); + printf("\n"); + + printf( + "With EVAL2:\n" + " EVAL2(RECURSE())\n" + ); + SHOW(EVAL2(RECURSE())); + printf("\n"); + + printf( + "With EVAL32:\n" + " EVAL32(RECURSE())\n" + ); + SHOW(EVAL32(RECURSE())); + printf("\n"); + +}; diff --git a/developer/example/scratchpad/#macro_lib.c# b/developer/example/scratchpad/#macro_lib.c# new file mode 100644 index 0000000..ab9f120 --- /dev/null +++ b/developer/example/scratchpad/#macro_lib.c# @@ -0,0 +1,124 @@ +/* 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__,~,~) + + + +/*=========================================================================== + Defer macros: these help “hide” recursive calls for additional expansion passes. +===========================================================================*/ +#define EMPTY() +#define DEFER1(m) m EMPTY() +#define DEFER2(m) m EMPTY EMPTY()() +#define DEFER3(m) m EMPTY EMPTY EMPTY()()() +#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()() /* as needed */ + +/*=========================================================================== + Token concatenation and basic utilities +===========================================================================*/ + +/* Assumes that EVAL,DEFER1,IF_ELSE,and HAS_ARGS are defined as in our macro library */ + +/* Helper: paste exactly two tokens with a separator. + If 'sep' is empty,then a ## sep ## b is equivalent to a ## b. +*/ +#define _CAT2(sep,a,b) a ## sep ## b + +#define _CAT(sep,first,...) \ + IF_ELSE(HAS_ARGS(__VA_ARGS__))( \ + _CAT2(sep,first,DEFER1(_CAT)(sep,__VA_ARGS__)) \ + )(first) + +/* Variadic CAT: + - If no tokens are provided,returns nothing. + - If one token is provided,returns that token. + - Otherwise,it recursively concatenates the tokens with the given separator. +*/ +#define CAT(sep,...) IF_ELSE(HAS_ARGS(__VA_ARGS__))( EVAL(_CAT(sep,__VA_ARGS__)) )(/* nothing */) + +#define Ξ(...) CAT(·,__VA_ARGS__) +#define Append(...) CAT(COMMA,__VA_ARGS__) + + +/*=========================================================================== + Put a 'PROBE()' in a list then detect it later. + + If a single value is given to IS_PROBE it won't have a second member,but + if the two element PROBE is given,the second element will be 1. + +===========================================================================*/ + +#define PROBE() ~,1 + +#define __IS_PROBE(a,b,...) b +#define _IS_PROBE(...) __IS_PROBE(__VA_ARGS__,0,0) +#define IS_PROBE(...) _IS_PROBE(__VA_ARGS__) + +#define _NOT_0 PROBE() + +// x == 0: _NOT_##x -> _NOT_0 -> ~,1 -> 1 +// x == 1: _NOT_##x -> _NOT_1 -> 0 +// +#define _NOT(x) IS_PROBE(_NOT_##x) +#define NOT(x) _NOT(x) +#define BOOL(x) NOT(NOT(x)) + +// This is a rewrite rule,if there is a definition for _IS_EQ__ it is replaced by its #define definition,presumably that of a Probe. +// The rule will then be #define _IS_EQ__ Probe() +#define _EQUAL_REWRITE(x,y) IS_PROBE( CAT(_IS_EQ_,x,_##y) ) + +#define EQUAL(x,y) BOOL( _EQUAL_REWRITE(x,y) ) + + + +/*=========================================================================== + HAS_ARGS: tests whether a variadic argument list is empty. + + A bit of a tricky one, _END_OF_ARGUMENTS will only be expanded if it + is followed by parenthesis,otherwise it is taken literally. +===========================================================================*/ +#define _END_OF_ARGUMENTS_() 0 +#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)()) + +/*=========================================================================== + MATCH(x,list) returns 1 if x is a member in the list, else 0 + + list is comma separated. + + when list is passed to EVAL(MATCH_IMPL(x,list)) it gets expanded + which causes the elements to spread out. + + #define list dog,cat,parakeet + Match(x,list) -> EVAL(MATCH_IMPL(x,dog,cat,parkeet)) + + HAS_ARGS will return true if there is a 'first' list element, else false. + + #define _IS_EQ__ Probe() must be defined for the equality test to work. + +===========================================================================*/ +#define MATCH_IMPL(x,first,...) \ + IF_ELSE \ + ( HAS_ARGS(first) ) \ + ( IF_ELSE \ + ( EQUAL(x,first) ) \ + (1) \ + ( MATCH_IMPL(x,__VA_ARGS__) ) \ + ) \ + (0) + +#define MATCH(x,list) EVAL(MATCH_IMPL(x,list)) + +/* End of macro_lib.c */ +#endif diff --git a/developer/example/scratchpad/cpp_recursion.c b/developer/example/scratchpad/cpp_recursion.c new file mode 100644 index 0000000..9f758e1 --- /dev/null +++ b/developer/example/scratchpad/cpp_recursion.c @@ -0,0 +1,35 @@ +#include +#include "macro_lib.c" + +/* Define decrement values for numbers 1 through 5 */ +#define DEC_1 0 +#define DEC_2 1 +#define DEC_3 2 +#define DEC_4 3 +#define DEC_5 4 +#define DEC(n) DEC_##n + +/* + COUNT_DOWN(n): + - If n is 0, outputs "Done". + - Otherwise, outputs the current number (as a string), a space, + and then recursively calls COUNT_DOWN on DEC(n). + + Note: DEFER1 is used to postpone the recursive call, + and EVAL (via ESTR) will force the complete expansion. +*/ +#define COUNT_DOWN(n) IF_ELSE(EQUAL(n,0))("Done") ( XSTR(n) " " DEFER1(COUNT_DOWN)(DEC(n)) ) + +/* Minimal stringization helpers. + STR(x) stringizes without expanding; + XSTR(x) expands x first then stringizes; + ESTR(x) forces full expansion (using EVAL) then stringizes. +*/ +#define STR(x) #x +#define XSTR(x) STR(x) +#define ESTR(x) XSTR(EVAL(x)) + +int main(void) { + printf("Countdown from 5: %s\n", ESTR(COUNT_DOWN(5))); + return 0; +} diff --git a/developer/example/scratchpad/tempt_eval.c b/developer/example/scratchpad/tempt_eval.c new file mode 100644 index 0000000..4f7b8aa --- /dev/null +++ b/developer/example/scratchpad/tempt_eval.c @@ -0,0 +1,23 @@ +#include +#include "macro_lib.c" + +/* A very simple base macro that expands to an integer literal */ +#define SIMPLE_MACRO1 549 +#define SIMPLE_MACRO2 7919 + +/* Define a chain of macros that simply pass along the value. + Each CALL_n() macro just calls the previous level. +*/ +#define CALL1() SIMPLE_MACRO1 +#define CALL2a() CALL1 EMPTY() () + 3 +#define CALL2b() DEFER1(CALL1)() + 5 + +int main(void) { + + printf( "SIMPLE_MACRO1 = %d\n", SIMPLE_MACRO1 ); + printf( "CALL1() = %d\n", EVAL(CALL1()) ); + printf( "CALL2a() = %d\n", EVAL(CALL2a()) ); + printf( "CALL2b() = %d\n", EVAL(CALL2b()) ); + + return 0; +} diff --git a/developer/example/tempt_eval.c b/developer/example/tempt_eval.c deleted file mode 100644 index 4f7b8aa..0000000 --- a/developer/example/tempt_eval.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include "macro_lib.c" - -/* A very simple base macro that expands to an integer literal */ -#define SIMPLE_MACRO1 549 -#define SIMPLE_MACRO2 7919 - -/* Define a chain of macros that simply pass along the value. - Each CALL_n() macro just calls the previous level. -*/ -#define CALL1() SIMPLE_MACRO1 -#define CALL2a() CALL1 EMPTY() () + 3 -#define CALL2b() DEFER1(CALL1)() + 5 - -int main(void) { - - printf( "SIMPLE_MACRO1 = %d\n", SIMPLE_MACRO1 ); - printf( "CALL1() = %d\n", EVAL(CALL1()) ); - printf( "CALL2a() = %d\n", EVAL(CALL2a()) ); - printf( "CALL2b() = %d\n", EVAL(CALL2b()) ); - - return 0; -} diff --git a/developer/example/try_1_exists.c b/developer/example/try_1_exists.c new file mode 100644 index 0000000..cd13b41 --- /dev/null +++ b/developer/example/try_1_exists.c @@ -0,0 +1,106 @@ +#include +#define STR(x) #x +// no evaluation, and one pass of evaluation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#include "cpp_ext_0.c" + +// 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; +} + +/* + 2025-03-27T12:38:04Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > gcc try_1_exists.c + + 2025-03-27T12:40:32Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > ./a.out + _CAT(FOO ,BAR) → 12345 + + _FIRST(11 ,22 ,33) = 11 + _SECOND(11 ,22 ,33) = 22 + + EXISTS_ITEM() = 0 + EXISTS_ITEM(0) = 1 + EXISTS_ITEM(1) = 1 + EXISTS_ITEM(hello) = 1 + + NOT_EXISTS_ITEM() = 1 + NOT_EXISTS_ITEM(0) = 0 + NOT_EXISTS_ITEM(1) = 0 + NOT_EXISTS_ITEM(hello) = 0 + + EXISTS(10,11,12) = 1 + EXISTS() = 0 + + NOT_EXISTS(10,11,12) = 0 + NOT_EXISTS() = 1 +*/ diff --git a/developer/example/try_2_connectors.c b/developer/example/try_2_connectors.c new file mode 100644 index 0000000..0003f19 --- /dev/null +++ b/developer/example/try_2_connectors.c @@ -0,0 +1,155 @@ +#include +#define STR(x) #x +// no evaluation, and one pass of evaluation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#include "cpp_ext_0.c" + +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; +} +/* + 2025-03-27T12:40:37Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > gcc try_2_connectors.c + + 2025-03-27T12:41:56Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > ./a.out + EXISTS_ITEM(x0) --> 0 + NOT_EXISTS_ITEM(x0) --> 1 + + MATCH(x0) --> MATCH() + NOT_MATCH(x0) --> NOT_MATCH() + + _NOT(0) --> 1 + _NOT(1) --> 0 + + _AND(0 ,0) --> 0 + _AND(1 ,0) --> 0 + _AND(0 ,1) --> 0 + _AND(1 ,1) --> 1 + _AND(1 ,x) --> 0 + + _OR(0 ,0) --> 0 + _OR(0 ,1) --> 1 + _OR(1 ,0) --> 1 + _OR(1 ,1) --> 1 + + _EQ(0 ,0) --> 1 + _EQ(1 ,1) --> 1 + _EQ(0 ,1) --> 0 + _EQ(x ,x) --> 0 + + _NOT_EQ(0 ,1) --> 1 + _NOT_EQ(0 ,0) --> 0 + + _BOOL_2(0) --> 0 + _BOOL_2(1) --> 1 + _BOOL_2(2) --> 1 + _BOOL_2(x0) --> 0 + + BOOL(0) --> 0 + BOOL(1) --> 1 + BOOL(10) --> 1 + BOOL() --> 0 + BOOL(x0) --> 0 + + NOT(0) --> 1 + NOT(1) --> 0 + NOT() --> 1 + NOT(10) --> 0 + + AND(1 ,0) --> 0 + AND(1 ,1) --> 1 + + OR(0 ,0) --> 0 + OR(1 ,0) --> 1 + + + 2025-03-27T12:41:59Z[developer] + Thomas-developer@Stanley§/home/Thomas-masu/developer/N/developer/example§ + > +*/ diff --git a/developer/example/try_3_if.c b/developer/example/try_3_if.c new file mode 100644 index 0000000..5c617e4 --- /dev/null +++ b/developer/example/try_3_if.c @@ -0,0 +1,62 @@ +#include +#define STR(x) #x +// no evaluation, and one pass of evaluation +#define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + +#include "cpp_ext_0.c" + +int main(void){ + + //--------------------------------------------------------------------------- + // Basic boolean cases + //--------------------------------------------------------------------------- + + SHOW(IF_ELSE(1)(yes)(no)); +#if 0 + SHOW(IF_ELSE(0)(yes)(no)); // → no + + //--------------------------------------------------------------------------- + // Symbolic identifiers + //--------------------------------------------------------------------------- + SHOW(IF_ELSE(TRUE)(ok)(fail)); // → ok + SHOW(IF_ELSE(FALSE)(ok)(fail)); // → fail + SHOW(IF_ELSE(foo)(alpha)(omega)); // → omega (foo is undefined) + + //--------------------------------------------------------------------------- + // Logic expressions + //--------------------------------------------------------------------------- + SHOW(IF_ELSE(AND(1 ,1))(pass)(fail)); // → pass + SHOW(IF_ELSE(OR(0 ,0))(yes)(no)); // → no + SHOW(IF_ELSE(NOT(0))(on)(off)); // → on + + //--------------------------------------------------------------------------- + // Code-like output + //--------------------------------------------------------------------------- + SHOW(IF_ELSE(1)(int x = 1;)(int x = 2;)); // → int x = 1; + SHOW(IF_ELSE(0)(int x = 1;)(int x = 2;)); // → int x = 2; + + //--------------------------------------------------------------------------- + // Comma usage in true/false branches + //--------------------------------------------------------------------------- + SHOW(IF_ELSE(1)(a ,b ,c)(x ,y ,z)); // → a ,b ,c + SHOW(IF_ELSE(0)(a ,b ,c)(x ,y ,z)); // → x ,y ,z + + //--------------------------------------------------------------------------- + // Empty condition + //--------------------------------------------------------------------------- + SHOW(IF_ELSE()(true)(false)); // → false (BOOL() = 0) + + //--------------------------------------------------------------------------- + // Nested IF_ELSE + //--------------------------------------------------------------------------- + SHOW( + IF_ELSE(AND(1 ,1))( + IF_ELSE(0)(inner_true)(inner_false) + )( + outer_false + ) + ); // → inner_false + +#endif + return 0; +} diff --git a/developer/example/try_access.c b/developer/example/try_access.c new file mode 100644 index 0000000..0089610 --- /dev/null +++ b/developer/example/try_access.c @@ -0,0 +1,43 @@ +#include +#include "cpp_ext_0.c" + +#define SHOW(x) printf(#x " = %s\n", x) + +#define STRINGIFY(x) #x +#define EXPAND_STRING(x) STRINGIFY(x) + +int main(void){ + //--------------------------------------------------------------------------- + // FIRST with pad fallback + //--------------------------------------------------------------------------- + SHOW(EXPAND_STRING(FIRST(none))); // → none + SHOW(EXPAND_STRING(FIRST(pad ,x))); // → x + SHOW(EXPAND_STRING(FIRST(pad ,x ,y ,z))); // → x + + //--------------------------------------------------------------------------- + // SECOND with pad fallback + //--------------------------------------------------------------------------- + SHOW(EXPAND_STRING(SECOND(pad))); // → pad + SHOW(EXPAND_STRING(SECOND(pad ,a))); // → pad + SHOW(EXPAND_STRING(SECOND(pad ,a ,b))); // → b + SHOW(EXPAND_STRING(SECOND(pad ,a ,b ,c))); // → b + + //--------------------------------------------------------------------------- + // THIRD with pad fallback + //--------------------------------------------------------------------------- + SHOW(EXPAND_STRING(THIRD(pad))); // → pad + SHOW(EXPAND_STRING(THIRD(pad ,a))); // → pad + SHOW(EXPAND_STRING(THIRD(pad ,a ,b))); // → pad + SHOW(EXPAND_STRING(THIRD(pad ,a ,b ,c))); // → c + SHOW(EXPAND_STRING(THIRD(pad ,a ,b ,c ,d))); // → c + + //--------------------------------------------------------------------------- + // REST returns the tail after the first item + //--------------------------------------------------------------------------- + SHOW(EXPAND_STRING(REST())); // → (empty) + SHOW(EXPAND_STRING(REST(a))); // → (empty) + SHOW(EXPAND_STRING(REST(a ,b))); // → b + SHOW(EXPAND_STRING(REST(a ,b ,c))); // → b ,c + + return 0; +} diff --git a/developer/example/try_connectors.c b/developer/example/try_connectors.c deleted file mode 100644 index af96825..0000000 --- a/developer/example/try_connectors.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include "cpp_RT.c" - -#define SHOW( x) printf(#x " = %d\n", x) - -int main(void){ - //-------------------------------------------------------------------------- - // Existence Checks (sanity anchor) - //-------------------------------------------------------------------------- - - #define x0 - SHOW( EXISTS_ITEM(x0) ); // → 0 (assumed undefined) - SHOW( NOT_EXISTS_ITEM(x0) ); // → 1 - printf("\n"); - - SHOW( MATCH(x0) ); - SHOW( NOT_MATCH(x0) ); - printf("\n"); - - - //-------------------------------------------------------------------------- - // Primitive Connectors - //-------------------------------------------------------------------------- - - SHOW( _NOT(0) ); // _RWR_NOT_0 is defined → MATCH → 1 - SHOW( _NOT(1) ); // no rule → MATCH fails → 0 - printf("\n"); - - SHOW( _AND(0 ,0) ); // rule defined → MATCH → 1 - SHOW( _AND(1 ,0) ); // rule defined → MATCH → 1 - SHOW( _AND(0 ,1) ); // rule defined → MATCH → 1 - SHOW( _AND(1 ,1) ); // rule defined → MATCH → 1 - SHOW( _AND(1 ,x) ); // not legal args, but worked, rule missing → MATCH fails → 0 - printf("\n"); - - SHOW( _OR(0 ,0) ); // rule defined → NOT_MATCH → 0 - SHOW( _OR(0 ,1) ); // rule missing → NOT_MATCH → 1 - SHOW( _OR(1 ,0) ); // rule missing → NOT_MATCH → 1 - SHOW( _OR(1 ,1) ); // rule missing → NOT_MATCH → 1 - printf("\n"); - - - - //-------------------------------------------------------------------------- - // Equality - //-------------------------------------------------------------------------- - - SHOW( _EQ(0 ,0) ); // rule defined → MATCH → 1 - SHOW( _EQ(1 ,1) ); // rule defined → MATCH → 1 - SHOW( _EQ(0 ,1) ); // no rule → MATCH fails → 0 - SHOW( _EQ(x ,x) ); // no rule → MATCH fails → 0 - printf("\n"); - - SHOW( _NOT_EQ(0 ,1) ); // rule missing → EXISTS → 1 - SHOW( _NOT_EQ(0 ,0) ); // rule exists → EXISTS → 0 - printf("\n"); - - //-------------------------------------------------------------------------- - // Logical Connectors (BOOL + AND/OR/NOT) - //-------------------------------------------------------------------------- - - SHOW( _BOOL_2(0) ); // 0 - SHOW( _BOOL_2(1) ); // 1 - SHOW( _BOOL_2(2) ); // 1 because it exists - SHOW( _BOOL_2(x0) ); // 0 because it does not exit (see the #define at the top) - printf("\n"); - - SHOW( BOOL(0) ); // _FIRST = 0, EXISTS_ITEM(_FIRST) = 0 → _AND(0 ,1) → 0 - SHOW( BOOL(1) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 - SHOW( BOOL(10) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 - SHOW( BOOL() ); // EXISTS_ITEM(1) = 0 → BOOL = 0 - SHOW( BOOL(x0) ); // EXISTS_ITEM(1) = 0 → BOOL = 0 - printf("\n"); - - SHOW( NOT(0) ); // BOOL = 0 → NOT(0) = _NOT(0) = 1 - SHOW( NOT(1) ); // BOOL = 0 → NOT(0) = 1 - SHOW( NOT() ); // BOOL = 0 → NOT(0) = 1 - SHOW( NOT(10) ); // BOOL = 0 → NOT(0) = 1 - printf("\n"); - - SHOW( AND(1 ,0) ); // 0 - SHOW( AND(1 ,1) ); // BOOL(1), BOOL(1) = 0,0 → AND(0 ,0) = _AND(0 ,0) = 1 - printf("\n"); - - SHOW( OR(0 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 - SHOW( OR(1 ,0) ); // BOOL(1), BOOL(0) = 0,0 → OR(0 ,0) = _OR(0 ,0) = 0 - printf("\n"); - - return 0; -} diff --git a/developer/example/try_exists.c b/developer/example/try_exists.c deleted file mode 100644 index 4eee2e8..0000000 --- a/developer/example/try_exists.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include "cpp_RT.c" - - -#define STR(x) #x -#define XSTR(x) STR(x) - - -// Patch for CAT to succeed -#define FOOBAR 12345 - -// Patch for _EXISTS to succeed on 0 -#define _REWRITE_TWION_0 _REWRITE_TWION - -int main(void){ - - // Constant macros - int x COMMA y = 1; // Tests that COMMA = , - - // Token paste test - int _cat_result = FOOBAR; // _CAT(FOO ,BAR) → FOOBAR → 12345 - printf("_CAT(FOO ,BAR) → %d\n", _cat_result); - printf("\n"); - - // Selector macros - int first = _FIRST(11 ,22 ,33); // → 11 - int second = _SECOND(11 ,22 ,33); // → 22 - printf("_FIRST(11 ,22 ,33) = %d\n", first); - printf("_SECOND(11 ,22 ,33) = %d\n", second); - printf("\n"); - - // Existence detection - int empty = EXISTS_ITEM(); // → 1 (rewrite hits) - int empty_0 = EXISTS_ITEM(0); // → 1 (rewrite hits) - int empty_1 = EXISTS_ITEM(1); // → 0 (no rewrite) - int empty_f = EXISTS_ITEM(hello); // → 0 - - printf("EXISTS_ITEM() = %d\n", empty); - printf("EXISTS_ITEM(0) = %d\n", empty_0); - printf("EXISTS_ITEM(1) = %d\n", empty_1); - printf("EXISTS_ITEM(hello) = %d\n", empty_f); - printf("\n"); - - // Not Existence detection - empty = NOT_EXISTS_ITEM(); // → 1 (rewrite hits) - empty_0 = NOT_EXISTS_ITEM(0); // → 1 (rewrite hits) - empty_1 = NOT_EXISTS_ITEM(1); // → 0 (no rewrite) - empty_f = NOT_EXISTS_ITEM(hello); // → 0 - - printf("NOT_EXISTS_ITEM() = %d\n", empty); - printf("NOT_EXISTS_ITEM(0) = %d\n", empty_0); - printf("NOT_EXISTS_ITEM(1) = %d\n", empty_1); - printf("NOT_EXISTS_ITEM(hello) = %d\n", empty_f); - printf("\n"); - - - // int empty_10 = EXISTS_ITEM(10,11,12); // illegal call, try it anyway ..compilation error - int empty_11 = EXISTS(10,11,12); // this is a legal call - int empty_12 = EXISTS(); - - // printf("EXISTS_ITEM(10,11,12) = %d\n", empty_10); - printf("EXISTS(10,11,12) = %d\n", empty_11); - printf("EXISTS() = %d\n", empty_12); - printf("\n"); - - // int empty_10 = EXISTS_ITEM(10,11,12); // illegal call, try it anyway ..compilation error - empty_11 = NOT_EXISTS(10,11,12); // this is a legal call - empty_12 = NOT_EXISTS(); - - // printf("NOT_EXISTS_ITEM(10,11,12) = %d\n", empty_10); - printf("NOT_EXISTS(10,11,12) = %d\n", empty_11); - printf("NOT_EXISTS() = %d\n", empty_12); - printf("\n"); - - - return 0; -}