2018-12-30 16:43:04 -08:00
|
|
|
---
|
|
|
|
|
title: preprocessor / define
|
|
|
|
|
---
|
docs/lpc: source-file resolution, diagnostics, full preprocessor reference
New pages: lpc/source-files (extension rules, extension-blind object
identity, registry-before-filesystem, portable-code guidance),
lpc/diagnostics (clang-style output, macro expansion notes, include
chains, fix-its, show_error_context), preprocessor/conditionals
(token-based #if with C precedence, defined()/efun_defined()) and
preprocessor/pragma (real pragma table from the driver).
Rewrote preprocessor/index (full directive table, immutable
predefines), define (function-like macros, stringize/paste, rescan,
redefinition-warning semantics) and include (search order, master
get_include_path, trailing text, macro file names); constructs/include
is now a summary pointing at the reference, and constructs/inherit
documents pathname resolution. Dropped the vestigial
preprocessor/README; sidebar gains the new pages plus the previously
unlisted text_blocks.
AGENTS.md now points agents at docs/lpc/ as the authoritative LPC
reference. Validated with a clean docusaurus production build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:49:14 -07:00
|
|
|
# #define and #undef
|
2018-12-30 16:43:04 -08:00
|
|
|
|
docs/lpc: source-file resolution, diagnostics, full preprocessor reference
New pages: lpc/source-files (extension rules, extension-blind object
identity, registry-before-filesystem, portable-code guidance),
lpc/diagnostics (clang-style output, macro expansion notes, include
chains, fix-its, show_error_context), preprocessor/conditionals
(token-based #if with C precedence, defined()/efun_defined()) and
preprocessor/pragma (real pragma table from the driver).
Rewrote preprocessor/index (full directive table, immutable
predefines), define (function-like macros, stringize/paste, rescan,
redefinition-warning semantics) and include (search order, master
get_include_path, trailing text, macro file names); constructs/include
is now a summary pointing at the reference, and constructs/inherit
documents pathname resolution. Dropped the vestigial
preprocessor/README; sidebar gains the new pages plus the previously
unlisted text_blocks.
AGENTS.md now points agents at docs/lpc/ as the authoritative LPC
reference. Validated with a clean docusaurus production build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:49:14 -07:00
|
|
|
`#define` creates a **macro**: a name that is replaced by a body of
|
|
|
|
|
text wherever it appears later in the file.
|
1995-03-12 00:14:16 -05:00
|
|
|
|
docs/lpc: source-file resolution, diagnostics, full preprocessor reference
New pages: lpc/source-files (extension rules, extension-blind object
identity, registry-before-filesystem, portable-code guidance),
lpc/diagnostics (clang-style output, macro expansion notes, include
chains, fix-its, show_error_context), preprocessor/conditionals
(token-based #if with C precedence, defined()/efun_defined()) and
preprocessor/pragma (real pragma table from the driver).
Rewrote preprocessor/index (full directive table, immutable
predefines), define (function-like macros, stringize/paste, rescan,
redefinition-warning semantics) and include (search order, master
get_include_path, trailing text, macro file names); constructs/include
is now a summary pointing at the reference, and constructs/inherit
documents pathname resolution. Dropped the vestigial
preprocessor/README; sidebar gains the new pages plus the previously
unlisted text_blocks.
AGENTS.md now points agents at docs/lpc/ as the authoritative LPC
reference. Validated with a clean docusaurus production build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:49:14 -07:00
|
|
|
## Object-like macros
|
1995-03-12 00:14:16 -05:00
|
|
|
|
docs/lpc: source-file resolution, diagnostics, full preprocessor reference
New pages: lpc/source-files (extension rules, extension-blind object
identity, registry-before-filesystem, portable-code guidance),
lpc/diagnostics (clang-style output, macro expansion notes, include
chains, fix-its, show_error_context), preprocessor/conditionals
(token-based #if with C precedence, defined()/efun_defined()) and
preprocessor/pragma (real pragma table from the driver).
Rewrote preprocessor/index (full directive table, immutable
predefines), define (function-like macros, stringize/paste, rescan,
redefinition-warning semantics) and include (search order, master
get_include_path, trailing text, macro file names); constructs/include
is now a summary pointing at the reference, and constructs/inherit
documents pathname resolution. Dropped the vestigial
preprocessor/README; sidebar gains the new pages plus the previously
unlisted text_blocks.
AGENTS.md now points agents at docs/lpc/ as the authoritative LPC
reference. Validated with a clean docusaurus production build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:49:14 -07:00
|
|
|
```c
|
|
|
|
|
#define MAX_HP 100
|
|
|
|
|
#define GREETING "Welcome to " MUD_NAME
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Every later occurrence of the name (as a whole identifier — not inside
|
|
|
|
|
strings, comments, or longer identifiers) is replaced by the body.
|
|
|
|
|
|
|
|
|
|
## Function-like macros
|
|
|
|
|
|
|
|
|
|
A parameter list attached **directly** to the name (no space before
|
|
|
|
|
`(`) makes the macro function-like:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#define SQUARE(x) ((x) * (x))
|
|
|
|
|
#define MSG(who, text) tell_object(who, text "\n")
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Arguments are collected with full nesting awareness — commas inside
|
|
|
|
|
parentheses, strings, or character literals do not split arguments.
|
|
|
|
|
Parenthesize parameters in the body (as above) to avoid precedence
|
|
|
|
|
surprises at the use site.
|
|
|
|
|
|
|
|
|
|
Inside a macro body, `#param` produces the argument's text as a string
|
|
|
|
|
literal, and `a ## b` pastes two tokens together. `##` may not appear
|
|
|
|
|
at the very start or end of a body.
|
|
|
|
|
|
|
|
|
|
## Expansion and rescan
|
|
|
|
|
|
|
|
|
|
A macro's body is rescanned after substitution, so macros may reference
|
|
|
|
|
other macros freely. A macro that (directly or indirectly) references
|
|
|
|
|
itself stops expanding at the self-reference instead of recursing
|
|
|
|
|
forever, as in C.
|
|
|
|
|
|
|
|
|
|
Because `#if` expressions are evaluated over the same token stream,
|
|
|
|
|
arithmetic keeps C precedence across macro boundaries:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#define X 1+1
|
|
|
|
|
#if X*2 == 3 // 1+1*2 -- true
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Multi-line macros
|
|
|
|
|
|
|
|
|
|
End a line with `\` to continue the definition:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#define LONG_MACRO(x) do { \
|
|
|
|
|
write(x); \
|
|
|
|
|
} while (0)
|
|
|
|
|
```
|
|
|
|
|
|
lexer: block comments on directive lines may span physical lines (#1236) (#1239)
* tests: clear the active scanner before yylex_destroy in the harnesses
Both tokenizer harnesses destroyed their scanner without
lpc_lex_scanner_destroyed(), leaving the global active_scanner dangling;
the next compile's first current_line read then dereferenced the
destroyed scanner's guts (lpc_lex_current_line_ref ->
innermost_real_buffer_index). Order-dependent and layout-dependent: any
Preprocessor test followed by CompileEntry.FatalInsideIfExpressionRecovers
segfaulted deterministically in a minimal pair and intermittently in full
runs. Pre-existing (reproduces on master); surfaced while adding the
#1236 tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FMBJLkpkpVpZdz6PWzeWe
* lexer: a directive-line block comment may span physical lines (#1236)
The single anchored directive rule captures one physical line (plus
backslash continuations), so a /* comment opened after a #define body
and closed on a later line ended the capture at the newline:
strip_directive_comments() silently swallowed the open comment, the
define itself parsed, and the comment's remaining lines were tokenized
as code -- a regression against the old lexer for a pattern real
mudlibs use.
New lpc_lex_complete_directive() runs before the terminating-newline
consumption: it scans the captured text (quote-aware, same rules as
strip_directive_comments) and, when the line ends inside an open block
comment, pulls raw bytes through lpc_lex_getc() until the comment
closes and the logical line really ends. Comments fold to a single
space, so text after the close still belongs to the directive (C
semantics), and the tail may open further comments, strings, '//', or
backslash continuations. Newlines pulled this way get the same
bookkeeping as the rule's own terminator, and the count is backed out
of lpc_lex_on_directive()'s first-line attribution so diagnostics still
point at the directive. EOF inside the comment reports the same error
as SC_BLOCK_COMMENT's <<EOF>> rule instead of spinning.
Covered by new Preprocessor unit tests (repro shape, comment tail,
__LINE__ bookkeeping, live/dead #if, string-literal '/*', EOF) and
testsuite/single/tests/compiler/preprocessor.lpc pins; documented in
docs/lpc/preprocessor/define.md.
Fixes #1236
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FMBJLkpkpVpZdz6PWzeWe
---------
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-11 02:07:07 -04:00
|
|
|
A block comment opened on a directive line may also span lines — it
|
|
|
|
|
reads as whitespace and does not end the directive, so both of these
|
|
|
|
|
define `WARNING_LEVEL` as `1`:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#define WARNING_LEVEL 1 /* change to a higher value to
|
|
|
|
|
show more warnings */
|
|
|
|
|
|
|
|
|
|
#define WARNING_LEVEL 1 // single-line form
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Text after the comment's close on its final line still belongs to the
|
|
|
|
|
directive, matching C.
|
|
|
|
|
|
lexer: strip comments from directive payloads before parsing (#1240) (#1241)
A '//' comment after a #define body was captured INTO the stored macro
body. Expansion buffers carry no newline to end it, so when the macro
expanded inside a spliced line (a function-like macro's substituted
body, as in the report's MIN(credits, m[e][CREDITS])), the '//' ate the
rest of the splice and the parse failed with a baffling 'unexpected ;'
attributed to the outer macro. The same missed strip made
'#undef X // why' erase nothing and '#ifdef X // why' look up the
wrong name and silently take the false branch.
Comments are whitespace (C translation phase 3). dispatch_directive now
strips them from the payload before parsing for #define (name, params,
body -- body also right-trimmed so a stripped comment can't turn '1'
vs '1 ' into a spurious redefinition warning), #undef, #ifdef, #ifndef,
and #pragma (word-list payload); #if/#elif already stripped.
strip_directive_comments() now folds a block comment to ONE space
instead of nothing, so '1 -/*c*/-1' keeps its token boundaries instead
of pasting '--'. #error/#warn/#echo payloads stay raw.
Covered by five new Preprocessor unit tests (the report's repro shape,
paste-prevention via #if branch selection, param-list comment,
testsuite/single/tests/compiler/preprocessor.lpc; documented in
docs/lpc/preprocessor/define.md.
Fixes #1240
Claude-Session: https://claude.ai/code/session_016FMBJLkpkpVpZdz6PWzeWe
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-11 12:15:19 -04:00
|
|
|
Comments on a directive line are whitespace, never part of the macro:
|
|
|
|
|
a trailing `//` or `/* */` after the body (or after the name on
|
|
|
|
|
`#undef`/`#ifdef`) is stripped before the directive is parsed, and a
|
|
|
|
|
block comment inside the body separates tokens like a space would:
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#define CREDITS "credits" // key into the economy mapping
|
|
|
|
|
```
|
|
|
|
|
|
docs/lpc: source-file resolution, diagnostics, full preprocessor reference
New pages: lpc/source-files (extension rules, extension-blind object
identity, registry-before-filesystem, portable-code guidance),
lpc/diagnostics (clang-style output, macro expansion notes, include
chains, fix-its, show_error_context), preprocessor/conditionals
(token-based #if with C precedence, defined()/efun_defined()) and
preprocessor/pragma (real pragma table from the driver).
Rewrote preprocessor/index (full directive table, immutable
predefines), define (function-like macros, stringize/paste, rescan,
redefinition-warning semantics) and include (search order, master
get_include_path, trailing text, macro file names); constructs/include
is now a summary pointing at the reference, and constructs/inherit
documents pathname resolution. Dropped the vestigial
preprocessor/README; sidebar gains the new pages plus the previously
unlisted text_blocks.
AGENTS.md now points agents at docs/lpc/ as the authoritative LPC
reference. Validated with a clean docusaurus production build.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 00:49:14 -07:00
|
|
|
## Redefinition
|
|
|
|
|
|
|
|
|
|
Redefining a macro with a **different** body is allowed: the compiler
|
|
|
|
|
emits a warning (with a note pointing at the previous definition) and
|
|
|
|
|
the new definition takes effect. Redefining with an identical body is
|
|
|
|
|
silent. Redefining or `#undef`-ing a **predefined** macro (`__FILE__`,
|
|
|
|
|
`FLUFFOS`, ...) is a compile error.
|
|
|
|
|
|
|
|
|
|
## #undef
|
|
|
|
|
|
|
|
|
|
```c
|
|
|
|
|
#undef MAX_HP
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Removes a user macro definition; the name is ordinary text again.
|
|
|
|
|
`#undef` of an unknown name is harmless.
|