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
14 #include "general.h" /* must always come first */
22 #include "geany_lcpp.h"
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)
50 enum { NumTokens
= 12 };
52 typedef enum eException
54 ExceptionNone
, ExceptionEOF
, ExceptionFormattingError
,
55 ExceptionBraceFormattingError
58 /* Used to specify type of keyword.
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
,
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
,
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
,
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
101 typedef struct sKeywordDesc
105 short isValid
[7]; /* indicates languages for which kw is valid */
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 */
116 TOKEN_COMMA
, /* the comma character */
117 TOKEN_DOUBLE_COLON
, /* double colon indicates nested-name-specifier */
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 */
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 */
141 typedef enum eDeclaration
144 DECL_BASE
, /* base type (default) */
150 DECL_FUNCTION_TEMPLATE
,
151 DECL_IGNORE
, /* non-taggable "declaration" */
155 DECL_NOMANGLE
, /* C++ name demangling block */
162 typedef enum eVisibilityType
168 ACCESS_DEFAULT
, /* Java-specific */
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 */
180 typedef struct sTokenInfo
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 */
189 typedef enum eImplementation
198 /* Describes the statement currently undergoing analysis.
200 typedef struct sStatementInfo
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 */
220 /* Describes the type of tag being generated.
222 typedef enum eTagType
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 */
249 typedef struct sParenInfo
253 bool isNameCandidate
;
254 bool invalidContents
;
256 unsigned int parameterCount
;
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. */
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
,
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. */
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
,
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. */
328 JK_CLASS
, JK_FIELD
, JK_INTERFACE
, JK_METHOD
,
329 JK_PACKAGE
, JK_ENUMERATOR
, JK_ENUMERATION
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"},
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
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"},
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
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
[] = {
391 /* ANSI C | C# Java */
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
)
559 statementInfo
*st
= (statementInfo
*) statement
;
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");
581 fprintf(stderr
, "-----------------------------------------------\n");
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)
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
;
612 tokenIndex
= (st
->tokenIndex
+ num
- n
) % num
;
613 return st
->token
[tokenIndex
];
616 static void setToken (statementInfo
*const st
, const tokenType type
)
619 token
= activeToken (st
);
624 static void retardToken (statementInfo
*const st
)
626 if (st
->tokenIndex
== 0)
627 st
->tokenIndex
= (unsigned int) NumTokens
- 1;
630 setToken (st
, TOKEN_NONE
);
633 static tokenInfo
*newToken (void)
635 tokenInfo
*const token
= xMalloc (1, tokenInfo
);
636 token
->name
= vStringNew ();
641 static void deleteToken (tokenInfo
*const token
)
645 vStringDelete (token
->name
);
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
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";
716 for (i
= 0 ; i
< count
; ++i
)
718 const keywordDesc
*p
= &KeywordTable
[i
];
719 if (p
->id
== keyword
)
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
),
734 else if (isType (token
, TOKEN_KEYWORD
))
735 printf ("type: %-12s: %-13s line: %lu\n",
736 tokenString (token
->type
), keywordString (token
->keyword
),
739 printf ("type: %-12s line: %lu\n",
740 tokenString (token
->type
), token
->lineNumber
);
743 static void CTAGS_ATTR_UNUSED
ps (statementInfo
*const st
)
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
));
753 pt(activeToken (st
));
754 for (i
= 1 ; i
< (unsigned int) NumTokens
; ++i
)
756 printf("prev %u : ", i
);
757 pt(prevToken (st
, i
));
766 * Statement management
769 static bool isDataTypeKeyword (const tokenInfo
*const token
)
771 switch (token
->keyword
)
773 case KEYWORD_BOOLEAN
:
782 case KEYWORD_WCHAR_T
:
791 static bool isVariableKeyword (const tokenInfo
*const token
)
793 switch (token
->keyword
)
797 case KEYWORD_REGISTER
:
799 case KEYWORD_VIRTUAL
:
801 case KEYWORD_UNSIGNED
:
809 static bool isContextualKeyword (const tokenInfo
*const token
)
812 switch (token
->keyword
)
816 case KEYWORD_INTERFACE
:
817 case KEYWORD_NAMESPACE
:
834 static bool isContextualStatement (const statementInfo
*const st
)
840 if (isInputLanguage (Lang_vala
))
842 /* All can be a contextual statement as properties can be of any type */
847 switch (st
->declaration
)
871 static bool isMember (const statementInfo
*const st
)
874 if (isType (st
->context
, TOKEN_NAME
))
877 result
= isContextualStatement (st
->parent
);
881 static void initMemberInfo (statementInfo
*const st
)
883 accessType accessDefault
= ACCESS_UNDEFINED
;
885 if (st
->parent
!= NULL
) switch (st
->parent
->declaration
)
890 accessDefault
= ACCESS_UNDEFINED
;
895 if (isInputLanguage (Lang_java
))
896 accessDefault
= ACCESS_DEFAULT
;
898 accessDefault
= ACCESS_PRIVATE
;
905 accessDefault
= ACCESS_PUBLIC
;
911 st
->member
.accessDefault
= accessDefault
;
912 st
->member
.access
= accessDefault
;
915 static void reinitStatement (statementInfo
*const st
, const bool partial
)
921 st
->scope
= SCOPE_GLOBAL
;
922 if (isContextualStatement (st
->parent
))
923 st
->declaration
= DECL_BASE
;
925 st
->declaration
= DECL_NONE
;
927 st
->gotParenName
= false;
928 st
->implementation
= IMP_DEFAULT
;
932 st
->haveQualifyingName
= false;
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. */
947 st
->member
.access
= st
->member
.accessDefault
;
949 /* Init first token */
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
);
964 ++st
->tokenIndex
; /* this is quite safe because current tokenIndex = 0 */
967 static void initStatement (statementInfo
*const st
, statementInfo
*const parent
)
971 reinitStatement (st
, false);
974 const tokenInfo
*const src
= activeToken (parent
);
975 tokenInfo
*const dst
= activeToken (st
);
976 copyToken (dst
, src
);
982 * Tag generation functions
984 static cKind
cTagKind (const tagType type
)
986 cKind result
= CK_UNDEFINED
;
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;
1007 static csharpKind
csharpTagKind (const tagType type
)
1009 csharpKind result
= CSK_UNDEFINED
;
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;
1030 static dKind
dTagKind (const tagType type
)
1032 dKind result
= DK_UNDEFINED
;
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;
1054 static valaKind
valaTagKind (const tagType type
)
1056 valaKind result
= VK_UNDEFINED
;
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;
1076 static javaKind
javaTagKind (const tagType type
)
1078 javaKind result
= JK_UNDEFINED
;
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;
1094 static int kindIndexForType (const tagType type
)
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
);
1106 result
= cTagKind (type
);
1111 static bool includeTag (const tagType type, const bool isFileScope)
1114 if (isFileScope && ! Option.include.fileScope)
1116 else if (isInputLanguage (Lang_java))
1117 result = JavaKinds [javaTagKind (type)].enabled;
1119 result = CKinds [cTagKind (type)].enabled;
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;
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
)
1151 else if (st
->member
.access
!= ACCESS_UNDEFINED
)
1152 result
= accessString (st
->member
.access
);
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.
1170 case TAG_ENUMERATOR
:
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
);
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
);
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 ();
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
;
1235 unsigned int end
= st
->tokenIndex
;
1236 bool seenType
= false;
1238 switch (st
->declaration
) {
1241 case DECL_FUNCTION_TEMPLATE
:
1244 return vStringValue(st
->firstToken
->name
);
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
)))
1269 if (t
->type
!= TOKEN_DOUBLE_COLON
)
1271 if (t
->type
== TOKEN_NAME
)
1273 else if (t
->type
== TOKEN_KEYWORD
&& isDataTypeKeyword(t
))
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
];
1287 case TOKEN_NAME
: /* user typename */
1290 if ((t
->keyword
!= KEYWORD_EXTERN
&& t
->keyword
!= KEYWORD_STATIC
) && /* uninteresting keywords */
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
)))
1304 case TOKEN_STAR
: vStringCatS(vt
, " *"); continue;
1305 case TOKEN_ARRAY
: vStringCatS(vt
, "[]"); continue;
1306 case TOKEN_DOUBLE_COLON
:
1307 vStringCatS(vt
, "::");
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;
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
);
1389 /* remove last component (i.e. enumeration name) from scope */
1390 const char* const sc
= vStringValue (scope
);
1391 const char* colon
= strrchr (sc
, ':');
1394 while (*colon
== ':' && colon
> sc
)
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
);
1406 vStringDelete (scopedName
);
1410 static void makeTag (const tokenInfo
*const token
,
1411 const statementInfo
*const st
,
1412 bool isFileScope
, const tagType type
)
1416 fprintf(stderr
, "<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>\n");
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) */)
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
);
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
)
1453 switch (declaration
)
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
)
1527 case DECL_INTERFACE
:
1528 case DECL_NAMESPACE
:
1531 qualifyCompoundTag (st
, nameToken
);
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
))
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
))
1567 if (st
->scope
== SCOPE_EXTERN
|| ! st
->haveQualifyingName
)
1568 makeTag (nameToken
, st
, false, TAG_EXTERN_VAR
);
1570 makeTag (nameToken
, st
, (bool) (st
->scope
== SCOPE_STATIC
), TAG_VARIABLE
);
1579 static int skipToOneOf (const char *const chars
)
1584 while (c
!= EOF
&& c
!= '\0' && strchr (chars
, c
) == NULL
);
1589 /* Skip to the next non-white character.
1591 static int skipToNonWhite (void)
1599 while (isspace (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)
1613 while (c
!= EOF
&& (c
!= '\n' || next
!= '}'))
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
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 ();
1636 if (isInputLanguage(Lang_d
) && pair
[0] == '<')
1637 return; /* ignore e.g. Foo!(x < 2) */
1638 while (matchLevel
> 0 && (c
= lcppGetc ()) != EOF
)
1643 if (braceFormatting
&& lcppGetDirectiveNestLevel () != initialLevel
)
1645 skipToFormattedBraceMatch ();
1652 if (braceFormatting
&& lcppGetDirectiveNestLevel () != initialLevel
)
1654 skipToFormattedBraceMatch ();
1658 /* early out if matching "<>" and we encounter a ";" or "{" to mitigate
1659 * match problems with C++ generics containing a static expression like
1661 * normally neither ";" nor "{" could appear inside "<>" anyway. */
1662 else if (isInputLanguage (Lang_cpp
) && begin
== '<' &&
1663 (c
== ';' || c
== '{'))
1671 verbose ("%s: failed to find match for '%c' at line %lu\n",
1672 getInputFileName (), begin
, inputLineNumber
);
1674 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
1676 longjmp (Exception
, (int) ExceptionFormattingError
);
1680 static void skipParens (void)
1682 const int c
= skipToNonWhite ();
1690 static void skipBraces (void)
1692 const int c
= skipToNonWhite ();
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
;
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
);
1725 token
->keyword
= analyzeKeyword (vStringValue (token
->name
));
1727 if (token
->keyword
== KEYWORD_NONE
)
1728 token
->type
= TOKEN_NAME
;
1730 token
->type
= TOKEN_KEYWORD
;
1737 int c
= skipToNonWhite ();
1745 static void readIdentifier (tokenInfo
*const token
, const int firstChar
)
1747 vString
*const name
= token
->name
;
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
);
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 ();
1772 vStringPut (name
, c
);
1777 analyzeIdentifier (token
);
1780 static void readPackageName (tokenInfo
*const token
, const int firstChar
)
1782 vString
*const name
= token
->name
;
1787 while (lcppIsident (c
) || c
== '.')
1789 vStringPut (name
, c
);
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. */
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
;
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
;
1825 st
->declaration
= DECL_PACKAGE
;
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
;
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 */
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 ();
1861 vStringCatS (name
, "()");
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 */
1883 vStringPut (name
, ' ');
1886 vStringPut (name
, c
);
1889 } while (! isOneOf (c
, "(;") && c
!= EOF
);
1891 else if (isOneOf (c
, acceptable
))
1893 vStringPut (name
, ' '); /* always separate operator from keyword */
1896 vStringPut (name
, c
);
1898 } while (isOneOf (c
, acceptable
));
1903 token
->type
= TOKEN_NAME
;
1904 token
->keyword
= KEYWORD_NONE
;
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
)
1921 if (isInputLanguage (Lang_cpp
) || isInputLanguage (Lang_d
))
1923 int c
= skipToNonWhite ();
1926 reinitStatementWithToken (st
, prevToken (st
, 1), false);
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 ();
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 ();
1967 c
= skipToNonWhite ();
1968 if (lcppIsident1 (c
))
1970 readIdentifier (token
, c
);
1971 if (isType (token
, TOKEN_NAME
))
1972 vStringCat (parent
->name
, token
->name
);
1975 addParentClass (st
, parent
);
1979 else if (c
== qualifier
)
1980 vStringPut (parent
->name
, c
);
1983 else if (isType (token
, TOKEN_NAME
))
1985 addParentClass (st
, parent
);
1988 } while (c
!= '{' && c
!= EOF
);
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? */
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;
2050 if (isInputLanguage (Lang_csharp
))
2051 st
->declaration
= DECL_EVENT
;
2054 case KEYWORD_SIGNAL
:
2056 if (isInputLanguage (Lang_vala
))
2057 st
->declaration
= DECL_SIGNAL
;
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
;
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
;
2081 if (isInputLanguage (Lang_d
))
2082 { /* static if (is(typeof(__traits(getMember, a, name)) == function)) */
2083 int c
= skipToNonWhite ();
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
);
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
2115 * [::] [nested-name-spec] class-name (...)
2118 static void skipMemIntializerList (tokenInfo
*const token
)
2124 c
= skipToNonWhite ();
2125 while (lcppIsident1 (c
) || c
== ':')
2128 readIdentifier (token
, c
);
2129 c
= skipToNonWhite ();
2134 c
= skipToNonWhite ();
2139 c
= skipToNonWhite ();
2145 static void skipMacro (statementInfo
*const st
)
2147 tokenInfo
*const prev2
= prevToken (st
, 2);
2149 if (isType (prev2
, TOKEN_NAME
))
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 */
2161 /* template constraint */
2172 if (vStringValue(token
->name
)[0] == '@')
2177 /* Skips over characters following the parameter list. This will be either
2178 * non-ANSI style function declarations or C++ stuff. Our choices:
2182 * int func (one, two) int one; float two; {...}
2184 * int func (int one, float two);
2185 * int func (int one, float two) {...}
2187 * int foo (...) [const|volatile] [throw (...)];
2188 * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
2189 * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
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;
2200 int c
= skipToNonWhite ();
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;
2215 if (elementCount
> 0)
2223 if (parameters
== 0 || elementCount
< 2)
2228 else if (--parameters
== 0)
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.
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)
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.
2295 c
= skipToNonWhite ();
2302 restartStatement (st
);
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
== ',');
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 */
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
== ',');
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 ();
2373 if (isOneOf (c
, "{;,="))
2375 else if (isInputLanguage (Lang_java
))
2376 skipJavaThrows (st
);
2377 else if (isInputLanguage (Lang_vala
))
2378 skipValaPostParens(st
);
2381 if (! skipPostArgumentStuff (st
, info
))
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 ();
2411 /* DEBUG_PRINT("parseParens, po++\n"); */
2412 info
->isKnrParamList
= false;
2413 if (identifierCount
== 0)
2414 info
->isParamList
= false;
2420 info
->isKnrParamList
= false;
2425 info
->isNameCandidate
= false;
2426 info
->isKnrParamList
= false;
2431 info
->isNameCandidate
= false;
2432 if (info
->isKnrParamList
)
2434 ++info
->parameterCount
;
2435 identifierCount
= 0;
2441 info
->isKnrParamList
= false;
2442 info
->isNameCandidate
= false;
2445 info
->isParamList
= false;
2453 info
->isKnrParamList
= false;
2459 info
->isKnrParamList
= false;
2466 info
->parameterCount
= 0;
2472 info
->isKnrParamList
= false;
2475 info
->isNameCandidate
= false;
2480 else if (isType (token
, TOKEN_PAREN_NAME
))
2482 c
= skipToNonWhite ();
2483 if (c
== '*') /* check for function pointer */
2486 c
= skipToNonWhite ();
2494 info
->nestedArgs
= true;
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;
2524 info
->isParamList
= false;
2525 info
->isKnrParamList
= false;
2526 info
->isNameCandidate
= false;
2527 info
->invalidContents
= true;
2533 } while (! info
->nestedArgs
&& depth
> 0 &&
2534 (info
->isKnrParamList
|| info
->isNameCandidate
));
2536 if (! info
->nestedArgs
) while (depth
> 0)
2542 lcppStopCollectingSignature ();
2544 if (! info
->isNameCandidate
)
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
);
2570 initParenInfo (&info
);
2571 parseParens (st
, &info
);
2572 c
= skipToNonWhite ();
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
||
2582 (c
== '=' && st
->implementation
!= IMP_VIRTUAL
) ||
2583 (st
->declaration
== DECL_NONE
&& isOneOf (c
, ",;"))))
2585 token
->type
= TOKEN_NAME
;
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
)
2597 setToken (st
, TOKEN_ARGS
);
2599 analyzePostParens (st
, &info
);
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
));
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
== ':');
2649 setToken (st
, TOKEN_DOUBLE_COLON
);
2650 st
->haveQualifyingName
= false;
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 (",;");
2665 setToken (st
, TOKEN_COMMA
);
2667 setToken (st
, TOKEN_SEMICOLON
);
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
||
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
)
2693 c
= skipToNonWhite ();
2696 longjmp (Exception
, (int) ExceptionFormattingError
);
2700 case ';': done
= true; break;
2703 if (st
->implementation
== IMP_VIRTUAL
)
2704 st
->implementation
= IMP_PURE_VIRTUAL
;
2707 case '[': skipToMatch ("[]"); break;
2708 case '(': skipToMatch ("()"); break;
2709 case '{': skipToMatch ("{}"); break;
2712 if (insideEnumBody (st
))
2714 else if (! lcppIsBraceFormat ())
2716 verbose ("%s: unexpected closing brace at line %lu\n",
2717 getInputFileName (), getInputLineNumber ());
2718 longjmp (Exception
, (int) ExceptionBraceFormattingError
);
2728 static void processInitializer (statementInfo
*const st
)
2730 const bool inEnumBody
= insideEnumBody (st
);
2731 const int c
= skipInitializer (st
);
2734 setToken (st
, TOKEN_SEMICOLON
);
2736 setToken (st
, TOKEN_COMMA
);
2737 else if (c
== '}' && inEnumBody
)
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
)
2781 tokenInfo
*token
= activeToken (st
);
2784 c
= skipToNonWhite();
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;
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
);
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
);
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
;
2844 static void deleteStatement (void)
2846 statementInfo
*const st
= CurrentStatement
;
2847 statementInfo
*const parent
= st
->parent
;
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
);
2859 CurrentStatement
= parent
;
2862 static void deleteAllStatements (void)
2864 while (CurrentStatement
!= NULL
)
2868 static bool isStatementEnd (const statementInfo
*const st
)
2870 const tokenInfo
*const token
= activeToken (st
);
2873 if (isType (token
, TOKEN_SEMICOLON
))
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
));
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 ();
2902 lcppBeginStatement ();
2907 static void nest (statementInfo
*const st
, const unsigned int nestLevel
)
2909 switch (st
->declaration
)
2913 case DECL_INTERFACE
:
2914 case DECL_NAMESPACE
:
2918 createTags (nestLevel
, 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
)
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
);
2947 if (st
->haveQualifyingName
)
2948 makeTag (token
, st
, false, TAG_PACKAGE
);
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
);
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
);
2993 switch (st
->declaration
)
2997 case DECL_INTERFACE
:
2998 case DECL_NAMESPACE
:
3000 copyToken (st
->blockName
, name_token
);
3003 /* anything else can be a property */
3005 /* makeTag (prev, st, false, TAG_PROPERTY); */
3006 /* FIXME: temporary hack to get properties shown */
3007 makeTag (prev
, st
, false, TAG_FIELD
);
3012 else if (isInputLanguage (Lang_csharp
))
3013 makeTag (prev
, st
, false, TAG_PROPERTY
);
3016 tokenInfo
*contextual_token
= (tokenInfo
*)prev
;
3017 if(isContextualKeyword (contextual_token
))
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
;
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
);
3047 case TOKEN_SEMICOLON
:
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
);
3059 qualifyVariableTag (st
, prev
);
3061 else if (isType (prev
, TOKEN_ARGS
) && isType (prev2
, TOKEN_NAME
))
3063 qualifyFunctionDeclTag (st
, prev2
);
3072 /* Parses the current file and decides whether to write out and tags that
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
); )
3086 token
= activeToken (st
);
3087 if (isType (token
, TOKEN_BRACE_CLOSE
))
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));
3105 tagCheck (st
);/* this can add new token */
3106 if (isType (activeToken (st
), TOKEN_BRACE_OPEN
))
3107 nest (st
, nestLevel
+ 1);
3108 checkStatementEnd (st
);
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
),
3127 exception
= (exception_t
) setjmp (Exception
);
3128 rescan
= RESCAN_NONE
;
3129 if (exception
== ExceptionNone
)
3131 createTags (0, NULL
);
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 ());
3147 static void buildKeywordHash (const langType language
, unsigned int idx
)
3149 const size_t count
= ARRAY_SIZE (KeywordTable
);
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
)
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
};
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
;
3228 extern parserDefinition
* CppParserOld (void)
3230 static const char *const extensions
[] = {
3231 "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
3233 #ifndef CASE_INSENSITIVE_FILENAMES
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
;
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
;
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
;
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
;
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
;