2 /* C pre-processor functions */
10 #include "../common/xmalloc.h"
26 /*****************************************************************************/
28 /*****************************************************************************/
32 static int Pass1 (char* from, char* to);
36 /*****************************************************************************/
38 /*****************************************************************************/
42 /* Set when the pp calls expr() recursively */
43 unsigned char Preprocessing = 0;
45 /* Management data for #if */
47 static int i_ifdef = -1;
48 static char s_ifdef[N_IFDEF];
50 /* Buffer for macro expansion */
51 static char mlinebuf [LINESIZE];
52 static char* mline = mlinebuf;
55 /* Flag: Expand macros in this line */
56 static int ExpandMacros = 1;
60 /*****************************************************************************/
62 /*****************************************************************************/
66 static int keepch (char c)
67 /* Put character c into translation buffer. */
74 static void keepstr (const char* S)
75 /* Put string str into translation buffer. */
84 static void comment (void)
85 /* Remove comment from line. */
87 unsigned StartingLine = GetCurrentLine();
91 while (*lptr != '*' || nch () != '/') {
93 if (NextLine () == 0) {
94 PPError (ERR_EOF_IN_COMMENT, StartingLine);
98 if (*lptr == '/' && nch() == '*') {
99 PPWarning (WARN_NESTED_COMMENT);
110 static void skipblank (void)
111 /* Skip blanks and tabs in the input stream. */
113 while (IsBlank (*lptr)) {
120 static char* CopyQuotedString (int Quote, char* Target)
121 /* Copy a single or double quoted string from lptr to Target. Return the
122 * new target pointer. Target will not be terminated after the copy.
125 /* Copy the starting quote */
128 /* Copy the characters inside the string */
129 while (*lptr != '\0' && *lptr != Quote) {
130 /* Keep an escaped char */
134 /* Copy the character */
138 /* If we had a terminating quote, copy it */
143 /* Return the new target pointer */
149 /*****************************************************************************/
151 /*****************************************************************************/
155 static int macname (char *sname)
156 /* Get macro symbol name. If error, print message and clear line. */
158 if (issym (sname) == 0) {
159 PPError (ERR_IDENT_EXPECTED);
169 static void ExpandMacroArgs (Macro* M)
170 /* Preprocessor pass 2. Perform macro substitution. */
174 const char* Replacement;
177 /* Save the current line pointer and setup the new ones */
179 lptr = M->Replacement;
181 /* Copy the macro replacement checking for parameters to replace */
182 while ((C = *lptr) != '\0') {
183 /* If the next token is an identifier, check for a macro arg */
186 Replacement = FindMacroArg (M, Ident);
188 /* Macro arg, keep the replacement */
189 keepstr (Replacement);
191 /* No macro argument, keep the original identifier */
194 } else if (C == '#' && IsIdent (nch ())) {
197 Replacement = FindMacroArg (M, Ident);
200 keepstr (Replacement);
206 } else if (IsQuoteChar(C)) {
207 mptr = CopyQuotedString (C, mptr);
213 /* Reset the line pointer */
219 static int MacroCall (Macro* M)
220 /* Process a function like macro */
222 unsigned ArgCount; /* Macro argument count */
223 unsigned ParCount; /* Number of open parenthesis */
224 char Buf[LINESIZE]; /* Argument buffer */
226 const char* ArgStart;
229 /* Expect an argument list */
232 PPError (ERR_ILLEGAL_MACRO_CALL);
236 /* Eat the left paren */
239 /* Read the actual macro arguments and store pointers to these arguments
240 * into the array of actual arguments in the macro definition.
251 } else if (IsQuoteChar(C)) {
252 B = CopyQuotedString (C, B);
253 } else if (C == ',' || C == ')') {
255 /* End of actual argument */
258 while (IsBlank(*ArgStart)) {
261 if (ArgCount < M->ArgCount) {
262 M->ActualArgs[ArgCount++] = ArgStart;
263 } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
264 /* Be sure not to count the single empty argument for a
265 * macro that does not have arguments.
270 /* Start the next one */
281 } else if (IsBlank (C)) {
282 /* Squeeze runs of blanks */
285 } else if (C == '\0') {
286 /* End of line inside macro argument list - read next line */
287 if (NextLine () == 0) {
291 /* Just copy the character */
296 /* Compare formal argument count with actual */
297 if (M->ArgCount != ArgCount) {
298 PPError (ERR_MACRO_ARGCOUNT);
299 /* Be sure to make enough empty arguments available */
300 while (ArgCount < M->ArgCount) {
301 M->ActualArgs [ArgCount++] = "";
305 /* Preprocess the line, replacing macro parameters */
314 static void ExpandMacro (Macro* M)
317 /* Check if this is a function like macro */
318 if (M->ArgCount >= 0) {
319 /* Function like macro */
320 if (MacroCall (M) == 0) {
324 /* Just copy the replacement text */
325 keepstr (M->Replacement);
331 static void addmac (void)
332 /* Add a macro to the macro table. */
339 /* Read the macro name */
341 if (!macname (Ident)) {
345 /* Create a new macro definition */
346 M = NewMacro (Ident);
348 /* Check if this is a function like macro */
351 /* Skip the left paren */
354 /* Set the marker that this is a function like macro */
357 /* Read the formal parameter list */
362 if (macname (Ident) == 0) {
365 AddMacroArg (M, Ident);
372 PPError (ERR_RPAREN_EXPECTED);
379 /* Insert the macro into the macro table and allocate the ActualArgs array */
382 /* Remove whitespace and comments from the line, store the preprocessed
390 /* Create a copy of the replacement */
391 M->Replacement = xstrdup (Buf);
396 /*****************************************************************************/
398 /*****************************************************************************/
402 static int Pass1 (char* from, char* to)
403 /* Preprocessor pass 1. Remove whitespace and comments. */
413 while ((c = *lptr) != 0) {
417 } else if (IsIdent (c)) {
419 if (Preprocessing && strcmp(Ident, "defined") == 0) {
420 /* Handle the "defined" operator */
429 PPError (ERR_IDENT_EXPECTED);
433 *mptr++ = IsMacro(Ident)? '1' : '0';
437 PPError (ERR_RPAREN_EXPECTED);
449 } else if (IsQuoteChar(c)) {
450 mptr = CopyQuotedString (c, mptr);
451 } else if (c == '/' && nch () == '*') {
454 } else if (ANSI == 0 && c == '/' && nch () == '/') {
456 /* Beware: Because line continuation chars are handled when reading
457 * lines, we may only skip til the end of the source line, which
458 * may not be the same as the end of the input line. The end of the
459 * source line is denoted by a lf (\n) character.
463 } while (*lptr != '\n' && *lptr != '\0');
477 static int Pass2 (char *from, char *to)
478 /* Preprocessor pass 2. Perform macro substitution. */
488 while ((C = *lptr) != '\0') {
489 /* If we have an identifier, check if it's a macro */
492 M = FindMacro (Ident);
499 } else if (IsQuoteChar(C)) {
500 mptr = CopyQuotedString (C, mptr);
510 static void xlateline (void)
511 /* Translate one line. */
517 Done = Pass1 (line, mline);
518 if (ExpandMacros == 0) {
520 ExpandMacros = 1; /* Reset to default */
529 Done = Pass2 (line, mline);
537 static void doundef (void)
538 /* Process #undef directive */
543 if (macname (Ident)) {
544 UndefineMacro (Ident);
550 static int setmflag (int skip, int flag, int cond)
551 /* setmflag( skip, flag, cond ) */
554 s_ifdef[++i_ifdef] = 3;
557 s_ifdef[++i_ifdef] = 6;
558 return (flag ^ cond);
564 static int doiff (int skip)
565 /* Process #if directive */
570 /* We're about to abuse the compiler expression parser to evaluate the
571 * #if expression. Save the current tokens to come back here later.
576 /* Remove the #if from the line and add two semicolons as sentinels */
579 while ((*S++ = *lptr++) != '\0') ;
583 /* Switch into special preprocessing mode */
586 /* Expand macros in this line */
589 /* Prime the token pump (remove old tokens from the stream) */
593 /* Call the expression parser */
596 /* End preprocessing mode */
599 /* Reset the old tokens */
603 /* Set the #if condition according to the expression result */
604 return (setmflag (skip, 1, lval.e_const != 0));
609 static int doifdef (int skip, int flag)
610 /* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
615 if (macname (Ident) == 0) {
618 return setmflag (skip, flag, IsMacro(Ident));
624 static void doinclude (void)
625 /* Open an include file. */
638 /* Get the next char and check for a valid file name terminator. Setup
639 * the include directory spec (SYS/USR) by looking at the terminator.
654 PPError (ERR_INCLUDE_LTERM_EXPECTED);
658 /* Search for the right terminator */
659 End = strchr (lptr, RTerm);
661 /* No terminator found */
662 PPError (ERR_INCLUDE_RTERM_EXPECTED);
666 /* Create a temp copy of the filename */
668 Name = xmalloc (Length + 1);
669 memcpy (Name, lptr, Length);
672 /* Open the include file */
673 OpenIncludeFile (Name, DirSpec);
675 /* Delete the temp filename copy */
679 /* Clear the remaining line so the next input will come from the new
687 static void doerror (void)
692 PPError (ERR_INVALID_USER_ERROR);
694 PPError (ERR_USER_ERROR, lptr);
697 /* clear rest of line */
703 /* C preprocessor. */
705 /* stuff used to bum the keyword dispatching stuff */
721 static const struct tok_elt pre_toks[] = {
722 { "define", D_DEFINE },
724 { "endif", D_ENDIF },
725 { "error", D_ERROR },
727 { "ifdef", D_IFDEF },
728 { "ifndef", D_IFNDEF },
729 { "include", D_INCLUDE },
731 { "pragma", D_PRAGMA },
732 { "undef", D_UNDEF },
738 int searchtok (const char *sym, const struct tok_elt *toks)
739 /* Search a token in a table */
741 while (toks->toknam && strcmp (toks->toknam, sym))
743 return (toks->toknbr);
748 void preprocess (void)
749 /* Preprocess a line */
755 /* Process compiler directives, skip empty lines */
758 /* Skip white space at the beginning of the line */
761 /* Check for stuff to skip */
763 while ((c = *lptr) == '\0' || c == '#' || Skip) {
765 /* Check for preprocessor lines lines */
770 /* ignore the empty preprocessor directive */
773 if (!issym (sname)) {
774 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
777 switch (searchtok (sname, pre_toks)) {
786 if (s_ifdef[i_ifdef] & 2) {
787 if (s_ifdef[i_ifdef] & 4) {
790 s_ifdef[i_ifdef] ^= 2;
792 PPError (ERR_UNEXPECTED_CPP_ELSE);
798 Skip = s_ifdef[i_ifdef--] & 1;
800 PPError (ERR_UNEXPECTED_CPP_ENDIF);
815 Skip = doifdef (Skip, 1);
819 Skip = doifdef (Skip, 0);
829 /* Not allowed in strict ANSI mode */
831 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
838 /* Don't expand macros in this line */
840 /* #pragma is handled on the scanner level */
852 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
858 if (NextLine () == 0) {
860 PPError (ERR_CPP_ENDIF_EXPECTED);
870 printf ("line: %s\n", line);