2 * $Id: get.c 559 2007-06-17 03:30:09Z elliotth $
4 * Copyright (c) 1996-2002, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains the high level source read functions (preprocessor
10 * directives are handled within this level).
16 #include "general.h" /* must always come first */
30 #define stringMatch(s1,s2) (strcmp (s1,s2) == 0)
31 #define isspacetab(c) ((c) == SPACE || (c) == TAB)
36 typedef enum { COMMENT_NONE
, COMMENT_C
, COMMENT_CPLUS
} Comment
;
39 MaxCppNestingLevel
= 20,
43 /* Defines the one nesting level of a preprocessor conditional.
45 typedef struct sConditionalInfo
{
46 boolean ignoreAllBranches
; /* ignoring parent conditional branch */
47 boolean singleBranch
; /* choose only one branch */
48 boolean branchChosen
; /* branch already selected */
49 boolean ignoring
; /* current ignore state */
53 DRCTV_NONE
, /* no known directive - ignore to end of line */
54 DRCTV_DEFINE
, /* "#define" encountered */
55 DRCTV_HASH
, /* initial '#' read; determine directive */
56 DRCTV_IF
, /* "#if" or "#ifdef" encountered */
57 DRCTV_PRAGMA
, /* #pragma encountered */
58 DRCTV_UNDEF
/* "#undef" encountered */
61 /* Defines the current state of the pre-processor.
63 typedef struct sCppState
{
64 int ungetch
, ungetch2
; /* ungotten characters, if any */
65 boolean resolveRequired
; /* must resolve if/else/elif/endif branch */
66 boolean hasAtLiteralStrings
; /* supports @"c:\" strings */
68 enum eState state
; /* current directive being processed */
69 boolean accept
; /* is a directive syntactically permitted? */
70 vString
* name
; /* macro name */
71 unsigned int nestLevel
; /* level 0 is not used */
72 conditionalInfo ifdef
[MaxCppNestingLevel
];
80 /* Use brace formatting to detect end of block.
82 static boolean BraceFormat
= FALSE
;
84 static cppState Cpp
= {
85 '\0', '\0', /* ungetch characters */
86 FALSE
, /* resolveRequired */
87 FALSE
, /* hasAtLiteralStrings */
89 DRCTV_NONE
, /* state */
93 { {FALSE
,FALSE
,FALSE
,FALSE
} } /* ifdef array */
98 * FUNCTION DEFINITIONS
101 extern boolean
isBraceFormat (void)
106 extern unsigned int getDirectiveNestLevel (void)
108 return Cpp
.directive
.nestLevel
;
111 extern void cppInit (const boolean state
, const boolean hasAtLiteralStrings
)
117 Cpp
.resolveRequired
= FALSE
;
118 Cpp
.hasAtLiteralStrings
= hasAtLiteralStrings
;
120 Cpp
.directive
.state
= DRCTV_NONE
;
121 Cpp
.directive
.accept
= TRUE
;
122 Cpp
.directive
.nestLevel
= 0;
124 Cpp
.directive
.ifdef
[0].ignoreAllBranches
= FALSE
;
125 Cpp
.directive
.ifdef
[0].singleBranch
= FALSE
;
126 Cpp
.directive
.ifdef
[0].branchChosen
= FALSE
;
127 Cpp
.directive
.ifdef
[0].ignoring
= FALSE
;
129 if (Cpp
.directive
.name
== NULL
)
130 Cpp
.directive
.name
= vStringNew ();
132 vStringClear (Cpp
.directive
.name
);
135 extern void cppTerminate (void)
137 if (Cpp
.directive
.name
!= NULL
)
139 vStringDelete (Cpp
.directive
.name
);
140 Cpp
.directive
.name
= NULL
;
144 extern void cppBeginStatement (void)
146 Cpp
.resolveRequired
= TRUE
;
149 extern void cppEndStatement (void)
151 Cpp
.resolveRequired
= FALSE
;
157 * This section handles preprocessor directives. It strips out all
158 * directives and may emit a tag for #define directives.
161 /* This puts a character back into the input queue for the source File.
162 * Up to two characters may be ungotten.
164 extern void cppUngetc (const int c
)
166 Assert (Cpp
.ungetch2
== '\0');
167 Cpp
.ungetch2
= Cpp
.ungetch
;
171 /* Reads a directive, whose first character is given by "c", into "name".
173 static boolean
readDirective (int c
, char *const name
, unsigned int maxLength
)
177 for (i
= 0 ; i
< maxLength
- 1 ; ++i
)
182 if (c
== EOF
|| ! isalpha (c
))
190 name
[i
] = '\0'; /* null terminate */
192 return (boolean
) isspacetab (c
);
195 /* Reads an identifier, whose first character is given by "c", into "tag",
196 * together with the file location and corresponding line number.
198 static void readIdentifier (int c
, vString
*const name
)
203 vStringPut (name
, c
);
204 } while (c
= fileGetc (), (c
!= EOF
&& isident (c
)));
206 vStringTerminate (name
);
209 static conditionalInfo
*currentConditional (void)
211 return &Cpp
.directive
.ifdef
[Cpp
.directive
.nestLevel
];
214 static boolean
isIgnore (void)
216 return Cpp
.directive
.ifdef
[Cpp
.directive
.nestLevel
].ignoring
;
219 static boolean
setIgnore (const boolean ignore
)
221 return Cpp
.directive
.ifdef
[Cpp
.directive
.nestLevel
].ignoring
= ignore
;
224 static boolean
isIgnoreBranch (void)
226 conditionalInfo
*const ifdef
= currentConditional ();
228 /* Force a single branch if an incomplete statement is discovered
229 * en route. This may have allowed earlier branches containing complete
230 * statements to be followed, but we must follow no further branches.
232 if (Cpp
.resolveRequired
&& ! BraceFormat
)
233 ifdef
->singleBranch
= TRUE
;
235 /* We will ignore this branch in the following cases:
237 * 1. We are ignoring all branches (conditional was within an ignored
238 * branch of the parent conditional)
239 * 2. A branch has already been chosen and either of:
240 * a. A statement was incomplete upon entering the conditional
241 * b. A statement is incomplete upon encountering a branch
243 return (boolean
) (ifdef
->ignoreAllBranches
||
244 (ifdef
->branchChosen
&& ifdef
->singleBranch
));
247 static void chooseBranch (void)
251 conditionalInfo
*const ifdef
= currentConditional ();
253 ifdef
->branchChosen
= (boolean
) (ifdef
->singleBranch
||
254 Cpp
.resolveRequired
);
258 /* Pushes one nesting level for an #if directive, indicating whether or not
259 * the branch should be ignored and whether a branch has already been chosen.
261 static boolean
pushConditional (const boolean firstBranchChosen
)
263 const boolean ignoreAllBranches
= isIgnore (); /* current ignore */
264 boolean ignoreBranch
= FALSE
;
266 if (Cpp
.directive
.nestLevel
< (unsigned int) MaxCppNestingLevel
- 1)
268 conditionalInfo
*ifdef
;
270 ++Cpp
.directive
.nestLevel
;
271 ifdef
= currentConditional ();
273 /* We take a snapshot of whether there is an incomplete statement in
274 * progress upon encountering the preprocessor conditional. If so,
275 * then we will flag that only a single branch of the conditional
276 * should be followed.
278 ifdef
->ignoreAllBranches
= ignoreAllBranches
;
279 ifdef
->singleBranch
= Cpp
.resolveRequired
;
280 ifdef
->branchChosen
= firstBranchChosen
;
281 ifdef
->ignoring
= (boolean
) (ignoreAllBranches
|| (
282 ! firstBranchChosen
&& ! BraceFormat
&&
283 (ifdef
->singleBranch
|| !Option
.if0
)));
284 ignoreBranch
= ifdef
->ignoring
;
289 /* Pops one nesting level for an #endif directive.
291 static boolean
popConditional (void)
293 if (Cpp
.directive
.nestLevel
> 0)
294 --Cpp
.directive
.nestLevel
;
299 static void makeDefineTag (const char *const name
)
301 const boolean isFileScope
= (boolean
) (! isHeaderFile ());
303 if (includingDefineTags () &&
304 (! isFileScope
|| Option
.include
.fileScope
))
307 initTagEntry (&e
, name
);
308 e
.lineNumberEntry
= (boolean
) (Option
.locate
!= EX_PATTERN
);
309 e
.isFileScope
= isFileScope
;
310 e
.truncateLine
= TRUE
;
311 e
.kindName
= "macro";
317 static void directiveDefine (const int c
)
321 readIdentifier (c
, Cpp
.directive
.name
);
323 makeDefineTag (vStringValue (Cpp
.directive
.name
));
325 Cpp
.directive
.state
= DRCTV_NONE
;
328 static void directivePragma (int c
)
332 readIdentifier (c
, Cpp
.directive
.name
);
333 if (stringMatch (vStringValue (Cpp
.directive
.name
), "weak"))
335 /* generate macro tag for weak name */
339 } while (c
== SPACE
);
342 readIdentifier (c
, Cpp
.directive
.name
);
343 makeDefineTag (vStringValue (Cpp
.directive
.name
));
347 Cpp
.directive
.state
= DRCTV_NONE
;
350 static boolean
directiveIf (const int c
)
352 DebugStatement ( const boolean ignore0
= isIgnore (); )
353 const boolean ignore
= pushConditional ((boolean
) (c
!= '0'));
355 Cpp
.directive
.state
= DRCTV_NONE
;
356 DebugStatement ( debugCppNest (TRUE
, Cpp
.directive
.nestLevel
);
357 if (ignore
!= ignore0
) debugCppIgnore (ignore
); )
362 static boolean
directiveHash (const int c
)
364 boolean ignore
= FALSE
;
365 char directive
[MaxDirectiveName
];
366 DebugStatement ( const boolean ignore0
= isIgnore (); )
368 readDirective (c
, directive
, MaxDirectiveName
);
369 if (stringMatch (directive
, "define"))
370 Cpp
.directive
.state
= DRCTV_DEFINE
;
371 else if (stringMatch (directive
, "undef"))
372 Cpp
.directive
.state
= DRCTV_UNDEF
;
373 else if (strncmp (directive
, "if", (size_t) 2) == 0)
374 Cpp
.directive
.state
= DRCTV_IF
;
375 else if (stringMatch (directive
, "elif") ||
376 stringMatch (directive
, "else"))
378 ignore
= setIgnore (isIgnoreBranch ());
379 if (! ignore
&& stringMatch (directive
, "else"))
381 Cpp
.directive
.state
= DRCTV_NONE
;
382 DebugStatement ( if (ignore
!= ignore0
) debugCppIgnore (ignore
); )
384 else if (stringMatch (directive
, "endif"))
386 DebugStatement ( debugCppNest (FALSE
, Cpp
.directive
.nestLevel
); )
387 ignore
= popConditional ();
388 Cpp
.directive
.state
= DRCTV_NONE
;
389 DebugStatement ( if (ignore
!= ignore0
) debugCppIgnore (ignore
); )
391 else if (stringMatch (directive
, "pragma"))
392 Cpp
.directive
.state
= DRCTV_PRAGMA
;
394 Cpp
.directive
.state
= DRCTV_NONE
;
399 /* Handles a pre-processor directive whose first character is given by "c".
401 static boolean
handleDirective (const int c
)
403 boolean ignore
= isIgnore ();
405 switch (Cpp
.directive
.state
)
407 case DRCTV_NONE
: ignore
= isIgnore (); break;
408 case DRCTV_DEFINE
: directiveDefine (c
); break;
409 case DRCTV_HASH
: ignore
= directiveHash (c
); break;
410 case DRCTV_IF
: ignore
= directiveIf (c
); break;
411 case DRCTV_PRAGMA
: directivePragma (c
); break;
412 case DRCTV_UNDEF
: directiveDefine (c
); break;
417 /* Called upon reading of a slash ('/') characters, determines whether a
418 * comment is encountered, and its type.
420 static Comment
isComment (void)
423 const int next
= fileGetc ();
427 else if (next
== '/')
428 comment
= COMMENT_CPLUS
;
432 comment
= COMMENT_NONE
;
437 /* Skips over a C style comment. According to ANSI specification a comment
438 * is treated as white space, so we perform this substitution.
440 int skipOverCComment (void)
450 const int next
= fileGetc ();
456 c
= SPACE
; /* replace comment with space */
464 /* Skips over a C++ style comment.
466 static int skipOverCplusComment (void)
470 while ((c
= fileGetc ()) != EOF
)
473 fileGetc (); /* throw away next character, too */
474 else if (c
== NEWLINE
)
480 /* Skips to the end of a string, returning a special character to
481 * symbolically represent a generic string.
483 static int skipToEndOfString (boolean ignoreBackslash
)
487 while ((c
= fileGetc ()) != EOF
)
489 if (c
== BACKSLASH
&& ! ignoreBackslash
)
490 fileGetc (); /* throw away next character, too */
491 else if (c
== DOUBLE_QUOTE
)
494 return STRING_SYMBOL
; /* symbolic representation of string */
497 /* Skips to the end of the three (possibly four) 'c' sequence, returning a
498 * special character to symbolically represent a generic character.
499 * Also detects Vera numbers that include a base specifier (ie. 'b1010).
501 static int skipToEndOfChar (void)
504 int count
= 0, veraBase
= '\0';
506 while ((c
= fileGetc ()) != EOF
)
510 fileGetc (); /* throw away next character, too */
511 else if (c
== SINGLE_QUOTE
)
513 else if (c
== NEWLINE
)
518 else if (count
== 1 && strchr ("DHOB", toupper (c
)) != NULL
)
520 else if (veraBase
!= '\0' && ! isalnum (c
))
526 return CHAR_SYMBOL
; /* symbolic representation of character */
529 /* This function returns the next character, stripping out comments,
530 * C pre-processor directives, and the contents of single and double
531 * quoted strings. In short, strip anything which places a burden upon
534 extern int cppGetc (void)
536 boolean directive
= FALSE
;
537 boolean ignore
= FALSE
;
540 if (Cpp
.ungetch
!= '\0')
543 Cpp
.ungetch
= Cpp
.ungetch2
;
545 return c
; /* return here to avoid re-calling debugPutc () */
560 break; /* ignore most white space */
563 if (directive
&& ! ignore
)
565 Cpp
.directive
.accept
= TRUE
;
569 Cpp
.directive
.accept
= FALSE
;
570 c
= skipToEndOfString (FALSE
);
574 if (Cpp
.directive
.accept
)
577 Cpp
.directive
.state
= DRCTV_HASH
;
578 Cpp
.directive
.accept
= FALSE
;
583 Cpp
.directive
.accept
= FALSE
;
584 c
= skipToEndOfChar ();
589 const Comment comment
= isComment ();
591 if (comment
== COMMENT_C
)
592 c
= skipOverCComment ();
593 else if (comment
== COMMENT_CPLUS
)
595 c
= skipOverCplusComment ();
600 Cpp
.directive
.accept
= FALSE
;
606 int next
= fileGetc ();
610 else if (next
== '?')
619 int next
= fileGetc ();
627 case '(': c
= '['; break;
628 case ')': c
= ']'; break;
629 case '<': c
= '{'; break;
630 case '>': c
= '}'; break;
631 case '/': c
= BACKSLASH
; goto process
;
632 case '!': c
= '|'; break;
633 case SINGLE_QUOTE
: c
= '^'; break;
634 case '-': c
= '~'; break;
635 case '=': c
= '#'; goto process
;
645 if (c
== '@' && Cpp
.hasAtLiteralStrings
)
647 int next
= fileGetc ();
648 if (next
== DOUBLE_QUOTE
)
650 Cpp
.directive
.accept
= FALSE
;
651 c
= skipToEndOfString (TRUE
);
655 Cpp
.directive
.accept
= FALSE
;
657 ignore
= handleDirective (c
);
660 } while (directive
|| ignore
);
662 DebugStatement ( debugPutc (DEBUG_CPP
, c
); )
663 DebugStatement ( if (c
== NEWLINE
)
664 debugPrintf (DEBUG_CPP
, "%6ld: ", getInputLineNumber () + 1); )
669 /* vi:set tabstop=4 shiftwidth=4: */