1 /*
2 * Copyright (c) 1996-2002, Darren Hiebert
3 *
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
6 *
7 * This module contains the high level input read functions (preprocessor
8 * directives are handled within this level).
9 */
10
11 /*
12 * INCLUDE FILES
13 */
14 #include "general.h" /* must always come first */
15
16 #include <string.h>
17
18 #include "debug.h"
19 #include "entry.h"
20 #include "htable.h"
21 #include "cpreprocessor.h"
22 #include "kind.h"
23 #include "options.h"
24 #include "read.h"
25 #include "vstring.h"
26 #include "param.h"
27 #include "parse.h"
28 #include "xtag.h"
29
30 #include "cxx/cxx_debug.h"
31
32 /*
33 * MACROS
34 */
35 #define stringMatch(s1,s2) (strcmp (s1,s2) == 0)
36 #define isspacetab(c) ((c) == SPACE || (c) == TAB)
37
38 /*
39 * DATA DECLARATIONS
40 */
41 typedef enum { COMMENT_NONE, COMMENT_C, COMMENT_CPLUS, COMMENT_D } Comment;
42
43 enum eCppLimits {
44 MaxCppNestingLevel = 20,
45 MaxDirectiveName = 10
46 };
47
48 /* Defines the one nesting level of a preprocessor conditional.
49 */
50 typedef struct sConditionalInfo {
51 bool ignoreAllBranches; /* ignoring parent conditional branch */
52 bool singleBranch; /* choose only one branch */
53 bool branchChosen; /* branch already selected */
54 bool ignoring; /* current ignore state */
55 int enterExternalParserBlockNestLevel; /* the parser state when entering this conditional: used only by cxx */
56 } conditionalInfo;
57
58 enum eState {
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_ELIF, /* "#elif" encountered */
64 DRCTV_PRAGMA, /* #pragma encountered */
65 DRCTV_UNDEF, /* "#undef" encountered */
66 DRCTV_INCLUDE, /* "#include" encountered */
67 };
68
69 /* Defines the current state of the pre-processor.
70 */
71 typedef struct sCppState {
72 langType lang;
73 langType clientLang;
74
75 int * ungetBuffer; /* memory buffer for unget characters */
76 int ungetBufferSize; /* the current unget buffer size */
77 int * ungetPointer; /* the current unget char: points in the middle of the buffer */
78 int ungetDataSize; /* the number of valid unget characters in the buffer */
79
80 /* the contents of the last SYMBOL_CHAR or SYMBOL_STRING */
81 vString * charOrStringContents;
82
83 bool resolveRequired; /* must resolve if/else/elif/endif branch */
84 bool hasAtLiteralStrings; /* supports @"c:\" strings */
85 bool hasCxxRawLiteralStrings; /* supports R"xxx(...)xxx" strings */
86 bool hasSingleQuoteLiteralNumbers; /* supports vera number literals:
87 'h..., 'o..., 'd..., and 'b... */
88
89 bool useClientLangDefineMacroKindIndex;
90 int defineMacroKindIndex;
91 int macroUndefRoleIndex;
92 int macroConditionRoleIndex;
93
94 bool useClientLangMacroParamKindIndex;
95 int macroParamKindIndex;
96
97 bool useClientLangHeaderKindIndex;
98 int headerKindIndex;
99 int headerSystemRoleIndex;
100 int headerLocalRoleIndex;
101
102 int macrodefFieldIndex;
103
104 struct sDirective {
105 enum eState state; /* current directive being processed */
106 bool accept; /* is a directive syntactically permitted? */
107 vString * name; /* macro name */
108 unsigned int nestLevel; /* level 0 is not used */
109 conditionalInfo ifdef [MaxCppNestingLevel];
110 } directive;
111
112 cppMacroInfo * macroInUse;
113 hashTable * fileMacroTable;
114
115 } cppState;
116
117
118 typedef enum {
119 CPREPRO_MACRO_KIND_UNDEF_ROLE,
120 CPREPRO_MACRO_KIND_CONDITION_ROLE,
121 } cPreProMacroRole;
122
123 static roleDefinition CPREPROMacroRoles [] = {
124 RoleTemplateUndef,
125 RoleTemplateCondition,
126 };
127
128
129 typedef enum {
130 CPREPRO_HEADER_KIND_SYSTEM_ROLE,
131 CPREPRO_HEADER_KIND_LOCAL_ROLE,
132 } cPreProHeaderRole;
133
134 static roleDefinition CPREPROHeaderRoles [] = {
135 RoleTemplateSystem,
136 RoleTemplateLocal,
137 };
138
139
140 typedef enum {
141 CPREPRO_MACRO, CPREPRO_HEADER, CPREPRO_PARAM,
142 } cPreProkind;
143
144 static kindDefinition CPreProKinds [] = {
145 { true, 'd', "macro", "macro definitions",
146 .referenceOnly = false, ATTACH_ROLES(CPREPROMacroRoles)},
147 { true, 'h', "header", "included header files",
148 .referenceOnly = true, ATTACH_ROLES(CPREPROHeaderRoles)},
149 { false, 'D', "parameter", "macro parameters", },
150 };
151
152 typedef enum {
153 F_MACRODEF,
154 COUNT_FIELD
155 } cPreProField;
156
157 static fieldDefinition CPreProFields[COUNT_FIELD] = {
158 { .name = "macrodef",
159 .description = "macro definition",
160 .enabled = false },
161 };
162
163 /*
164 * DATA DEFINITIONS
165 */
166
167 static bool doesExaminCodeWithInIf0Branch;
168 static bool doesExpandMacros;
169
170 /*
171 * CXX parser state. This is stored at the beginning of a conditional.
172 * If at the exit of the conditional the state is changed then we assume
173 * that no further branches should be followed.
174 */
175 static int externalParserBlockNestLevel;
176
177
178 /* Use brace formatting to detect end of block.
179 */
180 static bool BraceFormat = false;
181
cppPushExternalParserBlock(void)182 void cppPushExternalParserBlock(void)
183 {
184 externalParserBlockNestLevel++;
185 }
186
cppPopExternalParserBlock(void)187 void cppPopExternalParserBlock(void)
188 {
189 externalParserBlockNestLevel--;
190 }
191
192
193 static cppState Cpp = {
194 .lang = LANG_IGNORE,
195 .clientLang = LANG_IGNORE,
196 .ungetBuffer = NULL,
197 .ungetBufferSize = 0,
198 .ungetPointer = NULL,
199 .ungetDataSize = 0,
200 .charOrStringContents = NULL,
201 .resolveRequired = false,
202 .hasAtLiteralStrings = false,
203 .hasCxxRawLiteralStrings = false,
204 .hasSingleQuoteLiteralNumbers = false,
205 .useClientLangDefineMacroKindIndex = false,
206 .defineMacroKindIndex = CPREPRO_MACRO,
207 .macroUndefRoleIndex = CPREPRO_MACRO_KIND_UNDEF_ROLE,
208 .macroConditionRoleIndex = CPREPRO_MACRO_KIND_CONDITION_ROLE,
209 .useClientLangMacroParamKindIndex = false,
210 .macroParamKindIndex = CPREPRO_PARAM,
211 .useClientLangHeaderKindIndex = false,
212 .headerKindIndex = CPREPRO_HEADER,
213 .headerSystemRoleIndex = CPREPRO_HEADER_KIND_SYSTEM_ROLE,
214 .headerLocalRoleIndex = CPREPRO_HEADER_KIND_LOCAL_ROLE,
215 .macrodefFieldIndex = FIELD_UNKNOWN,
216 .directive = {
217 .state = DRCTV_NONE,
218 .accept = false,
219 .name = NULL,
220 .nestLevel = 0,
221 .ifdef = {
222 {
223 .ignoreAllBranches = false,
224 .singleBranch = false,
225 .branchChosen = false,
226 .ignoring = false,
227 }
228 }
229 } /* directive */
230 };
231
232 /*
233 * FUNCTION DECLARATIONS
234 */
235
236 static hashTable *makeMacroTable (void);
237 static cppMacroInfo * saveMacro(hashTable *table, const char * macro);
238
239 /*
240 * FUNCTION DEFINITIONS
241 */
242
cppIsBraceFormat(void)243 extern bool cppIsBraceFormat (void)
244 {
245 return BraceFormat;
246 }
247
cppGetDirectiveNestLevel(void)248 extern unsigned int cppGetDirectiveNestLevel (void)
249 {
250 return Cpp.directive.nestLevel;
251 }
252
cppInitCommon(langType clientLang,const bool state,const bool hasAtLiteralStrings,const bool hasCxxRawLiteralStrings,const bool hasSingleQuoteLiteralNumbers,int defineMacroKindIndex,int macroUndefRoleIndex,int macroConditionRoleIndex,int macroParamKindIndex,int headerKindIndex,int headerSystemRoleIndex,int headerLocalRoleIndex,int macrodefFieldIndex)253 static void cppInitCommon(langType clientLang,
254 const bool state, const bool hasAtLiteralStrings,
255 const bool hasCxxRawLiteralStrings,
256 const bool hasSingleQuoteLiteralNumbers,
257 int defineMacroKindIndex,
258 int macroUndefRoleIndex,
259 int macroConditionRoleIndex,
260 int macroParamKindIndex,
261 int headerKindIndex,
262 int headerSystemRoleIndex, int headerLocalRoleIndex,
263 int macrodefFieldIndex)
264 {
265 BraceFormat = state;
266
267 CXX_DEBUG_PRINT("cppInit: brace format is %d",BraceFormat);
268
269 externalParserBlockNestLevel = 0;
270
271 if (Cpp.lang == LANG_IGNORE)
272 {
273 langType t;
274
275 t = getNamedLanguage ("CPreProcessor", 0);
276 initializeParser (t);
277 }
278
279 Cpp.clientLang = clientLang;
280 Cpp.ungetBuffer = NULL;
281 Cpp.ungetPointer = NULL;
282
283 CXX_DEBUG_ASSERT(!Cpp.charOrStringContents,"This string should be null when CPP is not initialized");
284 Cpp.charOrStringContents = vStringNew();
285
286 Cpp.resolveRequired = false;
287 Cpp.hasAtLiteralStrings = hasAtLiteralStrings;
288 Cpp.hasCxxRawLiteralStrings = hasCxxRawLiteralStrings;
289 Cpp.hasSingleQuoteLiteralNumbers = hasSingleQuoteLiteralNumbers;
290
291 if (defineMacroKindIndex != KIND_GHOST_INDEX)
292 {
293 Cpp.defineMacroKindIndex = defineMacroKindIndex;
294 Cpp.useClientLangDefineMacroKindIndex = true;
295
296 Cpp.macroUndefRoleIndex = macroUndefRoleIndex;
297 Cpp.macroConditionRoleIndex = macroConditionRoleIndex;
298 Cpp.macrodefFieldIndex = macrodefFieldIndex;
299 }
300 else
301 {
302 Cpp.defineMacroKindIndex = CPREPRO_MACRO;
303 Cpp.useClientLangDefineMacroKindIndex = false;
304
305 Cpp.macroUndefRoleIndex = CPREPRO_MACRO_KIND_UNDEF_ROLE;
306 Cpp.macroConditionRoleIndex = CPREPRO_MACRO_KIND_CONDITION_ROLE;
307 Cpp.macrodefFieldIndex = CPreProFields [F_MACRODEF].ftype;
308 }
309
310 if (macroParamKindIndex != KIND_GHOST_INDEX)
311 {
312 Cpp.macroParamKindIndex = macroParamKindIndex;
313 Cpp.useClientLangMacroParamKindIndex = true;
314 }
315 else
316 {
317 Cpp.macroParamKindIndex = CPREPRO_PARAM;
318 Cpp.useClientLangMacroParamKindIndex = false;
319 }
320
321 if (headerKindIndex != KIND_GHOST_INDEX)
322 {
323 Cpp.headerKindIndex = headerKindIndex;
324 Cpp.useClientLangHeaderKindIndex = true;
325
326 Cpp.headerSystemRoleIndex = headerSystemRoleIndex;
327 Cpp.headerLocalRoleIndex = headerLocalRoleIndex;
328 }
329 else
330 {
331 Cpp.headerKindIndex = CPREPRO_HEADER;
332 Cpp.useClientLangHeaderKindIndex = false;
333
334 Cpp.headerSystemRoleIndex = CPREPRO_HEADER_KIND_SYSTEM_ROLE;
335 Cpp.headerLocalRoleIndex = CPREPRO_HEADER_KIND_LOCAL_ROLE;
336 }
337
338 Cpp.directive.state = DRCTV_NONE;
339 Cpp.directive.accept = true;
340 Cpp.directive.nestLevel = 0;
341
342 Cpp.directive.ifdef [0].ignoreAllBranches = false;
343 Cpp.directive.ifdef [0].singleBranch = false;
344 Cpp.directive.ifdef [0].branchChosen = false;
345 Cpp.directive.ifdef [0].ignoring = false;
346
347 Cpp.directive.name = vStringNewOrClear (Cpp.directive.name);
348
349 Cpp.macroInUse = NULL;
350 Cpp.fileMacroTable =
351 (doesExpandMacros
352 && isFieldEnabled (FIELD_SIGNATURE)
353 && isFieldEnabled (Cpp.macrodefFieldIndex)
354 && (getLanguageCorkUsage ((clientLang == LANG_IGNORE)
355 ? Cpp.lang
356 : clientLang) & CORK_SYMTAB))
357 ? makeMacroTable ()
358 : NULL;
359 }
360
cppInit(const bool state,const bool hasAtLiteralStrings,const bool hasCxxRawLiteralStrings,const bool hasSingleQuoteLiteralNumbers,int defineMacroKindIndex,int macroUndefRoleIndex,int macroConditionRoleIndex,int macroParamKindIndex,int headerKindIndex,int headerSystemRoleIndex,int headerLocalRoleIndex,int macrodefFieldIndex)361 extern void cppInit (const bool state, const bool hasAtLiteralStrings,
362 const bool hasCxxRawLiteralStrings,
363 const bool hasSingleQuoteLiteralNumbers,
364 int defineMacroKindIndex,
365 int macroUndefRoleIndex,
366 int macroConditionRoleIndex,
367 int macroParamKindIndex,
368 int headerKindIndex,
369 int headerSystemRoleIndex, int headerLocalRoleIndex,
370 int macrodefFieldIndex)
371 {
372 langType client = getInputLanguage ();
373
374 cppInitCommon (client, state, hasAtLiteralStrings,
375 hasCxxRawLiteralStrings, hasSingleQuoteLiteralNumbers,
376 defineMacroKindIndex, macroUndefRoleIndex, macroConditionRoleIndex,
377 macroParamKindIndex,
378 headerKindIndex, headerSystemRoleIndex, headerLocalRoleIndex,
379 macrodefFieldIndex);
380 }
381
cppClearMacroInUse(cppMacroInfo ** pM)382 static void cppClearMacroInUse (cppMacroInfo **pM)
383 {
384 for (cppMacroInfo *p = *pM; p; p = p->next)
385 {
386 CXX_DEBUG_PRINT("Macro <%p> clear useCount: %d -> 0", p, p->useCount);
387 p->useCount = 0;
388 }
389 *pM = NULL;
390 }
391
cppTerminate(void)392 extern void cppTerminate (void)
393 {
394 if (Cpp.directive.name != NULL)
395 {
396 vStringDelete (Cpp.directive.name);
397 Cpp.directive.name = NULL;
398 }
399
400 if(Cpp.ungetBuffer)
401 {
402 eFree(Cpp.ungetBuffer);
403 Cpp.ungetBuffer = NULL;
404 }
405
406 if(Cpp.charOrStringContents)
407 {
408 vStringDelete(Cpp.charOrStringContents);
409 Cpp.charOrStringContents = NULL;
410 }
411
412 Cpp.clientLang = LANG_IGNORE;
413
414 cppClearMacroInUse (&Cpp.macroInUse);
415
416 if (Cpp.fileMacroTable)
417 {
418 hashTableDelete (Cpp.fileMacroTable);
419 Cpp.fileMacroTable = NULL;
420 }
421 }
422
cppBeginStatement(void)423 extern void cppBeginStatement (void)
424 {
425 Cpp.resolveRequired = true;
426 }
427
cppEndStatement(void)428 extern void cppEndStatement (void)
429 {
430 Cpp.resolveRequired = false;
431 }
432
433 /*
434 * Scanning functions
435 *
436 * This section handles preprocessor directives. It strips out all
437 * directives and may emit a tag for #define directives.
438 */
439
440 /* This puts a character back into the input queue for the input File. */
cppUngetc(const int c)441 extern void cppUngetc (const int c)
442 {
443 if(!Cpp.ungetPointer)
444 {
445 // no unget data
446 if(!Cpp.ungetBuffer)
447 {
448 Cpp.ungetBuffer = (int *)eMalloc(8 * sizeof(int));
449 Cpp.ungetBufferSize = 8;
450 }
451 Assert(Cpp.ungetBufferSize > 0);
452 Cpp.ungetPointer = Cpp.ungetBuffer + Cpp.ungetBufferSize - 1;
453 *(Cpp.ungetPointer) = c;
454 Cpp.ungetDataSize = 1;
455 return;
456 }
457
458 // Already have some unget data in the buffer. Must prepend.
459 Assert(Cpp.ungetBuffer);
460 Assert(Cpp.ungetBufferSize > 0);
461 Assert(Cpp.ungetDataSize > 0);
462 Assert(Cpp.ungetPointer >= Cpp.ungetBuffer);
463
464 if(Cpp.ungetPointer == Cpp.ungetBuffer)
465 {
466 Cpp.ungetBufferSize += 8;
467 int * tmp = (int *)eMalloc(Cpp.ungetBufferSize * sizeof(int));
468 memcpy(tmp+8,Cpp.ungetPointer,Cpp.ungetDataSize * sizeof(int));
469 eFree(Cpp.ungetBuffer);
470 Cpp.ungetBuffer = tmp;
471 Cpp.ungetPointer = tmp + 7;
472 } else {
473 Cpp.ungetPointer--;
474 }
475
476 *(Cpp.ungetPointer) = c;
477 Cpp.ungetDataSize++;
478 }
479
cppUngetBufferSize()480 int cppUngetBufferSize()
481 {
482 return Cpp.ungetBufferSize;
483 }
484
485 /* This puts an entire string back into the input queue for the input File. */
cppUngetString(const char * string,int len)486 void cppUngetString(const char * string,int len)
487 {
488 if(!string)
489 return;
490 if(len < 1)
491 return;
492
493 if(!Cpp.ungetPointer)
494 {
495 // no unget data
496 if(!Cpp.ungetBuffer)
497 {
498 Cpp.ungetBufferSize = 8 + len;
499 Cpp.ungetBuffer = (int *)eMalloc(Cpp.ungetBufferSize * sizeof(int));
500 } else if(Cpp.ungetBufferSize < len)
501 {
502 Cpp.ungetBufferSize = 8 + len;
503 Cpp.ungetBuffer = (int *)eRealloc(Cpp.ungetBuffer,Cpp.ungetBufferSize * sizeof(int));
504 }
505 Cpp.ungetPointer = Cpp.ungetBuffer + Cpp.ungetBufferSize - len;
506 } else {
507 // Already have some unget data in the buffer. Must prepend.
508 Assert(Cpp.ungetBuffer);
509 Assert(Cpp.ungetBufferSize > 0);
510 Assert(Cpp.ungetDataSize > 0);
511 Assert(Cpp.ungetPointer >= Cpp.ungetBuffer);
512
513 if(Cpp.ungetBufferSize < (Cpp.ungetDataSize + len))
514 {
515 Cpp.ungetBufferSize = 8 + len + Cpp.ungetDataSize;
516 int * tmp = (int *)eMalloc(Cpp.ungetBufferSize * sizeof(int));
517 memcpy(tmp + 8 + len,Cpp.ungetPointer,Cpp.ungetDataSize * sizeof(int));
518 eFree(Cpp.ungetBuffer);
519 Cpp.ungetBuffer = tmp;
520 Cpp.ungetPointer = tmp + 8;
521 } else {
522 Cpp.ungetPointer -= len;
523 Assert(Cpp.ungetPointer >= Cpp.ungetBuffer);
524 }
525 }
526
527 int * p = Cpp.ungetPointer;
528 const char * s = string;
529 const char * e = string + len;
530
531 while(s < e)
532 *p++ = *s++;
533
534 Cpp.ungetDataSize += len;
535 }
536
cppUngetStringBuiltByMacro(const char * string,int len,cppMacroInfo * macro)537 extern void cppUngetStringBuiltByMacro(const char * string,int len, cppMacroInfo *macro)
538 {
539 if (macro->useCount == 0)
540 {
541 cppMacroInfo *m = Cpp.macroInUse;
542 Cpp.macroInUse = macro;
543 macro->next = m;
544 }
545 macro->useCount++;
546
547 CXX_DEBUG_PRINT("Macro <%p> increment useCount: %d->%d", macro,
548 (macro->useCount - 1), macro->useCount);
549
550 cppUngetString (string, len);
551 }
552
cppGetcFromUngetBufferOrFile(void)553 static int cppGetcFromUngetBufferOrFile(void)
554 {
555 if(Cpp.ungetPointer)
556 {
557 Assert(Cpp.ungetBuffer);
558 Assert(Cpp.ungetBufferSize > 0);
559 Assert(Cpp.ungetDataSize > 0);
560
561 int c = *(Cpp.ungetPointer);
562 Cpp.ungetDataSize--;
563 if(Cpp.ungetDataSize > 0)
564 Cpp.ungetPointer++;
565 else
566 Cpp.ungetPointer = NULL;
567 return c;
568 }
569
570 if (Cpp.macroInUse)
571 cppClearMacroInUse (&Cpp.macroInUse);
572 return getcFromInputFile();
573 }
574
575
576 /* Reads a directive, whose first character is given by "c", into "name".
577 */
readDirective(int c,char * const name,unsigned int maxLength)578 static bool readDirective (int c, char *const name, unsigned int maxLength)
579 {
580 unsigned int i;
581
582 for (i = 0 ; i < maxLength - 1 ; ++i)
583 {
584 if (i > 0)
585 {
586 c = cppGetcFromUngetBufferOrFile ();
587 if (c == EOF || ! isalpha (c))
588 {
589 cppUngetc (c);
590 break;
591 }
592 }
593 name [i] = c;
594 }
595 name [i] = '\0'; /* null terminate */
596
597 return (bool) isspacetab (c);
598 }
599
600 /* Reads an identifier, whose first character is given by "c", into "tag",
601 * together with the file location and corresponding line number.
602 */
readIdentifier(int c,vString * const name)603 static void readIdentifier (int c, vString *const name)
604 {
605 vStringClear (name);
606 do
607 {
608 vStringPut (name, c);
609 c = cppGetcFromUngetBufferOrFile ();
610 } while (c != EOF && cppIsident (c));
611 cppUngetc (c);
612 }
613
readFilename(int c,vString * const name)614 static void readFilename (int c, vString *const name)
615 {
616 int c_end = (c == '<')? '>': '"';
617
618 vStringClear (name);
619
620 while (c = cppGetcFromUngetBufferOrFile (), (c != EOF && c != c_end && c != '\n'))
621 vStringPut (name, c);
622 }
623
currentConditional(void)624 static conditionalInfo *currentConditional (void)
625 {
626 return &Cpp.directive.ifdef [Cpp.directive.nestLevel];
627 }
628
isIgnore(void)629 static bool isIgnore (void)
630 {
631 return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring;
632 }
633
setIgnore(const bool ignore)634 static bool setIgnore (const bool ignore)
635 {
636 return Cpp.directive.ifdef [Cpp.directive.nestLevel].ignoring = ignore;
637 }
638
isIgnoreBranch(void)639 static bool isIgnoreBranch (void)
640 {
641 conditionalInfo *const ifdef = currentConditional ();
642
643 /* Force a single branch if an incomplete statement is discovered
644 * en route. This may have allowed earlier branches containing complete
645 * statements to be followed, but we must follow no further branches.
646 */
647
648 /*
649 * CXX: Force a single branch if the external parser (cxx) block nest level at the beginning
650 * of this conditional is not equal to the current block nest level (at exit of the first branch).
651 *
652 * Follow both branches example: (same state at enter and exit)
653 *
654 * #if something
655 * xxxxx;
656 * #else
657 * yyyy;
658 * #endif
659 *
660 * Follow single branch example: (different block level at enter and exit)
661 *
662 * if {
663 * #if something
664 * } else x;
665 * #else
666 * }
667 * #endif
668 */
669
670 if (
671 (Cpp.resolveRequired || (ifdef->enterExternalParserBlockNestLevel != externalParserBlockNestLevel)) &&
672 (!BraceFormat)
673 )
674 {
675 CXX_DEBUG_PRINT("Choosing single branch");
676 ifdef->singleBranch = true;
677 }
678
679 /* We will ignore this branch in the following cases:
680 *
681 * 1. We are ignoring all branches (conditional was within an ignored
682 * branch of the parent conditional)
683 * 2. A branch has already been chosen and either of:
684 * a. A statement was incomplete upon entering the conditional
685 * b. A statement is incomplete upon encountering a branch
686 */
687 return (bool) (ifdef->ignoreAllBranches ||
688 (ifdef->branchChosen && ifdef->singleBranch));
689 }
690
chooseBranch(void)691 static void chooseBranch (void)
692 {
693 if (! BraceFormat)
694 {
695 conditionalInfo *const ifdef = currentConditional ();
696
697 ifdef->branchChosen = (bool) (ifdef->singleBranch ||
698 Cpp.resolveRequired);
699 }
700 }
701
702 /* Pushes one nesting level for an #if directive, indicating whether or not
703 * the branch should be ignored and whether a branch has already been chosen.
704 */
pushConditional(const bool firstBranchChosen)705 static bool pushConditional (const bool firstBranchChosen)
706 {
707 const bool ignoreAllBranches = isIgnore (); /* current ignore */
708 bool ignoreBranch = false;
709
710 if (Cpp.directive.nestLevel < (unsigned int) MaxCppNestingLevel - 1)
711 {
712 conditionalInfo *ifdef;
713
714 ++Cpp.directive.nestLevel;
715 ifdef = currentConditional ();
716
717 /* We take a snapshot of whether there is an incomplete statement in
718 * progress upon encountering the preprocessor conditional. If so,
719 * then we will flag that only a single branch of the conditional
720 * should be followed.
721 */
722 ifdef->ignoreAllBranches = ignoreAllBranches;
723 ifdef->singleBranch = Cpp.resolveRequired;
724 ifdef->branchChosen = firstBranchChosen;
725 ifdef->ignoring = (bool) (ignoreAllBranches || (
726 ! firstBranchChosen && ! BraceFormat &&
727 (ifdef->singleBranch || !doesExaminCodeWithInIf0Branch)));
728 ifdef->enterExternalParserBlockNestLevel = externalParserBlockNestLevel;
729 ignoreBranch = ifdef->ignoring;
730 }
731 return ignoreBranch;
732 }
733
734 /* Pops one nesting level for an #endif directive.
735 */
popConditional(void)736 static bool popConditional (void)
737 {
738 if (Cpp.directive.nestLevel > 0)
739 --Cpp.directive.nestLevel;
740
741 return isIgnore ();
742 }
743
doesCPreProRunAsStandaloneParser(int kind)744 static bool doesCPreProRunAsStandaloneParser (int kind)
745 {
746 if (kind == CPREPRO_HEADER)
747 return !Cpp.useClientLangDefineMacroKindIndex;
748 else if (kind == CPREPRO_MACRO)
749 return !Cpp.useClientLangHeaderKindIndex;
750 else if (kind == CPREPRO_PARAM)
751 return !Cpp.useClientLangMacroParamKindIndex;
752 else
753 {
754 AssertNotReached();
755 return true;
756 }
757 }
758
makeDefineTag(const char * const name,const char * const signature,bool undef)759 static int makeDefineTag (const char *const name, const char* const signature, bool undef)
760 {
761 bool standing_alone = doesCPreProRunAsStandaloneParser(CPREPRO_MACRO);
762 langType lang = standing_alone ? Cpp.lang: Cpp.clientLang;
763 const bool isFileScope = (bool) (! isInputHeaderFile ());
764
765 if (!isLanguageEnabled (lang))
766 return CORK_NIL;
767
768 Assert (Cpp.defineMacroKindIndex != KIND_GHOST_INDEX);
769
770 if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE))
771 return CORK_NIL;
772
773 if (undef && (Cpp.macroUndefRoleIndex == ROLE_DEFINITION_INDEX))
774 return CORK_NIL;
775
776 if (! isLanguageKindEnabled (lang,
777 Cpp.defineMacroKindIndex))
778 return CORK_NIL;
779
780 if (
781 /* condition for definition tag */
782 (!undef)
783 || /* condition for reference tag */
784 (undef && isXtagEnabled(XTAG_REFERENCE_TAGS) &&
785 isLanguageRoleEnabled(lang, Cpp.defineMacroKindIndex,
786 Cpp.macroUndefRoleIndex)))
787 {
788 tagEntryInfo e;
789 int r;
790
791 if (standing_alone)
792 pushLanguage (Cpp.lang);
793
794 if (undef)
795 initRefTagEntry (&e, name, Cpp.defineMacroKindIndex,
796 Cpp.macroUndefRoleIndex);
797 else
798 initTagEntry (&e, name, Cpp.defineMacroKindIndex);
799 e.isFileScope = isFileScope;
800 if (isFileScope)
801 markTagExtraBit (&e, XTAG_FILE_SCOPE);
802 e.truncateLineAfterTag = true;
803 e.extensionFields.signature = signature;
804
805 r = makeTagEntry (&e);
806
807 if (standing_alone)
808 popLanguage ();
809
810 return r;
811 }
812 return CORK_NIL;
813 }
814
makeIncludeTag(const char * const name,bool systemHeader)815 static void makeIncludeTag (const char *const name, bool systemHeader)
816 {
817 bool standing_alone = doesCPreProRunAsStandaloneParser(CPREPRO_HEADER);
818 langType lang = standing_alone ? Cpp.lang: Cpp.clientLang;
819 tagEntryInfo e;
820 int role_index;
821
822 if (!isLanguageEnabled (lang))
823 return;
824
825 Assert (Cpp.headerKindIndex != KIND_GHOST_INDEX);
826
827 role_index = systemHeader? Cpp.headerSystemRoleIndex: Cpp.headerLocalRoleIndex;
828 if (role_index == ROLE_DEFINITION_INDEX)
829 return;
830
831 if (!isXtagEnabled (XTAG_REFERENCE_TAGS))
832 return;
833
834 if (!isLanguageKindEnabled(lang, Cpp.headerKindIndex))
835 return;
836
837 if (isLanguageRoleEnabled(lang, Cpp.headerKindIndex, role_index))
838 {
839 if (standing_alone)
840 pushLanguage (Cpp.lang);
841
842 initRefTagEntry (&e, name, Cpp.headerKindIndex, role_index);
843 e.isFileScope = false;
844 e.truncateLineAfterTag = true;
845 makeTagEntry (&e);
846
847 if (standing_alone)
848 popLanguage ();
849 }
850 }
851
makeParamTag(vString * name,short nth,bool placeholder)852 static void makeParamTag (vString *name, short nth, bool placeholder)
853 {
854 bool standing_alone = doesCPreProRunAsStandaloneParser(CPREPRO_MACRO);
855
856 Assert (Cpp.macroParamKindIndex != KIND_GHOST_INDEX);
857
858 if (standing_alone)
859 pushLanguage (Cpp.lang);
860 int r = makeSimpleTag (name, Cpp.macroParamKindIndex);
861 if (standing_alone)
862 popLanguage ();
863
864 tagEntryInfo *e = getEntryInCorkQueue (r);
865 if (e)
866 {
867 e->extensionFields.nth = nth;
868 if (placeholder)
869 e->placeholder = 1;
870 }
871 }
872
regenreateSignatureFromParameters(vString * buffer,int from,int to)873 static void regenreateSignatureFromParameters (vString * buffer, int from, int to)
874 {
875 vStringPut(buffer, '(');
876 for (int pindex = from; pindex < to; pindex++)
877 {
878 tagEntryInfo *e = getEntryInCorkQueue (pindex);
879 if (e && !isTagExtra (e))
880 {
881 vStringCatS (buffer, e->name);
882 vStringPut (buffer, ',');
883 }
884 }
885 if (vStringLast (buffer) == ',')
886 vStringChop (buffer);
887 vStringPut (buffer, ')');
888 }
889
patchScopeFieldOfParameters(int from,int to,int parentIndex)890 static void patchScopeFieldOfParameters(int from, int to, int parentIndex)
891 {
892 for (int pindex = from; pindex < to; pindex++)
893 {
894 tagEntryInfo *e = getEntryInCorkQueue (pindex);
895 if (e)
896 e->extensionFields.scopeIndex = parentIndex;
897 }
898 }
899
directiveDefine(const int c,bool undef)900 static int directiveDefine (const int c, bool undef)
901 {
902 // FIXME: We could possibly handle the macros here!
903 // However we'd need a separate hash table for macros of the current file
904 // to avoid breaking the "global" ones.
905
906 int r = CORK_NIL;
907
908 if (cppIsident1 (c))
909 {
910 readIdentifier (c, Cpp.directive.name);
911 if (! isIgnore ())
912 {
913 unsigned long lineNumber = getInputLineNumber ();
914 MIOPos filePosition = getInputFilePosition ();
915 int p = cppGetcFromUngetBufferOrFile ();
916 short nth = 0;
917
918 if (p == '(')
919 {
920 vString *param = vStringNew ();
921 int param_start = (int)countEntryInCorkQueue();
922 do {
923 p = cppGetcFromUngetBufferOrFile ();
924 if (isalnum(p) || p == '_' || p == '$'
925 /* Handle variadic macros like (a,...) */
926 || p == '.')
927 {
928 vStringPut (param, p);
929 continue;
930 }
931
932 if (vStringLength (param) > 0)
933 {
934 makeParamTag (param, nth++, vStringChar(param, 0) == '.');
935 vStringClear (param);
936 }
937 if (p == '\\')
938 cppGetcFromUngetBufferOrFile (); /* Throw away the next char */
939 } while (p != ')' && p != EOF);
940 vStringDelete (param);
941
942 int param_end = (int)countEntryInCorkQueue();
943 if (p == ')')
944 {
945 vString *signature = vStringNew ();
946 regenreateSignatureFromParameters (signature, param_start, param_end);
947 r = makeDefineTag (vStringValue (Cpp.directive.name), vStringValue (signature), undef);
948 vStringDelete (signature);
949 }
950 else
951 r = makeDefineTag (vStringValue (Cpp.directive.name), NULL, undef);
952
953 tagEntryInfo *e = getEntryInCorkQueue (r);
954 if (e)
955 {
956 e->lineNumber = lineNumber;
957 e->filePosition = filePosition;
958 patchScopeFieldOfParameters (param_start, param_end, r);
959 }
960 }
961 else
962 {
963 cppUngetc (p);
964 r = makeDefineTag (vStringValue (Cpp.directive.name), NULL, undef);
965 }
966 }
967 }
968 Cpp.directive.state = DRCTV_NONE;
969
970 if (r != CORK_NIL && Cpp.fileMacroTable)
971 registerEntry (r);
972 return r;
973 }
974
directiveUndef(const int c)975 static void directiveUndef (const int c)
976 {
977 if (isXtagEnabled (XTAG_REFERENCE_TAGS))
978 {
979 directiveDefine (c, true);
980 }
981 else
982 {
983 Cpp.directive.state = DRCTV_NONE;
984 }
985 }
986
directivePragma(int c)987 static void directivePragma (int c)
988 {
989 if (cppIsident1 (c))
990 {
991 readIdentifier (c, Cpp.directive.name);
992 if (stringMatch (vStringValue (Cpp.directive.name), "weak"))
993 {
994 /* generate macro tag for weak name */
995 do
996 {
997 c = cppGetcFromUngetBufferOrFile ();
998 } while (c == SPACE);
999 if (cppIsident1 (c))
1000 {
1001 readIdentifier (c, Cpp.directive.name);
1002 makeDefineTag (vStringValue (Cpp.directive.name), NULL, false);
1003 }
1004 }
1005 }
1006 Cpp.directive.state = DRCTV_NONE;
1007 }
1008
directiveIf(const int c)1009 static bool directiveIf (const int c)
1010 {
1011 DebugStatement ( const bool ignore0 = isIgnore (); )
1012 const bool ignore = pushConditional ((bool) (c != '0'));
1013
1014 Cpp.directive.state = DRCTV_NONE;
1015 DebugStatement ( debugCppNest (true, Cpp.directive.nestLevel);
1016 if (ignore != ignore0) debugCppIgnore (ignore); )
1017
1018 return ignore;
1019 }
1020
directiveElif(const int c)1021 static void directiveElif (const int c)
1022 {
1023 Cpp.directive.state = DRCTV_NONE;
1024 }
1025
directiveInclude(const int c)1026 static void directiveInclude (const int c)
1027 {
1028 if (c == '<' || c == '"')
1029 {
1030 readFilename (c, Cpp.directive.name);
1031 if ((! isIgnore ()) && vStringLength (Cpp.directive.name))
1032 makeIncludeTag (vStringValue (Cpp.directive.name),
1033 c == '<');
1034 }
1035 Cpp.directive.state = DRCTV_NONE;
1036 }
1037
directiveHash(const int c)1038 static bool directiveHash (const int c)
1039 {
1040 bool ignore = false;
1041 char directive [MaxDirectiveName];
1042 DebugStatement ( const bool ignore0 = isIgnore (); )
1043
1044 readDirective (c, directive, MaxDirectiveName);
1045 if (stringMatch (directive, "define"))
1046 Cpp.directive.state = DRCTV_DEFINE;
1047 else if (stringMatch (directive, "include"))
1048 Cpp.directive.state = DRCTV_INCLUDE;
1049 else if (stringMatch (directive, "undef"))
1050 Cpp.directive.state = DRCTV_UNDEF;
1051 else if (strncmp (directive, "if", (size_t) 2) == 0)
1052 Cpp.directive.state = DRCTV_IF;
1053 else if (stringMatch (directive, "elif") ||
1054 stringMatch (directive, "else"))
1055 {
1056 ignore = setIgnore (isIgnoreBranch ());
1057 CXX_DEBUG_PRINT("Found #elif or #else: ignore is %d",ignore);
1058 if (! ignore && stringMatch (directive, "else"))
1059 chooseBranch ();
1060 Cpp.directive.state = (directive[2] == 'i')? DRCTV_ELIF: DRCTV_NONE;
1061 DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
1062 }
1063 else if (stringMatch (directive, "endif"))
1064 {
1065 DebugStatement ( debugCppNest (false, Cpp.directive.nestLevel); )
1066 ignore = popConditional ();
1067 Cpp.directive.state = DRCTV_NONE;
1068 DebugStatement ( if (ignore != ignore0) debugCppIgnore (ignore); )
1069 }
1070 else if (stringMatch (directive, "pragma"))
1071 Cpp.directive.state = DRCTV_PRAGMA;
1072 else
1073 Cpp.directive.state = DRCTV_NONE;
1074
1075 return ignore;
1076 }
1077
1078 /* Handles a pre-processor directive whose first character is given by "c".
1079 */
handleDirective(const int c,int * macroCorkIndex,bool * inspect_conidtion)1080 static bool handleDirective (const int c, int *macroCorkIndex, bool *inspect_conidtion)
1081 {
1082 bool ignore = isIgnore ();
1083
1084 switch (Cpp.directive.state)
1085 {
1086 case DRCTV_NONE: ignore = isIgnore (); break;
1087 case DRCTV_DEFINE:
1088 *macroCorkIndex = directiveDefine (c, false);
1089 break;
1090 case DRCTV_HASH: ignore = directiveHash (c); break;
1091 case DRCTV_IF:
1092 ignore = directiveIf (c);
1093 *inspect_conidtion = true;
1094 break;
1095 case DRCTV_ELIF:
1096 directiveElif (c);
1097 *inspect_conidtion = true;
1098 break;
1099 case DRCTV_PRAGMA: directivePragma (c); break;
1100 case DRCTV_UNDEF: directiveUndef (c); break;
1101 case DRCTV_INCLUDE: directiveInclude (c); break;
1102 }
1103 return ignore;
1104 }
1105
1106 /* Called upon reading of a slash ('/') characters, determines whether a
1107 * comment is encountered, and its type.
1108 */
isComment(void)1109 static Comment isComment (void)
1110 {
1111 Comment comment;
1112 const int next = cppGetcFromUngetBufferOrFile ();
1113
1114 if (next == '*')
1115 comment = COMMENT_C;
1116 else if (next == '/')
1117 comment = COMMENT_CPLUS;
1118 else if (next == '+')
1119 comment = COMMENT_D;
1120 else
1121 {
1122 cppUngetc (next);
1123 comment = COMMENT_NONE;
1124 }
1125 return comment;
1126 }
1127
1128 /* Skips over a C style comment. According to ANSI specification a comment
1129 * is treated as white space, so we perform this substitution.
1130 */
cppSkipOverCComment(void)1131 static int cppSkipOverCComment (void)
1132 {
1133 int c = cppGetcFromUngetBufferOrFile ();
1134
1135 while (c != EOF)
1136 {
1137 if (c != '*')
1138 c = cppGetcFromUngetBufferOrFile ();
1139 else
1140 {
1141 const int next = cppGetcFromUngetBufferOrFile ();
1142
1143 if (next != '/')
1144 c = next;
1145 else
1146 {
1147 c = SPACE; /* replace comment with space */
1148 break;
1149 }
1150 }
1151 }
1152 return c;
1153 }
1154
1155 /* Skips over a C++ style comment.
1156 */
skipOverCplusComment(void)1157 static int skipOverCplusComment (void)
1158 {
1159 int c;
1160
1161 while ((c = cppGetcFromUngetBufferOrFile ()) != EOF)
1162 {
1163 if (c == BACKSLASH)
1164 cppGetcFromUngetBufferOrFile (); /* throw away next character, too */
1165 else if (c == NEWLINE)
1166 break;
1167 }
1168 return c;
1169 }
1170
1171 /* Skips over a D style comment.
1172 * Really we should match nested /+ comments. At least they're less common.
1173 */
skipOverDComment(void)1174 static int skipOverDComment (void)
1175 {
1176 int c = cppGetcFromUngetBufferOrFile ();
1177
1178 while (c != EOF)
1179 {
1180 if (c != '+')
1181 c = cppGetcFromUngetBufferOrFile ();
1182 else
1183 {
1184 const int next = cppGetcFromUngetBufferOrFile ();
1185
1186 if (next != '/')
1187 c = next;
1188 else
1189 {
1190 c = SPACE; /* replace comment with space */
1191 break;
1192 }
1193 }
1194 }
1195 return c;
1196 }
1197
cppGetLastCharOrStringContents(void)1198 const vString * cppGetLastCharOrStringContents (void)
1199 {
1200 CXX_DEBUG_ASSERT(Cpp.charOrStringContents,"Shouldn't be called when CPP is not initialized");
1201 return Cpp.charOrStringContents;
1202 }
1203
1204 /* Skips to the end of a string, returning a special character to
1205 * symbolically represent a generic string.
1206 */
skipToEndOfString(bool ignoreBackslash)1207 static int skipToEndOfString (bool ignoreBackslash)
1208 {
1209 int c;
1210
1211 vStringClear(Cpp.charOrStringContents);
1212
1213 while ((c = cppGetcFromUngetBufferOrFile ()) != EOF)
1214 {
1215 if (c == BACKSLASH && ! ignoreBackslash)
1216 {
1217 vStringPutWithLimit (Cpp.charOrStringContents, c, 1024);
1218 c = cppGetcFromUngetBufferOrFile (); /* throw away next character, too */
1219 if (c != EOF)
1220 vStringPutWithLimit (Cpp.charOrStringContents, c, 1024);
1221 }
1222 else if (c == DOUBLE_QUOTE)
1223 break;
1224 else
1225 vStringPutWithLimit (Cpp.charOrStringContents, c, 1024);
1226 }
1227 return STRING_SYMBOL; /* symbolic representation of string */
1228 }
1229
isCxxRawLiteralDelimiterChar(int c)1230 static int isCxxRawLiteralDelimiterChar (int c)
1231 {
1232 return (c != ' ' && c != '\f' && c != '\n' && c != '\r' && c != '\t' && c != '\v' &&
1233 c != '(' && c != ')' && c != '\\');
1234 }
1235
skipToEndOfCxxRawLiteralString(void)1236 static int skipToEndOfCxxRawLiteralString (void)
1237 {
1238 int c = cppGetcFromUngetBufferOrFile ();
1239
1240 if (c != '(' && ! isCxxRawLiteralDelimiterChar (c))
1241 {
1242 cppUngetc (c);
1243 c = skipToEndOfString (false);
1244 }
1245 else
1246 {
1247 char delim[16];
1248 unsigned int delimLen = 0;
1249 bool collectDelim = true;
1250
1251 do
1252 {
1253 if (collectDelim)
1254 {
1255 if (isCxxRawLiteralDelimiterChar (c) &&
1256 delimLen < (sizeof delim / sizeof *delim))
1257 delim[delimLen++] = c;
1258 else
1259 collectDelim = false;
1260 }
1261 else if (c == ')')
1262 {
1263 unsigned int i = 0;
1264
1265 while ((c = cppGetcFromUngetBufferOrFile ()) != EOF && i < delimLen && delim[i] == c)
1266 i++;
1267 if (i == delimLen && c == DOUBLE_QUOTE)
1268 break;
1269 else
1270 cppUngetc (c);
1271 }
1272 }
1273 while ((c = cppGetcFromUngetBufferOrFile ()) != EOF);
1274 c = STRING_SYMBOL;
1275 }
1276 return c;
1277 }
1278
1279 /* Skips to the end of the three (possibly four) 'c' sequence, returning a
1280 * special character to symbolically represent a generic character.
1281 * Also detects Vera numbers that include a base specifier (ie. 'b1010).
1282 */
skipToEndOfChar()1283 static int skipToEndOfChar ()
1284 {
1285 int c;
1286 int count = 0, veraBase = '\0';
1287
1288 vStringClear(Cpp.charOrStringContents);
1289
1290 while ((c = cppGetcFromUngetBufferOrFile ()) != EOF)
1291 {
1292 ++count;
1293 if (c == BACKSLASH)
1294 {
1295 vStringPutWithLimit (Cpp.charOrStringContents, c, 10);
1296 c = cppGetcFromUngetBufferOrFile (); /* throw away next character, too */
1297 if (c != EOF)
1298 vStringPutWithLimit (Cpp.charOrStringContents, c, 10);
1299 }
1300 else if (c == SINGLE_QUOTE)
1301 break;
1302 else if (c == NEWLINE)
1303 {
1304 cppUngetc (c);
1305 break;
1306 }
1307 else if (Cpp.hasSingleQuoteLiteralNumbers)
1308 {
1309 if (count == 1 && strchr ("DHOB", toupper (c)) != NULL)
1310 {
1311 veraBase = c;
1312 vStringPutWithLimit (Cpp.charOrStringContents, c, 10);
1313 }
1314 else if (veraBase != '\0' && ! isalnum (c))
1315 {
1316 cppUngetc (c);
1317 break;
1318 }
1319 else
1320 vStringPutWithLimit (Cpp.charOrStringContents, c, 10);
1321 }
1322 else
1323 vStringPutWithLimit (Cpp.charOrStringContents, c, 10);
1324 }
1325 return CHAR_SYMBOL; /* symbolic representation of character */
1326 }
1327
attachFields(int macroCorkIndex,unsigned long endLine,const char * macrodef)1328 static void attachFields (int macroCorkIndex, unsigned long endLine, const char *macrodef)
1329 {
1330 tagEntryInfo *tag = getEntryInCorkQueue (macroCorkIndex);
1331 if (!tag)
1332 return;
1333
1334 tag->extensionFields.endLine = endLine;
1335 if (macrodef)
1336 attachParserFieldToCorkEntry (macroCorkIndex, Cpp.macrodefFieldIndex, macrodef);
1337 }
1338
conditionMayFlush(vString * condition,bool del)1339 static vString * conditionMayFlush (vString* condition, bool del)
1340 {
1341 bool standing_alone = doesCPreProRunAsStandaloneParser(CPREPRO_MACRO);
1342
1343 if (condition == NULL)
1344 return condition;
1345
1346 size_t len = vStringLength(condition);
1347 if (len > 0
1348 && (! (
1349 (len == 7
1350 && strcmp (vStringValue (condition), "defined") == 0)
1351 )))
1352 {
1353 if (standing_alone)
1354 pushLanguage (Cpp.lang);
1355
1356 makeSimpleRefTag (condition, Cpp.defineMacroKindIndex, Cpp.macroConditionRoleIndex);
1357
1358 if (standing_alone)
1359 popLanguage ();
1360 }
1361
1362 if (del)
1363 {
1364 vStringDelete (condition);
1365 return NULL;
1366 }
1367
1368 vStringClear(condition);
1369 return condition;
1370 }
1371
conditionMayPut(vString * condition,int c)1372 static void conditionMayPut (vString *condition, int c)
1373 {
1374 if (condition == NULL)
1375 return;
1376
1377 if (vStringLength (condition) > 0
1378 || (!isdigit(c)))
1379 vStringPut(condition, c);
1380 }
1381
1382 /* This function returns the next character, stripping out comments,
1383 * C pre-processor directives, and the contents of single and double
1384 * quoted strings. In short, strip anything which places a burden upon
1385 * the tokenizer.
1386 */
cppGetc(void)1387 extern int cppGetc (void)
1388 {
1389 bool directive = false;
1390 bool ignore = false;
1391 int c;
1392 int macroCorkIndex = CORK_NIL;
1393 vString *macrodef = NULL;
1394 vString *condition = NULL;
1395
1396
1397 do {
1398 start_loop:
1399 c = cppGetcFromUngetBufferOrFile ();
1400 process:
1401 switch (c)
1402 {
1403 case EOF:
1404 ignore = false;
1405 directive = false;
1406 if (macroCorkIndex != CORK_NIL)
1407 {
1408 attachFields (macroCorkIndex,
1409 getInputLineNumber(),
1410 macrodef? vStringValue (macrodef): NULL);
1411 macroCorkIndex = CORK_NIL;
1412 }
1413 condition = conditionMayFlush(condition, true);
1414 break;
1415
1416 case TAB:
1417 case SPACE:
1418 if (macrodef && vStringLength (macrodef) > 0
1419 && vStringLast (macrodef) != ' ')
1420 vStringPut (macrodef, ' ');
1421 condition = conditionMayFlush(condition, false);
1422 break; /* ignore most white space */
1423
1424 case NEWLINE:
1425 if (directive)
1426 condition = conditionMayFlush(condition, true);
1427 if (directive && ! ignore)
1428 {
1429 directive = false;
1430 if (macroCorkIndex != CORK_NIL)
1431 {
1432 attachFields (macroCorkIndex,
1433 getInputLineNumber(),
1434 macrodef? vStringValue (macrodef): NULL);
1435 macroCorkIndex = CORK_NIL;
1436 }
1437 }
1438 Cpp.directive.accept = true;
1439 break;
1440
1441 case DOUBLE_QUOTE:
1442 condition = conditionMayFlush(condition, false);
1443
1444 if (Cpp.directive.state == DRCTV_INCLUDE)
1445 goto enter;
1446 else
1447 {
1448 Cpp.directive.accept = false;
1449 c = skipToEndOfString (false);
1450 }
1451
1452 if (macrodef)
1453 {
1454 /* We record the contents of string literal.
1455 *
1456 */
1457 vStringPut (macrodef, '"');
1458 vStringCat (macrodef, Cpp.charOrStringContents);
1459 vStringPut (macrodef, '"');
1460 }
1461
1462 break;
1463
1464 case '#':
1465 condition = conditionMayFlush(condition, false);
1466
1467 if (Cpp.directive.accept)
1468 {
1469 directive = true;
1470 Cpp.directive.state = DRCTV_HASH;
1471 Cpp.directive.accept = false;
1472 }
1473 if (macrodef)
1474 vStringPut (macrodef, '#');
1475 break;
1476
1477 case SINGLE_QUOTE:
1478 condition = conditionMayFlush(condition, false);
1479
1480 Cpp.directive.accept = false;
1481 c = skipToEndOfChar ();
1482
1483 /* We assume none may want to know the content of the
1484 * literal; just put ''. */
1485 if (macrodef)
1486 vStringCatS (macrodef, "''");
1487
1488 break;
1489
1490 case '/':
1491 {
1492 condition = conditionMayFlush(condition, false);
1493
1494 const Comment comment = isComment ();
1495
1496 if (comment == COMMENT_C)
1497 c = cppSkipOverCComment ();
1498 else if (comment == COMMENT_CPLUS)
1499 {
1500 c = skipOverCplusComment ();
1501 if (c == NEWLINE)
1502 cppUngetc (c);
1503 }
1504 else if (comment == COMMENT_D)
1505 c = skipOverDComment ();
1506 else
1507 {
1508 Cpp.directive.accept = false;
1509 if (macrodef)
1510 vStringPut (macrodef, '/');
1511 }
1512 break;
1513 }
1514
1515 case BACKSLASH:
1516 {
1517 condition = conditionMayFlush(condition, false);
1518
1519 int next = cppGetcFromUngetBufferOrFile ();
1520
1521 if (next == NEWLINE)
1522 goto start_loop;
1523 else
1524 {
1525 cppUngetc (next);
1526 if (macrodef)
1527 vStringPut (macrodef, '\\');
1528 }
1529 break;
1530 }
1531
1532 case '?':
1533 {
1534 condition = conditionMayFlush(condition, false);
1535
1536 int next = cppGetcFromUngetBufferOrFile ();
1537 if (next != '?')
1538 {
1539 cppUngetc (next);
1540 if (macrodef)
1541 vStringPut (macrodef, '?');
1542 }
1543 else
1544 {
1545 next = cppGetcFromUngetBufferOrFile ();
1546 switch (next)
1547 {
1548 case '(': c = '['; break;
1549 case ')': c = ']'; break;
1550 case '<': c = '{'; break;
1551 case '>': c = '}'; break;
1552 case '/': c = BACKSLASH; goto process;
1553 case '!': c = '|'; break;
1554 case SINGLE_QUOTE: c = '^'; break;
1555 case '-': c = '~'; break;
1556 case '=': c = '#'; goto process;
1557 default:
1558 cppUngetc ('?');
1559 cppUngetc (next);
1560 break;
1561 }
1562 if (macrodef)
1563 vStringPut (macrodef, c);
1564 }
1565 } break;
1566
1567 /* digraphs:
1568 * input: <: :> <% %> %: %:%:
1569 * output: [ ] { } # ##
1570 */
1571 case '<':
1572 {
1573 condition = conditionMayFlush(condition, false);
1574
1575 /*
1576 Quoted from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3237.html:
1577 ------
1578 if the next three characters are <:: and the
1579 subsequent character is neither : nor >, the < is
1580 treated as a preprocessor token by itself (and not as
1581 the first character of the alternative token */
1582 int next[3];
1583 next[0] = cppGetcFromUngetBufferOrFile ();
1584 switch (next[0])
1585 {
1586 case ':':
1587 next[1] = cppGetcFromUngetBufferOrFile ();
1588 if (next[1] == ':')
1589 {
1590 next[2] = cppGetcFromUngetBufferOrFile ();
1591 if (! (next[2] == ':' || next[2] == '>'))
1592 {
1593 cppUngetc (next[2]);
1594 cppUngetc (next[1]);
1595 cppUngetc (next[0]);
1596 c = '<';
1597 }
1598 else
1599 {
1600 cppUngetc (next[2]);
1601 cppUngetc (next[1]);
1602 c = '[';
1603 }
1604 }
1605 else
1606 {
1607 cppUngetc (next[1]);
1608 c = '[';
1609 }
1610 break;
1611 case '%': c = '{'; break;
1612 default: cppUngetc (next[0]);
1613 }
1614
1615 if (macrodef)
1616 vStringPut (macrodef, c);
1617
1618 goto enter;
1619 }
1620 case ':':
1621 {
1622 condition = conditionMayFlush(condition, false);
1623
1624 int next = cppGetcFromUngetBufferOrFile ();
1625 if (next == '>')
1626 c = ']';
1627 else
1628 cppUngetc (next);
1629
1630 if (macrodef)
1631 vStringPut (macrodef, c);
1632
1633 goto enter;
1634 }
1635 case '%':
1636 {
1637 condition = conditionMayFlush(condition, false);
1638
1639 int next = cppGetcFromUngetBufferOrFile ();
1640 switch (next)
1641 {
1642 case '>': c = '}'; break;
1643 case ':': c = '#'; goto process;
1644 default: cppUngetc (next);
1645 }
1646
1647 if (macrodef)
1648 vStringPut (macrodef, c);
1649
1650 goto enter;
1651 }
1652
1653 default:
1654 if (c == '@' && Cpp.hasAtLiteralStrings)
1655 {
1656 condition = conditionMayFlush(condition, false);
1657
1658 int next = cppGetcFromUngetBufferOrFile ();
1659 if (next == DOUBLE_QUOTE)
1660 {
1661 Cpp.directive.accept = false;
1662 c = skipToEndOfString (true);
1663 if (macrodef)
1664 vStringCatS (macrodef, "@\"\"");
1665 break;
1666 }
1667 else
1668 {
1669 cppUngetc (next);
1670 if (macrodef)
1671 vStringPut (macrodef, '@');
1672 }
1673 }
1674 else if (c == 'R' && Cpp.hasCxxRawLiteralStrings)
1675 {
1676 conditionMayPut(condition, c);
1677
1678 /* OMG!11 HACK!!11 Get the previous character.
1679 *
1680 * We need to know whether the previous character was an identifier or not,
1681 * because "R" has to be on its own, not part of an identifier. This allows
1682 * for constructs like:
1683 *
1684 * #define FOUR "4"
1685 * const char *p = FOUR"5";
1686 *
1687 * which is not a raw literal, but a preprocessor concatenation.
1688 *
1689 * FIXME: handle
1690 *
1691 * const char *p = R\
1692 * "xxx(raw)xxx";
1693 *
1694 * which is perfectly valid (yet probably very unlikely). */
1695 int prev = getNthPrevCFromInputFile (1, '\0');
1696 int prev2 = getNthPrevCFromInputFile (2, '\0');
1697 int prev3 = getNthPrevCFromInputFile (3, '\0');
1698
1699 if (! cppIsident (prev) ||
1700 (! cppIsident (prev2) && (prev == 'L' || prev == 'u' || prev == 'U')) ||
1701 (! cppIsident (prev3) && (prev2 == 'u' && prev == '8')))
1702 {
1703 int next = cppGetcFromUngetBufferOrFile ();
1704 if (next != DOUBLE_QUOTE)
1705 {
1706 cppUngetc (next);
1707 if (macrodef)
1708 vStringPut (macrodef, 'R');
1709 }
1710 else
1711 {
1712 Cpp.directive.accept = false;
1713 c = skipToEndOfCxxRawLiteralString ();
1714
1715 /* We assume none may want to know the content of the
1716 * literal; just put "". */
1717 if (macrodef)
1718 vStringCatS (macrodef, "\"\"");
1719
1720 break;
1721 }
1722 }
1723 else
1724 {
1725 if (macrodef)
1726 vStringPut (macrodef, 'R');
1727 }
1728 }
1729 else if(isxdigit(c))
1730 {
1731 /* Check for digit separator. If we find it we just skip it */
1732 int next = cppGetcFromUngetBufferOrFile();
1733 if(next != SINGLE_QUOTE)
1734 cppUngetc(next);
1735 if (macrodef)
1736 vStringPut (macrodef, c);
1737 conditionMayPut(condition, c);
1738 }
1739 else
1740 {
1741 if (macrodef)
1742 vStringPut (macrodef, c);
1743 if (isalnum(c) || c == '_')
1744 conditionMayPut(condition, c);
1745 else
1746 condition = conditionMayFlush(condition, false);
1747 }
1748 enter:
1749 Cpp.directive.accept = false;
1750 if (directive)
1751 {
1752 bool inspect_conidtion = false;
1753 ignore = handleDirective (c, ¯oCorkIndex, &inspect_conidtion);
1754 if (Cpp.macrodefFieldIndex != FIELD_UNKNOWN
1755 && macroCorkIndex != CORK_NIL
1756 && macrodef == NULL)
1757 macrodef = vStringNew ();
1758 if (condition == NULL
1759 && inspect_conidtion)
1760 {
1761 condition = vStringNew ();
1762 if (isalpha(c) || c == '_')
1763 conditionMayPut(condition, c);
1764 }
1765 }
1766 break;
1767 }
1768 } while (directive || ignore);
1769
1770 if (macrodef)
1771 vStringDelete (macrodef);
1772
1773 if (condition)
1774 vStringDelete (condition);
1775
1776 DebugStatement ( debugPutc (DEBUG_CPP, c); )
1777 DebugStatement ( if (c == NEWLINE)
1778 debugPrintf (DEBUG_CPP, "%6ld: ", getInputLineNumber () + 1); )
1779
1780 return c;
1781 }
1782
findCppTags(void)1783 static void findCppTags (void)
1784 {
1785 cppInitCommon (Cpp.lang, 0, false, false, false,
1786 KIND_GHOST_INDEX, 0, 0,
1787 KIND_GHOST_INDEX,
1788 KIND_GHOST_INDEX, 0, 0,
1789 FIELD_UNKNOWN);
1790
1791 findRegexTagsMainloop (cppGetc);
1792
1793 cppTerminate ();
1794 }
1795
1796
1797 /*
1798 * Token ignore processing
1799 */
1800
1801 static hashTable * cmdlineMacroTable;
1802
1803
buildMacroInfoFromTagEntry(int corkIndex,tagEntryInfo * entry,void * data)1804 static bool buildMacroInfoFromTagEntry (int corkIndex,
1805 tagEntryInfo * entry,
1806 void * data)
1807 {
1808 cppMacroInfo **info = data;
1809
1810 if (entry->langType == Cpp.clientLang
1811 && entry->kindIndex == Cpp.defineMacroKindIndex
1812 && isRoleAssigned (entry, ROLE_DEFINITION_INDEX))
1813 {
1814 vString *macrodef = vStringNewInit (entry->name);
1815 if (entry->extensionFields.signature)
1816 vStringCatS (macrodef, entry->extensionFields.signature);
1817 vStringPut (macrodef, '=');
1818
1819 const char *val = getParserFieldValueForType (entry, Cpp.macrodefFieldIndex);
1820 if (val)
1821 vStringCatS (macrodef, val);
1822
1823 *info = saveMacro (Cpp.fileMacroTable, vStringValue (macrodef));
1824 vStringDelete (macrodef);
1825
1826 return false;
1827 }
1828 return true;
1829 }
1830
cppFindMacroFromSymtab(const char * const name)1831 extern cppMacroInfo * cppFindMacroFromSymtab (const char *const name)
1832 {
1833 cppMacroInfo *info = NULL;
1834 foreachEntriesInScope (CORK_NIL, name, buildMacroInfoFromTagEntry, &info);
1835
1836 return info;
1837 }
1838
1839 /* Determines whether or not "name" should be ignored, per the ignore list.
1840 */
cppFindMacro(const char * const name)1841 extern cppMacroInfo * cppFindMacro (const char *const name)
1842 {
1843 cppMacroInfo *info;
1844
1845 if (cmdlineMacroTable)
1846 {
1847 info = (cppMacroInfo *)hashTableGetItem (cmdlineMacroTable,(char *)name);
1848 if (info)
1849 return info;
1850 }
1851
1852 if (Cpp.fileMacroTable)
1853 {
1854 info = (cppMacroInfo *)hashTableGetItem (Cpp.fileMacroTable,(char *)name);
1855 if (info)
1856 return info;
1857
1858 info = cppFindMacroFromSymtab(name);
1859 if (info)
1860 return info;
1861 }
1862 return NULL;
1863 }
1864
cppBuildMacroReplacement(const cppMacroInfo * macro,const char ** parameters,int parameterCount)1865 extern vString * cppBuildMacroReplacement(
1866 const cppMacroInfo * macro,
1867 const char ** parameters, /* may be NULL */
1868 int parameterCount
1869 )
1870 {
1871 if(!macro)
1872 return NULL;
1873
1874 if(!macro->replacements)
1875 return NULL;
1876
1877 vString * ret = vStringNew();
1878
1879 cppMacroReplacementPartInfo * r = macro->replacements;
1880
1881 while(r)
1882 {
1883 if(r->parameterIndex < 0)
1884 {
1885 if(r->constant)
1886 vStringCat(ret,r->constant);
1887 } else {
1888 if(parameters && (r->parameterIndex < parameterCount))
1889 {
1890 if(r->flags & CPP_MACRO_REPLACEMENT_FLAG_STRINGIFY)
1891 vStringPut(ret,'"');
1892
1893 vStringCatS(ret,parameters[r->parameterIndex]);
1894 if(r->flags & CPP_MACRO_REPLACEMENT_FLAG_VARARGS)
1895 {
1896 int idx = r->parameterIndex + 1;
1897 while(idx < parameterCount)
1898 {
1899 vStringPut(ret,',');
1900 vStringCatS(ret,parameters[idx]);
1901 idx++;
1902 }
1903 }
1904
1905 if(r->flags & CPP_MACRO_REPLACEMENT_FLAG_STRINGIFY)
1906 vStringPut(ret,'"');
1907 }
1908 }
1909
1910 r = r->next;
1911 }
1912
1913 return ret;
1914 }
1915
1916
saveIgnoreToken(const char * ignoreToken)1917 static void saveIgnoreToken(const char * ignoreToken)
1918 {
1919 if(!ignoreToken)
1920 return;
1921
1922 Assert (cmdlineMacroTable);
1923
1924 const char * c = ignoreToken;
1925 char cc = *c;
1926
1927 const char * tokenBegin = c;
1928 const char * tokenEnd = NULL;
1929 const char * replacement = NULL;
1930 bool ignoreFollowingParenthesis = false;
1931
1932 while(cc)
1933 {
1934 if(cc == '=')
1935 {
1936 if(!tokenEnd)
1937 tokenEnd = c;
1938 c++;
1939 if(*c)
1940 replacement = c;
1941 break;
1942 }
1943
1944 if(cc == '+')
1945 {
1946 if(!tokenEnd)
1947 tokenEnd = c;
1948 ignoreFollowingParenthesis = true;
1949 }
1950
1951 c++;
1952 cc = *c;
1953 }
1954
1955 if(!tokenEnd)
1956 tokenEnd = c;
1957
1958 if(tokenEnd <= tokenBegin)
1959 return;
1960
1961 cppMacroInfo * info = (cppMacroInfo *)eMalloc(sizeof(cppMacroInfo));
1962
1963 info->hasParameterList = ignoreFollowingParenthesis;
1964 if(replacement)
1965 {
1966 cppMacroReplacementPartInfo * rep = \
1967 (cppMacroReplacementPartInfo *)eMalloc(sizeof(cppMacroReplacementPartInfo));
1968 rep->parameterIndex = -1;
1969 rep->flags = 0;
1970 rep->constant = vStringNewInit(replacement);
1971 rep->next = NULL;
1972 info->replacements = rep;
1973 } else {
1974 info->replacements = NULL;
1975 }
1976 info->useCount = 0;
1977 info->next = NULL;
1978
1979 hashTablePutItem(cmdlineMacroTable,eStrndup(tokenBegin,tokenEnd - tokenBegin),info);
1980
1981 verbose (" ignore token: %s\n", ignoreToken);
1982 }
1983
saveMacro(hashTable * table,const char * macro)1984 static cppMacroInfo * saveMacro(hashTable *table, const char * macro)
1985 {
1986 CXX_DEBUG_ENTER_TEXT("Save macro %s",macro);
1987
1988 if(!macro)
1989 return NULL;
1990
1991 Assert (table);
1992
1993 const char * c = macro;
1994
1995 // skip initial spaces
1996 while(*c && isspacetab(*c))
1997 c++;
1998
1999 if(!*c)
2000 {
2001 CXX_DEBUG_LEAVE_TEXT("Bad empty macro definition");
2002 return NULL;
2003 }
2004
2005 if(!(isalpha(*c) || (*c == '_' || (*c == '$') )))
2006 {
2007 CXX_DEBUG_LEAVE_TEXT("Macro does not start with an alphanumeric character");
2008 return NULL; // must be a sequence of letters and digits
2009 }
2010
2011 const char * identifierBegin = c;
2012
2013 while(*c && (isalnum(*c) || (*c == '_') || (*c == '$') ))
2014 c++;
2015
2016 const char * identifierEnd = c;
2017
2018 CXX_DEBUG_PRINT("Macro identifier '%.*s'",identifierEnd - identifierBegin,identifierBegin);
2019
2020 #define MAX_PARAMS 16
2021
2022 const char * paramBegin[MAX_PARAMS];
2023 const char * paramEnd[MAX_PARAMS];
2024
2025 int iParamCount = 0;
2026
2027 while(*c && isspacetab(*c))
2028 c++;
2029
2030 cppMacroInfo * info = (cppMacroInfo *)eMalloc(sizeof(cppMacroInfo));
2031 info->useCount = 0;
2032 info->next = NULL;
2033
2034 if(*c == '(')
2035 {
2036 // parameter list
2037 CXX_DEBUG_PRINT("Macro has a parameter list");
2038
2039 info->hasParameterList = true;
2040
2041 c++;
2042 while(*c)
2043 {
2044 while(*c && isspacetab(*c))
2045 c++;
2046
2047 if(*c && (*c != ',') && (*c != ')'))
2048 {
2049 paramBegin[iParamCount] = c;
2050 c++;
2051 while(*c && (*c != ',') && (*c != ')') && (!isspacetab(*c)))
2052 c++;
2053 paramEnd[iParamCount] = c;
2054
2055 CXX_DEBUG_PRINT(
2056 "Macro parameter %d '%.*s'",
2057 iParamCount,
2058 paramEnd[iParamCount] - paramBegin[iParamCount],
2059 paramBegin[iParamCount]
2060 );
2061
2062 iParamCount++;
2063 if(iParamCount >= MAX_PARAMS)
2064 break;
2065 }
2066
2067 while(*c && isspacetab(*c))
2068 c++;
2069
2070 if(*c == ')')
2071 break;
2072
2073 if(*c == ',')
2074 c++;
2075 }
2076
2077 while(*c && (*c != ')'))
2078 c++;
2079
2080 if(*c == ')')
2081 c++;
2082
2083 CXX_DEBUG_PRINT("Got %d parameters",iParamCount);
2084
2085 } else {
2086 info->hasParameterList = false;
2087 }
2088
2089 while(*c && isspacetab(*c))
2090 c++;
2091
2092 info->replacements = NULL;
2093
2094
2095 if(*c == '=')
2096 {
2097 CXX_DEBUG_PRINT("Macro has a replacement part");
2098
2099 // have replacement part
2100 c++;
2101
2102 cppMacroReplacementPartInfo * lastReplacement = NULL;
2103 int nextParameterReplacementFlags = 0;
2104
2105 #define ADD_REPLACEMENT_NEW_PART(part) \
2106 do { \
2107 if(lastReplacement) \
2108 lastReplacement->next = part; \
2109 else \
2110 info->replacements = part; \
2111 lastReplacement = part; \
2112 } while(0)
2113
2114 #define ADD_CONSTANT_REPLACEMENT_NEW_PART(start,len) \
2115 do { \
2116 cppMacroReplacementPartInfo * rep = \
2117 (cppMacroReplacementPartInfo *)eMalloc(sizeof(cppMacroReplacementPartInfo)); \
2118 rep->parameterIndex = -1; \
2119 rep->flags = 0; \
2120 rep->constant = vStringNew(); \
2121 vStringNCatS(rep->constant,start,len); \
2122 rep->next = NULL; \
2123 CXX_DEBUG_PRINT("Constant replacement part: '%s'",vStringValue(rep->constant)); \
2124 ADD_REPLACEMENT_NEW_PART(rep); \
2125 } while(0)
2126
2127 #define ADD_CONSTANT_REPLACEMENT(start,len) \
2128 do { \
2129 if(lastReplacement && (lastReplacement->parameterIndex == -1)) \
2130 { \
2131 vStringNCatS(lastReplacement->constant,start,len); \
2132 CXX_DEBUG_PRINT( \
2133 "Constant replacement part changed: '%s'", \
2134 vStringValue(lastReplacement->constant) \
2135 ); \
2136 } else { \
2137 ADD_CONSTANT_REPLACEMENT_NEW_PART(start,len); \
2138 } \
2139 } while(0)
2140
2141 // parse replacements
2142 const char * begin = c;
2143
2144 while(*c)
2145 {
2146 if(isalpha(*c) || (*c == '_'))
2147 {
2148 if(c > begin)
2149 ADD_CONSTANT_REPLACEMENT(begin,c - begin);
2150
2151 const char * tokenBegin = c;
2152
2153 while(*c && (isalnum(*c) || (*c == '_')))
2154 c++;
2155
2156 // check if it is a parameter
2157 int tokenLen = c - tokenBegin;
2158
2159 CXX_DEBUG_PRINT("Check token '%.*s'",tokenLen,tokenBegin);
2160
2161 bool bIsVarArg = (tokenLen == 11) && (strncmp(tokenBegin,"__VA_ARGS__",11) == 0);
2162
2163 int i = 0;
2164 for(;i<iParamCount;i++)
2165 {
2166 int paramLen = paramEnd[i] - paramBegin[i];
2167
2168 if(
2169 (
2170 bIsVarArg &&
2171 (paramLen == 3) &&
2172 (strncmp(paramBegin[i],"...",3) == 0)
2173 ) || (
2174 (!bIsVarArg) &&
2175 (paramLen == tokenLen) &&
2176 (strncmp(paramBegin[i],tokenBegin,paramLen) == 0)
2177 )
2178 )
2179 {
2180 // parameter!
2181 cppMacroReplacementPartInfo * rep = \
2182 (cppMacroReplacementPartInfo *)eMalloc(sizeof(cppMacroReplacementPartInfo));
2183 rep->parameterIndex = i;
2184 rep->flags = nextParameterReplacementFlags |
2185 (bIsVarArg ? CPP_MACRO_REPLACEMENT_FLAG_VARARGS : 0);
2186 rep->constant = NULL;
2187 rep->next = NULL;
2188
2189 nextParameterReplacementFlags = 0;
2190
2191 CXX_DEBUG_PRINT("Parameter replacement part: %d (vararg %d)",i,bIsVarArg);
2192
2193 ADD_REPLACEMENT_NEW_PART(rep);
2194 break;
2195 }
2196 }
2197
2198 if(i >= iParamCount)
2199 {
2200 // no parameter found
2201 ADD_CONSTANT_REPLACEMENT(tokenBegin,tokenLen);
2202 }
2203
2204 begin = c;
2205 continue;
2206 }
2207
2208 if((*c == '"') || (*c == '\''))
2209 {
2210 // skip string/char constant
2211 char term = *c;
2212 c++;
2213 while(*c)
2214 {
2215 if(*c == '\\')
2216 {
2217 c++;
2218 if(*c)
2219 c++;
2220 } else if(*c == term)
2221 {
2222 c++;
2223 break;
2224 }
2225 c++;
2226 }
2227 continue;
2228 }
2229
2230 if(*c == '#')
2231 {
2232 // check for token paste/stringification
2233 if(c > begin)
2234 ADD_CONSTANT_REPLACEMENT(begin,c - begin);
2235
2236 c++;
2237 if(*c == '#')
2238 {
2239 // token paste
2240 CXX_DEBUG_PRINT("Found token paste operator");
2241 while(*c == '#')
2242 c++;
2243
2244 // we just skip this part and the following spaces
2245 while(*c && isspacetab(*c))
2246 c++;
2247
2248 if(lastReplacement && (lastReplacement->parameterIndex == -1))
2249 {
2250 // trim spaces from the last replacement constant!
2251 vStringStripTrailing(lastReplacement->constant);
2252 CXX_DEBUG_PRINT(
2253 "Last replacement truncated to '%s'",
2254 vStringValue(lastReplacement->constant)
2255 );
2256 }
2257 } else {
2258 // stringification
2259 CXX_DEBUG_PRINT("Found stringification operator");
2260 nextParameterReplacementFlags |= CPP_MACRO_REPLACEMENT_FLAG_STRINGIFY;
2261 }
2262
2263 begin = c;
2264 continue;
2265 }
2266
2267 c++;
2268 }
2269
2270 if(c > begin)
2271 ADD_CONSTANT_REPLACEMENT(begin,c - begin);
2272 }
2273
2274 hashTablePutItem(table,eStrndup(identifierBegin,identifierEnd - identifierBegin),info);
2275 CXX_DEBUG_LEAVE();
2276
2277 return info;
2278 }
2279
freeMacroInfo(cppMacroInfo * info)2280 static void freeMacroInfo(cppMacroInfo * info)
2281 {
2282 if(!info)
2283 return;
2284 cppMacroReplacementPartInfo * pPart = info->replacements;
2285 while(pPart)
2286 {
2287 if(pPart->constant)
2288 vStringDelete(pPart->constant);
2289 cppMacroReplacementPartInfo * pPartToDelete = pPart;
2290 pPart = pPart->next;
2291 eFree(pPartToDelete);
2292 }
2293 eFree(info);
2294 }
2295
makeMacroTable(void)2296 static hashTable *makeMacroTable (void)
2297 {
2298 return hashTableNew(
2299 1024,
2300 hashCstrhash,
2301 hashCstreq,
2302 eFree,
2303 (void (*)(void *))freeMacroInfo
2304 );
2305 }
2306
initializeCpp(const langType language)2307 static void initializeCpp (const langType language)
2308 {
2309 Cpp.lang = language;
2310 }
2311
finalizeCpp(const langType language,bool initialized)2312 static void finalizeCpp (const langType language, bool initialized)
2313 {
2314 if (cmdlineMacroTable)
2315 {
2316 hashTableDelete (cmdlineMacroTable);
2317 cmdlineMacroTable = NULL;
2318 }
2319 }
2320
CpreProExpandMacrosInInput(const langType language CTAGS_ATTR_UNUSED,const char * name,const char * arg)2321 static void CpreProExpandMacrosInInput (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg)
2322 {
2323 doesExpandMacros = paramParserBool (arg, doesExpandMacros,
2324 name, "parameter");
2325 }
2326
CpreProInstallIgnoreToken(const langType language CTAGS_ATTR_UNUSED,const char * optname CTAGS_ATTR_UNUSED,const char * arg)2327 static void CpreProInstallIgnoreToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg)
2328 {
2329 if (arg == NULL || arg[0] == '\0')
2330 {
2331 if (cmdlineMacroTable)
2332 {
2333 hashTableDelete(cmdlineMacroTable);
2334 cmdlineMacroTable = NULL;
2335 }
2336 verbose (" clearing list\n");
2337 } else {
2338 if (!cmdlineMacroTable)
2339 cmdlineMacroTable = makeMacroTable ();
2340 saveIgnoreToken(arg);
2341 }
2342 }
2343
CpreProInstallMacroToken(const langType language CTAGS_ATTR_UNUSED,const char * optname CTAGS_ATTR_UNUSED,const char * arg)2344 static void CpreProInstallMacroToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg)
2345 {
2346 if (arg == NULL || arg[0] == '\0')
2347 {
2348 if (cmdlineMacroTable)
2349 {
2350 hashTableDelete(cmdlineMacroTable);
2351 cmdlineMacroTable = NULL;
2352 }
2353 verbose (" clearing list\n");
2354 } else {
2355 if (!cmdlineMacroTable)
2356 cmdlineMacroTable = makeMacroTable ();
2357 saveMacro(cmdlineMacroTable, arg);
2358 }
2359 }
2360
CpreProSetIf0(const langType language CTAGS_ATTR_UNUSED,const char * name,const char * arg)2361 static void CpreProSetIf0 (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg)
2362 {
2363 doesExaminCodeWithInIf0Branch = paramParserBool (arg, doesExaminCodeWithInIf0Branch,
2364 name, "parameter");
2365 }
2366
2367 static parameterHandlerTable CpreProParameterHandlerTable [] = {
2368 { .name = "if0",
2369 .desc = "examine code within \"#if 0\" branch (true or [false])",
2370 .handleParameter = CpreProSetIf0,
2371 },
2372 { .name = "ignore",
2373 .desc = "a token to be specially handled",
2374 .handleParameter = CpreProInstallIgnoreToken,
2375 },
2376 { .name = "define",
2377 .desc = "define replacement for an identifier (name(params,...)=definition)",
2378 .handleParameter = CpreProInstallMacroToken,
2379 },
2380 { .name = "_expand",
2381 .desc = "expand macros if their definitions are in the current C/C++/CUDA input file (true or [false])",
2382 .handleParameter = CpreProExpandMacrosInInput,
2383 }
2384 };
2385
CPreProParser(void)2386 extern parserDefinition* CPreProParser (void)
2387 {
2388 parserDefinition* const def = parserNew ("CPreProcessor");
2389 def->kindTable = CPreProKinds;
2390 def->kindCount = ARRAY_SIZE (CPreProKinds);
2391 def->initialize = initializeCpp;
2392 def->parser = findCppTags;
2393 def->finalize = finalizeCpp;
2394
2395 def->fieldTable = CPreProFields;
2396 def->fieldCount = ARRAY_SIZE (CPreProFields);
2397
2398 def->parameterHandlerTable = CpreProParameterHandlerTable;
2399 def->parameterHandlerCount = ARRAY_SIZE(CpreProParameterHandlerTable);
2400
2401 def->useCork = CORK_QUEUE | CORK_SYMTAB;
2402 return def;
2403 }
2404