2 /* C pre-processor functions */
25 /*****************************************************************************/
27 /*****************************************************************************/
31 static int Pass1 (char* from, char* to);
35 /*****************************************************************************/
37 /*****************************************************************************/
41 /* Set when the pp calls expr() recursively */
42 unsigned char Preprocessing = 0;
44 /* Management data for #if */
46 static int i_ifdef = -1;
47 static char s_ifdef[N_IFDEF];
49 /* Buffer for macro expansion */
50 static char mlinebuf [LINESIZE];
51 static char* mline = mlinebuf;
54 /* Flag: Expand macros in this line */
55 static int ExpandMacros = 1;
59 /*****************************************************************************/
61 /*****************************************************************************/
65 static int keepch (char c)
66 /* Put character c into translation buffer. */
73 static void keepstr (const char* S)
74 /* Put string str into translation buffer. */
83 static void comment (void)
84 /* Remove comment from line. */
86 unsigned StartingLine = ln;
90 while (*lptr != '*' || nch () != '/') {
92 if (readline () == 0) {
93 PPError (ERR_EOF_IN_COMMENT, StartingLine);
97 if (*lptr == '/' && nch() == '*') {
98 PPWarning (WARN_NESTED_COMMENT);
109 static void skipblank (void)
110 /* Skip blanks and tabs in the input stream. */
112 while (IsBlank (*lptr)) {
119 static char* CopyQuotedString (int Quote, char* Target)
120 /* Copy a single or double quoted string from lptr to Target. Return the
121 * new target pointer. Target will not be terminated after the copy.
124 /* Copy the starting quote */
127 /* Copy the characters inside the string */
128 while (*lptr != '\0' && *lptr != Quote) {
129 /* Keep an escaped char */
133 /* Copy the character */
137 /* If we had a terminating quote, copy it */
142 /* Return the new target pointer */
148 /*****************************************************************************/
150 /*****************************************************************************/
154 static int macname (char *sname)
155 /* Get macro symbol name. If error, print message and kill line. */
157 if (issym (sname) == 0) {
158 PPError (ERR_IDENT_EXPECTED);
168 static void ExpandMacroArgs (Macro* M)
169 /* Preprocessor pass 2. Perform macro substitution. */
173 const char* Replacement;
176 /* Save the current line pointer and setup the new ones */
178 lptr = M->Replacement;
180 /* Copy the macro replacement checking for parameters to replace */
181 while ((C = *lptr) != '\0') {
182 /* If the next token is an identifier, check for a macro arg */
185 Replacement = FindMacroArg (M, Ident);
187 /* Macro arg, keep the replacement */
188 keepstr (Replacement);
190 /* No macro argument, keep the original identifier */
193 } else if (C == '#' && IsIdent (nch ())) {
196 Replacement = FindMacroArg (M, Ident);
199 keepstr (Replacement);
205 } else if (IsQuoteChar(C)) {
206 mptr = CopyQuotedString (C, mptr);
212 /* Reset the line pointer */
218 static int MacroCall (Macro* M)
219 /* Process a function like macro */
221 unsigned ArgCount; /* Macro argument count */
222 unsigned ParCount; /* Number of open parenthesis */
223 char Buf[LINESIZE]; /* Argument buffer */
225 const char* ArgStart;
228 /* Expect an argument list */
231 PPError (ERR_ILLEGAL_MACRO_CALL);
235 /* Eat the left paren */
238 /* Read the actual macro arguments and store pointers to these arguments
239 * into the array of actual arguments in the macro definition.
250 } else if (IsQuoteChar(C)) {
251 B = CopyQuotedString (C, B);
252 } else if (C == ',' || C == ')') {
254 /* End of actual argument */
257 while (IsBlank(*ArgStart)) {
260 if (ArgCount < M->ArgCount) {
261 M->ActualArgs[ArgCount++] = ArgStart;
262 } else if (C != ')' || *ArgStart != '\0' || M->ArgCount > 0) {
263 /* Be sure not to count the single empty argument for a
264 * macro that does not have arguments.
269 /* Start the next one */
280 } else if (IsBlank (C)) {
281 /* Squeeze runs of blanks */
284 } else if (C == '\0') {
285 /* End of line inside macro argument list - read next line */
286 if (readline () == 0) {
290 /* Just copy the character */
295 /* Compare formal argument count with actual */
296 if (M->ArgCount != ArgCount) {
297 PPError (ERR_MACRO_ARGCOUNT);
298 /* Be sure to make enough empty arguments available */
299 while (ArgCount < M->ArgCount) {
300 M->ActualArgs [ArgCount++] = "";
304 /* Preprocess the line, replacing macro parameters */
313 static void ExpandMacro (Macro* M)
316 /* Check if this is a function like macro */
317 if (M->ArgCount >= 0) {
318 /* Function like macro */
319 if (MacroCall (M) == 0) {
323 /* Just copy the replacement text */
324 keepstr (M->Replacement);
330 static void addmac (void)
331 /* Add a macro to the macro table. */
338 /* Read the macro name */
340 if (!macname (Ident)) {
344 /* Create a new macro definition */
345 M = NewMacro (Ident);
347 /* Check if this is a function like macro */
350 /* Skip the left paren */
353 /* Set the marker that this is a function like macro */
356 /* Read the formal parameter list */
361 if (macname (Ident) == 0) {
364 AddMacroArg (M, Ident);
371 PPError (ERR_RPAREN_EXPECTED);
378 /* Insert the macro into the macro table and allocate the ActualArgs array */
381 /* Remove whitespace and comments from the line, store the preprocessed
389 /* Create a copy of the replacement */
390 M->Replacement = xstrdup (Buf);
395 /*****************************************************************************/
397 /*****************************************************************************/
401 static int Pass1 (char* from, char* to)
402 /* Preprocessor pass 1. Remove whitespace and comments. */
412 while ((c = *lptr) != 0) {
416 } else if (IsIdent (c)) {
418 if (Preprocessing && strcmp(Ident, "defined") == 0) {
419 /* Handle the "defined" operator */
428 PPError (ERR_IDENT_EXPECTED);
432 *mptr++ = IsMacro(Ident)? '1' : '0';
436 PPError (ERR_RPAREN_EXPECTED);
448 } else if (IsQuoteChar(c)) {
449 mptr = CopyQuotedString (c, mptr);
450 } else if (c == '/' && nch () == '*') {
453 } else if (ANSI == 0 && c == '/' && nch () == '/') {
455 /* Beware: Because line continuation chars are handled when reading
456 * lines, we may only skip til the end of the source line, which
457 * may not be the same as the end of the input line. The end of the
458 * source line is denoted by a lf (\n) character.
462 } while (*lptr != '\n' && *lptr != '\0');
476 static int Pass2 (char *from, char *to)
477 /* Preprocessor pass 2. Perform macro substitution. */
487 while ((C = *lptr) != '\0') {
488 /* If we have an identifier, check if it's a macro */
491 M = FindMacro (Ident);
498 } else if (IsQuoteChar(C)) {
499 mptr = CopyQuotedString (C, mptr);
509 static void xlateline (void)
510 /* Translate one line. */
516 Done = Pass1 (line, mline);
517 if (ExpandMacros == 0) {
519 ExpandMacros = 1; /* Reset to default */
528 Done = Pass2 (line, mline);
536 static void doundef (void)
537 /* Process #undef directive */
542 if (macname (Ident)) {
543 UndefineMacro (Ident);
549 static int setmflag (int skip, int flag, int cond)
550 /* setmflag( skip, flag, cond ) */
553 s_ifdef[++i_ifdef] = 3;
556 s_ifdef[++i_ifdef] = 6;
557 return (flag ^ cond);
563 static int doiff (int skip)
564 /* Process #if directive */
569 /* We're about to abuse the compiler expression parser to evaluate the
570 * #if expression. Save the current tokens to come back here later.
575 /* Remove the #if from the line and add two semicolons as sentinels */
578 while ((*S++ = *lptr++) != '\0') ;
582 /* Switch into special preprocessing mode */
585 /* Expand macros in this line */
588 /* Prime the token pump (remove old tokens from the stream) */
592 /* Call the expression parser */
595 /* End preprocessing mode */
598 /* Reset the old tokens */
602 /* Set the #if condition according to the expression result */
603 return (setmflag (skip, 1, lval.e_const != 0));
608 static int doifdef (int skip, int flag)
609 /* Process #ifdef if flag == 1, or #ifndef if flag == 0. */
614 if (macname (Ident) == 0) {
617 return setmflag (skip, flag, IsMacro(Ident));
623 static void doinclude (void)
624 /* Open an include file. */
632 if (ifile >= MAXFILES) {
633 PPError (ERR_INCLUDE_NESTING);
638 if (!strchr ("\"<", (term = cgch ()))) {
639 PPError (ERR_INCLUDE_LTERM_EXPECTED);
643 term = '>'; /* get right terminator */
646 /* Get the name of the include file */
648 while ((c = *lptr) && (c != term) && count < sizeof (name)-1) {
653 PPError (ERR_INCLUDE_RTERM_EXPECTED);
658 /* Now search for the name */
659 p = FindInclude (name, (term == '\"')? INC_USER : INC_SYS);
661 PPError (ERR_INCLUDE_NOT_FOUND, name);
665 /* Save the existing file info */
666 filetab[ifile].f_ln = ln;
667 filetab[ifile].f_name = fin;
668 filetab[ifile].f_iocb = inp;
671 /* Assign the name and output it */
674 printf ("including '%s'\n", fin);
677 /* Try to open the include file */
678 if ((inp = fopen (fin, "r")) == 0) {
679 /* oops! restore old file */
680 PPError (ERR_INCLUDE_OPEN_FAILURE, fin);
683 inp = filetab[ifile].f_iocb;
684 fin = filetab[ifile].f_name;
690 /* clear rest of line so next read will come from new file (if open) */
696 static void doerror (void)
701 PPError (ERR_INVALID_USER_ERROR);
703 PPError (ERR_USER_ERROR, lptr);
706 /* clear rest of line */
712 /* C preprocessor. */
714 /* stuff used to bum the keyword dispatching stuff */
730 static const struct tok_elt pre_toks[] = {
731 { "define", D_DEFINE },
733 { "endif", D_ENDIF },
734 { "error", D_ERROR },
736 { "ifdef", D_IFDEF },
737 { "ifndef", D_IFNDEF },
738 { "include", D_INCLUDE },
740 { "pragma", D_PRAGMA },
741 { "undef", D_UNDEF },
747 int searchtok (const char *sym, const struct tok_elt *toks)
748 /* Search a token in a table */
750 while (toks->toknam && strcmp (toks->toknam, sym))
752 return (toks->toknbr);
757 void preprocess (void)
758 /* Preprocess a line */
764 /* Process compiler directives, skip empty lines */
767 /* Skip white space at the beginning of the line */
770 /* Check for stuff to skip */
772 while ((c = *lptr) == '\0' || c == '#' || Skip) {
774 /* Check for preprocessor lines lines */
779 /* ignore the empty preprocessor directive */
782 if (!issym (sname)) {
783 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
786 switch (searchtok (sname, pre_toks)) {
795 if (s_ifdef[i_ifdef] & 2) {
796 if (s_ifdef[i_ifdef] & 4) {
799 s_ifdef[i_ifdef] ^= 2;
801 PPError (ERR_UNEXPECTED_CPP_ELSE);
807 Skip = s_ifdef[i_ifdef--] & 1;
809 PPError (ERR_UNEXPECTED_CPP_ENDIF);
824 Skip = doifdef (Skip, 1);
828 Skip = doifdef (Skip, 0);
838 /* Not allowed in strict ANSI mode */
840 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
847 /* Don't expand macros in this line */
849 /* #pragma is handled on the scanner level */
861 PPError (ERR_CPP_DIRECTIVE_EXPECTED);
867 if (readline () == 0) {
869 PPError (ERR_CPP_ENDIF_EXPECTED);
879 printf ("line: %s\n", line);