1 /*****************************************************************************/
5 /* cc65 preprocessor */
9 /* (C) 1998-2010, Ullrich von Bassewitz */
10 /* Roemerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
64 /*****************************************************************************/
66 /*****************************************************************************/
70 /* Set when the preprocessor calls expr() recursively */
71 unsigned char Preprocessing = 0;
73 /* Management data for #if */
75 #define IFCOND_NONE 0x00U
76 #define IFCOND_SKIP 0x01U
77 #define IFCOND_ELSE 0x02U
78 #define IFCOND_NEEDTERM 0x04U
79 static unsigned char IfStack[MAX_IFS];
80 static int IfIndex = -1;
82 /* Buffer for macro expansion */
85 /* Structure used when expanding macros */
86 typedef struct MacroExp MacroExp;
88 Collection ActualArgs; /* Actual arguments */
89 StrBuf Replacement; /* Replacement with arguments substituted */
90 Macro* M; /* The macro we're handling */
95 /*****************************************************************************/
97 /*****************************************************************************/
101 static unsigned Pass1 (StrBuf* Source, StrBuf* Target);
102 /* Preprocessor pass 1. Remove whitespace. Handle old and new style comments
103 * and the "defined" operator.
106 static void MacroReplacement (StrBuf* Source, StrBuf* Target);
107 /* Perform macro replacement. */
111 /*****************************************************************************/
112 /* Low level preprocessor token handling */
113 /*****************************************************************************/
117 /* Types of preprocessor tokens */
137 /* Preprocessor keyword to token mapping table */
138 static const struct PPToken {
139 const char* Key; /* Keyword */
140 pptoken_t Tok; /* Token */
142 { "define", PP_DEFINE },
145 { "endif", PP_ENDIF },
146 { "error", PP_ERROR },
148 { "ifdef", PP_IFDEF },
149 { "ifndef", PP_IFNDEF },
150 { "include", PP_INCLUDE },
152 { "pragma", PP_PRAGMA },
153 { "undef", PP_UNDEF },
154 { "warning", PP_WARNING },
157 /* Number of preprocessor tokens */
158 #define PPTOKEN_COUNT (sizeof(PPTokens) / sizeof(PPTokens[0]))
162 static int CmpToken (const void* Key, const void* Elem)
163 /* Compare function for bsearch */
165 return strcmp ((const char*) Key, ((const struct PPToken*) Elem)->Key);
170 static pptoken_t FindPPToken (const char* Ident)
171 /* Find a preprocessor token and return it. Return PP_ILLEGAL if the identifier
172 * is not a valid preprocessor token.
176 P = bsearch (Ident, PPTokens, PPTOKEN_COUNT, sizeof (PPTokens[0]), CmpToken);
177 return P? P->Tok : PP_ILLEGAL;
182 /*****************************************************************************/
183 /* struct MacroExp */
184 /*****************************************************************************/
188 static MacroExp* InitMacroExp (MacroExp* E, Macro* M)
189 /* Initialize a MacroExp structure */
191 InitCollection (&E->ActualArgs);
192 SB_Init (&E->Replacement);
199 static void DoneMacroExp (MacroExp* E)
200 /* Cleanup after use of a MacroExp structure */
204 /* Delete the list with actual arguments */
205 for (I = 0; I < CollCount (&E->ActualArgs); ++I) {
206 FreeStrBuf (CollAtUnchecked (&E->ActualArgs, I));
208 DoneCollection (&E->ActualArgs);
209 SB_Done (&E->Replacement);
214 static void ME_AppendActual (MacroExp* E, StrBuf* Arg)
215 /* Add a copy of Arg to the list of actual macro arguments.
216 * NOTE: This function will clear Arg!
219 /* Create a new string buffer */
220 StrBuf* A = NewStrBuf ();
222 /* Move the contents of Arg to A */
225 /* Add A to the actual arguments */
226 CollAppend (&E->ActualArgs, A);
231 static StrBuf* ME_GetActual (MacroExp* E, unsigned Index)
232 /* Return an actual macro argument with the given index */
234 return CollAt (&E->ActualArgs, Index);
239 static int ME_ArgIsVariadic (const MacroExp* E)
240 /* Return true if the next actual argument we will add is a variadic one */
242 return (E->M->Variadic &&
243 E->M->ArgCount == (int) CollCount (&E->ActualArgs) + 1);
248 /*****************************************************************************/
250 /*****************************************************************************/
254 static void Stringize (StrBuf* Source, StrBuf* Target)
255 /* Stringize the given string: Add double quotes at start and end and preceed
256 * each occurance of " and \ by a backslash.
261 /* Add a starting quote */
262 SB_AppendChar (Target, '\"');
264 /* Replace any characters inside the string may not be part of a string
267 while ((C = SB_Get (Source)) != '\0') {
271 SB_AppendChar (Target, '\\');
274 SB_AppendChar (Target, C);
279 /* Add the closing quote */
280 SB_AppendChar (Target, '\"');
285 static void OldStyleComment (void)
286 /* Remove an old style C comment from line. */
288 /* Remember the current line number, so we can output better error
289 * messages if the comment is not terminated in the current file.
291 unsigned StartingLine = GetCurrentLine();
293 /* Skip the start of comment chars */
297 /* Skip the comment */
298 while (CurC != '*' || NextC != '/') {
300 if (NextLine () == 0) {
301 PPError ("End-of-file reached in comment starting at line %u",
306 if (CurC == '/' && NextC == '*') {
307 PPWarning ("`/*' found inside a comment");
313 /* Skip the end of comment chars */
320 static void NewStyleComment (void)
321 /* Remove a new style C comment from line. */
323 /* Beware: Because line continuation chars are handled when reading
324 * lines, we may only skip til the end of the source line, which
325 * may not be the same as the end of the input line. The end of the
326 * source line is denoted by a lf (\n) character.
330 } while (CurC != '\n' && CurC != '\0');
338 static int SkipWhitespace (int SkipLines)
339 /* Skip white space in the input stream. Do also skip newlines if SkipLines
340 * is true. Return zero if nothing was skipped, otherwise return a
346 if (IsSpace (CurC)) {
349 } else if (CurC == '\0' && SkipLines) {
350 /* End of line, read next */
351 if (NextLine () != 0) {
358 /* No more white space */
367 static void CopyQuotedString (StrBuf* Target)
368 /* Copy a single or double quoted string from the input to Target. */
370 /* Remember the quote character, copy it to the target buffer and skip it */
372 SB_AppendChar (Target, CurC);
375 /* Copy the characters inside the string */
376 while (CurC != '\0' && CurC != Quote) {
377 /* Keep an escaped char */
379 SB_AppendChar (Target, CurC);
382 /* Copy the character */
383 SB_AppendChar (Target, CurC);
387 /* If we had a terminating quote, copy it */
389 SB_AppendChar (Target, CurC);
396 /*****************************************************************************/
398 /*****************************************************************************/
402 static int MacName (char* Ident)
403 /* Get a macro symbol name into Ident. If we have an error, print a
404 * diagnostic message and clear the line.
407 if (IsSym (Ident) == 0) {
408 PPError ("Identifier expected");
418 static void ReadMacroArgs (MacroExp* E)
419 /* Identify the arguments to a macro call */
421 unsigned Parens; /* Number of open parenthesis */
422 StrBuf Arg = STATIC_STRBUF_INITIALIZER;
424 /* Read the actual macro arguments */
429 /* Nested parenthesis */
430 SB_AppendChar (&Arg, CurC);
434 } else if (IsQuote (CurC)) {
436 /* Quoted string - just copy */
437 CopyQuotedString (&Arg);
439 } else if (CurC == ',' || CurC == ')') {
442 /* Comma or right paren inside nested parenthesis */
446 SB_AppendChar (&Arg, CurC);
448 } else if (CurC == ',' && ME_ArgIsVariadic (E)) {
449 /* It's a comma, but we're inside a variadic macro argument, so
450 * just copy it and proceed.
452 SB_AppendChar (&Arg, CurC);
455 /* End of actual argument. Remove whitespace from the end. */
456 while (IsSpace (SB_LookAtLast (&Arg))) {
460 /* If this is not the single empty argument for a macro with
461 * an empty argument list, remember it.
463 if (CurC != ')' || SB_NotEmpty (&Arg) || E->M->ArgCount > 0) {
464 ME_AppendActual (E, &Arg);
467 /* Check for end of macro param list */
473 /* Start the next param */
477 } else if (SkipWhitespace (1)) {
478 /* Squeeze runs of blanks within an arg */
479 if (SB_NotEmpty (&Arg)) {
480 SB_AppendChar (&Arg, ' ');
482 } else if (CurC == '/' && NextC == '*') {
483 if (SB_NotEmpty (&Arg)) {
484 SB_AppendChar (&Arg, ' ');
487 } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
488 if (SB_NotEmpty (&Arg)) {
489 SB_AppendChar (&Arg, ' ');
492 } else if (CurC == '\0') {
493 /* End of input inside macro argument list */
494 PPError ("Unterminated argument list invoking macro `%s'", E->M->Name);
499 /* Just copy the character */
500 SB_AppendChar (&Arg, CurC);
505 /* Deallocate string buf resources */
511 static void MacroArgSubst (MacroExp* E)
512 /* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */
521 /* Remember the current input and switch to the macro replacement. */
522 int OldIndex = SB_GetIndex (&E->M->Replacement);
523 SB_Reset (&E->M->Replacement);
524 OldSource = InitLine (&E->M->Replacement);
526 /* Argument handling loop */
527 while (CurC != '\0') {
529 /* If we have an identifier, check if it's a macro */
532 /* Check if it's a macro argument */
533 if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
535 /* A macro argument. Get the corresponding actual argument. */
536 Arg = ME_GetActual (E, ArgIdx);
538 /* Copy any following whitespace */
539 HaveSpace = SkipWhitespace (0);
541 /* If a ## operator follows, we have to insert the actual
542 * argument as is, otherwise it must be macro replaced.
544 if (CurC == '#' && NextC == '#') {
546 /* ### Add placemarker if necessary */
547 SB_Append (&E->Replacement, Arg);
551 /* Replace the formal argument by a macro replaced copy
555 MacroReplacement (Arg, &E->Replacement);
557 /* If we skipped whitespace before, re-add it now */
559 SB_AppendChar (&E->Replacement, ' ');
566 /* An identifier, keep it */
567 SB_AppendStr (&E->Replacement, Ident);
571 } else if (CurC == '#' && NextC == '#') {
578 /* Since we need to concatenate the token sequences, remove
579 * any whitespace that was added to target, since it must come
582 while (IsSpace (SB_LookAtLast (&E->Replacement))) {
583 SB_Drop (&E->Replacement, 1);
586 /* If the next token is an identifier which is a macro argument,
587 * replace it, otherwise do nothing.
591 /* Check if it's a macro argument */
592 if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
594 /* Get the corresponding actual argument and add it. */
595 SB_Append (&E->Replacement, ME_GetActual (E, ArgIdx));
599 /* Just an ordinary identifier - add as is */
600 SB_AppendStr (&E->Replacement, Ident);
605 } else if (CurC == '#' && E->M->ArgCount >= 0) {
607 /* A # operator within a macro expansion of a function like
608 * macro. Read the following identifier and check if it's a
613 if (!IsSym (Ident) || (ArgIdx = FindMacroArg (E->M, Ident)) < 0) {
614 PPError ("`#' is not followed by a macro parameter");
616 /* Make a valid string from Replacement */
617 Arg = ME_GetActual (E, ArgIdx);
619 Stringize (Arg, &E->Replacement);
622 } else if (IsQuote (CurC)) {
623 CopyQuotedString (&E->Replacement);
625 SB_AppendChar (&E->Replacement, CurC);
631 /* Remove whitespace from the end of the line */
632 while (IsSpace (SB_LookAtLast (&E->Replacement))) {
633 SB_Drop (&E->Replacement, 1);
637 /* Switch back the input */
638 InitLine (OldSource);
639 SB_SetIndex (&E->M->Replacement, OldIndex);
644 static void MacroCall (StrBuf* Target, Macro* M)
645 /* Process a function like macro */
649 /* Eat the left paren */
652 /* Initialize our MacroExp structure */
653 InitMacroExp (&E, M);
655 /* Read the actual macro arguments */
658 /* Compare formal and actual argument count */
659 if (CollCount (&E.ActualArgs) != (unsigned) M->ArgCount) {
661 StrBuf Arg = STATIC_STRBUF_INITIALIZER;
663 /* Argument count mismatch */
664 PPError ("Macro argument count mismatch");
666 /* Be sure to make enough empty arguments available */
667 while (CollCount (&E.ActualArgs) < (unsigned) M->ArgCount) {
668 ME_AppendActual (&E, &Arg);
672 /* Replace macro arguments handling the # and ## operators */
675 /* Do macro replacement on the macro that already has the parameters
679 MacroReplacement (&E.Replacement, Target);
682 /* Free memory allocated for the macro expansion structure */
688 static void ExpandMacro (StrBuf* Target, Macro* M)
689 /* Expand a macro into Target */
692 static unsigned V = 0;
693 printf ("Expanding %s(%u)\n", M->Name, ++V);
696 /* Check if this is a function like macro */
697 if (M->ArgCount >= 0) {
699 int Whitespace = SkipWhitespace (1);
701 /* Function like macro but no parameter list */
702 SB_AppendStr (Target, M->Name);
704 SB_AppendChar (Target, ' ');
707 /* Function like macro */
708 MacroCall (Target, M);
714 InitMacroExp (&E, M);
716 /* Handle # and ## operators for object like macros */
719 /* Do macro replacement on the macro that already has the parameters
723 MacroReplacement (&E.Replacement, Target);
726 /* Free memory allocated for the macro expansion structure */
731 printf ("Done with %s(%u)\n", M->Name, V--);
737 static void DefineMacro (void)
738 /* Handle a macro definition. */
745 /* Read the macro name */
747 if (!MacName (Ident)) {
751 /* Remember if we're in C89 mode */
752 C89 = (IS_Get (&Standard) == STD_C89);
754 /* Get an existing macro definition with this name */
755 Existing = FindMacro (Ident);
757 /* Create a new macro definition */
758 M = NewMacro (Ident);
760 /* Check if this is a function like macro */
763 /* Skip the left paren */
766 /* Set the marker that this is a function like macro */
769 /* Read the formal parameter list */
772 /* Skip white space and check for end of parameter list */
778 /* The next token must be either an identifier, or - if not in
779 * C89 mode - the ellipsis.
781 if (!C89 && CurC == '.') {
784 if (CurC != '.' || NextC != '.') {
785 PPError ("`...' expected");
792 /* Remember that the macro is variadic and use __VA_ARGS__ as
795 AddMacroArg (M, "__VA_ARGS__");
799 /* Must be macro argument name */
800 if (MacName (Ident) == 0) {
804 /* __VA_ARGS__ is only allowed in C89 mode */
805 if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) {
806 PPWarning ("`__VA_ARGS__' can only appear in the expansion "
807 "of a C99 variadic macro");
810 /* Add the macro argument */
811 AddMacroArg (M, Ident);
814 /* If we had an ellipsis, or the next char is not a comma, we've
815 * reached the end of the macro argument list.
818 if (M->Variadic || CurC != ',') {
824 /* Check for a right paren and eat it if we find one */
826 PPError ("`)' expected");
833 /* Skip whitespace before the macro replacement */
836 /* Insert the macro into the macro table and allocate the ActualArgs array */
839 /* Remove whitespace and comments from the line, store the preprocessed
840 * line into the macro replacement buffer.
842 Pass1 (Line, &M->Replacement);
844 /* Remove whitespace from the end of the line */
845 while (IsSpace (SB_LookAtLast (&M->Replacement))) {
846 SB_Drop (&M->Replacement, 1);
849 printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
852 /* If we have an existing macro, check if the redefinition is identical.
853 * Print a diagnostic if not.
855 if (Existing && MacroCmp (M, Existing) != 0) {
856 PPError ("Macro redefinition is not identical");
862 /*****************************************************************************/
864 /*****************************************************************************/
868 static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
869 /* Preprocessor pass 1. Remove whitespace. Handle old and new style comments
870 * and the "defined" operator.
877 /* Switch to the new input source */
878 StrBuf* OldSource = InitLine (Source);
880 /* Loop removing ws and comments */
882 while (CurC != '\0') {
883 if (SkipWhitespace (0)) {
884 /* Squeeze runs of blanks */
885 if (!IsSpace (SB_LookAtLast (Target))) {
886 SB_AppendChar (Target, ' ');
888 } else if (IsSym (Ident)) {
889 if (Preprocessing && strcmp (Ident, "defined") == 0) {
890 /* Handle the "defined" operator */
899 SB_AppendChar (Target, IsMacro (Ident)? '1' : '0');
903 PPError ("`)' expected");
909 PPError ("Identifier expected");
910 SB_AppendChar (Target, '0');
914 SB_AppendStr (Target, Ident);
916 } else if (IsQuote (CurC)) {
917 CopyQuotedString (Target);
918 } else if (CurC == '/' && NextC == '*') {
919 if (!IsSpace (SB_LookAtLast (Target))) {
920 SB_AppendChar (Target, ' ');
923 } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') {
924 if (!IsSpace (SB_LookAtLast (Target))) {
925 SB_AppendChar (Target, ' ');
929 SB_AppendChar (Target, CurC);
934 /* Switch back to the old source */
935 InitLine (OldSource);
937 /* Return the number of identifiers found in the line */
943 static void MacroReplacement (StrBuf* Source, StrBuf* Target)
944 /* Perform macro replacement. */
949 /* Remember the current input and switch to Source */
950 StrBuf* OldSource = InitLine (Source);
952 /* Loop substituting macros */
953 while (CurC != '\0') {
954 /* If we have an identifier, check if it's a macro */
956 /* Check if it's a macro */
957 if ((M = FindMacro (Ident)) != 0 && !M->Expanding) {
958 /* It's a macro, expand it */
959 ExpandMacro (Target, M);
961 /* An identifier, keep it */
962 SB_AppendStr (Target, Ident);
964 } else if (IsQuote (CurC)) {
965 CopyQuotedString (Target);
966 } else if (IsSpace (CurC)) {
967 if (!IsSpace (SB_LookAtLast (Target))) {
968 SB_AppendChar (Target, CurC);
972 SB_AppendChar (Target, CurC);
977 /* Switch back the input */
978 InitLine (OldSource);
983 static void PreprocessLine (void)
984 /* Translate one line. */
986 /* Trim whitespace and remove comments. The function returns the number of
987 * identifiers found. If there were any, we will have to check for macros.
990 if (Pass1 (Line, MLine) > 0) {
991 MLine = InitLine (MLine);
994 MacroReplacement (Line, MLine);
997 /* Read from the new line */
999 MLine = InitLine (MLine);
1004 static int PushIf (int Skip, int Invert, int Cond)
1005 /* Push a new if level onto the if stack */
1007 /* Check for an overflow of the if stack */
1008 if (IfIndex >= MAX_IFS-1) {
1009 PPError ("Too many nested #if clauses");
1013 /* Push the #if condition */
1016 IfStack[IfIndex] = IFCOND_SKIP | IFCOND_NEEDTERM;
1019 IfStack[IfIndex] = IFCOND_NONE | IFCOND_NEEDTERM;
1020 return (Invert ^ Cond);
1026 static void DoError (void)
1027 /* Print an error */
1031 PPError ("Invalid #error directive");
1033 PPError ("#error: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line));
1036 /* Clear the rest of line */
1042 static int DoIf (int Skip)
1043 /* Process #if directive */
1047 /* We're about to abuse the compiler expression parser to evaluate the
1048 * #if expression. Save the current tokens to come back here later.
1049 * NOTE: Yes, this is a hack, but it saves a complete separate expression
1050 * evaluation for the preprocessor.
1052 Token SavedCurTok = CurTok;
1053 Token SavedNextTok = NextTok;
1055 /* Make sure the line infos for the tokens won't get removed */
1056 if (SavedCurTok.LI) {
1057 UseLineInfo (SavedCurTok.LI);
1059 if (SavedNextTok.LI) {
1060 UseLineInfo (SavedNextTok.LI);
1063 /* Switch into special preprocessing mode */
1066 /* Expand macros in this line */
1069 /* Add two semicolons as sentinels to the line, so the following
1070 * expression evaluation will eat these two tokens but nothing from
1071 * the following line.
1073 SB_AppendStr (Line, ";;");
1074 SB_Terminate (Line);
1076 /* Load CurTok and NextTok with tokens from the new input */
1080 /* Call the expression parser */
1081 ConstExpr (hie1, &Expr);
1083 /* End preprocessing mode */
1086 /* Reset the old tokens */
1087 CurTok = SavedCurTok;
1088 NextTok = SavedNextTok;
1090 /* Set the #if condition according to the expression result */
1091 return PushIf (Skip, 1, Expr.IVal != 0);
1096 static int DoIfDef (int skip, int flag)
1097 /* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
1102 if (MacName (Ident) == 0) {
1105 return PushIf (skip, flag, IsMacro(Ident));
1111 static void DoInclude (void)
1112 /* Open an include file. */
1116 StrBuf Filename = STATIC_STRBUF_INITIALIZER;
1119 /* Preprocess the remainder of the line */
1125 /* Get the next char and check for a valid file name terminator. Setup
1126 * the include directory spec (SYS/USR) by looking at the terminator.
1141 PPError ("`\"' or `<' expected");
1146 /* Get a copy of the filename */
1147 while (CurC != '\0' && CurC != RTerm) {
1148 SB_AppendChar (&Filename, CurC);
1151 SB_Terminate (&Filename);
1153 /* Check if we got a terminator */
1154 if (CurC == RTerm) {
1155 /* Open the include file */
1156 OpenIncludeFile (SB_GetConstBuf (&Filename), DirSpec);
1157 } else if (CurC == '\0') {
1158 /* No terminator found */
1159 PPError ("#include expects \"FILENAME\" or <FILENAME>");
1163 /* Free the allocated filename data */
1164 SB_Done (&Filename);
1166 /* Clear the remaining line so the next input will come from the new
1174 static void DoPragma (void)
1175 /* Handle a #pragma line by converting the #pragma preprocessor directive into
1176 * the _Pragma() compiler operator.
1179 /* Skip blanks following the #pragma directive */
1182 /* Copy the remainder of the line into MLine removing comments and ws */
1184 Pass1 (Line, MLine);
1186 /* Convert the directive into the operator */
1187 SB_CopyStr (Line, "_Pragma (");
1189 Stringize (MLine, Line);
1190 SB_AppendChar (Line, ')');
1192 /* Initialize reading from line */
1199 static void DoUndef (void)
1200 /* Process the #undef directive */
1205 if (MacName (Ident)) {
1206 UndefineMacro (Ident);
1212 static void DoWarning (void)
1213 /* Print a warning */
1217 PPError ("Invalid #warning directive");
1219 PPWarning ("#warning: %s", SB_GetConstBuf (Line) + SB_GetIndex (Line));
1222 /* Clear the rest of line */
1228 void Preprocess (void)
1229 /* Preprocess a line */
1234 /* Create the output buffer if we don't already have one */
1236 MLine = NewStrBuf ();
1239 /* Skip white space at the beginning of the line */
1242 /* Check for stuff to skip */
1244 while (CurC == '\0' || CurC == '#' || Skip) {
1246 /* Check for preprocessor lines lines */
1251 /* Ignore the empty preprocessor directive */
1254 if (!IsSym (Directive)) {
1255 PPError ("Preprocessor directive expected");
1258 switch (FindPPToken (Directive)) {
1268 if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
1270 /* Handle as #else/#if combination */
1271 if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
1274 IfStack[IfIndex] |= IFCOND_ELSE;
1277 /* #elif doesn't need a terminator */
1278 IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
1280 PPError ("Duplicate #else/#elif");
1283 PPError ("Unexpected #elif");
1289 if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
1290 if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
1293 IfStack[IfIndex] |= IFCOND_ELSE;
1295 PPError ("Duplicate #else");
1298 PPError ("Unexpected `#else'");
1304 /* Remove any clauses on top of stack that do not
1305 * need a terminating #endif.
1307 while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
1311 /* Stack may not be empty here or something is wrong */
1312 CHECK (IfIndex >= 0);
1314 /* Remove the clause that needs a terminator */
1315 Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0;
1317 PPError ("Unexpected `#endif'");
1332 Skip = DoIfDef (Skip, 1);
1336 Skip = DoIfDef (Skip, 0);
1346 /* Should do something in C99 at least, but we ignore it */
1366 /* #warning is a non standard extension */
1367 if (IS_Get (&Standard) > STD_C99) {
1373 PPError ("Preprocessor directive expected");
1381 PPError ("Preprocessor directive expected");
1388 if (NextLine () == 0) {
1390 PPError ("`#endif' expected");
1400 if (Verbosity > 1 && SB_NotEmpty (Line)) {
1401 printf ("%s(%u): %.*s\n", GetCurrentFile (), GetCurrentLine (),
1402 (int) SB_GetLen (Line), SB_GetConstBuf (Line));