Path: utzoo!attcan!uunet!lll-winken!ames!pasteur!ucbvax!WSL.DEC.COM!joel From: joel@WSL.DEC.COM (Joel McCormack) Newsgroups: comp.lang.modula2 Subject: Re: conditional compilation (was C++ vs Modula-2) Message-ID: <8901140135.AA15110@gilroy.pa.dec.com> Date: 14 Jan 89 01:44:06 GMT References: <427@loligo.cc.fsu.edu> Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: Info-Modula2 Distribution List Organization: The Internet Lines: 92 I was hired by DEC 4 years ago to write a Pascal compiler for a RISC machine, the Titan. After evaluating the options, I figured the easiest way to go about it was to modify Mike Powell's Modula-2 compiler, which already generated code for the machine. Since I hate fixing bugs in two places, the obvious choice was to maintain one set of sources, conditionally compiled. I started to set this up by calling the C preprocessor from the Modula-2 comiler, but that got too messy too quickly. Including .h files is not the same as importing modules, no matter what a C hacker tells you. So I added conditional compilation to the compiler. It was quite easy, took less than a week, and I wouldn't live without it. Conditional compilation is not the same as dead code elimination, no matter what a Modula-2 purist tells you. I now have one set of sources that generates two compilers. It is very occasionally confusing to follow program logic, but the reduction in maintenance effort is well worth it. The facility looks like this: ProgramArgument = "-D"Ident"="ConstantExpression. Directive = "$IF" ConstantExpression "THEN" ProgramText {"$ELSIF" ConstantExpression "THEN" ProgramText} ["$ELSE" ProgramText] "$END" [";"] | "$CONST" Ident "=" ConstantExpression. [";"] ConstantExpression = SimpleConstExpr [Relation SimpleConstExpr]. Relation = "=" | "#" | "<>" | "<" | "<=" | ">" | ">=" | IN. SimpleConstExpr = ["+" | "-"] ConstTerm {AddOperator ConstTerm}. AddOperator = "+" | "-" | "OR". ConstTerm = ConstFactor {MultiplyOperator ConstFactor}. MultiplyOperator = "*" | "DIV" | "MOD" | "AND" | "&". ConstFactor = Ident | Number | String | Set | "NOT" ConstFactor | "~" ConstFactor | "(" ConstantExpression ")". Set = "{" SetRange {"," SetRange} "}". SetRange = Number [".." Number]. Number = digit {digit}. digit = "0".."9". String = "'" {character} "'" | '"' {character} '"'. Ident = letter {letter | digit}. letter = "A".."Z" | "a".."z". $ as the first non-blank character on a line indicates a directive. This may cause some hassles with RCS $Header declarations in comments. Just put another character in front of the $, and RCS will still find the $Header. All ConstantExpressions are evaluated, and all CONST declarations enter a name in the symbol table, including those in sections that are being skipped due to a previous expression evaluating FALSE. I am not sure if this will cause problems (some identifiers may be defined with different values in different sections, maybe?). It can be changed if someone comes up with a convincing case. TRUE and FALSE are predefine boolean Idents. Constants passed in from the command line override those defined in $CONST definitions. + - * DIV MOD apply only to numbers. AND & OR NOT ~ apply only to booleans. Relational operators apply to number, booleans, sets, and strings. About the only thing I'm inclined to add is a DEFINED procedure, which would work just like the C preprocessor. - Joel McCormack joel@decwrl.dec.com decwrl!joel