diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 35a9119c7..855d59844 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -67,6 +67,17 @@ +/* Macro scanner mode flags */ +#define MSM_NONE 0x00U /* Default */ +#define MSM_MULTILINE 0x01U /* Read from multiple lines */ +#define MSM_IN_DIRECTIVE 0x02U /* In PP directives scan */ +#define MSM_IN_ARG_LIST 0x04U /* In macro argument scan */ +#define MSM_IN_ARG_EXPANSION 0x08U /* In expansion on arguments */ +#define MSM_OP_DEFINED 0x10U /* Handle the defined operator */ +#define MSM_OP_HAS_INCLUDE 0x20U /* Handle the __has_include operator */ +#define MSM_OP_HAS_C_ATTRIBUTE 0x40U /* Handle the __has_c_attribute operator */ +#define MSM_TOK_HEADER 0x80U /* Support header tokens */ + /* Management data for #if */ #define IFCOND_NONE 0x00U #define IFCOND_SKIP 0x01U @@ -105,13 +116,16 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target); ** non-newline whitespace sequences. */ -static int ParseDirectives (int InArgList); -/* Handle directives. Return 1 if there are directives parsed, -1 if new lines -** are read, otherwise 0. +static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); +/* Preprocess a single line. Handle specified tokens and operators, remove +** whitespace and comments, then do macro replacement. */ -static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine); -/* Perform macro replacement. */ +static int ParseDirectives (unsigned ModeFlags); +/* Handle directives. Return 1 if any whitespace or newlines are parsed. */ + +static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); +/* Scan for and perform macro replacement */ @@ -545,7 +559,7 @@ static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) Newlines += PendingNewLines - OldPendingNewLines; PendingNewLines = OldPendingNewLines; OldPendingNewLines = 0; - Skipped = ParseDirectives (1) || Skipped; + Skipped = ParseDirectives (MSM_IN_ARG_LIST) || Skipped; Skipped = SkipWhitespace (MultiLine) || Skipped; } PendingNewLines += Newlines; @@ -809,122 +823,89 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine) -/*****************************************************************************/ -/* Preprocessing */ -/*****************************************************************************/ - - - -static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) -/* Mimic Translation Phase 3. Handle old and new style comments. Collapse -** non-newline whitespace sequences. -*/ +static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags) +/* Scan for and perform macro replacement */ { - /* Switch to the new input source */ - StrBuf* OldSource = InitLine (Source); - - /* Loop removing ws and comments */ - while (CurC != '\0') { - int HasWhiteSpace = 0; - while (1) { - /* Squeeze runs of blanks */ - if (IsSpace (CurC)) { - NextChar (); - HasWhiteSpace = 1; - } else if (CurC == '/' && NextC == '*') { - OldStyleComment (); - HasWhiteSpace = 1; - } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { - NewStyleComment (); - HasWhiteSpace = 1; - } else { - /* No more white space */ - break; - } - } - if (HasWhiteSpace) { - SB_AppendChar (Target, ' '); - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); - } else { - SB_AppendChar (Target, CurC); - NextChar (); - } - } - - /* Terminate the new input line */ - SB_Terminate (Target); - - /* Switch back to the old source */ - InitLine (OldSource); -} - - - -static void ProcessSingleLine (StrBuf* Source, - StrBuf* Target, - int HandleDefined, - int HandleHeader) -/* Process a single line. Remove whitespace, old and new style comments. -** Recognize and handle the "defined" operator if HandleDefined is true. -** Recognize and handle header name tokens if HandleHeader is true. -*/ -{ - int OldIndex = SB_GetIndex (Source); ident Ident; - int HaveParen; - /* Operate on the new input source */ + /* Remember the current input and switch to Source */ StrBuf* OldSource = InitLine (Source); - SkipWhitespace (0); - - /* Loop removing ws and comments */ + /* Loop substituting macros */ while (CurC != '\0') { - if (SkipWhitespace (0)) { - /* Squeeze runs of blanks */ - if (!IsSpace (SB_LookAtLast (Target))) { - SB_AppendChar (Target, ' '); - } - } else if (IsSym (Ident)) { - if (HandleDefined && strcmp (Ident, "defined") == 0) { + /* If we have an identifier, check if it's a macro */ + if (IsSym (Ident)) { + if ((ModeFlags & MSM_OP_DEFINED) != 0 && strcmp (Ident, "defined") == 0) { /* Handle the "defined" operator */ + int HaveParen = 0; + SkipWhitespace (0); - HaveParen = 0; if (CurC == '(') { HaveParen = 1; NextChar (); SkipWhitespace (0); } if (IsSym (Ident)) { - SB_AppendChar (Target, IsMacro (Ident)? '1' : '0'); + /* Eat the identifier */ + SB_AppendChar (Target, IsMacro (Ident) ? '1' : '0'); if (HaveParen) { SkipWhitespace (0); if (CurC != ')') { PPError ("')' expected"); + ClearLine (); } else { NextChar (); } } } else { - PPError ("Identifier expected"); + PPError ("Macro name must be an identifier"); + ClearLine (); SB_AppendChar (Target, '0'); } } else { + /* Check if it's an expandable macro */ Macro* M = FindMacro (Ident); if (M != 0 && !M->Expanding) { /* Check if this is a function-like macro */ if (M->ArgCount >= 0) { - int Whitespace = SkipWhitespace (0); + int MultiLine = (ModeFlags & MSM_MULTILINE) != 0; + int Whitespace = SkipWhitespace (MultiLine); if (CurC != '(') { /* Function-like macro without an argument list is not replaced */ SB_AppendStr (Target, M->Name); - if (Whitespace) { + if (Whitespace > 0) { SB_AppendChar (Target, ' '); } + + /* Directives can only be found in an argument list + ** that spans multiple lines. + */ + if (MultiLine) { + if (CurC == '#') { + /* If we were going to support #pragma in + ** macro argument list, it would be output + ** to OLine. + */ + if (OLine == 0) { + OLine = Target; + ParseDirectives (ModeFlags); + OLine = 0; + } else { + ParseDirectives (ModeFlags); + } + } + /* Add the source info to preprocessor output if needed */ + AddPreLine (Target); + } } else { /* Function-like macro */ - ExpandMacro (Target, M, 0); + if (OLine == 0) { + OLine = Target; + ExpandMacro (Target, M, MultiLine); + OLine = 0; + } else { + ExpandMacro (Target, M, MultiLine); + } } } else { /* Object-like macro */ @@ -935,97 +916,19 @@ static void ProcessSingleLine (StrBuf* Source, SB_AppendStr (Target, Ident); } } - } else if (HandleHeader && (CurC == '<' || CurC == '\"')) { - CopyHeaderNameToken (Target); - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); } else { - SB_AppendChar (Target, CurC); - NextChar (); - } - } - - /* Switch back to the old source */ - InitLine (OldSource); - - /* Restore the source input index */ - SB_SetIndex (Source, OldIndex); -} - - - -static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine) -/* Perform macro replacement. */ -{ - ident Ident; - Macro* M; - - /* Remember the current input and switch to Source */ - StrBuf* OldSource = InitLine (Source); - - /* Loop substituting macros */ - while (CurC != '\0') { - /* If we have an identifier, check if it's a macro */ - if (IsSym (Ident)) { - /* Check if it's a macro */ - if ((M = FindMacro (Ident)) != 0 && !M->Expanding) { - /* Check if this is a function-like macro */ - if (M->ArgCount >= 0) { - int Whitespace = SkipWhitespace (MultiLine); - if (CurC != '(') { - /* Function-like macro without an argument list is not replaced */ - SB_AppendStr (Target, M->Name); - if (Whitespace > 0) { - SB_AppendChar (Target, ' '); - } - - /* Directives can only be found in an argument list - ** that spans multiple lines. - */ - if (MultiLine) { - if (CurC == '#') { - /* If we were going to support #pragma in - ** macro argument list, it would be output - ** to OLine. - */ - if (OLine == 0) { - OLine = Target; - ParseDirectives (0); - OLine = 0; - } else { - ParseDirectives (0); - } - } - /* Add the source info to preprocessor output if needed */ - AddPreLine (Target); - } - } else { - /* Function-like macro */ - if (OLine == 0) { - OLine = Target; - ExpandMacro (Target, M, MultiLine); - OLine = 0; - } else { - ExpandMacro (Target, M, MultiLine); - } - } + if ((ModeFlags & MSM_TOK_HEADER) != 0 && (CurC == '<' || CurC == '\"')) { + CopyHeaderNameToken (Target); + } else if (IsQuote (CurC)) { + CopyQuotedString (Target); + } else { + int Whitespace = SkipWhitespace (0); + if (Whitespace) { + SB_AppendChar (Target, ' '); } else { - /* Object-like macro */ - ExpandMacro (Target, M, 0); + SB_AppendChar (Target, CurC); + NextChar (); } - } else { - /* An identifier, keep it */ - SB_AppendStr (Target, Ident); - } - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); - } else { - int Whitespace = SkipWhitespace (0); - if (Whitespace) { - SB_AppendChar (Target, ' '); - } else { - SB_AppendChar (Target, CurC); - NextChar (); } } } @@ -1260,7 +1163,7 @@ static int DoIf (int Skip) /* Macro-replace a single line with support for the "defined" operator */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 1, 0); + PreprocessDirective (Line, MLine, MSM_OP_DEFINED); /* Read from the processed line */ SB_Reset (MLine); @@ -1324,7 +1227,7 @@ static void DoInclude (void) /* Macro-replace a single line with special support for */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 0, 1); + PreprocessDirective (Line, MLine, MSM_TOK_HEADER); /* Read from the processed line */ SB_Reset (MLine); @@ -1400,7 +1303,7 @@ static void DoPragma (void) /* Macro-replace a single line */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 0, 0); + PreprocessDirective (Line, MLine, MSM_NONE); /* Convert #pragma to _Pragma () */ SB_AppendStr (PragmaLine, "_Pragma ("); @@ -1448,7 +1351,7 @@ static void DoWarning (void) -static int ParseDirectives (int InArgList) +static int ParseDirectives (unsigned ModeFlags) /* Handle directives. Return 1 if any whitespace or newlines are parsed. */ { int PPSkip = 0; @@ -1576,7 +1479,7 @@ static int ParseDirectives (int InArgList) case PPD_PRAGMA: if (!PPSkip) { - if (!InArgList) { + if ((ModeFlags & MSM_IN_ARG_LIST) == 0) { DoPragma (); } else { PPError ("Embedded #pragma directive within macro arguments is unsupported"); @@ -1626,11 +1529,76 @@ static int ParseDirectives (int InArgList) /*****************************************************************************/ -/* Preprocessor */ +/* Preprocessing */ /*****************************************************************************/ +static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) +/* Mimic Translation Phase 3. Handle old and new style comments. Collapse +** non-newline whitespace sequences. +*/ +{ + /* Switch to the new input source */ + StrBuf* OldSource = InitLine (Source); + + /* Loop removing ws and comments */ + while (CurC != '\0') { + int HasWhiteSpace = 0; + while (1) { + /* Squeeze runs of blanks */ + if (IsSpace (CurC)) { + NextChar (); + HasWhiteSpace = 1; + } else if (CurC == '/' && NextC == '*') { + OldStyleComment (); + HasWhiteSpace = 1; + } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { + NewStyleComment (); + HasWhiteSpace = 1; + } else { + /* No more white space */ + break; + } + } + if (HasWhiteSpace) { + SB_AppendChar (Target, ' '); + } else if (IsQuote (CurC)) { + CopyQuotedString (Target); + } else { + SB_AppendChar (Target, CurC); + NextChar (); + } + } + + /* Terminate the new input line */ + SB_Terminate (Target); + + /* Switch back to the old source */ + InitLine (OldSource); +} + + + +static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags) +/* Preprocess a single line. Handle specified tokens and operators, remove +** whitespace and comments, then do macro replacement. +*/ +{ + int OldIndex = SB_GetIndex (Source); + MacroExp E; + + SkipWhitespace (0); + InitMacroExp (&E); + MacroReplacement (Source, Target, ModeFlags | MSM_IN_DIRECTIVE); + DoneMacroExp (&E); + + /* Restore the source input index */ + SB_SetIndex (Source, OldIndex); +} + + + void Preprocess (void) /* Preprocess lines count of which is affected by directives */ { @@ -1641,7 +1609,7 @@ void Preprocess (void) /* Parse any directives */ OLine = PLine; - ParseDirectives (0); + ParseDirectives (MSM_MULTILINE); OLine = 0; /* Add the source info to preprocessor output if needed */ @@ -1651,7 +1619,7 @@ void Preprocess (void) AppendIndent (PLine, SB_GetIndex (Line)); /* Expand macros if any */ - MacroReplacement (Line, PLine, 1); + MacroReplacement (Line, PLine, MSM_MULTILINE); /* Add the source info to preprocessor output if needed */ AddPreLine (PLine);