-/*
- * 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-2005, Ullrich von Bassewitz */
+/* Römerstraße 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 <stdio.h>
#include <string.h>
+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 */
/*****************************************************************************/
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);
/* 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 */
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 */
/* 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);
}
static void ExpandMacro (StrBuf* Target, Macro* M)
/* Expand a macro into Target */
{
+ /* ### printf ("Expanding %s(%u)\n", M->Name, ++V); */
+
/* Check if this is a function like macro */
- //printf ("Expanding %s(%u)\n", M->Name, ++V);
if (M->ArgCount >= 0) {
int Whitespace = IsSpace (CurC);
DoneMacroExp (&E);
}
- //printf ("Done with %s(%u)\n", M->Name, V--);
+ /* ### printf ("Done with %s(%u)\n", M->Name, V--); */
}
ident Ident;
Macro* M;
Macro* Existing;
+ int C89;
/* Read the macro name */
SkipWhitespace ();
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);
/* 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 ();
}
SB_Drop (&M->Replacement, 1);
}
- //printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
+ /* ### printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement)); */
/* If we have an existing macro, check if the redefinition is identical.
* Print a diagnostic if not.
* the following line.
*/
SB_AppendStr (Line, ";;");
+ SB_Terminate (Line);
/* Load CurTok and NextTok with tokens from the new input */
NextToken ();