Implements real symbol-presence conditional compilation in the lexer.
Previously {$IFDEF} was hardcoded false (always took {$ELSE}) and
{$DEFINE}/{$UNDEF} were silently consumed, with no define table and no
command-line flag.
- A case-insensitive define table on TLexer. {$DEFINE sym} / {$UNDEF sym}
add and remove symbols; {$IFDEF sym} keeps its body when defined (and
{$IFNDEF sym} when not), with an optional {$ELSE} and a closing {$ENDIF}.
IFDEF/IFNDEF blocks nest (the existing depth-tracking skip helpers are
reused, now driven by the real truth value).
- Predefined symbols, seeded in every lexer: BLAISE (the headline
cross-compiler use case — {$IFDEF BLAISE} ... {$ELSE} ... {$ENDIF}) plus
the target CPU/OS symbols CPUX86_64, CPUAMD64, LINUX, UNIX. No version
macro yet.
- A -d / --define <sym> command-line flag (FPC -dSYM / Delphi -D), carried
on TFrontEndOpts and threaded to the program's lexer AND to every unit the
TUnitLoader compiles, so {$IFDEF} resolves consistently across the program
and its units.
Tests:
- cp.test.lexer.pas: predefined BLAISE keeps the body, undefined takes ELSE,
IFNDEF, DEFINE-then-IFDEF, UNDEF-then-IFDEF, and AddDefine (the -d path).
- cp.test.e2e.misc.pas (dual-backend): the {$IFDEF BLAISE} cross-compiler
pattern, and a combined DEFINE/UNDEF/IFNDEF/CPU-OS/nested program.
Docs: grammar.ebnf documents the directives and predefines; language-
rationale.adoc records the decision (symbol-presence only, no {$IF} expr
form yet; BLAISE + CPU/OS predefined, no version macro) and alternatives.
Verified: FIXPOINT_OK, NATIVE_FIXPOINT_OK, NATIVE_INTERNAL_OK; full suite
green on both the QBE-built and native-built runners (3715 tests).