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