Merge pull request #11 from esorton/bugfix/add-constexpr-keyword-to-arduino-ctags
[arduino-ctags.git] / c.c
blob105bfa8bbbf1394d3583d648ae07d9d69246ae53
1 /*
2 * $Id: c.c 689 2008-12-13 21:17:36Z elliotth $
4 * Copyright (c) 1996-2003, Darren Hiebert
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for parsing and scanning C, C++ and Java
10 * source files.
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <string.h>
19 #include <setjmp.h>
21 #include "debug.h"
22 #include "entry.h"
23 #include "get.h"
24 #include "keyword.h"
25 #include "options.h"
26 #include "parse.h"
27 #include "read.h"
28 #include "routines.h"
31 * MACROS
34 #define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
35 #define parentDecl(st) ((st)->parent == NULL ? \
36 DECL_NONE : (st)->parent->declaration)
37 #define isType(token,t) (boolean) ((token)->type == (t))
38 #define insideEnumBody(st) ((st)->parent == NULL ? FALSE : \
39 (boolean) ((st)->parent->declaration == DECL_ENUM))
40 #define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
41 ! (st)->haveQualifyingName && (st)->scope == SCOPE_EXTERN)
43 #define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
45 #define isHighChar(c) ((c) != EOF && (unsigned char)(c) >= 0xc0)
48 * DATA DECLARATIONS
51 enum { NumTokens = 15 };
53 typedef enum eException {
54 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
55 ExceptionBraceFormattingError
56 } exception_t;
58 /* Used to specify type of keyword.
60 typedef enum eKeywordId {
61 KEYWORD_NONE = -1,
62 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
63 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
64 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
65 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST, KEYWORD_CONSTEXPR,
66 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
67 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
68 KEYWORD_DOUBLE,
69 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
70 KEYWORD_EXTENDS, KEYWORD_EVENT,
71 KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FOREACH,
72 KEYWORD_FRIEND, KEYWORD_FUNCTION,
73 KEYWORD_GOTO,
74 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
75 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
76 KEYWORD_INTERNAL,
77 KEYWORD_LOCAL, KEYWORD_LONG,
78 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
79 KEYWORD_MUTABLE,
80 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, KEYWORD_NOEXCEPT,
81 KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
82 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
83 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
84 KEYWORD_REGISTER, KEYWORD_RETURN,
85 KEYWORD_SHADOW, KEYWORD_STATE,
86 KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STATIC_ASSERT, KEYWORD_STRING,
87 KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
88 KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
89 KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
90 KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
91 KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
92 KEYWORD_USING,
93 KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
94 KEYWORD_WCHAR_T, KEYWORD_WHILE
95 } keywordId;
97 /* Used to determine whether keyword is valid for the current language and
98 * what its ID is.
100 typedef struct sKeywordDesc {
101 const char *name;
102 keywordId id;
103 short isValid [5]; /* indicates languages for which kw is valid */
104 } keywordDesc;
106 /* Used for reporting the type of object parsed by nextToken ().
108 typedef enum eTokenType {
109 TOKEN_NONE, /* none */
110 TOKEN_ARGS, /* a parenthetical pair and its contents */
111 TOKEN_BRACE_CLOSE,
112 TOKEN_BRACE_OPEN,
113 TOKEN_COLON, /* the colon character */
114 TOKEN_COMMA, /* the comma character */
115 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
116 TOKEN_KEYWORD,
117 TOKEN_NAME, /* an unknown name */
118 TOKEN_PACKAGE, /* a Java package name */
119 TOKEN_PAREN_NAME, /* a single name in parentheses */
120 TOKEN_SEMICOLON, /* the semicolon character */
121 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
122 TOKEN_STAR, /* pointer * detection */
123 TOKEN_AMPERSAND, /* ampersand & detection */
124 TOKEN_COUNT
125 } tokenType;
127 /* This describes the scoping of the current statement.
129 typedef enum eTagScope {
130 SCOPE_GLOBAL, /* no storage class specified */
131 SCOPE_STATIC, /* static storage class */
132 SCOPE_EXTERN, /* external storage class */
133 SCOPE_FRIEND, /* declares access only */
134 SCOPE_TYPEDEF, /* scoping depends upon context */
135 SCOPE_COUNT
136 } tagScope;
138 typedef enum eDeclaration {
139 DECL_NONE,
140 DECL_BASE, /* base type (default) */
141 DECL_CLASS,
142 DECL_ENUM,
143 DECL_EVENT,
144 DECL_FUNCTION,
145 DECL_IGNORE, /* non-taggable "declaration" */
146 DECL_INTERFACE,
147 DECL_NAMESPACE,
148 DECL_NOMANGLE, /* C++ name demangling block */
149 DECL_PACKAGE,
150 DECL_PROGRAM, /* Vera program */
151 DECL_STRUCT,
152 DECL_TASK, /* Vera task */
153 DECL_UNION,
154 DECL_COUNT
155 } declType;
157 typedef enum eVisibilityType {
158 ACCESS_UNDEFINED,
159 ACCESS_LOCAL,
160 ACCESS_PRIVATE,
161 ACCESS_PROTECTED,
162 ACCESS_PUBLIC,
163 ACCESS_DEFAULT, /* Java-specific */
164 ACCESS_COUNT
165 } accessType;
167 /* Information about the parent class of a member (if any).
169 typedef struct sMemberInfo {
170 accessType access; /* access of current statement */
171 accessType accessDefault; /* access default for current statement */
172 } memberInfo;
174 typedef struct sTokenInfo {
175 tokenType type;
176 keywordId keyword;
177 vString* name; /* the name of the token */
178 unsigned long lineNumber; /* line number of tag */
179 fpos_t filePosition; /* file position of line containing name */
180 } tokenInfo;
182 typedef enum eImplementation {
183 IMP_DEFAULT,
184 IMP_ABSTRACT,
185 IMP_VIRTUAL,
186 IMP_PURE_VIRTUAL,
187 IMP_COUNT
188 } impType;
190 /* Describes the statement currently undergoing analysis.
192 typedef struct sStatementInfo {
193 tagScope scope;
194 declType declaration; /* specifier associated with TOKEN_SPEC */
195 boolean gotName; /* was a name parsed yet? */
196 boolean haveQualifyingName; /* do we have a name we are considering? */
197 boolean gotParenName; /* was a name inside parentheses parsed yet? */
198 boolean gotArgs; /* was a list of parameters parsed yet? */
199 boolean isPointer; /* is 'name' a pointer? */
200 boolean inFunction; /* are we inside of a function? */
201 boolean assignment; /* have we handled an '='? */
202 boolean notVariable; /* has a variable declaration been disqualified ? */
203 impType implementation; /* abstract or concrete implementation? */
204 unsigned int tokenIndex; /* currently active token */
205 tokenInfo* token [(int) NumTokens];
206 tokenInfo* context; /* accumulated scope of current statement */
207 tokenInfo* blockName; /* name of current block */
208 memberInfo member; /* information regarding parent class/struct */
209 vString* parentClasses; /* parent classes */
210 struct sStatementInfo *parent; /* statement we are nested within */
211 } statementInfo;
213 /* Describes the type of tag being generated.
215 typedef enum eTagType {
216 TAG_UNDEFINED,
217 TAG_CLASS, /* class name */
218 TAG_ENUM, /* enumeration name */
219 TAG_ENUMERATOR, /* enumerator (enumeration value) */
220 TAG_EVENT, /* event */
221 TAG_FIELD, /* field (Java) */
222 TAG_FUNCTION, /* function definition */
223 TAG_INTERFACE, /* interface declaration */
224 TAG_LOCAL, /* local variable definition */
225 TAG_MEMBER, /* structure, class or interface member */
226 TAG_METHOD, /* method declaration */
227 TAG_NAMESPACE, /* namespace name */
228 TAG_PACKAGE, /* package name */
229 TAG_PROGRAM, /* program name */
230 TAG_PROPERTY, /* property name */
231 TAG_PROTOTYPE, /* function prototype or declaration */
232 TAG_STRUCT, /* structure name */
233 TAG_TASK, /* task name */
234 TAG_TYPEDEF, /* typedef name */
235 TAG_UNION, /* union name */
236 TAG_VARIABLE, /* variable definition */
237 TAG_EXTERN_VAR, /* external variable declaration */
238 TAG_COUNT /* must be last */
239 } tagType;
241 typedef struct sParenInfo {
242 boolean isPointer;
243 boolean isParamList;
244 boolean isKnrParamList;
245 boolean isNameCandidate;
246 boolean invalidContents;
247 boolean nestedArgs;
248 unsigned int parameterCount;
249 } parenInfo;
252 * DATA DEFINITIONS
255 static jmp_buf Exception;
257 static langType Lang_c;
258 static langType Lang_cpp;
259 static langType Lang_csharp;
260 static langType Lang_java;
261 static langType Lang_vera;
262 static vString *Signature;
263 static boolean CollectingSignature;
264 static vString *ReturnType;
266 /* Number used to uniquely identify anonymous structs and unions. */
267 static int AnonymousID = 0;
269 /* Used to index into the CKinds table. */
270 typedef enum {
271 CK_UNDEFINED = -1,
272 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
273 CK_ENUMERATION, CK_LOCAL, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
274 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
275 CK_EXTERN_VARIABLE
276 } cKind;
278 static kindOption CKinds [] = {
279 { TRUE, 'c', "class", "classes"},
280 { TRUE, 'd', "macro", "macro definitions"},
281 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
282 { TRUE, 'f', "function", "function definitions"},
283 { TRUE, 'g', "enum", "enumeration names"},
284 { FALSE, 'l', "local", "local variables"},
285 { TRUE, 'm', "member", "class, struct, and union members"},
286 { TRUE, 'n', "namespace", "namespaces"},
287 { FALSE, 'p', "prototype", "function prototypes"},
288 { TRUE, 's', "struct", "structure names"},
289 { TRUE, 't', "typedef", "typedefs"},
290 { TRUE, 'u', "union", "union names"},
291 { TRUE, 'v', "variable", "variable definitions"},
292 { FALSE, 'x', "externvar", "external and forward variable declarations"},
295 typedef enum {
296 CSK_UNDEFINED = -1,
297 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
298 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
299 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
300 } csharpKind;
302 static kindOption CsharpKinds [] = {
303 { TRUE, 'c', "class", "classes"},
304 { TRUE, 'd', "macro", "macro definitions"},
305 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
306 { TRUE, 'E', "event", "events"},
307 { TRUE, 'f', "field", "fields"},
308 { TRUE, 'g', "enum", "enumeration names"},
309 { TRUE, 'i', "interface", "interfaces"},
310 { FALSE, 'l', "local", "local variables"},
311 { TRUE, 'm', "method", "methods"},
312 { TRUE, 'n', "namespace", "namespaces"},
313 { TRUE, 'p', "property", "properties"},
314 { TRUE, 's', "struct", "structure names"},
315 { TRUE, 't', "typedef", "typedefs"},
318 /* Used to index into the JavaKinds table. */
319 typedef enum {
320 JK_UNDEFINED = -1,
321 JK_CLASS, JK_ENUM_CONSTANT, JK_FIELD, JK_ENUM, JK_INTERFACE,
322 JK_LOCAL, JK_METHOD, JK_PACKAGE, JK_ACCESS, JK_CLASS_PREFIX
323 } javaKind;
325 static kindOption JavaKinds [] = {
326 { TRUE, 'c', "class", "classes"},
327 { TRUE, 'e', "enum constant", "enum constants"},
328 { TRUE, 'f', "field", "fields"},
329 { TRUE, 'g', "enum", "enum types"},
330 { TRUE, 'i', "interface", "interfaces"},
331 { FALSE, 'l', "local", "local variables"},
332 { TRUE, 'm', "method", "methods"},
333 { TRUE, 'p', "package", "packages"},
336 /* Used to index into the VeraKinds table. */
337 typedef enum {
338 VK_UNDEFINED = -1,
339 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
340 VK_ENUMERATION, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
341 VK_TASK, VK_TYPEDEF, VK_VARIABLE,
342 VK_EXTERN_VARIABLE
343 } veraKind;
345 static kindOption VeraKinds [] = {
346 { TRUE, 'c', "class", "classes"},
347 { TRUE, 'd', "macro", "macro definitions"},
348 { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
349 { TRUE, 'f', "function", "function definitions"},
350 { TRUE, 'g', "enum", "enumeration names"},
351 { FALSE, 'l', "local", "local variables"},
352 { TRUE, 'm', "member", "class, struct, and union members"},
353 { TRUE, 'p', "program", "programs"},
354 { FALSE, 'P', "prototype", "function prototypes"},
355 { TRUE, 't', "task", "tasks"},
356 { TRUE, 'T', "typedef", "typedefs"},
357 { TRUE, 'v', "variable", "variable definitions"},
358 { FALSE, 'x', "externvar", "external variable declarations"}
361 static const keywordDesc KeywordTable [] = {
362 /* C++ */
363 /* ANSI C | C# Java */
364 /* | | | | Vera */
365 /* keyword keyword ID | | | | | */
366 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0 } },
367 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0 } },
368 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1 } },
369 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1 } },
370 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1 } },
371 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1 } },
372 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1 } },
373 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0 } },
374 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0 } },
375 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0 } },
376 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0 } },
377 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0 } },
378 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1 } },
379 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0 } },
380 { "constexpr", KEYWORD_CONSTEXPR, { 0, 1, 0, 0, 0 } },
381 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1 } },
382 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1 } },
383 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1 } },
384 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0 } },
385 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0 } },
386 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0 } },
387 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0 } },
388 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0 } },
389 { "else", KEYWORD_ELSE, { 1, 1, 1, 1, 0 } },
390 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1 } },
391 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1 } },
392 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0 } },
393 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1 } },
394 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1 } },
395 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0 } },
396 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0 } },
397 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0 } },
398 { "foreach", KEYWORD_FOREACH, { 0, 0, 1, 0, 0 } },
399 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0 } },
400 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1 } },
401 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0 } },
402 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0 } },
403 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0 } },
404 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0 } },
405 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0 } },
406 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1 } },
407 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1 } },
408 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0 } },
409 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1 } },
410 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1 } },
411 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0 } },
412 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1 } },
413 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0 } },
414 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1 } },
415 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1 } },
416 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1 } },
417 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1 } },
418 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0 } },
419 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0 } },
420 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0 } },
421 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0 } },
422 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1 } },
423 { "noexcept", KEYWORD_NOEXCEPT, { 0, 1, 0, 0, 0 } },
424 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0 } },
425 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1 } },
426 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0 } },
427 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0 } },
428 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0 } },
429 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1 } },
430 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1 } },
431 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0 } },
432 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1 } },
433 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1 } },
434 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1 } },
435 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0 } },
436 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0 } },
437 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1 } },
438 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0 } },
439 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0 } },
440 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1 } },
441 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1 } },
442 { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0} },
443 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1 } },
444 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0 } },
445 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0 } },
446 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0 } },
447 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1 } },
448 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0 } },
449 { "this", KEYWORD_THIS, { 0, 1, 1, 1, 0 } },
450 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0 } },
451 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0 } },
452 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1 } },
453 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1 } },
454 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0 } },
455 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0 } },
456 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1 } },
457 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0 } },
458 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0 } },
459 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0 } },
460 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0 } },
461 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0 } },
462 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0 } },
463 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0 } },
464 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1 } },
465 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1 } },
466 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0 } },
467 { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0 } },
468 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0 } }
472 * FUNCTION PROTOTYPES
474 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
477 * FUNCTION DEFINITIONS
480 extern boolean includingDefineTags (void)
482 return CKinds [CK_DEFINE].enabled;
486 * Token management
489 static void initToken (tokenInfo* const token)
491 token->type = TOKEN_NONE;
492 token->keyword = KEYWORD_NONE;
493 token->lineNumber = getSourceLineNumber ();
494 token->filePosition = getInputFilePosition ();
495 vStringClear (token->name);
498 static void advanceToken (statementInfo* const st)
500 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
501 st->tokenIndex = 0;
502 else
503 ++st->tokenIndex;
504 initToken (st->token [st->tokenIndex]);
507 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
509 unsigned int tokenIndex;
510 unsigned int num = (unsigned int) NumTokens;
511 Assert (n < num);
512 tokenIndex = (st->tokenIndex + num - n) % num;
513 return st->token [tokenIndex];
516 static void setToken (statementInfo *const st, const tokenType type)
518 tokenInfo *token;
519 token = activeToken (st);
520 initToken (token);
521 token->type = type;
524 static void retardToken (statementInfo *const st)
526 if (st->tokenIndex == 0)
527 st->tokenIndex = (unsigned int) NumTokens - 1;
528 else
529 --st->tokenIndex;
530 setToken (st, TOKEN_NONE);
533 static tokenInfo *newToken (void)
535 tokenInfo *const token = xMalloc (1, tokenInfo);
536 token->name = vStringNew ();
537 initToken (token);
538 return token;
541 static void deleteToken (tokenInfo *const token)
543 if (token != NULL)
545 vStringDelete (token->name);
546 eFree (token);
550 static const char *accessString (const accessType access)
552 static const char *const names [] = {
553 "?", "local", "private", "protected", "public", "default"
555 Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
556 Assert ((int) access < ACCESS_COUNT);
557 return names [(int) access];
560 static const char *implementationString (const impType imp)
562 static const char *const names [] ={
563 "?", "abstract", "virtual", "pure virtual"
565 Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
566 Assert ((int) imp < IMP_COUNT);
567 return names [(int) imp];
571 * Debugging functions
573 #ifdef DEBUG
575 #define boolString(c) ((c) ? "TRUE" : "FALSE")
577 static const char *tokenString (const tokenType type)
579 static const char *const names [] = {
580 "none", "args", "}", "{", "colon", "comma", "double colon", "keyword",
581 "name", "package", "paren-name", "semicolon", "specifier", "star", "ampersand"
583 Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
584 Assert ((int) type < TOKEN_COUNT);
585 return names [(int) type];
588 static const char *scopeString (const tagScope scope)
590 static const char *const names [] = {
591 "global", "static", "extern", "friend", "typedef"
593 Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
594 Assert ((int) scope < SCOPE_COUNT);
595 return names [(int) scope];
598 static const char *declString (const declType declaration)
600 static const char *const names [] = {
601 "?", "base", "class", "enum", "event", "function", "ignore",
602 "interface", "namespace", "no mangle", "package", "program",
603 "struct", "task", "union",
605 Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
606 Assert ((int) declaration < DECL_COUNT);
607 return names [(int) declaration];
610 static const char *keywordString (const keywordId keyword)
612 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
613 const char *name = "none";
614 size_t i;
615 for (i = 0 ; i < count ; ++i)
617 const keywordDesc *p = &KeywordTable [i];
618 if (p->id == keyword)
620 name = p->name;
621 break;
624 return name;
627 static void __unused__ pt (tokenInfo *const token)
629 if (isType (token, TOKEN_NAME))
630 printf ("type: %-12s: %-13s line: %lu\n",
631 tokenString (token->type), vStringValue (token->name),
632 token->lineNumber);
633 else if (isType (token, TOKEN_KEYWORD))
634 printf ("type: %-12s: %-13s line: %lu\n",
635 tokenString (token->type), keywordString (token->keyword),
636 token->lineNumber);
637 else
638 printf ("type: %-12s line: %lu\n",
639 tokenString (token->type), token->lineNumber);
642 static void __unused__ ps (statementInfo *const st)
644 unsigned int i;
645 printf ("scope: %s decl: %s gotName: %s gotParenName: %s isPointer: %s\n",
646 scopeString (st->scope), declString (st->declaration),
647 boolString (st->gotName), boolString (st->gotParenName), boolString (st->isPointer));
648 printf ("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
649 printf ("access: %s default: %s\n", accessString (st->member.access),
650 accessString (st->member.accessDefault));
651 printf ("active token : ");
652 pt (activeToken (st));
653 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
655 printf ("prev %u : ", i);
656 pt (prevToken (st, i));
658 printf ("context: ");
659 pt (st->context);
662 #endif
665 * Statement management
668 static boolean isContextualKeyword (const tokenInfo *const token)
670 boolean result;
671 switch (token->keyword)
673 case KEYWORD_CLASS:
674 case KEYWORD_ENUM:
675 case KEYWORD_INTERFACE:
676 case KEYWORD_NAMESPACE:
677 case KEYWORD_STRUCT:
678 case KEYWORD_UNION:
679 result = TRUE;
680 break;
682 default: result = FALSE; break;
684 return result;
687 static boolean isContextualStatement (const statementInfo *const st)
689 boolean result = FALSE;
690 if (st != NULL) switch (st->declaration)
692 case DECL_CLASS:
693 case DECL_ENUM:
694 case DECL_INTERFACE:
695 case DECL_NAMESPACE:
696 case DECL_STRUCT:
697 case DECL_UNION:
698 result = TRUE;
699 break;
701 default: result = FALSE; break;
703 return result;
706 static boolean isMember (const statementInfo *const st)
708 boolean result;
709 if (isType (st->context, TOKEN_NAME))
710 result = TRUE;
711 else
712 result = (boolean)
713 (st->parent != NULL && isContextualStatement (st->parent));
714 return result;
717 static void initMemberInfo (statementInfo *const st)
719 accessType accessDefault = ACCESS_UNDEFINED;
721 if (st->parent != NULL) switch (st->parent->declaration)
723 case DECL_ENUM:
724 accessDefault = (isLanguage (Lang_java) ? ACCESS_PUBLIC : ACCESS_UNDEFINED);
725 break;
726 case DECL_NAMESPACE:
727 accessDefault = ACCESS_UNDEFINED;
728 break;
730 case DECL_CLASS:
731 if (isLanguage (Lang_java))
732 accessDefault = ACCESS_DEFAULT;
733 else
734 accessDefault = ACCESS_PRIVATE;
735 break;
737 case DECL_INTERFACE:
738 case DECL_STRUCT:
739 case DECL_UNION:
740 accessDefault = ACCESS_PUBLIC;
741 break;
743 default: break;
745 st->member.accessDefault = accessDefault;
746 st->member.access = accessDefault;
749 static void reinitStatement (statementInfo *const st, const boolean partial)
751 unsigned int i;
753 if (! partial)
755 st->scope = SCOPE_GLOBAL;
756 if (isContextualStatement (st->parent))
757 st->declaration = DECL_BASE;
758 else
759 st->declaration = DECL_NONE;
761 st->gotParenName = FALSE;
762 st->isPointer = FALSE;
763 st->inFunction = FALSE;
764 st->assignment = FALSE;
765 st->notVariable = FALSE;
766 st->implementation = IMP_DEFAULT;
767 st->gotArgs = FALSE;
768 st->gotName = FALSE;
769 st->haveQualifyingName = FALSE;
770 st->tokenIndex = 0;
772 if (st->parent != NULL)
773 st->inFunction = st->parent->inFunction;
775 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
776 initToken (st->token [i]);
778 initToken (st->context);
780 /* Keep the block name, so that a variable following after a comma will
781 * still have the structure name.
783 if (! partial)
784 initToken (st->blockName);
786 vStringClear (st->parentClasses);
788 /* Init member info.
790 if (! partial)
791 st->member.access = st->member.accessDefault;
794 static void initStatement (statementInfo *const st, statementInfo *const parent)
796 st->parent = parent;
797 initMemberInfo (st);
798 reinitStatement (st, FALSE);
802 * Tag generation functions
804 static cKind cTagKind (const tagType type)
806 cKind result = CK_UNDEFINED;
807 switch (type)
809 case TAG_CLASS: result = CK_CLASS; break;
810 case TAG_ENUM: result = CK_ENUMERATION; break;
811 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
812 case TAG_FUNCTION: result = CK_FUNCTION; break;
813 case TAG_LOCAL: result = CK_LOCAL; break;
814 case TAG_MEMBER: result = CK_MEMBER; break;
815 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
816 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
817 case TAG_STRUCT: result = CK_STRUCT; break;
818 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
819 case TAG_UNION: result = CK_UNION; break;
820 case TAG_VARIABLE: result = CK_VARIABLE; break;
821 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
823 default: Assert ("Bad C tag type" == NULL); break;
825 return result;
828 static csharpKind csharpTagKind (const tagType type)
830 csharpKind result = CSK_UNDEFINED;
831 switch (type)
833 case TAG_CLASS: result = CSK_CLASS; break;
834 case TAG_ENUM: result = CSK_ENUMERATION; break;
835 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
836 case TAG_EVENT: result = CSK_EVENT; break;
837 case TAG_FIELD: result = CSK_FIELD ; break;
838 case TAG_INTERFACE: result = CSK_INTERFACE; break;
839 case TAG_LOCAL: result = CSK_LOCAL; break;
840 case TAG_METHOD: result = CSK_METHOD; break;
841 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
842 case TAG_PROPERTY: result = CSK_PROPERTY; break;
843 case TAG_STRUCT: result = CSK_STRUCT; break;
844 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
846 default: Assert ("Bad C# tag type" == NULL); break;
848 return result;
851 static javaKind javaTagKind (const tagType type)
853 javaKind result = JK_UNDEFINED;
854 switch (type)
856 case TAG_CLASS: result = JK_CLASS; break;
857 case TAG_ENUM: result = JK_ENUM; break;
858 case TAG_ENUMERATOR: result = JK_ENUM_CONSTANT; break;
859 case TAG_FIELD: result = JK_FIELD; break;
860 case TAG_INTERFACE: result = JK_INTERFACE; break;
861 case TAG_LOCAL: result = JK_LOCAL; break;
862 case TAG_METHOD: result = JK_METHOD; break;
863 case TAG_PACKAGE: result = JK_PACKAGE; break;
865 default: Assert ("Bad Java tag type" == NULL); break;
867 return result;
870 static veraKind veraTagKind (const tagType type) {
871 veraKind result = VK_UNDEFINED;
872 switch (type)
874 case TAG_CLASS: result = VK_CLASS; break;
875 case TAG_ENUM: result = VK_ENUMERATION; break;
876 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
877 case TAG_FUNCTION: result = VK_FUNCTION; break;
878 case TAG_LOCAL: result = VK_LOCAL; break;
879 case TAG_MEMBER: result = VK_MEMBER; break;
880 case TAG_PROGRAM: result = VK_PROGRAM; break;
881 case TAG_PROTOTYPE: result = VK_PROTOTYPE; break;
882 case TAG_TASK: result = VK_TASK; break;
883 case TAG_TYPEDEF: result = VK_TYPEDEF; break;
884 case TAG_VARIABLE: result = VK_VARIABLE; break;
885 case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
887 default: Assert ("Bad Vera tag type" == NULL); break;
889 return result;
892 static const char *tagName (const tagType type)
894 const char* result;
895 if (isLanguage (Lang_csharp))
896 result = CsharpKinds [csharpTagKind (type)].name;
897 else if (isLanguage (Lang_java))
898 result = JavaKinds [javaTagKind (type)].name;
899 else if (isLanguage (Lang_vera))
900 result = VeraKinds [veraTagKind (type)].name;
901 else
902 result = CKinds [cTagKind (type)].name;
903 return result;
906 static int tagLetter (const tagType type)
908 int result;
909 if (isLanguage (Lang_csharp))
910 result = CsharpKinds [csharpTagKind (type)].letter;
911 else if (isLanguage (Lang_java))
912 result = JavaKinds [javaTagKind (type)].letter;
913 else if (isLanguage (Lang_vera))
914 result = VeraKinds [veraTagKind (type)].letter;
915 else
916 result = CKinds [cTagKind (type)].letter;
917 return result;
920 static boolean includeTag (const tagType type, const boolean isFileScope)
922 boolean result;
923 if (isFileScope && ! Option.include.fileScope)
924 result = FALSE;
925 else if (isLanguage (Lang_csharp))
926 result = CsharpKinds [csharpTagKind (type)].enabled;
927 else if (isLanguage (Lang_java))
928 result = JavaKinds [javaTagKind (type)].enabled;
929 else if (isLanguage (Lang_vera))
930 result = VeraKinds [veraTagKind (type)].enabled;
931 else
932 result = CKinds [cTagKind (type)].enabled;
933 return result;
936 static tagType declToTagType (const declType declaration)
938 tagType type = TAG_UNDEFINED;
940 switch (declaration)
942 case DECL_CLASS: type = TAG_CLASS; break;
943 case DECL_ENUM: type = TAG_ENUM; break;
944 case DECL_EVENT: type = TAG_EVENT; break;
945 case DECL_FUNCTION: type = TAG_FUNCTION; break;
946 case DECL_INTERFACE: type = TAG_INTERFACE; break;
947 case DECL_NAMESPACE: type = TAG_NAMESPACE; break;
948 case DECL_PROGRAM: type = TAG_PROGRAM; break;
949 case DECL_TASK: type = TAG_TASK; break;
950 case DECL_STRUCT: type = TAG_STRUCT; break;
951 case DECL_UNION: type = TAG_UNION; break;
953 default: Assert ("Unexpected declaration" == NULL); break;
955 return type;
958 static const char* accessField (const statementInfo *const st)
960 const char* result = NULL;
961 if (isLanguage (Lang_cpp) && st->scope == SCOPE_FRIEND)
962 result = "friend";
963 else if (st->member.access != ACCESS_UNDEFINED)
964 result = accessString (st->member.access);
965 return result;
968 static void addContextSeparator (vString *const scope)
970 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
971 vStringCatS (scope, "::");
972 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
973 vStringCatS (scope, ".");
976 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
977 const statementInfo *const st,
978 vString *const scope, vString *const typeRef)
980 /* For selected tag types, append an extension flag designating the
981 * parent object in which the tag is defined.
983 switch (type)
985 default: break;
987 case TAG_FUNCTION:
988 case TAG_METHOD:
989 case TAG_PROTOTYPE:
990 if (vStringLength (Signature) > 0)
992 tag->extensionFields.signature = vStringValue (Signature);
995 if (vStringLength (ReturnType) > 0)
997 tag->extensionFields.returnType = vStringValue (ReturnType);
999 case TAG_CLASS:
1000 case TAG_ENUM:
1001 case TAG_ENUMERATOR:
1002 case TAG_EVENT:
1003 case TAG_FIELD:
1004 case TAG_INTERFACE:
1005 case TAG_MEMBER:
1006 case TAG_NAMESPACE:
1007 case TAG_PROPERTY:
1008 case TAG_STRUCT:
1009 case TAG_TASK:
1010 case TAG_TYPEDEF:
1011 case TAG_UNION:
1012 if (vStringLength (scope) > 0 &&
1013 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1015 if (isType (st->context, TOKEN_NAME))
1016 tag->extensionFields.scope [0] = tagName (TAG_CLASS);
1017 else
1018 tag->extensionFields.scope [0] =
1019 tagName (declToTagType (parentDecl (st)));
1020 tag->extensionFields.scope [1] = vStringValue (scope);
1022 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1023 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1026 tag->extensionFields.inheritance =
1027 vStringValue (st->parentClasses);
1029 if (st->implementation != IMP_DEFAULT &&
1030 (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
1031 isLanguage (Lang_java)))
1033 tag->extensionFields.implementation =
1034 implementationString (st->implementation);
1036 if (isMember (st))
1038 tag->extensionFields.access = accessField (st);
1040 break;
1043 /* Add typename info, type of the tag and name of struct/union/etc. */
1044 if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
1045 && isContextualStatement(st))
1047 char *p;
1049 tag->extensionFields.typeRef [0] =
1050 tagName (declToTagType (st->declaration));
1051 p = vStringValue (st->blockName->name);
1053 /* If there was no {} block get the name from the token before the
1054 * name (current token is ';' or ',', previous token is the name).
1056 if (p == NULL || *p == '\0')
1058 tokenInfo *const prev2 = prevToken (st, 2);
1059 if (isType (prev2, TOKEN_NAME))
1060 p = vStringValue (prev2->name);
1063 /* Prepend the scope name if there is one. */
1064 if (vStringLength (scope) > 0)
1066 vStringCopy(typeRef, scope);
1067 addContextSeparator (typeRef);
1068 vStringCatS(typeRef, p);
1069 p = vStringValue (typeRef);
1071 tag->extensionFields.typeRef [1] = p;
1075 static void findScopeHierarchy (vString *const string,
1076 const statementInfo *const st)
1078 vStringClear (string);
1079 if (isType (st->context, TOKEN_NAME))
1080 vStringCopy (string, st->context->name);
1081 if (st->parent != NULL)
1083 vString *temp = vStringNew ();
1084 const statementInfo *s;
1085 for (s = st->parent ; s != NULL ; s = s->parent)
1087 if (isContextualStatement (s) ||
1088 s->declaration == DECL_NAMESPACE ||
1089 s->declaration == DECL_PROGRAM)
1091 vStringCopy (temp, string);
1092 vStringClear (string);
1093 Assert (isType (s->blockName, TOKEN_NAME));
1094 if (isType (s->context, TOKEN_NAME) &&
1095 vStringLength (s->context->name) > 0)
1097 vStringCat (string, s->context->name);
1098 addContextSeparator (string);
1100 vStringCat (string, s->blockName->name);
1101 if (vStringLength (temp) > 0)
1102 addContextSeparator (string);
1103 vStringCat (string, temp);
1106 vStringDelete (temp);
1110 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1111 vString *const scope)
1113 if (Option.include.qualifiedTags &&
1114 scope != NULL && vStringLength (scope) > 0)
1116 vString *const scopedName = vStringNew ();
1118 if (type != TAG_ENUMERATOR)
1119 vStringCopy (scopedName, scope);
1120 else
1122 /* remove last component (i.e. enumeration name) from scope */
1123 const char* const sc = vStringValue (scope);
1124 const char* colon = strrchr (sc, ':');
1125 if (colon != NULL)
1127 while (*colon == ':' && colon > sc)
1128 --colon;
1129 vStringNCopy (scopedName, scope, colon + 1 - sc);
1132 if (vStringLength (scopedName) > 0)
1134 addContextSeparator (scopedName);
1135 vStringCatS (scopedName, e->name);
1136 e->name = vStringValue (scopedName);
1137 makeTagEntry (e);
1139 vStringDelete (scopedName);
1143 static void makeTag (const tokenInfo *const token,
1144 const statementInfo *const st,
1145 boolean isFileScope, const tagType type)
1147 /* Nothing is really of file scope when it appears in a header file.
1149 isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
1151 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 &&
1152 includeTag (type, isFileScope))
1154 vString *scope = vStringNew ();
1155 /* Use "typeRef" to store the typename from addOtherFields() until
1156 * it's used in makeTagEntry().
1158 vString *typeRef = vStringNew ();
1159 tagEntryInfo e;
1161 initTagEntry (&e, vStringValue (token->name));
1163 e.lineNumber = token->lineNumber;
1164 e.filePosition = token->filePosition;
1165 e.isFileScope = isFileScope;
1166 e.kindName = tagName (type);
1167 e.kind = tagLetter (type);
1169 findScopeHierarchy (scope, st);
1170 addOtherFields (&e, type, st, scope, typeRef);
1172 makeTagEntry (&e);
1173 makeExtraTagEntry (type, &e, scope);
1174 vStringDelete (scope);
1175 vStringDelete (typeRef);
1179 static boolean isValidTypeSpecifier (const declType declaration)
1181 boolean result;
1182 switch (declaration)
1184 case DECL_BASE:
1185 case DECL_CLASS:
1186 case DECL_ENUM:
1187 case DECL_EVENT:
1188 case DECL_STRUCT:
1189 case DECL_UNION:
1190 result = TRUE;
1191 break;
1193 default:
1194 result = FALSE;
1195 break;
1197 return result;
1200 static void qualifyEnumeratorTag (const statementInfo *const st,
1201 const tokenInfo *const nameToken)
1203 if (isType (nameToken, TOKEN_NAME))
1204 makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
1207 static void qualifyFunctionTag (const statementInfo *const st,
1208 const tokenInfo *const nameToken)
1210 if (isType (nameToken, TOKEN_NAME))
1212 tagType type;
1213 const boolean isFileScope =
1214 (boolean) (st->member.access == ACCESS_PRIVATE ||
1215 (!isMember (st) && st->scope == SCOPE_STATIC));
1216 if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1217 type = TAG_METHOD;
1218 else if (isLanguage (Lang_vera) && st->declaration == DECL_TASK)
1219 type = TAG_TASK;
1220 else
1221 type = TAG_FUNCTION;
1222 makeTag (nameToken, st, isFileScope, type);
1226 static void qualifyFunctionDeclTag (const statementInfo *const st,
1227 const tokenInfo *const nameToken)
1229 if (! isType (nameToken, TOKEN_NAME))
1231 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1232 qualifyFunctionTag (st, nameToken);
1233 else if (st->scope == SCOPE_TYPEDEF)
1234 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1235 else if (isValidTypeSpecifier (st->declaration) && ! isLanguage (Lang_csharp))
1236 makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
1239 static void qualifyCompoundTag (const statementInfo *const st,
1240 const tokenInfo *const nameToken)
1242 if (isType (nameToken, TOKEN_NAME))
1244 const tagType type = declToTagType (st->declaration);
1245 const boolean fileScoped = (boolean)
1246 (!(isLanguage (Lang_java) ||
1247 isLanguage (Lang_csharp) ||
1248 isLanguage (Lang_vera)));
1250 if (type != TAG_UNDEFINED)
1251 makeTag (nameToken, st, fileScoped, type);
1255 static void qualifyBlockTag (statementInfo *const st,
1256 const tokenInfo *const nameToken)
1258 switch (st->declaration)
1260 case DECL_CLASS:
1261 case DECL_ENUM:
1262 case DECL_INTERFACE:
1263 case DECL_NAMESPACE:
1264 case DECL_PROGRAM:
1265 case DECL_STRUCT:
1266 case DECL_UNION:
1267 qualifyCompoundTag (st, nameToken);
1268 break;
1269 default: break;
1273 static void qualifyVariableTag (const statementInfo *const st,
1274 const tokenInfo *const nameToken)
1276 /* We have to watch that we do not interpret a declaration of the
1277 * form "struct tag;" as a variable definition. In such a case, the
1278 * token preceding the name will be a keyword.
1280 if (! isType (nameToken, TOKEN_NAME))
1282 else if (st->scope == SCOPE_TYPEDEF)
1283 makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
1284 else if (st->declaration == DECL_EVENT)
1285 makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE),
1286 TAG_EVENT);
1287 else if (st->declaration == DECL_PACKAGE)
1288 makeTag (nameToken, st, FALSE, TAG_PACKAGE);
1289 else if (isValidTypeSpecifier (st->declaration))
1291 if (st->notVariable)
1293 else if (isMember (st))
1295 if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
1296 makeTag (nameToken, st,
1297 (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1298 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1299 makeTag (nameToken, st, TRUE, TAG_MEMBER);
1301 else
1303 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1304 makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
1305 else if (st->inFunction)
1306 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
1307 TAG_LOCAL);
1308 else
1309 makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
1310 TAG_VARIABLE);
1316 * Parsing functions
1319 static int skipToOneOf (const char *const chars)
1321 int c;
1323 c = cppGetc ();
1324 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1325 return c;
1328 /* Skip to the next non-white character.
1330 static int skipToNonWhite (void)
1332 boolean found = FALSE;
1333 int c;
1335 #if 0
1337 c = cppGetc ();
1338 while (isspace (c));
1339 #else
1340 while (1)
1342 c = cppGetc ();
1343 if (isspace (c))
1344 found = TRUE;
1345 else
1346 break;
1348 if (CollectingSignature && found)
1349 vStringPut (Signature, ' ');
1350 #endif
1352 return c;
1355 /* Skips to the next brace in column 1. This is intended for cases where
1356 * preprocessor constructs result in unbalanced braces.
1358 static void skipToFormattedBraceMatch (void)
1360 int c, next;
1362 c = cppGetc ();
1363 next = cppGetc ();
1364 while (c != EOF && (c != '\n' || next != '}'))
1366 c = next;
1367 next = cppGetc ();
1371 /* Skip to the matching character indicated by the pair string. If skipping
1372 * to a matching brace and any brace is found within a different level of a
1373 * #if conditional statement while brace formatting is in effect, we skip to
1374 * the brace matched by its formatting. It is assumed that we have already
1375 * read the character which starts the group (i.e. the first character of
1376 * "pair").
1378 static void skipToMatch (const char *const pair)
1380 const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
1381 const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
1382 const unsigned int initialLevel = getDirectiveNestLevel ();
1383 const int begin = pair [0], end = pair [1];
1384 const unsigned long inputLineNumber = getInputLineNumber ();
1385 int matchLevel = 1;
1386 int c = '\0';
1388 while (matchLevel > 0 && (c = skipToNonWhite ()) != EOF)
1390 if (CollectingSignature)
1391 vStringPut (Signature, c);
1394 if (c == begin)
1396 // watch out for '<<' in template arguments
1397 int x = cppGetc ();
1398 if(c == '<' && x == '<') {
1399 // we've found a << - do nothing except record the signature
1400 if (CollectingSignature)
1401 vStringPut(Signature, x);
1402 } else {
1403 cppUngetc (x);
1404 ++matchLevel;
1405 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1407 skipToFormattedBraceMatch ();
1408 break;
1412 else if (c == end)
1414 // don't care if you find a '>>' (the important thing is closing the brackets)
1415 int x = cppGetc ();
1416 cppUngetc (x);
1417 --matchLevel;
1418 if (braceFormatting && getDirectiveNestLevel () != initialLevel)
1420 skipToFormattedBraceMatch ();
1421 break;
1424 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1425 * match problems with C++ generics containing a static expression like
1426 * foo<X<Y> bar;
1427 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1428 else if (isLanguage (Lang_cpp) && begin == '<' &&
1429 (c == ';' || c == '{'))
1431 cppUngetc (c);
1432 break;
1435 if (c == EOF)
1437 verbose ("%s: failed to find match for '%c' at line %lu\n",
1438 getInputFileName (), begin, inputLineNumber);
1439 if (braceMatching)
1440 longjmp (Exception, (int) ExceptionBraceFormattingError);
1441 else
1442 longjmp (Exception, (int) ExceptionFormattingError);
1446 static void skipParens (void)
1448 const int c = skipToNonWhite ();
1450 if (c == '(')
1451 skipToMatch ("()");
1452 else
1453 cppUngetc (c);
1456 static void skipBraces (void)
1458 const int c = skipToNonWhite ();
1460 if (c == '{')
1461 skipToMatch ("{}");
1462 else
1463 cppUngetc (c);
1466 static keywordId analyzeKeyword (const char *const name)
1468 const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
1469 return id;
1472 static void analyzeIdentifier (tokenInfo *const token)
1474 char *const name = vStringValue (token->name);
1475 const char *replacement = NULL;
1476 boolean parensToo = FALSE;
1478 if (isLanguage (Lang_java) ||
1479 ! isIgnoreToken (name, &parensToo, &replacement))
1481 if (replacement != NULL)
1482 token->keyword = analyzeKeyword (replacement);
1483 else
1484 token->keyword = analyzeKeyword (vStringValue (token->name));
1486 if (token->keyword == KEYWORD_NONE)
1487 token->type = TOKEN_NAME;
1488 else
1489 token->type = TOKEN_KEYWORD;
1491 else
1493 initToken (token);
1494 if (parensToo)
1496 int c = skipToNonWhite ();
1498 if (c == '(')
1499 skipToMatch ("()");
1504 static void readIdentifier (tokenInfo *const token, const int firstChar)
1506 vString *const name = token->name;
1507 int c = firstChar;
1508 boolean first = TRUE;
1510 initToken (token);
1512 /* Bug #1585745: strangely, C++ destructors allow whitespace between
1513 * the ~ and the class name. */
1514 if (isLanguage (Lang_cpp) && firstChar == '~')
1516 vStringPut (name, c);
1517 c = skipToNonWhite ();
1522 vStringPut (name, c);
1523 if (CollectingSignature)
1525 if (!first)
1526 vStringPut (Signature, c);
1527 first = FALSE;
1529 c = cppGetc ();
1530 } while (isident (c) || ((isLanguage (Lang_java) || isLanguage (Lang_csharp)) && (isHighChar (c) || c == '.')));
1531 vStringTerminate (name);
1532 cppUngetc (c); /* unget non-identifier character */
1534 analyzeIdentifier (token);
1537 static void readPackageName (tokenInfo *const token, const int firstChar)
1539 vString *const name = token->name;
1540 int c = firstChar;
1542 initToken (token);
1544 while (isident (c) || c == '.')
1546 vStringPut (name, c);
1547 c = cppGetc ();
1549 vStringTerminate (name);
1550 cppUngetc (c); /* unget non-package character */
1553 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1555 st->declaration = declaration;
1557 if (declaration == DECL_NAMESPACE && !isLanguage (Lang_csharp))
1559 /* In C++ a namespace is specified one level at a time. */
1560 return;
1562 else
1564 /* In C#, a namespace can also be specified like a Java package name. */
1565 tokenInfo *const token = activeToken (st);
1566 Assert (isType (token, TOKEN_KEYWORD));
1567 readPackageName (token, skipToNonWhite ());
1568 token->type = TOKEN_NAME;
1569 st->gotName = TRUE;
1570 st->haveQualifyingName = TRUE;
1574 static void processName (statementInfo *const st)
1576 Assert (isType (activeToken (st), TOKEN_NAME));
1577 if (st->gotName && st->declaration == DECL_NONE)
1578 st->declaration = DECL_BASE;
1579 st->gotName = TRUE;
1580 st->haveQualifyingName = TRUE;
1583 static void readOperator (statementInfo *const st)
1585 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1586 const tokenInfo* const prev = prevToken (st,1);
1587 tokenInfo *const token = activeToken (st);
1588 vString *const name = token->name;
1589 int c = skipToNonWhite ();
1591 /* When we arrive here, we have the keyword "operator" in 'name'.
1593 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1594 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1595 ; /* ignore "operator" keyword if preceded by these keywords */
1596 else if (c == '(')
1598 /* Verify whether this is a valid function call (i.e. "()") operator.
1600 if (cppGetc () == ')')
1602 vStringPut (name, ' '); /* always separate operator from keyword */
1603 c = skipToNonWhite ();
1604 if (c == '(')
1605 vStringCatS (name, "()");
1607 else
1609 skipToMatch ("()");
1610 c = cppGetc ();
1613 else if (isident1 (c))
1615 /* Handle "new" and "delete" operators, and conversion functions
1616 * (per 13.3.1.1.2 [2] of the C++ spec).
1618 boolean whiteSpace = TRUE; /* default causes insertion of space */
1621 if (isspace (c))
1622 whiteSpace = TRUE;
1623 else
1625 if (whiteSpace)
1627 vStringPut (name, ' ');
1628 whiteSpace = FALSE;
1630 vStringPut (name, c);
1632 c = cppGetc ();
1633 } while (! isOneOf (c, "(;") && c != EOF);
1634 vStringTerminate (name);
1636 else if (isOneOf (c, acceptable))
1638 vStringPut (name, ' '); /* always separate operator from keyword */
1641 vStringPut (name, c);
1642 c = cppGetc ();
1643 } while (isOneOf (c, acceptable));
1644 vStringTerminate (name);
1647 cppUngetc (c);
1649 token->type = TOKEN_NAME;
1650 token->keyword = KEYWORD_NONE;
1651 processName (st);
1654 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1656 dest->type = src->type;
1657 dest->keyword = src->keyword;
1658 dest->filePosition = src->filePosition;
1659 dest->lineNumber = src->lineNumber;
1660 vStringCopy (dest->name, src->name);
1663 static void setAccess (statementInfo *const st, const accessType access)
1665 if (isMember (st))
1667 if (isLanguage (Lang_cpp))
1669 int c = skipToNonWhite ();
1671 if (c == ':')
1672 reinitStatement (st, FALSE);
1673 else
1674 cppUngetc (c);
1676 st->member.accessDefault = access;
1678 st->member.access = access;
1682 static void discardTypeList (tokenInfo *const token)
1684 int c = skipToNonWhite ();
1685 while (isident1 (c))
1687 readIdentifier (token, c);
1688 c = skipToNonWhite ();
1689 if (c == '.' || c == ',')
1690 c = skipToNonWhite ();
1692 cppUngetc (c);
1695 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1697 if (vStringLength (token->name) > 0 &&
1698 vStringLength (st->parentClasses) > 0)
1700 vStringPut (st->parentClasses, ',');
1702 vStringCat (st->parentClasses, token->name);
1705 static void readParents (statementInfo *const st, const int qualifier)
1707 tokenInfo *const token = newToken ();
1708 tokenInfo *const parent = newToken ();
1709 int c;
1713 c = skipToNonWhite ();
1714 if (isident1 (c))
1716 readIdentifier (token, c);
1717 if (isType (token, TOKEN_NAME))
1718 vStringCat (parent->name, token->name);
1719 else
1721 addParentClass (st, parent);
1722 initToken (parent);
1725 else if (c == qualifier)
1726 vStringPut (parent->name, c);
1727 else if (c == '<')
1728 skipToMatch ("<>");
1729 else if (isType (token, TOKEN_NAME))
1731 addParentClass (st, parent);
1732 initToken (parent);
1734 } while (c != '{' && c != EOF);
1735 cppUngetc (c);
1736 deleteToken (parent);
1737 deleteToken (token);
1740 static void skipStatement (statementInfo *const st)
1742 st->declaration = DECL_IGNORE;
1743 skipToOneOf (";");
1746 static void processInterface (statementInfo *const st)
1748 st->declaration = DECL_INTERFACE;
1751 static void checkIsClassEnum (statementInfo *const st, const declType decl)
1753 if (! isLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
1754 st->declaration = decl;
1757 static void processToken (tokenInfo *const token, statementInfo *const st)
1759 switch (token->keyword) /* is it a reserved word? */
1761 default: break;
1763 case KEYWORD_NONE: processName (st); break;
1764 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
1765 case KEYWORD_ATTRIBUTE:
1766 case KEYWORD_TYPENAME:
1767 case KEYWORD_INLINE: skipParens (); initToken (token); break;
1768 case KEYWORD_BIND: st->declaration = DECL_BASE; break;
1769 case KEYWORD_BIT: st->declaration = DECL_BASE; break;
1770 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
1771 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
1772 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
1773 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
1774 case KEYWORD_CONSTEXPR: st->declaration = DECL_BASE; break;
1775 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
1776 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
1777 case KEYWORD_EXTENDS: readParents (st, '.');
1778 setToken (st, TOKEN_NONE); break;
1779 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
1780 case KEYWORD_FUNCTION: st->declaration = DECL_BASE; break;
1781 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
1782 case KEYWORD_GOTO: skipStatement (st); break;
1783 case KEYWORD_IMPLEMENTS:readParents (st, '.');
1784 setToken (st, TOKEN_NONE); break;
1785 case KEYWORD_IMPORT: skipStatement (st); break;
1786 case KEYWORD_INT: st->declaration = DECL_BASE; break;
1787 case KEYWORD_INTEGER: st->declaration = DECL_BASE; break;
1788 case KEYWORD_INTERFACE: processInterface (st); break;
1789 case KEYWORD_LOCAL: setAccess (st, ACCESS_LOCAL); break;
1790 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
1791 case KEYWORD_OPERATOR: readOperator (st); break;
1792 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
1793 case KEYWORD_PROGRAM: st->declaration = DECL_PROGRAM; break;
1794 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
1795 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
1796 case KEYWORD_RETURN: skipStatement (st); break;
1797 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
1798 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
1799 case KEYWORD_STATIC_ASSERT: skipParens(); break;
1800 case KEYWORD_STRING: st->declaration = DECL_BASE; break;
1801 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
1802 case KEYWORD_TASK: st->declaration = DECL_TASK; break;
1803 case KEYWORD_THROWS: discardTypeList (token); break;
1804 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
1805 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
1806 case KEYWORD_USING: skipStatement (st); break;
1807 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
1808 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
1809 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
1810 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
1812 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
1813 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
1815 case KEYWORD_EVENT:
1816 if (isLanguage (Lang_csharp))
1817 st->declaration = DECL_EVENT;
1818 break;
1820 case KEYWORD_TYPEDEF:
1821 reinitStatement (st, FALSE);
1822 st->scope = SCOPE_TYPEDEF;
1823 break;
1825 case KEYWORD_EXTERN:
1826 if (! isLanguage (Lang_csharp) || !st->gotName)
1828 reinitStatement (st, FALSE);
1829 st->scope = SCOPE_EXTERN;
1830 st->declaration = DECL_BASE;
1832 break;
1834 case KEYWORD_STATIC:
1835 if (! (isLanguage (Lang_java) || isLanguage (Lang_csharp)))
1837 reinitStatement (st, FALSE);
1838 st->scope = SCOPE_STATIC;
1839 st->declaration = DECL_BASE;
1841 break;
1843 case KEYWORD_FOR:
1844 case KEYWORD_FOREACH:
1845 case KEYWORD_IF:
1846 case KEYWORD_SWITCH:
1847 case KEYWORD_WHILE:
1849 int c = skipToNonWhite ();
1850 if (c == '(')
1851 skipToMatch ("()");
1852 break;
1858 * Parenthesis handling functions
1861 static void restartStatement (statementInfo *const st)
1863 tokenInfo *const save = newToken ();
1864 tokenInfo *token = activeToken (st);
1866 copyToken (save, token);
1867 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
1868 reinitStatement (st, FALSE);
1869 token = activeToken (st);
1870 copyToken (token, save);
1871 deleteToken (save);
1872 processToken (token, st);
1875 /* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
1877 * mem-initializer-list:
1878 * mem-initializer, mem-initializer-list
1880 * mem-initializer:
1881 * [::] [nested-name-spec] class-name (...)
1882 * identifier
1884 static void skipMemIntializerList (tokenInfo *const token)
1886 int c;
1890 c = skipToNonWhite ();
1891 while (isident1 (c) || c == ':')
1893 if (c != ':')
1894 readIdentifier (token, c);
1895 c = skipToNonWhite ();
1897 if (c == '<')
1899 skipToMatch ("<>");
1900 c = skipToNonWhite ();
1902 if (c == '(')
1904 skipToMatch ("()");
1905 c = skipToNonWhite ();
1907 } while (c == ',');
1908 cppUngetc (c);
1911 static void skipMacro (statementInfo *const st)
1913 tokenInfo *const prev2 = prevToken (st, 2);
1915 if (isType (prev2, TOKEN_NAME))
1916 retardToken (st);
1917 skipToMatch ("()");
1920 /* Skips over characters following the parameter list. This will be either
1921 * non-ANSI style function declarations or C++ stuff. Our choices:
1923 * C (K&R):
1924 * int func ();
1925 * int func (one, two) int one; float two; {...}
1926 * C (ANSI):
1927 * int func (int one, float two);
1928 * int func (int one, float two) {...}
1929 * C++:
1930 * int foo (...) [const|volatile] [throw (...)];
1931 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
1932 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
1933 * catch (...) {...}
1935 static boolean skipPostArgumentStuff (
1936 statementInfo *const st, parenInfo *const info)
1938 tokenInfo *const token = activeToken (st);
1939 unsigned int parameters = info->parameterCount;
1940 unsigned int elementCount = 0;
1941 boolean restart = FALSE;
1942 boolean end = FALSE;
1943 int c = skipToNonWhite ();
1947 switch (c)
1949 case ')': break;
1950 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
1951 case '[': skipToMatch ("[]"); break;
1952 case '=': cppUngetc (c); end = TRUE; break;
1953 case '{': cppUngetc (c); end = TRUE; break;
1954 case '}': cppUngetc (c); end = TRUE; break;
1956 case '(':
1957 if (elementCount > 0)
1958 ++elementCount;
1959 skipToMatch ("()");
1960 break;
1962 case ';':
1963 if (parameters == 0 || elementCount < 2)
1965 cppUngetc (c);
1966 end = TRUE;
1968 else if (--parameters == 0)
1969 end = TRUE;
1970 break;
1972 default:
1973 if (isident1 (c))
1975 readIdentifier (token, c);
1976 switch (token->keyword)
1978 case KEYWORD_ATTRIBUTE: skipParens (); break;
1979 case KEYWORD_THROW: skipParens (); break;
1980 case KEYWORD_TRY: break;
1982 case KEYWORD_CONST:
1983 case KEYWORD_VOLATILE:
1984 if (vStringLength (Signature) > 0)
1986 vStringPut (Signature, ' ');
1987 vStringCat (Signature, token->name);
1989 break;
1991 case KEYWORD_CATCH:
1992 case KEYWORD_CLASS:
1993 case KEYWORD_EXPLICIT:
1994 case KEYWORD_EXTERN:
1995 case KEYWORD_FRIEND:
1996 case KEYWORD_INLINE:
1997 case KEYWORD_MUTABLE:
1998 case KEYWORD_NAMESPACE:
1999 case KEYWORD_NEW:
2000 case KEYWORD_NEWCOV:
2001 case KEYWORD_NOEXCEPT:
2002 case KEYWORD_OPERATOR:
2003 case KEYWORD_OVERLOAD:
2004 case KEYWORD_PRIVATE:
2005 case KEYWORD_PROTECTED:
2006 case KEYWORD_PUBLIC:
2007 case KEYWORD_STATIC:
2008 case KEYWORD_TEMPLATE:
2009 case KEYWORD_TYPEDEF:
2010 case KEYWORD_TYPENAME:
2011 case KEYWORD_USING:
2012 case KEYWORD_VIRTUAL:
2013 /* Never allowed within parameter declarations. */
2014 restart = TRUE;
2015 end = TRUE;
2016 break;
2018 default:
2019 /* "override" and "final" are only keywords in the declaration of a virtual
2020 * member function, so need to be handled specially, not as keywords */
2021 if (isLanguage(Lang_cpp) && isType (token, TOKEN_NAME) &&
2022 (strcmp ("override", vStringValue (token->name)) == 0 ||
2023 strcmp ("final", vStringValue (token->name)) == 0))
2025 else if (isType (token, TOKEN_NONE))
2027 else if (info->isKnrParamList && info->parameterCount > 0)
2028 ++elementCount;
2029 else
2031 /* If we encounter any other identifier immediately
2032 * following an empty parameter list, this is almost
2033 * certainly one of those Microsoft macro "thingies"
2034 * that the automatic source code generation sticks
2035 * in. Terminate the current statement.
2037 restart = TRUE;
2038 end = TRUE;
2040 break;
2044 if (! end)
2046 c = skipToNonWhite ();
2047 if (c == EOF)
2048 end = TRUE;
2050 } while (! end);
2052 if (restart)
2053 restartStatement (st);
2054 else
2055 setToken (st, TOKEN_NONE);
2057 return (boolean) (c != EOF);
2060 static void skipJavaThrows (statementInfo *const st)
2062 tokenInfo *const token = activeToken (st);
2063 int c = skipToNonWhite ();
2065 if (isident1 (c))
2067 readIdentifier (token, c);
2068 if (token->keyword == KEYWORD_THROWS)
2072 c = skipToNonWhite ();
2073 if (isident1 (c))
2075 readIdentifier (token, c);
2076 c = skipToNonWhite ();
2078 } while (c == '.' || c == ',');
2081 cppUngetc (c);
2082 setToken (st, TOKEN_NONE);
2085 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2087 const unsigned long inputLineNumber = getInputLineNumber ();
2088 int c = skipToNonWhite ();
2090 cppUngetc (c);
2091 if (isOneOf (c, "{;,="))
2093 else if (isLanguage (Lang_java))
2094 skipJavaThrows (st);
2095 else
2097 if (! skipPostArgumentStuff (st, info))
2099 verbose (
2100 "%s: confusing argument declarations beginning at line %lu\n",
2101 getInputFileName (), inputLineNumber);
2102 longjmp (Exception, (int) ExceptionFormattingError);
2107 static boolean languageSupportsGenerics (void)
2109 return (boolean) (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
2110 isLanguage (Lang_java));
2113 static void processAngleBracket (void)
2115 int c = cppGetc ();
2116 if (c == '>') {
2117 /* already found match for template */
2118 } else if (languageSupportsGenerics () && c != '<' && c != '=') {
2119 /* this is a template */
2120 cppUngetc (c);
2121 skipToMatch ("<>");
2122 } else if (c == '<') {
2123 /* skip "<<" or "<<=". */
2124 c = cppGetc ();
2125 if (c != '=') {
2126 cppUngetc (c);
2128 } else {
2129 cppUngetc (c);
2133 static void parseJavaAnnotation (statementInfo *const st)
2136 * @Override
2137 * @Target(ElementType.METHOD)
2138 * @SuppressWarnings(value = "unchecked")
2140 * But watch out for "@interface"!
2142 tokenInfo *const token = activeToken (st);
2144 int c = skipToNonWhite ();
2145 readIdentifier (token, c);
2146 if (token->keyword == KEYWORD_INTERFACE)
2148 /* Oops. This was actually "@interface" defining a new annotation. */
2149 processInterface (st);
2151 else
2153 /* Bug #1691412: skip any annotation arguments. */
2154 skipParens ();
2158 static void parseReturnType (statementInfo *const st)
2160 int i;
2161 int lower_bound;
2162 int upper_bound;
2163 tokenInfo * finding_tok;
2165 /* FIXME TODO: if java language must be supported then impement this here
2166 * removing the current FIXME */
2167 if (!isLanguage (Lang_c) && !isLanguage (Lang_cpp))
2169 return;
2172 vStringClear (ReturnType);
2174 finding_tok = prevToken (st, 1);
2176 if (isType (finding_tok, TOKEN_NONE))
2177 return;
2179 finding_tok = prevToken (st, 2);
2181 if (finding_tok->type == TOKEN_DOUBLE_COLON)
2183 /* get the total number of double colons */
2184 int j;
2185 int num_colons = 0;
2187 /* we already are at 2nd token */
2188 /* the +=2 means that colons are usually found at even places */
2189 for (j = 2; j < NumTokens; j+=2)
2191 tokenInfo *curr_tok;
2192 curr_tok = prevToken (st, j);
2193 if (curr_tok->type == TOKEN_DOUBLE_COLON)
2194 num_colons++;
2195 else
2196 break;
2199 /*printf ("FOUND colons %d\n", num_colons);*/
2200 lower_bound = 2 * num_colons + 1;
2202 else
2203 lower_bound = 1;
2205 upper_bound = -1;
2206 for (i = 0; i < NumTokens; i++) {
2207 tokenInfo *curr_tok;
2208 curr_tok = prevToken (st, i);
2209 if (curr_tok->type == TOKEN_BRACE_CLOSE || curr_tok->type == TOKEN_BRACE_OPEN) {
2210 upper_bound = i - 1;
2211 break;
2214 if (upper_bound < 0) {
2215 upper_bound = NumTokens - 1;
2218 for (i = upper_bound; i > lower_bound; i--)
2220 tokenInfo * curr_tok;
2221 curr_tok = prevToken (st, i);
2223 switch (curr_tok->type)
2225 case TOKEN_PAREN_NAME:
2226 case TOKEN_NONE:
2227 continue;
2228 break;
2230 case TOKEN_DOUBLE_COLON:
2231 /* usually C++ class scope */
2232 vStringCatS (ReturnType, "::");
2233 break;
2235 case TOKEN_STAR:
2236 /* pointers */
2237 vStringPut (ReturnType, '*');
2238 break;
2240 case TOKEN_AMPERSAND:
2241 /* references */
2242 vStringPut (ReturnType, '&');
2243 break;
2245 default:
2246 vStringCat (ReturnType, curr_tok->name);
2247 if (curr_tok->type == TOKEN_KEYWORD) {
2248 vStringPut (ReturnType, ' ');
2250 break;
2254 /* clear any white space from the front */
2255 vStringStripLeading (ReturnType);
2257 /* .. and from the tail too */
2258 vStringStripTrailing (ReturnType);
2260 /* put and end marker */
2261 vStringTerminate (ReturnType);
2264 printf ("~~~~~ statement ---->\n");
2265 ps (st);
2266 printf ("NumTokens: %d\n", NumTokens);
2267 printf ("FOUND ReturnType: %s\n", vStringValue (ReturnType));
2268 printf ("<~~~~~\n");
2269 //*/
2272 static int parseParens (statementInfo *const st, parenInfo *const info)
2274 tokenInfo *const token = activeToken (st);
2275 unsigned int identifierCount = 0;
2276 unsigned int depth = 1;
2277 boolean firstChar = TRUE;
2278 int nextChar = '\0';
2280 CollectingSignature = TRUE;
2281 vStringClear (Signature);
2282 vStringPut (Signature, '(');
2283 info->parameterCount = 1;
2286 int c = skipToNonWhite ();
2287 vStringPut (Signature, c);
2289 switch (c)
2291 case '&':
2292 case '*':
2293 info->isPointer = TRUE;
2294 info->isKnrParamList = FALSE;
2295 if (identifierCount == 0)
2296 info->isParamList = FALSE;
2297 initToken (token);
2298 break;
2300 case ':':
2301 info->isKnrParamList = FALSE;
2302 break;
2304 case '.':
2305 info->isNameCandidate = FALSE;
2306 c = cppGetc ();
2307 if (c != '.')
2309 cppUngetc (c);
2310 info->isKnrParamList = FALSE;
2312 else
2314 c = cppGetc ();
2315 if (c != '.')
2317 cppUngetc (c);
2318 info->isKnrParamList = FALSE;
2320 else
2321 vStringCatS (Signature, "..."); /* variable arg list */
2323 break;
2325 case ',':
2326 info->isNameCandidate = FALSE;
2327 if (info->isKnrParamList)
2329 ++info->parameterCount;
2330 identifierCount = 0;
2332 break;
2334 case '=':
2335 info->isKnrParamList = FALSE;
2336 info->isNameCandidate = FALSE;
2337 if (firstChar)
2339 info->isParamList = FALSE;
2340 skipMacro (st);
2341 depth = 0;
2343 break;
2345 case '[':
2346 info->isKnrParamList = FALSE;
2347 skipToMatch ("[]");
2348 break;
2350 case '<':
2351 info->isKnrParamList = FALSE;
2352 processAngleBracket ();
2353 break;
2355 case ')':
2356 if (firstChar)
2357 info->parameterCount = 0;
2358 --depth;
2359 break;
2361 case '(':
2362 info->isKnrParamList = FALSE;
2363 if (firstChar)
2365 info->isNameCandidate = FALSE;
2366 cppUngetc (c);
2367 vStringClear (Signature);
2368 skipMacro (st);
2369 depth = 0;
2370 vStringChop (Signature);
2372 else if (isType (token, TOKEN_PAREN_NAME))
2374 c = skipToNonWhite ();
2375 if (c == '*') /* check for function pointer */
2377 skipToMatch ("()");
2378 c = skipToNonWhite ();
2379 if (c == '(')
2380 skipToMatch ("()");
2381 else
2382 cppUngetc (c);
2384 else
2386 cppUngetc (c);
2387 cppUngetc ('(');
2388 info->nestedArgs = TRUE;
2391 else
2392 ++depth;
2393 break;
2395 default:
2396 if (c == '@' && isLanguage (Lang_java))
2398 parseJavaAnnotation(st);
2400 else if (isident1 (c))
2402 if (++identifierCount > 1)
2403 info->isKnrParamList = FALSE;
2404 readIdentifier (token, c);
2405 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2406 token->type = TOKEN_PAREN_NAME;
2407 else if (isType (token, TOKEN_KEYWORD))
2409 if (token->keyword != KEYWORD_CONST &&
2410 token->keyword != KEYWORD_VOLATILE)
2412 info->isKnrParamList = FALSE;
2413 info->isNameCandidate = FALSE;
2417 else
2419 info->isParamList = FALSE;
2420 info->isKnrParamList = FALSE;
2421 info->isNameCandidate = FALSE;
2422 info->invalidContents = TRUE;
2424 break;
2426 firstChar = FALSE;
2427 } while (! info->nestedArgs && depth > 0 &&
2428 (info->isKnrParamList || info->isNameCandidate));
2430 if (! info->nestedArgs) while (depth > 0)
2432 skipToMatch ("()");
2433 --depth;
2436 if (! info->isNameCandidate)
2437 initToken (token);
2439 vStringTerminate (Signature);
2440 if (info->isKnrParamList)
2441 vStringClear (Signature);
2442 CollectingSignature = FALSE;
2443 return nextChar;
2446 static void initParenInfo (parenInfo *const info)
2448 info->isPointer = FALSE;
2449 info->isParamList = TRUE;
2450 info->isKnrParamList = isLanguage (Lang_c);
2451 info->isNameCandidate = TRUE;
2452 info->invalidContents = FALSE;
2453 info->nestedArgs = FALSE;
2454 info->parameterCount = 0;
2457 static void analyzeParens (statementInfo *const st)
2459 tokenInfo *const prev = prevToken (st, 1);
2461 if (st->inFunction && ! st->assignment)
2462 st->notVariable = TRUE;
2463 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2465 tokenInfo *const token = activeToken (st);
2466 parenInfo info;
2467 int c;
2469 initParenInfo (&info);
2470 parseParens (st, &info);
2471 parseReturnType (st);
2472 c = skipToNonWhite ();
2473 cppUngetc (c);
2474 if (info.invalidContents)
2475 reinitStatement (st, FALSE);
2476 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2477 ! st->gotParenName &&
2478 (! info.isParamList || ! st->haveQualifyingName ||
2479 c == '(' ||
2480 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2481 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2483 token->type = TOKEN_NAME;
2484 processName (st);
2485 st->gotParenName = TRUE;
2486 if (! (c == '(' && info.nestedArgs))
2487 st->isPointer = info.isPointer;
2489 else if (! st->gotArgs && info.isParamList)
2491 st->gotArgs = TRUE;
2492 setToken (st, TOKEN_ARGS);
2493 advanceToken (st);
2494 if (st->scope != SCOPE_TYPEDEF)
2495 analyzePostParens (st, &info);
2497 else
2498 setToken (st, TOKEN_NONE);
2503 * Token parsing functions
2506 static void addContext (statementInfo *const st, const tokenInfo* const token)
2508 if (isType (token, TOKEN_NAME))
2510 if (vStringLength (st->context->name) > 0)
2512 if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
2513 vStringCatS (st->context->name, "::");
2514 else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
2515 vStringCatS (st->context->name, ".");
2517 vStringCat (st->context->name, token->name);
2518 st->context->type = TOKEN_NAME;
2522 static boolean inheritingDeclaration (declType decl)
2524 /* C# supports inheritance for enums. C++0x will too, but not yet. */
2525 if (decl == DECL_ENUM)
2527 return (boolean) (isLanguage (Lang_csharp));
2529 return (boolean) (
2530 decl == DECL_CLASS ||
2531 decl == DECL_STRUCT ||
2532 decl == DECL_INTERFACE);
2535 static void processColon (statementInfo *const st)
2537 int c = (isLanguage (Lang_cpp) ? cppGetc () : skipToNonWhite ());
2538 const boolean doubleColon = (boolean) (c == ':');
2540 if (doubleColon)
2542 setToken (st, TOKEN_DOUBLE_COLON);
2543 st->haveQualifyingName = FALSE;
2545 else
2547 cppUngetc (c);
2548 if ((isLanguage (Lang_cpp) || isLanguage (Lang_csharp)) &&
2549 inheritingDeclaration (st->declaration))
2551 readParents (st, ':');
2553 else if (parentDecl (st) == DECL_STRUCT)
2555 c = skipToOneOf (",;");
2556 if (c == ',')
2557 setToken (st, TOKEN_COMMA);
2558 else if (c == ';')
2559 setToken (st, TOKEN_SEMICOLON);
2561 else if (isLanguage (Lang_cpp) && st->declaration == DECL_ENUM)
2563 /* skip enum's base type */
2564 c = skipToOneOf ("{;");
2565 if (c == '{')
2566 setToken (st, TOKEN_BRACE_OPEN);
2567 else if (c == ';')
2568 setToken (st, TOKEN_SEMICOLON);
2570 else
2572 const tokenInfo *const prev = prevToken (st, 1);
2573 const tokenInfo *const prev2 = prevToken (st, 2);
2574 if (prev->keyword == KEYWORD_DEFAULT ||
2575 prev2->keyword == KEYWORD_CASE ||
2576 st->parent != NULL)
2578 reinitStatement (st, FALSE);
2584 /* Skips over any initializing value which may follow an '=' character in a
2585 * variable definition.
2587 static int skipInitializer (statementInfo *const st)
2589 boolean done = FALSE;
2590 int c;
2592 while (! done)
2594 c = skipToNonWhite ();
2596 if (c == EOF)
2597 longjmp (Exception, (int) ExceptionFormattingError);
2598 else switch (c)
2600 case ',':
2601 case ';': done = TRUE; break;
2603 case '0':
2604 if (st->implementation == IMP_VIRTUAL)
2605 st->implementation = IMP_PURE_VIRTUAL;
2606 break;
2608 case '[': skipToMatch ("[]"); break;
2609 case '(': skipToMatch ("()"); break;
2610 case '{': skipToMatch ("{}"); break;
2611 case '<': processAngleBracket(); break;
2613 case '}':
2614 if (insideEnumBody (st))
2615 done = TRUE;
2616 else if (! isBraceFormat ())
2618 verbose ("%s: unexpected closing brace at line %lu\n",
2619 getInputFileName (), getInputLineNumber ());
2620 longjmp (Exception, (int) ExceptionBraceFormattingError);
2622 break;
2624 default: break;
2627 return c;
2630 static void processInitializer (statementInfo *const st)
2632 const boolean inEnumBody = insideEnumBody (st);
2633 int c = cppGetc ();
2635 if (c != '=')
2637 cppUngetc (c);
2638 c = skipInitializer (st);
2639 st->assignment = TRUE;
2640 if (c == ';')
2641 setToken (st, TOKEN_SEMICOLON);
2642 else if (c == ',')
2643 setToken (st, TOKEN_COMMA);
2644 else if (c == '}' && inEnumBody)
2646 cppUngetc (c);
2647 setToken (st, TOKEN_COMMA);
2649 if (st->scope == SCOPE_EXTERN)
2650 st->scope = SCOPE_GLOBAL;
2654 static void parseIdentifier (statementInfo *const st, const int c)
2656 tokenInfo *const token = activeToken (st);
2658 readIdentifier (token, c);
2659 if (! isType (token, TOKEN_NONE))
2660 processToken (token, st);
2663 static void parseGeneralToken (statementInfo *const st, const int c)
2665 const tokenInfo *const prev = prevToken (st, 1);
2667 if (isident1 (c) || (isLanguage (Lang_java) && isHighChar (c)))
2669 parseIdentifier (st, c);
2670 if (isType (st->context, TOKEN_NAME) &&
2671 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2673 initToken (st->context);
2676 else if (c == '.' || c == '-')
2678 if (! st->assignment)
2679 st->notVariable = TRUE;
2680 if (c == '-')
2682 int c2 = cppGetc ();
2683 if (c2 != '>')
2684 cppUngetc (c2);
2687 else if (c == '!' || c == '>')
2689 int c2 = cppGetc ();
2690 if (c2 != '=')
2691 cppUngetc (c2);
2693 else if (c == '@' && isLanguage (Lang_java))
2695 parseJavaAnnotation (st);
2697 else if (isExternCDecl (st, c))
2699 st->declaration = DECL_NOMANGLE;
2700 st->scope = SCOPE_GLOBAL;
2704 /* Reads characters from the pre-processor and assembles tokens, setting
2705 * the current statement state.
2707 static void nextToken (statementInfo *const st)
2709 tokenInfo *token;
2712 int c = skipToNonWhite ();
2713 switch (c)
2715 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2716 /* analyze functions and co */
2717 case '(': analyzeParens (st); break;
2718 case '<': processAngleBracket (); break;
2719 case '*':
2720 st->haveQualifyingName = FALSE;
2721 setToken (st, TOKEN_STAR);
2722 break;
2723 case '&': setToken (st, TOKEN_AMPERSAND); break;
2725 case ',': setToken (st, TOKEN_COMMA); break;
2726 case ':': processColon (st); break;
2727 case ';': setToken (st, TOKEN_SEMICOLON); break;
2728 case '=': processInitializer (st); break;
2729 case '[': skipToMatch ("[]"); break;
2730 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2731 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2732 default: parseGeneralToken (st, c); break;
2734 token = activeToken (st);
2735 } while (isType (token, TOKEN_NONE));
2739 * Scanning support functions
2742 static statementInfo *CurrentStatement = NULL;
2744 static statementInfo *newStatement (statementInfo *const parent)
2746 statementInfo *const st = xMalloc (1, statementInfo);
2747 unsigned int i;
2749 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2750 st->token [i] = newToken ();
2752 st->context = newToken ();
2753 st->blockName = newToken ();
2754 st->parentClasses = vStringNew ();
2756 initStatement (st, parent);
2757 CurrentStatement = st;
2759 return st;
2762 static void deleteStatement (void)
2764 statementInfo *const st = CurrentStatement;
2765 statementInfo *const parent = st->parent;
2766 unsigned int i;
2768 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2770 deleteToken (st->token [i]); st->token [i] = NULL;
2772 deleteToken (st->blockName); st->blockName = NULL;
2773 deleteToken (st->context); st->context = NULL;
2774 vStringDelete (st->parentClasses); st->parentClasses = NULL;
2775 eFree (st);
2776 CurrentStatement = parent;
2779 static void deleteAllStatements (void)
2781 while (CurrentStatement != NULL)
2782 deleteStatement ();
2785 static boolean isStatementEnd (const statementInfo *const st)
2787 const tokenInfo *const token = activeToken (st);
2788 boolean isEnd;
2790 if (isType (token, TOKEN_SEMICOLON))
2791 isEnd = TRUE;
2792 else if (isType (token, TOKEN_BRACE_CLOSE))
2793 /* Java and C# do not require semicolons to end a block. Neither do C++
2794 * namespaces. All other blocks require a semicolon to terminate them.
2796 isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_csharp) ||
2797 ! isContextualStatement (st));
2798 else
2799 isEnd = FALSE;
2801 return isEnd;
2804 static void checkStatementEnd (statementInfo *const st)
2806 const tokenInfo *const token = activeToken (st);
2808 if (isType (token, TOKEN_COMMA))
2809 reinitStatement (st, TRUE);
2810 else if (isStatementEnd (st))
2812 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2813 reinitStatement (st, FALSE);
2814 cppEndStatement ();
2816 else
2818 cppBeginStatement ();
2819 advanceToken (st);
2823 static void nest (statementInfo *const st, const unsigned int nestLevel)
2825 switch (st->declaration)
2827 case DECL_CLASS:
2828 case DECL_ENUM:
2829 case DECL_INTERFACE:
2830 case DECL_NAMESPACE:
2831 case DECL_NOMANGLE:
2832 case DECL_STRUCT:
2833 case DECL_UNION:
2834 createTags (nestLevel, st);
2835 break;
2837 case DECL_FUNCTION:
2838 case DECL_TASK:
2839 st->inFunction = TRUE;
2841 /* fall through */
2842 default:
2843 if (includeTag (TAG_LOCAL, FALSE))
2844 createTags (nestLevel, st);
2845 else
2846 skipToMatch ("{}");
2847 break;
2849 advanceToken (st);
2850 setToken (st, TOKEN_BRACE_CLOSE);
2853 static void tagCheck (statementInfo *const st)
2855 const tokenInfo *const token = activeToken (st);
2856 const tokenInfo *const prev = prevToken (st, 1);
2857 const tokenInfo *const prev2 = prevToken (st, 2);
2859 switch (token->type)
2861 case TOKEN_NAME:
2862 if (insideEnumBody (st))
2863 qualifyEnumeratorTag (st, token);
2864 break;
2865 #if 0
2866 case TOKEN_PACKAGE:
2867 if (st->haveQualifyingName)
2868 makeTag (token, st, FALSE, TAG_PACKAGE);
2869 break;
2870 #endif
2871 case TOKEN_BRACE_OPEN:
2872 if (isType (prev, TOKEN_ARGS))
2874 if (st->haveQualifyingName)
2876 if (! isLanguage (Lang_vera))
2877 st->declaration = DECL_FUNCTION;
2878 if (isType (prev2, TOKEN_NAME))
2879 copyToken (st->blockName, prev2);
2880 qualifyFunctionTag (st, prev2);
2883 else if (isContextualStatement (st) ||
2884 st->declaration == DECL_NAMESPACE ||
2885 st->declaration == DECL_PROGRAM)
2887 tokenInfo *name_token = (tokenInfo *)prev;
2889 /* C++ 11 allows class <name> final { ... } */
2890 if (isLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) &&
2891 strcmp("final", vStringValue(prev->name)) == 0 &&
2892 isType(prev2, TOKEN_NAME))
2894 name_token = (tokenInfo *)prev2;
2895 copyToken (st->blockName, name_token);
2897 else if (isType (name_token, TOKEN_NAME))
2899 copyToken (st->blockName, prev);
2901 else
2903 /* For an anonymous struct or union we use a unique ID
2904 * a number, so that the members can be found.
2906 char buf [20]; /* length of "_anon" + digits + null */
2907 sprintf (buf, "__anon%d", ++AnonymousID);
2908 vStringCopyS (st->blockName->name, buf);
2909 st->blockName->type = TOKEN_NAME;
2910 st->blockName->keyword = KEYWORD_NONE;
2912 qualifyBlockTag (st, prev);
2914 else if (isLanguage (Lang_csharp))
2915 makeTag (prev, st, FALSE, TAG_PROPERTY);
2916 break;
2918 case TOKEN_SEMICOLON:
2919 case TOKEN_COMMA:
2920 if (insideEnumBody (st))
2922 else if (isType (prev, TOKEN_NAME))
2924 if (isContextualKeyword (prev2))
2925 makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
2926 else
2927 qualifyVariableTag (st, prev);
2929 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
2931 if (st->isPointer)
2932 qualifyVariableTag (st, prev2);
2933 else
2934 qualifyFunctionDeclTag (st, prev2);
2936 if (isLanguage (Lang_java) && token->type == TOKEN_SEMICOLON && insideEnumBody (st))
2938 /* In Java, after an initial enum-like part,
2939 * a semicolon introduces a class-like part.
2940 * See Bug #1730485 for the full rationale. */
2941 st->parent->declaration = DECL_CLASS;
2943 break;
2945 default: break;
2949 /* Parses the current file and decides whether to write out and tags that
2950 * are discovered.
2952 static void createTags (const unsigned int nestLevel,
2953 statementInfo *const parent)
2955 statementInfo *const st = newStatement (parent);
2957 DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
2958 while (TRUE)
2960 tokenInfo *token;
2962 nextToken (st);
2963 token = activeToken (st);
2965 if (isType (token, TOKEN_BRACE_CLOSE))
2967 if (nestLevel > 0)
2968 break;
2969 else
2971 verbose ("%s: unexpected closing brace at line %lu\n",
2972 getInputFileName (), getInputLineNumber ());
2973 longjmp (Exception, (int) ExceptionBraceFormattingError);
2976 else if (isType (token, TOKEN_DOUBLE_COLON))
2978 addContext (st, prevToken (st, 1));
2979 advanceToken (st);
2981 else
2983 tagCheck (st);
2984 if (isType (token, TOKEN_BRACE_OPEN))
2985 nest (st, nestLevel + 1);
2986 checkStatementEnd (st);
2989 deleteStatement ();
2990 DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
2993 static boolean findCTags (const unsigned int passCount)
2995 exception_t exception;
2996 boolean retry;
2998 Assert (passCount < 3);
2999 cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
3000 Signature = vStringNew ();
3001 ReturnType = vStringNew ();
3003 exception = (exception_t) setjmp (Exception);
3004 retry = FALSE;
3005 if (exception == ExceptionNone)
3006 createTags (0, NULL);
3007 else
3009 deleteAllStatements ();
3010 if (exception == ExceptionBraceFormattingError && passCount == 1)
3012 retry = TRUE;
3013 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3014 getInputFileName ());
3017 vStringDelete (Signature);
3018 vStringDelete (ReturnType);
3019 cppTerminate ();
3020 return retry;
3023 static void buildKeywordHash (const langType language, unsigned int idx)
3025 const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
3026 size_t i;
3027 for (i = 0 ; i < count ; ++i)
3029 const keywordDesc* const p = &KeywordTable [i];
3030 if (p->isValid [idx])
3031 addKeyword (p->name, language, (int) p->id);
3035 static void initializeCParser (const langType language)
3037 Lang_c = language;
3038 buildKeywordHash (language, 0);
3041 static void initializeCppParser (const langType language)
3043 Lang_cpp = language;
3044 buildKeywordHash (language, 1);
3047 static void initializeCsharpParser (const langType language)
3049 Lang_csharp = language;
3050 buildKeywordHash (language, 2);
3053 static void initializeJavaParser (const langType language)
3055 Lang_java = language;
3056 buildKeywordHash (language, 3);
3059 static void initializeVeraParser (const langType language)
3061 Lang_vera = language;
3062 buildKeywordHash (language, 4);
3065 extern parserDefinition* CParser (void)
3067 static const char *const extensions [] = { "c", NULL };
3068 parserDefinition* def = parserNew ("C");
3069 def->kinds = CKinds;
3070 def->kindCount = KIND_COUNT (CKinds);
3071 def->extensions = extensions;
3072 def->parser2 = findCTags;
3073 def->initialize = initializeCParser;
3074 return def;
3077 extern parserDefinition* CppParser (void)
3079 static const char *const extensions [] = {
3080 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3081 #ifndef CASE_INSENSITIVE_FILENAMES
3082 "C", "H",
3083 #endif
3084 NULL
3086 parserDefinition* def = parserNew ("C++");
3087 def->kinds = CKinds;
3088 def->kindCount = KIND_COUNT (CKinds);
3089 def->extensions = extensions;
3090 def->parser2 = findCTags;
3091 def->initialize = initializeCppParser;
3092 return def;
3095 extern parserDefinition* CsharpParser (void)
3097 static const char *const extensions [] = { "cs", NULL };
3098 parserDefinition* def = parserNew ("C#");
3099 def->kinds = CsharpKinds;
3100 def->kindCount = KIND_COUNT (CsharpKinds);
3101 def->extensions = extensions;
3102 def->parser2 = findCTags;
3103 def->initialize = initializeCsharpParser;
3104 return def;
3107 extern parserDefinition* JavaParser (void)
3109 static const char *const extensions [] = { "java", NULL };
3110 parserDefinition* def = parserNew ("Java");
3111 def->kinds = JavaKinds;
3112 def->kindCount = KIND_COUNT (JavaKinds);
3113 def->extensions = extensions;
3114 def->parser2 = findCTags;
3115 def->initialize = initializeJavaParser;
3116 return def;
3119 extern parserDefinition* VeraParser (void)
3121 static const char *const extensions [] = { "vr", "vri", "vrh", NULL };
3122 parserDefinition* def = parserNew ("Vera");
3123 def->kinds = VeraKinds;
3124 def->kindCount = KIND_COUNT (VeraKinds);
3125 def->extensions = extensions;
3126 def->parser2 = findCTags;
3127 def->initialize = initializeVeraParser;
3128 return def;
3131 /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */