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, &macroCorkIndex, &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