From: Thomas Walker Lynch Date: Wed, 2 Apr 2025 13:32:49 +0000 (+0000) Subject: bindling_type example workign with new gates X-Git-Url: https://git.reasoningtechnology.com/style/static/git-logo.png?a=commitdiff_plain;h=b74f73b22a62add82bb97d6662f521c927fc4b00;p=N bindling_type example workign with new gates --- diff --git "a/developer/cc\360\237\226\211/Binding.lib.c" "b/developer/cc\360\237\226\211/Binding.lib.c" index da7a380..c1bad54 100644 --- "a/developer/cc\360\237\226\211/Binding.lib.c" +++ "b/developer/cc\360\237\226\211/Binding.lib.c" @@ -1,5 +1,5 @@ /* -This files declares a binding struct named [Binding·TYPE]. It also provides +This files declares a binding struct named [Binding]. It also provides the macro `call` that uses the binding. Note this file does not make an instance of the binding, and does not intialize @@ -7,7 +7,7 @@ fields in an instance. Template parameters: - Binding·TYPE - Type used to name the binding struct. Binding struct instances get passed as arguments to functions etc. + Binding - Type used to name the binding struct. Binding struct instances get passed as arguments to functions etc. */ @@ -23,14 +23,12 @@ Template parameters: #define Binding·DEBUG #ifdef Binding·DEBUG #include - #pragma message( "in #ifndef Binding·TYPE_LIST section" ) + #pragma message( "in #ifndef Binding_LIST section" ) #endif #include "cpp_ext.c" #include "Core.lib.c" - #define Binding·NO_BINDING_FOR(x) BOOLEAN(NOT(CAT2(Binding·TYPE· ,x))) - /* usage e.g.: Binding·call(tm, function_name, arg1, arg2, ...) Expands to: (tm.fg->function_name)(tm ,arg1 ,arg2, ...) @@ -46,25 +44,25 @@ Template parameters: #endif -// once per Binding·TYPE value -#ifdef Binding·TYPE -#if Binding·NO_BINDING_FOR(Binding·TYPE) +// once per Binding value +#ifdef Binding +#if BOOLEAN(NOT_IN(Binding·SET ,Binding)) #ifdef Binding·DEBUG - #pragma message( "adding binding for:" STR_VAL(Binding·TYPE) ) + #pragma message( "adding binding for:" STR_VAL(Binding) ) #endif - struct Ξ(Binding·TYPE ,FG); - typedef struct Ξ(Binding·TYPE ,FG) Ξ(Binding·TYPE ,FG); + struct Ξ(Binding ,FG); + typedef struct Ξ(Binding ,FG) Ξ(Binding ,FG); - struct Ξ(Binding·TYPE ,Tableau); - typedef struct Ξ(Binding·TYPE ,Tableau) Ξ(Binding·TYPE ,Tableau); + struct Ξ(Binding ,Tableau); + typedef struct Ξ(Binding ,Tableau) Ξ(Binding ,Tableau); - typedef struct Ξ(Binding·TYPE){ - Ξ(Binding·TYPE ,Tableau) *tableau; - Ξ(Binding·TYPE ,FG) *fg; - } Ξ(Binding·TYPE); + typedef struct Ξ(Binding){ + Ξ(Binding ,Tableau) *tableau; + Ξ(Binding ,FG) *fg; + } Ξ(Binding); - static void Binding·wellformed_binding(Ξ(Binding·TYPE) b){ + static void Binding·wellformed_binding(Ξ(Binding) b){ #ifdef Binding·DEBUG Core·Guard·init_count(chk); Core·Guard·fg.check(&chk, 1, b.fg, "NULL fg table"); @@ -97,5 +95,5 @@ Template parameters: //-------------------------------------------------------------------------------- // undef the template parameters //-------------------------------------------------------------------------------- -#undef Binding·TYPE +#undef Binding diff --git "a/developer/cc\360\237\226\211/TM.lib.c" "b/developer/cc\360\237\226\211/TM.lib.c" index 0f93de3..ba2d80c 100644 --- "a/developer/cc\360\237\226\211/TM.lib.c" +++ "b/developer/cc\360\237\226\211/TM.lib.c" @@ -18,8 +18,8 @@ //-------------------------------------------------------------------------------- // once per translation unit -#ifndef TM·CVT_LIST -#define TM·CVT_LIST +#ifndef TM·FACE +#define TM·FACE #include #include @@ -64,19 +64,12 @@ #endif -// once per TM·CVT value #ifdef TM·CVT -#if NOT_CONTAINS( TM·CVT ,TM·CVT_LIST ) -#ifdef Binding·DEBUG - #pragma message( STR_VAL(TM·CVT_LIST) ) +#if BOOLEAN(NOT_IN(TM·SET ,TM·CVT)) +#ifdef TM·CVT·DEBUG + #pragma message( "adding binding for:" STR_VAL(Binding) ) #endif - //this is what it takes to append to a list in cpp ... - #undef TEMP - #define TEMP TM·CVT_LIST ,TM·CVT - #undef TM·CVT_LIST - #define TM·CVT_LIST TEMP - // some synonyms to make this section easier to read #undef TM #define TM Ξ(TM ,TM·CVT) diff --git "a/developer/cc\360\237\226\211/cpp_ext_0.c" "b/developer/cc\360\237\226\211/cpp_ext_0.c" index 2c2a661..0a8d334 100644 --- "a/developer/cc\360\237\226\211/cpp_ext_0.c" +++ "b/developer/cc\360\237\226\211/cpp_ext_0.c" @@ -160,6 +160,23 @@ LOGIC #define AND2(x ,y) IF(x) (y) () #define OR2(x ,y) IF(x) (1) (y) +/*=========================================================================== + Set + User must define set members manually: + + #define __ + + For example a set named TRIP with 1 ,2 ,3 in it: + + #define TRIP__1 + #define TRIP__2 + #define TRIP__3 + +*/ + +#define IN(set ,x) NOT(CAT3(set ,__ ,x)) +#define NOT_IN(set ,x) CAT3(set ,__ ,x) + /*=========================================================================== Registered Equivalence diff --git "a/developer/document\360\237\226\211/C_features_needed.org" "b/developer/document\360\237\226\211/C_features_needed.org" new file mode 100644 index 0000000..ae7f77f --- /dev/null +++ "b/developer/document\360\237\226\211/C_features_needed.org" @@ -0,0 +1,29 @@ + +1. C needs namespaces. The '·' notation seems to accomplish most of what is needed, and I'm doing this in existing C. Scoped 'using' would be nice for shortening the identifiers. + This can be done without changing the tool chain. + +2. control of evaluation in definitions + + Currently definitions remain literal text. + + Also #reassign assignment to a name an definition, possible with expansion and + using the same macro name taken with its older definition. Selective expansion + in definitions also needed. + + Without namespaces I can see the problem with developers stepping on each others's macro ames. However, with namespaces it seems that #redefine, or #redef is tractable. + +3. Something should be done about macros having to be on one line and having to account for, format, all those \. Perhaps an emacs mode similar as used for paragraphs? Anyway something should be done. + +4. ability to declare a type hierarchy based on struct types having the same field + names and format, or extensions thereof. + + typehier pair -> vector-2d -> complex + + Something like that. + +5. compiler switch to put the struct etc. types into the same space with the others. of course. + + +6. ability to use a macro to define a macro name. first create a value, then + call a function to enter it into the symbol table. + diff --git "a/developer/document\360\237\226\211/Needed_in_C.org" "b/developer/document\360\237\226\211/Needed_in_C.org" deleted file mode 100644 index d82aa95..0000000 --- "a/developer/document\360\237\226\211/Needed_in_C.org" +++ /dev/null @@ -1,27 +0,0 @@ - -1. C needs namespaces. The '·' notation seems to accomplish most of what is needed, and I'm doing this in existing C. Scoped 'using' would be nice for shortening the identifiers. - This can be done without changing the tool chain. - -2. control of evaluation in definitions - - Currently definitions remain literal text. - - Also #redefine delayed assignment to macro_name, with evaluation of the body. - - Without namespaces I can see the problem with developers stepping on each others's macro ames. However, with namespaces it seems that #redefine, or #redef is tractable. - -3. Something should be done about macros having to be on one line and having to account for, format, all those \. Perhaps an emacs mode similar as used for paragraphs? Anyway something should be done. - -4. ability to declare a type hierarchy based on struct types having the same field - names and format, or extensions thereof. - - typehier pair -> vector-2d -> complex - - Something like that. - -5. compiler switch to put the struct etc. types into the same space with the others. of course. - - -6. ability to use a macro to define a macro name. first create a value, then - call a function to enter it into the symbol table. - diff --git "a/developer/document\360\237\226\211/cpp_evaluation.org" "b/developer/document\360\237\226\211/cpp_evaluation.org" deleted file mode 100644 index 4529a7a..0000000 --- "a/developer/document\360\237\226\211/cpp_evaluation.org" +++ /dev/null @@ -1,334 +0,0 @@ -#+TITLE: C Preprocessor Evaluation Example -#+AUTHOR: Thomas Walker Lynch -#+OPTIONS: toc:nil - -1. Macro function definition - - Macro function definitions are not evaluated, so the body (the definition) of the macro remains literal until the time it is called. Thus macro calls in macro defintion remain - literal, unevaluated. - - A macro function has three parts, 1) a name 2) a parameter list 3) body - - Parameters are declared by listing them between parenthesis after the name. No space - can occur between the name and the parameter list! If there is space then the - parameter list will be taken as part of the body. - - Text after the parameter list forms the body. - - #+BEGIN_SRC c - #define name(x ,y ,z) - #define name(...) // argument list becomes __VA_ARGS__ - #define name(x ,...) - #+END_SRC - -2. directives - - #ifdef and #ifndef to not evaluate what follows. They expect a full formed - macro name. - - #if does evaluate, but expects existence as true, and 0 as false (though zero - also exists). Non-existence is an error. Wrap cpp_ext_0 logic in BOOLEAN to get 1 or 0. (cpp_ext_0 logic is true for existence, and false for nonexistence.) - -2. Macro Call - - A macro call that was colored blue will not be expanded. - - A macro call can occur anywhere in the source code. It takes the form of a macro - name followed by an argument list: - - #+BEGIN_SRC c - name(1 ,a ,b) - #+END_SRC - - In a call, space is allowed between the macro name and the argument list. - - Not in strings, not embedded in other tokens. If a macro definition has the same name as the call, then that is a redefinition, an redefinition is not allowed. - - cpp scans the tokens in the translation unit, upon finding a macro call it replaces it with the body from the macro definition using the following steps: - - ** 1. Argument Substitution Phase - - When the macro is invoked: - - 1. Each parameter in the macro body is replaced *verbatim* with the - corresponding argument. No evaluation is performed at this stage. - - 2. The new macro body is a new token stream: the old macro body with arguments pasted in. - - ** 2. Evaluation Phase - - The preprocessor then scans the argument substituted macro body *from left to right*, - evaluating macro calls *as it encounters them*. - - - If a token is **not** a macro call (see below), it is included as-is. - - If a token **is** a macro call, it is expanded immediately, using the same two-phase process. - - This produces a depth-first, left-to-right expansion strategy. - - Non-macro-call tokens include: - - 1. Any non-identifier (e.g. `+`, `123`, `"text"`) - - 2. Any identifier **not followed by `(`** - - 3. Any parameter or token used with `#` - - - `#param` turns the *original* argument text into a string. - - Because it stringifies, *the argument is never evaluated*. - - 4. Any parameter or token used with `##` - - - `##` concatenates tokens without evaluating them. - - The pasted result is *not* scanned recursively for macro calls. - - 5. any macro call token that has been "colored blue" by the evaluator. - - It is common that macros containing a `#` or a `##` will have an extra call - layer above them to cause the argument to be first substituted into a macro - where it will get evaluated. Large number of Eval calls are typically not needed - for this, rather what is needed is one layer above the layer with the `#` or `##`. - - ** 3. Colored blue macro call tokens are taken as literal text. - - During evaluation cpp keeps a list of macros that are actively being expanded. This includes the macro that has been called, of course, and all the calls that it found during its depth traversal to get to the current point of evaluation. If it sees any calls to the macros on the active expand list, it marks the macro call token itself as unexpandable, and thus to be treated as literal text. It is said that the macro call token "has been colored blue". - - Any subsequent appearance of a colored blue macro call token will be treated as literal text, no matter the context. This includes if the macro result was assigned to a variable, then that variable is evaluated later. It includes if the macro call token or the expression it is in is sent to another macro, etc. - - Example: - - #+BEGIN_SRC c - #define GROW(x) 1029 * GROW(x) - #define RESULT GROW(5) - - SHOW(RESULT); // → 1029 * GROW(5) - SHOW(EVAL(RESULT)); // → 1029 * GROW(5) again, never expands - #+END_SRC - - The macro call token `GROW(x)` which occurs in the body of a macro definition of the same name, gets colored blue, and thus is always treated as literal text. This happens even though an expression containing it is assigned to a variable, then that variable is evaluated in a totally different evaluation context. - - Apparently the designers of cpp do not want people to design recursive structures with cpp. However, there is a trick for getting around it using a confederate in place of the recursive call, then putting back the original call later, as shown in section 6. - -3. Example macros - - #+BEGIN_SRC c - #define FORCE_ONE(x) 1 - #define STR(x) #x - #define VAL(x) STR(x) - #define GROW(x) 7 * GROW(x) - #+END_SRC - - A call to ~FORCE_ONE(5)~ will expand to ~1~. - - A call to ~STR(FORCE_ONE(5))~ will expand to the string ~"FORCE_ONE_(5)"~. This is because arguments given to the ~#~ operator are not expanded. The variable gets replaced with its value, but the value it not 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. Cascading evaluation - - A macro can also fail to evaluate all possible macros, because during the left to right scan, it created a macro call, but during the scan it did not see it. - - #+BEGIN_SRC c - #define NULL_FN() // expands to nothing - #define NEGATE(x) -x - #define NOT_SO_FAST(x) NEGATE NULL_FN() (x) - #+END_SRC - - When evaluating ~NOT_SO_FAST(5)~, here's what happens: - - 1. ~NEGATE~ is encountered there is nothing to recur into, so it evaluates to itself. - the evaluation moves right. - - 2. ~EMPTY()~ is a macro, so it has no operands, so it is expanded. As it has no - body, it expands to nothing. CPP then moves to the right. - - 3. ~(x)~ is not a macro so there is nothing to recur into, so it becomes ~(5)~. - - 4. Thus the final result of the left to right pass is → ~NEGATE (5)~ The evaluator - recursively expands calls, but it never saw ~NEGATE (5)~, so it remains unexpanded. - This is the second reason a literal macro call might occur in an expansion. - - #+BEGIN_SRC bash - cat >test.c < - - int main(void){ - printf("example_eval.c\\n"); - - #define STR(x) #x - - // `#x` no 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. - - ------- - - The `IF` macro evolves and does three self evaluations, due to new strings - being created which in turn match already defined macros. - - series of events, explain why the DEFER3, ph - - #+BEGIN_SRC c - IF \ - ( NOT_EXISTS(__VA_ARGS__) ) \ - () \ - (IF \ - ( predicate(FIRST(__VA_ARGS__)) ) \ - ( FIRST( ,__VA_ARGS__) ) \ - ( DEFER3(_FIND_CONFEDERATE) ()(predicate ,REST(__VA_ARGS__)) ) \ - ) - #+END_SRC - - -6. Nesting, recursion approaches that do not work, and one that does. - - #+BEGIN_SRC c - - #include - #define STR(x) #x - // no 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/document\360\237\226\211/cpp_macro_expansion.org" "b/developer/document\360\237\226\211/cpp_macro_expansion.org" new file mode 100644 index 0000000..43ac72a --- /dev/null +++ "b/developer/document\360\237\226\211/cpp_macro_expansion.org" @@ -0,0 +1,337 @@ +#+TITLE: C Preprocessor Expansion Example +#+AUTHOR: Thomas Walker Lynch +#+OPTIONS: toc:nil + +1. Macro function definition + + Macro function definitions are not expanded, so the body (the definition) of the macro remains literal until the time it is called. Thus macro calls in macro defintion remain + literal, unexpanded. + + A macro function has three parts, 1) a name 2) a parameter list 3) body + + Parameters are declared by listing them between parenthesis after the name. No space + can occur between the name and the parameter list! If there is space then the + parameter list will be taken as part of the body. + + Text after the parameter list forms the body. + + #+BEGIN_SRC c + #define name(x ,y ,z) + #define name(...) // argument list becomes __VA_ARGS__ + #define name(x ,...) + #+END_SRC + +2. directives + + #define name is never expanded. body is not expanded when the definition is + added to the symbol table, but is expanded through a call to the macro. + + #ifdef and #ifndef do not evaluate what follows. They expect an already formed + macro name. + + #if does evaluate, but expects existence as true, and 0 as false (though zero + also exists). Non-existence is an error. Wrap cpp_ext_0 logic in BOOLEAN to get 1 or 0. (cpp_ext_0 logic is true for existence, and false for nonexistence.) + +2. Macro Call + + A macro call that was colored blue will not be expanded. + + A macro call can occur anywhere in the source code. It takes the form of a macro + name followed by an argument list: + + #+BEGIN_SRC c + name(1 ,a ,b) + #+END_SRC + + In a call, space is allowed between the macro name and the argument list. + + Not in strings, not embedded in other tokens. If a macro definition has the same name as the call, then that is a redefinition, an redefinition is not allowed. + + cpp scans the tokens in the translation unit, upon finding a macro call it replaces it with the body from the macro definition using the following steps: + + ** 1. Argument Substitution Phase + + When the macro is invoked: + + 1. Each parameter in the macro body is replaced *verbatim* with the + corresponding argument. No expansion is performed at this stage. + + 2. The new macro body is a new token stream: the old macro body with arguments pasted in. + + ** 2. Expansion Phase + + The preprocessor then scans the argument substituted macro body *from left to right*, + evaluating macro calls *as it encounters them*. + + - If a token is **not** a macro call (see below), it is included as-is. + - If a token **is** a macro call, it is expanded immediately, using the same two-phase process. + + This produces a depth-first, left-to-right expansion strategy. + + Non-macro-call tokens include: + + 1. Any non-identifier (e.g. `+`, `123`, `"text"`) + + 2. Any identifier **not followed by `(`** + + 3. Any parameter or token used with `#` + + - `#param` turns the *original* argument text into a string. + - Because it stringifies, *the argument is never expanded*. + + 4. Any parameter or token used with `##` + + - `##` concatenates tokens without evaluating them. + - The pasted result is *not* scanned recursively for macro calls. + + 5. any macro call token that has been "colored blue" by the evaluator. + + It is common that macros containing a `#` or a `##` will have an extra call + layer above them to cause the argument to be first substituted into a macro + where it will get expanded. Large number of Eval calls are typically not needed + for this, rather what is needed is one layer above the layer with the `#` or `##`. + + ** 3. Colored blue macro call tokens are taken as literal text. + + During expansion cpp keeps a list of macros that are actively being expanded. This includes the macro that has been called, of course, and all the calls that it found during its depth traversal to get to the current point of expansion. If it sees any calls to the macros on the active expand list, it marks the macro call token itself as unexpandable, and thus to be treated as literal text. It is said that the macro call token "has been colored blue". + + Any subsequent appearance of a colored blue macro call token will be treated as literal text, no matter the context. This includes if the macro result was assigned to a variable, then that variable is expanded later. It includes if the macro call token or the expression it is in is sent to another macro, etc. + + Example: + + #+BEGIN_SRC c + #define GROW(x) 1029 * GROW(x) + #define RESULT GROW(5) + + SHOW(RESULT); // → 1029 * GROW(5) + SHOW(EVAL(RESULT)); // → 1029 * GROW(5) again, never expands + #+END_SRC + + The macro call token `GROW(x)` which occurs in the body of a macro definition of the same name, gets colored blue, and thus is always treated as literal text. This happens even though an expression containing it is assigned to a variable, then that variable is expanded in a totally different expansion context. + + Apparently the designers of cpp do not want people to design recursive structures with cpp. However, there is a trick for getting around it using a confederate in place of the recursive call, then putting back the original call later, as shown in section 6. + +3. Example macros + + #+BEGIN_SRC c + #define FORCE_ONE(x) 1 + #define STR(x) #x + #define VAL(x) STR(x) + #define GROW(x) 7 * GROW(x) + #+END_SRC + + A call to ~FORCE_ONE(5)~ will expand to ~1~. + + A call to ~STR(FORCE_ONE(5))~ will expand to the string ~"FORCE_ONE_(5)"~. This is because arguments given to the ~#~ operator are not expanded. The variable gets replaced with its value, but the value it not expanded. + + A call to ~VAL(FORCE_ONE(5))~ will result in `1`. This is because there is no hash symbol in the VAL macro that is stopping the recursive expansion of ~x~. + +5. Cascading expansion + + A macro can also fail to evaluate all possible macros, because during the left to right scan, it created a macro call, but during the scan it did not see it. + + #+BEGIN_SRC c + #define NULL_FN() // expands to nothing + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE NULL_FN() (x) + #+END_SRC + + When evaluating ~NOT_SO_FAST(5)~, here's what happens: + + 1. ~NEGATE~ is encountered there is nothing to recur into, so it evaluates to itself. + the expansion moves right. + + 2. ~EMPTY()~ is a macro, so it has no operands, so it is expanded. As it has no + body, it expands to nothing. CPP then moves to the right. + + 3. ~(x)~ is not a macro so there is nothing to recur into, so it becomes ~(5)~. + + 4. Thus the final result of the left to right pass is → ~NEGATE (5)~ The evaluator + recursively expands calls, but it never saw ~NEGATE (5)~, so it remains unexpanded. + This is the second reason a literal macro call might occur in an expansion. + + #+BEGIN_SRC bash + cat >test.c < + + int main(void){ + printf("example_eval.c\\n"); + + #define STR(x) #x + + // `#x` no expansion of x due to the '#' + // `STR(x)` recurs and does a left to right expansion on the value of `x` + #define SHOW(x) printf(#x " → %s\\n", STR(x)); + + #define EMPTY() + #define NEGATE(x) -x + #define NOT_SO_FAST(x) NEGATE EMPTY() (x) + + SHOW(NOT_SO_FAST(5)); + + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + } + EOF + + gcc test.c + ./a.out + #+END_SRC + + Output: + + #+BEGIN_EXAMPLE + example_eval.c + NOT_SO_FAST(5) → NEGATE (5) + BE(NOT_SO_FAST(5)) → -5 + #+END_EXAMPLE + + Let’s examine the final lines: + + #+BEGIN_SRC c + #define BE(x) x + SHOW(BE(NOT_SO_FAST(5))) + #+END_SRC + + The expansion process: + + - cpp encounters ~BE(NOT_SO_FAST(5))~. + - It enters ~NOT_SO_FAST(5)~, expands it to ~NEGATE (5)~. + - Then ~BE(NEGATE (5))~ becomes ~-5~ through final macro expansion. + + ------- + + The `IF` macro evolves and does three self expansions, due to new strings + being created which in turn match already defined macros. + + series of events, explain why the DEFER3, ph + + #+BEGIN_SRC c + IF \ + ( NOT_EXISTS(__VA_ARGS__) ) \ + () \ + (IF \ + ( predicate(FIRST(__VA_ARGS__)) ) \ + ( FIRST( ,__VA_ARGS__) ) \ + ( DEFER3(_FIND_CONFEDERATE) ()(predicate ,REST(__VA_ARGS__)) ) \ + ) + #+END_SRC + + +6. Nesting, recursion approaches that do not work, and one that does. + + #+BEGIN_SRC c + + #include + #define STR(x) #x + // no expansion, and one pass of expansion + #define SHOW(expr) printf("%s --> %s\n", #expr, STR(expr)) + + #define BE(...) __VA_ARGS__ + #define EMPTY() + + #include + int main(void){ + printf("example_grow.c\n"); + printf("\n"); + + // case 1 + /* + GROW(7) → 17 * GROW(7) + GROW(GROW(5)) → 17 * GROW(17 * GROW(5)) + ,*/ + #define GROW(x) 17 * GROW(x) + SHOW(GROW(7)); + SHOW(GROW(GROW(5))); + printf("\n"); + + // case 2 + // GROW2(11) --> 19 * GROW2 (11) + #define GROW2(x) 19 * GROW2 EMPTY() (x) + SHOW(GROW2(11)) ; + printf("\n"); + + // case 3 + // GROW3(13) --> 119 * 19 * GROW2 (13) + #define GROW3(x) BE(119 * GROW2 EMPTY() (x)) + SHOW(GROW3(13)); + printf("\n"); + + // case 4 + /* + `BE` placed on the outside. The idea is that expansion will return `123 * GROW (15)` and then this will be expanded resulting in `123 * 123 * GROW(15)`. + + However, any time GROW4 literally spells out GROW4(...) inside its own expansion + it will leave it literally and not expand it. + + Though it is interesting that here that occurs at a higher level in the expansion tree than the first ocurrance of the recursive call, but still it is in the tree. + + GROW4(15) --> 123 * GROW4 (15) + ,*/ + #define GROW4(x) BE(123 * GROW4 EMPTY() (x)) + SHOW(GROW4(15)); + printf("\n"); + + // case 5 + /* + Substitution of the function named followed by a trampoline works. + + The original expression is written in terms of a deferred CONDFEDERATE function + instead of in terms of a recursive call to GROW5. cpp can suspect nothing. + + The result is an expression in terms of the unexpanded CONDFEDERATE function. + + The CONFEDERATE function is defined to return the token GROW5. Hence in a subsequent expansion, and there must be a subsequent expansion for this to work, The CONFEDERATE function will run, return GROW5 which is next to its call parenthesis, so then the + recursive call will run. + + BE(GROW5(21)) --> 541 * 541 * CONFEDERATE () (21) + BE(BE(GROW5(57))) --> 541 * 541 * 541 * CONFEDERATE () (57) + ,*/ + #define GROW5(x) 541 * CONFEDERATE EMPTY() () (x) + #define CONFEDERATE() GROW5 + SHOW(BE(GROW5(21))); + SHOW(BE(BE(GROW5(57)))); + printf("\n"); + + // case 6 + /* + Once a recursively called function is marked, or 'colored' it can never be expanded, even when passed through to another variable and separately expansion. + ,*/ + #define GROW6(x) 1029 * GROW6 EMPTY() (x) + #define RESULT1 GROW6(51) + SHOW(RESULT1); + SHOW(BE(RESULT1)); + printf("\n"); + // RESULT1 --> 1029 * GROW6 (51) + // BE(RESULT1) --> 1029 * GROW6 (51) + + // case 7 + #define RESULT2 GROW6(151) + SHOW(RESULT2); + SHOW(BE(RESULT2)); + printf("\n"); + // RESULT2 --> 1029 * GROW6 (151) + // BE(RESULT2) --> 1029 * GROW6 (151) + + } + + #+END_SRC + +7. Discussion on recursion + + Case 6, and Case 7 above show that once a token is marked as a would-be recursive call token it is marked and can never be expanded, no matter how hard the programmer + might try hide its actual origin. It can be assigned to variables, passed between co-routines, and nothing will help because the macro call token itself is marked. + + Case 5 shows a workaround. Instead of having a recursive call, a deferred call to a confederate is made. The resulting expression then amounts to a lazy expansion. The return value from the expansion will contain unmade calls to the confederate in each and every place that a recursive call was desired. + + In order to complete the expansion, the lazy result must undergo a second expansion, + where the confederate function calls are run, and they return the name of the original + function that was to be called, and then those calls are expanded. + + This leads to a trade off. To have recursion we must have two expansions of expressions so as to replace the confederates. + + Repeated expansion is a consequence of using confederate method to avoid macro calls from being marked not to be expanded. Deferring the calls is necessary so that the don't get replaced in the first expansion so that their replacements don't get marked. + + Note that each recursive call, potentially results in ore expressions appearing. Hence, there must be as many expansions as there are levels of recursion. This is a tell order for list processing. + + diff --git a/developer/example/bespoke_type.cli.c b/developer/example/bespoke_type.cli.c index c307dbf..a4774f3 100644 --- a/developer/example/bespoke_type.cli.c +++ b/developer/example/bespoke_type.cli.c @@ -19,10 +19,9 @@ Here by 'type' we mean a Tableau to FG table binding. */ - #undef Binding·TYPE - #define Binding·TYPE Bespoke - #define Binding·TYPE·Bespoke + #define Binding Bespoke #include "Binding.lib.c" + #define Binding·SET·Bespoke // This defines the FG table type for Bespoke (aka vtable). Each instance is a different implementation of the type sharing the same interface. typedef struct Bespoke·FG{