#include <string.h>
#include <stdlib.h>
#include <errno.h>
-#include <ctype.h>
-#include "../common/xmalloc.h"
+/* common */
+#include "chartype.h"
+#include "check.h"
+#include "inline.h"
+#include "print.h"
+#include "xmalloc.h"
+/* cc65 */
#include "codegen.h"
#include "error.h"
#include "expr.h"
#include "ident.h"
#include "incpath.h"
#include "input.h"
+#include "lineinfo.h"
#include "macrotab.h"
#include "scanner.h"
#include "util.h"
/*****************************************************************************/
-/* data */
+/* Data */
/*****************************************************************************/
-/* Set when the pp calls expr() recursively */
+/* Set when the preprocessor calls expr() recursively */
unsigned char Preprocessing = 0;
/* Management data for #if */
-#define N_IFDEF 16
-static int i_ifdef = -1;
-static char s_ifdef[N_IFDEF];
+#define MAX_IFS 64
+#define IFCOND_NONE 0x00U
+#define IFCOND_SKIP 0x01U
+#define IFCOND_ELSE 0x02U
+#define IFCOND_NEEDTERM 0x04U
+static unsigned char IfStack[MAX_IFS];
+static int IfIndex = -1;
/* Buffer for macro expansion */
static char mlinebuf [LINESIZE];
static char* mline = mlinebuf;
static char* mptr;
-/* Flag: Expand macros in this line */
-static int ExpandMacros = 1;
+
+
+/*****************************************************************************/
+/* Low level preprocessor token handling */
+/*****************************************************************************/
+
+
+
+/* Types of preprocessor tokens */
+typedef enum {
+ PP_DEFINE,
+ PP_ELIF,
+ PP_ELSE,
+ PP_ENDIF,
+ PP_ERROR,
+ PP_IF,
+ PP_IFDEF,
+ PP_IFNDEF,
+ PP_INCLUDE,
+ PP_LINE,
+ PP_PRAGMA,
+ PP_UNDEF,
+ PP_ILLEGAL
+} pptoken_t;
+
+
+
+/* Preprocessor keyword to token mapping table */
+static const struct PPToken {
+ const char* Key; /* Keyword */
+ pptoken_t Tok; /* Token */
+} PPTokens[] = {
+ { "define", PP_DEFINE },
+ { "elif", PP_ELIF },
+ { "else", PP_ELSE },
+ { "endif", PP_ENDIF },
+ { "error", PP_ERROR },
+ { "if", PP_IF },
+ { "ifdef", PP_IFDEF },
+ { "ifndef", PP_IFNDEF },
+ { "include", PP_INCLUDE },
+ { "line", PP_LINE },
+ { "pragma", PP_PRAGMA },
+ { "undef", PP_UNDEF },
+};
+
+/* Number of preprocessor tokens */
+#define PPTOKEN_COUNT (sizeof(PPTokens) / sizeof(PPTokens[0]))
+
+
+
+static int CmpToken (const void* Key, const void* Elem)
+/* Compare function for bsearch */
+{
+ return strcmp ((const char*) Key, ((const struct PPToken*) Elem)->Key);
+}
+
+
+
+static pptoken_t FindPPToken (const char* Ident)
+/* Find a preprocessor token and return ut. Return PP_ILLEGAL if the identifier
+ * is not a valid preprocessor token.
+ */
+{
+ struct PPToken* P;
+ P = bsearch (Ident, PPTokens, PPTOKEN_COUNT, sizeof (PPTokens[0]), CmpToken);
+ return P? P->Tok : PP_ILLEGAL;
+}
/*****************************************************************************/
-/* code */
+/* Code */
/*****************************************************************************/
-static int keepch (char c)
+#ifdef HAVE_INLINE
+INLINE void KeepChar (char c)
/* Put character c into translation buffer. */
{
- return (*mptr++ = c);
+ *mptr++ = c;
}
+#else
+#define KeepChar(c) *mptr++ = (c)
+#endif
-static void keepstr (const char* S)
+static void KeepStr (const char* S)
/* Put string str into translation buffer. */
{
+ unsigned Len = strlen (S);
+ memcpy (mptr, S, Len);
+ mptr += Len;
+}
+
+
+
+static void Stringize (const char* S)
+/* Stringize the given string: Add double quotes at start and end and preceed
+ * each occurance of " and \ by a backslash.
+ */
+{
+ KeepChar ('\"');
+ /* Replace any characters inside the string may not be part of a string
+ * unescaped.
+ */
while (*S) {
- keepch (*S++);
+ switch (*S) {
+ case '\"':
+ case '\\':
+ KeepChar ('\\');
+ /* FALLTHROUGH */
+ default:
+ KeepChar (*S);
+ break;
+ }
+ ++S;
}
+ KeepChar ('\"');
+}
+
+
+
+static void SwapLineBuffers (void)
+/* Swap both line buffers */
+{
+ /* Swap mline and line */
+ char* p = line;
+ line = mline;
+ mline = p;
}
-static void Comment (void)
-/* Remove a C comment from line. */
+static void OldStyleComment (void)
+/* Remove an old style C comment from line. */
{
/* Remember the current line number, so we can output better error
* messages if the comment is not terminated in the current file.
while (CurC != '*' || NextC != '/') {
if (CurC == '\0') {
if (NextLine () == 0) {
- PPError (ERR_EOF_IN_COMMENT, StartingLine);
+ PPError ("End-of-file reached in comment starting at line %u",
+ StartingLine);
return;
}
} else {
if (CurC == '/' && NextC == '*') {
- PPWarning (WARN_NESTED_COMMENT);
+ PPWarning ("`/*' found inside a comment");
}
NextChar ();
}
+static void NewStyleComment (void)
+/* Remove a new style C comment from line. */
+{
+ /* Beware: Because line continuation chars are handled when reading
+ * lines, we may only skip til the end of the source line, which
+ * may not be the same as the end of the input line. The end of the
+ * source line is denoted by a lf (\n) character.
+ */
+ do {
+ NextChar ();
+ } while (CurC != '\n' && CurC != '\0');
+ if (CurC == '\n') {
+ NextChar ();
+ }
+}
+
+
+
static void SkipBlank (void)
/* Skip blanks and tabs in the input stream. */
{
/* Copy the characters inside the string */
while (CurC != '\0' && CurC != Quote) {
/* Keep an escaped char */
- if (CurC == '\\') {
+ if (CurC == '\\') {
*Target++ = CurC;
NextChar ();
}
/*****************************************************************************/
-/* Macro stuff */
+/* Macro stuff */
/*****************************************************************************/
static int MacName (char* Ident)
-/* Get macro symbol name. If error, print message and clear line. */
+/* Get a macro symbol name into Ident. If we have an error, print a
+ * diagnostic message and clear the line.
+ */
{
if (IsSym (Ident) == 0) {
- PPError (ERR_IDENT_EXPECTED);
+ PPError ("Identifier expected");
ClearLine ();
- return 0;
+ return 0;
} else {
return 1;
}
static void ExpandMacroArgs (Macro* M)
-/* Preprocessor pass 2. Perform macro substitution. */
+/* Expand the arguments of a macro */
{
ident Ident;
const char* Replacement;
/* Copy the macro replacement checking for parameters to replace */
while (CurC != '\0') {
- /* If the next token is an identifier, check for a macro arg */
+ /* If the next token is an identifier, check for a macro arg */
if (IsIdent (CurC)) {
SymName (Ident);
- Replacement = FindMacroArg (M, Ident);
- if (Replacement) {
- /* Macro arg, keep the replacement */
- keepstr (Replacement);
+ Replacement = FindMacroArg (M, Ident);
+ if (Replacement) {
+ /* Macro arg, keep the replacement */
+ KeepStr (Replacement);
} else {
- /* No macro argument, keep the original identifier */
- keepstr (Ident);
+ /* No macro argument, keep the original identifier */
+ KeepStr (Ident);
}
} else if (CurC == '#' && IsIdent (NextC)) {
NextChar ();
SymName (Ident);
- Replacement = FindMacroArg (M, Ident);
+ Replacement = FindMacroArg (M, Ident);
if (Replacement) {
- keepch ('\"');
- keepstr (Replacement);
- keepch ('\"');
+ /* Make a valid string from Replacement */
+ Stringize (Replacement);
} else {
- keepch ('#');
- keepstr (Ident);
+ /* No replacement - keep the input */
+ KeepChar ('#');
+ KeepStr (Ident);
}
- } else if (IsQuoteChar (CurC)) {
+ } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else {
- *mptr++ = CurC;
- NextChar ();
+ KeepChar (CurC);
+ NextChar ();
}
}
static int MacroCall (Macro* M)
/* Process a function like macro */
{
- unsigned ArgCount; /* Macro argument count */
+ int ArgCount; /* Macro argument count */
unsigned ParCount; /* Number of open parenthesis */
char Buf[LINESIZE]; /* Argument buffer */
const char* ArgStart;
/* Expect an argument list */
SkipBlank ();
if (CurC != '(') {
- PPError (ERR_ILLEGAL_MACRO_CALL);
+ PPError ("Illegal macro call");
return 0;
}
B = Buf;
while (1) {
if (CurC == '(') {
- /* Nested parenthesis */
+ /* Nested parenthesis */
*B++ = CurC;
- NextChar ();
+ NextChar ();
++ParCount;
- } else if (IsQuoteChar (CurC)) {
+ } else if (IsQuote (CurC)) {
B = CopyQuotedString (B);
} else if (CurC == ',' || CurC == ')') {
if (ParCount == 0) {
- /* End of actual argument */
+ /* End of actual argument */
*B++ = '\0';
- while (IsBlank(*ArgStart)) {
- ++ArgStart;
- }
+ while (IsBlank(*ArgStart)) {
+ ++ArgStart;
+ }
if (ArgCount < M->ArgCount) {
M->ActualArgs[ArgCount++] = ArgStart;
} else if (CurC != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
- /* Be sure not to count the single empty argument for a
- * macro that does not have arguments.
- */
+ /* Be sure not to count the single empty argument for a
+ * macro that does not have arguments.
+ */
++ArgCount;
- }
+ }
- /* Check for end of macro param list */
- if (CurC == ')') {
- NextChar ();
- break;
- }
+ /* Check for end of macro param list */
+ if (CurC == ')') {
+ NextChar ();
+ break;
+ }
/* Start the next param */
ArgStart = B;
- NextChar ();
+ NextChar ();
} else {
- /* Comma or right paren inside nested parenthesis */
+ /* Comma or right paren inside nested parenthesis */
if (CurC == ')') {
--ParCount;
}
*B++ = CurC;
- NextChar ();
+ NextChar ();
}
} else if (IsBlank (CurC)) {
- /* Squeeze runs of blanks */
+ /* Squeeze runs of blanks */
*B++ = ' ';
SkipBlank ();
+ } else if (CurC == '/' && NextC == '*') {
+ *B++ = ' ';
+ OldStyleComment ();
+ } else if (ANSI == 0 && CurC == '/' && NextC == '/') {
+ *B++ = ' ';
+ NewStyleComment ();
} else if (CurC == '\0') {
- /* End of line inside macro argument list - read next line */
+ /* End of line inside macro argument list - read next line */
if (NextLine () == 0) {
return 0;
}
} else {
- /* Just copy the character */
+ /* Just copy the character */
*B++ = CurC;
- NextChar ();
+ NextChar ();
}
}
/* Compare formal argument count with actual */
if (M->ArgCount != ArgCount) {
- PPError (ERR_MACRO_ARGCOUNT);
- /* Be sure to make enough empty arguments available */
- while (ArgCount < M->ArgCount) {
- M->ActualArgs [ArgCount++] = "";
- }
+ PPError ("Macro argument count mismatch");
+ /* Be sure to make enough empty arguments available */
+ while (ArgCount < M->ArgCount) {
+ M->ActualArgs [ArgCount++] = "";
+ }
}
/* Preprocess the line, replacing macro parameters */
{
/* Check if this is a function like macro */
if (M->ArgCount >= 0) {
- /* Function like macro */
+ /* Function like macro */
if (MacroCall (M) == 0) {
ClearLine ();
}
} else {
- /* Just copy the replacement text */
- keepstr (M->Replacement);
+ /* Just copy the replacement text */
+ KeepStr (M->Replacement);
}
}
-static void addmac (void)
-/* Add a macro to the macro table. */
+static void DefineMacro (void)
+/* Handle a macro definition. */
{
char* saveptr;
ident Ident;
char Buf[LINESIZE];
Macro* M;
+ Macro* Existing;
/* Read the macro name */
SkipBlank ();
return;
}
+ /* Get an existing macro definition with this name */
+ Existing = FindMacro (Ident);
+
/* Create a new macro definition */
M = NewMacro (Ident);
NextChar ();
/* Set the marker that this is a function like macro */
- M->ArgCount = 0;
+ M->ArgCount = 0;
- /* Read the formal parameter list */
+ /* Read the formal parameter list */
while (1) {
SkipBlank ();
if (CurC == ')')
if (MacName (Ident) == 0) {
return;
}
- AddMacroArg (M, Ident);
+ AddMacroArg (M, Ident);
SkipBlank ();
if (CurC != ',')
break;
NextChar ();
}
- /* Check for a right paren and eat it if we find one */
+ /* Check for a right paren and eat it if we find one */
if (CurC != ')') {
- PPError (ERR_RPAREN_EXPECTED);
+ PPError ("`)' expected");
ClearLine ();
return;
}
/* Create a copy of the replacement */
M->Replacement = xstrdup (Buf);
+
+ /* If we have an existing macro, check if the redefinition is identical.
+ * Print a diagnostic if not.
+ */
+ if (Existing) {
+ if (MacroCmp (M, Existing) != 0) {
+ PPError ("Macro redefinition is not identical");
+ }
+ }
}
/*****************************************************************************/
-
+/* Preprocessing */
/*****************************************************************************/
done = 1;
while (CurC != '\0') {
if (IsBlank (CurC)) {
- keepch (' ');
+ KeepChar (' ');
SkipBlank ();
} else if (IsIdent (CurC)) {
SymName (Ident);
SkipBlank();
}
if (!IsIdent (CurC)) {
- PPError (ERR_IDENT_EXPECTED);
- *mptr++ = '0';
+ PPError ("Identifier expected");
+ KeepChar ('0');
} else {
SymName (Ident);
- *mptr++ = IsMacro (Ident)? '1' : '0';
+ KeepChar (IsMacro (Ident)? '1' : '0');
if (HaveParen) {
SkipBlank();
if (CurC != ')') {
- PPError (ERR_RPAREN_EXPECTED);
- } else {
+ PPError ("`)' expected");
+ } else {
NextChar ();
}
}
if (MaybeMacro (Ident[0])) {
done = 0;
}
- keepstr (Ident);
+ KeepStr (Ident);
}
- } else if (IsQuoteChar (CurC)) {
+ } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else if (CurC == '/' && NextC == '*') {
- keepch (' ');
- Comment ();
+ KeepChar (' ');
+ OldStyleComment ();
} else if (ANSI == 0 && CurC == '/' && NextC == '/') {
- keepch (' ');
- /* Beware: Because line continuation chars are handled when reading
- * lines, we may only skip til the end of the source line, which
- * may not be the same as the end of the input line. The end of the
- * source line is denoted by a lf (\n) character.
- */
- do {
- NextChar ();
- } while (CurC != '\n' && CurC != '\0');
- if (CurC == '\n') {
- NextChar ();
- }
+ KeepChar (' ');
+ NewStyleComment ();
} else {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
}
- keepch ('\0');
+ KeepChar ('\0');
return done;
}
/* Loop substituting macros */
no_chg = 1;
while (CurC != '\0') {
- /* If we have an identifier, check if it's a macro */
+ /* If we have an identifier, check if it's a macro */
if (IsIdent (CurC)) {
SymName (Ident);
M = FindMacro (Ident);
ExpandMacro (M);
no_chg = 0;
} else {
- keepstr (Ident);
+ KeepStr (Ident);
}
- } else if (IsQuoteChar(CurC)) {
+ } else if (IsQuote (CurC)) {
mptr = CopyQuotedString (mptr);
} else {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
}
-static void xlateline (void)
+static void PreprocessLine (void)
/* Translate one line. */
{
- int cnt;
- int Done;
+ unsigned I;
- Done = Pass1 (line, mline);
- if (ExpandMacros == 0) {
- Done = 1;
- ExpandMacros = 1; /* Reset to default */
- }
- cnt = 5;
- do {
+ /* Trim whitespace and remove comments. The function returns false if no
+ * identifiers were found that may be macros. If this is the case, no
+ * macro substitution is performed.
+ */
+ int Done = Pass1 (line, mline);
+
+ /* Repeatedly expand macros in the line */
+ for (I = 0; I < 5; ++I) {
/* Swap mline and line */
- char* p = line;
- line = mline;
- mline = p;
- if (Done)
- break;
- Done = Pass2 (line, mline);
- keepch ('\0');
- } while (--cnt);
+ SwapLineBuffers ();
+ if (Done) {
+ break;
+ }
+ /* Perform macro expansion */
+ Done = Pass2 (line, mline);
+ KeepChar ('\0');
+ }
/* Reinitialize line parsing */
InitLine (line);
-static void doundef (void)
-/* Process #undef directive */
+static void DoUndef (void)
+/* Process the #undef directive */
{
ident Ident;
-static int setmflag (int skip, int flag, int cond)
-/* setmflag( skip, flag, cond ) */
+static int PushIf (int Skip, int Invert, int Cond)
+/* Push a new if level onto the if stack */
{
- if (skip) {
- s_ifdef[++i_ifdef] = 3;
- return (1);
+ /* Check for an overflow of the if stack */
+ if (IfIndex >= MAX_IFS-1) {
+ PPError ("Too many nested #if clauses");
+ return 1;
+ }
+
+ /* Push the #if condition */
+ ++IfIndex;
+ if (Skip) {
+ IfStack[IfIndex] = IFCOND_SKIP | IFCOND_NEEDTERM;
+ return 1;
} else {
- s_ifdef[++i_ifdef] = 6;
- return (flag ^ cond);
+ IfStack[IfIndex] = IFCOND_NONE | IFCOND_NEEDTERM;
+ return (Invert ^ Cond);
}
}
-static int doiff (int skip)
+static int DoIf (int Skip)
/* Process #if directive */
{
- struct expent lval;
+ ExprDesc lval;
char* S;
/* We're about to abuse the compiler expression parser to evaluate the
* #if expression. Save the current tokens to come back here later.
+ * NOTE: Yes, this is a hack, but it saves a complete separate expression
+ * evaluation for the preprocessor.
*/
Token sv1 = CurTok;
Token sv2 = NextTok;
- /* Remove the #if from the line and add two semicolons as sentinels */
+ /* Make sure the line infos for the tokens won't get removed */
+ if (sv1.LI) {
+ UseLineInfo (sv1.LI);
+ }
+ if (sv2.LI) {
+ UseLineInfo (sv2.LI);
+ }
+
+ /* Remove the #if from the line */
SkipBlank ();
S = line;
while (CurC != '\0') {
- *S++ = CurC;
- NextChar ();
+ *S++ = CurC;
+ NextChar ();
}
- *S++ = ';';
- *S++ = ';';
- *S = '\0';
+ *S = '\0';
/* Start over parsing from line */
InitLine (line);
Preprocessing = 1;
/* Expand macros in this line */
- xlateline ();
+ PreprocessLine ();
+
+ /* Add two semicolons as sentinels to the line, so the following
+ * expression evaluation will eat these two tokens but nothing from
+ * the following line.
+ */
+ strcat (line, ";;");
/* Prime the token pump (remove old tokens from the stream) */
NextToken ();
NextToken ();
/* Call the expression parser */
- constexpr (&lval);
+ ConstExpr (&lval);
/* End preprocessing mode */
Preprocessing = 0;
NextTok = sv2;
/* Set the #if condition according to the expression result */
- return (setmflag (skip, 1, lval.e_const != 0));
+ return PushIf (Skip, 1, lval.ConstVal != 0);
}
-static int doifdef (int skip, int flag)
+static int DoIfDef (int skip, int flag)
/* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
{
ident Ident;
if (MacName (Ident) == 0) {
return 0;
} else {
- return setmflag (skip, flag, IsMacro(Ident));
+ return PushIf (skip, flag, IsMacro(Ident));
}
}
-static void doinclude (void)
+static void DoInclude (void)
/* Open an include file. */
{
char RTerm;
break;
default:
- PPError (ERR_INCLUDE_LTERM_EXPECTED);
+ PPError ("`\"' or `<' expected");
goto Done;
}
NextChar ();
*/
mptr = mline;
while (CurC != '\0' && CurC != RTerm) {
- *mptr++ = CurC;
+ KeepChar (CurC);
NextChar ();
}
*mptr = '\0';
/* Check if we got a terminator */
if (CurC != RTerm) {
/* No terminator found */
- PPError (ERR_INCLUDE_RTERM_EXPECTED);
+ PPError ("Missing terminator or file name too long");
goto Done;
}
-static void doerror (void)
+static void DoError (void)
/* Print an error */
{
SkipBlank ();
if (CurC == '\0') {
- PPError (ERR_INVALID_USER_ERROR);
+ PPError ("Invalid #error directive");
} else {
- PPError (ERR_USER_ERROR, lptr);
+ PPError ("#error: %s", lptr);
}
- /* clear rest of line */
+ /* Clear the rest of line */
ClearLine ();
}
-/* C preprocessor. */
-
-/* stuff used to bum the keyword dispatching stuff */
-enum {
- PP_DEFINE,
- PP_ELSE,
- PP_ENDIF,
- PP_ERROR,
- PP_IF,
- PP_IFDEF,
- PP_IFNDEF,
- PP_INCLUDE,
- PP_LINE,
- PP_PRAGMA,
- PP_UNDEF,
- PP_ILLEGAL
-};
-
-static const struct tok_elt pre_toks[] = {
- { "define", PP_DEFINE },
- { "else", PP_ELSE },
- { "endif", PP_ENDIF },
- { "error", PP_ERROR },
- { "if", PP_IF },
- { "ifdef", PP_IFDEF },
- { "ifndef", PP_IFNDEF },
- { "include", PP_INCLUDE },
- { "line", PP_LINE },
- { "pragma", PP_PRAGMA },
- { "undef", PP_UNDEF },
- { 0, PP_ILLEGAL }
-};
+static void DoPragma (void)
+/* Handle a #pragma line by converting the #pragma preprocessor directive into
+ * the _Pragma() compiler operator.
+ */
+{
+ /* Skip blanks following the #pragma directive */
+ SkipBlank ();
+ /* Copy the remainder of the line into mline removing comments and ws */
+ Pass1 (lptr, mline);
+ /* Convert the directive into the operator */
+ mptr = line;
+ KeepStr ("_Pragma (");
+ Stringize (mline);
+ KeepChar (')');
+ *mptr = '\0';
-static int searchtok (const char *sym, const struct tok_elt *toks)
-/* Search a token in a table */
-{
- while (toks->toknam && strcmp (toks->toknam, sym))
- ++toks;
- return (toks->toknbr);
+ /* Initialize reading from line */
+ InitLine (line);
}
void Preprocess (void)
/* Preprocess a line */
{
- int Skip;
- ident Directive;
+ int Skip;
+ ident Directive;
/* Skip white space at the beginning of the line */
SkipBlank ();
continue;
}
if (!IsSym (Directive)) {
- PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+ PPError ("Preprocessor directive expected");
ClearLine ();
} else {
- switch (searchtok (Directive, pre_toks)) {
+ switch (FindPPToken (Directive)) {
case PP_DEFINE:
if (!Skip) {
- addmac ();
+ DefineMacro ();
}
break;
+ case PP_ELIF:
+ if (IfIndex >= 0) {
+ if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
+
+ /* Handle as #else/#if combination */
+ if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
+ Skip = !Skip;
+ }
+ IfStack[IfIndex] |= IFCOND_ELSE;
+ Skip = DoIf (Skip);
+
+ /* #elif doesn't need a terminator */
+ IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
+ } else {
+ PPError ("Duplicate #else/#elif");
+ }
+ } else {
+ PPError ("Unexpected #elif");
+ }
+ break;
+
case PP_ELSE:
- if (s_ifdef[i_ifdef] & 2) {
- if (s_ifdef[i_ifdef] & 4) {
- Skip = !Skip;
- }
- s_ifdef[i_ifdef] ^= 2;
+ if (IfIndex >= 0) {
+ if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
+ if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
+ Skip = !Skip;
+ }
+ IfStack[IfIndex] |= IFCOND_ELSE;
+ } else {
+ PPError ("Duplicate #else");
+ }
} else {
- PPError (ERR_UNEXPECTED_CPP_ELSE);
+ PPError ("Unexpected `#else'");
}
break;
case PP_ENDIF:
- if (i_ifdef >= 0) {
- Skip = s_ifdef[i_ifdef--] & 1;
+ if (IfIndex >= 0) {
+ /* Remove any clauses on top of stack that do not
+ * need a terminating #endif.
+ */
+ while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
+ --IfIndex;
+ }
+
+ /* Stack may not be empty here or something is wrong */
+ CHECK (IfIndex >= 0);
+
+ /* Remove the clause that needs a terminator */
+ Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0;
} else {
- PPError (ERR_UNEXPECTED_CPP_ENDIF);
+ PPError ("Unexpected `#endif'");
}
break;
case PP_ERROR:
if (!Skip) {
- doerror ();
+ DoError ();
}
break;
case PP_IF:
- Skip = doiff (Skip);
+ Skip = DoIf (Skip);
break;
case PP_IFDEF:
- Skip = doifdef (Skip, 1);
+ Skip = DoIfDef (Skip, 1);
break;
case PP_IFNDEF:
- Skip = doifdef (Skip, 0);
+ Skip = DoIfDef (Skip, 0);
break;
case PP_INCLUDE:
if (!Skip) {
- doinclude ();
+ DoInclude ();
}
break;
case PP_LINE:
- /* Not allowed in strict ANSI mode */
- if (ANSI) {
- PPError (ERR_CPP_DIRECTIVE_EXPECTED);
- ClearLine ();
- }
- break;
+ /* Not allowed in strict ANSI mode */
+ if (!Skip && ANSI) {
+ PPError ("Preprocessor directive expected");
+ ClearLine ();
+ }
+ break;
case PP_PRAGMA:
- if (!Skip) {
- /* Don't expand macros in this line */
- ExpandMacros = 0;
- /* #pragma is handled on the scanner level */
- goto Done;
- }
+ if (!Skip) {
+ DoPragma ();
+ goto Done;
+ }
break;
case PP_UNDEF:
if (!Skip) {
- doundef ();
+ DoUndef ();
}
break;
default:
- PPError (ERR_CPP_DIRECTIVE_EXPECTED);
+ PPError ("Preprocessor directive expected");
ClearLine ();
}
- }
+ }
}
if (NextLine () == 0) {
- if (i_ifdef >= 0) {
- PPError (ERR_CPP_ENDIF_EXPECTED);
+ if (IfIndex >= 0) {
+ PPError ("`#endif' expected");
}
return;
}
- SkipBlank ();
+ SkipBlank ();
}
+ PreprocessLine ();
+
Done:
- xlateline ();
- if (Verbose > 1) {
- printf ("line: %s\n", line);
- }
+ Print (stdout, 2, "line: %s\n", line);
}