xref: /Universal-ctags/parsers/c.c (revision 081ee612a091a26ca86460bb8b7d642fe7599821)
1 /*
2 *   Copyright (c) 1996-2003, 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 functions for parsing and scanning C, C++, C#, D and Java
8 *   source files.
9 */
10 
11 /*
12 *   INCLUDE FILES
13 */
14 #include "general.h"        /* must always come first */
15 
16 #include <string.h>
17 #include <setjmp.h>
18 
19 #include "debug.h"
20 #include "entry.h"
21 #include "cpreprocessor.h"
22 #include "keyword.h"
23 #include "options.h"
24 #include "parse.h"
25 #include "read.h"
26 #include "routines.h"
27 #include "selectors.h"
28 #include "xtag.h"
29 
30 /*
31 *   MACROS
32 */
33 
34 #define activeToken(st)     ((st)->token [(int) (st)->tokenIndex])
35 #define parentDecl(st)      ((st)->parent == NULL ? \
36                             DECL_NONE : (st)->parent->declaration)
37 #define isType(token,t)     (bool) ((token)->type == (t))
38 #define insideEnumBody(st)  ((st)->parent == NULL ? false : \
39                             (bool) ((st)->parent->declaration == DECL_ENUM))
40 #define insideAnnotationBody(st)  ((st)->parent == NULL ? false : \
41 								  (bool) ((st)->parent->declaration == DECL_ANNOTATION))
42 #define insideInterfaceBody(st) ((st)->parent == NULL ? false : \
43                             (bool) ((st)->parent->declaration == DECL_INTERFACE))
44 #define isSignalDirection(token) (bool)(( (token)->keyword == KEYWORD_INPUT  ) ||\
45 					   ( (token)->keyword == KEYWORD_OUTPUT ) ||\
46 					   ( (token)->keyword == KEYWORD_INOUT  )  )
47 #define isExternCDecl(st,c) (bool) ((c) == STRING_SYMBOL  && \
48                     ! (st)->haveQualifyingName  && (st)->scope == SCOPE_EXTERN)
49 
50 #define isOneOf(c,s)        (bool) (strchr ((s), (c)) != NULL)
51 
52 #define isHighChar(c)       ((c) != EOF && (unsigned int)(c) >= 0xc0 && \
53 							               (unsigned int)(c) <= 0xff)
54 
55 /*
56 *   DATA DECLARATIONS
57 */
58 
59 enum { NumTokens = 3 };
60 
61 typedef enum eException {
62 	ExceptionNone, ExceptionEOF, ExceptionFormattingError,
63 	ExceptionBraceFormattingError
64 } exception_t;
65 
66 /*  Used to specify type of keyword.
67  */
68 enum eKeywordId {
69 	KEYWORD_ALIAS, KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
70 	KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
71 	KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
72 	KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CLOCK, KEYWORD_CONST,
73 	KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
74 	KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
75 	KEYWORD_DOUBLE,
76 	KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
77 	KEYWORD_EXTENDS, KEYWORD_EVENT,
78 	KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FOREACH,
79 	KEYWORD_FRIEND, KEYWORD_FUNCTION,
80 	KEYWORD_GOTO,
81 	KEYWORD_HDL_NODE,
82 	KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
83 	KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
84 	KEYWORD_INTERNAL,
85 	KEYWORD_LOCAL, KEYWORD_LONG,
86 	KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
87 	KEYWORD_MUTABLE,
88 	KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE,
89 	KEYWORD_NHOLD, KEYWORD_NOEXCEPT, KEYWORD_NSAMPLE,
90 	KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
91 	KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PHOLD, KEYWORD_PRIVATE,
92 	KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PSAMPLE, KEYWORD_PUBLIC,
93 	KEYWORD_REGISTER, KEYWORD_RETURN,
94 	KEYWORD_SHADOW, KEYWORD_STATE,
95 	KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRING,
96 	KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
97 	KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
98 	KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
99 	KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
100 	KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
101 	KEYWORD_USING,
102 	KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
103 	KEYWORD_WCHAR_T, KEYWORD_WHILE,
104 	KEYWORD_ALIGN, KEYWORD_ASM, KEYWORD_ASSERT, KEYWORD_AUTO,
105 	KEYWORD_BODY, KEYWORD_BOOL, KEYWORD_BREAK, KEYWORD_CAST,
106 	KEYWORD_CDOUBLE, KEYWORD_CENT, KEYWORD_CFLOAT, KEYWORD_CONTINUE,
107 	KEYWORD_CREAL, KEYWORD_DCHAR, KEYWORD_DEBUG,
108 	KEYWORD_DEPRECATED, KEYWORD_EXPORT, KEYWORD_FALSE, KEYWORD_FINALLY,
109 	KEYWORD_FOREACH_REVERSE, KEYWORD_IDOUBLE, KEYWORD_IFLOAT,
110 	KEYWORD_IN, KEYWORD_INVARIANT, KEYWORD_IREAL, KEYWORD_IS,
111 	KEYWORD_LAZY, KEYWORD_MIXIN, KEYWORD_MODULE, KEYWORD_NULL,
112 	KEYWORD_OUT, KEYWORD_PRAGMA, KEYWORD_REAL, KEYWORD_SCOPE,
113 	KEYWORD_SUPER, KEYWORD_TRUE, KEYWORD_TYPEID, KEYWORD_TYPEOF,
114 	KEYWORD_UBYTE, KEYWORD_UCENT, KEYWORD_UNITTEST, KEYWORD_VERSION,
115 	KEYWORD_WCHAR, KEYWORD_WITH
116 };
117 typedef int keywordId; /* to allow KEYWORD_NONE */
118 
119 /*  Used to determine whether keyword is valid for the current language and
120  *  what its ID is.
121  */
122 typedef struct sKeywordDesc {
123 	const char *name;
124 	keywordId id;
125 	short isValid [6]; /* indicates languages for which kw is valid */
126 } keywordDesc;
127 
128 /*  Used for reporting the type of object parsed by nextToken ().
129  */
130 typedef enum eTokenType {
131 	TOKEN_NONE,          /* none */
132 	TOKEN_ARGS,          /* a parenthetical pair and its contents */
133 	TOKEN_BRACE_CLOSE,
134 	TOKEN_BRACE_OPEN,
135 	TOKEN_COLON,         /* the colon character */
136 	TOKEN_COMMA,         /* the comma character */
137 	TOKEN_DOUBLE_COLON,  /* double colon indicates nested-name-specifier */
138 	TOKEN_KEYWORD,
139 	TOKEN_NAME,          /* an unknown name */
140 	TOKEN_PACKAGE,       /* a Java package name */
141 	TOKEN_PAREN_NAME,    /* a single name in parentheses */
142 	TOKEN_SEMICOLON,     /* the semicolon character */
143 	TOKEN_SPEC,          /* a storage class specifier, qualifier, type, etc. */
144 	TOKEN_COUNT
145 } tokenType;
146 
147 /*  This describes the scoping of the current statement.
148  */
149 typedef enum eTagScope {
150 	SCOPE_GLOBAL,        /* no storage class specified */
151 	SCOPE_STATIC,        /* static storage class */
152 	SCOPE_EXTERN,        /* external storage class */
153 	SCOPE_FRIEND,        /* declares access only */
154 	SCOPE_TYPEDEF,       /* scoping depends upon context */
155 	SCOPE_COUNT
156 } tagScope;
157 
158 typedef enum eDeclaration {
159 	DECL_NONE,
160 	DECL_BASE,           /* base type (default) */
161 	DECL_CLASS,
162 	DECL_ENUM,
163 	DECL_EVENT,
164 	DECL_FUNCTION,
165 	DECL_FUNCTION_TEMPLATE, /* D-only */
166 	DECL_IGNORE,         /* non-taggable "declaration" */
167 	DECL_INTERFACE,
168 	DECL_MIXIN,
169 	DECL_NAMESPACE,
170 	DECL_NOMANGLE,       /* C++ name demangling block */
171 	DECL_PACKAGE,
172 	DECL_PACKAGEREF,
173 	DECL_PRIVATE,
174 	DECL_PROGRAM,        /* Vera program */
175 	DECL_PROTECTED,
176 	DECL_PUBLIC,
177 	DECL_STRUCT,
178 	DECL_TASK,           /* Vera task */
179 	DECL_TEMPLATE,       /* D-only */
180 	DECL_UNION,
181 	DECL_USING,
182 	DECL_VERSION,        /* D conditional compile */
183 	DECL_ANNOTATION,     /* Java annotation */
184 	DECL_COUNT
185 } declType;
186 
187 typedef enum eVisibilityType {
188 	ACCESS_UNDEFINED,
189 	ACCESS_LOCAL,
190 	ACCESS_PRIVATE,
191 	ACCESS_PROTECTED,
192 	ACCESS_PUBLIC,
193 	ACCESS_DEFAULT,      /* Java-specific */
194 	ACCESS_COUNT
195 } accessType;
196 
197 /*  Information about the parent class of a member (if any).
198  */
199 typedef struct sMemberInfo {
200 	accessType access;           /* access of current statement */
201 	accessType accessDefault;    /* access default for current statement */
202 } memberInfo;
203 
204 typedef struct sTokenInfo {
205 	tokenType     type;
206 	keywordId     keyword;
207 	vString*      name;          /* the name of the token */
208 	unsigned long lineNumber;    /* line number of tag */
209 	MIOPos        filePosition;  /* file position of line containing name */
210 } tokenInfo;
211 
212 typedef enum eImplementation {
213 	IMP_DEFAULT,
214 	IMP_ABSTRACT,
215 	IMP_VIRTUAL,
216 	IMP_PURE_VIRTUAL,
217 	IMP_COUNT
218 } impType;
219 
220 /*  Describes the statement currently undergoing analysis.
221  */
222 typedef struct sStatementInfo {
223 	tagScope	scope;
224 	declType	declaration;    /* specifier associated with TOKEN_SPEC */
225 	bool		gotName;        /* was a name parsed yet? */
226 	bool		haveQualifyingName;  /* do we have a name we are considering? */
227 	bool		gotParenName;   /* was a name inside parentheses parsed yet? */
228 	bool		gotArgs;        /* was a list of parameters parsed yet? */
229 	bool		isPointer;      /* is 'name' a pointer? */
230 	bool     inFunction;     /* are we inside of a function? */
231 	bool		assignment;     /* have we handled an '='? */
232 	bool		notVariable;    /* has a variable declaration been disqualified ? */
233 	impType		implementation; /* abstract or concrete implementation? */
234 	unsigned int tokenIndex;    /* currently active token */
235 	tokenInfo*	token [(int) NumTokens];
236 	tokenInfo*	context;        /* accumulated scope of current statement */
237 	tokenInfo*	blockName;      /* name of current block */
238 	memberInfo	member;         /* information regarding parent class/struct */
239 	vString*	parentClasses;  /* parent classes */
240 	struct sStatementInfo *parent;  /* statement we are nested within */
241 } statementInfo;
242 
243 /*  Describes the type of tag being generated.
244  */
245 typedef enum eTagType {
246 	TAG_UNDEFINED,
247 	TAG_CLASS,       /* class name */
248 	TAG_ENUM,        /* enumeration name */
249 	TAG_ENUMERATOR,  /* enumerator (enumeration value) */
250 	TAG_EVENT,       /* event */
251 	TAG_FIELD,       /* field (Java) */
252 	TAG_FUNCTION,    /* function definition */
253 	TAG_INTERFACE,   /* interface declaration */
254 	TAG_LOCAL,       /* local variable definition */
255 	TAG_MEMBER,      /* structure, class or interface member */
256 	TAG_METHOD,      /* method declaration */
257 	TAG_MIXIN, 		 /* D mixin */
258 	TAG_NAMESPACE,   /* namespace name */
259 	TAG_PACKAGE,     /* package name / D module name */
260 	TAG_PACKAGEREF,	 /* referenced package name */
261 	TAG_PROGRAM,     /* program name */
262 	TAG_PROPERTY,    /* property name */
263 	TAG_PROTOTYPE,   /* function prototype or declaration */
264 	TAG_SIGNAL,	 /* VERA signal name */
265 	TAG_STRUCT,      /* structure name */
266 	TAG_TASK,        /* task name */
267 	TAG_TYPEDEF,     /* typedef name / D alias name */
268 	TAG_TEMPLATE,    /* D template name */
269 	TAG_UNION,       /* union name */
270 	TAG_VARIABLE,    /* variable definition */
271 	TAG_EXTERN_VAR,  /* external variable declaration */
272 	TAG_VERSION, 	 /* conditional template compilation */
273 	TAG_LABEL,	 /* goto label */
274 	TAG_ANNOTATION,  /* Java annotation definition */
275 	TAG_COUNT        /* must be last */
276 } tagType;
277 
278 typedef struct sParenInfo {
279 	bool isPointer;
280 	bool isParamList;
281 	bool isKnrParamList;
282 	bool isNameCandidate;
283 	bool invalidContents;
284 	bool nestedArgs;
285 	unsigned int parameterCount;
286 } parenInfo;
287 
288 /*
289 *   DATA DEFINITIONS
290 */
291 
292 static jmp_buf Exception;
293 
294 static langType Lang_c;
295 static langType Lang_cpp;
296 static langType Lang_csharp;
297 static langType Lang_d;
298 static langType Lang_java;
299 static langType Lang_vera;
300 static vString *Signature;
301 static bool CollectingSignature;
302 
303 /* Number used to uniquely identify anonymous structs and unions. */
304 static int AnonymousID = 0;
305 
306 #define COMMONK_UNDEFINED -1
307 
308 
309 /* Used to index into the CKinds table. */
310 typedef enum {
311 	CR_MACRO_UNDEF,
312 	CR_MACRO_CONDITION,
313 } cMacroRole;
314 
315 static roleDefinition CMacroRoles [] = {
316 	RoleTemplateUndef,
317 	RoleTemplateCondition,
318 };
319 
320 typedef enum {
321 	CR_HEADER_SYSTEM,
322 	CR_HEADER_LOCAL,
323 } cHeaderRole;
324 
325 static roleDefinition CHeaderRoles [] = {
326 	RoleTemplateSystem,
327 	RoleTemplateLocal,
328 };
329 
330 typedef enum {
331 	CK_UNDEFINED = COMMONK_UNDEFINED,
332 	CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
333 	CK_ENUMERATION, CK_HEADER, CK_LOCAL, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
334 	CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
335 	CK_EXTERN_VARIABLE, CK_LABEL, CK_MACRO_PARAM,
336 } cKind;
337 
338 static kindDefinition CKinds [] = {
339 	{ true,  'c', "class",      "classes"},
340 	{ true,  'd', "macro",      "macro definitions",
341 	  .referenceOnly = false, ATTACH_ROLES(CMacroRoles)},
342 	{ true,  'e', "enumerator", "enumerators (values inside an enumeration)"},
343 	{ true,  'f', "function",   "function definitions"},
344 	{ true,  'g', "enum",       "enumeration names"},
345 	{ true,  'h', "header",     "included header files",
346 	  .referenceOnly = true,  ATTACH_ROLES(CHeaderRoles)},
347 	{ false, 'l', "local",      "local variables"},
348 	{ true,  'm', "member",     "class, struct, and union members"},
349 	{ true,  'n', "namespace",  "namespaces"},
350 	{ false, 'p', "prototype",  "function prototypes"},
351 	{ true,  's', "struct",     "structure names"},
352 	{ true,  't', "typedef",    "typedefs"},
353 	{ true,  'u', "union",      "union names"},
354 	{ true,  'v', "variable",   "variable definitions"},
355 	{ false, 'x', "externvar",  "external and forward variable declarations"},
356 	{ false, 'L', "label",      "goto label"},
357 	{ false, 'D', "macroparam", "cpp macro parameters"},
358 };
359 
360 typedef enum {
361 	CSK_UNDEFINED = COMMONK_UNDEFINED,
362 	CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
363 	CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
364 	CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
365 } csharpKind;
366 
367 static kindDefinition CsharpKinds [] = {
368 	{ true,  'c', "class",      "classes"},
369 	{ true,  'd', "macro",      "macro definitions"},
370 	{ true,  'e', "enumerator", "enumerators (values inside an enumeration)"},
371 	{ true,  'E', "event",      "events"},
372 	{ true,  'f', "field",      "fields"},
373 	{ true,  'g', "enum",       "enumeration names"},
374 	{ true,  'i', "interface",  "interfaces"},
375 	{ false, 'l', "local",      "local variables"},
376 	{ true,  'm', "method",     "methods"},
377 	{ true,  'n', "namespace",  "namespaces"},
378 	{ true,  'p', "property",   "properties"},
379 	{ true,  's', "struct",     "structure names"},
380 	{ true,  't', "typedef",    "typedefs"},
381 };
382 
383 typedef enum
384 {
385 	DK_UNDEFINED = COMMONK_UNDEFINED,
386 	DK_ALIAS, DK_CLASS, DK_ENUMERATION, DK_ENUMERATOR, DK_EXTERN_VARIABLE, DK_FUNCTION,
387 	DK_INTERFACE, DK_LOCAL, DK_MEMBER, DK_MIXIN, DK_MODULE, DK_NAMESPACE,
388 	DK_PROTOTYPE, DK_STRUCT, DK_TEMPLATE, DK_UNION,
389 	DK_VARIABLE, DK_VERSION
390 } dKind;
391 
392 static kindDefinition DKinds [] = {
393 	{ true,  'a', "alias",      "aliases"},
394 	{ true,  'c', "class",      "classes"},
395 	{ true,  'g', "enum",       "enumeration names"},
396 	{ true,  'e', "enumerator", "enumerators (values inside an enumeration)"},
397 	{ false, 'x', "externvar",  "external variable declarations"},
398 	{ true,  'f', "function",   "function definitions"},
399 	{ true,  'i', "interface",  "interfaces"},
400 	{ false, 'l', "local",      "local variables"},
401 	{ true,  'm', "member",     "class, struct, and union members"},
402 	{ true,  'X', "mixin",      "mixins"},
403 	{ true,  'M', "module",     "modules"},
404 	{ true,  'n', "namespace",  "namespaces"},
405 	{ false, 'p', "prototype",  "function prototypes"},
406 	{ true,  's', "struct",     "structure names"},
407 	{ true,  'T', "template",   "templates"},
408 	{ true,  'u', "union",      "union names"},
409 	{ true,  'v', "variable",   "variable definitions"},
410 	{ true,  'V', "version",    "version statements"}
411 };
412 
413 /* Used to index into the JavaKinds table. */
414 typedef enum {
415 	JAVAR_PACKAGE_IMPORTED,
416 } javaPackageRole;
417 
418 static roleDefinition JavaPackageRoles [] = {
419 	{ true, "imported", "imported package"},
420 };
421 
422 typedef enum {
423 	JK_UNDEFINED = COMMONK_UNDEFINED,
424 	JK_ANNOTATION, JK_CLASS, JK_ENUM_CONSTANT, JK_FIELD, JK_ENUM, JK_INTERFACE,
425 	JK_LOCAL, JK_METHOD, JK_PACKAGE, JK_ACCESS, JK_CLASS_PREFIX
426 } javaKind;
427 
428 static kindDefinition JavaKinds [] = {
429 	{ true,  'a', "annotation",    "annotation declarations" },
430 	{ true,  'c', "class",         "classes"},
431 	{ true,  'e', "enumConstant",  "enum constants"},
432 	{ true,  'f', "field",         "fields"},
433 	{ true,  'g', "enum",          "enum types"},
434 	{ true,  'i', "interface",     "interfaces"},
435 	{ false, 'l', "local",         "local variables"},
436 	{ true,  'm', "method",        "methods"},
437 	{ true,  'p', "package",       "packages",
438 	  .referenceOnly = false, ATTACH_ROLES(JavaPackageRoles)},
439 };
440 
441 /* Used to index into the VeraKinds table. */
442 typedef enum {
443 	VR_MACRO_UNDEF,
444 	VR_MACRO_CONDITION,
445 } veraMacroRole;
446 
447 static roleDefinition VeraMacroRoles [] = {
448 	RoleTemplateUndef,
449 	RoleTemplateCondition,
450 };
451 
452 
453 typedef enum {
454 	VR_HEADER_SYSTEM,
455 	VR_HEADER_LOCAL,
456 } veraHeaderRole;
457 
458 static roleDefinition VeraHeaderRoles [] = {
459 	RoleTemplateSystem,
460 	RoleTemplateLocal,
461 };
462 
463 typedef enum {
464 	VK_UNDEFINED = COMMONK_UNDEFINED,
465 	VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
466 	VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
467 	VK_SIGNAL, VK_TASK, VK_TYPEDEF, VK_VARIABLE,
468 	VK_EXTERN_VARIABLE, VK_HEADER, VK_MACRO_PARAM,
469 } veraKind;
470 
471 static kindDefinition VeraKinds [] = {
472 	{ true,  'c', "class",      "classes"},
473 	{ true,  'd', "macro",      "macro definitions",
474 	  .referenceOnly = false, ATTACH_ROLES(VeraMacroRoles)},
475 	{ true,  'e', "enumerator", "enumerators (values inside an enumeration)"},
476 	{ true,  'f', "function",   "function definitions"},
477 	{ true,  'g', "enum",       "enumeration names"},
478 	{ true,  'i', "interface",  "interfaces"},
479 	{ false, 'l', "local",      "local variables"},
480 	{ true,  'm', "member",     "class, struct, and union members"},
481 	{ true,  'p', "program",    "programs"},
482 	{ false, 'P', "prototype",  "function prototypes"},
483 	{ true,  's', "signal",     "signals"},
484 	{ true,  't', "task",       "tasks"},
485 	{ true,  'T', "typedef",    "typedefs"},
486 	{ true,  'v', "variable",   "variable definitions"},
487 	{ false, 'x', "externvar",  "external variable declarations"},
488 	{ true,  'h', "header",     "included header files",
489 	  .referenceOnly = true, ATTACH_ROLES(VeraHeaderRoles)},
490 	{ false, 'D', "macroParameter", "cpp macro parameters"},
491 };
492 
493 static const keywordDesc KeywordTable [] = {
494      /*                                                C++    D          */
495      /*                                         ANSI C  |  C# | Java     */
496      /*                                              |  |  |  |  |  Vera */
497      /* keyword           keyword ID                 |  |  |  |  |  |    */
498      { "__attribute__",   KEYWORD_ATTRIBUTE,       { 1, 1, 1, 1, 0, 0 } },
499      { "abstract",        KEYWORD_ABSTRACT,        { 0, 0, 1, 1, 1, 0 } },
500      { "alias",           KEYWORD_ALIAS,           { 0, 0, 0, 1, 0, 0 } },
501      { "align",           KEYWORD_ALIGN,           { 0, 0, 0, 1, 0, 0 } },
502      { "asm",             KEYWORD_ASM,             { 0, 0, 0, 1, 0, 0 } },
503      { "assert",          KEYWORD_ASSERT,          { 0, 0, 0, 1, 0, 0 } },
504      { "auto",            KEYWORD_AUTO,            { 0, 0, 0, 1, 0, 0 } },
505      { "bad_state",       KEYWORD_BAD_STATE,       { 0, 0, 0, 0, 0, 1 } },
506      { "bad_trans",       KEYWORD_BAD_TRANS,       { 0, 0, 0, 0, 0, 1 } },
507      { "bind",            KEYWORD_BIND,            { 0, 0, 0, 0, 0, 1 } },
508      { "bind_var",        KEYWORD_BIND_VAR,        { 0, 0, 0, 0, 0, 1 } },
509      { "bit",             KEYWORD_BIT,             { 0, 0, 0, 0, 0, 1 } },
510      { "body",            KEYWORD_BODY,            { 0, 0, 0, 1, 0, 0 } },
511      { "bool",            KEYWORD_BOOL,            { 0, 0, 0, 1, 0, 0 } },
512      { "boolean",         KEYWORD_BOOLEAN,         { 0, 0, 0, 0, 1, 0 } },
513      { "break",           KEYWORD_BREAK,           { 0, 0, 0, 1, 0, 0 } },
514      { "byte",            KEYWORD_BYTE,            { 0, 0, 0, 1, 1, 0 } },
515      { "case",            KEYWORD_CASE,            { 1, 1, 1, 1, 1, 0 } },
516      { "cast",            KEYWORD_CAST,            { 0, 0, 0, 1, 0, 0 } },
517      { "catch",           KEYWORD_CATCH,           { 0, 1, 1, 1, 1, 0 } },
518      { "cdouble",         KEYWORD_CDOUBLE,         { 0, 0, 0, 1, 0, 0 } },
519      { "cent",            KEYWORD_CENT,            { 0, 0, 0, 1, 0, 0 } },
520      { "cfloat",          KEYWORD_CFLOAT,          { 0, 0, 0, 1, 0, 0 } },
521      { "char",            KEYWORD_CHAR,            { 1, 1, 1, 1, 1, 0 } },
522      { "class",           KEYWORD_CLASS,           { 0, 1, 1, 1, 1, 1 } },
523      { "CLOCK",           KEYWORD_CLOCK,           { 0, 0, 0, 0, 0, 1 } },
524      { "const",           KEYWORD_CONST,           { 1, 1, 1, 1, 1, 0 } },
525      { "constraint",      KEYWORD_CONSTRAINT,      { 0, 0, 0, 0, 0, 1 } },
526      { "continue",        KEYWORD_CONTINUE,        { 0, 0, 0, 1, 0, 0 } },
527      { "coverage_block",  KEYWORD_COVERAGE_BLOCK,  { 0, 0, 0, 0, 0, 1 } },
528      { "coverage_def",    KEYWORD_COVERAGE_DEF,    { 0, 0, 0, 0, 0, 1 } },
529      { "creal",           KEYWORD_CREAL,           { 0, 0, 0, 1, 0, 0 } },
530      { "dchar",           KEYWORD_DCHAR,           { 0, 0, 0, 1, 0, 0 } },
531      { "debug",           KEYWORD_DEBUG,           { 0, 0, 0, 1, 0, 0 } },
532      { "default",         KEYWORD_DEFAULT,         { 1, 1, 1, 1, 1, 0 } },
533      { "delegate",        KEYWORD_DELEGATE,        { 0, 0, 1, 1, 0, 0 } },
534      { "delete",          KEYWORD_DELETE,          { 0, 1, 0, 1, 0, 0 } },
535      { "deprecated",      KEYWORD_DEPRECATED,      { 0, 0, 0, 1, 0, 0 } },
536      { "do",              KEYWORD_DO,              { 1, 1, 1, 1, 1, 0 } },
537      { "double",          KEYWORD_DOUBLE,          { 1, 1, 1, 1, 1, 0 } },
538      { "else",            KEYWORD_ELSE,            { 1, 1, 1, 1, 1, 0 } },
539      { "enum",            KEYWORD_ENUM,            { 1, 1, 1, 1, 1, 1 } },
540      { "event",           KEYWORD_EVENT,           { 0, 0, 1, 0, 0, 1 } },
541      { "explicit",        KEYWORD_EXPLICIT,        { 0, 1, 1, 1, 0, 0 } },
542      { "export",          KEYWORD_EXPORT,          { 0, 0, 0, 1, 0, 0 } },
543      { "extends",         KEYWORD_EXTENDS,         { 0, 0, 0, 0, 1, 1 } },
544      { "extern",          KEYWORD_EXTERN,          { 1, 1, 1, 1, 0, 1 } },
545      { "false",           KEYWORD_FALSE,           { 0, 0, 0, 1, 0, 0 } },
546      { "final",           KEYWORD_FINAL,           { 0, 0, 0, 1, 1, 0 } },
547      { "finally",         KEYWORD_FINALLY,         { 0, 0, 0, 1, 0, 0 } },
548      { "float",           KEYWORD_FLOAT,           { 1, 1, 1, 1, 1, 0 } },
549      { "for",             KEYWORD_FOR,             { 1, 1, 1, 1, 1, 0 } },
550      { "foreach",         KEYWORD_FOREACH,         { 0, 0, 1, 1, 0, 0 } },
551      { "foreach_reverse", KEYWORD_FOREACH_REVERSE, { 0, 0, 0, 1, 0, 0 } },
552      { "friend",          KEYWORD_FRIEND,          { 0, 1, 0, 1, 0, 0 } },
553      { "function",        KEYWORD_FUNCTION,        { 0, 0, 0, 1, 0, 1 } },
554      { "goto",            KEYWORD_GOTO,            { 1, 1, 1, 1, 1, 0 } },
555      { "hdl_node",        KEYWORD_HDL_NODE,        { 0, 0, 0, 0, 0, 1 } },
556      { "idouble",         KEYWORD_IDOUBLE,         { 0, 0, 0, 1, 0, 0 } },
557      { "if",              KEYWORD_IF,              { 1, 1, 1, 1, 1, 0 } },
558      { "ifloat",          KEYWORD_IFLOAT,          { 0, 0, 0, 1, 0, 0 } },
559      { "implements",      KEYWORD_IMPLEMENTS,      { 0, 0, 0, 0, 1, 0 } },
560      { "import",          KEYWORD_IMPORT,          { 0, 0, 0, 1, 1, 0 } },
561      { "in",              KEYWORD_IN,              { 0, 0, 0, 1, 0, 0 } },
562      { "inline",          KEYWORD_INLINE,          { 0, 1, 0, 1, 0, 0 } },
563      { "inout",           KEYWORD_INOUT,           { 0, 0, 0, 1, 0, 1 } },
564      { "input",           KEYWORD_INPUT,           { 0, 0, 0, 0, 0, 1 } },
565      { "int",             KEYWORD_INT,             { 1, 1, 1, 1, 1, 0 } },
566      { "integer",         KEYWORD_INTEGER,         { 0, 0, 0, 0, 0, 1 } },
567      { "interface",       KEYWORD_INTERFACE,       { 0, 0, 1, 1, 1, 1 } },
568      { "internal",        KEYWORD_INTERNAL,        { 0, 0, 1, 0, 0, 0 } },
569      { "invariant",       KEYWORD_INVARIANT,       { 0, 0, 0, 1, 0, 0 } },
570      { "ireal",           KEYWORD_IREAL,           { 0, 0, 0, 1, 0, 0 } },
571      { "is",              KEYWORD_IS,              { 0, 0, 0, 1, 0, 0 } },
572      { "lazy",            KEYWORD_LAZY,            { 0, 0, 0, 1, 0, 0 } },
573      { "local",           KEYWORD_LOCAL,           { 0, 0, 0, 0, 0, 1 } },
574      { "long",            KEYWORD_LONG,            { 1, 1, 1, 1, 1, 0 } },
575      { "m_bad_state",     KEYWORD_M_BAD_STATE,     { 0, 0, 0, 0, 0, 1 } },
576      { "m_bad_trans",     KEYWORD_M_BAD_TRANS,     { 0, 0, 0, 0, 0, 1 } },
577      { "m_state",         KEYWORD_M_STATE,         { 0, 0, 0, 0, 0, 1 } },
578      { "m_trans",         KEYWORD_M_TRANS,         { 0, 0, 0, 0, 0, 1 } },
579      { "mixin",           KEYWORD_MIXIN,           { 0, 0, 0, 1, 0, 0 } },
580      { "module",          KEYWORD_MODULE,          { 0, 0, 0, 1, 0, 0 } },
581      { "mutable",         KEYWORD_MUTABLE,         { 0, 1, 0, 1, 0, 0 } },
582      { "namespace",       KEYWORD_NAMESPACE,       { 0, 1, 1, 1, 0, 0 } },
583      { "native",          KEYWORD_NATIVE,          { 0, 0, 0, 0, 1, 0 } },
584      { "new",             KEYWORD_NEW,             { 0, 1, 1, 1, 1, 0 } },
585      { "newcov",          KEYWORD_NEWCOV,          { 0, 0, 0, 0, 0, 1 } },
586      { "NHOLD",           KEYWORD_NHOLD,           { 0, 0, 0, 0, 0, 1 } },
587      { "noexcept",        KEYWORD_NOEXCEPT,        { 0, 1, 0, 0, 0, 0 } },
588      { "NSAMPLE",         KEYWORD_NSAMPLE,         { 0, 0, 0, 0, 0, 1 } },
589      { "null",            KEYWORD_NULL,            { 0, 0, 0, 1, 0, 0 } },
590      { "operator",        KEYWORD_OPERATOR,        { 0, 1, 1, 1, 0, 0 } },
591      { "out",             KEYWORD_OUT,             { 0, 0, 0, 1, 0, 0 } },
592      { "output",          KEYWORD_OUTPUT,          { 0, 0, 0, 0, 0, 1 } },
593      { "overload",        KEYWORD_OVERLOAD,        { 0, 1, 0, 1, 0, 0 } },
594      { "override",        KEYWORD_OVERRIDE,        { 0, 0, 1, 1, 0, 0 } },
595      { "package",         KEYWORD_PACKAGE,         { 0, 0, 0, 1, 1, 0 } },
596      { "packed",          KEYWORD_PACKED,          { 0, 0, 0, 0, 0, 1 } },
597      { "PHOLD",           KEYWORD_PHOLD,           { 0, 0, 0, 0, 0, 1 } },
598      { "port",            KEYWORD_PORT,            { 0, 0, 0, 0, 0, 1 } },
599      { "pragma",          KEYWORD_PRAGMA,          { 0, 0, 0, 1, 0, 0 } },
600      { "private",         KEYWORD_PRIVATE,         { 0, 1, 1, 1, 1, 0 } },
601      { "program",         KEYWORD_PROGRAM,         { 0, 0, 0, 0, 0, 1 } },
602      { "protected",       KEYWORD_PROTECTED,       { 0, 1, 1, 1, 1, 1 } },
603      { "PSAMPLE",         KEYWORD_PSAMPLE,         { 0, 0, 0, 0, 0, 1 } },
604      { "public",          KEYWORD_PUBLIC,          { 0, 1, 1, 1, 1, 1 } },
605      { "real",            KEYWORD_REAL,            { 0, 0, 0, 1, 0, 0 } },
606      { "register",        KEYWORD_REGISTER,        { 1, 1, 0, 1, 0, 0 } },
607      { "return",          KEYWORD_RETURN,          { 1, 1, 1, 1, 1, 0 } },
608      { "scope",           KEYWORD_SCOPE,           { 0, 0, 0, 1, 0, 0 } },
609      { "shadow",          KEYWORD_SHADOW,          { 0, 0, 0, 0, 0, 1 } },
610      { "short",           KEYWORD_SHORT,           { 1, 1, 1, 1, 1, 0 } },
611      { "signed",          KEYWORD_SIGNED,          { 1, 1, 0, 1, 0, 0 } },
612      { "state",           KEYWORD_STATE,           { 0, 0, 0, 0, 0, 1 } },
613      { "static",          KEYWORD_STATIC,          { 1, 1, 1, 1, 1, 1 } },
614      { "string",          KEYWORD_STRING,          { 0, 0, 1, 0, 0, 1 } },
615      { "struct",          KEYWORD_STRUCT,          { 1, 1, 1, 1, 0, 0 } },
616      { "super",           KEYWORD_SUPER,           { 0, 0, 0, 1, 0, 0 } },
617      { "switch",          KEYWORD_SWITCH,          { 1, 1, 1, 1, 1, 0 } },
618      { "synchronized",    KEYWORD_SYNCHRONIZED,    { 0, 0, 0, 1, 1, 0 } },
619      { "task",            KEYWORD_TASK,            { 0, 0, 0, 0, 0, 1 } },
620      { "template",        KEYWORD_TEMPLATE,        { 0, 1, 0, 1, 0, 0 } },
621      { "this",            KEYWORD_THIS,            { 0, 1, 1, 0, 1, 0 } },
622      { "throw",           KEYWORD_THROW,           { 0, 1, 1, 1, 1, 0 } },
623      { "throws",          KEYWORD_THROWS,          { 0, 0, 0, 0, 1, 0 } },
624      { "trans",           KEYWORD_TRANS,           { 0, 0, 0, 0, 0, 1 } },
625      { "transient",       KEYWORD_TRANSIENT,       { 0, 0, 0, 0, 1, 0 } },
626      { "transition",      KEYWORD_TRANSITION,      { 0, 0, 0, 0, 0, 1 } },
627      { "true",            KEYWORD_TRUE,            { 0, 0, 0, 1, 0, 0 } },
628      { "try",             KEYWORD_TRY,             { 0, 1, 1, 1, 0, 0 } },
629      { "typedef",         KEYWORD_TYPEDEF,         { 1, 1, 1, 1, 0, 1 } },
630      { "typeid",          KEYWORD_TYPEID,          { 0, 0, 0, 1, 0, 0 } },
631      { "typename",        KEYWORD_TYPENAME,        { 0, 1, 0, 1, 0, 0 } },
632      { "typeof",          KEYWORD_TYPEOF,          { 0, 0, 0, 1, 0, 0 } },
633      { "ubyte",           KEYWORD_UBYTE,           { 0, 0, 0, 1, 0, 0 } },
634      { "ucent",           KEYWORD_UCENT,           { 0, 0, 0, 1, 0, 0 } },
635      { "uint",            KEYWORD_UINT,            { 0, 0, 1, 1, 0, 0 } },
636      { "ulong",           KEYWORD_ULONG,           { 0, 0, 1, 1, 0, 0 } },
637      { "union",           KEYWORD_UNION,           { 1, 1, 0, 1, 0, 0 } },
638      { "unittest",        KEYWORD_UNITTEST,        { 0, 0, 0, 1, 0, 0 } },
639      { "unsigned",        KEYWORD_UNSIGNED,        { 1, 1, 1, 1, 0, 0 } },
640      { "ushort",          KEYWORD_USHORT,          { 0, 0, 1, 1, 0, 0 } },
641      { "using",           KEYWORD_USING,           { 0, 1, 1, 1, 0, 0 } },
642      { "version",         KEYWORD_VERSION,         { 0, 0, 0, 1, 0, 0 } },
643      { "virtual",         KEYWORD_VIRTUAL,         { 0, 1, 1, 1, 0, 1 } },
644      { "void",            KEYWORD_VOID,            { 1, 1, 1, 1, 1, 1 } },
645      { "volatile",        KEYWORD_VOLATILE,        { 1, 1, 1, 1, 1, 0 } },
646      { "wchar",           KEYWORD_WCHAR,           { 0, 0, 0, 1, 0, 0 } },
647      { "wchar_t",         KEYWORD_WCHAR_T,         { 0, 1, 1, 0, 0, 0 } },
648      { "while",           KEYWORD_WHILE,           { 1, 1, 1, 1, 1, 0 } },
649      { "with",            KEYWORD_WITH,            { 0, 0, 0, 1, 0, 0 } },
650 };
651 
652 /*
653 *   FUNCTION PROTOTYPES
654 */
655 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
656 
657 /*
658 *   FUNCTION DEFINITIONS
659 */
660 
661 /*
662 *   Token management
663 */
664 
initToken(tokenInfo * const token)665 static void initToken (tokenInfo* const token)
666 {
667 	token->type			= TOKEN_NONE;
668 	token->keyword		= KEYWORD_NONE;
669 	token->lineNumber	= getInputLineNumber ();
670 	token->filePosition	= getInputFilePosition ();
671 	vStringClear (token->name);
672 }
673 
advanceToken(statementInfo * const st)674 static void advanceToken (statementInfo* const st)
675 {
676 	if (st->tokenIndex >= (unsigned int) NumTokens - 1)
677 		st->tokenIndex = 0;
678 	else
679 		++st->tokenIndex;
680 	initToken (st->token [st->tokenIndex]);
681 }
682 
prevToken(const statementInfo * const st,unsigned int n)683 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
684 {
685 	unsigned int tokenIndex;
686 	unsigned int num = (unsigned int) NumTokens;
687 	Assert (n < num);
688 	tokenIndex = (st->tokenIndex + num - n) % num;
689 	return st->token [tokenIndex];
690 }
691 
setToken(statementInfo * const st,const tokenType type)692 static void setToken (statementInfo *const st, const tokenType type)
693 {
694 	tokenInfo *token;
695 	token = activeToken (st);
696 	initToken (token);
697 	token->type = type;
698 }
699 
retardToken(statementInfo * const st)700 static void retardToken (statementInfo *const st)
701 {
702 	if (st->tokenIndex == 0)
703 		st->tokenIndex = (unsigned int) NumTokens - 1;
704 	else
705 		--st->tokenIndex;
706 	setToken (st, TOKEN_NONE);
707 }
708 
newToken(void)709 static tokenInfo *newToken (void)
710 {
711 	tokenInfo *const token = xMalloc (1, tokenInfo);
712 	token->name = vStringNew ();
713 	initToken (token);
714 	return token;
715 }
716 
deleteToken(tokenInfo * const token)717 static void deleteToken (tokenInfo *const token)
718 {
719 	if (token != NULL)
720 	{
721 		vStringDelete (token->name);
722 		eFree (token);
723 	}
724 }
725 
accessString(const accessType access)726 static const char *accessString (const accessType access)
727 {
728 	static const char *const names [] = {
729 		"?", "local", "private", "protected", "public", "default"
730 	};
731 	Assert (ARRAY_SIZE (names) == ACCESS_COUNT);
732 	Assert ((int) access < ACCESS_COUNT);
733 	return names [(int) access];
734 }
735 
implementationString(const impType imp)736 static const char *implementationString (const impType imp)
737 {
738 	static const char *const names [] ={
739 		"?", "abstract", "virtual", "pure virtual"
740 	};
741 	Assert (ARRAY_SIZE (names) == IMP_COUNT);
742 	Assert ((int) imp < IMP_COUNT);
743 	return names [(int) imp];
744 }
745 
746 /*
747 *   Debugging functions
748 */
749 
750 #ifdef DEBUG
751 
752 #define boolString(c)   ((c) ? "true" : "false")
753 
tokenString(const tokenType type)754 static const char *tokenString (const tokenType type)
755 {
756 	static const char *const names [] = {
757 		"none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
758 		"name", "package", "paren-name", "semicolon", "specifier"
759 	};
760 	Assert (ARRAY_SIZE (names) == TOKEN_COUNT);
761 	Assert ((int) type < TOKEN_COUNT);
762 	return names [(int) type];
763 }
764 
scopeString(const tagScope scope)765 static const char *scopeString (const tagScope scope)
766 {
767 	static const char *const names [] = {
768 		"global", "static", "extern", "friend", "typedef"
769 	};
770 	Assert (ARRAY_SIZE (names) == SCOPE_COUNT);
771 	Assert ((int) scope < SCOPE_COUNT);
772 	return names [(int) scope];
773 }
774 
declString(const declType declaration)775 static const char *declString (const declType declaration)
776 {
777 	static const char *const names [] = {
778 		"?", "base", "class", "enum", "event", "function", "function template",
779 		"ignore", "interface", "mixin", "namespace", "no mangle", "package", "package ref",
780 		"private", "program", "protected", "public", "struct", "task", "template",
781 		"union", "using", "version", "annotation"
782 	};
783 	Assert (ARRAY_SIZE (names) == DECL_COUNT);
784 	Assert ((int) declaration < DECL_COUNT);
785 	return names [(int) declaration];
786 }
787 
keywordString(const keywordId keyword)788 static const char *keywordString (const keywordId keyword)
789 {
790 	const size_t count = ARRAY_SIZE (KeywordTable);
791 	const char *name = "none";
792 	size_t i;
793 	for (i = 0  ;  i < count  ;  ++i)
794 	{
795 		const keywordDesc *p = &KeywordTable [i];
796 		if (p->id == keyword)
797 		{
798 			name = p->name;
799 			break;
800 		}
801 	}
802 	return name;
803 }
804 
pt(tokenInfo * const token)805 static void CTAGS_ATTR_UNUSED pt (tokenInfo *const token)
806 {
807 	if (isType (token, TOKEN_NAME))
808 		printf ("type: %-12s: %-13s   line: %lu\n",
809 			tokenString (token->type), vStringValue (token->name),
810 			token->lineNumber);
811 	else if (isType (token, TOKEN_KEYWORD))
812 		printf ("type: %-12s: %-13s   line: %lu\n",
813 			tokenString (token->type), keywordString (token->keyword),
814 			token->lineNumber);
815 	else
816 		printf ("type: %-12s                  line: %lu\n",
817 			tokenString (token->type), token->lineNumber);
818 }
819 
ps(statementInfo * const st)820 static void CTAGS_ATTR_UNUSED ps (statementInfo *const st)
821 {
822 #define P	"[%-7u]"
823 	static unsigned int id = 0;
824 	unsigned int i;
825 	printf (P"scope: %s   decl: %s   gotName: %s   gotParenName: %s\n", id,
826 		scopeString (st->scope), declString (st->declaration),
827 		boolString (st->gotName), boolString (st->gotParenName));
828 	printf (P"haveQualifyingName: %s\n", id, boolString (st->haveQualifyingName));
829 	printf (P"access: %s   default: %s\n", id, accessString (st->member.access),
830 		accessString (st->member.accessDefault));
831 	printf (P"token  : ", id);
832 	pt (activeToken (st));
833 	for (i = 1  ;  i < (unsigned int) NumTokens  ;  ++i)
834 	{
835 		printf (P"prev %u : ", id, i);
836 		pt (prevToken (st, i));
837 	}
838 	printf (P"context: ", id);
839 	pt (st->context);
840 	id++;
841 #undef P
842 }
843 
844 #endif
845 
846 /*
847 *   Statement management
848 */
849 
isContextualKeyword(const tokenInfo * const token)850 static bool isContextualKeyword (const tokenInfo *const token)
851 {
852 	bool result;
853 	switch (token->keyword)
854 	{
855 		case KEYWORD_CLASS:
856 		case KEYWORD_ENUM:
857 		case KEYWORD_INTERFACE:
858 		case KEYWORD_NAMESPACE:
859 		case KEYWORD_STRUCT:
860 		case KEYWORD_UNION:
861 		case KEYWORD_VERSION:
862 		case KEYWORD_TEMPLATE:
863 			result = true;
864 			break;
865 
866 		default: result = false; break;
867 	}
868 	return result;
869 }
870 
isContextualStatement(const statementInfo * const st)871 static bool isContextualStatement (const statementInfo *const st)
872 {
873 	bool result = false;
874 	if (st != NULL) switch (st->declaration)
875 	{
876 		case DECL_CLASS:
877 		case DECL_ENUM:
878 		case DECL_INTERFACE:
879 		case DECL_NAMESPACE:
880 		case DECL_PRIVATE:
881 		case DECL_PROTECTED:
882 		case DECL_PUBLIC:
883 		case DECL_STRUCT:
884 		case DECL_UNION:
885 		case DECL_TEMPLATE:
886 		case DECL_ANNOTATION:
887 			result = true;
888 			break;
889 
890 		default: result = false; break;
891 	}
892 	return result;
893 }
894 
isMember(const statementInfo * const st)895 static bool isMember (const statementInfo *const st)
896 {
897 	bool result;
898 	if (isType (st->context, TOKEN_NAME))
899 		result = true;
900 	else
901 		result = (bool)
902 			(st->parent != NULL && isContextualStatement (st->parent));
903 	return result;
904 }
905 
initMemberInfo(statementInfo * const st)906 static void initMemberInfo (statementInfo *const st)
907 {
908 	accessType accessDefault = ACCESS_UNDEFINED;
909 	if (st->parent != NULL) switch (st->parent->declaration)
910 	{
911 		case DECL_PRIVATE:
912 			accessDefault = ACCESS_PRIVATE;
913 			break;
914 		case DECL_PROTECTED:
915 			accessDefault = ACCESS_PROTECTED;
916 			break;
917 		case DECL_PUBLIC:
918 			accessDefault = ACCESS_PUBLIC;
919 			break;
920 		case DECL_ENUM:
921 			accessDefault = (isInputLanguage (Lang_java) ? ACCESS_PUBLIC : ACCESS_UNDEFINED);
922 			break;
923 		case DECL_NAMESPACE:
924 			accessDefault = ACCESS_UNDEFINED;
925 			break;
926 
927 		case DECL_CLASS:
928 			if (isInputLanguage (Lang_java))
929 				accessDefault = ACCESS_DEFAULT;
930 			else if (isInputLanguage (Lang_d))
931 				accessDefault = ACCESS_PUBLIC;
932 			else
933 				accessDefault = ACCESS_PRIVATE;
934 			break;
935 
936 		case DECL_INTERFACE:
937 		case DECL_STRUCT:
938 		case DECL_UNION:
939 		case DECL_ANNOTATION:
940 			accessDefault = ACCESS_PUBLIC;
941 			break;
942 
943 		default: break;
944 	}
945 	st->member.accessDefault = accessDefault;
946 	st->member.access		 = accessDefault;
947 }
948 
reinitStatement(statementInfo * const st,const bool partial)949 static void reinitStatement (statementInfo *const st, const bool partial)
950 {
951 	unsigned int i;
952 
953 	if (! partial)
954 	{
955 		st->scope = SCOPE_GLOBAL;
956 		if (isContextualStatement (st->parent))
957 			st->declaration = DECL_BASE;
958 		else
959 			st->declaration = DECL_NONE;
960 	}
961 	st->gotParenName	= false;
962 	st->isPointer		= false;
963 	st->inFunction		= false;
964 	st->assignment		= false;
965 	st->notVariable		= false;
966 	st->implementation	= IMP_DEFAULT;
967 	st->gotArgs			= false;
968 	st->gotName			= false;
969 	st->haveQualifyingName = false;
970 	st->tokenIndex		= 0;
971 
972 	if (st->parent != NULL)
973 		st->inFunction = st->parent->inFunction;
974 
975 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
976 		initToken (st->token [i]);
977 
978 	initToken (st->context);
979 
980 	/*	Keep the block name, so that a variable following after a comma will
981 	 *	still have the structure name.
982 	 */
983 	if (! partial)
984 		initToken (st->blockName);
985 
986 	vStringClear (st->parentClasses);
987 
988 	/*  Init member info.
989 	 */
990 	if (! partial)
991 		st->member.access = st->member.accessDefault;
992 }
993 
initStatement(statementInfo * const st,statementInfo * const parent)994 static void initStatement (statementInfo *const st, statementInfo *const parent)
995 {
996 	st->parent = parent;
997 	initMemberInfo (st);
998 	reinitStatement (st, false);
999 }
1000 
1001 /*
1002 *   Tag generation functions
1003 */
1004 #define cTagKind(type) cTagKindFull(type, true)
1005 #define cTagKindNoAssert(type) cTagKindFull(type, false)
cTagKindFull(const tagType type,const bool with_assert)1006 static cKind cTagKindFull (const tagType type, const bool with_assert)
1007 {
1008 	cKind result = CK_UNDEFINED;
1009 	switch (type)
1010 	{
1011 		case TAG_CLASS:      result = CK_CLASS;       break;
1012 		case TAG_ENUM:       result = CK_ENUMERATION; break;
1013 		case TAG_ENUMERATOR: result = CK_ENUMERATOR;  break;
1014 		case TAG_FUNCTION:   result = CK_FUNCTION;    break;
1015 		case TAG_LOCAL:      result = CK_LOCAL;       break;
1016 		case TAG_MEMBER:     result = CK_MEMBER;      break;
1017 		case TAG_NAMESPACE:  result = CK_NAMESPACE;   break;
1018 		case TAG_PROTOTYPE:  result = CK_PROTOTYPE;   break;
1019 		case TAG_STRUCT:     result = CK_STRUCT;      break;
1020 		case TAG_TYPEDEF:    result = CK_TYPEDEF;     break;
1021 		case TAG_UNION:      result = CK_UNION;       break;
1022 		case TAG_VARIABLE:   result = CK_VARIABLE;    break;
1023 		case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1024 		case TAG_LABEL:      result = CK_LABEL; break;
1025 
1026 		default: if (with_assert) Assert ("Bad C tag type" == NULL); break;
1027 	}
1028 	return result;
1029 }
1030 
1031 #define csharpTagKind(type) csharpTagKindFull(type, true)
1032 #define csharpTagKindNoAssert(type) csharpTagKindFull(type, false)
csharpTagKindFull(const tagType type,const bool with_assert)1033 static csharpKind csharpTagKindFull (const tagType type, const bool with_assert)
1034 {
1035 	csharpKind result = CSK_UNDEFINED;
1036 	switch (type)
1037 	{
1038 		case TAG_CLASS:      result = CSK_CLASS;           break;
1039 		case TAG_ENUM:       result = CSK_ENUMERATION;     break;
1040 		case TAG_ENUMERATOR: result = CSK_ENUMERATOR;      break;
1041 		case TAG_EVENT:      result = CSK_EVENT;           break;
1042 		case TAG_FIELD:      result = CSK_FIELD ;          break;
1043 		case TAG_INTERFACE:  result = CSK_INTERFACE;       break;
1044 		case TAG_LOCAL:      result = CSK_LOCAL;           break;
1045 		case TAG_METHOD:     result = CSK_METHOD;          break;
1046 		case TAG_NAMESPACE:  result = CSK_NAMESPACE;       break;
1047 		case TAG_PROPERTY:   result = CSK_PROPERTY;        break;
1048 		case TAG_STRUCT:     result = CSK_STRUCT;          break;
1049 		case TAG_TYPEDEF:    result = CSK_TYPEDEF;         break;
1050 
1051 		default: if (with_assert) Assert ("Bad C# tag type" == NULL); break;
1052 	}
1053 	return result;
1054 }
1055 
1056 #define javaTagKind(type) javaTagKindFull(type, true)
1057 #define javaTagKindNoAssert(type) javaTagKindFull(type, false)
javaTagKindFull(const tagType type,bool with_assert)1058 static javaKind javaTagKindFull (const tagType type, bool with_assert)
1059 {
1060 	javaKind result = JK_UNDEFINED;
1061 	switch (type)
1062 	{
1063 		case TAG_CLASS:      result = JK_CLASS;         break;
1064 		case TAG_ENUM:       result = JK_ENUM;          break;
1065 		case TAG_ENUMERATOR: result = JK_ENUM_CONSTANT; break;
1066 		case TAG_FIELD:      result = JK_FIELD;         break;
1067 		case TAG_INTERFACE:  result = JK_INTERFACE;     break;
1068 		case TAG_LOCAL:      result = JK_LOCAL;         break;
1069 		case TAG_METHOD:     result = JK_METHOD;        break;
1070 		case TAG_PACKAGE:    /* Fall through */
1071 		case TAG_PACKAGEREF: result = JK_PACKAGE;       break;
1072 		case TAG_ANNOTATION: result = JK_ANNOTATION;     break;
1073 
1074 		default: if (with_assert) Assert ("Bad Java tag type" == NULL); break;
1075 	}
1076 	return result;
1077 }
1078 
1079 #define dTagKind(type) dTagKindFull(type, true)
1080 #define dTagKindNoAssert(type) dTagKindFull(type, false)
dTagKindFull(const tagType type,bool with_assert)1081 static dKind dTagKindFull (const tagType type, bool with_assert)
1082 {
1083 	dKind result = DK_UNDEFINED;
1084 	switch (type)
1085 	{
1086 		case TAG_TYPEDEF:    result = DK_ALIAS;           break;
1087 		case TAG_CLASS:      result = DK_CLASS;           break;
1088 		case TAG_ENUM:       result = DK_ENUMERATION;     break;
1089 		case TAG_ENUMERATOR: result = DK_ENUMERATOR;      break;
1090 		case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1091 		case TAG_FUNCTION:   result = DK_FUNCTION;        break;
1092 		case TAG_INTERFACE:  result = DK_INTERFACE;       break;
1093 		case TAG_LOCAL:      result = DK_LOCAL;           break;
1094 		case TAG_MEMBER:     result = DK_MEMBER;          break;
1095 		case TAG_MIXIN:      result = DK_MIXIN;           break;
1096 		case TAG_PACKAGE:    result = DK_MODULE;          break;
1097 		case TAG_NAMESPACE:  result = DK_NAMESPACE;       break;
1098 		case TAG_PROTOTYPE:  result = DK_PROTOTYPE;       break;
1099 		case TAG_STRUCT:     result = DK_STRUCT;          break;
1100 		case TAG_TEMPLATE:   result = DK_TEMPLATE;        break;
1101 		case TAG_UNION:      result = DK_UNION;           break;
1102 		case TAG_VARIABLE:   result = DK_VARIABLE;        break;
1103 		case TAG_VERSION:    result = DK_VERSION;         break;
1104 
1105 		default: if (with_assert) Assert ("Bad D tag type" == NULL); break;
1106 	}
1107 	return result;
1108 }
1109 
1110 #define veraTagKind(type) veraTagKindFull(type, true)
1111 #define veraTagKindNoAssert(type) veraTagKindFull(type, false)
veraTagKindFull(const tagType type,bool with_assert)1112 static veraKind veraTagKindFull (const tagType type, bool with_assert) {
1113 	veraKind result = VK_UNDEFINED;
1114 	switch (type)
1115 	{
1116 		case TAG_CLASS:      result = VK_CLASS;           break;
1117 		case TAG_ENUM:       result = VK_ENUMERATION;     break;
1118 		case TAG_ENUMERATOR: result = VK_ENUMERATOR;      break;
1119 		case TAG_FUNCTION:   result = VK_FUNCTION;        break;
1120 		case TAG_INTERFACE:  result = VK_INTERFACE;       break;
1121 		case TAG_LOCAL:      result = VK_LOCAL;           break;
1122 		case TAG_MEMBER:     result = VK_MEMBER;          break;
1123 		case TAG_PROGRAM:    result = VK_PROGRAM;         break;
1124 		case TAG_PROTOTYPE:  result = VK_PROTOTYPE;       break;
1125 		case TAG_SIGNAL:     result = VK_SIGNAL;          break;
1126 		case TAG_TASK:       result = VK_TASK;            break;
1127 		case TAG_TYPEDEF:    result = VK_TYPEDEF;         break;
1128 		case TAG_VARIABLE:   result = VK_VARIABLE;        break;
1129 		case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
1130 
1131 		default: if (with_assert) Assert ("Bad Vera tag type" == NULL); break;
1132 	}
1133 	return result;
1134 }
1135 
kindIndexForType(const tagType type)1136 static int kindIndexForType (const tagType type)
1137 {
1138 	int result;
1139 	if (isInputLanguage (Lang_csharp))
1140 		result = csharpTagKind (type);
1141 	else if (isInputLanguage (Lang_java))
1142 		result = javaTagKind (type);
1143 	else if (isInputLanguage (Lang_d))
1144 		result = dTagKind (type);
1145 	else if (isInputLanguage (Lang_vera))
1146 		result = veraTagKind (type);
1147 	else
1148 		result = cTagKind (type);
1149 	return result;
1150 }
1151 
roleForType(const tagType type)1152 static int roleForType (const tagType type)
1153 {
1154 	int result;
1155 
1156 	result = ROLE_DEFINITION_INDEX;
1157 	if (isInputLanguage (Lang_java))
1158 	{
1159 		if (type == TAG_PACKAGEREF)
1160 			result = JAVAR_PACKAGE_IMPORTED;
1161 	}
1162 
1163 	return result;
1164 }
1165 
tagName(const tagType type)1166 static const char *tagName (const tagType type)
1167 {
1168 	const char* result;
1169 	if (isInputLanguage (Lang_csharp))
1170 		result = CsharpKinds [csharpTagKind (type)].name;
1171 	else if (isInputLanguage (Lang_java))
1172 		result = JavaKinds [javaTagKind (type)].name;
1173 	else if (isInputLanguage (Lang_d))
1174 		result = DKinds [dTagKind (type)].name;
1175 	else if (isInputLanguage (Lang_vera))
1176 		result = VeraKinds [veraTagKind (type)].name;
1177 	else
1178 		result = CKinds [cTagKind (type)].name;
1179 	return result;
1180 }
1181 
includeTag(const tagType type,const bool isFileScope)1182 static bool includeTag (const tagType type, const bool isFileScope)
1183 {
1184 	bool result;
1185 	int k;
1186 
1187 	if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE))
1188 		return false;
1189 	else if (isInputLanguage (Lang_csharp))
1190 		k = csharpTagKindNoAssert (type);
1191 	else if (isInputLanguage (Lang_java))
1192 		k = javaTagKindNoAssert (type);
1193 	else if (isInputLanguage (Lang_d))
1194 		k = dTagKindNoAssert (type);
1195 	else if (isInputLanguage (Lang_vera))
1196 		k = veraTagKindNoAssert (type);
1197 	else
1198 		k = cTagKindNoAssert (type);
1199 
1200 	if (k == COMMONK_UNDEFINED)
1201 		result = false;
1202 	else
1203 		result = isInputLanguageKindEnabled (k);
1204 
1205 	return result;
1206 }
1207 
declToTagType(const declType declaration)1208 static tagType declToTagType (const declType declaration)
1209 {
1210 	tagType type = TAG_UNDEFINED;
1211 
1212 	switch (declaration)
1213 	{
1214 		case DECL_CLASS:        type = TAG_CLASS;       break;
1215 		case DECL_ENUM:         type = TAG_ENUM;        break;
1216 		case DECL_EVENT:        type = TAG_EVENT;       break;
1217 		case DECL_FUNCTION:     type = TAG_FUNCTION;    break;
1218 		case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1219 		case DECL_INTERFACE:    type = TAG_INTERFACE;   break;
1220 		case DECL_NAMESPACE:    type = TAG_NAMESPACE;   break;
1221 		case DECL_PROGRAM:      type = TAG_PROGRAM;     break;
1222 		case DECL_PRIVATE:      type = TAG_CLASS;       break;
1223 		case DECL_PROTECTED:    type = TAG_CLASS;       break;
1224 		case DECL_PUBLIC:       type = TAG_CLASS;       break;
1225 		case DECL_TASK:         type = TAG_TASK;        break;
1226 		case DECL_TEMPLATE: 	type = TAG_TEMPLATE; 	break;
1227 		case DECL_STRUCT:       type = TAG_STRUCT;      break;
1228 		case DECL_UNION:        type = TAG_UNION;       break;
1229 		case DECL_VERSION: 		type = TAG_VERSION; 	break;
1230 		case DECL_ANNOTATION:   type = TAG_ANNOTATION;  break;
1231 
1232 		default: Assert ("Unexpected declaration" == NULL); break;
1233 	}
1234 	return type;
1235 }
1236 
accessField(const statementInfo * const st)1237 static const char* accessField (const statementInfo *const st)
1238 {
1239 	const char* result = NULL;
1240 	if (isInputLanguage (Lang_cpp)  &&  st->scope == SCOPE_FRIEND)
1241 		result = "friend";
1242 	else if (st->member.access != ACCESS_UNDEFINED)
1243 		result = accessString (st->member.access);
1244 	return result;
1245 }
1246 
addContextSeparator(vString * const scope)1247 static void addContextSeparator (vString *const scope)
1248 {
1249 	if (isInputLanguage (Lang_c)  ||  isInputLanguage (Lang_cpp))
1250 		vStringCatS (scope, "::");
1251 	else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage(Lang_d))
1252 		vStringPut (scope, '.');
1253 }
1254 
addOtherFields(tagEntryInfo * const tag,const tagType type,const statementInfo * const st,vString * const scope,vString * const typeRef)1255 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1256 							const statementInfo *const st,
1257 							vString *const scope, vString *const typeRef)
1258 {
1259 	/*  For selected tag types, append an extension flag designating the
1260 	 *  parent object in which the tag is defined.
1261 	 */
1262 	switch (type)
1263 	{
1264 		default: break;
1265 
1266 		case TAG_FUNCTION:
1267 		case TAG_TEMPLATE:
1268 		case TAG_METHOD:
1269 		case TAG_PROTOTYPE:
1270 			if (vStringLength (Signature) > 0)
1271 				tag->extensionFields.signature = vStringValue (Signature);
1272 		case TAG_CLASS:
1273 		case TAG_ENUM:
1274 		case TAG_ENUMERATOR:
1275 		case TAG_EVENT:
1276 		case TAG_FIELD:
1277 		case TAG_INTERFACE:
1278 		case TAG_MEMBER:
1279 		case TAG_NAMESPACE:
1280 		case TAG_PROPERTY:
1281 		case TAG_SIGNAL:
1282 		case TAG_STRUCT:
1283 		case TAG_TASK:
1284 		case TAG_TYPEDEF:
1285 		case TAG_UNION:
1286 		case TAG_ANNOTATION:
1287 			if (vStringLength (scope) > 0  &&
1288 				(isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1289 			{
1290 				tagType ptype;
1291 
1292 				if (isType (st->context, TOKEN_NAME))
1293 				{
1294 					tag->extensionFields.scopeKindIndex = kindIndexForType (TAG_CLASS);
1295 					tag->extensionFields.scopeName = vStringValue (scope);
1296 				}
1297 				else if ((ptype = declToTagType (parentDecl (st))) &&
1298 					 includeTag (ptype, isXtagEnabled(XTAG_FILE_SCOPE)))
1299 				{
1300 					tag->extensionFields.scopeKindIndex = kindIndexForType (ptype);
1301 					tag->extensionFields.scopeName = vStringValue (scope);
1302 				}
1303 			}
1304 			if ((type == TAG_CLASS  ||  type == TAG_INTERFACE  ||
1305 				 type == TAG_STRUCT || type == TAG_ANNOTATION) && vStringLength (st->parentClasses) > 0)
1306 			{
1307 
1308 				tag->extensionFields.inheritance =
1309 						vStringValue (st->parentClasses);
1310 			}
1311 			if (st->implementation != IMP_DEFAULT &&
1312 				(isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) ||
1313 				 isInputLanguage (Lang_d) || isInputLanguage (Lang_java)))
1314 			{
1315 				tag->extensionFields.implementation =
1316 						implementationString (st->implementation);
1317 			}
1318 			if (isMember (st))
1319 			{
1320 				tag->extensionFields.access = accessField (st);
1321 			}
1322 			break;
1323 	}
1324 
1325 	/* Add typename info, type of the tag and name of struct/union/etc. */
1326 	if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
1327 			&& isContextualStatement(st))
1328 	{
1329 		char *p;
1330 
1331 		tag->extensionFields.typeRef [0] =
1332 						tagName (declToTagType (st->declaration));
1333 		p = vStringValue (st->blockName->name);
1334 
1335 		/*  If there was no {} block get the name from the token before the
1336 		 *  name (current token is ';' or ',', previous token is the name).
1337 		 */
1338 		if (p == NULL || *p == '\0')
1339 		{
1340 			tokenInfo *const prev2 = prevToken (st, 2);
1341 			if (isType (prev2, TOKEN_NAME))
1342 				p = vStringValue (prev2->name);
1343 		}
1344 
1345 		/* Prepend the scope name if there is one. */
1346 		if (vStringLength (scope) > 0)
1347 		{
1348 			vStringCopy(typeRef, scope);
1349 			addContextSeparator (typeRef);
1350 			vStringCatS(typeRef, p);
1351 			p = vStringValue (typeRef);
1352 		}
1353 		tag->extensionFields.typeRef [1] = p;
1354 	}
1355 }
1356 
findScopeHierarchy(vString * const string,const statementInfo * const st)1357 static bool findScopeHierarchy (vString *const string, const statementInfo *const st)
1358 {
1359 	bool found = false;
1360 
1361 	vStringClear (string);
1362 
1363 	if (isType (st->context, TOKEN_NAME))
1364 	{
1365 		vStringCopy (string, st->context->name);
1366 		found = true;
1367 	}
1368 
1369 	if (st->parent != NULL)
1370 	{
1371 		vString *temp = vStringNew ();
1372 		const statementInfo *s;
1373 		for (s = st->parent  ;  s != NULL  ;  s = s->parent)
1374 		{
1375 			if (isContextualStatement (s) ||
1376 				s->declaration == DECL_NAMESPACE ||
1377 				s->declaration == DECL_PROGRAM)
1378 			{
1379 				if (s->declaration == DECL_PRIVATE ||
1380 					s->declaration == DECL_PROTECTED ||
1381 					s->declaration == DECL_PUBLIC) {
1382 					continue;
1383 				}
1384 
1385 				found = true;
1386 				vStringCopy (temp, string);
1387 				vStringClear (string);
1388 				if (isType (s->blockName, TOKEN_NAME))
1389 				{
1390 					if (isType (s->context, TOKEN_NAME) &&
1391 					    vStringLength (s->context->name) > 0)
1392 					{
1393 						vStringCat (string, s->context->name);
1394 						addContextSeparator (string);
1395 					}
1396 					vStringCat (string, s->blockName->name);
1397 					if (vStringLength (temp) > 0)
1398 						addContextSeparator (string);
1399 					vStringCat (string, temp);
1400 				}
1401 				else
1402 				{
1403 					/* Information for building scope string
1404 					   is lacking. Maybe input is broken. */
1405 					found = false;
1406 				}
1407 			}
1408 		}
1409 		vStringDelete (temp);
1410 	}
1411 	return found;
1412 }
1413 
makeExtraTagEntry(const tagType type,tagEntryInfo * const e,vString * const scope)1414 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1415 							   vString *const scope)
1416 {
1417 	if (isXtagEnabled(XTAG_QUALIFIED_TAGS)  &&
1418 		scope != NULL  &&  vStringLength (scope) > 0)
1419 	{
1420 		vString *const scopedName = vStringNew ();
1421 
1422 		if (type != TAG_ENUMERATOR)
1423 			vStringCopy (scopedName, scope);
1424 		else
1425 		{
1426 			/* remove last component (i.e. enumeration name) from scope */
1427 			const char* const sc = vStringValue (scope);
1428 			const char* colon = strrchr (sc, ':');
1429 			if (colon != NULL)
1430 			{
1431 				while (*colon == ':'  &&  colon > sc)
1432 					--colon;
1433 				vStringNCopy (scopedName, scope, colon + 1 - sc);
1434 			}
1435 		}
1436 		if (vStringLength (scopedName) > 0)
1437 		{
1438 			addContextSeparator (scopedName);
1439 			vStringCatS (scopedName, e->name);
1440 			e->name = vStringValue (scopedName);
1441 			markTagExtraBit (e, XTAG_QUALIFIED_TAGS);
1442 			makeTagEntry (e);
1443 		}
1444 		vStringDelete (scopedName);
1445 	}
1446 }
1447 
makeTag(const tokenInfo * const token,const statementInfo * const st,bool isFileScope,const tagType type)1448 static int makeTag (const tokenInfo *const token,
1449 					 const statementInfo *const st,
1450 					 bool isFileScope, const tagType type)
1451 {
1452 	int corkIndex = CORK_NIL;
1453 	/*  Nothing is really of file scope when it appears in a header file.
1454 	 */
1455 	isFileScope = (bool) (isFileScope && ! isInputHeaderFile ());
1456 
1457 	if (isType (token, TOKEN_NAME)  &&  vStringLength (token->name) > 0  &&
1458 		includeTag (type, isFileScope))
1459 	{
1460 		vString *scope;
1461 		vString *typeRef;
1462 		bool isScopeBuilt;
1463 		/* Use "typeRef" to store the typename from addOtherFields() until
1464 		 * it's used in makeTagEntry().
1465 		 */
1466 		tagEntryInfo e;
1467 		int kind;
1468 		int role;
1469 
1470 		role = roleForType (type);
1471 		if (! (role == ROLE_DEFINITION_INDEX || isXtagEnabled (XTAG_REFERENCE_TAGS)))
1472 			return CORK_NIL;
1473 
1474 		scope  = vStringNew ();
1475 		typeRef = vStringNew ();
1476 
1477 		kind  = kindIndexForType(type);
1478 		if (role == ROLE_DEFINITION_INDEX)
1479 			initTagEntry (&e, vStringValue (token->name), kind);
1480 		else
1481 			initRefTagEntry (&e, vStringValue (token->name), kind, role);
1482 
1483 		e.lineNumber	= token->lineNumber;
1484 		e.filePosition	= token->filePosition;
1485 		e.isFileScope	= isFileScope;
1486 		if (e.isFileScope)
1487 			markTagExtraBit (&e, XTAG_FILE_SCOPE);
1488 
1489 		isScopeBuilt = findScopeHierarchy (scope, st);
1490 		addOtherFields (&e, type, st, scope, typeRef);
1491 
1492 		corkIndex = makeTagEntry (&e);
1493 		if (isScopeBuilt)
1494 			makeExtraTagEntry (type, &e, scope);
1495 		vStringDelete (scope);
1496 		vStringDelete (typeRef);
1497 	}
1498 	return corkIndex;
1499 }
1500 
isValidTypeSpecifier(const declType declaration)1501 static bool isValidTypeSpecifier (const declType declaration)
1502 {
1503 	bool result;
1504 	switch (declaration)
1505 	{
1506 		case DECL_BASE:
1507 		case DECL_CLASS:
1508 		case DECL_ENUM:
1509 		case DECL_EVENT:
1510 		case DECL_STRUCT:
1511 		case DECL_UNION:
1512 		case DECL_ANNOTATION:
1513 			result = true;
1514 			break;
1515 
1516 		default:
1517 			result = false;
1518 			break;
1519 	}
1520 	return result;
1521 }
1522 
qualifyEnumeratorTag(const statementInfo * const st,const tokenInfo * const nameToken)1523 static int qualifyEnumeratorTag (const statementInfo *const st,
1524 								 const tokenInfo *const nameToken)
1525 {
1526 	int corkIndex = CORK_NIL;
1527 	if (isType (nameToken, TOKEN_NAME))
1528 		corkIndex = makeTag (nameToken, st, true, TAG_ENUMERATOR);
1529 	return corkIndex;
1530 }
1531 
qualifyFunctionTag(const statementInfo * const st,const tokenInfo * const nameToken)1532 static int qualifyFunctionTag (const statementInfo *const st,
1533 								const tokenInfo *const nameToken)
1534 {
1535 	int corkIndex = CORK_NIL;
1536 	if (isType (nameToken, TOKEN_NAME))
1537 	{
1538 		tagType type;
1539 		const bool isFileScope =
1540 						(bool) (st->member.access == ACCESS_PRIVATE ||
1541 						(!isMember (st)  &&  st->scope == SCOPE_STATIC));
1542 		if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp))
1543 			type = TAG_METHOD;
1544 		else if (isInputLanguage (Lang_vera)  &&  st->declaration == DECL_TASK)
1545 			type = TAG_TASK;
1546 		else
1547 			type = TAG_FUNCTION;
1548 		corkIndex = makeTag (nameToken, st, isFileScope, type);
1549 	}
1550 	return corkIndex;
1551 }
1552 
qualifyFunctionDeclTag(const statementInfo * const st,const tokenInfo * const nameToken)1553 static int qualifyFunctionDeclTag (const statementInfo *const st,
1554 									const tokenInfo *const nameToken)
1555 {
1556 	int corkIndex = CORK_NIL;
1557 	if (! isType (nameToken, TOKEN_NAME))
1558 		;
1559 	else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp))
1560 		corkIndex = qualifyFunctionTag (st, nameToken);
1561 	else if (st->scope == SCOPE_TYPEDEF)
1562 		corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
1563 	else if (isValidTypeSpecifier (st->declaration) && ! isInputLanguage (Lang_csharp))
1564 		corkIndex = makeTag (nameToken, st, true, TAG_PROTOTYPE);
1565 	return corkIndex;
1566 }
1567 
qualifyCompoundTag(const statementInfo * const st,const tokenInfo * const nameToken)1568 static int qualifyCompoundTag (const statementInfo *const st,
1569 								const tokenInfo *const nameToken)
1570 {
1571 	int corkIndex = CORK_NIL;
1572 	if (isType (nameToken, TOKEN_NAME))
1573 	{
1574 		const tagType type = declToTagType (st->declaration);
1575 		const bool fileScoped = (bool)
1576 				(!(isInputLanguage (Lang_java) ||
1577 				   isInputLanguage (Lang_csharp) ||
1578 				   isInputLanguage (Lang_vera)));
1579 
1580 		if (type != TAG_UNDEFINED)
1581 			corkIndex = makeTag (nameToken, st, fileScoped, type);
1582 	}
1583 	return corkIndex;
1584 }
1585 
qualifyBlockTag(statementInfo * const st,const tokenInfo * const nameToken)1586 static int qualifyBlockTag (statementInfo *const st,
1587 							 const tokenInfo *const nameToken)
1588 {
1589 	int corkIndex = CORK_NIL;
1590 	switch (st->declaration)
1591 	{
1592 
1593 		case DECL_CLASS:
1594 		case DECL_ENUM:
1595 		case DECL_INTERFACE:
1596 		case DECL_NAMESPACE:
1597 		case DECL_PROGRAM:
1598 		case DECL_STRUCT:
1599 		case DECL_UNION:
1600 		case DECL_TEMPLATE:
1601 		case DECL_VERSION:
1602 		case DECL_ANNOTATION:
1603 			corkIndex = qualifyCompoundTag (st, nameToken);
1604 			break;
1605 		default: break;
1606 	}
1607 	return corkIndex;
1608 }
1609 
qualifyVariableTag(const statementInfo * const st,const tokenInfo * const nameToken)1610 static int qualifyVariableTag (const statementInfo *const st,
1611 								const tokenInfo *const nameToken)
1612 {
1613 	int corkIndex = CORK_NIL;
1614 	/*	We have to watch that we do not interpret a declaration of the
1615 	 *	form "struct tag;" as a variable definition. In such a case, the
1616 	 *	token preceding the name will be a keyword.
1617 	 */
1618 	if (! isType (nameToken, TOKEN_NAME))
1619 		;
1620 	else if (st->scope == SCOPE_TYPEDEF)
1621 		corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
1622 	else if (st->declaration == DECL_EVENT)
1623 		corkIndex = makeTag (nameToken, st, (bool) (st->member.access == ACCESS_PRIVATE),
1624 							 TAG_EVENT);
1625 	else if (st->declaration == DECL_PACKAGE)
1626 		corkIndex = makeTag (nameToken, st, false, TAG_PACKAGE);
1627 	else if (st->declaration == DECL_PACKAGEREF)
1628 		corkIndex = makeTag (nameToken, st, false, TAG_PACKAGEREF);
1629 	else if (st->declaration == DECL_USING && st->assignment)
1630 		corkIndex = makeTag (nameToken, st, true, TAG_TYPEDEF);
1631 	else if (isValidTypeSpecifier (st->declaration))
1632 	{
1633 		if (st->notVariable)
1634 			;
1635 		else if (isMember (st))
1636 		{
1637 			if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp))
1638 				corkIndex = makeTag (nameToken, st,
1639 									 (bool) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1640 			else if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_STATIC)
1641 				corkIndex = makeTag (nameToken, st, true, TAG_MEMBER);
1642 		}
1643 		else
1644 		{
1645 			if (st->scope == SCOPE_EXTERN  ||  ! st->haveQualifyingName)
1646 				corkIndex = makeTag (nameToken, st, false, TAG_EXTERN_VAR);
1647 			else if (st->inFunction)
1648 				corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
1649 									 TAG_LOCAL);
1650 			else
1651 				corkIndex = makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC),
1652 									 TAG_VARIABLE);
1653 		}
1654 	}
1655 	return corkIndex;
1656 }
1657 
1658 /*
1659 *   Parsing functions
1660 */
1661 
skipToOneOf(const char * const chars)1662 static int skipToOneOf (const char *const chars)
1663 {
1664 	int c;
1665 	do
1666 		c = cppGetc ();
1667 	while (c != EOF  &&  c != '\0'  &&  strchr (chars, c) == NULL);
1668 	return c;
1669 }
1670 
1671 /*  Skip to the next non-white character.
1672  */
skipToNonWhite(void)1673 static int skipToNonWhite (void)
1674 {
1675 	bool found = false;
1676 	int c;
1677 
1678 #if 0
1679 	do
1680 		c = cppGetc ();
1681 	while (cppIsspace (c));
1682 #else
1683 	while (1)
1684 	{
1685 		c = cppGetc ();
1686 		if (cppIsspace (c))
1687 			found = true;
1688 		else
1689 			break;
1690 	}
1691 	if (CollectingSignature && found)
1692 		vStringPut (Signature, ' ');
1693 #endif
1694 
1695 	return c;
1696 }
1697 
1698 /*  Skips to the next brace in column 1. This is intended for cases where
1699  *  preprocessor constructs result in unbalanced braces.
1700  */
skipToFormattedBraceMatch(void)1701 static void skipToFormattedBraceMatch (void)
1702 {
1703 	int c, next;
1704 
1705 	c = cppGetc ();
1706 	next = cppGetc ();
1707 	while (c != EOF  &&  (c != '\n'  ||  next != '}'))
1708 	{
1709 		c = next;
1710 		next = cppGetc ();
1711 	}
1712 }
1713 
1714 /*  Skip to the matching character indicated by the pair string. If skipping
1715  *  to a matching brace and any brace is found within a different level of a
1716  *  #if conditional statement while brace formatting is in effect, we skip to
1717  *  the brace matched by its formatting. It is assumed that we have already
1718  *  read the character which starts the group (i.e. the first character of
1719  *  "pair").
1720  */
skipToMatch(const char * const pair)1721 static void skipToMatch (const char *const pair)
1722 {
1723 	const bool braceMatching = (bool) (strcmp ("{}", pair) == 0);
1724 	const bool braceFormatting = (bool) (cppIsBraceFormat () && braceMatching);
1725 	const unsigned int initialLevel = cppGetDirectiveNestLevel ();
1726 	const int begin = pair [0], end = pair [1];
1727 	const unsigned long inputLineNumber = getInputLineNumber ();
1728 	int matchLevel = 1;
1729 	int c = '\0';
1730 
1731 	while (matchLevel > 0  &&  (c = skipToNonWhite ()) != EOF)
1732 	{
1733 		if (CollectingSignature)
1734 			vStringPut (Signature, c);
1735 		if (c == begin)
1736 		{
1737 			++matchLevel;
1738 			if (braceFormatting  &&  cppGetDirectiveNestLevel () != initialLevel)
1739 			{
1740 				skipToFormattedBraceMatch ();
1741 				break;
1742 			}
1743 		}
1744 		else if (c == end)
1745 		{
1746 			--matchLevel;
1747 			if (braceFormatting  &&  cppGetDirectiveNestLevel () != initialLevel)
1748 			{
1749 				skipToFormattedBraceMatch ();
1750 				break;
1751 			}
1752 		}
1753 	}
1754 	if (c == EOF)
1755 	{
1756 		verbose ("%s: failed to find match for '%c' at line %lu\n",
1757 				getInputFileName (), begin, inputLineNumber);
1758 		if (braceMatching)
1759 			longjmp (Exception, (int) ExceptionBraceFormattingError);
1760 		else
1761 			longjmp (Exception, (int) ExceptionFormattingError);
1762 	}
1763 }
1764 
skipCppTemplateParameterList(void)1765 static void skipCppTemplateParameterList (void)
1766 {
1767 	const unsigned long inputLineNumber = getInputLineNumber ();
1768 	int angleBracketsLevel = 1;
1769 	int c = '\0';
1770 
1771 	int roundBracketsLevel = 0;
1772 	bool defaultValueExpected = false;
1773 
1774 	while (angleBracketsLevel > 0  &&  (c = skipToNonWhite ()) != EOF)
1775 	{
1776 		if (CollectingSignature)
1777 			vStringPut (Signature, c);
1778 
1779 		if (c == '<')
1780 		{
1781 			int x = cppGetc ();
1782 			if(x != '<')
1783 			{
1784 				cppUngetc (x);
1785 				if (roundBracketsLevel == 0)
1786 				{
1787 					if (defaultValueExpected == false)
1788 						++angleBracketsLevel;
1789 				}
1790 			}
1791 			else if(CollectingSignature)
1792 				vStringPut (Signature, x);
1793 		}
1794 		else if (c == '>')
1795 		{
1796 			int x = cppGetc ();
1797 			if( x != '>')
1798 			{
1799 				cppUngetc (x);
1800 				if (roundBracketsLevel == 0)
1801 				{
1802 					--angleBracketsLevel;
1803 					defaultValueExpected = false;
1804 				}
1805 			}
1806 			else if(CollectingSignature)
1807 				vStringPut (Signature, x);
1808 		}
1809 		else if (c == '(')
1810 			roundBracketsLevel ++;
1811 		else if (c == ')')
1812 			roundBracketsLevel --;
1813 		else if (c == '=' && (roundBracketsLevel == 0))
1814 			defaultValueExpected = true;
1815 		else if (c == ',' && (roundBracketsLevel == 0))
1816 			defaultValueExpected = false;
1817 	}
1818 
1819 	if (c == EOF)
1820 	{
1821 		verbose ("%s: failed to find match for '%c' at line %lu\n",
1822 				getInputFileName (), '<', inputLineNumber);
1823 		longjmp (Exception, (int) ExceptionFormattingError);
1824 	}
1825 }
1826 
skipParens(void)1827 static void skipParens (void)
1828 {
1829 	const int c = skipToNonWhite ();
1830 
1831 	if (c == '(')
1832 		skipToMatch ("()");
1833 	else
1834 		cppUngetc (c);
1835 }
1836 
skipBraces(void)1837 static void skipBraces (void)
1838 {
1839 	const int c = skipToNonWhite ();
1840 
1841 	if (c == '{')
1842 		skipToMatch ("{}");
1843 	else
1844 		cppUngetc (c);
1845 }
1846 
analyzeKeyword(const char * const name)1847 static keywordId analyzeKeyword (const char *const name)
1848 {
1849 	const keywordId id = (keywordId) lookupKeyword (name, getInputLanguage ());
1850 	return id;
1851 }
1852 
analyzeIdentifier(tokenInfo * const token)1853 static void analyzeIdentifier (tokenInfo *const token)
1854 {
1855 	const char * name = vStringValue (token->name);
1856 
1857 	vString * replacement = NULL;
1858 
1859 	if(!isInputLanguage(Lang_java))
1860 	{
1861 		// C: check for ignored token
1862 		// (FIXME: java doesn't support -I... but maybe it should?)
1863 		const cppMacroInfo * macro = cppFindMacro(name);
1864 
1865 		if(macro)
1866 		{
1867 			if(macro->hasParameterList)
1868 			{
1869 				// This old parser does not support macro parameters: we simply assume them to be empty
1870 				int c = skipToNonWhite ();
1871 
1872 				if (c == '(')
1873 					skipToMatch ("()");
1874 			}
1875 
1876 			if(macro->replacements)
1877 			{
1878 				// There is a replacement: analyze it
1879 				replacement = cppBuildMacroReplacement(macro,NULL,0);
1880 				name = replacement ? vStringValue(replacement) : NULL;
1881 			} else {
1882 				// There is no replacement: just ignore
1883 				name = NULL;
1884 			}
1885 		}
1886 	}
1887 
1888 	if(!name)
1889 	{
1890 		initToken(token);
1891 		if(replacement)
1892 			vStringDelete(replacement);
1893 		return;
1894 	}
1895 
1896 	token->keyword = analyzeKeyword (name);
1897 
1898 	if (token->keyword == KEYWORD_NONE)
1899 		token->type = TOKEN_NAME;
1900 	else
1901 		token->type = TOKEN_KEYWORD;
1902 
1903 	if(replacement)
1904 		vStringDelete(replacement);
1905 }
1906 
readIdentifier(tokenInfo * const token,const int firstChar)1907 static void readIdentifier (tokenInfo *const token, const int firstChar)
1908 {
1909 	vString *const name = token->name;
1910 	int c = firstChar;
1911 	bool first = true;
1912 
1913 	initToken (token);
1914 
1915 	/* Bug #1585745: strangely, C++ destructors allow whitespace between
1916 	 * the ~ and the class name. */
1917 	if (isInputLanguage (Lang_cpp) && firstChar == '~')
1918 	{
1919 		vStringPut (name, c);
1920 		c = skipToNonWhite ();
1921 	}
1922 
1923 	do
1924 	{
1925 		vStringPut (name, c);
1926 		if (CollectingSignature)
1927 		{
1928 			if (!first)
1929 				vStringPut (Signature, c);
1930 			first = false;
1931 		}
1932 		c = cppGetc ();
1933 	} while (cppIsident (c) || ((isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp)) && (isHighChar (c) || c == '.')));
1934 	cppUngetc (c);        /* unget non-identifier character */
1935 
1936 	analyzeIdentifier (token);
1937 }
1938 
readPackageName(tokenInfo * const token,const int firstChar,bool allowWildCard)1939 static void readPackageName (tokenInfo *const token, const int firstChar, bool allowWildCard)
1940 {
1941 	vString *const name = token->name;
1942 	int c = firstChar;
1943 
1944 	initToken (token);
1945 
1946 	while (cppIsident (c)  || (allowWildCard && (c == '*')) ||  c == '.')
1947 	{
1948 		vStringPut (name, c);
1949 		c = cppGetc ();
1950 	}
1951 	cppUngetc (c);        /* unget non-package character */
1952 }
1953 
readPackageOrNamespace(statementInfo * const st,const declType declaration,bool allowWildCard)1954 static void readPackageOrNamespace (statementInfo *const st, const declType declaration, bool allowWildCard)
1955 {
1956 	st->declaration = declaration;
1957 
1958 	if (declaration == DECL_NAMESPACE && !isInputLanguage (Lang_csharp))
1959 	{
1960 		/* In C++ a namespace is specified one level at a time. */
1961 		return;
1962 	}
1963 	else
1964 	{
1965 		/* In C#, a namespace can also be specified like a Java package name. */
1966 		tokenInfo *const token = activeToken (st);
1967 		Assert (isType (token, TOKEN_KEYWORD));
1968 		readPackageName (token, skipToNonWhite (), allowWildCard);
1969 		token->type = TOKEN_NAME;
1970 		st->gotName = true;
1971 		st->haveQualifyingName = true;
1972 	}
1973 }
1974 
readVersionName(tokenInfo * const token,const int firstChar)1975 static void readVersionName (tokenInfo *const token, const int firstChar)
1976 {
1977 	vString *const name = token->name;
1978 	int c = firstChar;
1979 
1980 	initToken (token);
1981 
1982 	while (cppIsident (c))
1983 	{
1984 		vStringPut (name, c);
1985 		c = cppGetc ();
1986 	}
1987     cppGetc ();
1988 }
1989 
readVersion(statementInfo * const st)1990 static void readVersion (statementInfo *const st)
1991 {
1992     tokenInfo *const token = activeToken (st);
1993 	Assert (isType (token, TOKEN_KEYWORD));
1994     skipToNonWhite ();
1995 	readVersionName (token, cppGetc ());
1996 	token->type = TOKEN_NAME;
1997 	st->declaration = DECL_VERSION;
1998 	st->gotName = true;
1999 	st->haveQualifyingName = true;
2000 }
2001 
processName(statementInfo * const st)2002 static void processName (statementInfo *const st)
2003 {
2004 	Assert (isType (activeToken (st), TOKEN_NAME));
2005 	if (st->gotName  &&  st->declaration == DECL_NONE)
2006 		st->declaration = DECL_BASE;
2007 	st->gotName = true;
2008 	st->haveQualifyingName = true;
2009 }
2010 
readOperator(statementInfo * const st)2011 static void readOperator (statementInfo *const st)
2012 {
2013 	const char *const acceptable = "+-*/%^&|~!=<>,[]";
2014 	const tokenInfo* const prev = prevToken (st,1);
2015 	tokenInfo *const token = activeToken (st);
2016 	vString *const name = token->name;
2017 	int c = skipToNonWhite ();
2018 
2019 	/*  When we arrive here, we have the keyword "operator" in 'name'.
2020 	 */
2021 	if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
2022 		 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
2023 		;        /* ignore "operator" keyword if preceded by these keywords */
2024 	else if (c == '(')
2025 	{
2026 		/*  Verify whether this is a valid function call (i.e. "()") operator.
2027 		 */
2028 		if (cppGetc () == ')')
2029 		{
2030 			vStringPut (name, ' ');  /* always separate operator from keyword */
2031 			c = skipToNonWhite ();
2032 			if (c == '(')
2033 				vStringCatS (name, "()");
2034 		}
2035 		else
2036 		{
2037 			skipToMatch ("()");
2038 			c = cppGetc ();
2039 		}
2040 	}
2041 	else if (cppIsident1 (c))
2042 	{
2043 		/*  Handle "new" and "delete" operators, and conversion functions
2044 		 *  (per 13.3.1.1.2 [2] of the C++ spec).
2045 		 */
2046 		bool whiteSpace = true;  /* default causes insertion of space */
2047 		do
2048 		{
2049 			if (cppIsspace (c))
2050 				whiteSpace = true;
2051 			else
2052 			{
2053 				if (whiteSpace)
2054 				{
2055 					vStringPut (name, ' ');
2056 					whiteSpace = false;
2057 				}
2058 				vStringPut (name, c);
2059 			}
2060 			c = cppGetc ();
2061 		} while (! isOneOf (c, "(;")  &&  c != EOF);
2062 	}
2063 	else if (isOneOf (c, acceptable))
2064 	{
2065 		vStringPut (name, ' ');  /* always separate operator from keyword */
2066 		do
2067 		{
2068 			vStringPut (name, c);
2069 			c = cppGetc ();
2070 		} while (isOneOf (c, acceptable));
2071 	}
2072 
2073 	cppUngetc (c);
2074 
2075 	token->type	= TOKEN_NAME;
2076 	token->keyword = KEYWORD_NONE;
2077 	processName (st);
2078 }
2079 
copyToken(tokenInfo * const dest,const tokenInfo * const src)2080 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
2081 {
2082 	dest->type         = src->type;
2083 	dest->keyword      = src->keyword;
2084 	dest->filePosition = src->filePosition;
2085 	dest->lineNumber   = src->lineNumber;
2086 	vStringCopy (dest->name, src->name);
2087 }
2088 
setAccess(statementInfo * const st,const accessType access)2089 static void setAccess (statementInfo *const st, const accessType access)
2090 {
2091 	if (isInputLanguage (Lang_d))
2092 	{
2093 		int c = skipToNonWhite ();
2094 
2095 		if (c == '{')
2096 		{
2097 			switch(access)
2098 			{
2099 				case ACCESS_PRIVATE:
2100 					st->declaration = DECL_PRIVATE;
2101 					break;
2102 				case ACCESS_PUBLIC:
2103 					st->declaration = DECL_PUBLIC;
2104 					break;
2105 				case ACCESS_PROTECTED:
2106 					st->declaration = DECL_PROTECTED;
2107 					break;
2108 				default:
2109 					break;
2110 			}
2111 			st->member.access = access;
2112 			cppUngetc (c);
2113 		}
2114 		else if (c == ':') {
2115 			reinitStatement (st, false);
2116 			st->member.accessDefault = access;
2117 		}
2118 		else {
2119 			cppUngetc (c);
2120 		}
2121 	}
2122 
2123 	if (isMember (st))
2124 	{
2125 		if (isInputLanguage (Lang_cpp))
2126 		{
2127 			int c = skipToNonWhite ();
2128 
2129 			if (c == ':')
2130 				reinitStatement (st, false);
2131 			else
2132 				cppUngetc (c);
2133 
2134 			st->member.accessDefault = access;
2135 		}
2136 		else if (isInputLanguage (Lang_d))
2137 		{
2138 			if (st->parent != NULL &&
2139 				(st->parent->declaration == DECL_PRIVATE ||
2140 				st->parent->declaration == DECL_PROTECTED ||
2141 				st->parent->declaration == DECL_PUBLIC))
2142 			{
2143 				st->member.access = st->parent->member.access;
2144 				return;
2145 			}
2146 		}
2147 		st->member.access = access;
2148 	}
2149 }
2150 
discardTypeList(tokenInfo * const token)2151 static void discardTypeList (tokenInfo *const token)
2152 {
2153 	int c = skipToNonWhite ();
2154 	while (cppIsident1 (c))
2155 	{
2156 		readIdentifier (token, c);
2157 		c = skipToNonWhite ();
2158 		if (c == '.'  ||  c == ',')
2159 			c = skipToNonWhite ();
2160 	}
2161 	cppUngetc (c);
2162 }
2163 
addParentClass(statementInfo * const st,tokenInfo * const token)2164 static void addParentClass (statementInfo *const st, tokenInfo *const token)
2165 {
2166 	if (vStringLength (token->name) > 0  &&
2167 		vStringLength (st->parentClasses) > 0)
2168 	{
2169 		vStringPut (st->parentClasses, ',');
2170 	}
2171 	vStringCat (st->parentClasses, token->name);
2172 }
2173 
readParents(statementInfo * const st,const int qualifier)2174 static void readParents (statementInfo *const st, const int qualifier)
2175 {
2176 	tokenInfo *const token = newToken ();
2177 	tokenInfo *const parent = newToken ();
2178 	int c;
2179 
2180 	do
2181 	{
2182 		c = skipToNonWhite ();
2183 		if (cppIsident1 (c))
2184 		{
2185 			readIdentifier (token, c);
2186 			if (isType (token, TOKEN_NAME))
2187 				vStringCat (parent->name, token->name);
2188 			else
2189 			{
2190 				addParentClass (st, parent);
2191 				initToken (parent);
2192 			}
2193 		}
2194 		else if (c == qualifier)
2195 			vStringPut (parent->name, c);
2196 		else if (c == '<')
2197 			skipToMatch ("<>");
2198 		else if (isType (token, TOKEN_NAME))
2199 		{
2200 			addParentClass (st, parent);
2201 			initToken (parent);
2202 		}
2203 	} while (c != '{'  &&  c != EOF);
2204 	cppUngetc (c);
2205 	deleteToken (parent);
2206 	deleteToken (token);
2207 }
2208 
skipStatement(statementInfo * const st)2209 static void skipStatement (statementInfo *const st)
2210 {
2211 	st->declaration = DECL_IGNORE;
2212 	skipToOneOf (";");
2213 }
2214 
processAnnotation(statementInfo * const st)2215 static void processAnnotation (statementInfo *const st)
2216 {
2217 	st->declaration = DECL_ANNOTATION;
2218 }
2219 
processInterface(statementInfo * const st)2220 static void processInterface (statementInfo *const st)
2221 {
2222 	st->declaration = DECL_INTERFACE;
2223 }
2224 
checkIsClassEnum(statementInfo * const st,const declType decl)2225 static void checkIsClassEnum (statementInfo *const st, const declType decl)
2226 {
2227 	if (! isInputLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
2228 		st->declaration = decl;
2229 }
2230 
processToken(tokenInfo * const token,statementInfo * const st)2231 static void processToken (tokenInfo *const token, statementInfo *const st)
2232 {
2233 	switch ((int)token->keyword)        /* is it a reserved word? */
2234 	{
2235 		default: break;
2236 
2237 		case KEYWORD_NONE:      processName (st);                       break;
2238 		case KEYWORD_ABSTRACT:  st->implementation = IMP_ABSTRACT;      break;
2239 		case KEYWORD_ATTRIBUTE: skipParens (); initToken (token);       break;
2240 		case KEYWORD_BIND:      st->declaration = DECL_BASE;            break;
2241 		case KEYWORD_BIT:       st->declaration = DECL_BASE;            break;
2242 		case KEYWORD_CATCH:     skipParens (); skipBraces ();           break;
2243 		case KEYWORD_CHAR:      st->declaration = DECL_BASE;            break;
2244 		case KEYWORD_CLASS:     checkIsClassEnum (st, DECL_CLASS);      break;
2245 		case KEYWORD_CONST:     st->declaration = DECL_BASE;            break;
2246 		case KEYWORD_DOUBLE:    st->declaration = DECL_BASE;            break;
2247 		case KEYWORD_ENUM:      st->declaration = DECL_ENUM;            break;
2248 		case KEYWORD_EXTENDS:   readParents (st, '.');
2249 		                        setToken (st, TOKEN_NONE);              break;
2250 		case KEYWORD_FLOAT:     st->declaration = DECL_BASE;            break;
2251 		case KEYWORD_FUNCTION:  st->declaration = DECL_BASE;            break;
2252 		case KEYWORD_FRIEND:    st->scope       = SCOPE_FRIEND;         break;
2253 		case KEYWORD_GOTO:      skipStatement (st);                     break;
2254 		case KEYWORD_IMPLEMENTS:readParents (st, '.');
2255 		                        setToken (st, TOKEN_NONE);              break;
2256 		case KEYWORD_IMPORT:
2257 			if (isInputLanguage (Lang_java))
2258 				readPackageOrNamespace (st, DECL_PACKAGEREF, true);
2259 			else
2260 				skipStatement (st);
2261 			break;
2262 		case KEYWORD_INT:       st->declaration = DECL_BASE;            break;
2263 		case KEYWORD_INTEGER:   st->declaration = DECL_BASE;            break;
2264 		case KEYWORD_INTERFACE: processInterface (st);                  break;
2265 		case KEYWORD_LOCAL:     setAccess (st, ACCESS_LOCAL);           break;
2266 		case KEYWORD_LONG:      st->declaration = DECL_BASE;            break;
2267 		case KEYWORD_OPERATOR:  readOperator (st);                      break;
2268 		case KEYWORD_MIXIN:     st->declaration = DECL_MIXIN;           break;
2269 		case KEYWORD_PRIVATE:   setAccess (st, ACCESS_PRIVATE);         break;
2270 		case KEYWORD_PROGRAM:   st->declaration = DECL_PROGRAM;         break;
2271 		case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED);       break;
2272 		case KEYWORD_PUBLIC:    setAccess (st, ACCESS_PUBLIC);          break;
2273 		case KEYWORD_RETURN:    skipStatement (st);                     break;
2274 		case KEYWORD_SHORT:     st->declaration = DECL_BASE;            break;
2275 		case KEYWORD_SIGNED:    st->declaration = DECL_BASE;            break;
2276 		case KEYWORD_STRING:    st->declaration = DECL_BASE;            break;
2277 		case KEYWORD_STRUCT:    checkIsClassEnum (st, DECL_STRUCT);     break;
2278 		case KEYWORD_TASK:      st->declaration = DECL_TASK;            break;
2279 		case KEYWORD_THROWS:    discardTypeList (token);                break;
2280 		case KEYWORD_UNION:     st->declaration = DECL_UNION;           break;
2281 		case KEYWORD_UNSIGNED:  st->declaration = DECL_BASE;            break;
2282 		case KEYWORD_USING:     st->declaration = DECL_USING;           break;
2283 		case KEYWORD_VOID:      st->declaration = DECL_BASE;            break;
2284 		case KEYWORD_VOLATILE:  st->declaration = DECL_BASE;            break;
2285 		case KEYWORD_VERSION:   readVersion(st);                        break;
2286 		case KEYWORD_VIRTUAL:   st->implementation = IMP_VIRTUAL;       break;
2287 		case KEYWORD_WCHAR_T:   st->declaration = DECL_BASE;            break;
2288 		case KEYWORD_TEMPLATE:
2289 			if (isInputLanguage (Lang_d))
2290 				st->declaration = DECL_TEMPLATE;
2291 			break;
2292 		case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE, false); break;
2293 		case KEYWORD_MODULE:
2294 		case KEYWORD_PACKAGE:   readPackageOrNamespace (st, DECL_PACKAGE, false);   break;
2295 
2296 		case KEYWORD_EVENT:
2297 			if (isInputLanguage (Lang_csharp))
2298 				st->declaration = DECL_EVENT;
2299 			break;
2300 
2301 		case KEYWORD_ALIAS:
2302 		case KEYWORD_TYPEDEF:
2303 			reinitStatement (st, false);
2304 			st->scope = SCOPE_TYPEDEF;
2305 			break;
2306 
2307 		case KEYWORD_EXTERN:
2308 			if (! isInputLanguage (Lang_csharp) || !st->gotName)
2309 			{
2310 				reinitStatement (st, false);
2311 				st->scope = SCOPE_EXTERN;
2312 				st->declaration = DECL_BASE;
2313 			}
2314 			break;
2315 
2316 		case KEYWORD_STATIC:
2317 			if (! (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp)))
2318 			{
2319 				reinitStatement (st, false);
2320 				st->scope = SCOPE_STATIC;
2321 				st->declaration = DECL_BASE;
2322 			}
2323 			break;
2324 
2325 		case KEYWORD_FOR:
2326 		case KEYWORD_FOREACH:
2327 		case KEYWORD_IF:
2328 		case KEYWORD_SWITCH:
2329 		case KEYWORD_WHILE:
2330 		{
2331 			int c = skipToNonWhite ();
2332 			if (c == '(')
2333 				skipToMatch ("()");
2334 			break;
2335 		}
2336 	}
2337 }
2338 
2339 /*
2340 *   Parenthesis handling functions
2341 */
2342 
restartStatement(statementInfo * const st)2343 static void restartStatement (statementInfo *const st)
2344 {
2345 	tokenInfo *const save = newToken ();
2346 	tokenInfo *token = activeToken (st);
2347 
2348 	copyToken (save, token);
2349 	DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2350 	reinitStatement (st, false);
2351 	token = activeToken (st);
2352 	copyToken (token, save);
2353 	deleteToken (save);
2354 	processToken (token, st);
2355 }
2356 
2357 /*  Skips over a mem-initializer-list of a ctor-initializer, defined as:
2358  *
2359  *  mem-initializer-list:
2360  *    mem-initializer, mem-initializer-list
2361  *
2362  *  mem-initializer:
2363  *    [::] [nested-name-spec] class-name (...)
2364  *    identifier
2365  */
skipMemIntializerList(tokenInfo * const token)2366 static void skipMemIntializerList (tokenInfo *const token)
2367 {
2368 	int c;
2369 
2370 	do
2371 	{
2372 		c = skipToNonWhite ();
2373 		while (cppIsident1 (c)  ||  c == ':')
2374 		{
2375 			if (c != ':')
2376 				readIdentifier (token, c);
2377 			c = skipToNonWhite ();
2378 		}
2379 		if (c == '<')
2380 		{
2381 			skipToMatch ("<>");
2382 			c = skipToNonWhite ();
2383 		}
2384 		if (c == '(')
2385 		{
2386 			skipToMatch ("()");
2387 			c = skipToNonWhite ();
2388 		}
2389 	} while (c == ',');
2390 	cppUngetc (c);
2391 }
2392 
skipMacro(statementInfo * const st)2393 static void skipMacro (statementInfo *const st)
2394 {
2395 	tokenInfo *const prev2 = prevToken (st, 2);
2396 
2397 	if (isType (prev2, TOKEN_NAME))
2398 		retardToken (st);
2399 	skipToMatch ("()");
2400 }
2401 
2402 /*  Skips over characters following the parameter list. This will be either
2403  *  non-ANSI style function declarations or C++ stuff. Our choices:
2404  *
2405  *  C (K&R):
2406  *    int func ();
2407  *    int func (one, two) int one; float two; {...}
2408  *  C (ANSI):
2409  *    int func (int one, float two);
2410  *    int func (int one, float two) {...}
2411  *  C++:
2412  *    int foo (...) [const|volatile] [throw (...)];
2413  *    int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2414  *    int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2415  *        catch (...) {...}
2416  */
skipPostArgumentStuff(statementInfo * const st,parenInfo * const info)2417 static bool skipPostArgumentStuff (
2418 		statementInfo *const st, parenInfo *const info)
2419 {
2420 	tokenInfo *const token = activeToken (st);
2421 	unsigned int parameters = info->parameterCount;
2422 	unsigned int elementCount = 0;
2423 	bool restart = false;
2424 	bool end = false;
2425 	int c = skipToNonWhite ();
2426 
2427 	do
2428 	{
2429 		switch (c)
2430 		{
2431 		case ')':                               break;
2432 		case ':': skipMemIntializerList (token);break;  /* ctor-initializer */
2433 		case '[': skipToMatch ("[]");           break;
2434 		case '=': cppUngetc (c); end = true;    break;
2435 		case '{': cppUngetc (c); end = true;    break;
2436 		case '}': cppUngetc (c); end = true;    break;
2437 
2438 		case '(':
2439 			if (elementCount > 0)
2440 				++elementCount;
2441 			skipToMatch ("()");
2442 			break;
2443 
2444 		case ';':
2445 			if (parameters == 0  ||  elementCount < 2)
2446 			{
2447 				cppUngetc (c);
2448 				end = true;
2449 			}
2450 			else if (--parameters == 0)
2451 				end = true;
2452 			break;
2453 
2454 		default:
2455 			if (cppIsident1 (c))
2456 			{
2457 				readIdentifier (token, c);
2458 				switch (token->keyword)
2459 				{
2460 				case KEYWORD_ATTRIBUTE: skipParens ();  break;
2461 				case KEYWORD_THROW:     skipParens ();  break;
2462 				case KEYWORD_IF:        if (isInputLanguage (Lang_d)) skipParens ();  break;
2463 				case KEYWORD_TRY:                       break;
2464 				case KEYWORD_NOEXCEPT:                  break;
2465 
2466 				case KEYWORD_CONST:
2467 				case KEYWORD_VOLATILE:
2468 					if (vStringLength (Signature) > 0)
2469 					{
2470 						vStringPut (Signature, ' ');
2471 						vStringCat (Signature, token->name);
2472 					}
2473 					break;
2474 				case KEYWORD_ALIAS:
2475 				case KEYWORD_CATCH:
2476 				case KEYWORD_CLASS:
2477 				case KEYWORD_EXPLICIT:
2478 				case KEYWORD_EXTERN:
2479 				case KEYWORD_FRIEND:
2480 				case KEYWORD_INLINE:
2481 				case KEYWORD_MUTABLE:
2482 				case KEYWORD_NAMESPACE:
2483 				case KEYWORD_NEW:
2484 				case KEYWORD_NEWCOV:
2485 				case KEYWORD_OPERATOR:
2486 				case KEYWORD_OVERLOAD:
2487 				case KEYWORD_PRIVATE:
2488 				case KEYWORD_PROTECTED:
2489 				case KEYWORD_PUBLIC:
2490 				case KEYWORD_STATIC:
2491 				case KEYWORD_TEMPLATE:
2492 				case KEYWORD_TYPEDEF:
2493 				case KEYWORD_TYPENAME:
2494 				case KEYWORD_USING:
2495 				case KEYWORD_VIRTUAL:
2496 					/* Never allowed within parameter declarations. */
2497 					restart = true;
2498 					end = true;
2499 					break;
2500 
2501 				default:
2502 					/* "override" and "final" are only keywords in the declaration of a virtual
2503 					 * member function, so need to be handled specially, not as keywords */
2504 					if (isInputLanguage(Lang_cpp) && isType (token, TOKEN_NAME) &&
2505 						(strcmp ("override", vStringValue (token->name)) == 0 ||
2506 						 strcmp ("final", vStringValue (token->name)) == 0))
2507 						;
2508 					else if (isType (token, TOKEN_NONE))
2509 						;
2510 					else if (info->isKnrParamList  &&  info->parameterCount > 0)
2511 						++elementCount;
2512 					else
2513 					{
2514 						/*  If we encounter any other identifier immediately
2515 						 *  following an empty parameter list, this is almost
2516 						 *  certainly one of those Microsoft macro "thingies"
2517 						 *  that the automatic source code generation sticks
2518 						 *  in. Terminate the current statement.
2519 						 */
2520 						restart = true;
2521 						end = true;
2522 					}
2523 					break;
2524 				}
2525 			}
2526 		}
2527 		if (! end)
2528 		{
2529 			c = skipToNonWhite ();
2530 			if (c == EOF)
2531 				end = true;
2532 		}
2533 	} while (! end);
2534 
2535 	if (restart)
2536 		restartStatement (st);
2537 	else
2538 		setToken (st, TOKEN_NONE);
2539 
2540 	return (bool) (c != EOF);
2541 }
2542 
skipJavaThrows(statementInfo * const st)2543 static void skipJavaThrows (statementInfo *const st)
2544 {
2545 	tokenInfo *const token = activeToken (st);
2546 	int c = skipToNonWhite ();
2547 
2548 	if (cppIsident1 (c))
2549 	{
2550 		readIdentifier (token, c);
2551 		if (token->keyword == KEYWORD_THROWS)
2552 		{
2553 			do
2554 			{
2555 				c = skipToNonWhite ();
2556 				if (cppIsident1 (c))
2557 				{
2558 					readIdentifier (token, c);
2559 					c = skipToNonWhite ();
2560 				}
2561 			} while (c == '.'  ||  c == ',');
2562 		}
2563 	}
2564 	cppUngetc (c);
2565 	setToken (st, TOKEN_NONE);
2566 }
2567 
analyzePostParens(statementInfo * const st,parenInfo * const info)2568 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2569 {
2570 	const unsigned long inputLineNumber = getInputLineNumber ();
2571 	int c = skipToNonWhite ();
2572 
2573 	cppUngetc (c);
2574 	if (isOneOf (c, "{;,="))
2575 		;
2576 	else if (isInputLanguage (Lang_java)) {
2577 
2578 		if (!insideAnnotationBody(st)) {
2579 			skipJavaThrows (st);
2580 		}
2581 	} else {
2582 		if (! skipPostArgumentStuff (st, info))
2583 		{
2584 			verbose (
2585 				"%s: confusing argument declarations beginning at line %lu\n",
2586 				getInputFileName (), inputLineNumber);
2587 			longjmp (Exception, (int) ExceptionFormattingError);
2588 		}
2589 	}
2590 }
2591 
languageSupportsGenerics(void)2592 static bool languageSupportsGenerics (void)
2593 {
2594 	return (bool) (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) ||
2595 		isInputLanguage (Lang_java));
2596 }
2597 
processAngleBracket(void)2598 static void processAngleBracket (void)
2599 {
2600 	int c = cppGetc ();
2601 	if (c == '>') {
2602 		/* already found match for template */
2603 	} else if (languageSupportsGenerics () && c != '<' && c != '=') {
2604 		/* this is a template */
2605 		cppUngetc (c);
2606 		if (isInputLanguage (Lang_cpp))
2607 			skipCppTemplateParameterList ();
2608 		else
2609 			skipToMatch ("<>");
2610 	} else if (c == '<') {
2611 		/* skip "<<" or "<<=". */
2612 		c = cppGetc ();
2613 		if (c != '=') {
2614 			cppUngetc (c);
2615 		}
2616 	} else {
2617 		cppUngetc (c);
2618 	}
2619 }
2620 
parseJavaAnnotation(statementInfo * const st)2621 static void parseJavaAnnotation (statementInfo *const st)
2622 {
2623 	/*
2624 	 * @Override
2625 	 * @Target(ElementType.METHOD)
2626 	 * @SuppressWarnings(value = "unchecked")
2627 	 *
2628 	 * But watch out for "@interface"!
2629 	 */
2630 	tokenInfo *const token = activeToken (st);
2631 
2632 	int c = skipToNonWhite ();
2633 	readIdentifier (token, c);
2634 	if (token->keyword == KEYWORD_INTERFACE)
2635 	{
2636 		/* Oops. This was actually "@interface" defining a new annotation. */
2637 		processAnnotation(st);
2638 	}
2639 	else
2640 	{
2641 		/* Bug #1691412: skip any annotation arguments. */
2642 		skipParens ();
2643 	}
2644 }
2645 
parseParens(statementInfo * const st,parenInfo * const info)2646 static int parseParens (statementInfo *const st, parenInfo *const info)
2647 {
2648 	tokenInfo *const token = activeToken (st);
2649 	unsigned int identifierCount = 0;
2650 	unsigned int depth = 1;
2651 	bool firstChar = true;
2652 	int nextChar = '\0';
2653 
2654 	CollectingSignature = true;
2655 	vStringClear (Signature);
2656 	vStringPut (Signature, '(');
2657 	info->parameterCount = 1;
2658 	do
2659 	{
2660 		int c = skipToNonWhite ();
2661 		vStringPut (Signature, c);
2662 
2663 		switch (c)
2664 		{
2665 			case '^':
2666 				break;
2667 
2668 			case '&':
2669 			case '*':
2670 				info->isPointer = true;
2671 				info->isKnrParamList = false;
2672 				if (identifierCount == 0)
2673 					info->isParamList = false;
2674 				initToken (token);
2675 				break;
2676 
2677 			case ':':
2678 				info->isKnrParamList = false;
2679 				break;
2680 
2681 			case '.':
2682 				info->isNameCandidate = false;
2683 				c = cppGetc ();
2684 				if (c != '.')
2685 				{
2686 					cppUngetc (c);
2687 					info->isKnrParamList = false;
2688 				}
2689 				else
2690 				{
2691 					c = cppGetc ();
2692 					if (c != '.')
2693 					{
2694 						cppUngetc (c);
2695 						info->isKnrParamList = false;
2696 					}
2697 					else
2698 						vStringCatS (Signature, "..."); /* variable arg list */
2699 				}
2700 				break;
2701 
2702 			case ',':
2703 				info->isNameCandidate = false;
2704 				if (info->isKnrParamList)
2705 				{
2706 					++info->parameterCount;
2707 					identifierCount = 0;
2708 				}
2709 				break;
2710 
2711 			case '=':
2712 				info->isKnrParamList = false;
2713 				info->isNameCandidate = false;
2714 				if (firstChar)
2715 				{
2716 					info->isParamList = false;
2717 					skipMacro (st);
2718 					depth = 0;
2719 				}
2720 				break;
2721 
2722 			case '[':
2723 				info->isKnrParamList = false;
2724 				skipToMatch ("[]");
2725 				break;
2726 
2727 			case '<':
2728 				info->isKnrParamList = false;
2729 				processAngleBracket ();
2730 				break;
2731 
2732 			case ')':
2733 				if (firstChar)
2734 					info->parameterCount = 0;
2735 				--depth;
2736 				break;
2737 
2738 			case '(':
2739 				info->isKnrParamList = false;
2740 				if (firstChar)
2741 				{
2742 					info->isNameCandidate = false;
2743 					cppUngetc (c);
2744 					vStringClear (Signature);
2745 					skipMacro (st);
2746 					depth = 0;
2747 					vStringChop (Signature);
2748 				}
2749 				else if (isType (token, TOKEN_PAREN_NAME))
2750 				{
2751 					c = skipToNonWhite ();
2752 					if (c == '*')        /* check for function pointer */
2753 					{
2754 						skipToMatch ("()");
2755 						c = skipToNonWhite ();
2756 						if (c == '(')
2757 							skipToMatch ("()");
2758 						else
2759 							cppUngetc (c);
2760 					}
2761 					else
2762 					{
2763 						cppUngetc (c);
2764 						cppUngetc ('(');
2765 						info->nestedArgs = true;
2766 					}
2767 				}
2768 				else
2769 					++depth;
2770 				break;
2771 
2772 			default:
2773 				if (c == '@' && isInputLanguage (Lang_java))
2774 				{
2775 					parseJavaAnnotation(st);
2776 				}
2777 				else if (cppIsident1 (c))
2778 				{
2779 					if (++identifierCount > 1)
2780 						info->isKnrParamList = false;
2781 					readIdentifier (token, c);
2782 					if (isType (token, TOKEN_NAME)  &&  info->isNameCandidate)
2783 						token->type = TOKEN_PAREN_NAME;
2784 					else if (isType (token, TOKEN_KEYWORD))
2785 					{
2786 						if (token->keyword != KEYWORD_CONST &&
2787 							token->keyword != KEYWORD_VOLATILE)
2788 						{
2789 							info->isKnrParamList = false;
2790 							info->isNameCandidate = false;
2791 						}
2792 					}
2793 				}
2794 				else
2795 				{
2796 					info->isParamList     = false;
2797 					info->isKnrParamList  = false;
2798 					info->isNameCandidate = false;
2799 					info->invalidContents = true;
2800 				}
2801 				break;
2802 		}
2803 		firstChar = false;
2804 	} while (! info->nestedArgs  &&  depth > 0  &&
2805 			 (info->isKnrParamList  ||  info->isNameCandidate));
2806 
2807 	if (! info->nestedArgs) while (depth > 0)
2808 	{
2809 		skipToMatch ("()");
2810 		--depth;
2811 	}
2812 
2813 	if (! info->isNameCandidate)
2814 		initToken (token);
2815 
2816 	if (info->isKnrParamList)
2817 		vStringClear (Signature);
2818 	CollectingSignature = false;
2819 	return nextChar;
2820 }
2821 
initParenInfo(parenInfo * const info)2822 static void initParenInfo (parenInfo *const info)
2823 {
2824 	info->isPointer				= false;
2825 	info->isParamList			= true;
2826 	info->isKnrParamList		= isInputLanguage (Lang_c);
2827 	info->isNameCandidate		= true;
2828 	info->invalidContents		= false;
2829 	info->nestedArgs			= false;
2830 	info->parameterCount		= 0;
2831 }
2832 
analyzeParens(statementInfo * const st)2833 static void analyzeParens (statementInfo *const st)
2834 {
2835 	tokenInfo *const prev = prevToken (st, 1);
2836 	const tokenInfo *const prev2 = prevToken (st, 2);
2837 
2838 	if (
2839 			st->inFunction &&
2840 			!st->assignment &&
2841 			!(
2842 				/* C++: Accept Type var(...) as variable; */
2843 				isInputLanguage(Lang_cpp) &&
2844 				isType(prev,TOKEN_NAME) &&
2845 				isType(prev2,TOKEN_NAME)
2846 			)
2847 		)
2848 	{
2849 		st->notVariable = true;
2850 	}
2851 
2852 	if (! isType (prev, TOKEN_NONE))  /* in case of ignored enclosing macros */
2853 	{
2854 		tokenInfo *const token = activeToken (st);
2855 		parenInfo info;
2856 		int c;
2857 
2858 		initParenInfo (&info);
2859 		parseParens (st, &info);
2860 		c = skipToNonWhite ();
2861 		cppUngetc (c);
2862 		if (info.invalidContents)
2863 		{
2864 			/* FIXME: This breaks parsing of variable instantiations that have
2865 			   constants as parameters: Type var(0) or Type var("..."). */
2866 			reinitStatement (st, false);
2867 		}
2868 		else if (info.isNameCandidate  &&  isType (token, TOKEN_PAREN_NAME)  &&
2869 				 ! st->gotParenName  &&
2870 				 (! info.isParamList || ! st->haveQualifyingName  ||
2871 				  c == '('  ||
2872 				  (c == '='  &&  st->implementation != IMP_VIRTUAL && !isInputLanguage (Lang_cpp)) ||
2873 				  (st->declaration == DECL_NONE  &&  isOneOf (c, ",;"))))
2874 		{
2875 			token->type = TOKEN_NAME;
2876 			processName (st);
2877 			st->gotParenName = true;
2878 			if (! (c == '('  &&  info.nestedArgs))
2879 				st->isPointer = info.isPointer;
2880 			if (isInputLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2881 			{
2882 				st->declaration = DECL_FUNCTION_TEMPLATE;
2883 				copyToken (st->blockName, prev);
2884 			}
2885 		}
2886 		else if (! st->gotArgs  &&  info.isParamList)
2887 		{
2888 			st->gotArgs = true;
2889 			setToken (st, TOKEN_ARGS);
2890 			advanceToken (st);
2891 			if (st->scope != SCOPE_TYPEDEF)
2892 				analyzePostParens (st, &info);
2893 		}
2894 		else
2895 			setToken (st, TOKEN_NONE);
2896 	}
2897 }
2898 
2899 /*
2900 *   Token parsing functions
2901 */
2902 
addContext(statementInfo * const st,const tokenInfo * const token)2903 static void addContext (statementInfo *const st, const tokenInfo* const token)
2904 {
2905 	if (isType (token, TOKEN_NAME))
2906 	{
2907 		if (vStringLength (st->context->name) > 0)
2908 		{
2909 			if (isInputLanguage (Lang_c)  ||  isInputLanguage (Lang_cpp))
2910 				vStringCatS (st->context->name, "::");
2911 			else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) ||
2912 				isInputLanguage (Lang_d))
2913 				vStringPut (st->context->name, '.');
2914 		}
2915 		vStringCat (st->context->name, token->name);
2916 		st->context->type = TOKEN_NAME;
2917 	}
2918 }
2919 
inheritingDeclaration(declType decl)2920 static bool inheritingDeclaration (declType decl)
2921 {
2922 	/* enum base types */
2923 	if (decl == DECL_ENUM)
2924 	{
2925 		return (bool) (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) ||
2926 			isInputLanguage (Lang_d));
2927 	}
2928 	return (bool) (
2929 		decl == DECL_CLASS ||
2930 		decl == DECL_STRUCT ||
2931 		decl == DECL_INTERFACE);
2932 }
2933 
processColon(statementInfo * const st)2934 static void processColon (statementInfo *const st)
2935 {
2936 	int c = (isInputLanguage (Lang_cpp) ? cppGetc () : skipToNonWhite ());
2937 	const bool doubleColon = (bool) (c == ':');
2938 
2939 	if (doubleColon)
2940 	{
2941 		setToken (st, TOKEN_DOUBLE_COLON);
2942 		st->haveQualifyingName = false;
2943 	}
2944 	else
2945 	{
2946 		cppUngetc (c);
2947 		if ((isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_d))  &&
2948 			inheritingDeclaration (st->declaration))
2949 		{
2950 			readParents (st, ':');
2951 		}
2952 		else if (parentDecl (st) == DECL_STRUCT)
2953 		{
2954 			c = skipToOneOf (",;");
2955 			if (c == ',')
2956 				setToken (st, TOKEN_COMMA);
2957 			else if (c == ';')
2958 				setToken (st, TOKEN_SEMICOLON);
2959 		}
2960 		else
2961 		{
2962 			const tokenInfo *const prev  = prevToken (st, 1);
2963 			const tokenInfo *const prev2 = prevToken (st, 2);
2964 			if (prev->keyword == KEYWORD_DEFAULT ||
2965 				prev2->keyword == KEYWORD_CASE)
2966 			{
2967 				reinitStatement (st, false);
2968 			}
2969 			else if (st->parent != NULL)
2970 			{
2971 				if (prevToken (st->parent, 1)->keyword != KEYWORD_SWITCH)
2972 					makeTag (prev, st, false, TAG_LABEL);
2973 				reinitStatement (st, false);
2974 			}
2975 		}
2976 	}
2977 }
2978 
2979 /*  Skips over any initializing value which may follow an '=' character in a
2980  *  variable definition.
2981  */
skipInitializer(statementInfo * const st)2982 static int skipInitializer (statementInfo *const st)
2983 {
2984 	bool done = false;
2985 	int c;
2986 
2987 	while (! done)
2988 	{
2989 		c = skipToNonWhite ();
2990 
2991 		if (c == EOF)
2992 			longjmp (Exception, (int) ExceptionFormattingError);
2993 		else switch (c)
2994 		{
2995 			case ',':
2996 			case ';': done = true; break;
2997 
2998 			case '0':
2999 				if (st->implementation == IMP_VIRTUAL)
3000 					st->implementation = IMP_PURE_VIRTUAL;
3001 				break;
3002 
3003 			case '[': skipToMatch ("[]"); break;
3004 			case '(': skipToMatch ("()"); break;
3005 			case '{': skipToMatch ("{}"); break;
3006 			case '<': processAngleBracket(); break;
3007 
3008 			case '}':
3009 				if (insideEnumBody (st))
3010 					done = true;
3011 				else if (! cppIsBraceFormat ())
3012 				{
3013 					verbose ("%s: unexpected closing brace at line %lu\n",
3014 							getInputFileName (), getInputLineNumber ());
3015 					longjmp (Exception, (int) ExceptionBraceFormattingError);
3016 				}
3017 				break;
3018 
3019 			default: break;
3020 		}
3021 	}
3022 	return c;
3023 }
3024 
processInitializer(statementInfo * const st)3025 static void processInitializer (statementInfo *const st)
3026 {
3027 	const bool inEnumBody = insideEnumBody (st);
3028 	int c = cppGetc ();
3029 
3030 	if (c != '=')
3031 	{
3032 		cppUngetc (c);
3033 		c = skipInitializer (st);
3034 		st->assignment = true;
3035 		if (c == ';')
3036 			setToken (st, TOKEN_SEMICOLON);
3037 		else if (c == ',')
3038 			setToken (st, TOKEN_COMMA);
3039 		else if (c == '}'  &&  inEnumBody)
3040 		{
3041 			cppUngetc (c);
3042 			setToken (st, TOKEN_COMMA);
3043 		}
3044 		if (st->scope == SCOPE_EXTERN)
3045 			st->scope = SCOPE_GLOBAL;
3046 	}
3047 }
3048 
parseIdentifier(statementInfo * const st,const int c)3049 static void parseIdentifier (statementInfo *const st, const int c)
3050 {
3051 	tokenInfo *const token = activeToken (st);
3052 
3053 	readIdentifier (token, c);
3054 	if (! isType (token, TOKEN_NONE))
3055 		processToken (token, st);
3056 }
3057 
parseGeneralToken(statementInfo * const st,const int c)3058 static void parseGeneralToken (statementInfo *const st, const int c)
3059 {
3060 	const tokenInfo *const prev = prevToken (st, 1);
3061 
3062 	if (cppIsident1 (c) || (isInputLanguage (Lang_java) && isHighChar (c)))
3063 	{
3064 
3065 		parseIdentifier (st, c);
3066 		if (isType (st->context, TOKEN_NAME) &&
3067 			isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
3068 		{
3069 			initToken (st->context);
3070 		}
3071 	}
3072 	else if (c == '.' || c == '-')
3073 	{
3074 		if (! st->assignment)
3075 			st->notVariable = true;
3076 		if (c == '-')
3077 		{
3078 			int c2 = cppGetc ();
3079 			if (c2 != '>')
3080 				cppUngetc (c2);
3081 		}
3082 	}
3083 	else if (c == '!' || c == '>')
3084 	{
3085 		int c2 = cppGetc ();
3086 		if (c2 != '=')
3087 			cppUngetc (c2);
3088 	}
3089 	else if (c == '@' && isInputLanguage (Lang_java))
3090 	{
3091 		parseJavaAnnotation (st);
3092 	}
3093 	else if (isExternCDecl (st, c))
3094 	{
3095 		st->declaration = DECL_NOMANGLE;
3096 		st->scope = SCOPE_GLOBAL;
3097 	} else if (c == STRING_SYMBOL) {
3098 		setToken(st, TOKEN_NONE);
3099 	}
3100 }
3101 
3102 /*  Reads characters from the pre-processor and assembles tokens, setting
3103  *  the current statement state.
3104  */
nextToken(statementInfo * const st)3105 static void nextToken (statementInfo *const st)
3106 {
3107 	tokenInfo *token;
3108 	do
3109 	{
3110 		int c = skipToNonWhite ();
3111 		switch (c)
3112 		{
3113 			case EOF: longjmp (Exception, (int) ExceptionEOF);  break;
3114 			case '(': analyzeParens (st);                       break;
3115 			case '<': processAngleBracket ();                   break;
3116 			case '*': st->haveQualifyingName = false;           break;
3117 			case ',': setToken (st, TOKEN_COMMA);               break;
3118 			case ':': processColon (st);                        break;
3119 			case ';': setToken (st, TOKEN_SEMICOLON);           break;
3120 			case '=': processInitializer (st);                  break;
3121 			case '[': skipToMatch ("[]");                       break;
3122 			case '{': setToken (st, TOKEN_BRACE_OPEN);          break;
3123 			case '}': setToken (st, TOKEN_BRACE_CLOSE);         break;
3124 			default:  parseGeneralToken (st, c);                break;
3125 		}
3126 		token = activeToken (st);
3127 	} while (isType (token, TOKEN_NONE));
3128 }
3129 
3130 /*
3131 *   Scanning support functions
3132 */
3133 
3134 static statementInfo *CurrentStatement = NULL;
3135 
newStatement(statementInfo * const parent)3136 static statementInfo *newStatement (statementInfo *const parent)
3137 {
3138 	statementInfo *const st = xMalloc (1, statementInfo);
3139 	unsigned int i;
3140 
3141 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
3142 		st->token [i] = newToken ();
3143 
3144 	st->context = newToken ();
3145 	st->blockName = newToken ();
3146 	st->parentClasses = vStringNew ();
3147 
3148 	initStatement (st, parent);
3149 	CurrentStatement = st;
3150 
3151 	return st;
3152 }
3153 
deleteStatement(void)3154 static void deleteStatement (void)
3155 {
3156 	statementInfo *const st = CurrentStatement;
3157 	statementInfo *const parent = st->parent;
3158 	unsigned int i;
3159 
3160 	for (i = 0  ;  i < (unsigned int) NumTokens  ;  ++i)
3161 	{
3162 		deleteToken (st->token [i]);       st->token [i] = NULL;
3163 	}
3164 	deleteToken (st->blockName);           st->blockName = NULL;
3165 	deleteToken (st->context);             st->context = NULL;
3166 	vStringDelete (st->parentClasses);     st->parentClasses = NULL;
3167 	eFree (st);
3168 	CurrentStatement = parent;
3169 }
3170 
deleteAllStatements(void)3171 static void deleteAllStatements (void)
3172 {
3173 	while (CurrentStatement != NULL)
3174 		deleteStatement ();
3175 }
3176 
isStatementEnd(const statementInfo * const st)3177 static bool isStatementEnd (const statementInfo *const st)
3178 {
3179 	const tokenInfo *const token = activeToken (st);
3180 	bool isEnd;
3181 
3182 	if (isType (token, TOKEN_SEMICOLON))
3183 		isEnd = true;
3184 	else if (isType (token, TOKEN_BRACE_CLOSE))
3185 		/* Java and C# do not require semicolons to end a block. Neither do C++
3186 		 * namespaces. All other blocks require a semicolon to terminate them.
3187 		 */
3188 		isEnd = (bool) (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) ||
3189 				 isInputLanguage (Lang_d) || ! isContextualStatement (st));
3190 	else
3191 		isEnd = false;
3192 
3193 	return isEnd;
3194 }
3195 
checkStatementEnd(statementInfo * const st,int corkIndex)3196 static void checkStatementEnd (statementInfo *const st, int corkIndex)
3197 {
3198 	const tokenInfo *const token = activeToken (st);
3199 
3200 	tagEntryInfo *e = getEntryInCorkQueue (corkIndex);
3201 	if (e)
3202 		e->extensionFields.endLine = token->lineNumber;
3203 
3204 	if (isType (token, TOKEN_COMMA))
3205 		reinitStatement (st, true);
3206 	else if (isStatementEnd (st))
3207 	{
3208 		DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
3209 		reinitStatement (st, false);
3210 		cppEndStatement ();
3211 	}
3212 	else
3213 	{
3214 		cppBeginStatement ();
3215 		advanceToken (st);
3216 	}
3217 }
3218 
nest(statementInfo * const st,const unsigned int nestLevel)3219 static void nest (statementInfo *const st, const unsigned int nestLevel)
3220 {
3221 	switch (st->declaration)
3222 	{
3223 		case DECL_TEMPLATE:
3224 		case DECL_VERSION:
3225 			st->inFunction = false;
3226 		case DECL_CLASS:
3227 		case DECL_ENUM:
3228 		case DECL_INTERFACE:
3229 		case DECL_NAMESPACE:
3230 		case DECL_NOMANGLE:
3231 		case DECL_PRIVATE:
3232 		case DECL_PROTECTED:
3233 		case DECL_PUBLIC:
3234 		case DECL_STRUCT:
3235 		case DECL_UNION:
3236 		case DECL_ANNOTATION:
3237 			createTags (nestLevel, st);
3238 			break;
3239 
3240 		case DECL_FUNCTION:
3241 		case DECL_TASK:
3242 			st->inFunction = true;
3243 			/* fall through */
3244 		default:
3245 			if (includeTag (TAG_LOCAL, false) || includeTag (TAG_LABEL, false))
3246 				createTags (nestLevel, st);
3247 			else
3248 				skipToMatch ("{}");
3249 			break;
3250 	}
3251 	advanceToken (st);
3252 	setToken (st, TOKEN_BRACE_CLOSE);
3253 }
3254 
tagCheck(statementInfo * const st)3255 static int tagCheck (statementInfo *const st)
3256 {
3257 	const tokenInfo *const token = activeToken (st);
3258 	const tokenInfo *const prev  = prevToken (st, 1);
3259 	const tokenInfo *const prev2 = prevToken (st, 2);
3260 	int corkIndex = CORK_NIL;
3261 
3262 	switch (token->type)
3263 	{
3264 		case TOKEN_NAME:
3265 			if (insideEnumBody (st))
3266 				corkIndex = qualifyEnumeratorTag (st, token);
3267 			if (st->declaration == DECL_MIXIN)
3268 				corkIndex = makeTag (token, st, false, TAG_MIXIN);
3269 			if (isInputLanguage (Lang_vera) && insideInterfaceBody (st))
3270 			{
3271 				/* Quoted from
3272 				   http://www.asic-world.com/vera/hdl1.html#Interface_Declaration
3273 				   ------------------------------------------------
3274 				   interface interface_name
3275 				   {
3276 				   signal_direction [signal_width] signal_name signal_type
3277 				   [skew] [depth value][vca q_value][force][hdl_node "hdl_path"];
3278 				   }
3279 				   Where
3280 				   signal_direction : This can be one of the following
3281 				        input : ...
3282 				        output : ...
3283 				        inout : ...
3284 				   signal_width : The signal_width is a range specifying the width of
3285 				                  a vector signal. It must be in the form [msb:lsb].
3286 						  Interface signals can have any integer lsb value,
3287 						  even a negative value. The default width is 1.
3288 				   signal_name : The signal_name identifies the signal being defined.
3289 				                 It is the Vera name for the HDL signal being connected.
3290 				   signal_type : There are many signals types, most commonly used one are
3291 					NHOLD : ...
3292 					PHOLD : ...
3293 					PHOLD NHOLD : ...
3294 					NSAMPLE : ...
3295 					PSAMPLE : ...
3296 					PSAMPLE NSAMPLE : ...
3297 					CLOCK : ...
3298 					PSAMPLE PHOLD : ...
3299 					NSAMPLE NHOLD : ...
3300 					PSAMPLE PHOLD NSAMPLE NHOLD : ...
3301 				   ------------------------------------------------
3302 				   We want to capture "signal_name" here.
3303 				*/
3304 				if (( isType (prev, TOKEN_KEYWORD)
3305 				      && isSignalDirection(prev) ) ||
3306 				    ( isType (prev2, TOKEN_KEYWORD)
3307 				      && isSignalDirection(prev) ))
3308 					corkIndex = makeTag (token, st, false, TAG_SIGNAL);
3309 			}
3310 			break;
3311 #if 0
3312 		case TOKEN_PACKAGE:
3313 			if (st->haveQualifyingName)
3314 				corkIndex = makeTag (token, st, false, TAG_PACKAGE);
3315 			break;
3316 #endif
3317 		case TOKEN_BRACE_OPEN:
3318 			if (isType (prev, TOKEN_ARGS))
3319 			{
3320 				if (st->declaration == DECL_TEMPLATE)
3321 					corkIndex = qualifyBlockTag (st, prev2);
3322 				else if (st->declaration == DECL_FUNCTION_TEMPLATE) {
3323 					corkIndex = qualifyFunctionTag (st, st->blockName);
3324 				}
3325 				else if (st->haveQualifyingName)
3326 				{
3327 					if (isType (prev2, TOKEN_NAME))
3328 						copyToken (st->blockName, prev2);
3329 
3330 					/* D declaration templates */
3331 					if (isInputLanguage (Lang_d) &&
3332 						(st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
3333 						st->declaration == DECL_INTERFACE || st->declaration == DECL_UNION))
3334 						corkIndex = qualifyBlockTag (st, prev2);
3335 					else if(isInputLanguage (Lang_cpp) && st->inFunction)
3336 					{
3337 						/* Ignore. C/C++ allows nested function prototypes but
3338 						   this code actually catches far too many of them.
3339 						   Better some missing tags than a lot of false positives. */
3340 					}
3341 					else
3342 					{
3343 						if (! isInputLanguage (Lang_vera))
3344 							st->declaration = DECL_FUNCTION;
3345 						corkIndex = qualifyFunctionTag (st, prev2);
3346 					}
3347 				}
3348 			}
3349 			else if (isContextualStatement (st) ||
3350 					st->declaration == DECL_VERSION ||
3351 					st->declaration == DECL_PROGRAM)
3352 			{
3353 				const tokenInfo *name_token = prev;
3354 
3355 				/* C++ 11 allows class <name> final { ... } */
3356 				if (isInputLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) &&
3357 					strcmp("final", vStringValue(prev->name)) == 0 &&
3358 					isType(prev2, TOKEN_NAME))
3359 				{
3360 					name_token = prev2;
3361 				}
3362 
3363 				if (isType (name_token, TOKEN_NAME))
3364 					copyToken (st->blockName, name_token);
3365 				else
3366 				{
3367 					/*  For an anonymous struct or union we use a unique ID
3368 					 *  a number, so that the members can be found.
3369 					 */
3370 					char buf [20];  /* length of "_anon" + digits  + null */
3371 					sprintf (buf, "__anon%d", ++AnonymousID);
3372 					vStringCopyS (st->blockName->name, buf);
3373 					st->blockName->type = TOKEN_NAME;
3374 					st->blockName->keyword = KEYWORD_NONE;
3375 				}
3376 				corkIndex = qualifyBlockTag (st, name_token);
3377 			}
3378 			else if (isInputLanguage (Lang_csharp))
3379 				corkIndex = makeTag (prev, st, false, TAG_PROPERTY);
3380 			break;
3381 
3382 		case TOKEN_KEYWORD:
3383 
3384 			if (token->keyword == KEYWORD_DEFAULT && isType(prev, TOKEN_ARGS) && insideAnnotationBody(st)) {
3385 				corkIndex = qualifyFunctionDeclTag(st, prev2);
3386 			}
3387 			break;
3388 
3389 		case TOKEN_SEMICOLON:
3390 		case TOKEN_COMMA:
3391 			if (insideEnumBody (st))
3392 				;
3393 			else if (isType (prev, TOKEN_NAME))
3394 			{
3395 				if (isContextualKeyword (prev2))
3396 					corkIndex = makeTag (prev, st, true, TAG_EXTERN_VAR);
3397 				else
3398 					corkIndex = qualifyVariableTag (st, prev);
3399 			}
3400 			else if (isType (prev, TOKEN_ARGS)  &&  isType (prev2, TOKEN_NAME))
3401 			{
3402 				if (st->isPointer || st->inFunction)
3403 				{
3404 					/* If it looks like a pointer or we are in a function body then
3405 					   it's far more likely to be a variable. */
3406 					corkIndex = qualifyVariableTag (st, prev2);
3407 				}
3408 				else
3409 					corkIndex = qualifyFunctionDeclTag (st, prev2);
3410 			}
3411 			if (isInputLanguage (Lang_java) && token->type == TOKEN_SEMICOLON && insideEnumBody (st))
3412 			{
3413 				/* In Java, after an initial enum-like part,
3414 				 * a semicolon introduces a class-like part.
3415 				 * See Bug #1730485 for the full rationale. */
3416 				st->parent->declaration = DECL_CLASS;
3417 			}
3418 			break;
3419 
3420 		default: break;
3421 	}
3422 
3423 	return corkIndex;
3424 }
3425 
3426 /*  Parses the current file and decides whether to write out and tags that
3427  *  are discovered.
3428  */
createTags(const unsigned int nestLevel,statementInfo * const parent)3429 static void createTags (const unsigned int nestLevel,
3430 						statementInfo *const parent)
3431 {
3432 	statementInfo *const st = newStatement (parent);
3433 
3434 	DebugStatement ( if (nestLevel > 0) debugParseNest (true, nestLevel); )
3435 	while (true)
3436 	{
3437 		tokenInfo *token;
3438 
3439 		nextToken (st);
3440 		token = activeToken (st);
3441 		if (isType (token, TOKEN_BRACE_CLOSE))
3442 		{
3443 			if (nestLevel > 0)
3444 				break;
3445 			else
3446 			{
3447 				verbose ("%s: unexpected closing brace at line %lu\n",
3448 						getInputFileName (), getInputLineNumber ());
3449 				longjmp (Exception, (int) ExceptionBraceFormattingError);
3450 			}
3451 		}
3452 		else if (isType (token, TOKEN_DOUBLE_COLON))
3453 		{
3454 			addContext (st, prevToken (st, 1));
3455 			advanceToken (st);
3456 		}
3457 		else
3458 		{
3459 			int corkIndex = tagCheck (st);
3460 			if (isType (token, TOKEN_BRACE_OPEN))
3461 				nest (st, nestLevel + 1);
3462 			checkStatementEnd (st, corkIndex);
3463 		}
3464 	}
3465 	deleteStatement ();
3466 	DebugStatement ( if (nestLevel > 0) debugParseNest (false, nestLevel - 1); )
3467 }
3468 
findCTags(const unsigned int passCount)3469 static rescanReason findCTags (const unsigned int passCount)
3470 {
3471 	exception_t exception;
3472 	rescanReason rescan;
3473 	int kind_for_define = KIND_GHOST_INDEX;
3474 	int kind_for_header = KIND_GHOST_INDEX;
3475 	int kind_for_param  = KIND_GHOST_INDEX;
3476 	int role_for_macro_undef = ROLE_DEFINITION_INDEX;
3477 	int role_for_macro_condition = ROLE_DEFINITION_INDEX;
3478 	int role_for_header_system   = ROLE_DEFINITION_INDEX;
3479 	int role_for_header_local   = ROLE_DEFINITION_INDEX;
3480 
3481 	Assert (passCount < 3);
3482 
3483 	AnonymousID = 0;
3484 
3485 	if (isInputLanguage (Lang_c) || isInputLanguage (Lang_cpp))
3486 	{
3487 		kind_for_define = CK_DEFINE;
3488 		kind_for_header = CK_HEADER;
3489 		kind_for_param = CK_MACRO_PARAM,
3490 		role_for_macro_undef = CR_MACRO_UNDEF;
3491 		role_for_macro_condition = CR_MACRO_CONDITION;
3492 		role_for_header_system = CR_HEADER_SYSTEM;
3493 		role_for_header_local = CR_HEADER_LOCAL;
3494 	}
3495 	else if (isInputLanguage (Lang_vera))
3496 	{
3497 		kind_for_define = VK_DEFINE;
3498 		kind_for_header = VK_HEADER;
3499 		kind_for_param  = VK_MACRO_PARAM,
3500 		role_for_macro_undef = VR_MACRO_UNDEF;
3501 		role_for_macro_condition = VR_MACRO_CONDITION;
3502 		role_for_header_system = VR_HEADER_SYSTEM;
3503 		role_for_header_local = VR_HEADER_LOCAL;
3504 	}
3505 
3506 	cppInit ((bool) (passCount > 1), isInputLanguage (Lang_csharp), isInputLanguage(Lang_cpp),
3507 		 isInputLanguage(Lang_vera),
3508 		 kind_for_define, role_for_macro_undef, role_for_macro_condition, kind_for_param,
3509 		 kind_for_header, role_for_header_system, role_for_header_local,
3510 		 FIELD_UNKNOWN);
3511 
3512 	Signature = vStringNew ();
3513 
3514 	exception = (exception_t) setjmp (Exception);
3515 	rescan = RESCAN_NONE;
3516 	if (exception == ExceptionNone)
3517 		createTags (0, NULL);
3518 	else
3519 	{
3520 		deleteAllStatements ();
3521 		if (exception == ExceptionBraceFormattingError  &&  passCount == 1)
3522 		{
3523 			rescan = RESCAN_FAILED;
3524 			verbose ("%s: retrying file with fallback brace matching algorithm\n",
3525 					getInputFileName ());
3526 		}
3527 	}
3528 	vStringDelete (Signature);
3529 	cppTerminate ();
3530 	return rescan;
3531 }
3532 
buildKeywordHash(const langType language,unsigned int idx)3533 static void buildKeywordHash (const langType language, unsigned int idx)
3534 {
3535 	const size_t count = ARRAY_SIZE (KeywordTable);
3536 	size_t i;
3537 	for (i = 0  ;  i < count  ;  ++i)
3538 	{
3539 		const keywordDesc* const p = &KeywordTable [i];
3540 		if (p->isValid [idx])
3541 			addKeyword (p->name, language, (int) p->id);
3542 	}
3543 }
3544 
initializeCParser(const langType language)3545 static void initializeCParser (const langType language)
3546 {
3547 	Lang_c = language;
3548 	buildKeywordHash (language, 0);
3549 }
3550 
initializeCppParser(const langType language)3551 static void initializeCppParser (const langType language)
3552 {
3553 	Lang_cpp = language;
3554 	buildKeywordHash (language, 1);
3555 }
3556 
OldCParser(void)3557 extern parserDefinition* OldCParser (void)
3558 {
3559 	static const char *const extensions [] = { "c", NULL };
3560 	parserDefinition* def = parserNew ("OldC");
3561 	def->kindTable      = CKinds;
3562 	def->kindCount  = ARRAY_SIZE (CKinds);
3563 	def->extensions = extensions;
3564 	def->parser2    = findCTags;
3565 	def->initialize = initializeCParser;
3566 	def->enabled = 0;
3567 
3568 	/* cpreprocessor wants corkQueue. */
3569 	def->useCork    = CORK_QUEUE;
3570 	return def;
3571 }
3572 
OldCppParser(void)3573 extern parserDefinition* OldCppParser (void)
3574 {
3575 	static const char *const extensions [] = {
3576 		"c++", "cc", "cp", "cpp", "cxx",
3577 		"h", "h++", "hh", "hp", "hpp", "hxx", "inl",
3578 #ifndef CASE_INSENSITIVE_FILENAMES
3579 		"C", "H",
3580 #endif
3581 		NULL
3582 	};
3583 	static selectLanguage selectors[] = { selectByObjectiveCKeywords,
3584 					      NULL };
3585 
3586 	parserDefinition* def = parserNew ("OldC++");
3587 	def->kindTable      = CKinds;
3588 	def->kindCount  = ARRAY_SIZE (CKinds);
3589 	def->extensions = extensions;
3590 	def->parser2    = findCTags;
3591 	def->initialize = initializeCppParser;
3592 	def->selectLanguage = selectors;
3593 	def->enabled = 0;
3594 
3595 	/* cpreprocessor wants corkQueue. */
3596 	def->useCork    = CORK_QUEUE;
3597 	return def;
3598 }
3599