X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Fpreproc.c;h=1b13018bc3a623e5cf4fde505edb38df5f4f8f53;hb=9b7c16ec4cbb5282642c377272224e3fc825f860;hp=5c0b9b83f62132495e1e2452fcc978f0133d3a4c;hpb=1b3e3633b98f57e53af718f2b5a28eec79078c39;p=cc65 diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 5c0b9b83f..1b13018bc 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-2009, 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 */ /*****************************************************************************/ @@ -362,21 +402,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 +446,7 @@ static void ReadMacroArgs (MacroExp* E) } /* Check for end of macro param list */ - if (CurC == ')') { + if (CurC == ')') { NextChar (); break; } @@ -398,13 +454,6 @@ 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)) { /* Squeeze runs of blanks within an arg */ @@ -439,7 +488,7 @@ static void ReadMacroArgs (MacroExp* E) } /* Deallocate string buf resources */ - DoneStrBuf (&Arg); + SB_Done (&Arg); } @@ -455,6 +504,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); @@ -549,7 +599,6 @@ static void MacroArgSubst (MacroExp* E) NextChar (); SkipWhitespace (); 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 +624,7 @@ static void MacroArgSubst (MacroExp* E) /* Switch back the input */ InitLine (OldSource); + SB_SetIndex (&E->M->Replacement, OldIndex); } @@ -626,8 +676,12 @@ 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); @@ -664,7 +718,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 } @@ -675,6 +731,7 @@ static void DefineMacro (void) ident Ident; Macro* M; Macro* Existing; + int C89; /* Read the macro name */ SkipWhitespace (); @@ -682,6 +739,9 @@ static void DefineMacro (void) 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); @@ -699,17 +759,55 @@ static void DefineMacro (void) /* Read the formal parameter list */ while (1) { + + /* Skip white space and check for end of parameter list */ SkipWhitespace (); if (CurC == ')') { break; } - if (MacName (Ident) == 0) { - return; - } - AddMacroArg (M, Ident); + + /* 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 (); - if (CurC != ',') { - break; + if (M->Variadic || CurC != ',') { + break; } NextChar (); } @@ -738,8 +836,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. @@ -894,19 +993,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 */ { @@ -929,6 +1015,22 @@ static int PushIf (int Skip, int Invert, int Cond) +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 int DoIf (int Skip) /* Process #if directive */ { @@ -950,20 +1052,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; @@ -975,6 +1063,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 (); @@ -1019,6 +1108,9 @@ static void DoInclude (void) StrBuf Filename = STATIC_STRBUF_INITIALIZER; + /* Preprocess the remainder of the line */ + PreprocessLine (); + /* Skip blanks */ SkipWhitespace (); @@ -1051,18 +1143,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), DirSpec); + } 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) @@ -1072,22 +1163,6 @@ 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. @@ -1113,6 +1188,35 @@ static void DoPragma (void) +static void DoUndef (void) +/* Process the #undef directive */ +{ + ident Ident; + + SkipWhitespace (); + if (MacName (Ident)) { + UndefineMacro (Ident); + } +} + + + +static void DoWarning (void) +/* Print a warning */ +{ + SkipWhitespace (); + 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 */ { @@ -1250,6 +1354,18 @@ void Preprocess (void) } break; + case PP_WARNING: + /* #warning is a non standard extension */ + if (IS_Get (&Standard) > STD_C99) { + if (!Skip) { + DoWarning (); + } + } else { + PPError ("Preprocessor directive expected"); + ClearLine (); + } + break; + default: PPError ("Preprocessor directive expected"); ClearLine (); @@ -1271,7 +1387,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)); } }