The origin of the C Preprocessor

chistorymacros

The C preprocessor is attached to C, but it has a completely different syntax from the main language:

  • syntactically significant whitespace (end of line terminates a statement, gap after the macro determines the start of the replacement list)

  • keyword-based blocks instead of braced blocks, elif instead of else if

  • keyword-led definitions instead of declaration-reflects-use, no = for value definition

  • hints of an alternative string syntax (#include <> vs #include "")

  • lazy evaluation (of C, obviously; but 6.10.3.1 can be read as implying a specific order of macro expansion as well, in the few places that matters)

It really doesn't look like C at all! Technically it is its own language, but it's always been used as a nearly-integral part of C and it seems very strange that it wouldn't integrate with it syntactically.

Wikipedia doesn't talk about its history; the Portland Pattern Repository gives it a passing mention, but doesn't go into detail beyond the fact that it was designed by other people than the rest of C. Dennis Ritchie's website with the history of C probably had the answer, but is unfortunately no longer available.

As a macro engine, it obviously has very different semantics from the runtime language, which would explain some differences, but not the visual design aspects (it's also unclear to modern eyes whether it was originally intended as being capable of the kind of fun that its replacement system allows, or whether it was "just" an expedient way to inline functions in a time before powerful optimizers). It feels like something closer to what eventually became C++ templates would have been a more logical evolution towards macros, if C-like semantics had actually been the starting point, but there's less concrete evidence of this than there is for the syntax.

Do we have any record of why it was designed this way, or what the creators' influences were?

Best Answer

From http://www.jslint.com/chistory.html ("The Development of the C Language" by Dennis M. Ritchie):

Many other changes occurred around 1972-3, but the most important was the introduction of the preprocessor, partly at the urging of Alan Snyder [Snyder 74], but also in recognition of the utility of the the file-inclusion mechanisms available in BCPL and PL/I. Its original version was exceedingly simple, and provided only included files and simple string replacements: #include and #define of parameterless macros. Soon thereafter, it was extended, mostly by Mike Lesk and then by John Reiser, to incorporate macros with arguments and conditional compilation. The preprocessor was originally considered an optional adjunct to the language itself. Indeed, for some years, it was not even invoked unless the source program contained a special signal at its beginning. This attitude persisted, and explains both the incomplete integration of the syntax of the preprocessor with the rest of the language and the imprecision of its description in early reference manuals.

It appears from the account in section 4 of the [Snyder 74] reference linked in the quote above that Alan Snyder had been working on a portable (today one might say "retargetable") C compiler. Perhaps this was the motivation for asking for a preprocessor.

I have not been able to find any additional detail, though, on the design of the C preprocessor itself, as a language.

Related Topic