X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fpreproc.c;h=8edeacdd79bb20ab8761b88f402feb3445358986;hb=35e1184901ca38bdb2e56d154ed3b71f6096eacc;hp=5f8aaf0279c70380bd41871cff3a45c67fce6207;hpb=06b57e6e7e9b651b9db5020b8cb53fd315f423e5;p=cc65 diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 5f8aaf027..8edeacdd7 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1,8 +1,37 @@ -/* - * C pre-processor functions. - * Small portions of this code are copyright (C) 1989 John R. Dunning. - * See copyleft.jrd for license information. - */ +/*****************************************************************************/ +/* */ +/* preproc.c */ +/* */ +/* cc65 preprocessor */ +/* */ +/* */ +/* */ +/* (C) 1998-2010, Ullrich von Bassewitz */ +/* Roemerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + #include #include @@ -99,7 +128,8 @@ typedef enum { PP_INCLUDE, PP_LINE, PP_PRAGMA, - PP_UNDEF + PP_UNDEF, + PP_WARNING, } pptoken_t; @@ -121,6 +151,7 @@ static const struct PPToken { { "line", PP_LINE }, { "pragma", PP_PRAGMA }, { "undef", PP_UNDEF }, + { "warning", PP_WARNING }, }; /* Number of preprocessor tokens */ @@ -158,7 +189,7 @@ static MacroExp* InitMacroExp (MacroExp* E, Macro* M) /* Initialize a MacroExp structure */ { InitCollection (&E->ActualArgs); - InitStrBuf (&E->Replacement); + SB_Init (&E->Replacement); E->M = M; return E; } @@ -175,7 +206,7 @@ static void DoneMacroExp (MacroExp* E) FreeStrBuf (CollAtUnchecked (&E->ActualArgs, I)); } DoneCollection (&E->ActualArgs); - DoneStrBuf (&E->Replacement); + SB_Done (&E->Replacement); } @@ -205,6 +236,15 @@ static StrBuf* ME_GetActual (MacroExp* E, unsigned Index) +static int ME_ArgIsVariadic (const MacroExp* E) +/* Return true if the next actual argument we will add is a variadic one */ +{ + return (E->M->Variadic && + E->M->ArgCount == (int) CollCount (&E->ActualArgs) + 1); +} + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ @@ -295,12 +335,31 @@ static void NewStyleComment (void) -static void SkipWhitespace (void) -/* Skip white space in the input stream. */ +static int SkipWhitespace (int SkipLines) +/* Skip white space in the input stream. Do also skip newlines if SkipLines + * is true. Return zero if nothing was skipped, otherwise return a + * value != zero. + */ { - while (IsSpace (CurC)) { - NextChar (); + int Skipped = 0; + while (1) { + if (IsSpace (CurC)) { + NextChar (); + Skipped = 1; + } else if (CurC == '\0' && SkipLines) { + /* End of line, read next */ + if (NextLine () != 0) { + Skipped = 1; + } else { + /* End of input */ + break; + } + } else { + /* No more white space */ + break; + } } + return Skipped; } @@ -362,21 +421,37 @@ static void ReadMacroArgs (MacroExp* E) unsigned Parens; /* Number of open parenthesis */ StrBuf Arg = STATIC_STRBUF_INITIALIZER; - /* Read the actual macro arguments and store pointers to these arguments - * into the array of actual arguments in the macro definition. - */ - Parens = 0; + /* Read the actual macro arguments */ + Parens = 0; while (1) { if (CurC == '(') { + /* Nested parenthesis */ SB_AppendChar (&Arg, CurC); NextChar (); ++Parens; + } else if (IsQuote (CurC)) { + + /* Quoted string - just copy */ CopyQuotedString (&Arg); + } else if (CurC == ',' || CurC == ')') { - if (Parens == 0) { + if (Parens) { + /* Comma or right paren inside nested parenthesis */ + if (CurC == ')') { + --Parens; + } + SB_AppendChar (&Arg, CurC); + NextChar (); + } else if (CurC == ',' && ME_ArgIsVariadic (E)) { + /* It's a comma, but we're inside a variadic macro argument, so + * just copy it and proceed. + */ + SB_AppendChar (&Arg, CurC); + NextChar (); + } else { /* End of actual argument. Remove whitespace from the end. */ while (IsSpace (SB_LookAtLast (&Arg))) { SB_Drop (&Arg, 1); @@ -390,7 +465,7 @@ static void ReadMacroArgs (MacroExp* E) } /* Check for end of macro param list */ - if (CurC == ')') { + if (CurC == ')') { NextChar (); break; } @@ -398,20 +473,12 @@ static void ReadMacroArgs (MacroExp* E) /* Start the next param */ NextChar (); SB_Clear (&Arg); - } else { - /* Comma or right paren inside nested parenthesis */ - if (CurC == ')') { - --Parens; - } - SB_AppendChar (&Arg, CurC); - NextChar (); } - } else if (IsSpace (CurC)) { + } else if (SkipWhitespace (1)) { /* Squeeze runs of blanks within an arg */ if (SB_NotEmpty (&Arg)) { SB_AppendChar (&Arg, ' '); } - SkipWhitespace (); } else if (CurC == '/' && NextC == '*') { if (SB_NotEmpty (&Arg)) { SB_AppendChar (&Arg, ' '); @@ -423,14 +490,11 @@ static void ReadMacroArgs (MacroExp* E) } NewStyleComment (); } else if (CurC == '\0') { - /* End of line inside macro argument list - read next line */ - if (SB_NotEmpty (&Arg)) { - SB_AppendChar (&Arg, ' '); - } - if (NextLine () == 0) { - ClearLine (); - break; - } + /* End of input inside macro argument list */ + PPError ("Unterminated argument list invoking macro `%s'", E->M->Name); + + ClearLine (); + break; } else { /* Just copy the character */ SB_AppendChar (&Arg, CurC); @@ -439,7 +503,7 @@ static void ReadMacroArgs (MacroExp* E) } /* Deallocate string buf resources */ - DoneStrBuf (&Arg); + SB_Done (&Arg); } @@ -455,6 +519,7 @@ static void MacroArgSubst (MacroExp* E) /* Remember the current input and switch to the macro replacement. */ + int OldIndex = SB_GetIndex (&E->M->Replacement); SB_Reset (&E->M->Replacement); OldSource = InitLine (&E->M->Replacement); @@ -471,10 +536,7 @@ static void MacroArgSubst (MacroExp* E) Arg = ME_GetActual (E, ArgIdx); /* Copy any following whitespace */ - HaveSpace = IsSpace (CurC); - if (HaveSpace) { - SkipWhitespace (); - } + HaveSpace = SkipWhitespace (0); /* If a ## operator follows, we have to insert the actual * argument as is, otherwise it must be macro replaced. @@ -511,7 +573,7 @@ static void MacroArgSubst (MacroExp* E) /* ## operator. */ NextChar (); NextChar (); - SkipWhitespace (); + SkipWhitespace (0); /* Since we need to concatenate the token sequences, remove * any whitespace that was added to target, since it must come @@ -547,9 +609,8 @@ static void MacroArgSubst (MacroExp* E) * macro parameter. */ NextChar (); - SkipWhitespace (); + SkipWhitespace (0); if (!IsSym (Ident) || (ArgIdx = FindMacroArg (E->M, Ident)) < 0) { - printf ("<%.*s>\n", SB_GetLen (Line), SB_GetConstBuf (Line)); PPError ("`#' is not followed by a macro parameter"); } else { /* Make a valid string from Replacement */ @@ -575,6 +636,7 @@ static void MacroArgSubst (MacroExp* E) /* Switch back the input */ InitLine (OldSource); + SB_SetIndex (&E->M->Replacement, OldIndex); } @@ -595,9 +657,13 @@ static void MacroCall (StrBuf* Target, Macro* M) /* Compare formal and actual argument count */ if (CollCount (&E.ActualArgs) != (unsigned) M->ArgCount) { + + StrBuf Arg = STATIC_STRBUF_INITIALIZER; + + /* Argument count mismatch */ PPError ("Macro argument count mismatch"); + /* Be sure to make enough empty arguments available */ - StrBuf Arg = STATIC_STRBUF_INITIALIZER; while (CollCount (&E.ActualArgs) < (unsigned) M->ArgCount) { ME_AppendActual (&E, &Arg); } @@ -622,14 +688,15 @@ static void MacroCall (StrBuf* Target, Macro* M) static void ExpandMacro (StrBuf* Target, Macro* M) /* Expand a macro into Target */ { +#if 0 + static unsigned V = 0; + printf ("Expanding %s(%u)\n", M->Name, ++V); +#endif + /* Check if this is a function like macro */ - //printf ("Expanding %s(%u)\n", M->Name, ++V); if (M->ArgCount >= 0) { - int Whitespace = IsSpace (CurC); - if (Whitespace) { - SkipWhitespace (); - } + int Whitespace = SkipWhitespace (1); if (CurC != '(') { /* Function like macro but no parameter list */ SB_AppendStr (Target, M->Name); @@ -660,7 +727,9 @@ static void ExpandMacro (StrBuf* Target, Macro* M) DoneMacroExp (&E); } - //printf ("Done with %s(%u)\n", M->Name, V--); +#if 0 + printf ("Done with %s(%u)\n", M->Name, V--); +#endif } @@ -671,13 +740,17 @@ static void DefineMacro (void) ident Ident; Macro* M; Macro* Existing; + int C89; /* Read the macro name */ - SkipWhitespace (); + SkipWhitespace (0); if (!MacName (Ident)) { return; } + /* Remember if we're in C89 mode */ + C89 = (IS_Get (&Standard) == STD_C89); + /* Get an existing macro definition with this name */ Existing = FindMacro (Ident); @@ -695,17 +768,55 @@ static void DefineMacro (void) /* Read the formal parameter list */ while (1) { - SkipWhitespace (); + + /* Skip white space and check for end of parameter list */ + SkipWhitespace (0); if (CurC == ')') { break; } - if (MacName (Ident) == 0) { - return; - } - AddMacroArg (M, Ident); - SkipWhitespace (); - if (CurC != ',') { - break; + + /* The next token must be either an identifier, or - if not in + * C89 mode - the ellipsis. + */ + if (!C89 && CurC == '.') { + /* Ellipsis */ + NextChar (); + if (CurC != '.' || NextC != '.') { + PPError ("`...' expected"); + ClearLine (); + return; + } + NextChar (); + NextChar (); + + /* Remember that the macro is variadic and use __VA_ARGS__ as + * the argument name. + */ + AddMacroArg (M, "__VA_ARGS__"); + M->Variadic = 1; + + } else { + /* Must be macro argument name */ + if (MacName (Ident) == 0) { + return; + } + + /* __VA_ARGS__ is only allowed in C89 mode */ + if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) { + PPWarning ("`__VA_ARGS__' can only appear in the expansion " + "of a C99 variadic macro"); + } + + /* Add the macro argument */ + AddMacroArg (M, Ident); + } + + /* If we had an ellipsis, or the next char is not a comma, we've + * reached the end of the macro argument list. + */ + SkipWhitespace (0); + if (M->Variadic || CurC != ',') { + break; } NextChar (); } @@ -720,7 +831,7 @@ static void DefineMacro (void) } /* Skip whitespace before the macro replacement */ - SkipWhitespace (); + SkipWhitespace (0); /* Insert the macro into the macro table and allocate the ActualArgs array */ InsertMacro (M); @@ -734,8 +845,9 @@ static void DefineMacro (void) while (IsSpace (SB_LookAtLast (&M->Replacement))) { SB_Drop (&M->Replacement, 1); } - - //printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement)); +#if 0 + printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement)); +#endif /* If we have an existing macro, check if the redefinition is identical. * Print a diagnostic if not. @@ -768,26 +880,25 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target) /* Loop removing ws and comments */ IdentCount = 0; while (CurC != '\0') { - if (IsSpace (CurC)) { + if (SkipWhitespace (0)) { /* Squeeze runs of blanks */ if (!IsSpace (SB_LookAtLast (Target))) { SB_AppendChar (Target, ' '); } - SkipWhitespace (); } else if (IsSym (Ident)) { if (Preprocessing && strcmp (Ident, "defined") == 0) { /* Handle the "defined" operator */ - SkipWhitespace (); + SkipWhitespace (0); HaveParen = 0; if (CurC == '(') { HaveParen = 1; NextChar (); - SkipWhitespace (); + SkipWhitespace (0); } if (IsSym (Ident)) { SB_AppendChar (Target, IsMacro (Ident)? '1' : '0'); if (HaveParen) { - SkipWhitespace (); + SkipWhitespace (0); if (CurC != ')') { PPError ("`)' expected"); } else { @@ -890,19 +1001,6 @@ static void PreprocessLine (void) -static void DoUndef (void) -/* Process the #undef directive */ -{ - ident Ident; - - SkipWhitespace (); - if (MacName (Ident)) { - UndefineMacro (Ident); - } -} - - - static int PushIf (int Skip, int Invert, int Cond) /* Push a new if level onto the if stack */ { @@ -925,6 +1023,22 @@ static int PushIf (int Skip, int Invert, int Cond) +static void DoError (void) +/* Print an error */ +{ + SkipWhitespace (0); + if (CurC == '\0') { + PPError ("Invalid #error directive"); + } else { + PPError ("#error: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line)); + } + + /* Clear the rest of line */ + ClearLine (); +} + + + static int DoIf (int Skip) /* Process #if directive */ { @@ -946,20 +1060,6 @@ static int DoIf (int Skip) UseLineInfo (SavedNextTok.LI); } -#if 0 - /* Remove the #if from the line */ - SkipWhitespace (); - S = line; - while (CurC != '\0') { - *S++ = CurC; - NextChar (); - } - *S = '\0'; - - /* Start over parsing from line */ - InitLine (line); -#endif - /* Switch into special preprocessing mode */ Preprocessing = 1; @@ -971,6 +1071,7 @@ static int DoIf (int Skip) * the following line. */ SB_AppendStr (Line, ";;"); + SB_Terminate (Line); /* Load CurTok and NextTok with tokens from the new input */ NextToken (); @@ -997,7 +1098,7 @@ static int DoIfDef (int skip, int flag) { ident Ident; - SkipWhitespace (); + SkipWhitespace (0); if (MacName (Ident) == 0) { return 0; } else { @@ -1011,12 +1112,15 @@ static void DoInclude (void) /* Open an include file. */ { char RTerm; - unsigned DirSpec; + InputType IT; StrBuf Filename = STATIC_STRBUF_INITIALIZER; + /* Preprocess the remainder of the line */ + PreprocessLine (); + /* Skip blanks */ - SkipWhitespace (); + SkipWhitespace (0); /* Get the next char and check for a valid file name terminator. Setup * the include directory spec (SYS/USR) by looking at the terminator. @@ -1025,12 +1129,12 @@ static void DoInclude (void) case '\"': RTerm = '\"'; - DirSpec = INC_USER; + IT = IT_USRINC; break; case '<': RTerm = '>'; - DirSpec = INC_SYS; + IT = IT_SYSINC; break; default: @@ -1047,18 +1151,17 @@ static void DoInclude (void) SB_Terminate (&Filename); /* Check if we got a terminator */ - if (CurC != RTerm) { + if (CurC == RTerm) { + /* Open the include file */ + OpenIncludeFile (SB_GetConstBuf (&Filename), IT); + } else if (CurC == '\0') { /* No terminator found */ - PPError ("Missing terminator or file name too long"); - goto Done; + PPError ("#include expects \"FILENAME\" or "); } - /* Open the include file */ - OpenIncludeFile (SB_GetConstBuf (&Filename), DirSpec); - Done: /* Free the allocated filename data */ - DoneStrBuf (&Filename); + SB_Done (&Filename); /* Clear the remaining line so the next input will come from the new * file (if open) @@ -1068,29 +1171,13 @@ Done: -static void DoError (void) -/* Print an error */ -{ - SkipWhitespace (); - if (CurC == '\0') { - PPError ("Invalid #error directive"); - } else { - PPError ("#error: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line)); - } - - /* Clear the rest of line */ - ClearLine (); -} - - - 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 */ - SkipWhitespace (); + SkipWhitespace (0); /* Copy the remainder of the line into MLine removing comments and ws */ SB_Clear (MLine); @@ -1109,6 +1196,35 @@ static void DoPragma (void) +static void DoUndef (void) +/* Process the #undef directive */ +{ + ident Ident; + + SkipWhitespace (0); + if (MacName (Ident)) { + UndefineMacro (Ident); + } +} + + + +static void DoWarning (void) +/* Print a warning */ +{ + SkipWhitespace (0); + if (CurC == '\0') { + PPError ("Invalid #warning directive"); + } else { + PPWarning ("#warning: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line)); + } + + /* Clear the rest of line */ + ClearLine (); +} + + + void Preprocess (void) /* Preprocess a line */ { @@ -1121,7 +1237,7 @@ void Preprocess (void) } /* Skip white space at the beginning of the line */ - SkipWhitespace (); + SkipWhitespace (0); /* Check for stuff to skip */ Skip = 0; @@ -1130,7 +1246,7 @@ void Preprocess (void) /* Check for preprocessor lines lines */ if (CurC == '#') { NextChar (); - SkipWhitespace (); + SkipWhitespace (0); if (CurC == '\0') { /* Ignore the empty preprocessor directive */ continue; @@ -1246,8 +1362,24 @@ void Preprocess (void) } break; + case PP_WARNING: + /* #warning is a non standard extension */ + if (IS_Get (&Standard) > STD_C99) { + if (!Skip) { + DoWarning (); + } + } else { + if (!Skip) { + PPError ("Preprocessor directive expected"); + } + ClearLine (); + } + break; + default: - PPError ("Preprocessor directive expected"); + if (!Skip) { + PPError ("Preprocessor directive expected"); + } ClearLine (); } } @@ -1259,7 +1391,7 @@ void Preprocess (void) } return; } - SkipWhitespace (); + SkipWhitespace (0); } PreprocessLine (); @@ -1267,7 +1399,7 @@ void Preprocess (void) Done: if (Verbosity > 1 && SB_NotEmpty (Line)) { printf ("%s(%u): %.*s\n", GetCurrentFile (), GetCurrentLine (), - SB_GetLen (Line), SB_GetConstBuf (Line)); + (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } }