2 /* C pre-processor functions */
10 #include "../common/xmalloc.h"
27 /*****************************************************************************/
29 /*****************************************************************************/
33 static int Pass1 (char* from, char* to);
37 /*****************************************************************************/
39 /*****************************************************************************/
43 /* Set when the pp calls expr() recursively */
44 unsigned char Preprocessing = 0;
46 /* Management data for #if */
48 static int i_ifdef = -1;
49 static char s_ifdef[N_IFDEF];
51 /* Buffer for macro expansion */
52 static char mlinebuf [LINESIZE];
53 static char* mline = mlinebuf;
56 /* Flag: Expand macros in this line */
57 static int ExpandMacros = 1;
61 /*****************************************************************************/
63 /*****************************************************************************/
67 static int keepch (char c)
68 /* Put character c into translation buffer. */
75 static void keepstr (const char* S)
76 /* Put string str into translation buffer. */
85 static void comment (void)
86 /* Remove comment from line. */
88 unsigned StartingLine = GetCurrentLine();
92 while (*lptr != '*' || nch () != '/') {
94 if (NextLine () == 0) {
95 PPError (ERR_EOF_IN_COMMENT, StartingLine);
99 if (*lptr == '/' && nch() == '*') {
100 PPWarning (WARN_NESTED_COMMENT);
111 static void skipblank (void)
112 /* Skip blanks and tabs in the input stream. */
114 while (IsBlank (*lptr)) {
121 static char* CopyQuotedString (int Quote, char* Target)
122 /* Copy a single or double quoted string from lptr to Target. Return the
123 * new target pointer. Target will not be terminated after the copy.
126 /* Copy the starting quote */
129 /* Copy the characters inside the string */
130 while (*lptr != '\0' && *lptr != Quote) {
131 /* Keep an escaped char */
135 /* Copy the character */
139 /* If we had a terminating quote, copy it */
144 /* Return the new target pointer */
150 /*****************************************************************************/
152 /*****************************************************************************/
156 static int macname (char *sname)
157 /* Get macro symbol name. If error, print message and kill line. */
159 if (issym (sname) == 0) {
160 PPError (ERR_IDENT_EXPECTED);
170 static void ExpandMacroArgs (Macro* M)
171 /* Preprocessor pass 2. Perform macro substitution. */
175 const char* Replacement;
178 /* Save the current line pointer and setup the new ones */
180 lptr = M->Replacement;
182 /* Copy the macro replacement checking for parameters to replace */
183 while ((C = *lptr) != '\0') {
184 /* If the next token is an identifier, check for a macro arg */
187 Replacement = FindMacroArg (M, Ident);
189 /* Macro arg, keep the replacement */
190 keepstr (Replacement);
192 /* No macro argument, keep the original identifier */
195 } else if (C == '#' && IsIdent (nch ())) {
198 Replacement = FindMacroArg (M, Ident);
201 keepstr (Replacement);
207 } else if (IsQuoteChar(C)) {
208 mptr = CopyQuotedString (C, mptr);
214 /* Reset the line pointer */
220 static int MacroCall (Macro* M)
221 /* Process a function like macro */
223 unsigned ArgCount; /* Macro argument count */
224 unsigned ParCount; /* Number of open parenthesis */
225 char Buf[LINESIZE]; /* Argument buffer */
227 const char* ArgStart;
230 /* Expect an argument list */
233 PPError (ERR_ILLEGAL_MACRO_CALL);
237 /* Eat the left paren */
240 /* Read the actual macro arguments and store pointers to these arguments
241 * into the array of actual arguments in the macro definition.
252 } else if (IsQuoteChar(C)) {
253 B = CopyQuotedString (C, B);
254 } else if (C == ',' || C == ')') {
256 /* End of actual argument */
259 while (IsBlank(*ArgStart)) {
262 if (ArgCount < M->ArgCount) {
263 M->ActualArgs[ArgCount++] = ArgStart;
264 } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
265 /* Be sure not to count the single empty argument for a
266 * macro that does not have arguments.
271 /* Start the next one */
282 } else if (IsBlank (C)) {
283 /* Squeeze runs of blanks */
286 } else if (C == '\0') {
287 /* End of line inside macro argument list - read next line */
288 if (NextLine () == 0) {
292 /* Just copy the character */
297 /* Compare formal argument count with actual */
298 if (M->ArgCount != ArgCount) {
299 PPError (ERR_MACRO_ARGCOUNT);
300 /* Be sure to make enough empty arguments available */
301 while (ArgCount < M->ArgCount) {
302 M->ActualArgs [ArgCount++] = "";
306 /* Preprocess the line, replacing macro parameters */
315 static void ExpandMacro (Macro* M)
318 /* Check if this is a function like macro */
319 if (M->ArgCount >= 0) {
320 /* Function like macro */
321 if (MacroCall (M) == 0) {
325 /* Just copy the replacement text */
326 keepstr (M->Replacement);
332 static void addmac (void)
333 /* Add a macro to the macro table. */
340 /* Read the macro name */
342 if (!macname (Ident)) {
346 /* Create a new macro definition */
347 M = NewMacro (Ident);
349 /* Check if this is a function like macro */
352 /* Skip the left paren */
355 /* Set the marker that this is a function like macro */
358 /* Read the formal parameter list */
363 if (macname (Ident) == 0) {
366 AddMacroArg (M, Ident);
373 PPError (ERR_RPAREN_EXPECTED);
380 /* Insert the macro into the macro table and allocate the ActualArgs array */
383 /* Remove whitespace and comments from the line, store the preprocessed
391 /* Create a copy of the replacement */
392 M->Replacement = xstrdup (Buf);
397 /*****************************************************************************/
399 /*****************************************************************************/
403 static int Pass1 (char* from, char* to)
404 /* Preprocessor pass 1. Remove whitespace and comments. */
414 while ((c = *lptr) != 0) {
418 } else if (IsIdent (c)) {
420 if (Preprocessing && strcmp(Ident, "defined") == 0) {
421 /* Handle the "defined" operator */
430 PPError (ERR_IDENT_EXPECTED);
434 *mptr++ = IsMacro(Ident)? '1' : '0';
438 PPError (ERR_RPAREN_EXPECTED);
450 } else if (IsQuoteChar(c)) {
451 mptr = CopyQuotedString (c, mptr);
452 } else if (c == '/' && nch () == '*') {
455 } else if (ANSI == 0 && c == '/' && nch () == '/') {
457 /* Beware: Because line continuation chars are handled when reading
458 * lines, we may only skip til the end of the source line, which
459 * may not be the same as the end of the input line. The end of the
460 * source line is denoted by a lf (\n) character.
464 } while (*lptr != '\n' && *lptr != '\0');
478 static int Pass2 (char *from, char *to)
479 /* Preprocessor pass 2. Perform macro substitution. */
489 while ((C = *lptr) != '\0') {
490 /* If we have an identifier, check if it's a macro */
493 M = FindMacro (Ident);
500 } else if (IsQuoteChar(C)) {
501 mptr = CopyQuotedString (C, mptr);
511 static void xlateline (void)
512 /* Translate one line. */
518 Done = Pass1 (line, mline);
519 if (ExpandMacros == 0) {
521 ExpandMacros = 1; /* Reset to default */
530 Done = Pass2 (line, mline);
538 static void doundef (void)
539 /* Process #undef directive */
544 if (macname (Ident)) {
545 UndefineMacro (Ident);
551 static int setmflag (int skip, int flag, int cond)
552 /* setmflag( skip, flag, cond ) */
555 s_ifdef[++i_ifdef] = 3;
558 s_ifdef[++i_ifdef] = 6;
559 return (flag ^ cond);
565 static int doiff (int skip)
566 /* Process #if directive */
571 /* We're about to abuse the compiler expression parser to evaluate the
572 * #if expression. Save the current tokens to come back here later.
577 /* Remove the #if from the line and add two semicolons as sentinels */
580 while ((*S++ = *lptr++) != '\0') ;
584 /* Switch into special preprocessing mode */
587 /* Expand macros in this line */
590 /* Prime the token pump (remove old tokens from the stream) */
594 /* Call the expression parser */
597 /* End preprocessing mode */
600 /* Reset the old tokens */
604 /* Set the #if condition according to the expression result */
605 return (setmflag (skip, 1, lval.e_const != 0));
610 static int doifdef (int skip, int flag)
611 /* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
616 if (macname (Ident) == 0) {
619 return setmflag (skip, flag, IsMacro(Ident));
625 static void doinclude (void)
626 /* Open an include file. */
639 /* Get the next char and check for a valid file name terminator. Setup
640 * the include directory spec (SYS/USR) by looking at the terminator.
655 PPError (ERR_INCLUDE_LTERM_EXPECTED);
659 /* Search for the right terminator */
660 End = strchr (lptr, RTerm);
662 /* No terminator found */
663 PPError (ERR_INCLUDE_RTERM_EXPECTED);
667 /* Create a temp copy of the filename */
669 Name = xmalloc (Length + 1);
670 memcpy (Name, lptr, Length);
673 /* Open the include file */
674 OpenIncludeFile (Name, DirSpec);
676 /* Delete the temp filename copy */
680 /* clear rest of line so next read will come from new file (if open) */
686 static void doerror (void)
691 PPError (ERR_INVALID_USER_ERROR);
693 PPError (ERR_USER_ERROR, lptr);
696 /* clear rest of line */
702 /* C preprocessor. */
704 /* stuff used to bum the keyword dispatching stuff */
720 static const struct tok_elt pre_toks[] = {
721 { "define", D_DEFINE },
723 { "endif", D_ENDIF },
724 { "error", D_ERROR },
726 { "ifdef", D_IFDEF },
727 { "ifndef", D_IFNDEF },
728 { "include", D_INCLUDE },
730 { "pragma", D_PRAGMA },
731 { "undef", D_UNDEF },
737 int searchtok (const char *sym, const struct tok_elt *toks)
738 /* Search a token in a table */
740 while (toks->toknam && strcmp (toks->toknam, sym))
742 return (toks->toknbr);
747 void preprocess (void)
748 /* Preprocess a line */
754 /* Process compiler directives, skip empty lines */
757 /* Skip white space at the beginning of the line */
760 /* Check for stuff to skip */
762 while ((c = *lptr) == '\0' || c == '#' || Skip) {
764 /* Check for preprocessor lines lines */
769 /* ignore the empty preprocessor directive */
772 if (!issym (sname)) {
773 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
776 switch (searchtok (sname, pre_toks)) {
785 if (s_ifdef[i_ifdef] & 2) {
786 if (s_ifdef[i_ifdef] & 4) {
789 s_ifdef[i_ifdef] ^= 2;
791 PPError (ERR_UNEXPECTED_CPP_ELSE);
797 Skip = s_ifdef[i_ifdef--] & 1;
799 PPError (ERR_UNEXPECTED_CPP_ENDIF);
814 Skip = doifdef (Skip, 1);
818 Skip = doifdef (Skip, 0);
828 /* Not allowed in strict ANSI mode */
830 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
837 /* Don't expand macros in this line */
839 /* #pragma is handled on the scanner level */
851 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
857 if (NextLine () == 0) {
859 PPError (ERR_CPP_ENDIF_EXPECTED);
869 printf ("line: %s\n", line);