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