Skip to content

WCPL macros

WCPL has a simple macro mechanism that mimics most frequent patterns used by C macro writers while being implemented via an entirely different mechanism. While C macros manipulate sequences of tokens, WCPL macros manipulate complete expressions; substitution is done on the level of abstract syntax trees. Although it makes it impossible to use some advanced tricks empoyed by C macro experts, such as introducing unpaired braces, substituting types, and glueing identifiers from individual parts, most popular macro patterns still can be employed, and made to behave in the same way between WCPL and C.

WCPL macros have two flavors: expression macros and statement macros. Expression macros have a complete expression on the right-hand side of the macro. Formally, it is a primary_expression grammar category; informally, it is either a literal constant (no sign for numerical literals!) or any single expression enclosed in parentheses, e.g.:

#define NINE 9
#define MINUS_NINE (-9) /* has to be parenthesized! */
#define DBL_MAX 1.79769313486231570815e+308
#define stdin (&_iob[0]) 

Statement macro’s right-hand side is single statement wrapped in a “fake do”, i.e. preceded by the do keyword and followed by while (0) trailer. It may look strange, but it is indeed a standard C practice, allowing uses of such macros to be followed by a semicolon, as required by C statement grammar, e.g.:

#define p2up(x, res) do { \
  size_t c = clz32(x); \
  res = 32-c; \
} while (0)

Please note two additional features in the example above: the name of the macro being defined can be followed by a parenthesized list of argument names (no space is allowed between the name and the open parenthesis), and long macro bodies can be wrapped into multiple lines if internal end-of-line characters are “escaped” via a backslash. The latter feature is optional in WCPL (it always reads a complete grammar category, not a token list), but supported for compatibility with C preprocessor — the macro above works in the same way both in C and WCPL.

Expression macros can be parameterized as well. Please note that WCPL macro uses, which look like function calls, can only accept grammatically valid expressions as parameters. There is no such limitation in C, where any sequences of tokens will do, as long as they are separated by colons. Example:

/* works in C and WCPL */
#define getc(p) (--(p)->cnt >= 0 ? (unsigned char)*(p)->ptr++ : _fillbuf(p))

/* works in C, but not in WCPL */
#define cast(type, x) ((type)(x))  /* C can use types as macro parameters */ 

WCPL macros can only be defined on top level of the module or header file; they cannot be re-defined if an earlier definition exists, unless they undefined via #undef first:

#undef NINE
#define NINE "nine"

Some built-in macros such as __WCPL__ cannot be undefined or redefined. Additional macro features will be described in separate posts.