Replace utils_make_human_readable_str() with g_format_size()
[geany-mirror.git] / ctags / parsers / geany_c.c
blobd9ad0b0c915f4cba0007d3ae751af56210e66a38
1 /*
2 * Copyright (c) 1996-2003, Darren Hiebert
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.
7 * This module contains functions for parsing and scanning C, C++, C#, D and Java
8 * source files.
9 */
12 * INCLUDE FILES
14 #include "general.h" /* must always come first */
16 #include <string.h>
17 #include <setjmp.h>
19 #include "debug.h"
20 #include "mio.h"
21 #include "entry.h"
22 #include "geany_lcpp.h"
23 #include "keyword.h"
24 #include "options.h"
25 #include "parse.h"
26 #include "read.h"
27 #include "routines.h"
28 #include "xtag.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) (bool) ((token)->type == (t))
38 #define insideEnumBody(st) (bool) ((st)->parent == NULL ? false : \
39 ((st)->parent->declaration == DECL_ENUM))
40 #define isExternCDecl(st,c) (bool) ((c) == STRING_SYMBOL && \
41 ! (st)->haveQualifyingName && \
42 (st)->scope == SCOPE_EXTERN)
44 #define isOneOf(c,s) (bool) (strchr ((s), (c)) != NULL)
47 * DATA DECLARATIONS
50 enum { NumTokens = 12 };
52 typedef enum eException
54 ExceptionNone, ExceptionEOF, ExceptionFormattingError,
55 ExceptionBraceFormattingError
56 } exception_t;
58 /* Used to specify type of keyword.
60 enum eKeywordId
62 KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ALIAS,
63 KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
64 KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BODY,
65 KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
66 KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
67 KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
68 KEYWORD_DOUBLE,
69 KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
70 KEYWORD_EXTENDS, KEYWORD_EVENT,
71 KEYWORD_FINAL, KEYWORD_FINALLY, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION,
72 KEYWORD_GET, KEYWORD_GOTO,
73 KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_IN, KEYWORD_INLINE, KEYWORD_INT,
74 KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
75 KEYWORD_INTERNAL,
76 KEYWORD_LOCAL, KEYWORD_LONG,
77 KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
78 KEYWORD_MODULE, KEYWORD_MUTABLE,
79 KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, KEYWORD_NOEXCEPT,
80 KEYWORD_OPERATOR, KEYWORD_OUT, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
81 KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
82 KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
83 KEYWORD_REF, KEYWORD_REGISTER, KEYWORD_RETURN,
84 KEYWORD_SHADOW, KEYWORD_STATE,
85 KEYWORD_SET, KEYWORD_SHORT, KEYWORD_SIGNAL, KEYWORD_SIGNED, KEYWORD_SIZE_T, KEYWORD_STATIC,
86 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_WEAK, KEYWORD_WHILE
96 typedef int keywordId; /* to allow KEYWORD_NONE */
98 /* Used to determine whether keyword is valid for the current language and
99 * what its ID is.
101 typedef struct sKeywordDesc
103 const char *name;
104 keywordId id;
105 short isValid [7]; /* indicates languages for which kw is valid */
106 } keywordDesc;
108 /* Used for reporting the type of object parsed by nextToken ().
110 typedef enum eTokenType
112 TOKEN_NONE, /* none */
113 TOKEN_ARGS, /* a parenthetical pair and its contents */
114 TOKEN_BRACE_CLOSE,
115 TOKEN_BRACE_OPEN,
116 TOKEN_COMMA, /* the comma character */
117 TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
118 TOKEN_KEYWORD,
119 TOKEN_NAME, /* an unknown name */
120 TOKEN_PACKAGE, /* a Java package name */
121 TOKEN_PAREN_NAME, /* a single name in parentheses */
122 TOKEN_SEMICOLON, /* the semicolon character */
123 TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
124 TOKEN_STAR, /* pointer detection */
125 TOKEN_ARRAY, /* array detection */
126 TOKEN_COUNT
127 } tokenType;
129 /* This describes the scoping of the current statement.
131 typedef enum eTagScope
133 SCOPE_GLOBAL, /* no storage class specified */
134 SCOPE_STATIC, /* static storage class */
135 SCOPE_EXTERN, /* external storage class */
136 SCOPE_FRIEND, /* declares access only */
137 SCOPE_TYPEDEF, /* scoping depends upon context */
138 SCOPE_COUNT
139 } tagScope;
141 typedef enum eDeclaration
143 DECL_NONE,
144 DECL_BASE, /* base type (default) */
145 DECL_CLASS,
146 DECL_ENUM,
147 DECL_EVENT,
148 DECL_SIGNAL,
149 DECL_FUNCTION,
150 DECL_FUNCTION_TEMPLATE,
151 DECL_IGNORE, /* non-taggable "declaration" */
152 DECL_INTERFACE,
153 DECL_MODULE,
154 DECL_NAMESPACE,
155 DECL_NOMANGLE, /* C++ name demangling block */
156 DECL_PACKAGE,
157 DECL_STRUCT,
158 DECL_UNION,
159 DECL_COUNT
160 } declType;
162 typedef enum eVisibilityType
164 ACCESS_UNDEFINED,
165 ACCESS_PRIVATE,
166 ACCESS_PROTECTED,
167 ACCESS_PUBLIC,
168 ACCESS_DEFAULT, /* Java-specific */
169 ACCESS_COUNT
170 } accessType;
172 /* Information about the parent class of a member (if any).
174 typedef struct sMemberInfo
176 accessType access; /* access of current statement */
177 accessType accessDefault; /* access default for current statement */
178 } memberInfo;
180 typedef struct sTokenInfo
182 tokenType type;
183 keywordId keyword;
184 vString* name; /* the name of the token */
185 unsigned long lineNumber; /* line number of tag */
186 MIOPos filePosition; /* file position of line containing name */
187 } tokenInfo;
189 typedef enum eImplementation
191 IMP_DEFAULT,
192 IMP_ABSTRACT,
193 IMP_VIRTUAL,
194 IMP_PURE_VIRTUAL,
195 IMP_COUNT
196 } impType;
198 /* Describes the statement currently undergoing analysis.
200 typedef struct sStatementInfo
202 tagScope scope;
203 declType declaration; /* specifier associated with TOKEN_SPEC */
204 bool gotName; /* was a name parsed yet? */
205 bool haveQualifyingName; /* do we have a name we are considering? */
206 bool gotParenName; /* was a name inside parentheses parsed yet? */
207 bool gotArgs; /* was a list of parameters parsed yet? */
208 unsigned int nSemicolons; /* how many semicolons did we see in that statement */
209 impType implementation; /* abstract or concrete implementation? */
210 unsigned int tokenIndex; /* currently active token */
211 tokenInfo* token [((int) NumTokens)];
212 tokenInfo* context; /* accumulated scope of current statement */
213 tokenInfo* blockName; /* name of current block */
214 memberInfo member; /* information regarding parent class/struct */
215 vString* parentClasses; /* parent classes */
216 struct sStatementInfo *parent; /* statement we are nested within */
217 tokenInfo* firstToken; /* First token in the statement */
218 } statementInfo;
220 /* Describes the type of tag being generated.
222 typedef enum eTagType
224 TAG_UNDEFINED,
225 TAG_CLASS, /* class name */
226 TAG_ENUM, /* enumeration name */
227 TAG_ENUMERATOR, /* enumerator (enumeration value) */
228 TAG_FIELD, /* field (Java) */
229 TAG_FUNCTION, /* function definition */
230 TAG_INTERFACE, /* interface declaration */
231 TAG_MEMBER, /* structure, class or interface member */
232 TAG_METHOD, /* method declaration */
233 TAG_NAMESPACE, /* namespace name */
234 TAG_PACKAGE, /* package name / D module name */
235 TAG_PROTOTYPE, /* function prototype or declaration */
236 TAG_STRUCT, /* structure name */
237 TAG_TYPEDEF, /* typedef name */
238 TAG_UNION, /* union name */
239 TAG_VARIABLE, /* variable definition */
240 TAG_EXTERN_VAR, /* external variable declaration */
241 TAG_MACRO, /* #define s */
242 TAG_EVENT, /* event */
243 TAG_SIGNAL, /* signal */
244 TAG_LOCAL, /* local variable definition */
245 TAG_PROPERTY, /* property name */
246 TAG_COUNT /* must be last */
247 } tagType;
249 typedef struct sParenInfo
251 bool isParamList;
252 bool isKnrParamList;
253 bool isNameCandidate;
254 bool invalidContents;
255 bool nestedArgs;
256 unsigned int parameterCount;
257 } parenInfo;
260 * DATA DEFINITIONS
263 static jmp_buf Exception;
265 static langType Lang_c;
266 static langType Lang_cpp;
267 static langType Lang_csharp;
268 static langType Lang_java;
269 static langType Lang_d;
270 static langType Lang_vala;
272 /* Used to index into the CKinds table. */
273 typedef enum
275 CK_UNDEFINED = -1,
276 CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
277 CK_ENUMERATION, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
278 CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
279 CK_EXTERN_VARIABLE
280 } cKind;
282 static kindDefinition CKinds [] = {
283 { true, 'c', "class", "classes"},
284 { true, 'd', "macro", "macro definitions"},
285 { true, 'e', "enumerator", "enumerators (values inside an enumeration)"},
286 { true, 'f', "function", "function definitions"},
287 { true, 'g', "enum", "enumeration names"},
288 { true, 'm', "member", "class, struct, and union members"},
289 { true, 'n', "namespace", "namespaces"},
290 { false, 'p', "prototype", "function prototypes"},
291 { true, 's', "struct", "structure names"},
292 { true, 't', "typedef", "typedefs"},
293 { true, 'u', "union", "union names"},
294 { true, 'v', "variable", "variable definitions"},
295 { false, 'x', "externvar", "external variable declarations"},
298 /* Used to index into the DKinds table. */
299 typedef enum
301 DK_UNDEFINED = -1,
302 DK_CLASS, DK_ENUMERATOR, DK_FUNCTION,
303 DK_ENUMERATION, DK_INTERFACE, DK_MEMBER, DK_NAMESPACE, DK_PROTOTYPE,
304 DK_STRUCT, DK_TYPEDEF, DK_UNION, DK_VARIABLE,
305 DK_EXTERN_VARIABLE
306 } dKind;
308 static kindDefinition DKinds [] = {
309 { true, 'c', "class", "classes"},
310 { true, 'e', "enumerator", "enumerators (values inside an enumeration)"},
311 { true, 'f', "function", "function definitions"},
312 { true, 'g', "enum", "enumeration names"},
313 { true, 'i', "interface", "interfaces"},
314 { true, 'm', "member", "class, struct, and union members"},
315 { true, 'n', "namespace", "namespaces"},
316 { false, 'p', "prototype", "function prototypes"},
317 { true, 's', "struct", "structure names"},
318 { true, 't', "typedef", "typedefs"},
319 { true, 'u', "union", "union names"},
320 { true, 'v', "variable", "variable definitions"},
321 { false, 'x', "externvar", "external variable declarations"},
324 /* Used to index into the JavaKinds table. */
325 typedef enum
327 JK_UNDEFINED = -1,
328 JK_CLASS, JK_FIELD, JK_INTERFACE, JK_METHOD,
329 JK_PACKAGE, JK_ENUMERATOR, JK_ENUMERATION
330 } javaKind;
332 static kindDefinition JavaKinds [] = {
333 { true, 'c', "class", "classes"},
334 { true, 'f', "field", "fields"},
335 { true, 'i', "interface", "interfaces"},
336 { true, 'm', "method", "methods"},
337 { true, 'p', "package", "packages"},
338 { true, 'e', "enumConstant", "enum constants"},
339 { true, 'g', "enum", "enum types"},
342 typedef enum
344 CSK_UNDEFINED = -1,
345 CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
346 CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
347 CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
348 } csharpKind;
350 static kindDefinition CsharpKinds [] = {
351 { true, 'c', "class", "classes"},
352 { true, 'd', "macro", "macro definitions"},
353 { true, 'e', "enumerator", "enumerators (values inside an enumeration)"},
354 { true, 'E', "event", "events"},
355 { true, 'f', "field", "fields"},
356 { true, 'g', "enum", "enumeration names"},
357 { true, 'i', "interface", "interfaces"},
358 { false, 'l', "local", "local variables"},
359 { true, 'm', "method", "methods"},
360 { true, 'n', "namespace", "namespaces"},
361 { true, 'p', "property", "properties"},
362 { true, 's', "struct", "structure names"},
363 { true, 't', "typedef", "typedefs"},
366 typedef enum {
367 VK_UNDEFINED = -1,
368 VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FIELD,
369 VK_ENUMERATION, VK_INTERFACE, VK_LOCAL, VK_METHOD,
370 VK_NAMESPACE, VK_PROPERTY, VK_SIGNAL, VK_STRUCT
371 } valaKind;
373 static kindDefinition ValaKinds [] = {
374 { true, 'c', "class", "classes"},
375 { true, 'd', "macro", "macro definitions"},
376 { true, 'e', "enumerator", "enumerators (values inside an enumeration)"},
377 { true, 'f', "field", "fields"},
378 { true, 'g', "enum", "enumeration names"},
379 { true, 'i', "interface", "interfaces"},
380 { false, 'l', "local", "local variables"},
381 { true, 'm', "method", "methods"},
382 { true, 'n', "namespace", "namespaces"},
383 { true, 'p', "property", "properties"},
384 { true, 'S', "signal", "signals"},
385 { true, 's', "struct", "structure names"},
388 /* Note: some keyword aliases are added in initializeDParser, initializeValaParser */
389 static const keywordDesc KeywordTable [] = {
390 /* C++ */
391 /* ANSI C | C# Java */
392 /* | | | | Vera */
393 /* | | | | | Vala */
394 /* | | | | | | D */
395 /* keyword keyword ID | | | | | | | */
396 { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0, 1 } },
397 { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 1, 1 } },
398 { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
399 { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
400 { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0, 0 } },
401 { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0, 0 } },
402 { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0, 0 } },
403 { "body", KEYWORD_BODY, { 0, 0, 0, 0, 0, 0, 1 } },
404 { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 0, 0 } },
405 { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0, 1 } },
406 { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 1, 1 } },
407 { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 1, 1 } },
408 { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 1, 1 } },
409 { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 1, 1 } },
410 { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 1, 1 } },
411 { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0, 0 } },
412 { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0, 0 } },
413 { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0, 0 } },
414 { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1, 1 } },
415 { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 1, 1 } },
416 { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 1, 1 } },
417 { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 1, 1 } },
418 { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 1, 1 } },
419 { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1, 1 } },
420 { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1, 1 } },
421 { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0, 0 } },
422 { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0, 1 } },
423 { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0, 0 } },
424 { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 1, 0 } },
425 { "extern", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
426 { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 0, 1 } },
427 { "finally", KEYWORD_FINALLY, { 0, 0, 0, 0, 0, 1, 1 } },
428 { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1, 1 } },
429 { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 1, 1 } },
430 { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0, 0 } },
431 { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0, 1 } },
432 { "get", KEYWORD_GET, { 0, 0, 0, 0, 0, 1, 0 } },
433 { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 1, 1 } },
434 { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1, 1 } },
435 { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0, 0 } },
436 { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 0, 1 } },
437 { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 1, 0 } },
438 { "in", KEYWORD_IN, { 0, 0, 0, 0, 0, 0, 1 } },
439 { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0, 0 } },
440 { "inout", KEYWORD_CONST, { 0, 0, 0, 0, 0, 0, 1 } }, /* treat like const */
441 { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0, 0 } },
442 { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 1, 1 } },
443 { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 0, 0 } },
444 { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 1, 1 } },
445 { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0, 0 } },
446 { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0, 0 } },
447 { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 1, 1 } },
448 { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
449 { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
450 { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
451 { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
452 { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0, 0 } },
453 { "module", KEYWORD_MODULE, { 0, 0, 0, 0, 0, 0, 1 } },
454 { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 1, 0 } },
455 { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0, 0 } },
456 { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 1, 1 } },
457 { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0, 0 } },
458 { "noexcept", KEYWORD_NOEXCEPT, { 0, 1, 0, 0, 0, 0, 0 } },
459 { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0, 0 } },
460 { "out", KEYWORD_OUT, { 0, 0, 0, 0, 0, 1, 1 } },
461 { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0, 0 } },
462 { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0, 0 } },
463 { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 1, 1 } },
464 { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0, 1 } },
465 { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0, 0 } },
466 { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0, 0 } },
467 { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 1, 1 } },
468 { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0, 0 } },
469 { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 1, 1 } },
470 { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 1, 1 } },
471 { "ref", KEYWORD_REF, { 0, 0, 0, 0, 0, 1, 1 } },
472 { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0, 0 } },
473 { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1, 1 } },
474 { "set", KEYWORD_SET, { 0, 0, 0, 0, 0, 1, 0 } },
475 { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0, 0 } },
476 { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 1, 1 } },
477 { "signal", KEYWORD_SIGNAL, { 0, 0, 0, 0, 0, 1, 0 } },
478 { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0, 0 } },
479 { "size_t", KEYWORD_SIZE_T, { 0, 0, 0, 0, 0, 1, 0 } },
480 { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0, 0 } },
481 { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 1, 1 } },
482 { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0, 0, 0 } },
483 { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1, 0 } },
484 { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 1, 1 } },
485 { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 1, 1 } },
486 { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0, 1 } },
487 { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0, 0 } },
488 { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0, 0 } },
489 { "template", KEYWORD_NAMESPACE, { 0, 0, 0, 0, 0, 0, 1 } }, /* parse block */
490 { "this", KEYWORD_THIS, { 0, 0, 1, 1, 0, 1, 0 } }, /* 0 to allow D ctor tags */
491 { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 1, 1 } },
492 { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 1, 0 } },
493 { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0, 0 } },
494 { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0, 0 } },
495 { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0, 0 } },
496 { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 1, 1 } },
497 { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0, 1 } },
498 { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0, 0 } },
499 { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 1, 1 } },
500 { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 1, 1 } },
501 { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0, 1 } },
502 { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0, 1 } },
503 { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 1, 1 } },
504 { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 1, 0 } },
505 { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 1, 0 } },
506 { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1, 1 } },
507 { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0, 1 } },
508 { "wchar_t", KEYWORD_WCHAR_T, { 0, 1, 1, 0, 0, 0, 0 } },
509 { "weak", KEYWORD_WEAK, { 0, 0, 0, 0, 0, 1, 0 } },
510 { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1, 1 } }
515 * FUNCTION PROTOTYPES
517 static void createTags (const unsigned int nestLevel, statementInfo *const parent);
518 static void copyToken (tokenInfo *const dest, const tokenInfo *const src);
519 static const char *getVarType (const statementInfo *const st,
520 const tokenInfo *const token);
523 * FUNCTION DEFINITIONS
526 /* Debugging functions added by Biswa */
527 #if defined(DEBUG_C) && DEBUG_C
528 static char *tokenTypeName[] = {
529 "none", "args", "'}'", "'{'", "','", "'::'", "keyword", "name",
530 "package", "paren-name", "';'", "spec", "*", "[]", "count"
533 static char *tagScopeNames[] = {
534 "global", "static", "extern", "friend", "typedef", "count"};
536 static char *declTypeNames[] = {
537 "none", "base", "class", "enum", "function", "ignore", "interface",
538 "namespace", "nomangle", "package", "struct", "union", "count"};
540 static char *impTypeNames[] = {
541 "default", "abstract", "virtual", "pure-virtual", "count"};
543 void printToken(const tokenInfo *const token)
545 fprintf(stderr, "Type: %s, Keyword: %d, name: %s\n", tokenTypeName[token->type],
546 token->keyword, vStringValue(token->name));
549 void printTagEntry(const tagEntryInfo *tag)
551 fprintf(stderr, "Tag: %s (%s) [ impl: %s, scope: %s, type: %s\n", tag->name,
552 tag->kindName, tag->extensionFields.implementation, tag->extensionFields.scope[1],
553 tag->extensionFields.varType);
556 void printStatement(const statementInfo *const statement)
558 int i;
559 statementInfo *st = (statementInfo *) statement;
560 while (NULL != st)
562 fprintf(stderr, "Statement Info:\n------------------------\n");
563 fprintf(stderr, "scope: %s, decl: %s, impl: %s\n", tagScopeNames[st->scope],
564 declTypeNames[st->declaration], impTypeNames[st->implementation]);
565 for (i=0; i < NumTokens; ++i)
567 fprintf(stderr, "Token %d %s: ", i, (i == st->tokenIndex)?"(current)":"");
568 printToken(st->token[i]);
570 fprintf(stderr, "Context: ");
571 printToken(st->context);
572 fprintf(stderr, "Block: ");
573 printToken(st->blockName);
574 fprintf(stderr, "Parent classes: %s\n", vStringValue(st->parentClasses));
575 fprintf(stderr, "First token: ");
576 printToken(st->firstToken);
577 if (NULL != st->parent)
578 fprintf(stderr, "Printing Parent:\n");
579 st = st->parent;
581 fprintf(stderr, "-----------------------------------------------\n");
583 #endif
586 * Token management
589 static void initToken (tokenInfo* const token)
591 token->type = TOKEN_NONE;
592 token->keyword = KEYWORD_NONE;
593 token->lineNumber = getInputLineNumber ();
594 token->filePosition = getInputFilePosition ();
595 vStringClear (token->name);
598 static void advanceToken (statementInfo* const st)
600 if (st->tokenIndex >= (unsigned int) NumTokens - 1)
601 st->tokenIndex = 0;
602 else
603 ++st->tokenIndex;
604 initToken (st->token [st->tokenIndex]);
607 static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
609 unsigned int tokenIndex;
610 unsigned int num = (unsigned int) NumTokens;
611 Assert (n < num);
612 tokenIndex = (st->tokenIndex + num - n) % num;
613 return st->token [tokenIndex];
616 static void setToken (statementInfo *const st, const tokenType type)
618 tokenInfo *token;
619 token = activeToken (st);
620 initToken (token);
621 token->type = type;
624 static void retardToken (statementInfo *const st)
626 if (st->tokenIndex == 0)
627 st->tokenIndex = (unsigned int) NumTokens - 1;
628 else
629 --st->tokenIndex;
630 setToken (st, TOKEN_NONE);
633 static tokenInfo *newToken (void)
635 tokenInfo *const token = xMalloc (1, tokenInfo);
636 token->name = vStringNew ();
637 initToken (token);
638 return token;
641 static void deleteToken (tokenInfo *const token)
643 if (token != NULL)
645 vStringDelete (token->name);
646 eFree (token);
650 static const char *accessString (const accessType laccess)
652 static const char *const names [] = {
653 "?", "private", "protected", "public", "default"
655 Assert (ARRAY_SIZE (names) == ACCESS_COUNT);
656 Assert ((int) laccess < ACCESS_COUNT);
657 return names[(int) laccess];
660 static const char *implementationString (const impType imp)
662 static const char *const names [] = {
663 "?", "abstract", "virtual", "pure virtual"
665 Assert (ARRAY_SIZE (names) == IMP_COUNT);
666 Assert ((int) imp < IMP_COUNT);
667 return names [(int) imp];
671 * Debugging functions
674 #ifdef DEBUG
676 #define boolString(c) ((c) ? "TRUE" : "FALSE")
678 static const char *tokenString (const tokenType type)
680 static const char *const names [] = {
681 "none", "args", "}", "{", "comma", "double colon", "keyword", "name",
682 "package", "paren-name", "semicolon", "specifier", "*", "[]"
684 Assert (ARRAY_SIZE (names) == TOKEN_COUNT);
685 Assert ((int) type < TOKEN_COUNT);
686 return names [(int) type];
689 static const char *scopeString (const tagScope scope)
691 static const char *const names [] = {
692 "global", "static", "extern", "friend", "typedef"
694 Assert (ARRAY_SIZE (names) == SCOPE_COUNT);
695 Assert ((int) scope < SCOPE_COUNT);
696 return names [(int) scope];
699 static const char *declString (const declType declaration)
701 static const char *const names [] = {
702 "?", "base", "class", "enum", "event", "signal", "function",
703 "function template", "ignore", "interface", "module", "namespace",
704 "no mangle", "package", "struct", "union",
706 Assert (ARRAY_SIZE (names) == DECL_COUNT);
707 Assert ((int) declaration < DECL_COUNT);
708 return names [(int) declaration];
711 static const char *keywordString (const keywordId keyword)
713 const size_t count = ARRAY_SIZE (KeywordTable);
714 const char *name = "none";
715 size_t i;
716 for (i = 0 ; i < count ; ++i)
718 const keywordDesc *p = &KeywordTable [i];
719 if (p->id == keyword)
721 name = p->name;
722 break;
725 return name;
728 static void CTAGS_ATTR_UNUSED pt (tokenInfo *const token)
730 if (isType (token, TOKEN_NAME))
731 printf ("type: %-12s: %-13s line: %lu\n",
732 tokenString (token->type), vStringValue (token->name),
733 token->lineNumber);
734 else if (isType (token, TOKEN_KEYWORD))
735 printf ("type: %-12s: %-13s line: %lu\n",
736 tokenString (token->type), keywordString (token->keyword),
737 token->lineNumber);
738 else
739 printf ("type: %-12s line: %lu\n",
740 tokenString (token->type), token->lineNumber);
743 static void CTAGS_ATTR_UNUSED ps (statementInfo *const st)
745 unsigned int i;
746 printf("scope: %s decl: %s gotName: %s gotParenName: %s\n",
747 scopeString (st->scope), declString (st->declaration),
748 boolString (st->gotName), boolString (st->gotParenName));
749 printf("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
750 printf("access: %s default: %s\n", accessString (st->member.access),
751 accessString (st->member.accessDefault));
752 printf("token : ");
753 pt(activeToken (st));
754 for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
756 printf("prev %u : ", i);
757 pt(prevToken (st, i));
759 printf("context: ");
760 pt(st->context);
763 #endif
766 * Statement management
769 static bool isDataTypeKeyword (const tokenInfo *const token)
771 switch (token->keyword)
773 case KEYWORD_BOOLEAN:
774 case KEYWORD_BYTE:
775 case KEYWORD_CHAR:
776 case KEYWORD_DOUBLE:
777 case KEYWORD_FLOAT:
778 case KEYWORD_INT:
779 case KEYWORD_LONG:
780 case KEYWORD_SHORT:
781 case KEYWORD_VOID:
782 case KEYWORD_WCHAR_T:
783 case KEYWORD_SIZE_T:
784 return true;
785 default:
786 return false;
790 #if 0
791 static bool isVariableKeyword (const tokenInfo *const token)
793 switch (token->keyword)
795 case KEYWORD_CONST:
796 case KEYWORD_EXTERN:
797 case KEYWORD_REGISTER:
798 case KEYWORD_STATIC:
799 case KEYWORD_VIRTUAL:
800 case KEYWORD_SIGNED:
801 case KEYWORD_UNSIGNED:
802 return true;
803 default:
804 return false;
807 #endif
809 static bool isContextualKeyword (const tokenInfo *const token)
811 bool result;
812 switch (token->keyword)
814 case KEYWORD_CLASS:
815 case KEYWORD_ENUM:
816 case KEYWORD_INTERFACE:
817 case KEYWORD_NAMESPACE:
818 case KEYWORD_STRUCT:
819 case KEYWORD_UNION:
821 result = true;
822 break;
825 default:
827 result = false;
828 break;
831 return result;
834 static bool isContextualStatement (const statementInfo *const st)
836 bool result = false;
838 if (st != NULL)
840 if (isInputLanguage (Lang_vala))
842 /* All can be a contextual statement as properties can be of any type */
843 result = true;
845 else
847 switch (st->declaration)
849 case DECL_CLASS:
850 case DECL_ENUM:
851 case DECL_INTERFACE:
852 case DECL_NAMESPACE:
853 case DECL_STRUCT:
854 case DECL_UNION:
856 result = true;
857 break;
860 default:
862 result = false;
863 break;
868 return result;
871 static bool isMember (const statementInfo *const st)
873 bool result;
874 if (isType (st->context, TOKEN_NAME))
875 result = true;
876 else
877 result = isContextualStatement (st->parent);
878 return result;
881 static void initMemberInfo (statementInfo *const st)
883 accessType accessDefault = ACCESS_UNDEFINED;
885 if (st->parent != NULL) switch (st->parent->declaration)
887 case DECL_ENUM:
888 case DECL_NAMESPACE:
890 accessDefault = ACCESS_UNDEFINED;
891 break;
893 case DECL_CLASS:
895 if (isInputLanguage (Lang_java))
896 accessDefault = ACCESS_DEFAULT;
897 else
898 accessDefault = ACCESS_PRIVATE;
899 break;
901 case DECL_INTERFACE:
902 case DECL_STRUCT:
903 case DECL_UNION:
905 accessDefault = ACCESS_PUBLIC;
906 break;
908 default:
909 break;
911 st->member.accessDefault = accessDefault;
912 st->member.access = accessDefault;
915 static void reinitStatement (statementInfo *const st, const bool partial)
917 unsigned int i;
919 if (! partial)
921 st->scope = SCOPE_GLOBAL;
922 if (isContextualStatement (st->parent))
923 st->declaration = DECL_BASE;
924 else
925 st->declaration = DECL_NONE;
927 st->gotParenName = false;
928 st->implementation = IMP_DEFAULT;
929 st->gotArgs = false;
930 st->gotName = false;
931 st->nSemicolons = 0;
932 st->haveQualifyingName = false;
934 st->tokenIndex = 0;
935 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
937 initToken (st->token [i]);
940 initToken (st->context);
941 initToken (st->blockName);
942 vStringClear (st->parentClasses);
943 lcppClearSignature ();
945 /* Init member info. */
946 if (! partial)
947 st->member.access = st->member.accessDefault;
949 /* Init first token */
950 if (!partial)
951 initToken(st->firstToken);
954 static void reinitStatementWithToken (statementInfo *const st,
955 tokenInfo *token, const bool partial)
957 tokenInfo *const save = newToken ();
958 /* given token can be part of reinit statementInfo */
959 copyToken (save, token);
960 reinitStatement (st, partial);
961 token = activeToken (st);
962 copyToken (token, save);
963 deleteToken (save);
964 ++st->tokenIndex; /* this is quite safe because current tokenIndex = 0 */
967 static void initStatement (statementInfo *const st, statementInfo *const parent)
969 st->parent = parent;
970 initMemberInfo (st);
971 reinitStatement (st, false);
972 if (parent)
974 const tokenInfo *const src = activeToken (parent);
975 tokenInfo *const dst = activeToken (st);
976 copyToken (dst, src);
977 st->tokenIndex++;
982 * Tag generation functions
984 static cKind cTagKind (const tagType type)
986 cKind result = CK_UNDEFINED;
987 switch (type)
989 case TAG_CLASS: result = CK_CLASS; break;
990 case TAG_ENUM: result = CK_ENUMERATION; break;
991 case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
992 case TAG_FUNCTION: result = CK_FUNCTION; break;
993 case TAG_MEMBER: result = CK_MEMBER; break;
994 case TAG_NAMESPACE: result = CK_NAMESPACE; break;
995 case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
996 case TAG_STRUCT: result = CK_STRUCT; break;
997 case TAG_TYPEDEF: result = CK_TYPEDEF; break;
998 case TAG_UNION: result = CK_UNION; break;
999 case TAG_VARIABLE: result = CK_VARIABLE; break;
1000 case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
1002 default: Assert ("Bad C tag type" == NULL); break;
1004 return result;
1007 static csharpKind csharpTagKind (const tagType type)
1009 csharpKind result = CSK_UNDEFINED;
1010 switch (type)
1012 case TAG_CLASS: result = CSK_CLASS; break;
1013 case TAG_ENUM: result = CSK_ENUMERATION; break;
1014 case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
1015 case TAG_EVENT: result = CSK_EVENT; break;
1016 case TAG_FIELD: result = CSK_FIELD ; break;
1017 case TAG_INTERFACE: result = CSK_INTERFACE; break;
1018 case TAG_LOCAL: result = CSK_LOCAL; break;
1019 case TAG_METHOD: result = CSK_METHOD; break;
1020 case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
1021 case TAG_PROPERTY: result = CSK_PROPERTY; break;
1022 case TAG_STRUCT: result = CSK_STRUCT; break;
1023 case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
1025 default: Assert ("Bad C# tag type" == NULL); break;
1027 return result;
1030 static dKind dTagKind (const tagType type)
1032 dKind result = DK_UNDEFINED;
1033 switch (type)
1035 case TAG_CLASS: result = DK_CLASS; break;
1036 case TAG_ENUM: result = DK_ENUMERATION; break;
1037 case TAG_ENUMERATOR: result = DK_ENUMERATOR; break;
1038 case TAG_FUNCTION: result = DK_FUNCTION; break;
1039 case TAG_INTERFACE: result = DK_INTERFACE; break;
1040 case TAG_MEMBER: result = DK_MEMBER; break;
1041 case TAG_NAMESPACE: result = DK_NAMESPACE; break;
1042 case TAG_PROTOTYPE: result = DK_PROTOTYPE; break;
1043 case TAG_STRUCT: result = DK_STRUCT; break;
1044 case TAG_TYPEDEF: result = DK_TYPEDEF; break;
1045 case TAG_UNION: result = DK_UNION; break;
1046 case TAG_VARIABLE: result = DK_VARIABLE; break;
1047 case TAG_EXTERN_VAR: result = DK_EXTERN_VARIABLE; break;
1049 default: Assert ("Bad D tag type" == NULL); break;
1051 return result;
1054 static valaKind valaTagKind (const tagType type)
1056 valaKind result = VK_UNDEFINED;
1057 switch (type)
1059 case TAG_CLASS: result = VK_CLASS; break;
1060 case TAG_ENUM: result = VK_ENUMERATION; break;
1061 case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
1062 case TAG_SIGNAL: result = VK_SIGNAL; break;
1063 case TAG_FIELD: result = VK_FIELD ; break;
1064 case TAG_INTERFACE: result = VK_INTERFACE; break;
1065 case TAG_LOCAL: result = VK_LOCAL; break;
1066 case TAG_METHOD: result = VK_METHOD; break;
1067 case TAG_NAMESPACE: result = VK_NAMESPACE; break;
1068 case TAG_PROPERTY: result = VK_PROPERTY; break;
1069 case TAG_STRUCT: result = VK_STRUCT; break;
1071 default: Assert ("Bad Vala tag type" == NULL); break;
1073 return result;
1076 static javaKind javaTagKind (const tagType type)
1078 javaKind result = JK_UNDEFINED;
1079 switch (type)
1081 case TAG_CLASS: result = JK_CLASS; break;
1082 case TAG_FIELD: result = JK_FIELD; break;
1083 case TAG_INTERFACE: result = JK_INTERFACE; break;
1084 case TAG_METHOD: result = JK_METHOD; break;
1085 case TAG_PACKAGE: result = JK_PACKAGE; break;
1086 case TAG_ENUM: result = JK_ENUMERATION; break;
1087 case TAG_ENUMERATOR: result = JK_ENUMERATOR; break;
1089 default: Assert ("Bad Java tag type" == NULL); break;
1091 return result;
1094 static int kindIndexForType (const tagType type)
1096 int result;
1097 if (isInputLanguage (Lang_java))
1098 result = javaTagKind (type);
1099 else if (isInputLanguage (Lang_csharp))
1100 result = csharpTagKind (type);
1101 else if (isInputLanguage (Lang_d))
1102 result = dTagKind (type);
1103 else if (isInputLanguage (Lang_vala))
1104 result = valaTagKind (type);
1105 else
1106 result = cTagKind (type);
1107 return result;
1111 static bool includeTag (const tagType type, const bool isFileScope)
1113 bool result;
1114 if (isFileScope && ! Option.include.fileScope)
1115 result = false;
1116 else if (isInputLanguage (Lang_java))
1117 result = JavaKinds [javaTagKind (type)].enabled;
1118 else
1119 result = CKinds [cTagKind (type)].enabled;
1120 return result;
1124 static tagType declToTagType (const declType declaration)
1126 tagType type = TAG_UNDEFINED;
1128 switch (declaration)
1130 case DECL_CLASS: type = TAG_CLASS; break;
1131 case DECL_ENUM: type = TAG_ENUM; break;
1132 case DECL_FUNCTION: type = TAG_FUNCTION; break;
1133 case DECL_FUNCTION_TEMPLATE: type = TAG_FUNCTION; break;
1134 case DECL_INTERFACE: type = TAG_INTERFACE; break;
1135 case DECL_NAMESPACE: type = TAG_NAMESPACE; break;
1136 case DECL_STRUCT: type = TAG_STRUCT; break;
1137 case DECL_UNION: type = TAG_UNION; break;
1139 default: Assert ("Unexpected declaration" == NULL); break;
1141 return type;
1144 static const char* accessField (const statementInfo *const st)
1146 const char* result = NULL;
1148 if ((isInputLanguage (Lang_cpp) || isInputLanguage (Lang_d)) &&
1149 st->scope == SCOPE_FRIEND)
1150 result = "friend";
1151 else if (st->member.access != ACCESS_UNDEFINED)
1152 result = accessString (st->member.access);
1153 return result;
1156 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
1157 const tokenInfo *const nameToken,
1158 const statementInfo *const st, vString *const scope)
1160 /* For selected tag types, append an extension flag designating the
1161 * parent object in which the tag is defined.
1163 switch (type)
1165 default: break;
1167 case TAG_NAMESPACE:
1168 case TAG_CLASS:
1169 case TAG_ENUM:
1170 case TAG_ENUMERATOR:
1171 case TAG_FIELD:
1172 case TAG_FUNCTION:
1173 case TAG_INTERFACE:
1174 case TAG_MEMBER:
1175 case TAG_METHOD:
1176 case TAG_PROTOTYPE:
1177 case TAG_STRUCT:
1178 case TAG_TYPEDEF:
1179 case TAG_UNION:
1181 if (vStringLength (scope) > 0 &&
1182 (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
1184 if (isType (st->context, TOKEN_NAME))
1185 tag->extensionFields.scopeKindIndex = kindIndexForType (TAG_CLASS);
1186 else
1187 tag->extensionFields.scopeKindIndex =
1188 kindIndexForType (declToTagType (parentDecl (st)));
1189 tag->extensionFields.scopeName = vStringValue (scope);
1191 if ((type == TAG_CLASS || type == TAG_INTERFACE ||
1192 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
1194 tag->extensionFields.inheritance =
1195 vStringValue (st->parentClasses);
1197 if (st->implementation != IMP_DEFAULT &&
1198 (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala) ||
1199 isInputLanguage (Lang_java) || isInputLanguage (Lang_d)))
1201 tag->extensionFields.implementation =
1202 implementationString (st->implementation);
1204 if (isMember (st))
1206 tag->extensionFields.access = accessField (st);
1208 if ((true == st->gotArgs) &&
1209 ((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
1211 tag->extensionFields.signature = lcppGetSignature ();
1213 break;
1217 if ((TAG_FIELD == type) || (TAG_MEMBER == type) ||
1218 (TAG_EXTERN_VAR == type) || (TAG_TYPEDEF == type) ||
1219 (TAG_VARIABLE == type) || (TAG_METHOD == type) ||
1220 (TAG_PROTOTYPE == type) || (TAG_FUNCTION == type))
1222 if (((TOKEN_NAME == st->firstToken->type) || isDataTypeKeyword(st->firstToken))
1223 && (0 != strcmp(vStringValue(st->firstToken->name), tag->name)))
1225 tag->extensionFields.typeRef[1] = getVarType(st, nameToken);
1230 static const char *getVarType (const statementInfo *const st,
1231 const tokenInfo *const nameToken)
1233 static vString *vt = NULL;
1234 unsigned int i;
1235 unsigned int end = st->tokenIndex;
1236 bool seenType = false;
1238 switch (st->declaration) {
1239 case DECL_BASE:
1240 case DECL_FUNCTION:
1241 case DECL_FUNCTION_TEMPLATE:
1242 break;
1243 default:
1244 return vStringValue(st->firstToken->name);
1247 if (vt == NULL)
1248 vt = vStringNew();
1249 else
1250 vStringClear(vt);
1252 /* find the end of the type signature in the token list */
1253 for (i = 0; i < st->tokenIndex; i++)
1255 const tokenInfo *const t = st->token[i];
1257 /* stop if we find the token used to generate the tag name, or
1258 * a name token in the middle yet not preceded by a scope separator */
1259 if ((t == nameToken ||
1260 (t->type == nameToken->type &&
1261 t->keyword == nameToken->keyword &&
1262 t->lineNumber == nameToken->lineNumber &&
1263 strcmp(vStringValue(t->name), vStringValue(nameToken->name)) == 0)) ||
1264 (t->type == TOKEN_NAME && seenType &&
1265 (i > 0 && st->token[i - 1]->type != TOKEN_DOUBLE_COLON)))
1267 break;
1269 if (t->type != TOKEN_DOUBLE_COLON)
1270 end = i + 1;
1271 if (t->type == TOKEN_NAME)
1272 seenType = true;
1273 else if (t->type == TOKEN_KEYWORD && isDataTypeKeyword(t))
1274 seenType = true;
1277 /* ugly historic workaround when we can't figure out the type */
1278 if (end < 2 && ! st->gotArgs)
1279 return vStringValue(st->firstToken->name);
1281 for (i = 0; i < end; i++)
1283 tokenInfo *t = st->token[i];
1285 switch (t->type)
1287 case TOKEN_NAME: /* user typename */
1288 break;
1289 case TOKEN_KEYWORD:
1290 if ((t->keyword != KEYWORD_EXTERN && t->keyword != KEYWORD_STATIC) && /* uninteresting keywords */
1291 (st->gotArgs ||
1292 /* ignore uninteresting keywords for non-functions */
1293 (t->keyword != KEYWORD_PUBLIC &&
1294 t->keyword != KEYWORD_PRIVATE &&
1295 t->keyword != KEYWORD_PROTECTED &&
1296 t->keyword != KEYWORD_FINAL &&
1297 t->keyword != KEYWORD_TYPEDEF &&
1298 /* hack for D static conditions */
1299 t->keyword != KEYWORD_IF)))
1301 break;
1303 continue;
1304 case TOKEN_STAR: vStringCatS(vt, " *"); continue;
1305 case TOKEN_ARRAY: vStringCatS(vt, "[]"); continue;
1306 case TOKEN_DOUBLE_COLON:
1307 vStringCatS(vt, "::");
1308 continue;
1309 default: continue;
1311 if (vStringLength(vt) > 0)
1312 if (isalpha(vStringValue(vt)[vStringLength(vt) - 1]))
1313 vStringPut(vt, ' ');
1314 vStringCat(vt, t->name);
1316 return vStringValue(vt);
1319 static void addContextSeparator (vString *const scope)
1321 if (isInputLanguage (Lang_c) || isInputLanguage (Lang_cpp))
1322 vStringCatS (scope, "::");
1323 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_d) ||
1324 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1325 vStringCatS (scope, ".");
1328 static void findScopeHierarchy (vString *const string,
1329 const statementInfo *const st)
1331 const char* const anon = "<anonymous>";
1332 bool nonAnonPresent = false;
1334 vStringClear (string);
1335 if (isType (st->context, TOKEN_NAME))
1337 vStringCopy (string, st->context->name);
1338 nonAnonPresent = true;
1340 if (st->parent != NULL)
1342 vString *temp = vStringNew ();
1343 const statementInfo *s;
1345 for (s = st->parent ; s != NULL ; s = s->parent)
1347 if (isContextualStatement (s) ||
1348 s->declaration == DECL_NAMESPACE)
1350 vStringCopy (temp, string);
1351 vStringClear (string);
1352 if (isType (s->blockName, TOKEN_NAME))
1354 if (isType (s->context, TOKEN_NAME) &&
1355 vStringLength (s->context->name) > 0)
1357 vStringCat (string, s->context->name);
1358 addContextSeparator (string);
1360 vStringCat (string, s->blockName->name);
1361 nonAnonPresent = true;
1363 else
1364 vStringCopyS (string, anon);
1365 if (vStringLength (temp) > 0)
1366 addContextSeparator (string);
1367 vStringCat (string, temp);
1370 vStringDelete (temp);
1372 if (! nonAnonPresent)
1373 vStringClear (string);
1377 static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
1378 vString *const scope)
1380 if (isXtagEnabled(XTAG_QUALIFIED_TAGS) &&
1381 scope != NULL && vStringLength (scope) > 0)
1383 vString *const scopedName = vStringNew ();
1385 if (type != TAG_ENUMERATOR)
1386 vStringCopy (scopedName, scope);
1387 else
1389 /* remove last component (i.e. enumeration name) from scope */
1390 const char* const sc = vStringValue (scope);
1391 const char* colon = strrchr (sc, ':');
1392 if (colon != NULL)
1394 while (*colon == ':' && colon > sc)
1395 --colon;
1396 vStringNCopy (scopedName, scope, colon + 1 - sc);
1399 if (vStringLength (scopedName) > 0)
1401 addContextSeparator (scopedName);
1402 vStringCatS (scopedName, e->name);
1403 e->name = vStringValue (scopedName);
1404 makeTagEntry (e);
1406 vStringDelete (scopedName);
1410 static void makeTag (const tokenInfo *const token,
1411 const statementInfo *const st,
1412 bool isFileScope, const tagType type)
1414 #ifdef DEBUG_C
1415 printToken(token);
1416 fprintf(stderr, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
1417 printStatement(st);
1418 #endif
1419 /* Nothing is really of file scope when it appears in a header file.
1421 isFileScope = (bool) (isFileScope && ! isInputHeaderFile ());
1423 if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 /* &&
1424 includeTag (type, isFileScope) */)
1426 vString *scope;
1427 tagEntryInfo e;
1429 initTagEntry (&e, vStringValue (token->name), kindIndexForType (type));
1431 e.lineNumber = token->lineNumber;
1432 e.filePosition = token->filePosition;
1433 e.isFileScope = isFileScope;
1435 scope = vStringNew ();
1436 findScopeHierarchy (scope, st);
1437 addOtherFields (&e, type, token, st, scope);
1439 #ifdef DEBUG_C
1440 printTagEntry(&e);
1441 #endif
1442 makeTagEntry (&e);
1443 makeExtraTagEntry (type, &e, scope);
1444 vStringDelete (scope);
1445 if (NULL != e.extensionFields.signature)
1446 free((char *) e.extensionFields.signature);
1450 static bool isValidTypeSpecifier (const declType declaration)
1452 bool result;
1453 switch (declaration)
1455 case DECL_BASE:
1456 case DECL_CLASS:
1457 case DECL_ENUM:
1458 case DECL_STRUCT:
1459 case DECL_UNION:
1460 result = true;
1461 break;
1463 default:
1464 result = false;
1465 break;
1467 return result;
1470 static void qualifyEnumeratorTag (const statementInfo *const st,
1471 const tokenInfo *const nameToken)
1473 if (isType (nameToken, TOKEN_NAME))
1474 makeTag (nameToken, st, true, TAG_ENUMERATOR);
1477 static void qualifyFunctionTag (const statementInfo *const st,
1478 const tokenInfo *const nameToken)
1480 if (isType (nameToken, TOKEN_NAME))
1482 const tagType type = (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1483 ? TAG_METHOD : TAG_FUNCTION;
1484 const bool isFileScope =
1485 (bool) (st->member.access == ACCESS_PRIVATE ||
1486 (!isMember (st) && st->scope == SCOPE_STATIC));
1488 makeTag (nameToken, st, isFileScope, type);
1492 static void qualifyFunctionDeclTag (const statementInfo *const st,
1493 const tokenInfo *const nameToken)
1495 if (! isType (nameToken, TOKEN_NAME))
1497 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1498 qualifyFunctionTag (st, nameToken);
1499 else if (st->scope == SCOPE_TYPEDEF)
1500 makeTag (nameToken, st, true, TAG_TYPEDEF);
1501 else if (isValidTypeSpecifier (st->declaration) &&
1502 ! (isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala)))
1503 makeTag (nameToken, st, true, TAG_PROTOTYPE);
1506 static void qualifyCompoundTag (const statementInfo *const st,
1507 const tokenInfo *const nameToken)
1509 if (isType (nameToken, TOKEN_NAME))
1511 const tagType type = declToTagType (st->declaration);
1513 if (type != TAG_UNDEFINED)
1514 makeTag (nameToken, st, (bool) (! isInputLanguage (Lang_java) &&
1515 ! isInputLanguage (Lang_csharp) &&
1516 ! isInputLanguage (Lang_vala)), type);
1520 static void qualifyBlockTag (statementInfo *const st,
1521 const tokenInfo *const nameToken)
1523 switch (st->declaration)
1525 case DECL_CLASS:
1526 case DECL_ENUM:
1527 case DECL_INTERFACE:
1528 case DECL_NAMESPACE:
1529 case DECL_STRUCT:
1530 case DECL_UNION:
1531 qualifyCompoundTag (st, nameToken);
1532 break;
1533 default: break;
1537 static void qualifyVariableTag (const statementInfo *const st,
1538 const tokenInfo *const nameToken)
1540 /* We have to watch that we do not interpret a declaration of the
1541 * form "struct tag;" as a variable definition. In such a case, the
1542 * token preceding the name will be a keyword.
1544 if (! isType (nameToken, TOKEN_NAME))
1546 else if (st->declaration == DECL_IGNORE)
1548 else if (st->scope == SCOPE_TYPEDEF)
1549 makeTag (nameToken, st, true, TAG_TYPEDEF);
1550 else if (st->declaration == DECL_PACKAGE)
1551 makeTag (nameToken, st, false, TAG_PACKAGE);
1552 else if (st->declaration == DECL_MODULE) /* handle modules in D as namespaces */
1553 makeTag (nameToken, st, false, TAG_NAMESPACE);
1554 else if (isValidTypeSpecifier (st->declaration))
1556 if (isMember (st))
1558 if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1559 makeTag (nameToken, st, (bool) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
1560 else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
1561 makeTag (nameToken, st, true, TAG_MEMBER);
1563 else if (isInputLanguage (Lang_java) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
1565 else
1567 if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
1568 makeTag (nameToken, st, false, TAG_EXTERN_VAR);
1569 else
1570 makeTag (nameToken, st, (bool) (st->scope == SCOPE_STATIC), TAG_VARIABLE);
1576 * Parsing functions
1579 static int skipToOneOf (const char *const chars)
1581 int c;
1583 c = lcppGetc ();
1584 while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
1586 return c;
1589 /* Skip to the next non-white character.
1591 static int skipToNonWhite (void)
1593 int c;
1597 c = lcppGetc ();
1599 while (isspace (c));
1601 return c;
1604 /* Skips to the next brace in column 1. This is intended for cases where
1605 * preprocessor constructs result in unbalanced braces.
1607 static void skipToFormattedBraceMatch (void)
1609 int c, next;
1611 c = lcppGetc ();
1612 next = lcppGetc ();
1613 while (c != EOF && (c != '\n' || next != '}'))
1615 c = next;
1616 next = lcppGetc ();
1620 /* Skip to the matching character indicated by the pair string. If skipping
1621 * to a matching brace and any brace is found within a different level of a
1622 * #if conditional statement while brace formatting is in effect, we skip to
1623 * the brace matched by its formatting. It is assumed that we have already
1624 * read the character which starts the group (i.e. the first character of
1625 * "pair").
1627 static void skipToMatch (const char *const pair)
1629 const bool braceMatching = (bool) (strcmp ("{}", pair) == 0);
1630 const bool braceFormatting = (bool) (lcppIsBraceFormat () && braceMatching);
1631 const unsigned int initialLevel = lcppGetDirectiveNestLevel ();
1632 const int begin = pair [0], end = pair [1];
1633 const unsigned long inputLineNumber = getInputLineNumber ();
1634 int matchLevel = 1;
1635 int c = '\0';
1636 if (isInputLanguage(Lang_d) && pair[0] == '<')
1637 return; /* ignore e.g. Foo!(x < 2) */
1638 while (matchLevel > 0 && (c = lcppGetc ()) != EOF)
1640 if (c == begin)
1642 ++matchLevel;
1643 if (braceFormatting && lcppGetDirectiveNestLevel () != initialLevel)
1645 skipToFormattedBraceMatch ();
1646 break;
1649 else if (c == end)
1651 --matchLevel;
1652 if (braceFormatting && lcppGetDirectiveNestLevel () != initialLevel)
1654 skipToFormattedBraceMatch ();
1655 break;
1658 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1659 * match problems with C++ generics containing a static expression like
1660 * foo<X<Y> bar;
1661 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1662 else if (isInputLanguage (Lang_cpp) && begin == '<' &&
1663 (c == ';' || c == '{'))
1665 lcppUngetc (c);
1666 break;
1669 if (c == EOF)
1671 verbose ("%s: failed to find match for '%c' at line %lu\n",
1672 getInputFileName (), begin, inputLineNumber);
1673 if (braceMatching)
1674 longjmp (Exception, (int) ExceptionBraceFormattingError);
1675 else
1676 longjmp (Exception, (int) ExceptionFormattingError);
1680 static void skipParens (void)
1682 const int c = skipToNonWhite ();
1684 if (c == '(')
1685 skipToMatch ("()");
1686 else
1687 lcppUngetc (c);
1690 static void skipBraces (void)
1692 const int c = skipToNonWhite ();
1694 if (c == '{')
1695 skipToMatch ("{}");
1696 else
1697 lcppUngetc (c);
1700 static keywordId analyzeKeyword (const char *const name)
1702 const keywordId id = (keywordId) lookupKeyword (name, getInputLanguage ());
1704 /* ignore D @attributes and Java @annotations(...), but show them in function signatures */
1705 if ((isInputLanguage(Lang_d) || isInputLanguage(Lang_java)) && id == KEYWORD_NONE && name[0] == '@')
1707 skipParens(); /* if annotation has parameters, skip them */
1708 return KEYWORD_CONST;
1710 return id;
1713 static void analyzeIdentifier (tokenInfo *const token)
1715 char *const name = vStringValue (token->name);
1716 const char *replacement = NULL;
1717 bool parensToo = false;
1719 if (isInputLanguage (Lang_java) ||
1720 ! cppIsIgnoreToken (name, &parensToo, &replacement))
1722 if (replacement != NULL)
1723 token->keyword = analyzeKeyword (replacement);
1724 else
1725 token->keyword = analyzeKeyword (vStringValue (token->name));
1727 if (token->keyword == KEYWORD_NONE)
1728 token->type = TOKEN_NAME;
1729 else
1730 token->type = TOKEN_KEYWORD;
1732 else
1734 initToken (token);
1735 if (parensToo)
1737 int c = skipToNonWhite ();
1739 if (c == '(')
1740 skipToMatch ("()");
1745 static void readIdentifier (tokenInfo *const token, const int firstChar)
1747 vString *const name = token->name;
1748 int c = firstChar;
1750 initToken (token);
1752 /* Bug #1585745 (CTags): strangely, C++ destructors allow whitespace between
1753 * the ~ and the class name. */
1754 if (isInputLanguage (Lang_cpp) && firstChar == '~')
1756 vStringPut (name, c);
1757 c = skipToNonWhite ();
1762 vStringPut (name, c);
1763 c = lcppGetc ();
1764 } while (lcppIsident (c) || (isInputLanguage (Lang_vala) && '.' == c));
1765 lcppUngetc (c); /* unget non-identifier character */
1767 /* Vala supports '?' at end of a type (with or without whitespace before) for nullable types */
1768 if (isInputLanguage (Lang_vala))
1770 c = skipToNonWhite ();
1771 if ('?' == c)
1772 vStringPut (name, c);
1773 else
1774 lcppUngetc (c);
1777 analyzeIdentifier (token);
1780 static void readPackageName (tokenInfo *const token, const int firstChar)
1782 vString *const name = token->name;
1783 int c = firstChar;
1785 initToken (token);
1787 while (lcppIsident (c) || c == '.')
1789 vStringPut (name, c);
1790 c = lcppGetc ();
1792 lcppUngetc (c); /* unget non-package character */
1795 static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
1797 st->declaration = declaration;
1799 if (declaration == DECL_NAMESPACE && !(isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala)))
1801 /* In C++ a namespace is specified one level at a time. */
1802 return;
1804 else
1806 /* In C#, a namespace can also be specified like a Java package name. */
1807 tokenInfo *const token = activeToken (st);
1808 Assert (isType (token, TOKEN_KEYWORD));
1809 readPackageName (token, skipToNonWhite ());
1810 token->type = TOKEN_NAME;
1811 st->gotName = true;
1812 st->haveQualifyingName = true;
1816 static void readPackage (statementInfo *const st)
1818 tokenInfo *const token = activeToken (st);
1819 Assert (isType (token, TOKEN_KEYWORD));
1820 readPackageName (token, skipToNonWhite ());
1821 token->type = TOKEN_NAME;
1822 if (isInputLanguage (Lang_d))
1823 st->declaration = DECL_MODULE;
1824 else
1825 st->declaration = DECL_PACKAGE;
1826 st->gotName = true;
1827 st->haveQualifyingName = true;
1830 static void processName (statementInfo *const st)
1832 Assert (isType (activeToken (st), TOKEN_NAME));
1833 if (st->gotName && st->declaration == DECL_NONE)
1834 st->declaration = DECL_BASE;
1835 st->gotName = true;
1836 st->haveQualifyingName = true;
1839 static void readOperator (statementInfo *const st)
1841 const char *const acceptable = "+-*/%^&|~!=<>,[]";
1842 const tokenInfo* const prev = prevToken (st,1);
1843 tokenInfo *const token = activeToken (st);
1844 vString *const name = token->name;
1845 int c = skipToNonWhite ();
1847 /* When we arrive here, we have the keyword "operator" in 'name'.
1849 if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
1850 prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
1851 ; /* ignore "operator" keyword if preceded by these keywords */
1852 else if (c == '(')
1854 /* Verify whether this is a valid function call (i.e. "()") operator.
1856 if (lcppGetc () == ')')
1858 vStringPut (name, ' '); /* always separate operator from keyword */
1859 c = skipToNonWhite ();
1860 if (c == '(')
1861 vStringCatS (name, "()");
1863 else
1865 skipToMatch ("()");
1866 c = lcppGetc ();
1869 else if (lcppIsident1 (c))
1871 /* Handle "new" and "delete" operators, and conversion functions
1872 * (per 13.3.1.1.2 [2] of the C++ spec).
1874 bool whiteSpace = true; /* default causes insertion of space */
1877 if (isspace (c))
1878 whiteSpace = true;
1879 else
1881 if (whiteSpace)
1883 vStringPut (name, ' ');
1884 whiteSpace = false;
1886 vStringPut (name, c);
1888 c = lcppGetc ();
1889 } while (! isOneOf (c, "(;") && c != EOF);
1891 else if (isOneOf (c, acceptable))
1893 vStringPut (name, ' '); /* always separate operator from keyword */
1896 vStringPut (name, c);
1897 c = lcppGetc ();
1898 } while (isOneOf (c, acceptable));
1901 lcppUngetc (c);
1903 token->type = TOKEN_NAME;
1904 token->keyword = KEYWORD_NONE;
1905 processName (st);
1908 static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
1910 dest->type = src->type;
1911 dest->keyword = src->keyword;
1912 dest->filePosition = src->filePosition;
1913 dest->lineNumber = src->lineNumber;
1914 vStringCopy (dest->name, src->name);
1917 static void setAccess (statementInfo *const st, const accessType laccess)
1919 if (isMember (st))
1921 if (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_d))
1923 int c = skipToNonWhite ();
1925 if (c == ':')
1926 reinitStatementWithToken (st, prevToken (st, 1), false);
1927 else
1928 lcppUngetc (c);
1930 st->member.accessDefault = laccess;
1932 st->member.access = laccess;
1936 static void discardTypeList (tokenInfo *const token)
1938 int c = skipToNonWhite ();
1939 while (lcppIsident1 (c))
1941 readIdentifier (token, c);
1942 c = skipToNonWhite ();
1943 if (c == '.' || c == ',')
1944 c = skipToNonWhite ();
1946 lcppUngetc (c);
1949 static void addParentClass (statementInfo *const st, tokenInfo *const token)
1951 if (vStringLength (token->name) > 0 &&
1952 vStringLength (st->parentClasses) > 0)
1954 vStringPut (st->parentClasses, ',');
1956 vStringCat (st->parentClasses, token->name);
1959 static void readParents (statementInfo *const st, const int qualifier)
1961 tokenInfo *const token = newToken ();
1962 tokenInfo *const parent = newToken ();
1963 int c;
1967 c = skipToNonWhite ();
1968 if (lcppIsident1 (c))
1970 readIdentifier (token, c);
1971 if (isType (token, TOKEN_NAME))
1972 vStringCat (parent->name, token->name);
1973 else
1975 addParentClass (st, parent);
1976 initToken (parent);
1979 else if (c == qualifier)
1980 vStringPut (parent->name, c);
1981 else if (c == '<')
1982 skipToMatch ("<>");
1983 else if (isType (token, TOKEN_NAME))
1985 addParentClass (st, parent);
1986 initToken (parent);
1988 } while (c != '{' && c != EOF);
1989 lcppUngetc (c);
1990 deleteToken (parent);
1991 deleteToken (token);
1994 static void checkIsClassEnum (statementInfo *const st, const declType decl)
1996 if (! isInputLanguage (Lang_cpp) || st->declaration != DECL_ENUM)
1997 st->declaration = decl;
2000 static void processToken (tokenInfo *const token, statementInfo *const st)
2002 switch (token->keyword) /* is it a reserved word? */
2004 default: break;
2006 case KEYWORD_NONE: processName (st); break;
2007 case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
2008 case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
2009 case KEYWORD_CATCH: skipParens (); skipBraces (); break;
2010 case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
2011 case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break;
2012 case KEYWORD_CONST: st->declaration = DECL_BASE; break;
2013 case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break;
2014 case KEYWORD_ENUM: st->declaration = DECL_ENUM; break;
2015 case KEYWORD_EXTENDS: readParents (st, '.');
2016 setToken (st, TOKEN_NONE); break;
2017 case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
2018 case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
2019 case KEYWORD_IMPLEMENTS:readParents (st, '.');
2020 setToken (st, TOKEN_NONE); break;
2021 case KEYWORD_IMPORT: st->declaration = DECL_IGNORE; break;
2022 case KEYWORD_INT: st->declaration = DECL_BASE; break;
2023 case KEYWORD_BOOLEAN: st->declaration = DECL_BASE; break;
2024 case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
2025 case KEYWORD_SIZE_T: st->declaration = DECL_BASE; break;
2026 case KEYWORD_INTERFACE: st->declaration = DECL_INTERFACE; break;
2027 case KEYWORD_LONG: st->declaration = DECL_BASE; break;
2028 case KEYWORD_OPERATOR: readOperator (st); break;
2029 case KEYWORD_MODULE: readPackage (st); break;
2030 case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
2031 case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
2032 case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
2033 case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
2034 case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
2035 case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break;
2036 case KEYWORD_STATIC_ASSERT: skipParens (); break;
2037 case KEYWORD_THROWS: discardTypeList (token); break;
2038 case KEYWORD_TYPEDEF: st->scope = SCOPE_TYPEDEF; break;
2039 case KEYWORD_UNION: st->declaration = DECL_UNION; break;
2040 case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
2041 case KEYWORD_USING: st->declaration = DECL_IGNORE; break;
2042 case KEYWORD_VOID: st->declaration = DECL_BASE; break;
2043 case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
2044 case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
2046 case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
2047 case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
2048 case KEYWORD_EVENT:
2050 if (isInputLanguage (Lang_csharp))
2051 st->declaration = DECL_EVENT;
2052 break;
2054 case KEYWORD_SIGNAL:
2056 if (isInputLanguage (Lang_vala))
2057 st->declaration = DECL_SIGNAL;
2058 break;
2060 case KEYWORD_EXTERN:
2062 if (! isInputLanguage (Lang_csharp) || !st->gotName)
2064 /*reinitStatement (st, false);*/
2065 st->scope = SCOPE_EXTERN;
2066 st->declaration = DECL_BASE;
2068 break;
2070 case KEYWORD_STATIC:
2072 if (! isInputLanguage (Lang_java) && ! isInputLanguage (Lang_csharp) && ! isInputLanguage (Lang_vala))
2074 /*reinitStatement (st, false);*/
2075 st->scope = SCOPE_STATIC;
2076 st->declaration = DECL_BASE;
2078 break;
2080 case KEYWORD_IF:
2081 if (isInputLanguage (Lang_d))
2082 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2083 int c = skipToNonWhite ();
2084 if (c == '(')
2085 skipToMatch ("()");
2087 break;
2092 * Parenthesis handling functions
2095 static void restartStatement (statementInfo *const st)
2097 tokenInfo *const save = newToken ();
2098 tokenInfo *token = activeToken (st);
2100 copyToken (save, token);
2101 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
2102 reinitStatement (st, false);
2103 token = activeToken (st);
2104 copyToken (token, save);
2105 deleteToken (save);
2106 processToken (token, st);
2109 /* Skips over a mem-initializer-list of a ctor-initializer, defined as:
2111 * mem-initializer-list:
2112 * mem-initializer, mem-initializer-list
2114 * mem-initializer:
2115 * [::] [nested-name-spec] class-name (...)
2116 * identifier
2118 static void skipMemIntializerList (tokenInfo *const token)
2120 int c;
2124 c = skipToNonWhite ();
2125 while (lcppIsident1 (c) || c == ':')
2127 if (c != ':')
2128 readIdentifier (token, c);
2129 c = skipToNonWhite ();
2131 if (c == '<')
2133 skipToMatch ("<>");
2134 c = skipToNonWhite ();
2136 if (c == '(')
2138 skipToMatch ("()");
2139 c = skipToNonWhite ();
2141 } while (c == ',');
2142 lcppUngetc (c);
2145 static void skipMacro (statementInfo *const st)
2147 tokenInfo *const prev2 = prevToken (st, 2);
2149 if (isType (prev2, TOKEN_NAME))
2150 retardToken (st);
2151 skipToMatch ("()");
2154 static bool isDPostArgumentToken(tokenInfo *const token)
2156 switch (token->keyword)
2158 /* Note: some other keywords e.g. immutable are parsed as
2159 * KEYWORD_CONST - see initializeDParser */
2160 case KEYWORD_CONST:
2161 /* template constraint */
2162 case KEYWORD_IF:
2163 /* contracts */
2164 case KEYWORD_IN:
2165 case KEYWORD_OUT:
2166 case KEYWORD_BODY:
2167 return true;
2168 default:
2169 break;
2171 /* @attributes */
2172 if (vStringValue(token->name)[0] == '@')
2173 return true;
2174 return false;
2177 /* Skips over characters following the parameter list. This will be either
2178 * non-ANSI style function declarations or C++ stuff. Our choices:
2180 * C (K&R):
2181 * int func ();
2182 * int func (one, two) int one; float two; {...}
2183 * C (ANSI):
2184 * int func (int one, float two);
2185 * int func (int one, float two) {...}
2186 * C++:
2187 * int foo (...) [const|volatile] [throw (...)];
2188 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2189 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
2190 * catch (...) {...}
2192 static bool skipPostArgumentStuff (
2193 statementInfo *const st, parenInfo *const info)
2195 tokenInfo *const token = activeToken (st);
2196 unsigned int parameters = info->parameterCount;
2197 unsigned int elementCount = 0;
2198 bool restart = false;
2199 bool end = false;
2200 int c = skipToNonWhite ();
2204 switch (c)
2206 case ')': break;
2207 case ':': skipMemIntializerList (token);break; /* ctor-initializer */
2208 case '[': skipToMatch ("[]"); break;
2209 case '=': lcppUngetc (c); end = true; break;
2210 case '{': lcppUngetc (c); end = true; break;
2211 case '}': lcppUngetc (c); end = true; break;
2213 case '(':
2215 if (elementCount > 0)
2216 ++elementCount;
2217 skipToMatch ("()");
2218 break;
2221 case ';':
2223 if (parameters == 0 || elementCount < 2)
2225 lcppUngetc (c);
2226 end = true;
2228 else if (--parameters == 0)
2229 end = true;
2230 break;
2233 default:
2235 if (lcppIsident1 (c))
2237 readIdentifier (token, c);
2238 if (isInputLanguage(Lang_d) && isDPostArgumentToken(token))
2239 token->keyword = KEYWORD_CONST;
2241 switch (token->keyword)
2243 case KEYWORD_ATTRIBUTE: skipParens (); break;
2244 case KEYWORD_THROW: skipParens (); break;
2245 case KEYWORD_CONST: break;
2246 case KEYWORD_NOEXCEPT: break;
2247 case KEYWORD_TRY: break;
2248 case KEYWORD_VOLATILE: break;
2250 case KEYWORD_CATCH: case KEYWORD_CLASS:
2251 case KEYWORD_EXPLICIT: case KEYWORD_EXTERN:
2252 case KEYWORD_FRIEND: case KEYWORD_INLINE:
2253 case KEYWORD_MUTABLE: case KEYWORD_NAMESPACE:
2254 case KEYWORD_NEW: case KEYWORD_OPERATOR:
2255 case KEYWORD_OVERLOAD: case KEYWORD_PRIVATE:
2256 case KEYWORD_PROTECTED: case KEYWORD_PUBLIC:
2257 case KEYWORD_STATIC: case KEYWORD_TEMPLATE:
2258 case KEYWORD_TYPEDEF: case KEYWORD_TYPENAME:
2259 case KEYWORD_USING: case KEYWORD_VIRTUAL:
2260 /* Never allowed within parameter declarations.
2262 restart = true;
2263 end = true;
2264 break;
2266 default:
2267 /* "override" and "final" are only keywords in the declaration of a virtual
2268 * member function, so need to be handled specially, not as keywords */
2269 if (isInputLanguage(Lang_cpp) && isType (token, TOKEN_NAME) &&
2270 (strcmp ("override", vStringValue (token->name)) == 0 ||
2271 strcmp ("final", vStringValue (token->name)) == 0))
2273 else if (isType (token, TOKEN_NONE))
2275 else if (info->isKnrParamList && info->parameterCount > 0)
2276 ++elementCount;
2277 else
2279 /* If we encounter any other identifier immediately
2280 * following an empty parameter list, this is almost
2281 * certainly one of those Microsoft macro "thingies"
2282 * that the automatic source code generation sticks
2283 * in. Terminate the current statement.
2285 restart = true;
2286 end = true;
2288 break;
2293 if (! end)
2295 c = skipToNonWhite ();
2296 if (c == EOF)
2297 end = true;
2299 } while (! end);
2301 if (restart)
2302 restartStatement (st);
2303 else
2304 setToken (st, TOKEN_NONE);
2306 return (bool) (c != EOF);
2309 static void skipJavaThrows (statementInfo *const st)
2311 tokenInfo *const token = activeToken (st);
2312 int c = skipToNonWhite ();
2314 if (lcppIsident1 (c))
2316 readIdentifier (token, c);
2317 if (token->keyword == KEYWORD_THROWS)
2321 c = skipToNonWhite ();
2322 if (lcppIsident1 (c))
2324 readIdentifier (token, c);
2325 c = skipToNonWhite ();
2327 } while (c == '.' || c == ',');
2330 lcppUngetc (c);
2331 setToken (st, TOKEN_NONE);
2334 static void skipValaPostParens (statementInfo *const st)
2336 tokenInfo *const token = activeToken (st);
2337 int c = skipToNonWhite ();
2339 while (lcppIsident1 (c))
2341 readIdentifier (token, c);
2342 if (token->keyword == KEYWORD_ATTRIBUTE)
2344 /* parse contracts */
2345 skipParens ();
2346 c = skipToNonWhite ();
2348 else if (token->keyword == KEYWORD_THROWS)
2352 c = skipToNonWhite ();
2353 if (lcppIsident1 (c))
2355 readIdentifier (token, c);
2356 c = skipToNonWhite ();
2358 } while (c == '.' || c == ',');
2360 else
2361 break;
2363 lcppUngetc (c);
2364 setToken (st, TOKEN_NONE);
2367 static void analyzePostParens (statementInfo *const st, parenInfo *const info)
2369 const unsigned long inputLineNumber = getInputLineNumber ();
2370 int c = skipToNonWhite ();
2372 lcppUngetc (c);
2373 if (isOneOf (c, "{;,="))
2375 else if (isInputLanguage (Lang_java))
2376 skipJavaThrows (st);
2377 else if (isInputLanguage (Lang_vala))
2378 skipValaPostParens(st);
2379 else
2381 if (! skipPostArgumentStuff (st, info))
2383 verbose (
2384 "%s: confusing argument declarations beginning at line %lu\n",
2385 getInputFileName (), inputLineNumber);
2386 longjmp (Exception, (int) ExceptionFormattingError);
2391 static int parseParens (statementInfo *const st, parenInfo *const info)
2393 tokenInfo *const token = activeToken (st);
2394 unsigned int identifierCount = 0;
2395 unsigned int depth = 1;
2396 bool firstChar = true;
2397 int nextChar = '\0';
2399 lcppStartCollectingSignature ();
2401 info->parameterCount = 1;
2404 int c = skipToNonWhite ();
2406 switch (c)
2408 case '&':
2409 case '*':
2411 /* DEBUG_PRINT("parseParens, po++\n"); */
2412 info->isKnrParamList = false;
2413 if (identifierCount == 0)
2414 info->isParamList = false;
2415 initToken (token);
2416 break;
2418 case ':':
2420 info->isKnrParamList = false;
2421 break;
2423 case '.':
2425 info->isNameCandidate = false;
2426 info->isKnrParamList = false;
2427 break;
2429 case ',':
2431 info->isNameCandidate = false;
2432 if (info->isKnrParamList)
2434 ++info->parameterCount;
2435 identifierCount = 0;
2437 break;
2439 case '=':
2441 info->isKnrParamList = false;
2442 info->isNameCandidate = false;
2443 if (firstChar)
2445 info->isParamList = false;
2446 skipMacro (st);
2447 depth = 0;
2449 break;
2451 case '[':
2453 info->isKnrParamList = false;
2454 skipToMatch ("[]");
2455 break;
2457 case '<':
2459 info->isKnrParamList = false;
2460 skipToMatch ("<>");
2461 break;
2463 case ')':
2465 if (firstChar)
2466 info->parameterCount = 0;
2467 --depth;
2468 break;
2470 case '(':
2472 info->isKnrParamList = false;
2473 if (firstChar)
2475 info->isNameCandidate = false;
2476 lcppUngetc (c);
2477 skipMacro (st);
2478 depth = 0;
2480 else if (isType (token, TOKEN_PAREN_NAME))
2482 c = skipToNonWhite ();
2483 if (c == '*') /* check for function pointer */
2485 skipToMatch ("()");
2486 c = skipToNonWhite ();
2487 if (c == '(')
2488 skipToMatch ("()");
2490 else
2492 lcppUngetc (c);
2493 lcppUngetc ('(');
2494 info->nestedArgs = true;
2497 else
2498 ++depth;
2499 break;
2502 default:
2504 if (lcppIsident1 (c))
2506 if (++identifierCount > 1)
2507 info->isKnrParamList = false;
2508 readIdentifier (token, c);
2509 if (isType (token, TOKEN_NAME) && info->isNameCandidate)
2510 token->type = TOKEN_PAREN_NAME;
2511 else if (isType (token, TOKEN_KEYWORD))
2513 info->isKnrParamList = false;
2514 info->isNameCandidate = false;
2517 else if (isInputLanguage(Lang_d) && c == '!')
2518 { /* D template instantiation */
2519 info->isNameCandidate = false;
2520 info->isKnrParamList = false;
2522 else
2524 info->isParamList = false;
2525 info->isKnrParamList = false;
2526 info->isNameCandidate = false;
2527 info->invalidContents = true;
2529 break;
2532 firstChar = false;
2533 } while (! info->nestedArgs && depth > 0 &&
2534 (info->isKnrParamList || info->isNameCandidate));
2536 if (! info->nestedArgs) while (depth > 0)
2538 skipToMatch ("()");
2539 --depth;
2542 lcppStopCollectingSignature ();
2544 if (! info->isNameCandidate)
2545 initToken (token);
2547 return nextChar;
2550 static void initParenInfo (parenInfo *const info)
2552 info->isParamList = true;
2553 info->isKnrParamList = true;
2554 info->isNameCandidate = true;
2555 info->invalidContents = false;
2556 info->nestedArgs = false;
2557 info->parameterCount = 0;
2560 static void analyzeParens (statementInfo *const st)
2562 tokenInfo *const prev = prevToken (st, 1);
2564 if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
2566 tokenInfo *const token = activeToken (st);
2567 parenInfo info;
2568 int c;
2570 initParenInfo (&info);
2571 parseParens (st, &info);
2572 c = skipToNonWhite ();
2573 lcppUngetc (c);
2574 if (info.invalidContents)
2576 reinitStatement (st, false);
2578 else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
2579 ! st->gotParenName &&
2580 (! info.isParamList || ! st->haveQualifyingName ||
2581 c == '(' ||
2582 (c == '=' && st->implementation != IMP_VIRTUAL) ||
2583 (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
2585 token->type = TOKEN_NAME;
2586 processName (st);
2587 st->gotParenName = true;
2588 if (isInputLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
2590 st->declaration = DECL_FUNCTION_TEMPLATE;
2591 copyToken (st->blockName, prev);
2594 else if (! st->gotArgs && info.isParamList)
2596 st->gotArgs = true;
2597 setToken (st, TOKEN_ARGS);
2598 advanceToken (st);
2599 analyzePostParens (st, &info);
2601 else
2602 setToken (st, TOKEN_NONE);
2607 * Token parsing functions
2610 static void addContext (statementInfo *const st, const tokenInfo* const token)
2612 if (isType (token, TOKEN_NAME))
2614 if (vStringLength (st->context->name) > 0)
2616 if (isInputLanguage (Lang_c) || isInputLanguage (Lang_cpp))
2617 vStringCatS (st->context->name, "::");
2618 else if (isInputLanguage (Lang_java) ||
2619 isInputLanguage (Lang_d) ||
2620 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala))
2621 vStringCatS (st->context->name, ".");
2623 vStringCat (st->context->name, token->name);
2624 st->context->type = TOKEN_NAME;
2628 static bool inheritingDeclaration (declType decl)
2630 /* enum base types */
2631 if (decl == DECL_ENUM)
2633 return (bool) (isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) ||
2634 isInputLanguage (Lang_d));
2636 return (bool) (
2637 decl == DECL_CLASS ||
2638 decl == DECL_STRUCT ||
2639 decl == DECL_INTERFACE);
2642 static void processColon (statementInfo *const st)
2644 int c = lcppGetc ();
2645 const bool doubleColon = (bool) (c == ':');
2647 if (doubleColon)
2649 setToken (st, TOKEN_DOUBLE_COLON);
2650 st->haveQualifyingName = false;
2652 else
2654 lcppUngetc (c);
2655 if ((isInputLanguage (Lang_cpp) || isInputLanguage (Lang_csharp) || isInputLanguage (Lang_d) ||
2656 isInputLanguage (Lang_vala)) &&
2657 inheritingDeclaration (st->declaration))
2659 readParents (st, ':');
2661 else if (parentDecl (st) == DECL_STRUCT || parentDecl (st) == DECL_CLASS)
2663 c = skipToOneOf (",;");
2664 if (c == ',')
2665 setToken (st, TOKEN_COMMA);
2666 else if (c == ';')
2667 setToken (st, TOKEN_SEMICOLON);
2669 else
2671 const tokenInfo *const prev = prevToken (st, 1);
2672 const tokenInfo *const prev2 = prevToken (st, 2);
2673 if (prev->keyword == KEYWORD_DEFAULT ||
2674 prev2->keyword == KEYWORD_CASE ||
2675 st->parent != NULL)
2677 reinitStatement (st, false);
2683 /* Skips over any initializing value which may follow an '=' character in a
2684 * variable definition.
2686 static int skipInitializer (statementInfo *const st)
2688 bool done = false;
2689 int c;
2691 while (! done)
2693 c = skipToNonWhite ();
2695 if (c == EOF)
2696 longjmp (Exception, (int) ExceptionFormattingError);
2697 else switch (c)
2699 case ',':
2700 case ';': done = true; break;
2702 case '0':
2703 if (st->implementation == IMP_VIRTUAL)
2704 st->implementation = IMP_PURE_VIRTUAL;
2705 break;
2707 case '[': skipToMatch ("[]"); break;
2708 case '(': skipToMatch ("()"); break;
2709 case '{': skipToMatch ("{}"); break;
2711 case '}':
2712 if (insideEnumBody (st))
2713 done = true;
2714 else if (! lcppIsBraceFormat ())
2716 verbose ("%s: unexpected closing brace at line %lu\n",
2717 getInputFileName (), getInputLineNumber ());
2718 longjmp (Exception, (int) ExceptionBraceFormattingError);
2720 break;
2722 default: break;
2725 return c;
2728 static void processInitializer (statementInfo *const st)
2730 const bool inEnumBody = insideEnumBody (st);
2731 const int c = skipInitializer (st);
2733 if (c == ';')
2734 setToken (st, TOKEN_SEMICOLON);
2735 else if (c == ',')
2736 setToken (st, TOKEN_COMMA);
2737 else if (c == '}' && inEnumBody)
2739 lcppUngetc (c);
2740 setToken (st, TOKEN_COMMA);
2742 if (st->scope == SCOPE_EXTERN)
2743 st->scope = SCOPE_GLOBAL;
2746 static void parseIdentifier (statementInfo *const st, const int c)
2748 tokenInfo *const token = activeToken (st);
2750 readIdentifier (token, c);
2751 if (! isType (token, TOKEN_NONE))
2752 processToken (token, st);
2755 static void parseGeneralToken (statementInfo *const st, const int c)
2757 const tokenInfo *const prev = prevToken (st, 1);
2759 if (lcppIsident1(c))
2761 parseIdentifier (st, c);
2762 if (isType (st->context, TOKEN_NAME) &&
2763 isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
2765 initToken (st->context);
2768 else if (isExternCDecl (st, c))
2770 st->declaration = DECL_NOMANGLE;
2771 st->scope = SCOPE_GLOBAL;
2775 /* Reads characters from the pre-processor and assembles tokens, setting
2776 * the current statement state.
2778 static void nextToken (statementInfo *const st)
2780 int c;
2781 tokenInfo *token = activeToken (st);
2784 c = skipToNonWhite();
2785 switch (c)
2787 case EOF: longjmp (Exception, (int) ExceptionEOF); break;
2788 case '(': analyzeParens (st); token = activeToken (st); break;
2789 case '*': setToken (st, TOKEN_STAR); break;
2790 case ',': setToken (st, TOKEN_COMMA); break;
2791 case ':': processColon (st); break;
2792 case ';': setToken (st, TOKEN_SEMICOLON); break;
2793 case '<': skipToMatch ("<>"); break;
2794 case '=': processInitializer (st); break;
2795 case '[':
2796 /* Hack for Vala: [..] can be a function attribute.
2797 * Seems not to have bad side effects, but have to test it more. */
2798 if (!isInputLanguage (Lang_vala))
2799 setToken (st, TOKEN_ARRAY);
2800 skipToMatch ("[]");
2801 break;
2802 case '{': setToken (st, TOKEN_BRACE_OPEN); break;
2803 case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
2804 default: parseGeneralToken (st, c); break;
2806 } while (isType (token, TOKEN_NONE));
2808 if (isType (token, TOKEN_SEMICOLON) && st->parent)
2809 st->parent->nSemicolons ++;
2811 /* We want to know about non-keyword variable types */
2812 if (TOKEN_NONE == st->firstToken->type)
2814 if ((TOKEN_NAME == token->type) || isDataTypeKeyword(token))
2815 copyToken(st->firstToken, token);
2820 * Scanning support functions
2822 static unsigned int contextual_fake_count = 0;
2823 static statementInfo *CurrentStatement = NULL;
2825 static statementInfo *newStatement (statementInfo *const parent)
2827 statementInfo *const st = xMalloc (1, statementInfo);
2828 unsigned int i;
2830 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2831 st->token [i] = newToken ();
2833 st->context = newToken ();
2834 st->blockName = newToken ();
2835 st->parentClasses = vStringNew ();
2836 st->firstToken = newToken();
2838 initStatement (st, parent);
2839 CurrentStatement = st;
2841 return st;
2844 static void deleteStatement (void)
2846 statementInfo *const st = CurrentStatement;
2847 statementInfo *const parent = st->parent;
2848 unsigned int i;
2850 for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
2852 deleteToken (st->token [i]); st->token [i] = NULL;
2854 deleteToken (st->blockName); st->blockName = NULL;
2855 deleteToken (st->context); st->context = NULL;
2856 vStringDelete (st->parentClasses); st->parentClasses = NULL;
2857 deleteToken(st->firstToken);
2858 eFree (st);
2859 CurrentStatement = parent;
2862 static void deleteAllStatements (void)
2864 while (CurrentStatement != NULL)
2865 deleteStatement ();
2868 static bool isStatementEnd (const statementInfo *const st)
2870 const tokenInfo *const token = activeToken (st);
2871 bool isEnd;
2873 if (isType (token, TOKEN_SEMICOLON))
2874 isEnd = true;
2875 else if (isType (token, TOKEN_BRACE_CLOSE))
2876 /* Java, D, C#, Vala do not require semicolons to end a block. Neither do
2877 * C++ namespaces. All other blocks require a semicolon to terminate them.
2879 isEnd = (bool) (isInputLanguage (Lang_java) || isInputLanguage (Lang_d) ||
2880 isInputLanguage (Lang_csharp) || isInputLanguage (Lang_vala) ||
2881 ! isContextualStatement (st));
2882 else
2883 isEnd = false;
2885 return isEnd;
2888 static void checkStatementEnd (statementInfo *const st)
2890 const tokenInfo *const token = activeToken (st);
2891 bool comma = isType (token, TOKEN_COMMA);
2893 if (comma || isStatementEnd (st))
2895 reinitStatementWithToken (st, activeToken (st), comma);
2897 DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
2898 lcppEndStatement ();
2900 else
2902 lcppBeginStatement ();
2903 advanceToken (st);
2907 static void nest (statementInfo *const st, const unsigned int nestLevel)
2909 switch (st->declaration)
2911 case DECL_CLASS:
2912 case DECL_ENUM:
2913 case DECL_INTERFACE:
2914 case DECL_NAMESPACE:
2915 case DECL_NOMANGLE:
2916 case DECL_STRUCT:
2917 case DECL_UNION:
2918 createTags (nestLevel, st);
2919 break;
2920 default:
2921 skipToMatch ("{}");
2922 break;
2924 advanceToken (st);
2925 setToken (st, TOKEN_BRACE_CLOSE);
2928 static void tagCheck (statementInfo *const st)
2930 const tokenInfo *const token = activeToken (st);
2931 const tokenInfo *const prev = prevToken (st, 1);
2932 const tokenInfo *const prev2 = prevToken (st, 2);
2934 switch (token->type)
2936 case TOKEN_NAME:
2938 if (insideEnumBody (st) &&
2939 /* Java enumerations can contain members after a semicolon */
2940 (! isInputLanguage(Lang_java) || st->parent->nSemicolons < 1))
2941 qualifyEnumeratorTag (st, token);
2942 break;
2944 #if 0
2945 case TOKEN_PACKAGE:
2947 if (st->haveQualifyingName)
2948 makeTag (token, st, false, TAG_PACKAGE);
2949 break;
2951 #endif
2952 case TOKEN_BRACE_OPEN:
2954 if (isType (prev, TOKEN_ARGS))
2956 if (st->declaration == DECL_FUNCTION_TEMPLATE)
2957 qualifyFunctionTag (st, st->blockName);
2958 else if (st->haveQualifyingName)
2960 if (isType (prev2, TOKEN_NAME))
2961 copyToken (st->blockName, prev2);
2962 /* D structure templates */
2963 if (isInputLanguage (Lang_d) &&
2964 (st->declaration == DECL_CLASS || st->declaration == DECL_STRUCT ||
2965 st->declaration == DECL_INTERFACE || st->declaration == DECL_NAMESPACE))
2966 qualifyBlockTag (st, prev2);
2967 else
2969 st->declaration = DECL_FUNCTION;
2970 qualifyFunctionTag (st, prev2);
2974 else if (isContextualStatement (st))
2976 tokenInfo *name_token = (tokenInfo *)prev;
2977 bool free_name_token = false;
2979 /* C++ 11 allows class <name> final { ... } */
2980 if (isInputLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) &&
2981 strcmp("final", vStringValue(prev->name)) == 0 &&
2982 isType(prev2, TOKEN_NAME))
2984 name_token = (tokenInfo *)prev2;
2985 copyToken (st->blockName, name_token);
2987 else if (isType (name_token, TOKEN_NAME))
2989 if (!isInputLanguage (Lang_vala))
2990 copyToken (st->blockName, name_token);
2991 else
2993 switch (st->declaration)
2995 case DECL_CLASS:
2996 case DECL_ENUM:
2997 case DECL_INTERFACE:
2998 case DECL_NAMESPACE:
2999 case DECL_STRUCT:
3000 copyToken (st->blockName, name_token);
3001 break;
3003 /* anything else can be a property */
3004 default:
3005 /* makeTag (prev, st, false, TAG_PROPERTY); */
3006 /* FIXME: temporary hack to get properties shown */
3007 makeTag (prev, st, false, TAG_FIELD);
3008 break;
3012 else if (isInputLanguage (Lang_csharp))
3013 makeTag (prev, st, false, TAG_PROPERTY);
3014 else
3016 tokenInfo *contextual_token = (tokenInfo *)prev;
3017 if(isContextualKeyword (contextual_token))
3019 char buffer[64];
3021 name_token = newToken ();
3022 free_name_token = true;
3023 copyToken (name_token, contextual_token);
3025 sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
3026 vStringClear(name_token->name);
3027 vStringCatS(name_token->name, buffer);
3029 name_token->type = TOKEN_NAME;
3030 name_token->keyword = KEYWORD_NONE;
3032 advanceToken (st);
3033 contextual_token = activeToken (st);
3034 copyToken (contextual_token, token);
3035 copyToken ((tokenInfo *const)token, name_token);
3036 copyToken (st->blockName, name_token);
3037 copyToken (st->firstToken, name_token);
3040 qualifyBlockTag (st, name_token);
3041 if (free_name_token)
3042 deleteToken (name_token);
3044 break;
3046 case TOKEN_ARRAY:
3047 case TOKEN_SEMICOLON:
3048 case TOKEN_COMMA:
3050 if (insideEnumBody (st) &&
3051 /* Java enumerations can contain members after a semicolon */
3052 (! isInputLanguage (Lang_java) || st->parent->nSemicolons < 2))
3054 else if (isType (prev, TOKEN_NAME))
3056 if (isContextualKeyword (prev2))
3057 makeTag (prev, st, true, TAG_EXTERN_VAR);
3058 else
3059 qualifyVariableTag (st, prev);
3061 else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
3063 qualifyFunctionDeclTag (st, prev2);
3065 break;
3067 default:
3068 break;
3072 /* Parses the current file and decides whether to write out and tags that
3073 * are discovered.
3075 static void createTags (const unsigned int nestLevel,
3076 statementInfo *const parent)
3078 statementInfo *const st = newStatement (parent);
3080 DebugStatement ( if (nestLevel > 0) debugParseNest (true, nestLevel); )
3081 while (true)
3083 tokenInfo *token;
3085 nextToken (st);
3086 token = activeToken (st);
3087 if (isType (token, TOKEN_BRACE_CLOSE))
3089 if (nestLevel > 0)
3090 break;
3091 else
3093 verbose ("%s: unexpected closing brace at line %lu\n",
3094 getInputFileName (), getInputLineNumber ());
3095 longjmp (Exception, (int) ExceptionBraceFormattingError);
3098 else if (isType (token, TOKEN_DOUBLE_COLON))
3100 addContext (st, prevToken (st, 1));
3101 advanceToken (st);
3103 else
3105 tagCheck (st);/* this can add new token */
3106 if (isType (activeToken (st), TOKEN_BRACE_OPEN))
3107 nest (st, nestLevel + 1);
3108 checkStatementEnd (st);
3111 deleteStatement ();
3112 DebugStatement ( if (nestLevel > 0) debugParseNest (false, nestLevel - 1); )
3115 static rescanReason findCTags (const unsigned int passCount)
3117 exception_t exception;
3118 rescanReason rescan = RESCAN_NONE;
3120 contextual_fake_count = 0;
3122 Assert (passCount < 3);
3124 lcppInit ((bool) (passCount > 1), isInputLanguage (Lang_csharp), isInputLanguage(Lang_cpp),
3125 CK_DEFINE);
3127 exception = (exception_t) setjmp (Exception);
3128 rescan = RESCAN_NONE;
3129 if (exception == ExceptionNone)
3131 createTags (0, NULL);
3133 else
3135 deleteAllStatements ();
3136 if (exception == ExceptionBraceFormattingError && passCount == 1)
3138 rescan = RESCAN_FAILED;
3139 verbose ("%s: retrying file with fallback brace matching algorithm\n",
3140 getInputFileName ());
3143 lcppTerminate ();
3144 return rescan;
3147 static void buildKeywordHash (const langType language, unsigned int idx)
3149 const size_t count = ARRAY_SIZE (KeywordTable);
3150 size_t i;
3151 for (i = 0 ; i < count ; ++i)
3153 const keywordDesc* const p = &KeywordTable [i];
3154 if (p->isValid [idx])
3155 addKeyword (p->name, language, (int) p->id);
3159 static void initializeCParser (const langType language)
3161 Lang_c = language;
3162 buildKeywordHash (language, 0);
3165 static void initializeCppParser (const langType language)
3167 Lang_cpp = language;
3168 buildKeywordHash (language, 1);
3171 static void initializeJavaParser (const langType language)
3173 Lang_java = language;
3174 buildKeywordHash (language, 3);
3177 static void initializeDParser (const langType language)
3179 /* treat these like const - some are for parsing like const(Type), some are just
3180 * function attributes */
3181 const char *const_aliases[] = {"immutable", "nothrow", "pure", "shared", NULL};
3182 const char **s;
3184 Lang_d = language;
3185 buildKeywordHash (language, 6);
3187 for (s = const_aliases; *s != NULL; s++)
3189 addKeyword (*s, language, KEYWORD_CONST);
3191 /* other keyword aliases */
3192 addKeyword ("alias", language, KEYWORD_TYPEDEF);
3193 /* skip 'static assert(...)' like 'static if (...)' */
3194 addKeyword ("assert", language, KEYWORD_IF);
3195 addKeyword ("unittest", language, KEYWORD_BODY); /* ignore */
3196 addKeyword ("version", language, KEYWORD_NAMESPACE); /* parse block */
3199 static void initializeCsharpParser (const langType language)
3201 Lang_csharp = language;
3202 buildKeywordHash (language, 2);
3205 static void initializeValaParser (const langType language)
3207 Lang_vala = language;
3208 buildKeywordHash (language, 5);
3210 /* keyword aliases */
3211 addKeyword ("ensures", language, KEYWORD_ATTRIBUTE); /* ignore */
3212 addKeyword ("errordomain", language, KEYWORD_ENUM); /* looks like enum */
3213 addKeyword ("requires", language, KEYWORD_ATTRIBUTE); /* ignore */
3216 extern parserDefinition* CParserOld (void)
3218 static const char *const extensions [] = { "c", "pc", "sc", NULL };
3219 parserDefinition* def = parserNew ("C");
3220 def->kindTable = CKinds;
3221 def->kindCount = ARRAY_SIZE (CKinds);
3222 def->extensions = extensions;
3223 def->parser2 = findCTags;
3224 def->initialize = initializeCParser;
3225 return def;
3228 extern parserDefinition* CppParserOld (void)
3230 static const char *const extensions [] = {
3231 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3232 "i",
3233 #ifndef CASE_INSENSITIVE_FILENAMES
3234 "C", "H",
3235 #endif
3236 NULL
3238 parserDefinition* def = parserNew ("C++");
3239 def->kindTable = CKinds;
3240 def->kindCount = ARRAY_SIZE (CKinds);
3241 def->extensions = extensions;
3242 def->parser2 = findCTags;
3243 def->initialize = initializeCppParser;
3244 return def;
3247 extern parserDefinition* JavaParser (void)
3249 static const char *const extensions [] = { "java", NULL };
3250 parserDefinition* def = parserNew ("Java");
3251 def->kindTable = JavaKinds;
3252 def->kindCount = ARRAY_SIZE (JavaKinds);
3253 def->extensions = extensions;
3254 def->parser2 = findCTags;
3255 def->initialize = initializeJavaParser;
3256 return def;
3259 extern parserDefinition* DParser (void)
3261 static const char *const extensions [] = { "d", "di", NULL };
3262 parserDefinition* def = parserNew ("D");
3263 def->kindTable = DKinds;
3264 def->kindCount = ARRAY_SIZE (DKinds);
3265 def->extensions = extensions;
3266 def->parser2 = findCTags;
3267 def->initialize = initializeDParser;
3268 return def;
3271 extern parserDefinition* CsharpParser (void)
3273 static const char *const extensions [] = { "cs", NULL };
3274 parserDefinition* def = parserNew ("C#");
3275 def->kindTable = CsharpKinds;
3276 def->kindCount = ARRAY_SIZE (CsharpKinds);
3277 def->extensions = extensions;
3278 def->parser2 = findCTags;
3279 def->initialize = initializeCsharpParser;
3280 return def;
3283 extern parserDefinition* ValaParser (void)
3285 static const char *const extensions [] = { "vala", NULL };
3286 parserDefinition* def = parserNew ("Vala");
3287 def->kindTable = ValaKinds;
3288 def->kindCount = ARRAY_SIZE (ValaKinds);
3289 def->extensions = extensions;
3290 def->parser2 = findCTags;
3291 def->initialize = initializeValaParser;
3292 return def;