diff options
Diffstat (limited to 'README')
| -rw-r--r-- | README | 480 |
1 files changed, 480 insertions, 0 deletions
@@ -0,0 +1,480 @@ +mcpu-cpp +======== + +mcpu-cpp is the preprocessor/front-end source manager for MCPU programming +languages. It is an independent component of the LibMPU/LibMPUIO/LibMCPU +software platform and provides preprocessing, language selection, include-path +management, dependency generation and preprocessing diagnostics for the MCPU +toolchain. + +Text model +---------- + +External text files are UTF-8. Internally mcpu-cpp uses strict UCS-2 through +LibMPUIO. UTF-8 scalar values which cannot be represented by UCS-2 are +rejected. Legacy external code pages are not supported; the external representation is UTF-8. + +Lexical analysis +---------------- + +mcpu-cpp does not use flex. Its preprocessing scanners are hand-written and +operate on the internal UCS-2 text model. The `#if` expression grammar and its +expression lexer are generated by ZUBR 4.1.0. + +Parser architecture +------------------- + +The generated `src/mcpp-expr.c` is shipped in release archives, so ordinary +builds do not require ZUBR. In the developer Git tree the generated parser +may be omitted; the root `./bootstrap` script regenerates it from +`src/mcpp-expr.zubr` with ZUBR 4.1.0 before regenerating the Autotools files. + +Documentation +------------- + +The normative preprocessing manual is maintained in two synchronized forms: + + doc/mcpu-cpp-en.md English + doc/mcpu-cpp-ru.md Russian + +Both documents describe the same public contract and are distributed together. + +Configuration +------------- + +mcpu-cpp reads UTF-8 configuration files using a simple `NAME = value;` +syntax. Shell-style `$NAME` and `${NAME}` references are expanded from values +already defined in the effective configuration and then from the process +environment. + +MCPU uses one relocatable installation tree rather than a versioned directory +per tool. With `--prefix=/usr --libdir=/usr/lib64`, `make install` creates: + +```text +/usr/lib64/mcpu/ + bin/mcpu-cpp + etc/mcpu-cpp.conf + include/ + lib/ +``` + +`/usr/bin/mcpu-cpp` is a public symbolic link to +`../lib64/mcpu/bin/mcpu-cpp`. The absolute `/usr/lib64/mcpu` path is an +install-time choice only; it is not embedded as the runtime MCPU root. + +On Linux, mcpu-cpp resolves its real executable through `/proc/self/exe`, takes +the parent of the executable directory as the MCPU runtime root, and derives +`<root>/etc/mcpu-cpp.conf` and `<root>/include` from it. A fallback based on +`argv[0]`, `PATH`, and `realpath(3)` is used only when `/proc/self/exe` cannot +be read. Consequently a complete MCPU tree may be copied or moved without +rebuilding mcpu-cpp. + +This is the intended ecosystem-wide layout for future `mcpu-as`, `mcpu-ld`, +`mcpu-run`, libraries and CRT components as well: tool versions do not define +separate roots; a coherent MCPU environment is identified by one physical +runtime tree. + +Configuration layers are applied in this order: + +```text +runtime-derived defaults +<runtime-root>/etc/mcpu-cpp.conf +/etc/mcpu/mcpu-cpp.conf optional +$HOME/.mcpu/mcpu-cpp.conf optional, highest priority +``` + +The packaged config deliberately does not store an absolute default system +include path. Before reading any config file mcpu-cpp sets +`MCPU_CPP_SYSTEM_INCLUDE_PATH=<runtime-root>/include`; any higher-priority +configuration may replace that value or set it empty. + +`--config-file FILE` reads only FILE on top of the runtime-derived defaults. +`--no-config` reads no configuration files at all but keeps those runtime +defaults. Use `-nostdinc` when the effective standard-system include tree +itself must be suppressed for one invocation. + +Installation does not create `/etc/mcpu`; that directory is reserved for an +optional distributor or system-administrator override. The per-user +configuration is deliberately not versioned. + +Recognized path variables are: + + MCPU_CPP_INCLUDE_PATH + MCPU_CPP_DIFF_INCLUDE_PATH + MCPU_CPP_DIFT_INCLUDE_PATH + MCPU_CPP_ALG_INCLUDE_PATH + MCPU_CPP_AS_INCLUDE_PATH + MCPU_CPP_AVM_INCLUDE_PATH + MCPU_CPP_ACS_INCLUDE_PATH + MCPU_CPP_SYSTEM_INCLUDE_PATH + MCPU_CPP_AFTER_INCLUDE_PATH + +User and AFTER path lists use the host PATH separator (`:` on UNIX systems). +`MCPU_CPP_SYSTEM_INCLUDE_PATH` is different: it is one replaceable root of the +MCPU system-header tree. Its runtime-derived default is +`<runtime-root>/include`. When a switched language is active mcpu-cpp +searches `<root>/<lang>` and then `<root>`. A higher-priority configuration can +replace the root completely for a developer/tester sandbox, or set it to an +empty value to disable the configured system tree. + +Command line +------------ + + mcpu-cpp [options] [input [output]] + +Important options: + + -o FILE write output to FILE instead of stdout + -D NAME[=VALUE] define a command-line macro + -U NAME undefine a command-line macro + -imacros FILE preprocess FILE for macro state; discard its output + -include FILE preprocess FILE before the primary input + -I DIR, -IDIR add a user include directory + -isystem DIR add an explicit system include directory + -idirafter DIR add a directory searched after system directories + -nostdinc suppress the effective standard-system include tree + -dM dump non-predefined macros to stdout + -dMP dump predefined macros first, then other macros + -dD preserve #define directives in normal output + -dconfig dump effective configuration variables to stdout + -dsearch-dirs dump effective include search directories and exit + -M output make dependencies including system headers + -MM output make dependencies excluding system headers + -MD write dependencies and keep preprocessing output + -MMD like -MD but exclude system headers + -MF FILE write dependencies to FILE ('-' means stdout) + -MT TARGET set unquoted make dependency target + -MQ TARGET set make-quoted dependency target + --object-suffix SFX set object suffix used for dependency targets + -w suppress all warnings + -Wcomment[s] warn about nested /* and multi-line // comments + -Wno-comment[s] disable comment warnings even under -Wall + -Wall enable all optional warning classes + -Werror promote every emitted warning to an error + -Wno-error keep emitted warnings as warnings + --config-file FILE use only FILE as the configuration file + --no-config do not read config files; keep runtime-derived defaults + -v, --verbose print configuration and include activity + --help print help + --version print version + +Include search +-------------- + +For `#include "file"`, the physical directory containing the current source +file is searched first. For `#include <file>`, that first step is omitted. +The remaining include search order is normative: + +```text +explicit -I +explicit -isystem +MCPU_CPP_<LANG>_INCLUDE_PATH +MCPU_CPP_INCLUDE_PATH +MCPU_CPP_SYSTEM_INCLUDE_PATH/<lang> +MCPU_CPP_SYSTEM_INCLUDE_PATH +explicit -idirafter +MCPU_CPP_AFTER_INCLUDE_PATH +``` + +Command-line include directories therefore override persistent configuration. +The language-specific user paths are freely configurable. The system path is +a single effective root; mcpu-cpp derives the fixed `<root>/<lang>` directory +itself, so there are intentionally no +`MCPU_CPP_SYSTEM_<LANG>_INCLUDE_PATH` variables. Replacing +`MCPU_CPP_SYSTEM_INCLUDE_PATH` replaces the complete installed system-header +tree rather than adding another directory. An empty effective value disables +the configured system tree. Neither `-idirafter` nor +`MCPU_CPP_AFTER_INCLUDE_PATH` acquires automatic language subdirectories. + +`#include_next` is intended for wrapper headers. It remembers the exact +physical entry of this effective search chain that supplied the current header +and resumes at the following entry. This allows an explicit wrapper to alter +policy and then continue into a sandbox or installed system tree without +copying the original header or hard-coding its absolute pathname. The +`"file"` and `<file>` forms are equivalent for `#include_next`, and logical +names established by `#line` do not affect physical search provenance. + +`#pragma once` marks the current physical file as processed for the remainder +of the preprocessing run. Identity is the filesystem device/inode pair, not +the pathname spelling, so the same file reached through another relative name, +a symbolic link or a hard link is skipped. The exact active directive is +consumed by mcpu-cpp; an inactive `#pragma once` has no effect. Other pragmas +remain in output for later compiler stages. + +Command-line forced files +------------------------- + +`-imacros FILE` and `-include FILE` use one deterministic preprocessing +pipeline. Predefined macros are installed first, all command-line `-D`/`-U` +actions are then applied in their own command-line order, every `-imacros` +file is processed in command-line order, every `-include` file is processed in +command-line order, and only then does preprocessing enter the primary input. +The relative placement of `-imacros` and `-include` options in argv therefore +does not interleave the two classes: every `-imacros` always precedes every +`-include`. + +An `-imacros` file goes through the ordinary preprocessing machinery, including +`#include`, macro definition/undefinition, conditional directives, `#lang`, +`#pragma once`, diagnostics and dependency tracking. Its normal preprocessing +output, including output from headers reached from that file, is discarded. +The resulting macro table and other preprocessing state remain available to +subsequent forced files and to the primary input. `-include` uses the same +preprocessing machinery but retains its normal output, as if the header had +been included immediately before the primary source. + +The operand of either forced-file option has GNU-style command-line search +semantics. An absolute path is used directly. A relative path is searched +first in the current working directory and then through the ordinary quoted +include chain shown above. The physical directory of the primary input does +not receive the special first priority that a literal `#include "file"` inside +that source would receive. Once a forced file has been found, quoted includes +inside it are resolved normally relative to that file's physical directory, +and `#include_next` retains the search-chain provenance of the entry that found +it. + +Forced files are ordinary physical dependencies. Files reached through CWD or +user include classes remain user dependencies; files found through `-isystem`, +the configured system tree, `-idirafter` or configured AFTER paths retain +system dependency class for `-MM`/`-MMD`. + + +Dependency generation +--------------------- + +`-M` preprocesses the translation unit and writes one make rule instead of +normal preprocessor output. The rule contains the main source file and every +physical header actually reached through the ordinary `#include` / +`#include_next` pipeline, including system headers. Repeated spellings, +symbolic links and hard links to the same physical file are recorded once. +Logical names established by `#line` are never dependency names. + +`-MM` uses the same traversal but omits headers found through `-isystem`, the +configured MCPU system tree, `-idirafter` and configured AFTER paths, and also +omits headers reachable only as descendants of such a system header. Quote +versus angle include spelling does not decide whether a dependency is system. +If the same physical file is also reached directly through a user include +context, it remains a user dependency. + +The default target is the input basename with its suffix replaced by the +configured object suffix (normally `.o`). In dependency-only `-M`/`-MM` mode, +`-MF FILE` selects the make-rule destination; without `-MF`, the existing +mcpu-cpp `-o FILE` destination remains available. + +`-MD` and `-MMD` generate dependencies as a side effect and do **not** suppress +normal preprocessing output. `-MD` includes system headers like `-M`; `-MMD` +applies the same user-only filter as `-MM`. Without `-MF`, the dependency file +is `<input-basename>.d` in the current directory, or is derived from ordinary +`-o` output by replacing its suffix with `.d`. `-MF FILE` overrides that +automatic name, and `-MF -` sends the dependency rule to stdout. + +Options `-MT` and `-MQ` are intentionally left for the next dependency stage. + +#lang contract +-------------- + +The initial language state is `0`. It is the base MCPU language state and is +installed before preprocessing begins. `0` is deliberately not a parameter of +`#lang`. + +`#lang` requires exactly one quoted language name: + + #lang "diff" + +The text inside the quotes is not escape-decoded. It must be a non-empty +single word without whitespace, and the closing quote must occur on the same +physical source line. After the closing quote only whitespace is allowed. +The accepted names come only from the internal language table: `diff`, `dift`, +`alg`, `as`, `avm`, and `ACS`. Matching is ASCII case-insensitive, so for +example `"diff"`, `"Diff"`, `"DIFF"` and `"dIfF"` all select the same +language. Unsupported names such as `"0"`, `"c"` and `"vasm"` are errors. + +External whitespace is normalized when `#lang` is copied to output. For +example: + + # lang "DiFf" + +is emitted as: + + #lang "DiFf" + +The spelling inside the quotes is preserved as written. + +`#lang` and `#endlang` form one translation-unit-wide stack. The stack is not +reset at an `#include` boundary. Therefore a `#lang` in one file and its +matching `#endlang` in another included file are intentionally legal, exactly +as required by the macro-expansion contract. + +Both directives are passed through to output so the later language dispatcher +and parser layer can observe the same language boundaries. `#lang` is emitted +in the normalized form described above. + +Macro operators +--------------- + +Function-macro stringification (`#`) is supported. +The operator uses the raw, unexpanded actual argument, removes leading and +trailing whitespace, folds internal whitespace outside quoted tokens to one +space, and escapes double quotes and backslashes as required by the resulting +quoted string. `##` token concatenation is also supported and rescans the concatenated token +through the ordinary macro-expansion path. + +The completed predefined ABI/environment layer from 0.0.12 is preserved. +INT/UINT DECIMAL_DIG counts only decimal digits of the corresponding numeric +maximum, without a sign or terminating NUL. Integer decimal precision and +Real DECIMAL_DIG/MANT_DIG metadata cover every configured type width; +large MAX/MIN/EPSILON textual values remain capped at 256 bits. + +`__MCPU_CPP_VERSION__` is the mcpu-cpp package version. `_ARCH_MCPU` identifies +the target. The LibMPU profile macros use the MCPU namespace: +`__MCPU_MACHINE_REGISTER_WIDTH__`, `__MCPU_REAL_IO_LIMIT__` and +`__MCPU_MATH_FN_LIMIT__`. + +MCPU pointers are always 64 bits independently of the host. `intptr` and +`ptrdiff` are signed `int64`; `uintptr` is `uint64`: + + __INTPTR_TYPE__ int64 + __INTPTR_WIDTH__ 64 + __INTPTR_MAX__ 0x7fffffffffffffff + __UINTPTR_TYPE__ uint64 + __UINTPTR_WIDTH__ 64 + __UINTPTR_MAX__ 0xffffffffffffffff + __PTRDIFF_TYPE__ int64 + __PTRDIFF_WIDTH__ 64 + __PTRDIFF_MAX__ 0x7fffffffffffffff + +The configured LibMPU size and signed-size types are exposed only in the MCPU +namespace. For a 64-bit profile the public contract is: + + __MCPU_SIZE_TYPE__ uint64 + __MCPU_SIZE_WIDTH__ 64 + __MCPU_SIZEOF_SIZE__ 8 + __MCPU_SIZE_MAX__ 0xffffffffffffffff + __MCPU_SSIZE_TYPE__ int64 + __MCPU_SSIZE_WIDTH__ 64 + __MCPU_SIZEOF_SSIZE__ 8 + __MCPU_SSIZE_MAX__ 0x7fffffffffffffff + +Integer TYPE/WIDTH/SIZEOF metadata is generated for every power-of-two LibMPU +integer family through `NB_I_MAX * 8`. Real and Complex TYPE/WIDTH/SIZEOF +metadata is generated through the configured `MPU_REAL_IO_LIMIT`. Complex +WIDTH is the language type parameter: `complex128` has WIDTH 128 but SIZEOF 32 +bytes, because it stores two real128 components. + +Every available Real family also exports two compact conversion/layout +properties through `MPU_REAL_IO_LIMIT`: `__SIZEOF_REAL<bits>_EXP__` comes from +LibMPU `_sizeof_exp()`, while `__REAL<bits>_MAX_STRLEN__` comes from +`_real_max_string()`. MAX_STRLEN is a number of characters, not bytes; a +zero-terminated `char8` or `char16` buffer therefore needs at least +`MAX_STRLEN + 1` elements. + +Large numeric textual values remain deliberately capped at 256 bits. Integer +MAX and Real MAX/MIN/EPSILON/exponent-value macros are not emitted above that +width. Integer DECIMAL_DIG and Real DECIMAL_DIG/MANT_DIG remain available for +the complete configured families. Integer MIN expressions are never +predefined. This keeps `-dMP` compact while preserving useful precision, +structural and text-buffer metadata for large LibMPU types. + +The future language uses fixed-width names. Character types are `char8` and +`char16`; their sizes are `__SIZEOF_CHAR8__` and `__SIZEOF_CHAR16__`. Ordinary +C `char`, `short`, `int`, `long`, `wchar_t`, and the C-style `char*_t` names are +not part of the target language type model. + +The effective `MCPU_CPP_SYSTEM_INCLUDE_PATH` automatically contributes a +language-specific subdirectory for each active switched language. For example, +with the runtime-derived root and `#lang "diff"`, +`<runtime-root>/include/diff` is searched before +`<runtime-root>/include`. These derived directories need not exist and +require no extra configuration variables. + +`-dM` dumps only the current non-predefined macro table in deterministic +`#define` form. `-dMP` first dumps active predefined macros and then the +non-predefined macros; each group is sorted by name. +`-dconfig` dumps the effective configuration variables in sorted `NAME = value;` +form. `-v` prints the include-related effective configuration values once, +after all configuration layers have been resolved, and then preserves the usual +include/language runtime trace. `-dsearch-dirs` prints `search: DIR` lines for +the effective global include directories in semantic priority order and exits +without preprocessing. The dynamic source-directory step used by quoted +includes is not part of that global dump. None of these dump actions requires +an input file. + +The dynamic source macros `__FILE__`, `__LINE__`, `__BASE_FILE__`, +`__INCLUDE_LEVEL__`, `__DATE__` and `__TIME__` use one translation-unit +source stack and timestamp. Stringification, concatenation and conditional +compilation are part of the current preprocessing contract. + +Parser generation +----------------- + +The #if expression parser is generated by ZUBR 4.1.0 from +`src/mcpp-expr.zubr`. The grammar also contains the UCS-2 lexical analyzer. +The generated source `src/mcpp-expr.c` is included in release archives, so a +normal build from a release archive does not require ZUBR. + +The conditional-expression evaluator is deliberately 64-bit only. Integer +literals may use `U`/`u`, or the MCPU width suffix `zNNN[Uu]` / `ZNNN[Uu]`. +For valid widths up to 64, the low N bits are taken and then sign-extended +(`zNNN`) or zero-extended (`zNNNu`) to 64 bits; all later operations remain +64-bit and the original width is forgotten. Widths above 64 are rejected in +conditional directives. Invalid widths not exceeding 64 produce a warning +and the width suffix is ignored. C `L`/`LL` integer suffixes are not accepted. + +`#error` and `#warning` are implemented as diagnostic directives. Their +arguments are not macro-expanded. Outside quoted tokens, whitespace sequences +are folded to one space for the diagnostic text. `#error` stops preprocessing; +`#warning` continues. Both directives disappear from normal and `-dD` output, +and both are ignored in inactive conditional branches. + +Warning control follows a compact GNU-like model. `-Wcomment` and `-Wcomments` +enable warnings for `/*` inside an existing block comment and for a +backslash-newline continuing a `//` comment; `-Wall` currently enables this +optional warning class. The specific `-Wno-comment`/`-Wno-comments` setting +overrides `-Wall` regardless of command-line order. `-w` globally suppresses +all warnings, including `#warning`, invalid `zNNN` widths, macro redefinition, +invalid `##` paste and enabled comment diagnostics. It does not suppress +errors. `-Werror` promotes every warning that is actually emitted to an error +and unsuccessful preprocessing; because `-w` prevents warning emission first, +`-w -Werror` and `-Werror -w` are equivalent and successful when no independent +error occurs. Likewise, warning classes may be enabled by `-Wcomment` or +`-Wall`, but remain silent under `-w` regardless of option order. `-Wno-error` +restores ordinary warning severity. `-Werror` does not by itself enable +optional warning classes. + +When `mcpp-expr.zubr` is changed, the ordinary Automake `.zubr.c` rule +regenerates the C source with: + + zubr -vl -s -Bmcpp_ -o mcpp-expr.c mcpp-expr.zubr + + +Developer bootstrap +------------------- + +A Git checkout may omit files that are regenerated mechanically, including +`configure`, `Makefile.in`, Automake helper scripts, `config.h.in`, `aclocal.m4` +and `src/mcpp-expr.c`. Regenerate them with: + +```text +./bootstrap +``` + +`./bootstrap --target-dest-dir=DIR` follows the LibMPU/LibMPUIO convention for +using Autoconf macro/header directories from a target ROOTFS. Release archives +remain self-contained and do not require bootstrap before `configure`. + +Build +----- + +mcpu-cpp uses Autoconf/Automake and obtains LibMPUIO compilation and linker +flags from `mpuio-config`, following the conventions of LibMPU and LibMPUIO. +No pkg-config or flex dependency is introduced. The 1.0.2 release is +developed and tested against LibMPU 1.0.25 and LibMPUIO 1.0.4. The LibMPUIO +UCS-2 ctype API is required. ZUBR 4.1.0 is the parser-regeneration tool; it is +not required for a normal build from a release archive containing the generated +`src/mcpp-expr.c`. + +A normal build is: + + ./configure --prefix=/usr --libdir=/usr/lib64 + make + make tests + make install |
