The RT extensions won't let you write recrusive macros. My apologies to my cpp magic friends. However, they will let you write sets, and to associate values with set members. See the documents directory more information.
-Also for reference, I put the cpp magic like faux recursion in the top level library directory, but I suspect you won't need it.
-
### `#rt_macro`
-Defines a macro in standard ISO form, using token literal parsing and optional parameter substitution. Basically it is `#define` where the body is contained within parenthesis, and need not be on one line.
+Defines a macro in standard ISO form, using token literal parsing and parameter substitution. Basically it is functional form of `#define` where the body is contained within parenthesis, and need not be on one line.
#### Syntax (EBNF):
; whitespace, including newlines, is ignored
```
-If you need an unbalanced paren, define a macro that expands to a paren and use that. Parenthesis need only to match when the body is lexed.
+If you need an unbalanced paren, define a macro that expands to a paren and use that. Parenthesis need only to match when the body is lexed. Note that the parameter list can be empty, but it is required, both on the definition and the call.
### `#assign`
This is another variation on #define. Currently it can not be used to define function like macros.
-Unlike assign, there is an option to expand the name and body before the definition is registered. When the name is expanded, it must expand to an identifier that can be used as a nmae.
+Unlike define, there is an option to expand either or both of the name and body expressions before the definition is registered. When the name is expanded, it must expand to an identifier that can be used as a nmae.
-Should the body or name contain macros that are expanded, these expansions are done before the macro is put in the symbol table. Hence, the name.
+Should the name or body contain macros that are expanded, these expansions are done before the macro is put in the symbol table. Which is why this directive is called 'assign'.
-If the assigned name arrives as an already defined, though disabled macro, `#assign` will clear the disabled flag. This does not enable recursion, but it does enable one more step of evaluation the next time the macro is evaluated. Note that macros are 'painted' during evaluation, so removing the flag only enables evaluation until the macro is painted again.
+If the assigned name arrives at the directory with a definition, though it is disabled, `#assign` will clear the disabled flag. This does not enable recursion, because disabling (so called painting) is done by the evaluator. However, it does enable one more step of evaluation for a recursive macro each time assign is called.
#### Syntax (EBNF):
#### Examples
-See the experiments/ directory for more examples.
+See the `developer/experiments` directory for more examples.
```
#assign (A_NAME) (3)
__CAT(, foo, bar, baz) // expands to: foobarbaz
```
-
-### License
-
-This project is licensed under the **MIT License**.
-See the `LICENSE.text` file for full terms.
-
## Project Structure / Building
The top level directory is for project overhead files. Development work is done in the 'developer' directory. If someday there is a test bench it will go in the 'tester' directory.
The build script directory will have a README.org, as well as bash scripts that can be read directly.
+## License
+
+This project is licensed under the **MIT License**.
+See the `LICENSE.text` file for full terms.
+
# === environment.sh ===
# Source this file in each build script to ensure consistent paths and settings
-echo "ROOT: $ROOT"
-cd $SCRIPT_DIR
+#!/bin/sh
-#--------------------------------------------------------------------------------
-# tools
+: "${REPO_HOME:?REPO_HOME is not set}"
+: "${DEVELOPER:?DEVELOPER is not set}"
+: "${SCRIPT_DIR:?SCRIPT_DIR is not set}"
- # machine target
- export HOST=$(gcc -dumpmachine)
+[ -d "$REPO_HOME" ] || { echo "Directory not found: REPO_HOME ($REPO_HOME)" >&2; exit 1; }
+[ -d "$DEVELOPER" ] || { echo "Directory not found: DEVELOPER ($DEVELOPER)" >&2; exit 1; }
+[ -d "$SCRIPT_DIR" ] || { echo "Directory not found: SCRIPT_DIR ($SCRIPT_DIR)" >&2; exit 1; }
- export MAKE_JOBS=$(getconf _NPROCESSORS_ONLN)
- export MAKE=make
-
- # Compiler path prefixes
- export CC_FOR_BUILD=$(command -v gcc)
- export CXX_FOR_BUILD=$(command -v g++)
-
-#--------------------------------------------------------------------------------
-# Tool and library versions (optimized build with Graphite and LTO compression)
-
- export GCC_VER=12.2.0 # GCC version to build
- export GMP_VER=6.2.1 # Sufficient for GCC 12.2
- export MPFR_VER=4.1.0 # Stable version compatible with GCC 12.2
- export MPC_VER=1.2.1 # Recommended for GCC 12.2
- export ISL_VER=0.24 # GCC 12.x infra uses this; don't use 0.26+ unless patched
- export ZSTD_VER=1.5.5 # zstd compression for LTO bytecode
+echo "REPO_HOME: $REPO_HOME"
+echo "DEVELOPER: $DEVELOPER"
+echo "SCRIPT_DIR: $SCRIPT_DIR"
#--------------------------------------------------------------------------------
# project structure
# temporary directory
- export TMPDIR="$ROOT/tmp"
+ export TMPDIR="$REPO_HOME/tmp"
# Project directories
- export SYSROOT="$ROOT/sysroot"
- export TOOLCHAIN="$ROOT/toolchain"
- export BUILD_DIR="$ROOT/build"
- export LOGDIR="$ROOT/log"
- export UPSTREAM="$ROOT/upstream"
- export SRC=$ROOT/source
-
- # Synthesized directory lists
+ export SYSROOT="$DEVELOPER/sysroot"
+ export TOOLCHAIN="$DEVELOPER/toolchain"
+ export BUILD_DIR="$DEVELOPER/build"
+ export LOGDIR="$DEVELOPER/log"
+ export UPSTREAM="$DEVELOPER/upstream"
+ export SRC=$DEVELOPER/source
+
+ # lists of project directories to synthesize
PROJECT_DIR_LIST=(
"$LOGDIR"
"$SYSROOT" "$TOOLCHAIN" "$BUILD_DIR"
"$UPSTREAM" "$SRC"
)
- # list these in the order they can be deleted
+ # list these in the order for which they can be deleted
PROJECT_SUBDIR_LIST=(
"$SYSROOT/usr/lib"
"$SYSROOT/lib"
"$SYSROOT/usr/include"
)
+#--------------------------------------------------------------------------------
+# Tool and library versions (optimized build with Graphite and LTO compression)
+
+ export GCC_VER=12.2.0 # GCC version to build
+ export GMP_VER=6.2.1 # Sufficient for GCC 12.2
+ export MPFR_VER=4.1.0 # Stable version compatible with GCC 12.2
+ export MPC_VER=1.2.1 # Recommended for GCC 12.2
+ export ISL_VER=0.24 # GCC 12.x infra uses this; don't use 0.26+ unless patched
+ export ZSTD_VER=1.5.5 # zstd compression for LTO bytecode
+
+#--------------------------------------------------------------------------------
+# tools
+
+ # Compiler path prefixes
+ export CC_FOR_BUILD="$(command -v gcc)"
+ export CXX_FOR_BUILD="$(command -v g++)"
+ export MAKE="$(command -v make)"
+
+ # Verify that compilers were found
+ : "${CC_FOR_BUILD:?gcc not found in PATH}"
+ : "${CXX_FOR_BUILD:?g++ not found in PATH}"
+ : "${MAKE:?make not found in PATH}"
+
+ [ -x "$CC_FOR_BUILD" ] || { echo "❌ $CC_FOR_BUILD is not executable"; exit 1; }
+ [ -x "$CXX_FOR_BUILD" ] || { echo "❌ $CXX_FOR_BUILD is not executable"; exit 1; }
+ [ -x "$MAKE" ] || { echo "❌ $MAKE is not executable"; exit 1; }
+
+ # Machine target
+ export HOST="$("$CC_FOR_BUILD" -dumpmachine)"
+
+ # Determine parallelism
+ if command -v getconf >/dev/null 2>&1; then
+ export MAKE_JOBS=$(getconf _NPROCESSORS_ONLN)
+ else
+ echo "⚠️ getconf not found; defaulting MAKE_JOBS=1"
+ export MAKE_JOBS=1
+ fi
+
+
#--------------------------------------------------------------------------------
# upstream -> local stuff
--- /dev/null
+** directives.cc
+
+Midway there is a table that lists the directives.
+
+I put the code for `#assign` and `#macro` at the bottom under the section: "RT Extensions".
+
+
+** macros.cc
+
+The code in the directives file points into macros to do the work. I put that code for `#assign` and `#macro` at the bottom under the section: "RT Extensions".
+
+
+** include/cpplib.h
+
+Added entry to `enum cpp_builtin_type` for `BT_CAT`
+
+
+** init.cc
+
+Has, `static const struct builtin_macro builtin_array[] =`, I added a line for
+
+ B("__CAT", BT_CAT, true),
+
+Strange the original for this file has a comma after the last entry, so I did the same.
+
+The `true` means that there will be a warning if __CAT is redefined.
B("__STDC__", BT_STDC, true),
// RT Extension
- B("__CALL", BT_CALL, true),
+ B("__CAT", BT_CAT, true),
};
#undef B
number = builtin_has_include (pfile, node,
node->value.builtin == BT_HAS_INCLUDE_NEXT);
break;
+
+ case BT_CAT:
+
+ const char *str = "calico";
+ size_t len = strlen(str) + 1;
+ uchar *result = (uchar *) _cpp_unaligned_alloc(pfile, len);
+ memcpy(result, str, len);
+
+
+ break;
+
}
if (result == NULL)
echo "mkdir -p $TMPDIR"
mkdir -p "$TMPDIR"
- echo "echo $TMPDIR/ > $TMPDIR/.gitignore"
echo "$TMPDIR/" > "$TMPDIR/.gitignore"
else
echo "⚠️ TMPDIR already exists"
fi
# Create root-level .gitignore if missing
-if [[ -f "$ROOT/.gitignore" ]]; then
- echo "⚠️ $ROOT/.gitignore already exists"
+if [[ -f "$REPO_HOME/.gitignore" ]]; then
+ echo "⚠️ $REPO_HOME/.gitignore already exists"
else
- echo "create $ROOT/.gitignore"
+ echo "create $REPO_HOME/.gitignore"
{
echo "# Ignore synthesized top-level directories"
for dir in "${PROJECT_DIR_LIST[@]}"; do
- rel_path="${dir#$ROOT/}"
+ rel_path="${dir#$REPO_HOME/}"
echo "/$rel_path"
done
echo "# Ignore synthesized files"
echo "/.gitignore"
- } > "$ROOT/.gitignore"
+ } > "$REPO_HOME/.gitignore"
fi
-echo "✅ setup_project.sh"
+echo
+echo "Created project structure:"
+tree -L 2 "$REPO_HOME" 2>/dev/null || find "$REPO_HOME" -maxdepth 2
+
exit 1
fi
-export ROOT=$(dirname "$script_afp")/developer
-export SCRIPT_DIR="$ROOT"/script_Deb-12.10_gcc-12.4.1🖉
+export REPO_HOME="$(dirname "$script_afp")"
+export DEVELOPER="$REPO_HOME/developer"
+export SCRIPT_DIR="$DEVELOPER"/script_Deb-12.10_gcc-12.4.1🖉
cd "$SCRIPT_DIR"
fi
export ROOT=$(dirname "$script_afp")
-export PATH="$ROOT/toolchain/bin:$PATH"
+export PATH="$ROOT/release/amd64_Deb-12.10_gcc-12.4.1/bin:$PATH"
* cpp_ext
-These cpp_ext files predate the RT extensions, but as they are related to cpp I have put them here.
+These cpp_ext files are not used in the code for RT_gcc. Nor do they use RT extensions. Rather developing them was part of the due diligence before electing to write the RT extensions.
+
+I find cpp_ext_0 to be useful, and would not hesitate to use it in production code.
+
+In contrast, was a good pedagogical tool for learning cpp, but I would hesitate to use it in production code. The reasoning being that recursion can lead to compiler error messages that span pages.
** cpp_ext_0
** cpp_ext_1
-This is a whole different animal from that of cpp_ext_0. This one uses trickery to facilitate recursive programming in cpp.
-
I pulled the original version from Jonathan Heathcote's "cpp magic", http://jhnet.co.uk/articles/cpp_magic, and modified it to work with the non-existence is false logic. Open AI suggests additional contributors to cpp trickery:
Paul F. Dubois — wrote about C macro tricks in early numerical computing contexts.
The Boost Preprocessor Library (by Paul Mensonides and others) contains some of the most extensive and formalized C macro "magic" ever crafted.
I don't use cpp_ext_1 in production code because it can lead to very long error messages when compiling, and I have found non-recursive approaches for what I need. See the top level document/ directory for more discussion on cpp techniques (yet to come ;-).
+
+* cpp_ext_rt
+
+In cpp_ext_0 it was not possible to write a routine that adds a member to a set, because we cannot create macro names on the fly. The `#assign` directive in the rt extension solves this problem.
+
+Cat is an often used macro for prefixing a namespace, prefixing a set name to the front of an identifier before a membership test, or creating identifiers for equality matching. Seldom do we need very many levels of concatenation, though the exact number is not always bounded. Currently I use cpp_ext_1 recursion for variadic concatenation so that CAT won't have a number, CAT2, CAT3, etc. Variadic CAT seems like a reasonable thing to be able to do perhaps by putting ## in front of __VA_ARGS__. Hence, I added the built in macro __CAT(SEP, ...).
+
+
+++ /dev/null
-
-Currently there is no release, so I have linked these into the developer/toolchain directory.
+++ /dev/null
-../../developer/toolchain/bin
\ No newline at end of file
+++ /dev/null
-../../developer/toolchain/include
\ No newline at end of file
+++ /dev/null
-../../developer/toolchain/lib
\ No newline at end of file
+++ /dev/null
-../../developer/toolchain/lib64
\ No newline at end of file
+++ /dev/null
-../../developer/toolchain/libexec
\ No newline at end of file
+++ /dev/null
-../../developer/toolchain/share
\ No newline at end of file
--- /dev/null
+
+Currently there is no release, so I have linked these into the developer/toolchain directory.
--- /dev/null
+../../developer/toolchain/bin
\ No newline at end of file
--- /dev/null
+../../developer/toolchain/include
\ No newline at end of file
--- /dev/null
+../../developer/toolchain/lib
\ No newline at end of file
--- /dev/null
+../../developer/toolchain/lib64
\ No newline at end of file
--- /dev/null
+../../developer/toolchain/libexec
\ No newline at end of file
--- /dev/null
+../../developer/toolchain/share
\ No newline at end of file