36
36
typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS } Comment;
39
MaxCppNestingLevel = 20,
39
MaxCppNestingLevel = 20,
43
43
/* Defines the one nesting level of a preprocessor conditional.
45
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 */
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 */
52
61
/* Defines the current state of the pre-processor.
54
63
typedef struct sCppState {
55
int ungetch, ungetch2; /* ungotten characters, if any */
56
boolean resolveRequired; /* must resolve if/else/elif/endif branch */
59
DRCTV_NONE, /* no known directive - ignore to end of line */
60
DRCTV_DEFINE, /* "#define" encountered */
61
DRCTV_HASH, /* initial '#' read; determine directive */
62
DRCTV_IF, /* "#if" or "#ifdef" encountered */
63
DRCTV_UNDEF /* "#undef" encountered */
65
boolean accept; /* is a directive syntatically permitted? */
66
vString * name; /* macro name */
67
unsigned int nestLevel; /* level 0 is not used */
68
conditionalInfo ifdef [MaxCppNestingLevel];
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];
96
101
extern boolean isBraceFormat (void)
101
106
extern unsigned int getDirectiveNestLevel (void)
103
return Cpp.directive.nestLevel;
108
return Cpp.directive.nestLevel;
106
extern void cppInit (const boolean state)
111
extern void cppInit (const boolean state, const boolean hasAtLiteralStrings)
112
Cpp.resolveRequired = FALSE;
114
Cpp.directive.state = DRCTV_NONE;
115
Cpp.directive.accept = TRUE;
116
Cpp.directive.nestLevel = 0;
118
if (Cpp.directive.name == NULL)
119
Cpp.directive.name = vStringNew ();
121
vStringClear (Cpp.directive.name);
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);
124
135
extern void cppTerminate (void)
126
if (Cpp.directive.name != NULL)
128
vStringDelete (Cpp.directive.name);
129
Cpp.directive.name = NULL;
137
if (Cpp.directive.name != NULL)
139
vStringDelete (Cpp.directive.name);
140
Cpp.directive.name = NULL;
133
144
extern void cppBeginStatement (void)
135
Cpp.resolveRequired = TRUE;
146
Cpp.resolveRequired = TRUE;
138
149
extern void cppEndStatement (void)
140
Cpp.resolveRequired = FALSE;
151
Cpp.resolveRequired = FALSE;
153
164
extern void cppUngetc (const int c)
155
Assert (Cpp.ungetch2 == '\0');
156
Cpp.ungetch2 = Cpp.ungetch;
166
Assert (Cpp.ungetch2 == '\0');
167
Cpp.ungetch2 = Cpp.ungetch;
160
171
/* Reads a directive, whose first character is given by "c", into "name".
162
173
static boolean readDirective (int c, char *const name, unsigned int maxLength)
166
for (i = 0 ; i < maxLength - 1 ; ++i)
177
for (i = 0 ; i < maxLength - 1 ; ++i)
171
if (c == EOF || ! isalpha (c))
182
if (c == EOF || ! isalpha (c))
179
name [i] = '\0'; /* null terminate */
190
name [i] = '\0'; /* null terminate */
181
return (boolean) isspacetab (c);
192
return (boolean) isspacetab (c);
184
195
/* Reads an identifier, whose first character is given by "c", into "tag",
185
196
* together with the file location and corresponding line number.
187
static boolean readDefineTag (int c, vString *const name,
188
boolean *const parameterized)
198
static void readIdentifier (int c, vString *const name)
193
vStringPut (name, c);
194
} while (c = fileGetc (), (c != EOF && isident (c)));
196
vStringPut (name, '\0');
198
*parameterized = (boolean) (c == '(');
199
return (boolean) (isspace (c) || c == '(');
203
vStringPut (name, c);
204
} while (c = fileGetc (), (c != EOF && isident (c)));
206
vStringTerminate (name);
202
209
static conditionalInfo *currentConditional (void)
204
return &Cpp.directive.ifdef [Cpp.directive.nestLevel];
211
return &Cpp.directive.ifdef [Cpp.directive.nestLevel];
207
214
static boolean isIgnore (void)
209
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring;
216
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring;
212
219
static boolean setIgnore (const boolean ignore)
214
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore;
221
return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore;
217
224
static boolean isIgnoreBranch (void)
219
conditionalInfo *const ifdef = currentConditional ();
221
/* Force a single branch if an incomplete statement is discovered
222
* en route. This may have allowed earlier branches containing complete
223
* statements to be followed, but we must follow no further branches.
225
if (Cpp.resolveRequired && ! BraceFormat)
226
ifdef->singleBranch = TRUE;
228
/* We will ignore this branch in the following cases:
230
* 1. We are ignoring all branches (conditional was within an ignored
231
* branch of the parent conditional)
232
* 2. A branch has already been chosen and either of:
233
* a. A statement was incomplete upon entering the conditional
234
* b. A statement is incomplete upon encountering a branch
236
return (boolean) (ifdef->ignoreAllBranches ||
237
(ifdef->branchChosen && ifdef->singleBranch));
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));
240
247
static void chooseBranch (void)
244
conditionalInfo *const ifdef = currentConditional ();
251
conditionalInfo *const ifdef = currentConditional ();
246
ifdef->branchChosen = (boolean) (ifdef->singleBranch ||
247
Cpp.resolveRequired);
253
ifdef->branchChosen = (boolean) (ifdef->singleBranch ||
254
Cpp.resolveRequired);
251
258
/* Pushes one nesting level for an #if directive, indicating whether or not
254
261
static boolean pushConditional (const boolean firstBranchChosen)
256
const boolean ignoreAllBranches = isIgnore (); /* current ignore */
257
boolean ignoreBranch = FALSE;
259
if (Cpp.directive.nestLevel < (unsigned int) MaxCppNestingLevel - 1)
261
conditionalInfo *ifdef;
263
++Cpp.directive.nestLevel;
264
ifdef = currentConditional ();
266
/* We take a snapshot of whether there is an incomplete statement in
267
* progress upon encountering the preprocessor conditional. If so,
268
* then we will flag that only a single branch of the conditional
269
* should be followed.
271
ifdef->ignoreAllBranches= ignoreAllBranches;
272
ifdef->singleBranch = Cpp.resolveRequired;
273
ifdef->branchChosen = firstBranchChosen;
274
ifdef->ignoring = (boolean) (ignoreAllBranches || (
275
! firstBranchChosen && ! BraceFormat &&
276
(ifdef->singleBranch || !Option.if0)));
277
ignoreBranch = ifdef->ignoring;
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;
282
289
/* Pops one nesting level for an #endif directive.
284
291
static boolean popConditional (void)
286
if (Cpp.directive.nestLevel > 0)
287
--Cpp.directive.nestLevel;
293
if (Cpp.directive.nestLevel > 0)
294
--Cpp.directive.nestLevel;
292
299
static void makeDefineTag (const char *const name, boolean parameterized)
294
const boolean isFileScope = (boolean) (! isHeaderFile ());
296
if (includingDefineTags () &&
297
(! isFileScope || Option.include.fileScope))
301
initTagEntry (&e, name);
303
e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
304
e.isFileScope = isFileScope;
305
e.truncateLine = TRUE;
306
e.kindName = "macro";
309
e.extensionFields.arglist = getArglistFromPos(getInputFilePosition()
313
free((char *) e.extensionFields.arglist);
301
const boolean isFileScope = (boolean) (! isHeaderFile ());
303
if (includingDefineTags () &&
304
(! isFileScope || Option.include.fileScope))
308
initTagEntry (&e, name);
310
e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
311
e.isFileScope = isFileScope;
312
e.truncateLine = TRUE;
313
e.kindName = "macro";
316
e.extensionFields.arglist = getArglistFromPos(getInputFilePosition()
320
free((char *) e.extensionFields.arglist);
317
324
static void directiveDefine (const int c)
319
boolean parameterized;
323
readDefineTag (c, Cpp.directive.name, ¶meterized);
326
// the second argument need to be tested, not sure if TRUE is correct
327
makeDefineTag (vStringValue (Cpp.directive.name), TRUE);
329
Cpp.directive.state = DRCTV_NONE;
326
boolean parameterized;
331
readIdentifier (c, Cpp.directive.name);
334
parameterized = (boolean) (nc == '(');
336
makeDefineTag (vStringValue (Cpp.directive.name), parameterized);
338
Cpp.directive.state = DRCTV_NONE;
341
static void directivePragma (int c)
345
readIdentifier (c, Cpp.directive.name);
346
if (stringMatch (vStringValue (Cpp.directive.name), "weak"))
348
/* generate macro tag for weak name */
352
} while (c == SPACE);
355
readIdentifier (c, Cpp.directive.name);
356
makeDefineTag (vStringValue (Cpp.directive.name), FALSE);
360
Cpp.directive.state = DRCTV_NONE;
332
363
static boolean directiveIf (const int c)
334
const boolean ignore = pushConditional ((boolean) (c != '0'));
336
Cpp.directive.state = DRCTV_NONE;
365
const boolean ignore = pushConditional ((boolean) (c != '0'));
367
Cpp.directive.state = DRCTV_NONE;
341
372
static boolean directiveHash (const int c)
343
boolean ignore = FALSE;
344
char directive [MaxDirectiveName];
345
DebugStatement ( const boolean ignore0 = isIgnore (); )
347
readDirective (c, directive, MaxDirectiveName);
348
if (stringMatch (directive, "define"))
349
Cpp.directive.state = DRCTV_DEFINE;
350
else if (stringMatch (directive, "undef"))
351
Cpp.directive.state = DRCTV_UNDEF;
352
else if (strncmp (directive, "if", (size_t) 2) == 0)
353
Cpp.directive.state = DRCTV_IF;
354
else if (stringMatch (directive, "elif") ||
355
stringMatch (directive, "else"))
357
ignore = setIgnore (isIgnoreBranch ());
358
if (! ignore && stringMatch (directive, "else"))
360
Cpp.directive.state = DRCTV_NONE;
361
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
363
else if (stringMatch (directive, "endif"))
365
DebugStatement ( debugCppNest (FALSE, Cpp.directive.nestLevel); )
366
ignore = popConditional ();
367
Cpp.directive.state = DRCTV_NONE;
368
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
370
else /* "pragma", etc. */
371
Cpp.directive.state = DRCTV_NONE;
374
boolean ignore = FALSE;
375
char directive [MaxDirectiveName];
376
DebugStatement ( const boolean ignore0 = isIgnore (); )
378
readDirective (c, directive, MaxDirectiveName);
379
if (stringMatch (directive, "define"))
380
Cpp.directive.state = DRCTV_DEFINE;
381
else if (stringMatch (directive, "undef"))
382
Cpp.directive.state = DRCTV_UNDEF;
383
else if (strncmp (directive, "if", (size_t) 2) == 0)
384
Cpp.directive.state = DRCTV_IF;
385
else if (stringMatch (directive, "elif") ||
386
stringMatch (directive, "else"))
388
ignore = setIgnore (isIgnoreBranch ());
389
if (! ignore && stringMatch (directive, "else"))
391
Cpp.directive.state = DRCTV_NONE;
392
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
394
else if (stringMatch (directive, "endif"))
396
DebugStatement ( debugCppNest (FALSE, Cpp.directive.nestLevel); )
397
ignore = popConditional ();
398
Cpp.directive.state = DRCTV_NONE;
399
DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
401
else if (stringMatch (directive, "pragma"))
402
Cpp.directive.state = DRCTV_PRAGMA;
404
Cpp.directive.state = DRCTV_NONE;
376
409
/* Handles a pre-processor directive whose first character is given by "c".
378
411
static boolean handleDirective (const int c)
380
boolean ignore = isIgnore ();
413
boolean ignore = isIgnore ();
382
switch (Cpp.directive.state)
384
case DRCTV_NONE: ignore = isIgnore (); break;
385
case DRCTV_DEFINE: directiveDefine (c); break;
386
case DRCTV_HASH: ignore = directiveHash (c); break;
387
case DRCTV_IF: ignore = directiveIf (c); break;
388
case DRCTV_UNDEF: directiveDefine (c); break;
415
switch (Cpp.directive.state)
417
case DRCTV_NONE: ignore = isIgnore (); break;
418
case DRCTV_DEFINE: directiveDefine (c); break;
419
case DRCTV_HASH: ignore = directiveHash (c); break;
420
case DRCTV_IF: ignore = directiveIf (c); break;
421
case DRCTV_PRAGMA: directivePragma (c); break;
422
case DRCTV_UNDEF: directiveDefine (c); break;
393
427
/* Called upon reading of a slash ('/') characters, determines whether a
396
430
static Comment isComment (void)
399
const int next = fileGetc ();
433
const int next = fileGetc ();
403
else if (next == '/')
404
comment = COMMENT_CPLUS;
408
comment = COMMENT_NONE;
437
else if (next == '/')
438
comment = COMMENT_CPLUS;
442
comment = COMMENT_NONE;
413
447
/* Skips over a C style comment. According to ANSI specification a comment
414
* is treated as white space, so we perform this subsitution.
448
* is treated as white space, so we perform this substitution.
416
static int skipOverCComment (void)
450
int skipOverCComment (void)
426
const int next = fileGetc ();
460
const int next = fileGetc ();
432
c = ' '; /* replace comment with space */
466
c = SPACE; /* replace comment with space */
440
474
/* Skips over a C++ style comment.
442
476
static int skipOverCplusComment (void)
446
while ((c = fileGetc ()) != EOF)
449
fileGetc (); /* throw away next character, too */
450
else if (c == NEWLINE)
480
while ((c = fileGetc ()) != EOF)
483
fileGetc (); /* throw away next character, too */
484
else if (c == NEWLINE)
456
490
/* Skips to the end of a string, returning a special character to
457
491
* symbolically represent a generic string.
459
static int skipToEndOfString (void)
493
static int skipToEndOfString (boolean ignoreBackslash)
463
while ((c = fileGetc ()) != EOF)
466
fileGetc (); /* throw away next character, too */
467
else if (c == DOUBLE_QUOTE)
470
return STRING_SYMBOL; /* symbolic representation of string */
497
while ((c = fileGetc ()) != EOF)
499
if (c == BACKSLASH && ! ignoreBackslash)
500
fileGetc (); /* throw away next character, too */
501
else if (c == DOUBLE_QUOTE)
504
return STRING_SYMBOL; /* symbolic representation of string */
473
507
/* Skips to the end of the three (possibly four) 'c' sequence, returning a
474
508
* special character to symbolically represent a generic character.
509
* Also detects Vera numbers that include a base specifier (ie. 'b1010).
476
511
static int skipToEndOfChar (void)
514
int count = 0, veraBase = '\0';
480
while ((c = fileGetc ()) != EOF)
483
fileGetc (); /* throw away next character, too */
484
else if (c == SINGLE_QUOTE)
486
else if (c == NEWLINE)
516
while ((c = fileGetc ()) != EOF)
520
fileGetc (); /* throw away next character, too */
521
else if (c == SINGLE_QUOTE)
523
else if (c == NEWLINE)
528
else if (count == 1 && strchr ("DHOB", toupper (c)) != NULL)
530
else if (veraBase != '\0' && ! isalnum (c))
492
return CHAR_SYMBOL; /* symbolic representation of character */
536
return CHAR_SYMBOL; /* symbolic representation of character */
495
539
/* This function returns the next character, stripping out comments,
500
544
extern int cppGetc (void)
502
boolean directive = FALSE;
503
boolean ignore = FALSE;
546
boolean directive = FALSE;
547
boolean ignore = FALSE;
506
if (Cpp.ungetch != '\0')
509
Cpp.ungetch = Cpp.ungetch2;
511
return c; /* return here to avoid re-calling debugPutc () */
550
if (Cpp.ungetch != '\0')
553
Cpp.ungetch = Cpp.ungetch2;
555
return c; /* return here to avoid re-calling debugPutc () */
526
break; /* ignore most white space */
529
if (directive && ! ignore)
531
Cpp.directive.accept = TRUE;
535
Cpp.directive.accept = FALSE;
536
c = skipToEndOfString ();
540
if (Cpp.directive.accept)
543
Cpp.directive.state = DRCTV_HASH;
544
Cpp.directive.accept = FALSE;
549
Cpp.directive.accept = FALSE;
550
c = skipToEndOfChar ();
555
const Comment comment = isComment ();
557
if (comment == COMMENT_C)
558
c = skipOverCComment ();
559
else if (comment == COMMENT_CPLUS)
561
c = skipOverCplusComment ();
566
Cpp.directive.accept = FALSE;
572
int next = fileGetc ();
576
else if (next == '?')
585
int next = fileGetc ();
593
case '(': c = '['; break;
594
case ')': c = ']'; break;
595
case '<': c = '{'; break;
596
case '>': c = '}'; break;
597
case '/': c = BACKSLASH; goto process;
598
case '!': c = '|'; break;
599
case SINGLE_QUOTE: c = '^'; break;
600
case '-': c = '~'; break;
601
case '=': c = '#'; goto process;
570
break; /* ignore most white space */
573
if (directive && ! ignore)
575
Cpp.directive.accept = TRUE;
579
Cpp.directive.accept = FALSE;
580
c = skipToEndOfString (FALSE);
584
if (Cpp.directive.accept)
587
Cpp.directive.state = DRCTV_HASH;
588
Cpp.directive.accept = FALSE;
593
Cpp.directive.accept = FALSE;
594
c = skipToEndOfChar ();
599
const Comment comment = isComment ();
601
if (comment == COMMENT_C)
602
c = skipOverCComment ();
603
else if (comment == COMMENT_CPLUS)
605
c = skipOverCplusComment ();
610
Cpp.directive.accept = FALSE;
616
int next = fileGetc ();
620
else if (next == '?')
629
int next = fileGetc ();
637
case '(': c = '['; break;
638
case ')': c = ']'; break;
639
case '<': c = '{'; break;
640
case '>': c = '}'; break;
641
case '/': c = BACKSLASH; goto process;
642
case '!': c = '|'; break;
643
case SINGLE_QUOTE: c = '^'; break;
644
case '-': c = '~'; break;
645
case '=': c = '#'; goto process;
655
if (c == '@' && Cpp.hasAtLiteralStrings)
657
int next = fileGetc ();
658
if (next == DOUBLE_QUOTE)
660
Cpp.directive.accept = FALSE;
661
c = skipToEndOfString (TRUE);
665
Cpp.directive.accept = FALSE;
667
ignore = handleDirective (c);
611
Cpp.directive.accept = FALSE;
613
ignore = handleDirective (c);
616
} while (directive || ignore);
618
DebugStatement ( debugPutc (DEBUG_CPP, c); )
619
DebugStatement ( if (c == NEWLINE)
620
debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); )
670
} while (directive || ignore);
672
DebugStatement ( debugPutc (DEBUG_CPP, c); )
673
DebugStatement ( if (c == NEWLINE)
674
debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); )
626
679
extern char *getArglistFromPos(fpos_t startPosition, const char *tokenName)
628
681
fpos_t originalPosition;