fluffos/docs/lpc/preprocessor/define.md

102 lines
2.8 KiB
Markdown
Raw Permalink Normal View History

2018-12-30 16:43:04 -08:00
---
title: preprocessor / define
---
# #define and #undef
2018-12-30 16:43:04 -08: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
## Object-like macros
1995-03-12 00:14:16 -05: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.
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
```
## 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.