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